From e9f2cd0628ac063a79411fd9d4a28145aaaf7e46 Mon Sep 17 00:00:00 2001 From: Vitor Vilela Date: Mon, 22 Apr 2019 01:37:07 -0300 Subject: [PATCH 001/136] Small adjust to make it work with VS2015 and older C# --- DiztinGUIsh/Data.cs | 6 ++++-- DiztinGUIsh/ExportDisassembly.cs | 3 ++- DiztinGUIsh/GotoDialog.cs | 15 ++++++++++----- DiztinGUIsh/LogCreator.cs | 6 ++++-- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/DiztinGUIsh/Data.cs b/DiztinGUIsh/Data.cs index 7c7ce5a4..325f5461 100644 --- a/DiztinGUIsh/Data.cs +++ b/DiztinGUIsh/Data.cs @@ -210,7 +210,8 @@ public static void SetMXFlags(int i, int mx) public static string GetLabel(int i) { - if (alias.TryGetValue(i, out string val)) return val; + string val; + if (alias.TryGetValue(i, out val)) return val; return ""; } @@ -227,7 +228,8 @@ public static Dictionary GetAllLabels() public static string GetComment(int i) { - if (comment.TryGetValue(i, out string val)) return val; + string val; + if (comment.TryGetValue(i, out val)) return val; return ""; } diff --git a/DiztinGUIsh/ExportDisassembly.cs b/DiztinGUIsh/ExportDisassembly.cs index 5ea2b84c..54481826 100644 --- a/DiztinGUIsh/ExportDisassembly.cs +++ b/DiztinGUIsh/ExportDisassembly.cs @@ -80,7 +80,8 @@ private bool ValidateFormat() if (!LogCreator.parameters.ContainsKey(kind)) return false; // not valid if parameter isn't an integer - if (indexOfColon >= 0 && !int.TryParse(tokens[i].Substring(indexOfColon + 1), out int oof)) return false; + int oof; + if (indexOfColon >= 0 && !int.TryParse(tokens[i].Substring(indexOfColon + 1), out oof)) return false; } return true; diff --git a/DiztinGUIsh/GotoDialog.cs b/DiztinGUIsh/GotoDialog.cs index 4ff67e28..99389b8a 100644 --- a/DiztinGUIsh/GotoDialog.cs +++ b/DiztinGUIsh/GotoDialog.cs @@ -27,8 +27,9 @@ private void GotoDialog_Load(object sender, EventArgs e) public int GetOffset() { + int offset; NumberStyles style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; - if (int.TryParse(textPC.Text, style, null, out int offset)) return offset; + if (int.TryParse(textPC.Text, style, null, out offset)) return offset; return -1; } @@ -45,9 +46,10 @@ private void textROM_TextChanged(object sender, EventArgs e) { updatingText = true; + int address; NumberStyles style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; Util.NumberBase noBase = radioDec.Checked ? Util.NumberBase.Decimal : Util.NumberBase.Hexadecimal; - if (int.TryParse(textROM.Text, style, null, out int address)) + if (int.TryParse(textROM.Text, style, null, out address)) { int pc = Util.ConvertSNEStoPC(address); if (pc >= 0 && pc < Data.GetROMSize()) textPC.Text = Util.NumberToBaseString(pc, noBase, 0); @@ -64,7 +66,8 @@ private void textPC_TextChanged(object sender, EventArgs e) NumberStyles style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; Util.NumberBase noBase = radioDec.Checked ? Util.NumberBase.Decimal : Util.NumberBase.Hexadecimal; - if (int.TryParse(textPC.Text, style, null, out int offset)) + int offset; + if (int.TryParse(textPC.Text, style, null, out offset)) { int addr = Util.ConvertPCtoSNES(offset); if (addr >= 0) textROM.Text = Util.NumberToBaseString(addr, noBase, 6); @@ -97,13 +100,15 @@ private void radioHex_CheckedChanged(object sender, EventArgs e) { if (radioHex.Checked) { - if (int.TryParse(textPC.Text, out int result)) + int result; + if (int.TryParse(textPC.Text, out result)) { textPC.Text = Util.NumberToBaseString(result, Util.NumberBase.Hexadecimal, 0); } } else { - if (int.TryParse(textPC.Text, NumberStyles.HexNumber, null, out int result)) + int result; + if (int.TryParse(textPC.Text, NumberStyles.HexNumber, null, out result)) { textPC.Text = result.ToString(); } diff --git a/DiztinGUIsh/LogCreator.cs b/DiztinGUIsh/LogCreator.cs index 6181aeb5..8403c929 100644 --- a/DiztinGUIsh/LogCreator.cs +++ b/DiztinGUIsh/LogCreator.cs @@ -111,7 +111,8 @@ public static int CreateLog(StreamWriter sw, StreamWriter er) bank = snes >> 16; } - if ((Data.GetInOutPoint(pointer) & (Data.InOutPoint.ReadPoint)) != 0 || (tempAlias.TryGetValue(pointer, out string label) && label.Length > 0)) sw.WriteLine(GetLine(pointer, "empty")); + string label; + if ((Data.GetInOutPoint(pointer) & (Data.InOutPoint.ReadPoint)) != 0 || (tempAlias.TryGetValue(pointer, out label) && label.Length > 0)) sw.WriteLine(GetLine(pointer, "empty")); sw.WriteLine(GetLine(pointer, null)); if ((Data.GetInOutPoint(pointer) & (Data.InOutPoint.EndPoint)) != 0) sw.WriteLine(GetLine(pointer, "empty")); pointer += GetLineByteLength(pointer); @@ -262,7 +263,8 @@ private static int GetLineByteLength(int offset) public static string GetParameter(int offset, string parameter, int length) { - if (parameters.TryGetValue(parameter, out Tuple, int> tup)) return tup.Item1.Invoke(offset, length); + Tuple, int> tup; + if (parameters.TryGetValue(parameter, out tup)) return tup.Item1.Invoke(offset, length); return ""; } From 154f139abf4810d0833966c4fa83148c892e2318 Mon Sep 17 00:00:00 2001 From: Vitor Vilela Date: Mon, 22 Apr 2019 02:09:59 -0300 Subject: [PATCH 002/136] Add SA-1 ROM support. --- DiztinGUIsh/Data.cs | 2 +- DiztinGUIsh/ImportROMDialog.Designer.cs | 4 ++- DiztinGUIsh/ImportROMDialog.cs | 19 +++++++++++++- DiztinGUIsh/LogCreator.cs | 2 ++ DiztinGUIsh/Util.cs | 35 +++++++++++++++++++++++-- 5 files changed, 57 insertions(+), 5 deletions(-) diff --git a/DiztinGUIsh/Data.cs b/DiztinGUIsh/Data.cs index 325f5461..72cd170c 100644 --- a/DiztinGUIsh/Data.cs +++ b/DiztinGUIsh/Data.cs @@ -45,7 +45,7 @@ public enum InOutPoint : byte public enum ROMMapMode : byte { - LoROM, HiROM, ExHiROM + LoROM, HiROM, ExHiROM, SA1ROM, ExSA1ROM } public enum ROMSpeed : byte diff --git a/DiztinGUIsh/ImportROMDialog.Designer.cs b/DiztinGUIsh/ImportROMDialog.Designer.cs index 7e4b32f3..8db45b9b 100644 --- a/DiztinGUIsh/ImportROMDialog.Designer.cs +++ b/DiztinGUIsh/ImportROMDialog.Designer.cs @@ -106,7 +106,9 @@ private void InitializeComponent() this.comboBox1.Items.AddRange(new object[] { "LoROM", "HiROM", - "ExHiROM"}); + "ExHiROM", + "SA-1 ROM", + "SA-1 ROM (FuSoYa\'s 8MB mapper)"}); this.comboBox1.Location = new System.Drawing.Point(103, 18); this.comboBox1.Name = "comboBox1"; this.comboBox1.Size = new System.Drawing.Size(121, 21); diff --git a/DiztinGUIsh/ImportROMDialog.cs b/DiztinGUIsh/ImportROMDialog.cs index b9cb8f54..bb9a43a1 100644 --- a/DiztinGUIsh/ImportROMDialog.cs +++ b/DiztinGUIsh/ImportROMDialog.cs @@ -93,7 +93,22 @@ public Dictionary GetGeneratedLabels() private Data.ROMMapMode DetectROMMapMode() { - if ((data[Data.LOROM_SETTING_OFFSET] & 0xEC) == 0x20) + if ((data[Data.LOROM_SETTING_OFFSET] == 0x23)) + { + if (data.Length > 0x400000) + { + detectMessage.Text = "ROM Map Mode Detected: SA-1 ROM (FuSoYa's 8MB mapper)"; + comboBox1.SelectedIndex = 4; + return Data.ROMMapMode.ExSA1ROM; + } + else + { + detectMessage.Text = "ROM Map Mode Detected: SA-1 ROM"; + comboBox1.SelectedIndex = 3; + return Data.ROMMapMode.SA1ROM; + } + } + else if ((data[Data.LOROM_SETTING_OFFSET] & 0xEC) == 0x20) { detectMessage.Text = "ROM Map Mode Detected: LoROM"; comboBox1.SelectedIndex = 0; @@ -202,6 +217,8 @@ private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) case 0: mode = Data.ROMMapMode.LoROM; break; case 1: mode = Data.ROMMapMode.HiROM; break; case 2: mode = Data.ROMMapMode.ExHiROM; break; + case 3: mode = Data.ROMMapMode.SA1ROM; break; + case 4: mode = Data.ROMMapMode.ExSA1ROM; break; } UpdateOffsetAndSpeed(); UpdateTextboxes(); diff --git a/DiztinGUIsh/LogCreator.cs b/DiztinGUIsh/LogCreator.cs index 8403c929..8c1bee16 100644 --- a/DiztinGUIsh/LogCreator.cs +++ b/DiztinGUIsh/LogCreator.cs @@ -348,6 +348,8 @@ private static string GetMap(int offset, int length) case Data.ROMMapMode.LoROM: s = "lorom"; break; case Data.ROMMapMode.HiROM: s = "hirom"; break; case Data.ROMMapMode.ExHiROM: s = "exhirom"; break; + case Data.ROMMapMode.SA1ROM: s = "sa1rom"; break; + case Data.ROMMapMode.ExSA1ROM: s = "exsa1rom"; break; } return string.Format("{0," + (length * -1) + "}", s); } diff --git a/DiztinGUIsh/Util.cs b/DiztinGUIsh/Util.cs index 9d5143f5..b7173c29 100644 --- a/DiztinGUIsh/Util.cs +++ b/DiztinGUIsh/Util.cs @@ -154,11 +154,23 @@ public static int ConvertPCtoSNES(int offset) offset |= 0x400000; if (Data.GetROMSpeed() == Data.ROMSpeed.FastROM || offset >= 0x7E0000) offset |= 0x800000; } - else // if (Data.GetROMMapMode() == Data.ROMMapMode.ExHiROM) + else if (Data.GetROMMapMode() == Data.ROMMapMode.ExHiROM) { if (offset < 0x40000) offset |= 0xC00000; else if (offset >= 0x7E0000) offset &= 0x3FFFFF; } + else + { + if (offset >= 0x400000 && Data.GetROMMapMode() == Data.ROMMapMode.ExSA1ROM) + { + offset += 0x800000; + } + else + { + offset = ((offset & 0x3F8000) << 1) | 0x8000 | (offset & 0x7FFF); + if (offset >= 0x400000) offset += 0x400000; + } + } return offset; } @@ -179,9 +191,28 @@ public static int ConvertSNEStoPC(int address) } else if (Data.GetROMMapMode() == Data.ROMMapMode.HiROM) { return UnmirroredOffset(address & 0x3FFFFF); - } else // if (Data.GetROMMapMode() == Data.ROMMapMode.ExHiROM) + } else if (Data.GetROMMapMode() == Data.ROMMapMode.ExHiROM) { return UnmirroredOffset(((~address & 0x800000) >> 1) | (address & 0x3FFFFF)); + } else + { + // BW-RAM is N/A to PC addressing + if (address >= 0x400000 && address <= 0x7FFFFF) return -1; + + if (address >= 0xC00000) + { + if (Data.GetROMMapMode() == Data.ROMMapMode.ExSA1ROM) return UnmirroredOffset(address & 0x7FFFFF); + else return UnmirroredOffset(address & 0x3FFFFF); + } + else + { + if (address >= 0x800000) address -= 0x400000; + + // SRAM is N/A to PC addressing + if (((address & 0x8000) == 0)) return -1; + + return UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); + } } } From d1a8d5ca93e84ba687dfcca2c3b4a89409446ade Mon Sep 17 00:00:00 2001 From: Vitor Vilela Date: Sat, 27 Apr 2019 18:39:14 -0300 Subject: [PATCH 003/136] Paint data bank cell if current opcode is MVN/MVP. --- DiztinGUIsh/static/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiztinGUIsh/static/Util.cs b/DiztinGUIsh/static/Util.cs index 197a3c1e..18424e97 100644 --- a/DiztinGUIsh/static/Util.cs +++ b/DiztinGUIsh/static/Util.cs @@ -434,7 +434,7 @@ public static void PaintCell(int offset, DataGridViewCellStyle style, int column ) style.BackColor = Color.Yellow; break; case 8: // Data Bank - if (opcode == 0xAB) // PLB + if (opcode == 0xAB || opcode == 0x44 || opcode == 0x54) // PLB MVP MVN style.BackColor = Color.OrangeRed; else if (opcode == 0x8B) // PHB style.BackColor = Color.Yellow; From d9f3da1acada5dbc8b1f4f304caa528cf74cad55 Mon Sep 17 00:00:00 2001 From: Vitor Vilela Date: Sat, 27 Apr 2019 18:39:14 -0300 Subject: [PATCH 004/136] Paint data bank cell if current opcode is MVN/MVP. --- DiztinGUIsh/static/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiztinGUIsh/static/Util.cs b/DiztinGUIsh/static/Util.cs index 197a3c1e..18424e97 100644 --- a/DiztinGUIsh/static/Util.cs +++ b/DiztinGUIsh/static/Util.cs @@ -434,7 +434,7 @@ public static void PaintCell(int offset, DataGridViewCellStyle style, int column ) style.BackColor = Color.Yellow; break; case 8: // Data Bank - if (opcode == 0xAB) // PLB + if (opcode == 0xAB || opcode == 0x44 || opcode == 0x54) // PLB MVP MVN style.BackColor = Color.OrangeRed; else if (opcode == 0x8B) // PHB style.BackColor = Color.Yellow; From cb57227163057c4c8a8db95bd593a881d802bc00 Mon Sep 17 00:00:00 2001 From: Vitor Vilela Date: Sun, 2 Jun 2019 14:41:10 -0300 Subject: [PATCH 005/136] Add support for imporing usage maps --- DiztinGUIsh/static/Data.cs | 11 + DiztinGUIsh/static/diz/Manager.cs | 51 +++ DiztinGUIsh/window/MainWindow.Designer.cs | 364 +++++++++++----------- DiztinGUIsh/window/MainWindow.cs | 11 + DiztinGUIsh/window/MainWindow.resx | 3 + 5 files changed, 266 insertions(+), 174 deletions(-) diff --git a/DiztinGUIsh/static/Data.cs b/DiztinGUIsh/static/Data.cs index 6dbda335..706a0301 100644 --- a/DiztinGUIsh/static/Data.cs +++ b/DiztinGUIsh/static/Data.cs @@ -43,6 +43,17 @@ public enum InOutPoint : byte ReadPoint = 0x08 } + [Flags] + public enum BsnesPlusUsage : byte + { + UsageRead = 0x80, + UsageWrite = 0x40, + UsageExec = 0x20, + UsageOpcode = 0x10, + UsageFlagM = 0x02, + UsageFlagX = 0x01, + }; + public enum ROMMapMode : byte { LoROM, HiROM, ExHiROM, SA1ROM, ExSA1ROM diff --git a/DiztinGUIsh/static/diz/Manager.cs b/DiztinGUIsh/static/diz/Manager.cs index f7e1888f..aa88c0db 100644 --- a/DiztinGUIsh/static/diz/Manager.cs +++ b/DiztinGUIsh/static/diz/Manager.cs @@ -239,5 +239,56 @@ public static void RescanInOutPoints() Project.unsavedChanges = true; } + + public static int ImportUsageMap(byte[] usageMap) + { + int size = Data.GetROMSize(); + bool unsaved = false; + int modified = 0; + + for (int i = 0; i < size; i++) + { + // TODO: get every single possible SNES address for mapping. + var map = Util.ConvertPCtoSNES(i); + + var flags = (Data.BsnesPlusUsage)usageMap[map]; + + if (flags == 0) + { + // no information available + continue; + } + + if (Data.GetFlag(i) != Data.FlagType.Unreached) + { + // skip if there is something already set.. + continue; + } + + // opcode: 0x30, operand: 0x20 + if (flags.HasFlag(Data.BsnesPlusUsage.UsageExec)) + { + Data.SetFlag(i, Data.FlagType.Operand); + + if (flags.HasFlag(Data.BsnesPlusUsage.UsageOpcode)) + { + Data.SetFlag(i, Data.FlagType.Opcode); + } + + Data.SetMXFlags(i, ((int)flags & 3) << 4); + unsaved = true; + modified++; + } + else if (flags.HasFlag(Data.BsnesPlusUsage.UsageRead)) + { + Data.SetFlag(i, Data.FlagType.Data8Bit); + unsaved = true; + modified++; + } + } + + Project.unsavedChanges |= unsaved; + return modified; + } } } diff --git a/DiztinGUIsh/window/MainWindow.Designer.cs b/DiztinGUIsh/window/MainWindow.Designer.cs index 20295ffd..1645bd21 100644 --- a/DiztinGUIsh/window/MainWindow.Designer.cs +++ b/DiztinGUIsh/window/MainWindow.Designer.cs @@ -44,6 +44,19 @@ private void InitializeComponent() System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle13 = new System.Windows.Forms.DataGridViewCellStyle(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainWindow)); this.table = new System.Windows.Forms.DataGridView(); + this.ColumnAlias = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnPC = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnChar = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnHex = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnPoints = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnInstruction = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnIA = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnFlag = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnDB = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnDP = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnM = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnX = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnComment = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.menuStrip1 = new System.Windows.Forms.MenuStrip(); this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.newProjectToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -103,6 +116,8 @@ private void InitializeComponent() this.decimalToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.hexadecimalToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.binaryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.optionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.moveWithStepToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.viewHelpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.githubToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -117,21 +132,8 @@ private void InitializeComponent() this.vScrollBar1 = new System.Windows.Forms.VScrollBar(); this.saveLogSingleFile = new System.Windows.Forms.SaveFileDialog(); this.chooseLogFolder = new System.Windows.Forms.FolderBrowserDialog(); - this.ColumnAlias = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnPC = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnChar = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnHex = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnPoints = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnInstruction = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnIA = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnFlag = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnDB = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnDP = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnM = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnX = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnComment = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.optionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.moveWithStepToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.importUsageMapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.openUsageMapFile = new System.Windows.Forms.OpenFileDialog(); ((System.ComponentModel.ISupportInitialize)(this.table)).BeginInit(); this.menuStrip1.SuspendLayout(); this.statusStrip1.SuspendLayout(); @@ -186,6 +188,149 @@ private void InitializeComponent() this.table.MouseDown += new System.Windows.Forms.MouseEventHandler(this.table_MouseDown); this.table.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.table_MouseWheel); // + // ColumnAlias + // + dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; + dataGridViewCellStyle1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnAlias.DefaultCellStyle = dataGridViewCellStyle1; + this.ColumnAlias.HeaderText = "Label"; + this.ColumnAlias.MaxInputLength = 20; + this.ColumnAlias.Name = "ColumnAlias"; + this.ColumnAlias.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + // + // ColumnPC + // + dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle2.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnPC.DefaultCellStyle = dataGridViewCellStyle2; + this.ColumnPC.HeaderText = "PC"; + this.ColumnPC.MaxInputLength = 6; + this.ColumnPC.Name = "ColumnPC"; + this.ColumnPC.ReadOnly = true; + this.ColumnPC.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnPC.Width = 45; + // + // ColumnChar + // + dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; + dataGridViewCellStyle3.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnChar.DefaultCellStyle = dataGridViewCellStyle3; + this.ColumnChar.HeaderText = "@"; + this.ColumnChar.MaxInputLength = 1; + this.ColumnChar.Name = "ColumnChar"; + this.ColumnChar.ReadOnly = true; + this.ColumnChar.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnChar.Width = 26; + // + // ColumnHex + // + dataGridViewCellStyle4.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; + dataGridViewCellStyle4.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnHex.DefaultCellStyle = dataGridViewCellStyle4; + this.ColumnHex.HeaderText = "#"; + this.ColumnHex.MaxInputLength = 3; + this.ColumnHex.Name = "ColumnHex"; + this.ColumnHex.ReadOnly = true; + this.ColumnHex.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnHex.Width = 20; + // + // ColumnPoints + // + dataGridViewCellStyle5.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle5.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnPoints.DefaultCellStyle = dataGridViewCellStyle5; + this.ColumnPoints.HeaderText = "<*>"; + this.ColumnPoints.MaxInputLength = 3; + this.ColumnPoints.Name = "ColumnPoints"; + this.ColumnPoints.ReadOnly = true; + this.ColumnPoints.Width = 26; + // + // ColumnInstruction + // + dataGridViewCellStyle6.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle6.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnInstruction.DefaultCellStyle = dataGridViewCellStyle6; + this.ColumnInstruction.HeaderText = "Instruction"; + this.ColumnInstruction.MaxInputLength = 64; + this.ColumnInstruction.Name = "ColumnInstruction"; + this.ColumnInstruction.ReadOnly = true; + this.ColumnInstruction.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + // + // ColumnIA + // + dataGridViewCellStyle7.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle7.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnIA.DefaultCellStyle = dataGridViewCellStyle7; + this.ColumnIA.HeaderText = "IA"; + this.ColumnIA.MaxInputLength = 6; + this.ColumnIA.Name = "ColumnIA"; + this.ColumnIA.ReadOnly = true; + this.ColumnIA.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnIA.Width = 45; + // + // ColumnFlag + // + dataGridViewCellStyle8.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnFlag.DefaultCellStyle = dataGridViewCellStyle8; + this.ColumnFlag.HeaderText = "Flag"; + this.ColumnFlag.Name = "ColumnFlag"; + this.ColumnFlag.ReadOnly = true; + this.ColumnFlag.Width = 80; + // + // ColumnDB + // + dataGridViewCellStyle9.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; + dataGridViewCellStyle9.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnDB.DefaultCellStyle = dataGridViewCellStyle9; + this.ColumnDB.HeaderText = "B"; + this.ColumnDB.MaxInputLength = 2; + this.ColumnDB.Name = "ColumnDB"; + this.ColumnDB.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnDB.Width = 20; + // + // ColumnDP + // + dataGridViewCellStyle10.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle10.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnDP.DefaultCellStyle = dataGridViewCellStyle10; + this.ColumnDP.HeaderText = "D"; + this.ColumnDP.MaxInputLength = 4; + this.ColumnDP.Name = "ColumnDP"; + this.ColumnDP.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnDP.Width = 32; + // + // ColumnM + // + dataGridViewCellStyle11.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle11.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnM.DefaultCellStyle = dataGridViewCellStyle11; + this.ColumnM.HeaderText = "M"; + this.ColumnM.MaxInputLength = 2; + this.ColumnM.Name = "ColumnM"; + this.ColumnM.ReadOnly = true; + this.ColumnM.Width = 20; + // + // ColumnX + // + dataGridViewCellStyle12.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle12.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnX.DefaultCellStyle = dataGridViewCellStyle12; + this.ColumnX.HeaderText = "X"; + this.ColumnX.MaxInputLength = 2; + this.ColumnX.Name = "ColumnX"; + this.ColumnX.ReadOnly = true; + this.ColumnX.Width = 20; + // + // ColumnComment + // + this.ColumnComment.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + dataGridViewCellStyle13.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle13.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnComment.DefaultCellStyle = dataGridViewCellStyle13; + this.ColumnComment.HeaderText = "Comment"; + this.ColumnComment.Name = "ColumnComment"; + this.ColumnComment.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + // // menuStrip1 // this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -210,6 +355,7 @@ private void InitializeComponent() this.exportLogToolStripMenuItem, this.importCDLToolStripMenuItem, this.importTraceLogToolStripMenuItem, + this.importUsageMapToolStripMenuItem, this.toolStripSeparator7, this.exitToolStripMenuItem}); this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; @@ -691,6 +837,23 @@ private void InitializeComponent() this.binaryToolStripMenuItem.Text = "Binary"; this.binaryToolStripMenuItem.Click += new System.EventHandler(this.binaryToolStripMenuItem_Click); // + // optionsToolStripMenuItem + // + this.optionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.moveWithStepToolStripMenuItem}); + this.optionsToolStripMenuItem.Name = "optionsToolStripMenuItem"; + this.optionsToolStripMenuItem.Size = new System.Drawing.Size(212, 22); + this.optionsToolStripMenuItem.Text = "Options"; + // + // moveWithStepToolStripMenuItem + // + this.moveWithStepToolStripMenuItem.Checked = true; + this.moveWithStepToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; + this.moveWithStepToolStripMenuItem.Name = "moveWithStepToolStripMenuItem"; + this.moveWithStepToolStripMenuItem.Size = new System.Drawing.Size(158, 22); + this.moveWithStepToolStripMenuItem.Text = "Move With Step"; + this.moveWithStepToolStripMenuItem.Click += new System.EventHandler(this.moveWithStepToolStripMenuItem_Click); + // // helpToolStripMenuItem // this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -705,21 +868,21 @@ private void InitializeComponent() // this.viewHelpToolStripMenuItem.Name = "viewHelpToolStripMenuItem"; this.viewHelpToolStripMenuItem.ShortcutKeys = System.Windows.Forms.Keys.F1; - this.viewHelpToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.viewHelpToolStripMenuItem.Size = new System.Drawing.Size(146, 22); this.viewHelpToolStripMenuItem.Text = "View Help"; this.viewHelpToolStripMenuItem.Click += new System.EventHandler(this.viewHelpToolStripMenuItem_Click); // // githubToolStripMenuItem // this.githubToolStripMenuItem.Name = "githubToolStripMenuItem"; - this.githubToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.githubToolStripMenuItem.Size = new System.Drawing.Size(146, 22); this.githubToolStripMenuItem.Text = "Github"; this.githubToolStripMenuItem.Click += new System.EventHandler(this.githubToolStripMenuItem_Click); // // aboutToolStripMenuItem // this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem"; - this.aboutToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.aboutToolStripMenuItem.Size = new System.Drawing.Size(146, 22); this.aboutToolStripMenuItem.Text = "About"; this.aboutToolStripMenuItem.Click += new System.EventHandler(this.aboutToolStripMenuItem_Click); // @@ -781,165 +944,16 @@ private void InitializeComponent() // this.saveLogSingleFile.Filter = "Assembly Files|*.asm|All Files|*.*"; // - // ColumnAlias + // importUsageMapToolStripMenuItem // - dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; - dataGridViewCellStyle1.Font = new System.Drawing.Font("Arial Narrow", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnAlias.DefaultCellStyle = dataGridViewCellStyle1; - this.ColumnAlias.HeaderText = "Label"; - this.ColumnAlias.MaxInputLength = 20; - this.ColumnAlias.Name = "ColumnAlias"; - this.ColumnAlias.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.importUsageMapToolStripMenuItem.Name = "importUsageMapToolStripMenuItem"; + this.importUsageMapToolStripMenuItem.Size = new System.Drawing.Size(235, 22); + this.importUsageMapToolStripMenuItem.Text = "Import Usage Map..."; + this.importUsageMapToolStripMenuItem.Click += new System.EventHandler(this.ImportUsageMapToolStripMenuItem_Click); // - // ColumnPC + // openUsageMapFile // - dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle2.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnPC.DefaultCellStyle = dataGridViewCellStyle2; - this.ColumnPC.HeaderText = "PC"; - this.ColumnPC.MaxInputLength = 6; - this.ColumnPC.Name = "ColumnPC"; - this.ColumnPC.ReadOnly = true; - this.ColumnPC.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnPC.Width = 45; - // - // ColumnChar - // - dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; - dataGridViewCellStyle3.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnChar.DefaultCellStyle = dataGridViewCellStyle3; - this.ColumnChar.HeaderText = "@"; - this.ColumnChar.MaxInputLength = 1; - this.ColumnChar.Name = "ColumnChar"; - this.ColumnChar.ReadOnly = true; - this.ColumnChar.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnChar.Width = 26; - // - // ColumnHex - // - dataGridViewCellStyle4.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; - dataGridViewCellStyle4.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnHex.DefaultCellStyle = dataGridViewCellStyle4; - this.ColumnHex.HeaderText = "#"; - this.ColumnHex.MaxInputLength = 3; - this.ColumnHex.Name = "ColumnHex"; - this.ColumnHex.ReadOnly = true; - this.ColumnHex.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnHex.Width = 20; - // - // ColumnPoints - // - dataGridViewCellStyle5.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; - dataGridViewCellStyle5.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnPoints.DefaultCellStyle = dataGridViewCellStyle5; - this.ColumnPoints.HeaderText = "<*>"; - this.ColumnPoints.MaxInputLength = 3; - this.ColumnPoints.Name = "ColumnPoints"; - this.ColumnPoints.ReadOnly = true; - this.ColumnPoints.Width = 26; - // - // ColumnInstruction - // - dataGridViewCellStyle6.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle6.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnInstruction.DefaultCellStyle = dataGridViewCellStyle6; - this.ColumnInstruction.HeaderText = "Instruction"; - this.ColumnInstruction.MaxInputLength = 64; - this.ColumnInstruction.Name = "ColumnInstruction"; - this.ColumnInstruction.ReadOnly = true; - this.ColumnInstruction.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - // - // ColumnIA - // - dataGridViewCellStyle7.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle7.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnIA.DefaultCellStyle = dataGridViewCellStyle7; - this.ColumnIA.HeaderText = "IA"; - this.ColumnIA.MaxInputLength = 6; - this.ColumnIA.Name = "ColumnIA"; - this.ColumnIA.ReadOnly = true; - this.ColumnIA.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnIA.Width = 45; - // - // ColumnFlag - // - dataGridViewCellStyle8.Font = new System.Drawing.Font("Arial Narrow", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnFlag.DefaultCellStyle = dataGridViewCellStyle8; - this.ColumnFlag.HeaderText = "Flag"; - this.ColumnFlag.Name = "ColumnFlag"; - this.ColumnFlag.ReadOnly = true; - this.ColumnFlag.Width = 80; - // - // ColumnDB - // - dataGridViewCellStyle9.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; - dataGridViewCellStyle9.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnDB.DefaultCellStyle = dataGridViewCellStyle9; - this.ColumnDB.HeaderText = "B"; - this.ColumnDB.MaxInputLength = 2; - this.ColumnDB.Name = "ColumnDB"; - this.ColumnDB.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnDB.Width = 20; - // - // ColumnDP - // - dataGridViewCellStyle10.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle10.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnDP.DefaultCellStyle = dataGridViewCellStyle10; - this.ColumnDP.HeaderText = "D"; - this.ColumnDP.MaxInputLength = 4; - this.ColumnDP.Name = "ColumnDP"; - this.ColumnDP.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnDP.Width = 32; - // - // ColumnM - // - dataGridViewCellStyle11.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; - dataGridViewCellStyle11.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnM.DefaultCellStyle = dataGridViewCellStyle11; - this.ColumnM.HeaderText = "M"; - this.ColumnM.MaxInputLength = 2; - this.ColumnM.Name = "ColumnM"; - this.ColumnM.ReadOnly = true; - this.ColumnM.Width = 20; - // - // ColumnX - // - dataGridViewCellStyle12.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; - dataGridViewCellStyle12.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnX.DefaultCellStyle = dataGridViewCellStyle12; - this.ColumnX.HeaderText = "X"; - this.ColumnX.MaxInputLength = 2; - this.ColumnX.Name = "ColumnX"; - this.ColumnX.ReadOnly = true; - this.ColumnX.Width = 20; - // - // ColumnComment - // - this.ColumnComment.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; - dataGridViewCellStyle13.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle13.Font = new System.Drawing.Font("Arial Narrow", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnComment.DefaultCellStyle = dataGridViewCellStyle13; - this.ColumnComment.HeaderText = "Comment"; - this.ColumnComment.Name = "ColumnComment"; - this.ColumnComment.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - // - // optionsToolStripMenuItem - // - this.optionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.moveWithStepToolStripMenuItem}); - this.optionsToolStripMenuItem.Name = "optionsToolStripMenuItem"; - this.optionsToolStripMenuItem.Size = new System.Drawing.Size(212, 22); - this.optionsToolStripMenuItem.Text = "Options"; - // - // moveWithStepToolStripMenuItem - // - this.moveWithStepToolStripMenuItem.Checked = true; - this.moveWithStepToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; - this.moveWithStepToolStripMenuItem.Name = "moveWithStepToolStripMenuItem"; - this.moveWithStepToolStripMenuItem.Size = new System.Drawing.Size(180, 22); - this.moveWithStepToolStripMenuItem.Text = "Move With Step"; - this.moveWithStepToolStripMenuItem.Click += new System.EventHandler(this.moveWithStepToolStripMenuItem_Click); + this.openUsageMapFile.Filter = "bsnes-plus usage map files|*.bin"; // // MainWindow // @@ -1060,6 +1074,8 @@ private void InitializeComponent() private System.Windows.Forms.DataGridViewTextBoxColumn ColumnComment; private System.Windows.Forms.ToolStripMenuItem optionsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem moveWithStepToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem importUsageMapToolStripMenuItem; + private System.Windows.Forms.OpenFileDialog openUsageMapFile; } } diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index a92a4ad6..71eea333 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -791,5 +791,16 @@ public OpenFileDialog GetRomOpenFileDialog() { return openROMFile; } + + private void ImportUsageMapToolStripMenuItem_Click(object sender, EventArgs e) + { + if (openUsageMapFile.ShowDialog() == DialogResult.OK) + { + int total = Manager.ImportUsageMap(File.ReadAllBytes(openUsageMapFile.FileName)); + + MessageBox.Show($"Modified total {total} flags!", "Done", + MessageBoxButtons.OK, MessageBoxIcon.Information); + } + } } } diff --git a/DiztinGUIsh/window/MainWindow.resx b/DiztinGUIsh/window/MainWindow.resx index b541887c..3c39bd17 100644 --- a/DiztinGUIsh/window/MainWindow.resx +++ b/DiztinGUIsh/window/MainWindow.resx @@ -177,6 +177,9 @@ 808, 17 + + 953, 17 + From afb55a1cec8a3cf69b71889b11ed4c020193acc5 Mon Sep 17 00:00:00 2001 From: Vitor Vilela Date: Sun, 2 Jun 2019 14:57:48 -0300 Subject: [PATCH 006/136] Add high DPI support --- DiztinGUIsh/Program.cs | 8 + DiztinGUIsh/window/MainWindow.Designer.cs | 193 ++++++++++++---------- DiztinGUIsh/window/MainWindow.cs | 7 + 3 files changed, 122 insertions(+), 86 deletions(-) diff --git a/DiztinGUIsh/Program.cs b/DiztinGUIsh/Program.cs index 8a0954e1..84bcd0e0 100644 --- a/DiztinGUIsh/Program.cs +++ b/DiztinGUIsh/Program.cs @@ -14,6 +14,11 @@ static class Program [STAThread] static void Main(string[] args) { + if (Environment.OSVersion.Version.Major >= 6) + { + SetProcessDPIAware(); + } + Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); MainWindow window = new MainWindow(); @@ -22,5 +27,8 @@ static void Main(string[] args) Application.Run(window); } + + [System.Runtime.InteropServices.DllImport("user32.dll")] + private static extern bool SetProcessDPIAware(); } } diff --git a/DiztinGUIsh/window/MainWindow.Designer.cs b/DiztinGUIsh/window/MainWindow.Designer.cs index 1645bd21..e71d7de1 100644 --- a/DiztinGUIsh/window/MainWindow.Designer.cs +++ b/DiztinGUIsh/window/MainWindow.Designer.cs @@ -67,6 +67,7 @@ private void InitializeComponent() this.exportLogToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.importCDLToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.importTraceLogToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.importUsageMapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator(); this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -132,7 +133,6 @@ private void InitializeComponent() this.vScrollBar1 = new System.Windows.Forms.VScrollBar(); this.saveLogSingleFile = new System.Windows.Forms.SaveFileDialog(); this.chooseLogFolder = new System.Windows.Forms.FolderBrowserDialog(); - this.importUsageMapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.openUsageMapFile = new System.Windows.Forms.OpenFileDialog(); ((System.ComponentModel.ISupportInitialize)(this.table)).BeginInit(); this.menuStrip1.SuspendLayout(); @@ -169,7 +169,7 @@ private void InitializeComponent() dataGridViewCellStyle14.SelectionForeColor = System.Drawing.SystemColors.HighlightText; dataGridViewCellStyle14.WrapMode = System.Windows.Forms.DataGridViewTriState.False; this.table.DefaultCellStyle = dataGridViewCellStyle14; - this.table.Location = new System.Drawing.Point(0, 24); + this.table.Location = new System.Drawing.Point(0, 30); this.table.Margin = new System.Windows.Forms.Padding(0); this.table.MultiSelect = false; this.table.Name = "table"; @@ -181,7 +181,7 @@ private void InitializeComponent() this.table.ShowCellToolTips = false; this.table.ShowEditingIcon = false; this.table.ShowRowErrors = false; - this.table.Size = new System.Drawing.Size(700, 500); + this.table.Size = new System.Drawing.Size(933, 615); this.table.TabIndex = 0; this.table.VirtualMode = true; this.table.KeyDown += new System.Windows.Forms.KeyEventHandler(this.table_KeyDown); @@ -195,8 +195,10 @@ private void InitializeComponent() this.ColumnAlias.DefaultCellStyle = dataGridViewCellStyle1; this.ColumnAlias.HeaderText = "Label"; this.ColumnAlias.MaxInputLength = 20; + this.ColumnAlias.MinimumWidth = 6; this.ColumnAlias.Name = "ColumnAlias"; this.ColumnAlias.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnAlias.Width = 125; // // ColumnPC // @@ -205,6 +207,7 @@ private void InitializeComponent() this.ColumnPC.DefaultCellStyle = dataGridViewCellStyle2; this.ColumnPC.HeaderText = "PC"; this.ColumnPC.MaxInputLength = 6; + this.ColumnPC.MinimumWidth = 6; this.ColumnPC.Name = "ColumnPC"; this.ColumnPC.ReadOnly = true; this.ColumnPC.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; @@ -217,6 +220,7 @@ private void InitializeComponent() this.ColumnChar.DefaultCellStyle = dataGridViewCellStyle3; this.ColumnChar.HeaderText = "@"; this.ColumnChar.MaxInputLength = 1; + this.ColumnChar.MinimumWidth = 6; this.ColumnChar.Name = "ColumnChar"; this.ColumnChar.ReadOnly = true; this.ColumnChar.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; @@ -229,6 +233,7 @@ private void InitializeComponent() this.ColumnHex.DefaultCellStyle = dataGridViewCellStyle4; this.ColumnHex.HeaderText = "#"; this.ColumnHex.MaxInputLength = 3; + this.ColumnHex.MinimumWidth = 6; this.ColumnHex.Name = "ColumnHex"; this.ColumnHex.ReadOnly = true; this.ColumnHex.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; @@ -241,6 +246,7 @@ private void InitializeComponent() this.ColumnPoints.DefaultCellStyle = dataGridViewCellStyle5; this.ColumnPoints.HeaderText = "<*>"; this.ColumnPoints.MaxInputLength = 3; + this.ColumnPoints.MinimumWidth = 6; this.ColumnPoints.Name = "ColumnPoints"; this.ColumnPoints.ReadOnly = true; this.ColumnPoints.Width = 26; @@ -252,9 +258,11 @@ private void InitializeComponent() this.ColumnInstruction.DefaultCellStyle = dataGridViewCellStyle6; this.ColumnInstruction.HeaderText = "Instruction"; this.ColumnInstruction.MaxInputLength = 64; + this.ColumnInstruction.MinimumWidth = 6; this.ColumnInstruction.Name = "ColumnInstruction"; this.ColumnInstruction.ReadOnly = true; this.ColumnInstruction.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnInstruction.Width = 125; // // ColumnIA // @@ -263,6 +271,7 @@ private void InitializeComponent() this.ColumnIA.DefaultCellStyle = dataGridViewCellStyle7; this.ColumnIA.HeaderText = "IA"; this.ColumnIA.MaxInputLength = 6; + this.ColumnIA.MinimumWidth = 6; this.ColumnIA.Name = "ColumnIA"; this.ColumnIA.ReadOnly = true; this.ColumnIA.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; @@ -273,6 +282,7 @@ private void InitializeComponent() dataGridViewCellStyle8.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.ColumnFlag.DefaultCellStyle = dataGridViewCellStyle8; this.ColumnFlag.HeaderText = "Flag"; + this.ColumnFlag.MinimumWidth = 6; this.ColumnFlag.Name = "ColumnFlag"; this.ColumnFlag.ReadOnly = true; this.ColumnFlag.Width = 80; @@ -284,6 +294,7 @@ private void InitializeComponent() this.ColumnDB.DefaultCellStyle = dataGridViewCellStyle9; this.ColumnDB.HeaderText = "B"; this.ColumnDB.MaxInputLength = 2; + this.ColumnDB.MinimumWidth = 6; this.ColumnDB.Name = "ColumnDB"; this.ColumnDB.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; this.ColumnDB.Width = 20; @@ -295,6 +306,7 @@ private void InitializeComponent() this.ColumnDP.DefaultCellStyle = dataGridViewCellStyle10; this.ColumnDP.HeaderText = "D"; this.ColumnDP.MaxInputLength = 4; + this.ColumnDP.MinimumWidth = 6; this.ColumnDP.Name = "ColumnDP"; this.ColumnDP.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; this.ColumnDP.Width = 32; @@ -306,6 +318,7 @@ private void InitializeComponent() this.ColumnM.DefaultCellStyle = dataGridViewCellStyle11; this.ColumnM.HeaderText = "M"; this.ColumnM.MaxInputLength = 2; + this.ColumnM.MinimumWidth = 6; this.ColumnM.Name = "ColumnM"; this.ColumnM.ReadOnly = true; this.ColumnM.Width = 20; @@ -317,6 +330,7 @@ private void InitializeComponent() this.ColumnX.DefaultCellStyle = dataGridViewCellStyle12; this.ColumnX.HeaderText = "X"; this.ColumnX.MaxInputLength = 2; + this.ColumnX.MinimumWidth = 6; this.ColumnX.Name = "ColumnX"; this.ColumnX.ReadOnly = true; this.ColumnX.Width = 20; @@ -328,11 +342,13 @@ private void InitializeComponent() dataGridViewCellStyle13.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.ColumnComment.DefaultCellStyle = dataGridViewCellStyle13; this.ColumnComment.HeaderText = "Comment"; + this.ColumnComment.MinimumWidth = 6; this.ColumnComment.Name = "ColumnComment"; this.ColumnComment.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; // // menuStrip1 // + this.menuStrip1.ImageScalingSize = new System.Drawing.Size(20, 20); this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.fileToolStripMenuItem, this.editToolStripMenuItem, @@ -340,7 +356,8 @@ private void InitializeComponent() this.helpToolStripMenuItem}); this.menuStrip1.Location = new System.Drawing.Point(0, 0); this.menuStrip1.Name = "menuStrip1"; - this.menuStrip1.Size = new System.Drawing.Size(717, 24); + this.menuStrip1.Padding = new System.Windows.Forms.Padding(8, 2, 0, 2); + this.menuStrip1.Size = new System.Drawing.Size(956, 28); this.menuStrip1.TabIndex = 1; this.menuStrip1.Text = "menuStrip1"; // @@ -359,14 +376,14 @@ private void InitializeComponent() this.toolStripSeparator7, this.exitToolStripMenuItem}); this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; - this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); + this.fileToolStripMenuItem.Size = new System.Drawing.Size(46, 24); this.fileToolStripMenuItem.Text = "&File"; // // newProjectToolStripMenuItem // this.newProjectToolStripMenuItem.Name = "newProjectToolStripMenuItem"; this.newProjectToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.N))); - this.newProjectToolStripMenuItem.Size = new System.Drawing.Size(235, 22); + this.newProjectToolStripMenuItem.Size = new System.Drawing.Size(292, 26); this.newProjectToolStripMenuItem.Text = "New Project..."; this.newProjectToolStripMenuItem.Click += new System.EventHandler(this.newProjectToolStripMenuItem_Click); // @@ -374,7 +391,7 @@ private void InitializeComponent() // this.openProjectToolStripMenuItem.Name = "openProjectToolStripMenuItem"; this.openProjectToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O))); - this.openProjectToolStripMenuItem.Size = new System.Drawing.Size(235, 22); + this.openProjectToolStripMenuItem.Size = new System.Drawing.Size(292, 26); this.openProjectToolStripMenuItem.Text = "Open Project..."; this.openProjectToolStripMenuItem.Click += new System.EventHandler(this.openProjectToolStripMenuItem_Click); // @@ -383,7 +400,7 @@ private void InitializeComponent() this.saveProjectToolStripMenuItem.Enabled = false; this.saveProjectToolStripMenuItem.Name = "saveProjectToolStripMenuItem"; this.saveProjectToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S))); - this.saveProjectToolStripMenuItem.Size = new System.Drawing.Size(235, 22); + this.saveProjectToolStripMenuItem.Size = new System.Drawing.Size(292, 26); this.saveProjectToolStripMenuItem.Text = "Save Project"; this.saveProjectToolStripMenuItem.Click += new System.EventHandler(this.saveProjectToolStripMenuItem_Click); // @@ -393,21 +410,21 @@ private void InitializeComponent() this.saveProjectAsToolStripMenuItem.Name = "saveProjectAsToolStripMenuItem"; this.saveProjectAsToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) | System.Windows.Forms.Keys.S))); - this.saveProjectAsToolStripMenuItem.Size = new System.Drawing.Size(235, 22); + this.saveProjectAsToolStripMenuItem.Size = new System.Drawing.Size(292, 26); this.saveProjectAsToolStripMenuItem.Text = "Save Project As..."; this.saveProjectAsToolStripMenuItem.Click += new System.EventHandler(this.saveProjectAsToolStripMenuItem_Click); // // toolStripSeparator1 // this.toolStripSeparator1.Name = "toolStripSeparator1"; - this.toolStripSeparator1.Size = new System.Drawing.Size(232, 6); + this.toolStripSeparator1.Size = new System.Drawing.Size(289, 6); // // exportLogToolStripMenuItem // this.exportLogToolStripMenuItem.Enabled = false; this.exportLogToolStripMenuItem.Name = "exportLogToolStripMenuItem"; this.exportLogToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.E))); - this.exportLogToolStripMenuItem.Size = new System.Drawing.Size(235, 22); + this.exportLogToolStripMenuItem.Size = new System.Drawing.Size(292, 26); this.exportLogToolStripMenuItem.Text = "Export Disassembly..."; this.exportLogToolStripMenuItem.Click += new System.EventHandler(this.exportLogToolStripMenuItem_Click); // @@ -416,26 +433,34 @@ private void InitializeComponent() this.importCDLToolStripMenuItem.Enabled = false; this.importCDLToolStripMenuItem.Name = "importCDLToolStripMenuItem"; this.importCDLToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.I))); - this.importCDLToolStripMenuItem.Size = new System.Drawing.Size(235, 22); + this.importCDLToolStripMenuItem.Size = new System.Drawing.Size(292, 26); this.importCDLToolStripMenuItem.Text = "Import CDL..."; // // importTraceLogToolStripMenuItem // this.importTraceLogToolStripMenuItem.Enabled = false; this.importTraceLogToolStripMenuItem.Name = "importTraceLogToolStripMenuItem"; - this.importTraceLogToolStripMenuItem.Size = new System.Drawing.Size(235, 22); + this.importTraceLogToolStripMenuItem.Size = new System.Drawing.Size(292, 26); this.importTraceLogToolStripMenuItem.Text = "Import Trace Log..."; // + // importUsageMapToolStripMenuItem + // + this.importUsageMapToolStripMenuItem.Enabled = false; + this.importUsageMapToolStripMenuItem.Name = "importUsageMapToolStripMenuItem"; + this.importUsageMapToolStripMenuItem.Size = new System.Drawing.Size(292, 26); + this.importUsageMapToolStripMenuItem.Text = "Import Usage Map..."; + this.importUsageMapToolStripMenuItem.Click += new System.EventHandler(this.ImportUsageMapToolStripMenuItem_Click); + // // toolStripSeparator7 // this.toolStripSeparator7.Name = "toolStripSeparator7"; - this.toolStripSeparator7.Size = new System.Drawing.Size(232, 6); + this.toolStripSeparator7.Size = new System.Drawing.Size(289, 6); // // exitToolStripMenuItem // this.exitToolStripMenuItem.Name = "exitToolStripMenuItem"; this.exitToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.F4))); - this.exitToolStripMenuItem.Size = new System.Drawing.Size(235, 22); + this.exitToolStripMenuItem.Size = new System.Drawing.Size(292, 26); this.exitToolStripMenuItem.Text = "Exit"; this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click); // @@ -469,32 +494,32 @@ private void InitializeComponent() this.fixMisalignedInstructionsToolStripMenuItem, this.rescanForInOutPointsToolStripMenuItem}); this.editToolStripMenuItem.Name = "editToolStripMenuItem"; - this.editToolStripMenuItem.Size = new System.Drawing.Size(39, 20); + this.editToolStripMenuItem.Size = new System.Drawing.Size(49, 24); this.editToolStripMenuItem.Text = "&Edit"; // // stepOverToolStripMenuItem // this.stepOverToolStripMenuItem.Name = "stepOverToolStripMenuItem"; - this.stepOverToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.stepOverToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.stepOverToolStripMenuItem.Text = "&Step"; this.stepOverToolStripMenuItem.Click += new System.EventHandler(this.stepOverToolStripMenuItem_Click); // // stepInToolStripMenuItem // this.stepInToolStripMenuItem.Name = "stepInToolStripMenuItem"; - this.stepInToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.stepInToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.stepInToolStripMenuItem.Text = "Step &In"; this.stepInToolStripMenuItem.Click += new System.EventHandler(this.stepInToolStripMenuItem_Click); // // toolStripSeparator2 // this.toolStripSeparator2.Name = "toolStripSeparator2"; - this.toolStripSeparator2.Size = new System.Drawing.Size(250, 6); + this.toolStripSeparator2.Size = new System.Drawing.Size(306, 6); // // autoStepSafeToolStripMenuItem // this.autoStepSafeToolStripMenuItem.Name = "autoStepSafeToolStripMenuItem"; - this.autoStepSafeToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.autoStepSafeToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.autoStepSafeToolStripMenuItem.Text = "&Auto Step (Safe)"; this.autoStepSafeToolStripMenuItem.Click += new System.EventHandler(this.autoStepSafeToolStripMenuItem_Click); // @@ -502,55 +527,55 @@ private void InitializeComponent() // this.autoStepHarshToolStripMenuItem.Name = "autoStepHarshToolStripMenuItem"; this.autoStepHarshToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.A))); - this.autoStepHarshToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.autoStepHarshToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.autoStepHarshToolStripMenuItem.Text = "Auto Step (Harsh)"; this.autoStepHarshToolStripMenuItem.Click += new System.EventHandler(this.autoStepHarshToolStripMenuItem_Click); // // toolStripSeparator3 // this.toolStripSeparator3.Name = "toolStripSeparator3"; - this.toolStripSeparator3.Size = new System.Drawing.Size(250, 6); + this.toolStripSeparator3.Size = new System.Drawing.Size(306, 6); // // gotoToolStripMenuItem // this.gotoToolStripMenuItem.Name = "gotoToolStripMenuItem"; this.gotoToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.G))); - this.gotoToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.gotoToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.gotoToolStripMenuItem.Text = "Goto..."; this.gotoToolStripMenuItem.Click += new System.EventHandler(this.gotoToolStripMenuItem_Click); // // gotoIntermediateAddressToolStripMenuItem // this.gotoIntermediateAddressToolStripMenuItem.Name = "gotoIntermediateAddressToolStripMenuItem"; - this.gotoIntermediateAddressToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.gotoIntermediateAddressToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.gotoIntermediateAddressToolStripMenuItem.Text = "Goto In&termediate Address"; this.gotoIntermediateAddressToolStripMenuItem.Click += new System.EventHandler(this.gotoIntermediateAddressToolStripMenuItem_Click); // // gotoFirstUnreachedToolStripMenuItem // this.gotoFirstUnreachedToolStripMenuItem.Name = "gotoFirstUnreachedToolStripMenuItem"; - this.gotoFirstUnreachedToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.gotoFirstUnreachedToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.gotoFirstUnreachedToolStripMenuItem.Text = "Goto First &Unreached"; this.gotoFirstUnreachedToolStripMenuItem.Click += new System.EventHandler(this.gotoFirstUnreachedToolStripMenuItem_Click); // // gotoNearUnreachedToolStripMenuItem // this.gotoNearUnreachedToolStripMenuItem.Name = "gotoNearUnreachedToolStripMenuItem"; - this.gotoNearUnreachedToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.gotoNearUnreachedToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.gotoNearUnreachedToolStripMenuItem.Text = "Goto Previous Unreac&hed"; this.gotoNearUnreachedToolStripMenuItem.Click += new System.EventHandler(this.gotoNearUnreachedToolStripMenuItem_Click); // // gotoNextUnreachedToolStripMenuItem // this.gotoNextUnreachedToolStripMenuItem.Name = "gotoNextUnreachedToolStripMenuItem"; - this.gotoNextUnreachedToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.gotoNextUnreachedToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.gotoNextUnreachedToolStripMenuItem.Text = "Goto &Next Unreached"; this.gotoNextUnreachedToolStripMenuItem.Click += new System.EventHandler(this.gotoNextUnreachedToolStripMenuItem_Click); // // toolStripSeparator4 // this.toolStripSeparator4.Name = "toolStripSeparator4"; - this.toolStripSeparator4.Size = new System.Drawing.Size(250, 6); + this.toolStripSeparator4.Size = new System.Drawing.Size(306, 6); // // selectMarkerToolStripMenuItem // @@ -570,14 +595,14 @@ private void InitializeComponent() this.dWordPointerToolStripMenuItem, this.textToolStripMenuItem}); this.selectMarkerToolStripMenuItem.Name = "selectMarkerToolStripMenuItem"; - this.selectMarkerToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.selectMarkerToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.selectMarkerToolStripMenuItem.Text = "Select Marker"; // // unreachedToolStripMenuItem // this.unreachedToolStripMenuItem.Name = "unreachedToolStripMenuItem"; this.unreachedToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.U))); - this.unreachedToolStripMenuItem.Size = new System.Drawing.Size(205, 22); + this.unreachedToolStripMenuItem.Size = new System.Drawing.Size(258, 26); this.unreachedToolStripMenuItem.Text = "Unreached"; this.unreachedToolStripMenuItem.Click += new System.EventHandler(this.unreachedToolStripMenuItem_Click); // @@ -585,7 +610,7 @@ private void InitializeComponent() // this.opcodeToolStripMenuItem.Name = "opcodeToolStripMenuItem"; this.opcodeToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.O))); - this.opcodeToolStripMenuItem.Size = new System.Drawing.Size(205, 22); + this.opcodeToolStripMenuItem.Size = new System.Drawing.Size(258, 26); this.opcodeToolStripMenuItem.Text = "Opcode"; this.opcodeToolStripMenuItem.Click += new System.EventHandler(this.opcodeToolStripMenuItem_Click); // @@ -593,7 +618,7 @@ private void InitializeComponent() // this.operandToolStripMenuItem.Name = "operandToolStripMenuItem"; this.operandToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.P))); - this.operandToolStripMenuItem.Size = new System.Drawing.Size(205, 22); + this.operandToolStripMenuItem.Size = new System.Drawing.Size(258, 26); this.operandToolStripMenuItem.Text = "Operand"; this.operandToolStripMenuItem.Click += new System.EventHandler(this.operandToolStripMenuItem_Click); // @@ -601,7 +626,7 @@ private void InitializeComponent() // this.bitDataToolStripMenuItem.Name = "bitDataToolStripMenuItem"; this.bitDataToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.D1))); - this.bitDataToolStripMenuItem.Size = new System.Drawing.Size(205, 22); + this.bitDataToolStripMenuItem.Size = new System.Drawing.Size(258, 26); this.bitDataToolStripMenuItem.Text = "8-Bit Data"; this.bitDataToolStripMenuItem.Click += new System.EventHandler(this.bitDataToolStripMenuItem_Click); // @@ -609,7 +634,7 @@ private void InitializeComponent() // this.graphicsToolStripMenuItem.Name = "graphicsToolStripMenuItem"; this.graphicsToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.G))); - this.graphicsToolStripMenuItem.Size = new System.Drawing.Size(205, 22); + this.graphicsToolStripMenuItem.Size = new System.Drawing.Size(258, 26); this.graphicsToolStripMenuItem.Text = " Graphics"; this.graphicsToolStripMenuItem.Click += new System.EventHandler(this.graphicsToolStripMenuItem_Click); // @@ -617,7 +642,7 @@ private void InitializeComponent() // this.musicToolStripMenuItem.Name = "musicToolStripMenuItem"; this.musicToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.M))); - this.musicToolStripMenuItem.Size = new System.Drawing.Size(205, 22); + this.musicToolStripMenuItem.Size = new System.Drawing.Size(258, 26); this.musicToolStripMenuItem.Text = " Music"; this.musicToolStripMenuItem.Click += new System.EventHandler(this.musicToolStripMenuItem_Click); // @@ -625,7 +650,7 @@ private void InitializeComponent() // this.emptyToolStripMenuItem.Name = "emptyToolStripMenuItem"; this.emptyToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.E))); - this.emptyToolStripMenuItem.Size = new System.Drawing.Size(205, 22); + this.emptyToolStripMenuItem.Size = new System.Drawing.Size(258, 26); this.emptyToolStripMenuItem.Text = " Empty"; this.emptyToolStripMenuItem.Click += new System.EventHandler(this.emptyToolStripMenuItem_Click); // @@ -633,7 +658,7 @@ private void InitializeComponent() // this.bitDataToolStripMenuItem1.Name = "bitDataToolStripMenuItem1"; this.bitDataToolStripMenuItem1.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.D2))); - this.bitDataToolStripMenuItem1.Size = new System.Drawing.Size(205, 22); + this.bitDataToolStripMenuItem1.Size = new System.Drawing.Size(258, 26); this.bitDataToolStripMenuItem1.Text = "16-Bit Data"; this.bitDataToolStripMenuItem1.Click += new System.EventHandler(this.bitDataToolStripMenuItem1_Click); // @@ -641,7 +666,7 @@ private void InitializeComponent() // this.wordPointerToolStripMenuItem.Name = "wordPointerToolStripMenuItem"; this.wordPointerToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.W))); - this.wordPointerToolStripMenuItem.Size = new System.Drawing.Size(205, 22); + this.wordPointerToolStripMenuItem.Size = new System.Drawing.Size(258, 26); this.wordPointerToolStripMenuItem.Text = " Word Pointer"; this.wordPointerToolStripMenuItem.Click += new System.EventHandler(this.wordPointerToolStripMenuItem_Click); // @@ -649,7 +674,7 @@ private void InitializeComponent() // this.bitDataToolStripMenuItem2.Name = "bitDataToolStripMenuItem2"; this.bitDataToolStripMenuItem2.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.D3))); - this.bitDataToolStripMenuItem2.Size = new System.Drawing.Size(205, 22); + this.bitDataToolStripMenuItem2.Size = new System.Drawing.Size(258, 26); this.bitDataToolStripMenuItem2.Text = "24-Bit Data"; this.bitDataToolStripMenuItem2.Click += new System.EventHandler(this.bitDataToolStripMenuItem2_Click); // @@ -657,7 +682,7 @@ private void InitializeComponent() // this.longPointerToolStripMenuItem.Name = "longPointerToolStripMenuItem"; this.longPointerToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.L))); - this.longPointerToolStripMenuItem.Size = new System.Drawing.Size(205, 22); + this.longPointerToolStripMenuItem.Size = new System.Drawing.Size(258, 26); this.longPointerToolStripMenuItem.Text = " Long Pointer"; this.longPointerToolStripMenuItem.Click += new System.EventHandler(this.longPointerToolStripMenuItem_Click); // @@ -665,7 +690,7 @@ private void InitializeComponent() // this.bitDataToolStripMenuItem3.Name = "bitDataToolStripMenuItem3"; this.bitDataToolStripMenuItem3.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.D4))); - this.bitDataToolStripMenuItem3.Size = new System.Drawing.Size(205, 22); + this.bitDataToolStripMenuItem3.Size = new System.Drawing.Size(258, 26); this.bitDataToolStripMenuItem3.Text = "32-Bit Data"; this.bitDataToolStripMenuItem3.Click += new System.EventHandler(this.bitDataToolStripMenuItem3_Click); // @@ -673,7 +698,7 @@ private void InitializeComponent() // this.dWordPointerToolStripMenuItem.Name = "dWordPointerToolStripMenuItem"; this.dWordPointerToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.D))); - this.dWordPointerToolStripMenuItem.Size = new System.Drawing.Size(205, 22); + this.dWordPointerToolStripMenuItem.Size = new System.Drawing.Size(258, 26); this.dWordPointerToolStripMenuItem.Text = " DWord Pointer"; this.dWordPointerToolStripMenuItem.Click += new System.EventHandler(this.dWordPointerToolStripMenuItem_Click); // @@ -681,14 +706,14 @@ private void InitializeComponent() // this.textToolStripMenuItem.Name = "textToolStripMenuItem"; this.textToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.T))); - this.textToolStripMenuItem.Size = new System.Drawing.Size(205, 22); + this.textToolStripMenuItem.Size = new System.Drawing.Size(258, 26); this.textToolStripMenuItem.Text = "Text"; this.textToolStripMenuItem.Click += new System.EventHandler(this.textToolStripMenuItem_Click); // // markOneToolStripMenuItem // this.markOneToolStripMenuItem.Name = "markOneToolStripMenuItem"; - this.markOneToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.markOneToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.markOneToolStripMenuItem.Text = "Mar&k One"; this.markOneToolStripMenuItem.Click += new System.EventHandler(this.markOneToolStripMenuItem_Click); // @@ -696,19 +721,19 @@ private void InitializeComponent() // this.markManyToolStripMenuItem.Name = "markManyToolStripMenuItem"; this.markManyToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.K))); - this.markManyToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.markManyToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.markManyToolStripMenuItem.Text = "Mark Many..."; this.markManyToolStripMenuItem.Click += new System.EventHandler(this.markManyToolStripMenuItem_Click); // // toolStripSeparator5 // this.toolStripSeparator5.Name = "toolStripSeparator5"; - this.toolStripSeparator5.Size = new System.Drawing.Size(250, 6); + this.toolStripSeparator5.Size = new System.Drawing.Size(306, 6); // // addLabelToolStripMenuItem // this.addLabelToolStripMenuItem.Name = "addLabelToolStripMenuItem"; - this.addLabelToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.addLabelToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.addLabelToolStripMenuItem.Text = "Add &Label"; this.addLabelToolStripMenuItem.Click += new System.EventHandler(this.addLabelToolStripMenuItem_Click); // @@ -716,7 +741,7 @@ private void InitializeComponent() // this.setDataBankToolStripMenuItem.Name = "setDataBankToolStripMenuItem"; this.setDataBankToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.B))); - this.setDataBankToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.setDataBankToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.setDataBankToolStripMenuItem.Text = "Set Data &Bank..."; this.setDataBankToolStripMenuItem.Click += new System.EventHandler(this.setDataBankToolStripMenuItem_Click); // @@ -724,7 +749,7 @@ private void InitializeComponent() // this.setDirectPageToolStripMenuItem.Name = "setDirectPageToolStripMenuItem"; this.setDirectPageToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.D))); - this.setDirectPageToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.setDirectPageToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.setDirectPageToolStripMenuItem.Text = "Set &Direct Page..."; this.setDirectPageToolStripMenuItem.Click += new System.EventHandler(this.setDirectPageToolStripMenuItem_Click); // @@ -732,7 +757,7 @@ private void InitializeComponent() // this.toggleAccumulatorSizeMToolStripMenuItem.Name = "toggleAccumulatorSizeMToolStripMenuItem"; this.toggleAccumulatorSizeMToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.M))); - this.toggleAccumulatorSizeMToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.toggleAccumulatorSizeMToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.toggleAccumulatorSizeMToolStripMenuItem.Text = "Set Accu&mulator Size..."; this.toggleAccumulatorSizeMToolStripMenuItem.Click += new System.EventHandler(this.toggleAccumulatorSizeMToolStripMenuItem_Click); // @@ -740,27 +765,27 @@ private void InitializeComponent() // this.toggleIndexSizeToolStripMenuItem.Name = "toggleIndexSizeToolStripMenuItem"; this.toggleIndexSizeToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.X))); - this.toggleIndexSizeToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.toggleIndexSizeToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.toggleIndexSizeToolStripMenuItem.Text = "Set Inde&x Size..."; this.toggleIndexSizeToolStripMenuItem.Click += new System.EventHandler(this.toggleIndexSizeToolStripMenuItem_Click); // // addCommentToolStripMenuItem // this.addCommentToolStripMenuItem.Name = "addCommentToolStripMenuItem"; - this.addCommentToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.addCommentToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.addCommentToolStripMenuItem.Text = "Add &Comment"; this.addCommentToolStripMenuItem.Click += new System.EventHandler(this.addCommentToolStripMenuItem_Click); // // toolStripSeparator6 // this.toolStripSeparator6.Name = "toolStripSeparator6"; - this.toolStripSeparator6.Size = new System.Drawing.Size(250, 6); + this.toolStripSeparator6.Size = new System.Drawing.Size(306, 6); // // fixMisalignedInstructionsToolStripMenuItem // this.fixMisalignedInstructionsToolStripMenuItem.Name = "fixMisalignedInstructionsToolStripMenuItem"; this.fixMisalignedInstructionsToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.F))); - this.fixMisalignedInstructionsToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.fixMisalignedInstructionsToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.fixMisalignedInstructionsToolStripMenuItem.Text = "Fix Misaligned Flags..."; this.fixMisalignedInstructionsToolStripMenuItem.Click += new System.EventHandler(this.fixMisalignedInstructionsToolStripMenuItem_Click); // @@ -768,7 +793,7 @@ private void InitializeComponent() // this.rescanForInOutPointsToolStripMenuItem.Name = "rescanForInOutPointsToolStripMenuItem"; this.rescanForInOutPointsToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.P))); - this.rescanForInOutPointsToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.rescanForInOutPointsToolStripMenuItem.Size = new System.Drawing.Size(309, 26); this.rescanForInOutPointsToolStripMenuItem.Text = "Rescan for In/Out Points..."; this.rescanForInOutPointsToolStripMenuItem.Click += new System.EventHandler(this.rescanForInOutPointsToolStripMenuItem_Click); // @@ -780,7 +805,7 @@ private void InitializeComponent() this.constantsToolStripMenuItem, this.optionsToolStripMenuItem}); this.viewToolStripMenuItem.Name = "viewToolStripMenuItem"; - this.viewToolStripMenuItem.Size = new System.Drawing.Size(47, 20); + this.viewToolStripMenuItem.Size = new System.Drawing.Size(58, 24); this.viewToolStripMenuItem.Text = "&Tools"; // // visualMapToolStripMenuItem @@ -788,7 +813,7 @@ private void InitializeComponent() this.visualMapToolStripMenuItem.Enabled = false; this.visualMapToolStripMenuItem.Name = "visualMapToolStripMenuItem"; this.visualMapToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.V))); - this.visualMapToolStripMenuItem.Size = new System.Drawing.Size(212, 22); + this.visualMapToolStripMenuItem.Size = new System.Drawing.Size(264, 26); this.visualMapToolStripMenuItem.Text = "Visual Map"; this.visualMapToolStripMenuItem.Click += new System.EventHandler(this.visualMapToolStripMenuItem_Click); // @@ -797,7 +822,7 @@ private void InitializeComponent() this.graphicsWindowToolStripMenuItem.Enabled = false; this.graphicsWindowToolStripMenuItem.Name = "graphicsWindowToolStripMenuItem"; this.graphicsWindowToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.W))); - this.graphicsWindowToolStripMenuItem.Size = new System.Drawing.Size(212, 22); + this.graphicsWindowToolStripMenuItem.Size = new System.Drawing.Size(264, 26); this.graphicsWindowToolStripMenuItem.Text = "Graphics Window"; this.graphicsWindowToolStripMenuItem.Click += new System.EventHandler(this.graphicsWindowToolStripMenuItem_Click); // @@ -808,14 +833,14 @@ private void InitializeComponent() this.hexadecimalToolStripMenuItem, this.binaryToolStripMenuItem}); this.constantsToolStripMenuItem.Name = "constantsToolStripMenuItem"; - this.constantsToolStripMenuItem.Size = new System.Drawing.Size(212, 22); + this.constantsToolStripMenuItem.Size = new System.Drawing.Size(264, 26); this.constantsToolStripMenuItem.Text = "Constants"; // // decimalToolStripMenuItem // this.decimalToolStripMenuItem.Name = "decimalToolStripMenuItem"; this.decimalToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.C))); - this.decimalToolStripMenuItem.Size = new System.Drawing.Size(181, 22); + this.decimalToolStripMenuItem.Size = new System.Drawing.Size(228, 26); this.decimalToolStripMenuItem.Text = "Decimal"; this.decimalToolStripMenuItem.Click += new System.EventHandler(this.decimalToolStripMenuItem_Click); // @@ -825,7 +850,7 @@ private void InitializeComponent() this.hexadecimalToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; this.hexadecimalToolStripMenuItem.Name = "hexadecimalToolStripMenuItem"; this.hexadecimalToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.H))); - this.hexadecimalToolStripMenuItem.Size = new System.Drawing.Size(181, 22); + this.hexadecimalToolStripMenuItem.Size = new System.Drawing.Size(228, 26); this.hexadecimalToolStripMenuItem.Text = "Hexadecimal"; this.hexadecimalToolStripMenuItem.Click += new System.EventHandler(this.hexadecimalToolStripMenuItem_Click); // @@ -833,7 +858,7 @@ private void InitializeComponent() // this.binaryToolStripMenuItem.Name = "binaryToolStripMenuItem"; this.binaryToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.B))); - this.binaryToolStripMenuItem.Size = new System.Drawing.Size(181, 22); + this.binaryToolStripMenuItem.Size = new System.Drawing.Size(228, 26); this.binaryToolStripMenuItem.Text = "Binary"; this.binaryToolStripMenuItem.Click += new System.EventHandler(this.binaryToolStripMenuItem_Click); // @@ -842,7 +867,7 @@ private void InitializeComponent() this.optionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.moveWithStepToolStripMenuItem}); this.optionsToolStripMenuItem.Name = "optionsToolStripMenuItem"; - this.optionsToolStripMenuItem.Size = new System.Drawing.Size(212, 22); + this.optionsToolStripMenuItem.Size = new System.Drawing.Size(264, 26); this.optionsToolStripMenuItem.Text = "Options"; // // moveWithStepToolStripMenuItem @@ -850,7 +875,7 @@ private void InitializeComponent() this.moveWithStepToolStripMenuItem.Checked = true; this.moveWithStepToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; this.moveWithStepToolStripMenuItem.Name = "moveWithStepToolStripMenuItem"; - this.moveWithStepToolStripMenuItem.Size = new System.Drawing.Size(158, 22); + this.moveWithStepToolStripMenuItem.Size = new System.Drawing.Size(198, 26); this.moveWithStepToolStripMenuItem.Text = "Move With Step"; this.moveWithStepToolStripMenuItem.Click += new System.EventHandler(this.moveWithStepToolStripMenuItem_Click); // @@ -861,40 +886,42 @@ private void InitializeComponent() this.githubToolStripMenuItem, this.aboutToolStripMenuItem}); this.helpToolStripMenuItem.Name = "helpToolStripMenuItem"; - this.helpToolStripMenuItem.Size = new System.Drawing.Size(44, 20); + this.helpToolStripMenuItem.Size = new System.Drawing.Size(55, 24); this.helpToolStripMenuItem.Text = "&Help"; // // viewHelpToolStripMenuItem // this.viewHelpToolStripMenuItem.Name = "viewHelpToolStripMenuItem"; this.viewHelpToolStripMenuItem.ShortcutKeys = System.Windows.Forms.Keys.F1; - this.viewHelpToolStripMenuItem.Size = new System.Drawing.Size(146, 22); + this.viewHelpToolStripMenuItem.Size = new System.Drawing.Size(184, 26); this.viewHelpToolStripMenuItem.Text = "View Help"; this.viewHelpToolStripMenuItem.Click += new System.EventHandler(this.viewHelpToolStripMenuItem_Click); // // githubToolStripMenuItem // this.githubToolStripMenuItem.Name = "githubToolStripMenuItem"; - this.githubToolStripMenuItem.Size = new System.Drawing.Size(146, 22); + this.githubToolStripMenuItem.Size = new System.Drawing.Size(184, 26); this.githubToolStripMenuItem.Text = "Github"; this.githubToolStripMenuItem.Click += new System.EventHandler(this.githubToolStripMenuItem_Click); // // aboutToolStripMenuItem // this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem"; - this.aboutToolStripMenuItem.Size = new System.Drawing.Size(146, 22); + this.aboutToolStripMenuItem.Size = new System.Drawing.Size(184, 26); this.aboutToolStripMenuItem.Text = "About"; this.aboutToolStripMenuItem.Click += new System.EventHandler(this.aboutToolStripMenuItem_Click); // // statusStrip1 // + this.statusStrip1.ImageScalingSize = new System.Drawing.Size(20, 20); this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.percentComplete, this.seperator1, this.currentMarker}); - this.statusStrip1.Location = new System.Drawing.Point(0, 524); + this.statusStrip1.Location = new System.Drawing.Point(0, 646); this.statusStrip1.Name = "statusStrip1"; - this.statusStrip1.Size = new System.Drawing.Size(717, 22); + this.statusStrip1.Padding = new System.Windows.Forms.Padding(1, 0, 19, 0); + this.statusStrip1.Size = new System.Drawing.Size(956, 26); this.statusStrip1.TabIndex = 2; this.statusStrip1.Text = "statusStrip1"; // @@ -902,19 +929,19 @@ private void InitializeComponent() // this.percentComplete.Name = "percentComplete"; this.percentComplete.RightToLeft = System.Windows.Forms.RightToLeft.No; - this.percentComplete.Size = new System.Drawing.Size(72, 17); + this.percentComplete.Size = new System.Drawing.Size(92, 20); this.percentComplete.Text = "0.000% (0/0)"; // // seperator1 // this.seperator1.Name = "seperator1"; - this.seperator1.Size = new System.Drawing.Size(10, 17); + this.seperator1.Size = new System.Drawing.Size(13, 20); this.seperator1.Text = "|"; // // currentMarker // this.currentMarker.Name = "currentMarker"; - this.currentMarker.Size = new System.Drawing.Size(110, 17); + this.currentMarker.Size = new System.Drawing.Size(140, 20); this.currentMarker.Text = "Marker: Data (8-bit)"; // // openROMFile @@ -933,10 +960,10 @@ private void InitializeComponent() // vScrollBar1 // this.vScrollBar1.Enabled = false; - this.vScrollBar1.Location = new System.Drawing.Point(700, 24); + this.vScrollBar1.Location = new System.Drawing.Point(933, 30); this.vScrollBar1.Maximum = 32768; this.vScrollBar1.Name = "vScrollBar1"; - this.vScrollBar1.Size = new System.Drawing.Size(17, 500); + this.vScrollBar1.Size = new System.Drawing.Size(17, 615); this.vScrollBar1.TabIndex = 3; this.vScrollBar1.ValueChanged += new System.EventHandler(this.vScrollBar1_ValueChanged); // @@ -944,29 +971,23 @@ private void InitializeComponent() // this.saveLogSingleFile.Filter = "Assembly Files|*.asm|All Files|*.*"; // - // importUsageMapToolStripMenuItem - // - this.importUsageMapToolStripMenuItem.Name = "importUsageMapToolStripMenuItem"; - this.importUsageMapToolStripMenuItem.Size = new System.Drawing.Size(235, 22); - this.importUsageMapToolStripMenuItem.Text = "Import Usage Map..."; - this.importUsageMapToolStripMenuItem.Click += new System.EventHandler(this.ImportUsageMapToolStripMenuItem_Click); - // // openUsageMapFile // this.openUsageMapFile.Filter = "bsnes-plus usage map files|*.bin"; // // MainWindow // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(717, 546); + this.AutoScaleDimensions = new System.Drawing.SizeF(120F, 120F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.ClientSize = new System.Drawing.Size(956, 672); this.Controls.Add(this.vScrollBar1); this.Controls.Add(this.statusStrip1); this.Controls.Add(this.table); this.Controls.Add(this.menuStrip1); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MainMenuStrip = this.menuStrip1; - this.MinimumSize = new System.Drawing.Size(733, 200); + this.Margin = new System.Windows.Forms.Padding(4); + this.MinimumSize = new System.Drawing.Size(971, 235); this.Name = "MainWindow"; this.Text = "DiztinGUIsh"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainWindow_FormClosing); diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 71eea333..d98f371e 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -26,6 +26,11 @@ private void MainWindow_FormClosing(object sender, FormClosingEventArgs e) } private void MainWindow_SizeChanged(object sender, EventArgs e) + { + UpdatePanels(); + } + + private void UpdatePanels() { table.Height = this.Height - 85; table.Width = this.Width - 33; @@ -54,6 +59,8 @@ private void MainWindow_Load(object sender, EventArgs e) null, table, new object[] { true }); + + UpdatePanels(); } public void UpdateWindowTitle() From 0cc4319e1e85eed4d3d773f4588095549182cce8 Mon Sep 17 00:00:00 2001 From: Vitor Vilela Date: Sun, 2 Jun 2019 14:58:30 -0300 Subject: [PATCH 007/136] Carry MX flags to the operands --- DiztinGUIsh/static/diz/Manager.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/DiztinGUIsh/static/diz/Manager.cs b/DiztinGUIsh/static/diz/Manager.cs index aa88c0db..d398da6c 100644 --- a/DiztinGUIsh/static/diz/Manager.cs +++ b/DiztinGUIsh/static/diz/Manager.cs @@ -245,6 +245,7 @@ public static int ImportUsageMap(byte[] usageMap) int size = Data.GetROMSize(); bool unsaved = false; int modified = 0; + int prevFlags = 0; for (int i = 0; i < size; i++) { @@ -272,10 +273,11 @@ public static int ImportUsageMap(byte[] usageMap) if (flags.HasFlag(Data.BsnesPlusUsage.UsageOpcode)) { + prevFlags = ((int)flags & 3) << 4; Data.SetFlag(i, Data.FlagType.Opcode); } - Data.SetMXFlags(i, ((int)flags & 3) << 4); + Data.SetMXFlags(i, prevFlags); unsaved = true; modified++; } From a80a87bfa60240c597c9d2e3765a0c6dae2e7732 Mon Sep 17 00:00:00 2001 From: Vitor Vilela Date: Sun, 2 Jun 2019 15:20:09 -0300 Subject: [PATCH 008/136] Adjust column sizes because of DPI scaling I'm afraid these settings only work for my PC (125%), though... --- DiztinGUIsh/window/MainWindow.Designer.cs | 350 +++++++++++----------- DiztinGUIsh/window/MainWindow.cs | 1 + 2 files changed, 176 insertions(+), 175 deletions(-) diff --git a/DiztinGUIsh/window/MainWindow.Designer.cs b/DiztinGUIsh/window/MainWindow.Designer.cs index e71d7de1..e7f23769 100644 --- a/DiztinGUIsh/window/MainWindow.Designer.cs +++ b/DiztinGUIsh/window/MainWindow.Designer.cs @@ -44,19 +44,6 @@ private void InitializeComponent() System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle13 = new System.Windows.Forms.DataGridViewCellStyle(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainWindow)); this.table = new System.Windows.Forms.DataGridView(); - this.ColumnAlias = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnPC = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnChar = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnHex = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnPoints = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnInstruction = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnIA = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnFlag = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnDB = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnDP = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnM = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnX = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnComment = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.menuStrip1 = new System.Windows.Forms.MenuStrip(); this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.newProjectToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -134,6 +121,19 @@ private void InitializeComponent() this.saveLogSingleFile = new System.Windows.Forms.SaveFileDialog(); this.chooseLogFolder = new System.Windows.Forms.FolderBrowserDialog(); this.openUsageMapFile = new System.Windows.Forms.OpenFileDialog(); + this.ColumnAlias = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnPC = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnChar = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnHex = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnPoints = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnInstruction = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnIA = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnFlag = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnDB = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnDP = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnM = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnX = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnComment = new System.Windows.Forms.DataGridViewTextBoxColumn(); ((System.ComponentModel.ISupportInitialize)(this.table)).BeginInit(); this.menuStrip1.SuspendLayout(); this.statusStrip1.SuspendLayout(); @@ -188,164 +188,6 @@ private void InitializeComponent() this.table.MouseDown += new System.Windows.Forms.MouseEventHandler(this.table_MouseDown); this.table.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.table_MouseWheel); // - // ColumnAlias - // - dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; - dataGridViewCellStyle1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnAlias.DefaultCellStyle = dataGridViewCellStyle1; - this.ColumnAlias.HeaderText = "Label"; - this.ColumnAlias.MaxInputLength = 20; - this.ColumnAlias.MinimumWidth = 6; - this.ColumnAlias.Name = "ColumnAlias"; - this.ColumnAlias.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnAlias.Width = 125; - // - // ColumnPC - // - dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle2.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnPC.DefaultCellStyle = dataGridViewCellStyle2; - this.ColumnPC.HeaderText = "PC"; - this.ColumnPC.MaxInputLength = 6; - this.ColumnPC.MinimumWidth = 6; - this.ColumnPC.Name = "ColumnPC"; - this.ColumnPC.ReadOnly = true; - this.ColumnPC.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnPC.Width = 45; - // - // ColumnChar - // - dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; - dataGridViewCellStyle3.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnChar.DefaultCellStyle = dataGridViewCellStyle3; - this.ColumnChar.HeaderText = "@"; - this.ColumnChar.MaxInputLength = 1; - this.ColumnChar.MinimumWidth = 6; - this.ColumnChar.Name = "ColumnChar"; - this.ColumnChar.ReadOnly = true; - this.ColumnChar.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnChar.Width = 26; - // - // ColumnHex - // - dataGridViewCellStyle4.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; - dataGridViewCellStyle4.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnHex.DefaultCellStyle = dataGridViewCellStyle4; - this.ColumnHex.HeaderText = "#"; - this.ColumnHex.MaxInputLength = 3; - this.ColumnHex.MinimumWidth = 6; - this.ColumnHex.Name = "ColumnHex"; - this.ColumnHex.ReadOnly = true; - this.ColumnHex.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnHex.Width = 20; - // - // ColumnPoints - // - dataGridViewCellStyle5.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; - dataGridViewCellStyle5.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnPoints.DefaultCellStyle = dataGridViewCellStyle5; - this.ColumnPoints.HeaderText = "<*>"; - this.ColumnPoints.MaxInputLength = 3; - this.ColumnPoints.MinimumWidth = 6; - this.ColumnPoints.Name = "ColumnPoints"; - this.ColumnPoints.ReadOnly = true; - this.ColumnPoints.Width = 26; - // - // ColumnInstruction - // - dataGridViewCellStyle6.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle6.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnInstruction.DefaultCellStyle = dataGridViewCellStyle6; - this.ColumnInstruction.HeaderText = "Instruction"; - this.ColumnInstruction.MaxInputLength = 64; - this.ColumnInstruction.MinimumWidth = 6; - this.ColumnInstruction.Name = "ColumnInstruction"; - this.ColumnInstruction.ReadOnly = true; - this.ColumnInstruction.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnInstruction.Width = 125; - // - // ColumnIA - // - dataGridViewCellStyle7.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle7.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnIA.DefaultCellStyle = dataGridViewCellStyle7; - this.ColumnIA.HeaderText = "IA"; - this.ColumnIA.MaxInputLength = 6; - this.ColumnIA.MinimumWidth = 6; - this.ColumnIA.Name = "ColumnIA"; - this.ColumnIA.ReadOnly = true; - this.ColumnIA.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnIA.Width = 45; - // - // ColumnFlag - // - dataGridViewCellStyle8.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnFlag.DefaultCellStyle = dataGridViewCellStyle8; - this.ColumnFlag.HeaderText = "Flag"; - this.ColumnFlag.MinimumWidth = 6; - this.ColumnFlag.Name = "ColumnFlag"; - this.ColumnFlag.ReadOnly = true; - this.ColumnFlag.Width = 80; - // - // ColumnDB - // - dataGridViewCellStyle9.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; - dataGridViewCellStyle9.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnDB.DefaultCellStyle = dataGridViewCellStyle9; - this.ColumnDB.HeaderText = "B"; - this.ColumnDB.MaxInputLength = 2; - this.ColumnDB.MinimumWidth = 6; - this.ColumnDB.Name = "ColumnDB"; - this.ColumnDB.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnDB.Width = 20; - // - // ColumnDP - // - dataGridViewCellStyle10.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle10.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnDP.DefaultCellStyle = dataGridViewCellStyle10; - this.ColumnDP.HeaderText = "D"; - this.ColumnDP.MaxInputLength = 4; - this.ColumnDP.MinimumWidth = 6; - this.ColumnDP.Name = "ColumnDP"; - this.ColumnDP.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnDP.Width = 32; - // - // ColumnM - // - dataGridViewCellStyle11.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; - dataGridViewCellStyle11.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnM.DefaultCellStyle = dataGridViewCellStyle11; - this.ColumnM.HeaderText = "M"; - this.ColumnM.MaxInputLength = 2; - this.ColumnM.MinimumWidth = 6; - this.ColumnM.Name = "ColumnM"; - this.ColumnM.ReadOnly = true; - this.ColumnM.Width = 20; - // - // ColumnX - // - dataGridViewCellStyle12.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; - dataGridViewCellStyle12.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnX.DefaultCellStyle = dataGridViewCellStyle12; - this.ColumnX.HeaderText = "X"; - this.ColumnX.MaxInputLength = 2; - this.ColumnX.MinimumWidth = 6; - this.ColumnX.Name = "ColumnX"; - this.ColumnX.ReadOnly = true; - this.ColumnX.Width = 20; - // - // ColumnComment - // - this.ColumnComment.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; - dataGridViewCellStyle13.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle13.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnComment.DefaultCellStyle = dataGridViewCellStyle13; - this.ColumnComment.HeaderText = "Comment"; - this.ColumnComment.MinimumWidth = 6; - this.ColumnComment.Name = "ColumnComment"; - this.ColumnComment.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - // // menuStrip1 // this.menuStrip1.ImageScalingSize = new System.Drawing.Size(20, 20); @@ -975,6 +817,164 @@ private void InitializeComponent() // this.openUsageMapFile.Filter = "bsnes-plus usage map files|*.bin"; // + // ColumnAlias + // + dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; + dataGridViewCellStyle1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnAlias.DefaultCellStyle = dataGridViewCellStyle1; + this.ColumnAlias.HeaderText = "Label"; + this.ColumnAlias.MaxInputLength = 20; + this.ColumnAlias.MinimumWidth = 6; + this.ColumnAlias.Name = "ColumnAlias"; + this.ColumnAlias.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnAlias.Width = 130; + // + // ColumnPC + // + dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle2.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnPC.DefaultCellStyle = dataGridViewCellStyle2; + this.ColumnPC.HeaderText = "PC"; + this.ColumnPC.MaxInputLength = 6; + this.ColumnPC.MinimumWidth = 6; + this.ColumnPC.Name = "ColumnPC"; + this.ColumnPC.ReadOnly = true; + this.ColumnPC.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnPC.Width = 58; + // + // ColumnChar + // + dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; + dataGridViewCellStyle3.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnChar.DefaultCellStyle = dataGridViewCellStyle3; + this.ColumnChar.HeaderText = "@"; + this.ColumnChar.MaxInputLength = 1; + this.ColumnChar.MinimumWidth = 6; + this.ColumnChar.Name = "ColumnChar"; + this.ColumnChar.ReadOnly = true; + this.ColumnChar.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnChar.Width = 26; + // + // ColumnHex + // + dataGridViewCellStyle4.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; + dataGridViewCellStyle4.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnHex.DefaultCellStyle = dataGridViewCellStyle4; + this.ColumnHex.HeaderText = "#"; + this.ColumnHex.MaxInputLength = 3; + this.ColumnHex.MinimumWidth = 6; + this.ColumnHex.Name = "ColumnHex"; + this.ColumnHex.ReadOnly = true; + this.ColumnHex.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnHex.Width = 26; + // + // ColumnPoints + // + dataGridViewCellStyle5.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle5.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnPoints.DefaultCellStyle = dataGridViewCellStyle5; + this.ColumnPoints.HeaderText = "<*>"; + this.ColumnPoints.MaxInputLength = 3; + this.ColumnPoints.MinimumWidth = 6; + this.ColumnPoints.Name = "ColumnPoints"; + this.ColumnPoints.ReadOnly = true; + this.ColumnPoints.Width = 34; + // + // ColumnInstruction + // + dataGridViewCellStyle6.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle6.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnInstruction.DefaultCellStyle = dataGridViewCellStyle6; + this.ColumnInstruction.HeaderText = "Instruction"; + this.ColumnInstruction.MaxInputLength = 64; + this.ColumnInstruction.MinimumWidth = 6; + this.ColumnInstruction.Name = "ColumnInstruction"; + this.ColumnInstruction.ReadOnly = true; + this.ColumnInstruction.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnInstruction.Width = 125; + // + // ColumnIA + // + dataGridViewCellStyle7.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle7.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnIA.DefaultCellStyle = dataGridViewCellStyle7; + this.ColumnIA.HeaderText = "IA"; + this.ColumnIA.MaxInputLength = 6; + this.ColumnIA.MinimumWidth = 6; + this.ColumnIA.Name = "ColumnIA"; + this.ColumnIA.ReadOnly = true; + this.ColumnIA.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnIA.Width = 58; + // + // ColumnFlag + // + dataGridViewCellStyle8.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnFlag.DefaultCellStyle = dataGridViewCellStyle8; + this.ColumnFlag.HeaderText = "Flag"; + this.ColumnFlag.MinimumWidth = 6; + this.ColumnFlag.Name = "ColumnFlag"; + this.ColumnFlag.ReadOnly = true; + this.ColumnFlag.Width = 86; + // + // ColumnDB + // + dataGridViewCellStyle9.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; + dataGridViewCellStyle9.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnDB.DefaultCellStyle = dataGridViewCellStyle9; + this.ColumnDB.HeaderText = "B"; + this.ColumnDB.MaxInputLength = 2; + this.ColumnDB.MinimumWidth = 6; + this.ColumnDB.Name = "ColumnDB"; + this.ColumnDB.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnDB.Width = 26; + // + // ColumnDP + // + dataGridViewCellStyle10.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle10.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnDP.DefaultCellStyle = dataGridViewCellStyle10; + this.ColumnDP.HeaderText = "D"; + this.ColumnDP.MaxInputLength = 4; + this.ColumnDP.MinimumWidth = 6; + this.ColumnDP.Name = "ColumnDP"; + this.ColumnDP.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnDP.Width = 42; + // + // ColumnM + // + dataGridViewCellStyle11.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle11.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnM.DefaultCellStyle = dataGridViewCellStyle11; + this.ColumnM.HeaderText = "M"; + this.ColumnM.MaxInputLength = 2; + this.ColumnM.MinimumWidth = 6; + this.ColumnM.Name = "ColumnM"; + this.ColumnM.ReadOnly = true; + this.ColumnM.Width = 26; + // + // ColumnX + // + dataGridViewCellStyle12.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle12.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnX.DefaultCellStyle = dataGridViewCellStyle12; + this.ColumnX.HeaderText = "X"; + this.ColumnX.MaxInputLength = 2; + this.ColumnX.MinimumWidth = 6; + this.ColumnX.Name = "ColumnX"; + this.ColumnX.ReadOnly = true; + this.ColumnX.Width = 26; + // + // ColumnComment + // + this.ColumnComment.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + dataGridViewCellStyle13.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle13.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnComment.DefaultCellStyle = dataGridViewCellStyle13; + this.ColumnComment.HeaderText = "Comment"; + this.ColumnComment.MinimumWidth = 6; + this.ColumnComment.Name = "ColumnComment"; + this.ColumnComment.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + // // MainWindow // this.AutoScaleDimensions = new System.Drawing.SizeF(120F, 120F); @@ -1080,6 +1080,10 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem gotoNextUnreachedToolStripMenuItem; private System.Windows.Forms.SaveFileDialog saveLogSingleFile; private System.Windows.Forms.FolderBrowserDialog chooseLogFolder; + private System.Windows.Forms.ToolStripMenuItem optionsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem moveWithStepToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem importUsageMapToolStripMenuItem; + private System.Windows.Forms.OpenFileDialog openUsageMapFile; private System.Windows.Forms.DataGridViewTextBoxColumn ColumnAlias; private System.Windows.Forms.DataGridViewTextBoxColumn ColumnPC; private System.Windows.Forms.DataGridViewTextBoxColumn ColumnChar; @@ -1093,10 +1097,6 @@ private void InitializeComponent() private System.Windows.Forms.DataGridViewTextBoxColumn ColumnM; private System.Windows.Forms.DataGridViewTextBoxColumn ColumnX; private System.Windows.Forms.DataGridViewTextBoxColumn ColumnComment; - private System.Windows.Forms.ToolStripMenuItem optionsToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem moveWithStepToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem importUsageMapToolStripMenuItem; - private System.Windows.Forms.OpenFileDialog openUsageMapFile; } } diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index d98f371e..187bcedb 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -277,6 +277,7 @@ private void UpdateDataGridView() vScrollBar1.Maximum = Data.GetROMSize() - rowsToShow; vScrollBar1.Value = viewOffset; table.RowCount = rowsToShow; + importUsageMapToolStripMenuItem.Enabled = true; } } From 04cb6ea7406d6b3324a3b297cc8ddfdef0887f9f Mon Sep 17 00:00:00 2001 From: Vitor Vilela Date: Sun, 2 Jun 2019 15:20:24 -0300 Subject: [PATCH 009/136] Initlal trace log support --- DiztinGUIsh/static/diz/Manager.cs | 7 +++++++ DiztinGUIsh/window/MainWindow.cs | 2 ++ 2 files changed, 9 insertions(+) diff --git a/DiztinGUIsh/static/diz/Manager.cs b/DiztinGUIsh/static/diz/Manager.cs index d398da6c..27b47d24 100644 --- a/DiztinGUIsh/static/diz/Manager.cs +++ b/DiztinGUIsh/static/diz/Manager.cs @@ -292,5 +292,12 @@ public static int ImportUsageMap(byte[] usageMap) Project.unsavedChanges |= unsaved; return modified; } + + public static int ImportTraceLog(string[] lines) + { + // Must follow this format. + // 028cde rep #$30 A:0004 X:0000 Y:0004 S:1fdd D:0000 DB:02 nvmxdiZC V:133 H: 654 F:36 + return 0; + } } } diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 187bcedb..9bfb5978 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -277,6 +277,8 @@ private void UpdateDataGridView() vScrollBar1.Maximum = Data.GetROMSize() - rowsToShow; vScrollBar1.Value = viewOffset; table.RowCount = rowsToShow; + + importTraceLogToolStripMenuItem.Enabled = true; importUsageMapToolStripMenuItem.Enabled = true; } } From 6b955b6ad88bf6d8bbf2acbb55c8c8c76a52a32b Mon Sep 17 00:00:00 2001 From: Vitor Vilela Date: Mon, 3 Jun 2019 12:01:26 -0300 Subject: [PATCH 010/136] Get rid of the warnings --- DiztinGUIsh/static/Project.cs | 6 +++--- DiztinGUIsh/window/MainWindow.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DiztinGUIsh/static/Project.cs b/DiztinGUIsh/static/Project.cs index 5052ef3c..2001d6da 100644 --- a/DiztinGUIsh/static/Project.cs +++ b/DiztinGUIsh/static/Project.cs @@ -258,7 +258,7 @@ private static bool ValidateROM(string filename, string romName, int checksums, if (error == null) validFile = true; } - catch (Exception e) + catch (Exception) { error = string.Format("The linked ROM file '{0}' couldn't be found.", filename); } @@ -317,7 +317,7 @@ private static byte[] TryUnzip(byte[] data) return res.ToArray(); } } - catch (Exception e) + catch (Exception) { return null; } @@ -335,7 +335,7 @@ private static byte[] TryZip(byte[] data) return comp.ToArray(); } } - catch (Exception e) + catch (Exception) { return null; } diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 9bfb5978..8cf83143 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -198,7 +198,7 @@ private void viewHelpToolStripMenuItem_Click(object sender, EventArgs e) try { System.Diagnostics.Process.Start(Directory.GetCurrentDirectory() + "/help.html"); - } catch (Exception ex) + } catch (Exception) { MessageBox.Show("Can't find the help file.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } From d6534d279a4ef51fa1638fad412fa9894e3430dd Mon Sep 17 00:00:00 2001 From: Vitor Vilela Date: Mon, 3 Jun 2019 12:01:47 -0300 Subject: [PATCH 011/136] Add tracelog support --- DiztinGUIsh/static/diz/Manager.cs | 36 ++++++++++++++++++++++- DiztinGUIsh/window/MainWindow.Designer.cs | 7 +++++ DiztinGUIsh/window/MainWindow.cs | 11 +++++++ DiztinGUIsh/window/MainWindow.resx | 3 ++ 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/DiztinGUIsh/static/diz/Manager.cs b/DiztinGUIsh/static/diz/Manager.cs index 27b47d24..bde56fc1 100644 --- a/DiztinGUIsh/static/diz/Manager.cs +++ b/DiztinGUIsh/static/diz/Manager.cs @@ -297,7 +297,41 @@ public static int ImportTraceLog(string[] lines) { // Must follow this format. // 028cde rep #$30 A:0004 X:0000 Y:0004 S:1fdd D:0000 DB:02 nvmxdiZC V:133 H: 654 F:36 - return 0; + bool unsaved = false; + int modified = 0; + int size = Data.GetROMSize(); + + foreach (var line in lines) + { + if (line.Length < 80) + { + continue; + } + + // TODO: error treatment + // TODO: parse MX flags + int directPageIndex = line.IndexOf("D:") + 2; + int dataBankIndex = line.IndexOf("DB:") + 3; + + int snesAddress = Convert.ToInt32(line.Substring(0, 6), 16); + int directPage = Convert.ToInt32(line.Substring(directPageIndex, 4), 16); + int dataBank = Convert.ToInt32(line.Substring(dataBankIndex, 2), 16); + + int pc = Util.ConvertSNEStoPC(snesAddress); + Data.SetFlag(pc, Data.FlagType.Opcode); + + do + { + Data.SetDataBank(pc, dataBank); + Data.SetDirectPage(pc, directPage); + pc++; + unsaved = true; + modified++; + } while (pc < size && Data.GetFlag(pc) == Data.FlagType.Operand); + } + + Project.unsavedChanges |= unsaved; + return modified; } } } diff --git a/DiztinGUIsh/window/MainWindow.Designer.cs b/DiztinGUIsh/window/MainWindow.Designer.cs index e7f23769..335b3548 100644 --- a/DiztinGUIsh/window/MainWindow.Designer.cs +++ b/DiztinGUIsh/window/MainWindow.Designer.cs @@ -134,6 +134,7 @@ private void InitializeComponent() this.ColumnM = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.ColumnX = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.ColumnComment = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.openTraceLogDialog = new System.Windows.Forms.OpenFileDialog(); ((System.ComponentModel.ISupportInitialize)(this.table)).BeginInit(); this.menuStrip1.SuspendLayout(); this.statusStrip1.SuspendLayout(); @@ -284,6 +285,7 @@ private void InitializeComponent() this.importTraceLogToolStripMenuItem.Name = "importTraceLogToolStripMenuItem"; this.importTraceLogToolStripMenuItem.Size = new System.Drawing.Size(292, 26); this.importTraceLogToolStripMenuItem.Text = "Import Trace Log..."; + this.importTraceLogToolStripMenuItem.Click += new System.EventHandler(this.ImportTraceLogToolStripMenuItem_Click); // // importUsageMapToolStripMenuItem // @@ -975,6 +977,10 @@ private void InitializeComponent() this.ColumnComment.Name = "ColumnComment"; this.ColumnComment.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; // + // openTraceLogDialog + // + this.openTraceLogDialog.Filter = "bsnes-plus trace log|*.log"; + // // MainWindow // this.AutoScaleDimensions = new System.Drawing.SizeF(120F, 120F); @@ -1097,6 +1103,7 @@ private void InitializeComponent() private System.Windows.Forms.DataGridViewTextBoxColumn ColumnM; private System.Windows.Forms.DataGridViewTextBoxColumn ColumnX; private System.Windows.Forms.DataGridViewTextBoxColumn ColumnComment; + private System.Windows.Forms.OpenFileDialog openTraceLogDialog; } } diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 8cf83143..2b012772 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -812,5 +812,16 @@ private void ImportUsageMapToolStripMenuItem_Click(object sender, EventArgs e) MessageBoxButtons.OK, MessageBoxIcon.Information); } } + + private void ImportTraceLogToolStripMenuItem_Click(object sender, EventArgs e) + { + if (openTraceLogDialog.ShowDialog() == DialogResult.OK) + { + int total = Manager.ImportTraceLog(File.ReadAllLines(openTraceLogDialog.FileName)); + + MessageBox.Show($"Modified total {total} flags!", "Done", + MessageBoxButtons.OK, MessageBoxIcon.Information); + } + } } } diff --git a/DiztinGUIsh/window/MainWindow.resx b/DiztinGUIsh/window/MainWindow.resx index 3c39bd17..4f15579f 100644 --- a/DiztinGUIsh/window/MainWindow.resx +++ b/DiztinGUIsh/window/MainWindow.resx @@ -180,6 +180,9 @@ 953, 17 + + 1141, 17 + From 18596988a590013350d36155c6d61c81c3bb89bd Mon Sep 17 00:00:00 2001 From: Vitor Vilela Date: Mon, 17 Jun 2019 10:33:55 -0300 Subject: [PATCH 012/136] Ignore code executed on RAM when importing trace log --- DiztinGUIsh/static/diz/Manager.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/DiztinGUIsh/static/diz/Manager.cs b/DiztinGUIsh/static/diz/Manager.cs index bde56fc1..bcf95a61 100644 --- a/DiztinGUIsh/static/diz/Manager.cs +++ b/DiztinGUIsh/static/diz/Manager.cs @@ -318,6 +318,12 @@ public static int ImportTraceLog(string[] lines) int dataBank = Convert.ToInt32(line.Substring(dataBankIndex, 2), 16); int pc = Util.ConvertSNEStoPC(snesAddress); + + if (pc == -1) + { + continue; + } + Data.SetFlag(pc, Data.FlagType.Opcode); do From 61cc0cdf60bdb3e99240058f39343b3e06eb3c0c Mon Sep 17 00:00:00 2001 From: Vitor Vilela Date: Fri, 21 Jun 2019 12:24:32 -0300 Subject: [PATCH 013/136] Test all possible SNES addresses when importing usage map --- DiztinGUIsh/static/diz/Manager.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/DiztinGUIsh/static/diz/Manager.cs b/DiztinGUIsh/static/diz/Manager.cs index bcf95a61..18a46870 100644 --- a/DiztinGUIsh/static/diz/Manager.cs +++ b/DiztinGUIsh/static/diz/Manager.cs @@ -247,10 +247,15 @@ public static int ImportUsageMap(byte[] usageMap) int modified = 0; int prevFlags = 0; - for (int i = 0; i < size; i++) + for (int map = 0; map <= 0xFFFFFF; map++) { - // TODO: get every single possible SNES address for mapping. - var map = Util.ConvertPCtoSNES(i); + var i = Util.ConvertSNEStoPC(map); + + if (i == -1 || i >= size) + { + // branch predictor may optimize this + continue; + } var flags = (Data.BsnesPlusUsage)usageMap[map]; From 7ab27df038e7d2eb7c81c79bd012cd678ddcd8fd Mon Sep 17 00:00:00 2001 From: Vitor Vilela Date: Tue, 6 Aug 2019 01:56:41 -0300 Subject: [PATCH 014/136] Fix Direct Page opcodes log generation The low byte of DP was affecting the opcode itself. --- DiztinGUIsh/static/LogCreator.cs | 2 +- DiztinGUIsh/static/Util.cs | 7 ++++--- DiztinGUIsh/static/diz/CPU65C816.cs | 19 +++++++++++++------ 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/DiztinGUIsh/static/LogCreator.cs b/DiztinGUIsh/static/LogCreator.cs index 80342702..6b35231f 100644 --- a/DiztinGUIsh/static/LogCreator.cs +++ b/DiztinGUIsh/static/LogCreator.cs @@ -190,7 +190,7 @@ private static string GetLine(int offset, string special) } } } - int ia = Util.GetIntermediateAddress(offset); + int ia = Util.GetIntermediateAddress(offset, true); if (ia >= 0 && flag == Data.FlagType.Opcode && Data.GetInOutPoint(offset) == Data.InOutPoint.OutPoint && Data.GetFlag(Util.ConvertSNEStoPC(ia)) != Data.FlagType.Opcode) { err.WriteLine("({0}) Offset 0x{1:X}: Branch or jump instruction to a non-instruction.", ++errorCount, offset); diff --git a/DiztinGUIsh/static/Util.cs b/DiztinGUIsh/static/Util.cs index 18424e97..c8965939 100644 --- a/DiztinGUIsh/static/Util.cs +++ b/DiztinGUIsh/static/Util.cs @@ -42,7 +42,7 @@ public static int GetIntermediateAddressOrPointer(int offset) { case Data.FlagType.Unreached: case Data.FlagType.Opcode: - return GetIntermediateAddress(offset); + return GetIntermediateAddress(offset, true); case Data.FlagType.Pointer16Bit: int bank = Data.GetDataBank(offset); return (bank << 16) | GetROMWord(offset); @@ -53,11 +53,12 @@ public static int GetIntermediateAddressOrPointer(int offset) return -1; } - public static int GetIntermediateAddress(int offset) + public static int GetIntermediateAddress(int offset, bool resolve = false) { + // FIX ME: log and generation of dp opcodes. search references switch (Data.GetArchitechture(offset)) { - case Data.Architechture.CPU65C816: return CPU65C816.GetIntermediateAddress(offset); + case Data.Architechture.CPU65C816: return CPU65C816.GetIntermediateAddress(offset, resolve); case Data.Architechture.APUSPC700: return -1; case Data.Architechture.GPUSuperFX: return -1; } diff --git a/DiztinGUIsh/static/diz/CPU65C816.cs b/DiztinGUIsh/static/diz/CPU65C816.cs index 8db01dff..9a8e186a 100644 --- a/DiztinGUIsh/static/diz/CPU65C816.cs +++ b/DiztinGUIsh/static/diz/CPU65C816.cs @@ -57,14 +57,14 @@ public static int Step(int offset, bool branch, bool force, int prevOffset) || opcode == 0x70 || opcode == 0x90 || opcode == 0xB0 || opcode == 0xD0 // BVS BCC BCS BNE || opcode == 0xF0 || opcode == 0x20 || opcode == 0x22)))) // BEQ JSR JSL { - int iaNextOffsetPC = Util.ConvertSNEStoPC(Util.GetIntermediateAddress(offset)); + int iaNextOffsetPC = Util.ConvertSNEStoPC(Util.GetIntermediateAddress(offset, true)); if (iaNextOffsetPC >= 0) nextOffset = iaNextOffsetPC; } return nextOffset; } - public static int GetIntermediateAddress(int offset) + public static int GetIntermediateAddress(int offset, bool resolve) { int bank, directPage, operand, programCounter; int opcode = Data.GetROMByte(offset); @@ -80,9 +80,16 @@ public static int GetIntermediateAddress(int offset) case AddressMode.DIRECT_PAGE_INDIRECT_Y_INDEX: case AddressMode.DIRECT_PAGE_LONG_INDIRECT: case AddressMode.DIRECT_PAGE_LONG_INDIRECT_Y_INDEX: - directPage = Data.GetDirectPage(offset); - operand = Data.GetROMByte(offset + 1); - return (directPage + operand) & 0xFFFF; + if (resolve) + { + directPage = Data.GetDirectPage(offset); + operand = Data.GetROMByte(offset + 1); + return (directPage + operand) & 0xFFFF; + } + else + { + goto case AddressMode.DIRECT_PAGE_S_INDEX; + } case AddressMode.DIRECT_PAGE_S_INDEX: case AddressMode.DIRECT_PAGE_S_INDEX_INDIRECT_Y_INDEX: return Data.GetROMByte(offset + 1); @@ -185,7 +192,7 @@ public static int GetInstructionLength(int offset) public static void MarkInOutPoints(int offset) { int opcode = Data.GetROMByte(offset); - int iaOffsetPC = Util.ConvertSNEStoPC(Util.GetIntermediateAddress(offset)); + int iaOffsetPC = Util.ConvertSNEStoPC(Util.GetIntermediateAddress(offset, true)); // set read point on EA if (iaOffsetPC >= 0 && ( // these are all read/write/math instructions From b819614d7c8f8036d8e60697e3bab2af1b287541 Mon Sep 17 00:00:00 2001 From: gocha Date: Fri, 24 Jan 2020 00:20:47 +0900 Subject: [PATCH 015/136] Add basic function of importing BizHawk CDL --- DiztinGUIsh/BizHawkCdl.cs | 68 +++++++++++++++++++++++ DiztinGUIsh/DiztinGUIsh.csproj | 1 + DiztinGUIsh/static/diz/Manager.cs | 36 ++++++++++++ DiztinGUIsh/window/MainWindow.Designer.cs | 7 +++ DiztinGUIsh/window/MainWindow.cs | 31 +++++++++++ DiztinGUIsh/window/MainWindow.resx | 3 + 6 files changed, 146 insertions(+) create mode 100644 DiztinGUIsh/BizHawkCdl.cs diff --git a/DiztinGUIsh/BizHawkCdl.cs b/DiztinGUIsh/BizHawkCdl.cs new file mode 100644 index 00000000..00852dfb --- /dev/null +++ b/DiztinGUIsh/BizHawkCdl.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace DiztinGUIsh +{ + public class BizHawkCdl : Dictionary> + { + [Flags] + public enum Flag : byte + { + None = 0x00, + ExecFirst = 0x01, + ExecOperand = 0x02, + CPUData = 0x04, + DMAData = 0x08, + CPUXFlag = 0x10, + CPUMFlag = 0x20, + BRR = 0x80 + } + + public static BizHawkCdl LoadFromFile(string path) + { + using (var fs = new FileStream(path, FileMode.Open)) + { + return LoadFromStream(fs); + } + } + + public static BizHawkCdl LoadFromStream(Stream input) + { + var br = new BinaryReader(input); + + string id = br.ReadString(); + string subType; + if (id == "BIZHAWK-CDL-1") + { + subType = "PCE"; + } + else if (id == "BIZHAWK-CDL-2") + { + subType = br.ReadString().TrimEnd(' '); + } + else + { + throw new InvalidDataException("File is not a BizHawk CDL file."); + } + + if (subType != "SNES") + { + throw new InvalidDataException("The CDL file is not for SNES."); + } + + var cdl = new BizHawkCdl(); + int count = br.ReadInt32(); + for (int i = 0; i < count; i++) + { + string key = br.ReadString(); + int len = br.ReadInt32(); + var data = br.ReadBytes(len).Select(b => (Flag)b).ToArray(); + cdl[key] = data; + } + + return cdl; + } + } +} diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index f18ccc02..0e227dc9 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -67,6 +67,7 @@ + Form diff --git a/DiztinGUIsh/static/diz/Manager.cs b/DiztinGUIsh/static/diz/Manager.cs index f7e1888f..95d2fac1 100644 --- a/DiztinGUIsh/static/diz/Manager.cs +++ b/DiztinGUIsh/static/diz/Manager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -239,5 +240,40 @@ public static void RescanInOutPoints() Project.unsavedChanges = true; } + + public static void ImportBizHawkCDL(BizHawkCdl cdl) + { + if (!cdl.TryGetValue("CARTROM", out var cdlRomFlags)) + { + throw new InvalidDataException("The CDL file does not contain CARTROM block."); + } + + var size = Math.Min(cdlRomFlags.Count, Data.GetROMSize()); + for (var offset = 0; offset < size; offset++) + { + var cdlFlag = cdlRomFlags[offset]; + if (cdlFlag == BizHawkCdl.Flag.None) + continue; + + var type = Data.FlagType.Unreached; + if ((cdlFlag & BizHawkCdl.Flag.ExecFirst) != 0) + type = Data.FlagType.Opcode; + else if ((cdlFlag & BizHawkCdl.Flag.ExecOperand) != 0) + type = Data.FlagType.Operand; + else if ((cdlFlag & BizHawkCdl.Flag.CPUData) != 0) + type = Data.FlagType.Data8Bit; + else if ((cdlFlag & BizHawkCdl.Flag.DMAData) != 0) + type = Data.FlagType.Data8Bit; + Mark(offset, type, 1); + + if (type == Data.FlagType.Opcode || type == Data.FlagType.Operand) + { + var m = (cdlFlag & BizHawkCdl.Flag.CPUMFlag) != 0; + var x = (cdlFlag & BizHawkCdl.Flag.CPUXFlag) != 0; + MarkMFlag(offset, m, 1); + MarkXFlag(offset, x, 1); + } + } + } } } diff --git a/DiztinGUIsh/window/MainWindow.Designer.cs b/DiztinGUIsh/window/MainWindow.Designer.cs index 0110af30..3d4aca2b 100644 --- a/DiztinGUIsh/window/MainWindow.Designer.cs +++ b/DiztinGUIsh/window/MainWindow.Designer.cs @@ -132,6 +132,7 @@ private void InitializeComponent() this.vScrollBar1 = new System.Windows.Forms.VScrollBar(); this.saveLogSingleFile = new System.Windows.Forms.SaveFileDialog(); this.chooseLogFolder = new System.Windows.Forms.FolderBrowserDialog(); + this.openCDLDialog = new System.Windows.Forms.OpenFileDialog(); this.labelListToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); ((System.ComponentModel.ISupportInitialize)(this.table)).BeginInit(); this.menuStrip1.SuspendLayout(); @@ -417,6 +418,7 @@ private void InitializeComponent() this.importCDLToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.I))); this.importCDLToolStripMenuItem.Size = new System.Drawing.Size(235, 22); this.importCDLToolStripMenuItem.Text = "Import CDL..."; + this.importCDLToolStripMenuItem.Click += new System.EventHandler(this.importCDLToolStripMenuItem_Click); // // importTraceLogToolStripMenuItem // @@ -954,6 +956,10 @@ private void InitializeComponent() this.labelListToolStripMenuItem.Text = "Label List"; this.labelListToolStripMenuItem.Click += new System.EventHandler(this.labelListToolStripMenuItem_Click); // + // openCDLDialog + // + this.openCDLDialog.Filter = "BizHawk Code Data Logger Files|*.cdl|All Files|*.*"; + // // MainWindow // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -1075,6 +1081,7 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem optionsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem moveWithStepToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem labelListToolStripMenuItem; + private System.Windows.Forms.OpenFileDialog openCDLDialog; } } diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index ba1bfef6..39dcfdd4 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -94,6 +94,7 @@ private void newProjectToolStripMenuItem_Click(object sender, EventArgs e) { if (Project.NewProject(openROMFile.FileName)) { + importCDLToolStripMenuItem.Enabled = true; TriggerSaveOptions(false, true); UpdateWindowTitle(); UpdateDataGridView(); @@ -122,6 +123,7 @@ public void openProject(string filename) { if (Project.TryOpenProject(filename, openROMFile)) { + importCDLToolStripMenuItem.Enabled = true; TriggerSaveOptions(true, true); UpdateWindowTitle(); UpdateDataGridView(); @@ -149,6 +151,35 @@ private void saveProjectAsToolStripMenuItem_Click(object sender, EventArgs e) } } + private void importCDLToolStripMenuItem_Click(object sender, EventArgs e) + { + openCDLDialog.InitialDirectory = Project.currentFile; + DialogResult result = openCDLDialog.ShowDialog(); + if (result == DialogResult.OK) + { + if (ContinueUnsavedChanges()) + { + try + { + var cdl = BizHawkCdl.LoadFromFile(openCDLDialog.FileName); + Manager.ImportBizHawkCDL(cdl); + } + catch (InvalidDataException ex) + { + MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + catch (EndOfStreamException ex) + { + MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + UpdatePercent(); + UpdateWindowTitle(); + InvalidateTable(); + } + } + } + private void exportLogToolStripMenuItem_Click(object sender, EventArgs e) { ExportDisassembly export = new ExportDisassembly(); diff --git a/DiztinGUIsh/window/MainWindow.resx b/DiztinGUIsh/window/MainWindow.resx index b541887c..6625870e 100644 --- a/DiztinGUIsh/window/MainWindow.resx +++ b/DiztinGUIsh/window/MainWindow.resx @@ -177,6 +177,9 @@ 808, 17 + + 953, 17 + From 05907040f95e54fff84aef8762886a174812f930 Mon Sep 17 00:00:00 2001 From: gocha Date: Sun, 2 Feb 2020 17:40:58 +0900 Subject: [PATCH 016/136] [BizHawk CDL] Operand reuses the last M and X flag values used in Opcode --- DiztinGUIsh/static/diz/Manager.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/DiztinGUIsh/static/diz/Manager.cs b/DiztinGUIsh/static/diz/Manager.cs index 95d2fac1..51a6d0cb 100644 --- a/DiztinGUIsh/static/diz/Manager.cs +++ b/DiztinGUIsh/static/diz/Manager.cs @@ -249,6 +249,8 @@ public static void ImportBizHawkCDL(BizHawkCdl cdl) } var size = Math.Min(cdlRomFlags.Count, Data.GetROMSize()); + bool m = false; + bool x = false; for (var offset = 0; offset < size; offset++) { var cdlFlag = cdlRomFlags[offset]; @@ -257,7 +259,11 @@ public static void ImportBizHawkCDL(BizHawkCdl cdl) var type = Data.FlagType.Unreached; if ((cdlFlag & BizHawkCdl.Flag.ExecFirst) != 0) + { type = Data.FlagType.Opcode; + m = (cdlFlag & BizHawkCdl.Flag.CPUMFlag) != 0; + x = (cdlFlag & BizHawkCdl.Flag.CPUXFlag) != 0; + } else if ((cdlFlag & BizHawkCdl.Flag.ExecOperand) != 0) type = Data.FlagType.Operand; else if ((cdlFlag & BizHawkCdl.Flag.CPUData) != 0) @@ -268,8 +274,8 @@ public static void ImportBizHawkCDL(BizHawkCdl cdl) if (type == Data.FlagType.Opcode || type == Data.FlagType.Operand) { - var m = (cdlFlag & BizHawkCdl.Flag.CPUMFlag) != 0; - var x = (cdlFlag & BizHawkCdl.Flag.CPUXFlag) != 0; + // Operand reuses the last M and X flag values used in Opcode, + // since BizHawk CDL records M and X flags only in Opcode. MarkMFlag(offset, m, 1); MarkXFlag(offset, x, 1); } From 1a36d5a97dce0d79f76c8e5ccc52bdc1e75c1f09 Mon Sep 17 00:00:00 2001 From: gocha Date: Sun, 9 Feb 2020 23:47:07 +0900 Subject: [PATCH 017/136] [ui] Set default and cancel buttons for almost all dialogs --- DiztinGUIsh/window/dialog/ExportDisassembly.Designer.cs | 1 + DiztinGUIsh/window/dialog/GotoDialog.Designer.cs | 1 + DiztinGUIsh/window/dialog/HarshAutoStep.Designer.cs | 1 + DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs | 1 + DiztinGUIsh/window/dialog/InOutPointChecker.Designer.cs | 1 + DiztinGUIsh/window/dialog/MarkManyDialog.Designer.cs | 2 ++ 6 files changed, 7 insertions(+) diff --git a/DiztinGUIsh/window/dialog/ExportDisassembly.Designer.cs b/DiztinGUIsh/window/dialog/ExportDisassembly.Designer.cs index 1dd7a777..9149cb15 100644 --- a/DiztinGUIsh/window/dialog/ExportDisassembly.Designer.cs +++ b/DiztinGUIsh/window/dialog/ExportDisassembly.Designer.cs @@ -192,6 +192,7 @@ private void InitializeComponent() // // ExportDisassembly // + this.AcceptButton = this.button2; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.cancel; diff --git a/DiztinGUIsh/window/dialog/GotoDialog.Designer.cs b/DiztinGUIsh/window/dialog/GotoDialog.Designer.cs index 85a15764..a81b6ad4 100644 --- a/DiztinGUIsh/window/dialog/GotoDialog.Designer.cs +++ b/DiztinGUIsh/window/dialog/GotoDialog.Designer.cs @@ -127,6 +127,7 @@ private void InitializeComponent() // // GotoDialog // + this.AcceptButton = this.go; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.cancel; diff --git a/DiztinGUIsh/window/dialog/HarshAutoStep.Designer.cs b/DiztinGUIsh/window/dialog/HarshAutoStep.Designer.cs index 4eb5afae..d182f8af 100644 --- a/DiztinGUIsh/window/dialog/HarshAutoStep.Designer.cs +++ b/DiztinGUIsh/window/dialog/HarshAutoStep.Designer.cs @@ -196,6 +196,7 @@ private void InitializeComponent() // // HarshAutoStep // + this.AcceptButton = this.go; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.cancel; diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs b/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs index 330545b2..5ea99597 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs @@ -608,6 +608,7 @@ private void InitializeComponent() // // ImportROMDialog // + this.AcceptButton = this.okay; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.cancel; diff --git a/DiztinGUIsh/window/dialog/InOutPointChecker.Designer.cs b/DiztinGUIsh/window/dialog/InOutPointChecker.Designer.cs index 9aabf953..ac611b19 100644 --- a/DiztinGUIsh/window/dialog/InOutPointChecker.Designer.cs +++ b/DiztinGUIsh/window/dialog/InOutPointChecker.Designer.cs @@ -66,6 +66,7 @@ private void InitializeComponent() // // InOutPointChecker // + this.AcceptButton = this.rescan; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.cancel; diff --git a/DiztinGUIsh/window/dialog/MarkManyDialog.Designer.cs b/DiztinGUIsh/window/dialog/MarkManyDialog.Designer.cs index 71ca9783..9e682419 100644 --- a/DiztinGUIsh/window/dialog/MarkManyDialog.Designer.cs +++ b/DiztinGUIsh/window/dialog/MarkManyDialog.Designer.cs @@ -284,8 +284,10 @@ private void InitializeComponent() // // MarkManyDialog // + this.AcceptButton = this.okay; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cancel; this.ClientSize = new System.Drawing.Size(299, 206); this.Controls.Add(this.radioDec); this.Controls.Add(this.radioHex); From 65a807846d3cdd1252a9e5680a8cdb979d085ba4 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 29 Aug 2020 17:38:27 -0400 Subject: [PATCH 018/136] add ability to: - store comments specific to labels - print label comments in labels.asm - print all labels in all-labels.txt for analysis - update save file format to v2 - refactor save file code, combine all versions into one --- DiztinGUIsh/static/Data.cs | 41 +++- DiztinGUIsh/static/LogCreator.cs | 106 +++++++-- DiztinGUIsh/static/Project.cs | 201 ++++++++---------- DiztinGUIsh/static/Util.cs | 11 +- DiztinGUIsh/static/diz/CPU65C816.cs | 2 +- DiztinGUIsh/window/AliasList.Designer.cs | 25 ++- DiztinGUIsh/window/AliasList.cs | 89 +++++--- DiztinGUIsh/window/AliasList.resx | 3 + DiztinGUIsh/window/MainWindow.cs | 4 +- .../dialog/ExportDisassembly.Designer.cs | 44 +++- .../window/dialog/ExportDisassembly.cs | 29 ++- DiztinGUIsh/window/dialog/ImportROMDialog.cs | 7 +- 12 files changed, 369 insertions(+), 193 deletions(-) diff --git a/DiztinGUIsh/static/Data.cs b/DiztinGUIsh/static/Data.cs index 942adb2b..29bf2ab8 100644 --- a/DiztinGUIsh/static/Data.cs +++ b/DiztinGUIsh/static/Data.cs @@ -63,14 +63,27 @@ public const int private static ROMMapMode rom_map_mode; private static ROMSpeed rom_speed; private static List table; - private static Dictionary alias, comment; + private static Dictionary comment; + + public class AliasInfo + { + public string name = ""; // name of the label + public string comment = ""; // user-generated text, comment only + + public void CleanUp() + { + if (comment == null) comment = ""; + if (name == null) name = ""; + } + } + private static Dictionary alias; public static void Initiate(byte[] data, ROMMapMode mode, ROMSpeed speed) { rom_map_mode = mode; rom_speed = speed; int size = data.Length; - alias = new Dictionary(); + alias = new Dictionary(); comment = new Dictionary(); table = new List(); for (int i = 0; i < size; i++) @@ -90,7 +103,7 @@ public static void Initiate(byte[] data, ROMMapMode mode, ROMSpeed speed) } } - public static void Restore(List l = null, ROMMapMode m = ROMMapMode.LoROM, ROMSpeed s = ROMSpeed.Unknown, Dictionary a = null, Dictionary c = null) + public static void Restore(List l = null, ROMMapMode m = ROMMapMode.LoROM, ROMSpeed s = ROMSpeed.Unknown, Dictionary a = null, Dictionary c = null) { table = l ?? table; rom_map_mode = s == ROMSpeed.Unknown ? rom_map_mode : m; @@ -210,13 +223,22 @@ public static void SetMXFlags(int i, int mx) table[i].XFlag = ((mx & 0x10) != 0); } - public static string GetLabel(int i) + public static string GetLabelName(int i) + { + if (alias.TryGetValue(i, out AliasInfo val)) + return val?.name ?? ""; + + return ""; + } + public static string GetLabelComment(int i) { - if (alias.TryGetValue(i, out string val)) return val; + if (alias.TryGetValue(i, out AliasInfo val)) + return val?.comment ?? ""; + return ""; } - public static void AddLabel(int i, string v, bool overwrite) + public static void AddLabel(int i, AliasInfo v, bool overwrite) { if (v == null) { @@ -225,8 +247,7 @@ public static void AddLabel(int i, string v, bool overwrite) alias.Remove(i); AliasList.me.RemoveRow(i); } - } else - { + } else { if (alias.ContainsKey(i) && overwrite) { alias.Remove(i); @@ -234,13 +255,15 @@ public static void AddLabel(int i, string v, bool overwrite) } if (!alias.ContainsKey(i)) { + v.CleanUp(); + alias.Add(i, v); AliasList.me.AddRow(i, v); } } } - public static Dictionary GetAllLabels() + public static Dictionary GetAllLabels() { return alias; } diff --git a/DiztinGUIsh/static/LogCreator.cs b/DiztinGUIsh/static/LogCreator.cs index 1076573e..03180b28 100644 --- a/DiztinGUIsh/static/LogCreator.cs +++ b/DiztinGUIsh/static/LogCreator.cs @@ -1,6 +1,7 @@ using DiztinGUIsh.window; using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Text; @@ -49,6 +50,8 @@ public enum FormatStructure public static int dataPerLine = 8; public static FormatUnlabeled unlabeled = FormatUnlabeled.ShowInPoints; public static FormatStructure structure = FormatStructure.OneBankPerFile; + public static bool includeUnusedLabels; + public static bool printLabelSpecificComments; private static List> list; private static List usedLabels; @@ -58,8 +61,8 @@ public enum FormatStructure public static int CreateLog(StreamWriter sw, StreamWriter er) { - Dictionary tempAlias = Data.GetAllLabels(); - Data.Restore(a: new Dictionary(tempAlias)); + var tempAlias = Data.GetAllLabels(); + Data.Restore(a: new Dictionary(tempAlias)); AliasList.me.locked = true; bankSize = Data.GetROMMapMode() == Data.ROMMapMode.LoROM ? 0x8000 : 0x10000; // todo @@ -115,33 +118,71 @@ public static int CreateLog(StreamWriter sw, StreamWriter er) bank = snes >> 16; } - if ((Data.GetInOutPoint(pointer) & (Data.InOutPoint.ReadPoint)) != 0 || (tempAlias.TryGetValue(pointer, out string label) && label.Length > 0)) sw.WriteLine(GetLine(pointer, "empty")); + var c1 = (Data.GetInOutPoint(pointer) & (Data.InOutPoint.ReadPoint)) != 0; + var c2 = (tempAlias.TryGetValue(pointer, out var aliasInfo) && aliasInfo.name.Length > 0); + if (c1 || c2) + sw.WriteLine(GetLine(pointer, "empty")); + sw.WriteLine(GetLine(pointer, null)); if ((Data.GetInOutPoint(pointer) & (Data.InOutPoint.EndPoint)) != 0) sw.WriteLine(GetLine(pointer, "empty")); pointer += GetLineByteLength(pointer); } - if (structure == FormatStructure.OneBankPerFile) + WriteLabels(ref sw, pointer); + + if (structure == FormatStructure.OneBankPerFile) sw.Close(); + Data.Restore(a: tempAlias); + AliasList.me.locked = false; + return errorCount; + } + + private static void WriteLabels(ref StreamWriter sw, int pointer) + { + SwitchOutputFile(ref sw, pointer, $"{folder}/labels.asm"); + + Dictionary listToPrint = new Dictionary(); + + // part 1: important: include all labels we aren't defining somewhere else. needed for disassembly + foreach (var pair in Data.GetAllLabels()) { - sw.Close(); - sw = new StreamWriter(string.Format("{0}/labels.asm", folder)); - } else + if (usedLabels.Contains(pair.Key)) + continue; + + // this label was not defined elsewhere in our disassembly, so we need to include it in labels.asm + listToPrint.Add(pair.Key, pair.Value); + } + + foreach (var pair in listToPrint) { - sw.WriteLine(GetLine(pointer, "empty")); + sw.WriteLine(GetLine(pair.Key, "labelassign")); } - foreach (KeyValuePair pair in Data.GetAllLabels()) + // part 2: optional: if requested, print all labels regardless of use. + // Useful for debugging, documentation, or reverse engineering workflow. + // this file shouldn't need to be included in the build, it's just reference documentation + if (includeUnusedLabels) { - if (!usedLabels.Contains(pair.Key)) + SwitchOutputFile(ref sw, pointer, $"{folder}/all-labels.txt"); + foreach (var pair in Data.GetAllLabels()) { - sw.WriteLine(GetLine(pair.Key, "labelassign")); + // not the best place to add formatting, TODO: cleanup + var category = listToPrint.ContainsKey(pair.Key) ? "INLINE" : "EXTRA "; + sw.WriteLine($";!^!-{category}-! " + GetLine(pair.Key, "labelassign")); } } + } - if (structure == FormatStructure.OneBankPerFile) sw.Close(); - Data.Restore(a: tempAlias); - AliasList.me.locked = false; - return errorCount; + private static void SwitchOutputFile(ref StreamWriter sw, int pointer, string path) + { + if (structure == FormatStructure.OneBankPerFile) + { + sw.Close(); + sw = new StreamWriter(path); + } + else + { + sw.WriteLine(GetLine(pointer, "empty")); + } } private static void AddTemporaryLabels() @@ -166,7 +207,15 @@ private static void AddTemporaryLabels() } // TODO +/- labels - for (int i = 0; i < addMe.Count; i++) Data.AddLabel(addMe[i], Util.GetDefaultLabel(addMe[i]), false); + for (int i = 0; i < addMe.Count; i++) + { + Data.AddLabel(addMe[i], + new Data.AliasInfo() + { + name = Util.GetDefaultLabel(addMe[i]) + }, + false); + } } private static string GetLine(int offset, string special) @@ -277,7 +326,7 @@ private static int GetLineByteLength(int offset) min < max && offset + min < size && Data.GetFlag(offset + min) == Data.GetFlag(offset) && - Data.GetLabel(Util.ConvertPCtoSNES(offset + min)) == "" && + Data.GetLabelName(Util.ConvertPCtoSNES(offset + min)) == "" && (offset + min) / bankSize == myBank ) min += step; return min; @@ -306,7 +355,10 @@ private static string GetEmpty(int offset, int length) private static string GetLabel(int offset, int length) { int snes = Util.ConvertPCtoSNES(offset); - string label = Data.GetLabel(snes); + string label = Data.GetLabelName(snes); + if (label == null) + return ""; + usedLabels.Add(snes); bool noColon = label.Length == 0 || label[0] == '-' || label[0] == '+'; return string.Format("{0," + (length * -1) + "}", label + (noColon ? "" : ":")); @@ -467,7 +519,23 @@ private static string GetXFlag(int offset, int length) // output label at snes offset, and its value private static string GetLabelAssign(int offset, int length) { - string s = string.Format("{0} = {1}", Data.GetLabel(offset), Util.NumberToBaseString(offset, Util.NumberBase.Hexadecimal, 6, true)); + var labelName = Data.GetLabelName(offset); + var offsetStr = Util.NumberToBaseString(offset, Util.NumberBase.Hexadecimal, 6, true); + var labelComment = Data.GetLabelComment(offset); + + if (string.IsNullOrEmpty(labelName)) + return ""; + + if (labelComment == null) + labelComment = ""; + + var finalCommentText = ""; + + // TODO: sorry, probably not the best way to stuff this in here, consider putting it in the %comment% section in the future. -Dom + if (printLabelSpecificComments && labelComment != "") + finalCommentText = $"; !^ {labelComment} ^!"; + + string s = $"{labelName} = {offsetStr}{finalCommentText}"; return string.Format("{0," + (length * -1) + "}", s); } } diff --git a/DiztinGUIsh/static/Project.cs b/DiztinGUIsh/static/Project.cs index 75675074..de80d4e5 100644 --- a/DiztinGUIsh/static/Project.cs +++ b/DiztinGUIsh/static/Project.cs @@ -42,10 +42,10 @@ public static bool NewProject(string filename) currentFile = null; AliasList.me.Reset(); - Dictionary generatedLabels = import.GetGeneratedLabels(); + Dictionary generatedLabels = import.GetGeneratedLabels(); if (generatedLabels.Count > 0) { - foreach (KeyValuePair pair in generatedLabels) Data.AddLabel(pair.Key, pair.Value, true); + foreach (KeyValuePair pair in generatedLabels) Data.AddLabel(pair.Key, pair.Value, true); unsavedChanges = true; } @@ -66,13 +66,17 @@ public static bool NewProject(string filename) return false; } + private const int LATEST_FILE_FORMAT_VERSION = 2; + public static void SaveProject(string filename) { try { - byte[] data = SaveVersion1(); + const int versionToSave = LATEST_FILE_FORMAT_VERSION; + + byte[] data = SaveVersion(versionToSave); byte[] everything = new byte[HEADER_SIZE + data.Length]; - everything[0] = 1; // version + everything[0] = versionToSave; Util.StringToByteArray(watermark).CopyTo(everything, 1); data.CopyTo(everything, HEADER_SIZE); @@ -88,8 +92,26 @@ public static void SaveProject(string filename) } } - private static byte[] SaveVersion1() + private static byte[] SaveVersion(int version) { + void SaveStringToBytes(string str, List bytes) + { + // TODO: combine with Util.StringToByteArray() probably. + if (str != null) + { + foreach (var c in str) + { + bytes.Add((byte)c); + } + } + bytes.Add(0); + } + + if (version < 1 || version > LATEST_FILE_FORMAT_VERSION) + { + throw new ArgumentException($"Saving: Invalid save version requested for saving: {version}."); + } + int size = Data.GetROMSize(); byte[] romSettings = new byte[31]; romSettings[0] = (byte)Data.GetROMMapMode(); @@ -101,22 +123,26 @@ private static byte[] SaveVersion1() // TODO put selected offset in save file List label = new List(), comment = new List(); - Dictionary all_labels = Data.GetAllLabels(), all_comments = Data.GetAllComments(); + var all_labels = Data.GetAllLabels(); + var all_comments = Data.GetAllComments(); Util.IntegerIntoByteList(all_labels.Count, label); - foreach (KeyValuePair pair in all_labels) + foreach (var pair in all_labels) { Util.IntegerIntoByteList(pair.Key, label); - for (int i = 0; i < pair.Value.Length; i++) label.Add((byte)pair.Value[i]); - label.Add(0); + + SaveStringToBytes(pair.Value.name, label); + if (version >= 2) + { + SaveStringToBytes(pair.Value.comment, label); + } } Util.IntegerIntoByteList(all_comments.Count, comment); foreach (KeyValuePair pair in all_comments) { Util.IntegerIntoByteList(pair.Key, comment); - for (int i = 0; i < pair.Value.Length; i++) comment.Add((byte)pair.Value[i]); - comment.Add(0); + SaveStringToBytes(pair.Value, comment); } byte[] romLocation = Util.StringToByteArray(currentROMFile); @@ -157,13 +183,7 @@ public static bool TryOpenProject(string filename, OpenFileDialog open) } byte version = data[0]; - - switch (version) - { - case 0: OpenVersion0(data, open); break; - case 1: OpenVersion1(data, open); break; - default: throw new Exception("This DiztinGUIsh file uses a newer file format! You'll need to download the newest version of DiztinGUIsh to open it."); - } + OpenProject(version, data, open); unsavedChanges = false; currentFile = filename; @@ -176,20 +196,32 @@ public static bool TryOpenProject(string filename, OpenFileDialog open) } } - // differences between version 0 and version 1: - // version 0: addresses for aliases and comments were stored in PC offset format. - // tables: B, D lo, D hi, X, M, flag, arch, inoutpoint - // lists: alias, comment - // version 1: addresses for aliases and comments are stored in SNES address format. - // tables: B, D lo, D hi, X, M, flag, arch, inoutpoint, ??? - // lists: alias, comment, ??? - private static void OpenVersion0(byte[] unzipped, OpenFileDialog open) + private delegate int AddressConverter(int address); + + private static void OpenProject(int version, byte[] unzipped, OpenFileDialog open) { - MessageBox.Show( - "This project file is in an older format.\n" + - "You may want to back up your work or 'Save As' in case the conversion goes wrong.\n" + - "The project file will be untouched until it is saved again.", - "Project File Out of Date", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + if (version > LATEST_FILE_FORMAT_VERSION) + { + throw new ArgumentException("This DiztinGUIsh file uses a newer file format! You'll need to download the newest version of DiztinGUIsh to open it."); + } + else if (version != LATEST_FILE_FORMAT_VERSION) + { + MessageBox.Show( + "This project file is in an older format.\n" + + "You may want to back up your work or 'Save As' in case the conversion goes wrong.\n" + + "The project file will be untouched until it is saved again.", + "Project File Out of Date", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + + if (version < 0) + { + throw new ArgumentException($"Invalid project file version detected: {version}."); + } + + // version 0 needs to convert PC to SNES for some addresses + AddressConverter converter = address => address; + if (version == 0) + converter = Util.ConvertPCtoSNES; Data.ROMMapMode mode = (Data.ROMMapMode)unzipped[HEADER_SIZE]; Data.ROMSpeed speed = (Data.ROMSpeed)unzipped[HEADER_SIZE + 1]; @@ -198,10 +230,10 @@ private static void OpenVersion0(byte[] unzipped, OpenFileDialog open) byte[] rom; int pointer = HEADER_SIZE + 6; - for (int i = 0; i < 0x15; i++) romName += (char)unzipped[pointer++]; + for (int i = 0; i < 0x15; i++) romName += (char) unzipped[pointer++]; int checksums = Util.ByteArrayToInteger(unzipped, pointer); pointer += 4; - while (unzipped[pointer] != 0) romLocation += (char)unzipped[pointer++]; + while (unzipped[pointer] != 0) romLocation += (char) unzipped[pointer++]; pointer++; if (ValidateROM(romLocation, romName, checksums, mode, out rom, open)) @@ -215,38 +247,12 @@ private static void OpenVersion0(byte[] unzipped, OpenFileDialog open) for (int i = 0; i < size; i++) Data.SetFlag(i, (Data.FlagType)unzipped[pointer + 5 * size + i]); for (int i = 0; i < size; i++) Data.SetArchitechture(i, (Data.Architechture)unzipped[pointer + 6 * size + i]); for (int i = 0; i < size; i++) Data.SetInOutPoint(i, (Data.InOutPoint)unzipped[pointer + 7 * size + i]); - pointer += 8 * size; - int label_count = Util.ByteArrayToInteger(unzipped, pointer); - pointer += 4; AliasList.me.Reset(); - for (int i = 0; i < label_count; i++) - { - int offset = Util.ConvertPCtoSNES(Util.ByteArrayToInteger(unzipped, pointer)); // pc -> snes - pointer += 4; + ReadAliases(unzipped, ref pointer, converter, version >= 2); - string label = ""; - while (unzipped[pointer] != 0) label += (char)unzipped[pointer++]; - pointer++; - - Data.AddLabel(offset, label, true); - } - - int comment_count = Util.ByteArrayToInteger(unzipped, pointer); - pointer += 4; - - for (int i = 0; i < comment_count; i++) - { - int offset = Util.ConvertPCtoSNES(Util.ByteArrayToInteger(unzipped, pointer)); // pc -> snes - pointer += 4; - - string comment = ""; - while (unzipped[pointer] != 0) comment += (char)unzipped[pointer++]; - pointer++; - - Data.AddComment(offset, comment, true); - } + ReadComments(unzipped, ref pointer, converter); } else { @@ -254,68 +260,41 @@ private static void OpenVersion0(byte[] unzipped, OpenFileDialog open) } } - private static void OpenVersion1(byte[] unzipped, OpenFileDialog open) - { - Data.ROMMapMode mode = (Data.ROMMapMode)unzipped[HEADER_SIZE]; - Data.ROMSpeed speed = (Data.ROMSpeed)unzipped[HEADER_SIZE + 1]; - int size = Util.ByteArrayToInteger(unzipped, HEADER_SIZE + 2); - string romName = "", romLocation = ""; - byte[] rom; + // TODO: refactor ReadComments and ReadAliases into one generic list-reading function - int pointer = HEADER_SIZE + 6; - for (int i = 0; i < 0x15; i++) romName += (char)unzipped[pointer++]; - int checksums = Util.ByteArrayToInteger(unzipped, pointer); + private static void ReadComments(byte[] unzipped, ref int pointer, AddressConverter converter) + { + var count = Util.ByteArrayToInteger(unzipped, pointer); pointer += 4; - while (unzipped[pointer] != 0) romLocation += (char)unzipped[pointer++]; - pointer++; - if (ValidateROM(romLocation, romName, checksums, mode, out rom, open)) + for (var i = 0; i < count; i++) { - Data.Initiate(rom, mode, speed); - - for (int i = 0; i < size; i++) Data.SetDataBank(i, unzipped[pointer + i]); - for (int i = 0; i < size; i++) Data.SetDirectPage(i, unzipped[pointer + size + i] | (unzipped[pointer + 2 * size + i] << 8)); - for (int i = 0; i < size; i++) Data.SetXFlag(i, unzipped[pointer + 3 * size + i] != 0); - for (int i = 0; i < size; i++) Data.SetMFlag(i, unzipped[pointer + 4 * size + i] != 0); - for (int i = 0; i < size; i++) Data.SetFlag(i, (Data.FlagType)unzipped[pointer + 5 * size + i]); - for (int i = 0; i < size; i++) Data.SetArchitechture(i, (Data.Architechture)unzipped[pointer + 6 * size + i]); - for (int i = 0; i < size; i++) Data.SetInOutPoint(i, (Data.InOutPoint)unzipped[pointer + 7 * size + i]); - - pointer += 8 * size; - int label_count = Util.ByteArrayToInteger(unzipped, pointer); + int offset = converter(Util.ByteArrayToInteger(unzipped, pointer)); pointer += 4; - AliasList.me.Reset(); - for (int i = 0; i < label_count; i++) - { - int offset = Util.ByteArrayToInteger(unzipped, pointer); - pointer += 4; + var comment = Util.ReadZipString(unzipped, ref pointer); - string label = ""; - while (unzipped[pointer] != 0) label += (char)unzipped[pointer++]; - pointer++; + Data.AddComment(offset, comment, true); + } + } - Data.AddLabel(offset, label, true); - } + private static void ReadAliases(byte[] unzipped, ref int pointer, AddressConverter converter, bool readAliasComments) + { + int count = Util.ByteArrayToInteger(unzipped, pointer); + pointer += 4; - int comment_count = Util.ByteArrayToInteger(unzipped, pointer); + for (int i = 0; i < count; i++) + { + int offset = converter(Util.ByteArrayToInteger(unzipped, pointer)); pointer += 4; - for (int i = 0; i < comment_count; i++) - { - int offset = Util.ByteArrayToInteger(unzipped, pointer); - pointer += 4; + var aliasInfo = new Data.AliasInfo { + name = Util.ReadZipString(unzipped, ref pointer), + comment = readAliasComments ? Util.ReadZipString(unzipped, ref pointer) : "", + }; + aliasInfo.CleanUp(); - string comment = ""; - while (unzipped[pointer] != 0) comment += (char)unzipped[pointer++]; - pointer++; - - Data.AddComment(offset, comment, true); - } - } - else - { - throw new Exception("Couldn't open the ROM file!"); + Data.AddLabel(offset, aliasInfo, true); } } diff --git a/DiztinGUIsh/static/Util.cs b/DiztinGUIsh/static/Util.cs index 122c64a3..15e34ef7 100644 --- a/DiztinGUIsh/static/Util.cs +++ b/DiztinGUIsh/static/Util.cs @@ -126,7 +126,7 @@ public static string GetPointer(int offset, int bytes) } int pc = ConvertSNEStoPC(ia); - if (pc >= 0 && Data.GetLabel(ia) != "") param = Data.GetLabel(ia); + if (pc >= 0 && Data.GetLabelName(ia) != "") param = Data.GetLabelName(ia); return string.Format(format, param); } @@ -260,6 +260,15 @@ public static int ConvertSNEStoPC(int address) } } + public static string ReadZipString(byte[] unzipped, ref int pointer) + { + var label = ""; + while (unzipped[pointer] != 0) + label += (char)unzipped[pointer++]; + pointer++; + return label; + } + private static int UnmirroredOffset(int offset) { int size = Data.GetROMSize(); diff --git a/DiztinGUIsh/static/diz/CPU65C816.cs b/DiztinGUIsh/static/diz/CPU65C816.cs index 1888e629..6618c6e3 100644 --- a/DiztinGUIsh/static/diz/CPU65C816.cs +++ b/DiztinGUIsh/static/diz/CPU65C816.cs @@ -218,7 +218,7 @@ private static string FormatOperandAddress(int offset, AddressMode mode) { int address = Util.GetIntermediateAddress(offset); if (address < 0) return ""; - if (Data.GetLabel(address) != "") return Data.GetLabel(address); + if (Data.GetLabelName(address) != "") return Data.GetLabelName(address); int count = BytesToShow(mode); if (mode == AddressMode.RELATIVE_8 || mode == AddressMode.RELATIVE_16) address = Util.GetROMWord(offset + 1); diff --git a/DiztinGUIsh/window/AliasList.Designer.cs b/DiztinGUIsh/window/AliasList.Designer.cs index b4855b04..bb86f339 100644 --- a/DiztinGUIsh/window/AliasList.Designer.cs +++ b/DiztinGUIsh/window/AliasList.Designer.cs @@ -31,9 +31,11 @@ private void InitializeComponent() System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle18 = new System.Windows.Forms.DataGridViewCellStyle(); System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle16 = new System.Windows.Forms.DataGridViewCellStyle(); System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle17 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle15 = new System.Windows.Forms.DataGridViewCellStyle(); this.dataGridView1 = new System.Windows.Forms.DataGridView(); this.Address = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.Alias = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.Comment = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.import = new System.Windows.Forms.Button(); this.export = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); @@ -54,7 +56,8 @@ private void InitializeComponent() this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; this.dataGridView1.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { this.Address, - this.Alias}); + this.Alias, + this.Comment}); dataGridViewCellStyle18.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; dataGridViewCellStyle18.BackColor = System.Drawing.SystemColors.Window; dataGridViewCellStyle18.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); @@ -76,7 +79,7 @@ private void InitializeComponent() this.dataGridView1.ShowCellToolTips = false; this.dataGridView1.ShowEditingIcon = false; this.dataGridView1.ShowRowErrors = false; - this.dataGridView1.Size = new System.Drawing.Size(200, 310); + this.dataGridView1.Size = new System.Drawing.Size(400, 310); this.dataGridView1.TabIndex = 3; this.dataGridView1.TabStop = false; this.dataGridView1.CellBeginEdit += new System.Windows.Forms.DataGridViewCellCancelEventHandler(this.dataGridView1_CellBeginEdit); @@ -101,6 +104,15 @@ private void InitializeComponent() this.Alias.Name = "Alias"; this.Alias.Width = 138; // + // Comment + // + dataGridViewCellStyle15.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Comment.DefaultCellStyle = dataGridViewCellStyle15; + this.Comment.HeaderText = "Comment"; + this.Comment.MaxInputLength = 800; + this.Comment.Name = "Comment"; + this.Comment.Width = 1000; + // // import // this.import.DialogResult = System.Windows.Forms.DialogResult.Cancel; @@ -126,9 +138,9 @@ private void InitializeComponent() // this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.toolStripStatusLabel1}); - this.statusStrip1.Location = new System.Drawing.Point(0, 339); + this.statusStrip1.Location = new System.Drawing.Point(0, 342); this.statusStrip1.Name = "statusStrip1"; - this.statusStrip1.Size = new System.Drawing.Size(201, 22); + this.statusStrip1.Size = new System.Drawing.Size(402, 22); this.statusStrip1.TabIndex = 4; this.statusStrip1.Text = "statusStrip1"; // @@ -160,14 +172,14 @@ private void InitializeComponent() this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.import; - this.ClientSize = new System.Drawing.Size(201, 361); + this.ClientSize = new System.Drawing.Size(402, 364); this.Controls.Add(this.jump); this.Controls.Add(this.statusStrip1); this.Controls.Add(this.export); this.Controls.Add(this.import); this.Controls.Add(this.dataGridView1); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow; - this.MaximumSize = new System.Drawing.Size(217, 5000); + this.MaximumSize = new System.Drawing.Size(600, 5000); this.MinimumSize = new System.Drawing.Size(217, 250); this.Name = "AliasList"; this.ShowIcon = false; @@ -191,6 +203,7 @@ private void InitializeComponent() private System.Windows.Forms.Button export; private System.Windows.Forms.DataGridViewTextBoxColumn Address; private System.Windows.Forms.DataGridViewTextBoxColumn Alias; + private System.Windows.Forms.DataGridViewTextBoxColumn Comment; private System.Windows.Forms.StatusStrip statusStrip1; private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; private System.Windows.Forms.Button jump; diff --git a/DiztinGUIsh/window/AliasList.cs b/DiztinGUIsh/window/AliasList.cs index 64103fe5..aabfc1e8 100644 --- a/DiztinGUIsh/window/AliasList.cs +++ b/DiztinGUIsh/window/AliasList.cs @@ -63,34 +63,58 @@ private void jump_Click(object sender, EventArgs e) } } + private static void SplitOnFirstComma(string instr, out string first_part, out string remainder) + { + if (!instr.Contains(",")) + { + first_part = instr; + remainder = ""; + return; + } + + first_part = instr.Substring(0, instr.IndexOf(',')); + remainder = instr.Substring(instr.IndexOf(',') + 1); + } + private void import_Click(object sender, EventArgs e) { DialogResult result = openFileDialog1.ShowDialog(); - if (result == DialogResult.OK && openFileDialog1.FileName != "") + if (result != DialogResult.OK || openFileDialog1.FileName == "") + return; + + int errLine = 0; + try { - int errLine = 0; - try - { - Dictionary newValues = new Dictionary(); - string[] lines = File.ReadAllLines(openFileDialog1.FileName); - - for (int i = 0; i < lines.Length; i++) { - errLine = i + 1; - string addr = lines[i].Substring(0, lines[i].IndexOf(',')); - string label = lines[i].Substring(lines[i].IndexOf(',') + 1); - newValues.Add(int.Parse(addr, NumberStyles.HexNumber, null), label); // todo (validate for valid label characters) - } + Dictionary newValues = new Dictionary(); + string[] lines = File.ReadAllLines(openFileDialog1.FileName); + + // NOTE: this is kind of a risky way to parse CSV files, won't deal with weirdness in the comments + // section. + for (int i = 0; i < lines.Length; i++) { + var aliasInfo = new Data.AliasInfo(); + + errLine = i + 1; - foreach (KeyValuePair pair in newValues) Data.AddLabel(pair.Key, pair.Value, true); + AliasList.SplitOnFirstComma(lines[i], out var labelAddress, out var remainder); + AliasList.SplitOnFirstComma(remainder, out aliasInfo.name, out aliasInfo.comment); + + // todo (validate for valid label characters) + newValues.Add(int.Parse(labelAddress, NumberStyles.HexNumber, null), aliasInfo); } - catch (Exception) + + foreach (KeyValuePair pair in newValues) { - MessageBox.Show( - "An error occurred while parsing the file." + - (errLine > 0 ? string.Format(" (Check line {0}.)", errLine) : ""), - "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + pair.Value.CleanUp(); + Data.AddLabel(pair.Key, pair.Value, true); } } + catch (Exception) + { + MessageBox.Show( + "An error occurred while parsing the file." + + (errLine > 0 ? string.Format(" (Check line {0}.)", errLine) : ""), + "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } } private void export_Click(object sender, EventArgs e) @@ -102,9 +126,10 @@ private void export_Click(object sender, EventArgs e) { using (StreamWriter sw = new StreamWriter(saveFileDialog1.FileName)) { - foreach (KeyValuePair pair in Data.GetAllLabels()) + foreach (var pair in Data.GetAllLabels()) { - sw.WriteLine(string.Format("{0},{1}", Util.NumberToBaseString(pair.Key, Util.NumberBase.Hexadecimal, 6), pair.Value)); + sw.WriteLine( + $"{Util.NumberToBaseString(pair.Key, Util.NumberBase.Hexadecimal, 6)},{pair.Value.name},{pair.Value.comment}"); } } } catch (Exception) @@ -141,7 +166,12 @@ private void dataGridView1_CellValidating(object sender, DataGridViewCellValidat if (dataGridView1.Rows[e.RowIndex].IsNewRow) return; int val = -1, oldAddress = -1; int.TryParse((string)dataGridView1.Rows[e.RowIndex].Cells[0].Value, NumberStyles.HexNumber, null, out oldAddress); - string label = (string)dataGridView1.Rows[e.RowIndex].Cells[1].Value; + + var labelAliasInfo = new Data.AliasInfo + { + name = (string) dataGridView1.Rows[e.RowIndex].Cells[1].Value, + comment = (string)dataGridView1.Rows[e.RowIndex].Cells[2].Value, + }; toolStripStatusLabel1.Text = ""; @@ -168,17 +198,24 @@ private void dataGridView1_CellValidating(object sender, DataGridViewCellValidat case 1: { val = oldAddress; - label = e.FormattedValue.ToString(); + labelAliasInfo.name = e.FormattedValue.ToString(); // todo (validate for valid label characters) break; } + case 2: + { + val = oldAddress; + labelAliasInfo.comment = e.FormattedValue.ToString(); + // todo (validate for valid comment characters, if any) + break; + } } locked = true; if (currentlyEditing >= 0) { if (val >= 0) Data.AddLabel(oldAddress, null, true); - Data.AddLabel(val, label, true); + Data.AddLabel(val, labelAliasInfo, true); } locked = false; @@ -186,11 +223,11 @@ private void dataGridView1_CellValidating(object sender, DataGridViewCellValidat mw.InvalidateTable(); } - public void AddRow(int address, string alias) + public void AddRow(int address, Data.AliasInfo alias) { if (!locked) { - dataGridView1.Rows.Add(Util.NumberToBaseString(address, Util.NumberBase.Hexadecimal, 6), alias); + dataGridView1.Rows.Add(Util.NumberToBaseString(address, Util.NumberBase.Hexadecimal, 6), alias.name, alias.comment); dataGridView1.Invalidate(); } } diff --git a/DiztinGUIsh/window/AliasList.resx b/DiztinGUIsh/window/AliasList.resx index 8c39f3a8..f848e8bc 100644 --- a/DiztinGUIsh/window/AliasList.resx +++ b/DiztinGUIsh/window/AliasList.resx @@ -123,6 +123,9 @@ True + + True + 17, 17 diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index ba1bfef6..70eafaf7 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -392,7 +392,7 @@ private void table_CellValueNeeded(object sender, DataGridViewCellValueEventArgs if (row >= Data.GetROMSize()) return; switch (e.ColumnIndex) { - case 0: e.Value = Data.GetLabel(Util.ConvertPCtoSNES(row)); break; + case 0: e.Value = Data.GetLabelName(Util.ConvertPCtoSNES(row)); break; case 1: e.Value = Util.NumberToBaseString(Util.ConvertPCtoSNES(row), Util.NumberBase.Hexadecimal, 6); break; case 2: e.Value = (char)Data.GetROMByte(row); break; case 3: e.Value = Util.NumberToBaseString(Data.GetROMByte(row), DisplayBase); break; @@ -424,7 +424,7 @@ private void table_CellValuePushed(object sender, DataGridViewCellValueEventArgs if (row >= Data.GetROMSize()) return; switch (e.ColumnIndex) { - case 0: Data.AddLabel(Util.ConvertPCtoSNES(row), value, true); break; // todo (validate for valid label characters) + case 0: Data.AddLabel(Util.ConvertPCtoSNES(row), new Data.AliasInfo() {name=value}, true); break; // todo (validate for valid label characters) case 8: if (int.TryParse(value, NumberStyles.HexNumber, null, out result)) Data.SetDataBank(row, result); break; case 9: if (int.TryParse(value, NumberStyles.HexNumber, null, out result)) Data.SetDirectPage(row, result); break; case 10: Data.SetMFlag(row, (value == "8" || value == "M")); break; diff --git a/DiztinGUIsh/window/dialog/ExportDisassembly.Designer.cs b/DiztinGUIsh/window/dialog/ExportDisassembly.Designer.cs index 1dd7a777..ba0d1c9b 100644 --- a/DiztinGUIsh/window/dialog/ExportDisassembly.Designer.cs +++ b/DiztinGUIsh/window/dialog/ExportDisassembly.Designer.cs @@ -42,13 +42,15 @@ private void InitializeComponent() this.label5 = new System.Windows.Forms.Label(); this.label6 = new System.Windows.Forms.Label(); this.numData = new System.Windows.Forms.NumericUpDown(); + this.chkPrintLabelSpecificComments = new System.Windows.Forms.CheckBox(); + this.chkIncludeUnusedLabels = new System.Windows.Forms.CheckBox(); ((System.ComponentModel.ISupportInitialize)(this.numData)).BeginInit(); this.SuspendLayout(); // // cancel // this.cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.cancel.Location = new System.Drawing.Point(9, 444); + this.cancel.Location = new System.Drawing.Point(9, 491); this.cancel.Name = "cancel"; this.cancel.Size = new System.Drawing.Size(75, 23); this.cancel.TabIndex = 12; @@ -59,7 +61,7 @@ private void InitializeComponent() // // button2 // - this.button2.Location = new System.Drawing.Point(487, 444); + this.button2.Location = new System.Drawing.Point(487, 491); this.button2.Name = "button2"; this.button2.Size = new System.Drawing.Size(113, 23); this.button2.TabIndex = 11; @@ -69,7 +71,7 @@ private void InitializeComponent() // // textFormat // - this.textFormat.Location = new System.Drawing.Point(88, 92); + this.textFormat.Location = new System.Drawing.Point(88, 139); this.textFormat.Name = "textFormat"; this.textFormat.Size = new System.Drawing.Size(512, 20); this.textFormat.TabIndex = 8; @@ -78,7 +80,7 @@ private void InitializeComponent() // textSample // this.textSample.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.textSample.Location = new System.Drawing.Point(88, 119); + this.textSample.Location = new System.Drawing.Point(88, 166); this.textSample.Multiline = true; this.textSample.Name = "textSample"; this.textSample.ReadOnly = true; @@ -116,7 +118,7 @@ private void InitializeComponent() // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(12, 95); + this.label1.Location = new System.Drawing.Point(12, 142); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(74, 13); this.label1.TabIndex = 7; @@ -125,7 +127,7 @@ private void InitializeComponent() // label2 // this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(6, 122); + this.label2.Location = new System.Drawing.Point(6, 169); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(80, 13); this.label2.TabIndex = 9; @@ -190,12 +192,38 @@ private void InitializeComponent() 0}); this.numData.ValueChanged += new System.EventHandler(this.numData_ValueChanged); // + // chkPrintLabelSpecificComments + // + this.chkPrintLabelSpecificComments.AutoSize = true; + this.chkPrintLabelSpecificComments.Checked = true; + this.chkPrintLabelSpecificComments.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkPrintLabelSpecificComments.Location = new System.Drawing.Point(376, 93); + this.chkPrintLabelSpecificComments.Name = "chkPrintLabelSpecificComments"; + this.chkPrintLabelSpecificComments.Size = new System.Drawing.Size(225, 17); + this.chkPrintLabelSpecificComments.TabIndex = 13; + this.chkPrintLabelSpecificComments.Text = "Print label-specific comments in labels.asm"; + this.chkPrintLabelSpecificComments.UseVisualStyleBackColor = true; + this.chkPrintLabelSpecificComments.CheckedChanged += new System.EventHandler(this.chkPrintLabelSpecificComments_CheckedChanged); + // + // chkIncludeUnusedLabels + // + this.chkIncludeUnusedLabels.AutoSize = true; + this.chkIncludeUnusedLabels.Location = new System.Drawing.Point(376, 115); + this.chkIncludeUnusedLabels.Name = "chkIncludeUnusedLabels"; + this.chkIncludeUnusedLabels.Size = new System.Drawing.Size(192, 17); + this.chkIncludeUnusedLabels.TabIndex = 14; + this.chkIncludeUnusedLabels.Text = "Include unused labels in labels.asm"; + this.chkIncludeUnusedLabels.UseVisualStyleBackColor = true; + this.chkIncludeUnusedLabels.CheckedChanged += new System.EventHandler(this.chkIncludeUnusedLabels_CheckedChanged); + // // ExportDisassembly // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.cancel; - this.ClientSize = new System.Drawing.Size(612, 479); + this.ClientSize = new System.Drawing.Size(611, 525); + this.Controls.Add(this.chkIncludeUnusedLabels); + this.Controls.Add(this.chkPrintLabelSpecificComments); this.Controls.Add(this.numData); this.Controls.Add(this.label5); this.Controls.Add(this.label4); @@ -235,5 +263,7 @@ private void InitializeComponent() private System.Windows.Forms.Label label5; private System.Windows.Forms.Label label6; private System.Windows.Forms.NumericUpDown numData; + private System.Windows.Forms.CheckBox chkPrintLabelSpecificComments; + private System.Windows.Forms.CheckBox chkIncludeUnusedLabels; } } \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/ExportDisassembly.cs b/DiztinGUIsh/window/dialog/ExportDisassembly.cs index 5ea2b84c..7c7ac70b 100644 --- a/DiztinGUIsh/window/dialog/ExportDisassembly.cs +++ b/DiztinGUIsh/window/dialog/ExportDisassembly.cs @@ -20,6 +20,8 @@ public ExportDisassembly() textFormat.Text = LogCreator.format; comboUnlabeled.SelectedIndex = (int)LogCreator.unlabeled; comboStructure.SelectedIndex = (int)LogCreator.structure; + chkIncludeUnusedLabels.Checked = LogCreator.includeUnusedLabels; + chkPrintLabelSpecificComments.Checked = LogCreator.printLabelSpecificComments; UpdateSample(); } @@ -98,7 +100,8 @@ private void UpdateSample() List tempTable = Data.GetTable(); Data.ROMMapMode tempMode = Data.GetROMMapMode(); Data.ROMSpeed tempSpeed = Data.GetROMSpeed(); - Dictionary tempAlias = Data.GetAllLabels(), tempComment = Data.GetAllComments(); + var tempAlias = Data.GetAllLabels(); + var tempComment = Data.GetAllComments(); LogCreator.FormatStructure tempStructure = LogCreator.structure; Data.Restore(sampleTable, Data.ROMMapMode.LoROM, Data.ROMSpeed.FastROM, sampleAlias, sampleComment); LogCreator.structure = LogCreator.FormatStructure.SingleFile; @@ -244,14 +247,14 @@ private void UpdateSample() new ROMByte {Rom = 0x6D, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, }; - public static Dictionary sampleAlias = new Dictionary + public static Dictionary sampleAlias = new Dictionary { - { 0x00, "Emulation_RESET" }, - { 0x0A, "FastRESET" }, - { 0x32, "Test_Indices" }, - { 0x3A, "Pointer_Table" }, - { 0x44, "First_Routine" }, - { 0x5B, "Test_Data" } + { 0x00, new Data.AliasInfo() {name="Emulation_RESET", comment="Sample emulation reset location"} }, + { 0x0A, new Data.AliasInfo() {name="FastRESET", comment="Sample label" } }, + { 0x32, new Data.AliasInfo() {name="Test_Indices"} }, + { 0x3A, new Data.AliasInfo() {name="Pointer_Table"} }, + { 0x44, new Data.AliasInfo() {name="First_Routine"} }, + { 0x5B, new Data.AliasInfo() {name="Test_Data", comment="Pretty cool huh?" } } }; public static Dictionary sampleComment = new Dictionary @@ -261,5 +264,15 @@ private void UpdateSample() { 0x21, "clear APU regs" }, { 0x44, "this routine copies Test_Data to $7E0100" } }; + + private void chkPrintLabelSpecificComments_CheckedChanged(object sender, EventArgs e) + { + LogCreator.printLabelSpecificComments = chkPrintLabelSpecificComments.Checked; + } + + private void chkIncludeUnusedLabels_CheckedChanged(object sender, EventArgs e) + { + LogCreator.includeUnusedLabels = chkIncludeUnusedLabels.Checked; + } } } diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.cs b/DiztinGUIsh/window/dialog/ImportROMDialog.cs index fdce6f80..2133591b 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.cs @@ -43,9 +43,9 @@ public ImportROMDialog(byte [] rom) UpdateOffsetAndSpeed(); } - public Dictionary GetGeneratedLabels() + public Dictionary GetGeneratedLabels() { - Dictionary labels = new Dictionary(); + var labels = new Dictionary(); for (int i = 0; i < checkboxes.GetLength(0); i++) { @@ -56,7 +56,8 @@ public Dictionary GetGeneratedLabels() int index = offset + 15 + 0x10 * i + 2 * j; int val = data[index] + (data[index + 1] << 8); int pc = Util.ConvertSNEStoPC(val); - if (pc >= 0 && pc < data.Length && !labels.ContainsKey(val)) labels.Add(val, vectorNames[i, j]); + if (pc >= 0 && pc < data.Length && !labels.ContainsKey(val)) + labels.Add(val, new Data.AliasInfo() {name = vectorNames[i, j]}); } } } From 796f133708b18119e5a01eed17e8418f25b4b245 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 30 Aug 2020 22:01:26 -0400 Subject: [PATCH 019/136] increase max label length allowed --- DiztinGUIsh/window/AliasList.Designer.cs | 8 ++++---- DiztinGUIsh/window/MainWindow.Designer.cs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DiztinGUIsh/window/AliasList.Designer.cs b/DiztinGUIsh/window/AliasList.Designer.cs index b4855b04..e8e02858 100644 --- a/DiztinGUIsh/window/AliasList.Designer.cs +++ b/DiztinGUIsh/window/AliasList.Designer.cs @@ -76,7 +76,7 @@ private void InitializeComponent() this.dataGridView1.ShowCellToolTips = false; this.dataGridView1.ShowEditingIcon = false; this.dataGridView1.ShowRowErrors = false; - this.dataGridView1.Size = new System.Drawing.Size(200, 310); + this.dataGridView1.Size = new System.Drawing.Size(400, 310); this.dataGridView1.TabIndex = 3; this.dataGridView1.TabStop = false; this.dataGridView1.CellBeginEdit += new System.Windows.Forms.DataGridViewCellCancelEventHandler(this.dataGridView1_CellBeginEdit); @@ -97,7 +97,7 @@ private void InitializeComponent() dataGridViewCellStyle17.Font = new System.Drawing.Font("Arial Narrow", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Alias.DefaultCellStyle = dataGridViewCellStyle17; this.Alias.HeaderText = "Label"; - this.Alias.MaxInputLength = 20; + this.Alias.MaxInputLength = 60; this.Alias.Name = "Alias"; this.Alias.Width = 138; // @@ -126,9 +126,9 @@ private void InitializeComponent() // this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.toolStripStatusLabel1}); - this.statusStrip1.Location = new System.Drawing.Point(0, 339); + this.statusStrip1.Location = new System.Drawing.Point(0, 342); this.statusStrip1.Name = "statusStrip1"; - this.statusStrip1.Size = new System.Drawing.Size(201, 22); + this.statusStrip1.Size = new System.Drawing.Size(402, 22); this.statusStrip1.TabIndex = 4; this.statusStrip1.Text = "statusStrip1"; // diff --git a/DiztinGUIsh/window/MainWindow.Designer.cs b/DiztinGUIsh/window/MainWindow.Designer.cs index 0110af30..a5958f89 100644 --- a/DiztinGUIsh/window/MainWindow.Designer.cs +++ b/DiztinGUIsh/window/MainWindow.Designer.cs @@ -194,7 +194,7 @@ private void InitializeComponent() dataGridViewCellStyle1.Font = new System.Drawing.Font("Arial Narrow", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.ColumnAlias.DefaultCellStyle = dataGridViewCellStyle1; this.ColumnAlias.HeaderText = "Label"; - this.ColumnAlias.MaxInputLength = 20; + this.ColumnAlias.MaxInputLength = 60; this.ColumnAlias.Name = "ColumnAlias"; this.ColumnAlias.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; // From fad1620efc09966f3f39166c81a394e0c82b1893 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 30 Aug 2020 11:52:07 -0400 Subject: [PATCH 020/136] add support for pasting formatted addresses into GOTO dialog box it can now deal with being pasted stuff like: $C1/08A7 probably needs a bit more testing to make sure validation handles ROM memory bounds correctly, etc. --- DiztinGUIsh/static/Util.cs | 27 +++++++ .../window/dialog/GotoDialog.Designer.cs | 23 ++++-- DiztinGUIsh/window/dialog/GotoDialog.cs | 70 +++++++++++++++---- 3 files changed, 100 insertions(+), 20 deletions(-) diff --git a/DiztinGUIsh/static/Util.cs b/DiztinGUIsh/static/Util.cs index 122c64a3..9f98847e 100644 --- a/DiztinGUIsh/static/Util.cs +++ b/DiztinGUIsh/static/Util.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Drawing; +using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -315,6 +316,32 @@ public static int ByteArrayToInteger(byte[] data, int offset = 0) (data[offset + 3] << 24); } + // deal with addresses that look like this, + // might be pasted from other editors + // C0FFFF + // $C0FFFF + // C7/AAAA + // $C6/BBBB + public static bool StripFormattedAddress(ref string addressTxt, NumberStyles style, out int address) + { + address = -1; + + if (string.IsNullOrEmpty(addressTxt)) + return false; + + var inputText = new string(Array.FindAll(addressTxt.ToCharArray(), (c => + (char.IsLetterOrDigit(c) || char.IsWhiteSpace(c)) + ))); + + if (int.TryParse(inputText, style, null, out address)) + { + addressTxt = inputText; + return true; + } + + return false; + } + public static string TypeToString(Data.FlagType flag) { switch (flag) diff --git a/DiztinGUIsh/window/dialog/GotoDialog.Designer.cs b/DiztinGUIsh/window/dialog/GotoDialog.Designer.cs index 85a15764..970ff256 100644 --- a/DiztinGUIsh/window/dialog/GotoDialog.Designer.cs +++ b/DiztinGUIsh/window/dialog/GotoDialog.Designer.cs @@ -36,6 +36,7 @@ private void InitializeComponent() this.radioDec = new System.Windows.Forms.RadioButton(); this.cancel = new System.Windows.Forms.Button(); this.go = new System.Windows.Forms.Button(); + this.lblError = new System.Windows.Forms.Label(); this.SuspendLayout(); // // label1 @@ -59,7 +60,7 @@ private void InitializeComponent() // textROM // this.textROM.Location = new System.Drawing.Point(103, 12); - this.textROM.MaxLength = 6; + this.textROM.MaxLength = 8; this.textROM.Name = "textROM"; this.textROM.Size = new System.Drawing.Size(46, 20); this.textROM.TabIndex = 1; @@ -71,7 +72,7 @@ private void InitializeComponent() // textPC // this.textPC.Location = new System.Drawing.Point(103, 38); - this.textPC.MaxLength = 6; + this.textPC.MaxLength = 8; this.textPC.Name = "textPC"; this.textPC.Size = new System.Drawing.Size(46, 20); this.textPC.TabIndex = 3; @@ -106,7 +107,7 @@ private void InitializeComponent() // cancel // this.cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.cancel.Location = new System.Drawing.Point(12, 105); + this.cancel.Location = new System.Drawing.Point(12, 121); this.cancel.Name = "cancel"; this.cancel.Size = new System.Drawing.Size(75, 23); this.cancel.TabIndex = 7; @@ -117,7 +118,7 @@ private void InitializeComponent() // // go // - this.go.Location = new System.Drawing.Point(93, 105); + this.go.Location = new System.Drawing.Point(93, 121); this.go.Name = "go"; this.go.Size = new System.Drawing.Size(75, 23); this.go.TabIndex = 6; @@ -125,12 +126,23 @@ private void InitializeComponent() this.go.UseVisualStyleBackColor = true; this.go.Click += new System.EventHandler(this.go_Click); // + // lblError + // + this.lblError.AutoSize = true; + this.lblError.ForeColor = System.Drawing.Color.Red; + this.lblError.Location = new System.Drawing.Point(12, 102); + this.lblError.Name = "lblError"; + this.lblError.Size = new System.Drawing.Size(39, 13); + this.lblError.TabIndex = 8; + this.lblError.Text = "lblError"; + // // GotoDialog // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.cancel; - this.ClientSize = new System.Drawing.Size(180, 140); + this.ClientSize = new System.Drawing.Size(180, 153); + this.Controls.Add(this.lblError); this.Controls.Add(this.go); this.Controls.Add(this.cancel); this.Controls.Add(this.radioDec); @@ -161,5 +173,6 @@ private void InitializeComponent() private System.Windows.Forms.RadioButton radioDec; private System.Windows.Forms.Button cancel; private System.Windows.Forms.Button go; + private System.Windows.Forms.Label lblError; } } \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/GotoDialog.cs b/DiztinGUIsh/window/dialog/GotoDialog.cs index 4ff67e28..5ddd4306 100644 --- a/DiztinGUIsh/window/dialog/GotoDialog.cs +++ b/DiztinGUIsh/window/dialog/GotoDialog.cs @@ -23,6 +23,7 @@ public GotoDialog(int offset) private void GotoDialog_Load(object sender, EventArgs e) { textROM.SelectAll(); + UpdateUI(); } public int GetOffset() @@ -39,38 +40,77 @@ private void Go() private bool updatingText = false; - private void textROM_TextChanged(object sender, EventArgs e) + private bool UpdateTextChanged(string txtChanged, Action onSuccess) { + bool result = false; if (!updatingText) { updatingText = true; NumberStyles style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; Util.NumberBase noBase = radioDec.Checked ? Util.NumberBase.Decimal : Util.NumberBase.Hexadecimal; - if (int.TryParse(textROM.Text, style, null, out int address)) + + if (Util.StripFormattedAddress(ref txtChanged, style, out var address)) { - int pc = Util.ConvertSNEStoPC(address); - if (pc >= 0 && pc < Data.GetROMSize()) textPC.Text = Util.NumberToBaseString(pc, noBase, 0); + onSuccess(txtChanged, address, noBase); + result = true; } updatingText = false; } + + return result; + } + + // For both textbox TextChanged events: + // precondition: unvalidated input in textbox + // postcondtion: valid text is in both textboxes, or, button is greyed out and error message displayed. + + private void UpdateUI() + { + var validOffset = IsValidOffset(); + + if (validOffset) + { + go.Enabled = true; + lblError.Text = ""; + } + else + { + go.Enabled = false; + lblError.Text = "Invalid Offset"; + } + } + + private bool IsValidOffset() + { + const int highest_offset_allowed = 0xFFFFFF; // TODO: not sure this is correct, probably lower. what's highest address for SNES? + + var offset = GetOffset(); + return offset >= 0 && offset <= highest_offset_allowed; + } + + private void textROM_TextChanged(object sender, EventArgs e) + { + UpdateTextChanged(textROM.Text, (finaltext, address, noBase) => + { + int pc = Util.ConvertSNEStoPC(address); + if (pc >= 0 && pc < Data.GetROMSize()) textPC.Text = Util.NumberToBaseString(pc, noBase, 0); + textROM.Text = finaltext; + }); + + UpdateUI(); } private void textPC_TextChanged(object sender, EventArgs e) { - if (!updatingText) + UpdateTextChanged(textPC.Text, (finaltext, offset, noBase) => { - updatingText = true; + int addr = Util.ConvertPCtoSNES(offset); + if (addr >= 0) textROM.Text = Util.NumberToBaseString(addr, noBase, 6); + textPC.Text = finaltext; + }); - NumberStyles style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; - Util.NumberBase noBase = radioDec.Checked ? Util.NumberBase.Decimal : Util.NumberBase.Hexadecimal; - if (int.TryParse(textPC.Text, style, null, out int offset)) - { - int addr = Util.ConvertPCtoSNES(offset); - if (addr >= 0) textROM.Text = Util.NumberToBaseString(addr, noBase, 6); - } - updatingText = false; - } + UpdateUI(); } private void go_Click(object sender, EventArgs e) From a4678efc7f78c08598d46ce33101f3260bf5bfd2 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 1 Sep 2020 04:56:36 -0400 Subject: [PATCH 021/136] better validation for goto dialog box --- DiztinGUIsh/window/MainWindow.cs | 2 +- DiztinGUIsh/window/dialog/GotoDialog.cs | 57 +++++++++++++++++-------- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index ba1bfef6..9f87f797 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -615,7 +615,7 @@ private void gotoToolStripMenuItem_Click(object sender, EventArgs e) DialogResult result = go.ShowDialog(); if (result == DialogResult.OK) { - int offset = go.GetOffset(); + int offset = go.GetPcOffset(); if (offset >= 0 && offset < Data.GetROMSize()) SelectOffset(offset); else MessageBox.Show("That offset is out of range.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } diff --git a/DiztinGUIsh/window/dialog/GotoDialog.cs b/DiztinGUIsh/window/dialog/GotoDialog.cs index 5ddd4306..cc2ef183 100644 --- a/DiztinGUIsh/window/dialog/GotoDialog.cs +++ b/DiztinGUIsh/window/dialog/GotoDialog.cs @@ -26,13 +26,18 @@ private void GotoDialog_Load(object sender, EventArgs e) UpdateUI(); } - public int GetOffset() + private int ParseOffset(string text) { NumberStyles style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; - if (int.TryParse(textPC.Text, style, null, out int offset)) return offset; + if (int.TryParse(text, style, null, out int offset)) return offset; return -1; } + public int GetPcOffset() + { + return ParseOffset(textPC.Text); + } + private void Go() { this.DialogResult = DialogResult.OK; @@ -50,7 +55,7 @@ private bool UpdateTextChanged(string txtChanged, Action= 0) { onSuccess(txtChanged, address, noBase); result = true; @@ -67,35 +72,52 @@ private bool UpdateTextChanged(string txtChanged, Action= 0 && pc < Data.GetROMSize(); + } - var offset = GetOffset(); - return offset >= 0 && offset <= highest_offset_allowed; + private bool IsPCOffsetValid() + { + var offset = GetPcOffset(); + return IsValidPCAddress(offset); + } + + private bool IsRomAddressValid() + { + var address = ParseOffset(textROM.Text); + if (address < 0) + return false; + + return IsValidPCAddress(Util.ConvertSNEStoPC(address)); } private void textROM_TextChanged(object sender, EventArgs e) { - UpdateTextChanged(textROM.Text, (finaltext, address, noBase) => + UpdateTextChanged(textROM.Text,(finaltext, address, noBase) => { int pc = Util.ConvertSNEStoPC(address); - if (pc >= 0 && pc < Data.GetROMSize()) textPC.Text = Util.NumberToBaseString(pc, noBase, 0); + textROM.Text = finaltext; + textPC.Text = Util.NumberToBaseString(pc, noBase, 0); }); UpdateUI(); @@ -106,8 +128,9 @@ private void textPC_TextChanged(object sender, EventArgs e) UpdateTextChanged(textPC.Text, (finaltext, offset, noBase) => { int addr = Util.ConvertPCtoSNES(offset); - if (addr >= 0) textROM.Text = Util.NumberToBaseString(addr, noBase, 6); + textPC.Text = finaltext; + textROM.Text = Util.NumberToBaseString(addr, noBase, 6); }); UpdateUI(); From a0ea9817ff14d008585c1b40b65b2f1d028a54d3 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Thu, 3 Sep 2020 22:11:18 -0400 Subject: [PATCH 022/136] support multiple tracelog imports at once --- DiztinGUIsh/window/MainWindow.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index d1358b34..be352c7d 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -878,13 +878,20 @@ private void ImportUsageMapToolStripMenuItem_Click(object sender, EventArgs e) private void ImportTraceLogToolStripMenuItem_Click(object sender, EventArgs e) { - if (openTraceLogDialog.ShowDialog() == DialogResult.OK) - { - int total = Manager.ImportTraceLog(File.ReadAllLines(openTraceLogDialog.FileName)); + openTraceLogDialog.Multiselect = true; + if (openTraceLogDialog.ShowDialog() != DialogResult.OK) + return; - MessageBox.Show($"Modified total {total} flags!", "Done", - MessageBoxButtons.OK, MessageBoxIcon.Information); + int total = 0; + foreach (var filename in openTraceLogDialog.FileNames) + { + total += Manager.ImportTraceLog(File.ReadAllLines(filename)); } + + MessageBox.Show( + $"Modified total {total} flags from {openTraceLogDialog.FileNames.Length} files!", + "Done", + MessageBoxButtons.OK, MessageBoxIcon.Information); } } } From 95fdbb019be6d367b650fba9507405e05ed8ca42 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 8 Sep 2020 00:57:31 -0400 Subject: [PATCH 023/136] improved import log support - faster - allow selection of multiple files - add progress bar UI funtionality --- DiztinGUIsh/DiztinGUIsh.csproj | 11 ++ DiztinGUIsh/LargeFileReader.cs | 55 ++++++ DiztinGUIsh/ProgressBarWorker.cs | 79 ++++++++ DiztinGUIsh/static/Util.cs | 23 +++ DiztinGUIsh/static/diz/Manager.cs | 118 ++++++++---- DiztinGUIsh/window/MainWindow.cs | 170 +++++++++++++----- .../window/dialog/ProgressDialog.Designer.cs | 89 +++++++++ DiztinGUIsh/window/dialog/ProgressDialog.cs | 34 ++++ DiztinGUIsh/window/dialog/ProgressDialog.resx | 120 +++++++++++++ 9 files changed, 616 insertions(+), 83 deletions(-) create mode 100644 DiztinGUIsh/LargeFileReader.cs create mode 100644 DiztinGUIsh/ProgressBarWorker.cs create mode 100644 DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs create mode 100644 DiztinGUIsh/window/dialog/ProgressDialog.cs create mode 100644 DiztinGUIsh/window/dialog/ProgressDialog.resx diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 0e227dc9..2e06a93c 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -68,6 +68,8 @@ + + Form @@ -75,6 +77,12 @@ About.cs + + Form + + + ProgressDialog.cs + Form @@ -143,6 +151,9 @@ About.cs + + ProgressDialog.cs + ExportDisassembly.cs diff --git a/DiztinGUIsh/LargeFileReader.cs b/DiztinGUIsh/LargeFileReader.cs new file mode 100644 index 00000000..53c1a30a --- /dev/null +++ b/DiztinGUIsh/LargeFileReader.cs @@ -0,0 +1,55 @@ +using System; +using System.IO; + +namespace DiztinGUIsh +{ + public class LargeFileReader : ProgressBarWorker + { + public string Filename { get; set; } + public Action LineReadCallback { get; set; } + + protected long FileLengthInBytes { get; set; } + + protected override void Thread_DoWork() + { + using (var fs = File.Open(Filename, FileMode.Open, FileAccess.Read)) + using (var bs = new BufferedStream(fs)) + using (var sr = new StreamReader(bs)) + { + FileLengthInBytes = fs.Length; + + string line; + while ((line = sr.ReadLine()) != null) + { + this.LineReadCallback(line); + this.UpdateProgress(fs.Position); + } + } + } + + private int previousProgress = 0; + + protected void UpdateProgress(long currentPositionInBytes) + { + float percent = (float)currentPositionInBytes / (float)FileLengthInBytes; + int progressValue = (int)(percent * 100); + + if (progressValue <= previousProgress) + return; + + // don't do this too often, kinda slow due to thread synchronization. + base.UpdateProgress(progressValue); + + previousProgress = progressValue; + } + public static void ReadFileLines(string filename, Action lineReadCallback) + { + var lfr = new LargeFileReader() + { + Filename = filename, + LineReadCallback = lineReadCallback, + }; + lfr.Run(); + } + } +} diff --git a/DiztinGUIsh/ProgressBarWorker.cs b/DiztinGUIsh/ProgressBarWorker.cs new file mode 100644 index 00000000..4fa31fd7 --- /dev/null +++ b/DiztinGUIsh/ProgressBarWorker.cs @@ -0,0 +1,79 @@ +using System; +using System.Threading; +using DiztinGUIsh.window.dialog; + +namespace DiztinGUIsh +{ public abstract class ProgressBarWorker + { + private ProgressDialog Dialog = null; + private bool IsRunning = false; + private Thread backgroundThread = null; + + protected void UpdateProgress(int i) + { + // i must be in range of 0 to 100 + Dialog.UpdateProgress(i); + } + + protected abstract void Thread_DoWork(); + + // call from main thread to start a long-running job + // + // shows a progress bar dialog box while the work is being performed + // note: we're not being super-careful about thread safety here. + // if main thread is blocked it should be fine, but, if other things can + // still happen in the background, be really careful. + public void Run() + { + Setup(); + backgroundThread.Start(); + WaitForJobToFinish(); + } + + protected virtual void Setup() + { + if (IsRunning) + throw new InvalidOperationException( + "Progress bar already running, existing job must finish first"); + + IsRunning = true; + + Dialog = new ProgressDialog(); + + // setup, but don't start, the new thread + backgroundThread = new Thread(new ThreadStart(Thread_Main)); + } + + // blocking function + private void WaitForJobToFinish() + { + // blocks til worker thread closes this dialog box + Dialog.ShowDialog(); + } + + // called from a new worker thread + private void Thread_Main() + { + try + { + // BAD APPROACH. we should instead get an event + // I'm too lazy right now. TODO FIXME + while (!Dialog.Visible) + Thread.Sleep(50); + + Thread_DoWork(); + } + finally + { + IsRunning = false; + SignalJobIsDone(); + } + } + + private void SignalJobIsDone() + { + // unblock the main thread from ShowDialog() + Dialog?.BeginInvoke(new Action(() => Dialog.Close())); + } + } +} diff --git a/DiztinGUIsh/static/Util.cs b/DiztinGUIsh/static/Util.cs index f91b205a..95c38ce7 100644 --- a/DiztinGUIsh/static/Util.cs +++ b/DiztinGUIsh/static/Util.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Drawing; using System.Globalization; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -578,5 +580,26 @@ public static void PaintCell(int offset, DataGridViewCellStyle style, int column ) style.BackColor = Color.DeepPink; } } + + public static long GetFileSizeInBytes(string filename) + { + FileInfo fi = new FileInfo(filename); + if (!fi.Exists) + return -1; + + return fi.Length; + } + public static void InvokeIfRequired(this ISynchronizeInvoke obj, MethodInvoker action) + { + if (obj.InvokeRequired) + { + var args = new object[0]; + obj.Invoke(action, args); + } + else + { + action(); + } + } } } diff --git a/DiztinGUIsh/static/diz/Manager.cs b/DiztinGUIsh/static/diz/Manager.cs index 5a691d01..d276a880 100644 --- a/DiztinGUIsh/static/diz/Manager.cs +++ b/DiztinGUIsh/static/diz/Manager.cs @@ -1,9 +1,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace DiztinGUIsh { @@ -299,50 +296,101 @@ public static int ImportUsageMap(byte[] usageMap) return modified; } - public static int ImportTraceLog(string[] lines) + public static int ImportTraceLog(string filename) { - // Must follow this format. - // 028cde rep #$30 A:0004 X:0000 Y:0004 S:1fdd D:0000 DB:02 nvmxdiZC V:133 H: 654 F:36 - bool unsaved = false; - int modified = 0; - int size = Data.GetROMSize(); + var numberOfAddressesModified = 0; - foreach (var line in lines) + // caution: trace logs can be gigantic, even a few seconds can be > 1GB + LargeFileReader.ReadFileLines(filename, delegate (string line) { - if (line.Length < 80) - { - continue; - } + numberOfAddressesModified += ImportTraceLogLine(line); + }); - // TODO: error treatment - // TODO: parse MX flags - int directPageIndex = line.IndexOf("D:") + 2; - int dataBankIndex = line.IndexOf("DB:") + 3; + return numberOfAddressesModified; + } - int snesAddress = Convert.ToInt32(line.Substring(0, 6), 16); - int directPage = Convert.ToInt32(line.Substring(directPageIndex, 4), 16); - int dataBank = Convert.ToInt32(line.Substring(dataBankIndex, 2), 16); + // this class exists for performance optimization ONLY. + // class representing offsets into a trace log + // we calculate it once from sample data and hang onto it + private class CachedTraceLineIndex + { + private string sample = + "028cde rep #$30 A:0004 X:0000 Y:0004 S:1fdd D:0000 DB:02 nvmxdiZC V:133 H: 654 F:36"; - int pc = Util.ConvertSNEStoPC(snesAddress); + // index of the start of the info + public readonly int + addr, + D, DB, + flags, + f_N, f_V, f_M, f_X, f_D, f_I, f_Z, f_C; - if (pc == -1) + public CachedTraceLineIndex() + { + int SkipToken(string token) { - continue; + return sample.IndexOf(token) + token.Length; } - Data.SetFlag(pc, Data.FlagType.Opcode); - - do - { - Data.SetDataBank(pc, dataBank); - Data.SetDirectPage(pc, directPage); - pc++; - unsaved = true; - modified++; - } while (pc < size && Data.GetFlag(pc) == Data.FlagType.Operand); + addr = 0; + D = SkipToken("D:"); + DB = SkipToken("DB:"); + flags = DB + 3; + + // flags: nvmxdizc + f_N = flags + 0; + f_V = flags + 1; + f_M = flags + 2; + f_X = flags + 3; + f_D = flags + 4; + f_I = flags + 5; + f_Z = flags + 6; + f_C = flags + 7; } + } - Project.unsavedChanges |= unsaved; + static CachedTraceLineIndex CachedIdx = new CachedTraceLineIndex(); + + private static int ImportTraceLogLine(string line) + { + // caution: very performance-sensitive function, please take care when making modifications + // string.IndexOf() is super-slow too. + // Input lines must follow this strict format and be this exact formatting and column indices. + // 028cde rep #$30 A:0004 X:0000 Y:0004 S:1fdd D:0000 DB:02 nvmxdiZC V:133 H: 654 F:36 + + int GetHexValueAt(int startIndex, int length) { + return Convert.ToInt32(line.Substring(startIndex, length), 16); + } + + if (line.Length < 80) + return 0; + + int snesAddress = GetHexValueAt(0, 6); + int pc = Util.ConvertSNEStoPC(snesAddress); + if (pc == -1) + return 0; + + // TODO: error treatment + + int directPage = GetHexValueAt(CachedIdx.D, 4); + int dataBank = GetHexValueAt(CachedIdx.DB, 2); + bool xflag_set = line[CachedIdx.f_X] == 'x'; + bool mflag_set = line[CachedIdx.f_M] == 'm'; + + Data.SetFlag(pc, Data.FlagType.Opcode); + + int modified = 0; + int size = Data.GetROMSize(); + do + { + Data.SetDataBank(pc, dataBank); + Data.SetDirectPage(pc, directPage); + Data.SetXFlag(pc, xflag_set); + Data.SetMFlag(pc, mflag_set); + + pc++; + modified++; + } while (pc < size && Data.GetFlag(pc) == Data.FlagType.Operand); + Project.unsavedChanges = true; return modified; } diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index be352c7d..278cfaad 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -69,7 +69,7 @@ private void MainWindow_Load(object sender, EventArgs e) public void UpdateWindowTitle() { this.Text = - (Project.unsavedChanges ? "*" : "") + + (Project.unsavedChanges ? "*" : "") + (Project.currentFile == null ? "New Project" : Project.currentFile) + " - DiztinGUIsh"; } @@ -78,9 +78,11 @@ private bool ContinueUnsavedChanges() { if (Project.unsavedChanges) { - DialogResult confirm = MessageBox.Show("You have unsaved changes. They will be lost if you continue.", "Unsaved Changes", MessageBoxButtons.OKCancel); + DialogResult confirm = MessageBox.Show("You have unsaved changes. They will be lost if you continue.", + "Unsaved Changes", MessageBoxButtons.OKCancel); return confirm == DialogResult.OK; } + return true; } @@ -203,7 +205,8 @@ private void exportLogToolStripMenuItem_Click(object sender, EventArgs e) file = saveLogSingleFile.FileName; error = Path.GetDirectoryName(file) + "/error.txt"; } - } else + } + else { chooseLogFolder.SelectedPath = Path.GetDirectoryName(Project.currentFile); result = chooseLogFolder.ShowDialog(); @@ -221,9 +224,14 @@ private void exportLogToolStripMenuItem_Click(object sender, EventArgs e) using (StreamWriter er = new StreamWriter(error)) { errors = LogCreator.CreateLog(sw, er); - if (errors > 0) MessageBox.Show("Disassembly created with errors. See errors.txt for details.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - else MessageBox.Show("Disassembly created successfully!", "Complete", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); + if (errors > 0) + MessageBox.Show("Disassembly created with errors. See errors.txt for details.", "Warning", + MessageBoxButtons.OK, MessageBoxIcon.Warning); + else + MessageBox.Show("Disassembly created successfully!", "Complete", MessageBoxButtons.OK, + MessageBoxIcon.Asterisk); } + if (errors == 0) File.Delete(error); } } @@ -234,7 +242,8 @@ private void viewHelpToolStripMenuItem_Click(object sender, EventArgs e) try { System.Diagnostics.Process.Start(Directory.GetCurrentDirectory() + "/help.html"); - } catch (Exception) + } + catch (Exception) { MessageBox.Show("Can't find the help file.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } @@ -287,7 +296,9 @@ private void UpdateBase(Util.NumberBase noBase) public void UpdatePercent() { int totalUnreached = 0, size = Data.GetROMSize(); - for (int i = 0; i < size; i++) if (Data.GetFlag(i) == Data.FlagType.Unreached) totalUnreached++; + for (int i = 0; i < size; i++) + if (Data.GetFlag(i) == Data.FlagType.Unreached) + totalUnreached++; int reached = size - totalUnreached; percentComplete.Text = string.Format("{0:N3}% ({1:D}/{2:D})", reached * 100.0 / size, reached, size); } @@ -344,7 +355,8 @@ private void vScrollBar1_ValueChanged(object sender, EventArgs e) UpdateDataGridView(); if (selOffset < viewOffset) table.CurrentCell = table.Rows[0].Cells[table.CurrentCell.ColumnIndex]; - else if (selOffset >= viewOffset + rowsToShow) table.CurrentCell = table.Rows[rowsToShow - 1].Cells[table.CurrentCell.ColumnIndex]; + else if (selOffset >= viewOffset + rowsToShow) + table.CurrentCell = table.Rows[rowsToShow - 1].Cells[table.CurrentCell.ColumnIndex]; else table.CurrentCell = table.Rows[selOffset - viewOffset].Cells[table.CurrentCell.ColumnIndex]; InvalidateTable(); @@ -392,14 +404,30 @@ private void table_KeyDown(object sender, KeyEventArgs e) amount = amount + 1 >= table.ColumnCount ? table.ColumnCount - 1 : amount + 1; table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[amount]; break; - case Keys.S: Step(offset); break; - case Keys.I: StepIn(offset); break; - case Keys.A: AutoStepSafe(offset); break; - case Keys.T: GoToIntermediateAddress(offset); break; - case Keys.U: GoToUnreached(true, true); break; - case Keys.H: GoToUnreached(false, false); break; - case Keys.N: GoToUnreached(false, true); break; - case Keys.K: Mark(offset); break; + case Keys.S: + Step(offset); + break; + case Keys.I: + StepIn(offset); + break; + case Keys.A: + AutoStepSafe(offset); + break; + case Keys.T: + GoToIntermediateAddress(offset); + break; + case Keys.U: + GoToUnreached(true, true); + break; + case Keys.H: + GoToUnreached(false, false); + break; + case Keys.N: + GoToUnreached(false, true); + break; + case Keys.K: + Mark(offset); + break; case Keys.L: table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[0]; table.BeginEdit(true); @@ -423,6 +451,7 @@ private void table_KeyDown(object sender, KeyEventArgs e) table.BeginEdit(true); break; } + e.Handled = true; InvalidateTable(); } @@ -433,11 +462,21 @@ private void table_CellValueNeeded(object sender, DataGridViewCellValueEventArgs if (row >= Data.GetROMSize()) return; switch (e.ColumnIndex) { - case 0: e.Value = Data.GetLabelName(Util.ConvertPCtoSNES(row)); break; - case 1: e.Value = Util.NumberToBaseString(Util.ConvertPCtoSNES(row), Util.NumberBase.Hexadecimal, 6); break; - case 2: e.Value = (char)Data.GetROMByte(row); break; - case 3: e.Value = Util.NumberToBaseString(Data.GetROMByte(row), DisplayBase); break; - case 4: e.Value = Util.PointToString(Data.GetInOutPoint(row)); break; + case 0: + e.Value = Data.GetLabelName(Util.ConvertPCtoSNES(row)); + break; + case 1: + e.Value = Util.NumberToBaseString(Util.ConvertPCtoSNES(row), Util.NumberBase.Hexadecimal, 6); + break; + case 2: + e.Value = (char) Data.GetROMByte(row); + break; + case 3: + e.Value = Util.NumberToBaseString(Data.GetROMByte(row), DisplayBase); + break; + case 4: + e.Value = Util.PointToString(Data.GetInOutPoint(row)); + break; case 5: int len = Manager.GetInstructionLength(row); if (row + len <= Data.GetROMSize()) e.Value = Util.GetInstruction(row); @@ -448,12 +487,24 @@ private void table_CellValueNeeded(object sender, DataGridViewCellValueEventArgs if (ia >= 0) e.Value = Util.NumberToBaseString(ia, Util.NumberBase.Hexadecimal, 6); else e.Value = ""; break; - case 7: e.Value = Util.TypeToString(Data.GetFlag(row)); break; - case 8: e.Value = Util.NumberToBaseString(Data.GetDataBank(row), Util.NumberBase.Hexadecimal, 2); break; - case 9: e.Value = Util.NumberToBaseString(Data.GetDirectPage(row), Util.NumberBase.Hexadecimal, 4); break; - case 10: e.Value = Util.BoolToSize(Data.GetMFlag(row)); break; - case 11: e.Value = Util.BoolToSize(Data.GetXFlag(row)); break; - case 12: e.Value = Data.GetComment(Util.ConvertPCtoSNES(row)); break; + case 7: + e.Value = Util.TypeToString(Data.GetFlag(row)); + break; + case 8: + e.Value = Util.NumberToBaseString(Data.GetDataBank(row), Util.NumberBase.Hexadecimal, 2); + break; + case 9: + e.Value = Util.NumberToBaseString(Data.GetDirectPage(row), Util.NumberBase.Hexadecimal, 4); + break; + case 10: + e.Value = Util.BoolToSize(Data.GetMFlag(row)); + break; + case 11: + e.Value = Util.BoolToSize(Data.GetXFlag(row)); + break; + case 12: + e.Value = Data.GetComment(Util.ConvertPCtoSNES(row)); + break; } } @@ -465,13 +516,26 @@ private void table_CellValuePushed(object sender, DataGridViewCellValueEventArgs if (row >= Data.GetROMSize()) return; switch (e.ColumnIndex) { - case 0: Data.AddLabel(Util.ConvertPCtoSNES(row), new Data.AliasInfo() {name=value}, true); break; // todo (validate for valid label characters) - case 8: if (int.TryParse(value, NumberStyles.HexNumber, null, out result)) Data.SetDataBank(row, result); break; - case 9: if (int.TryParse(value, NumberStyles.HexNumber, null, out result)) Data.SetDirectPage(row, result); break; - case 10: Data.SetMFlag(row, (value == "8" || value == "M")); break; - case 11: Data.SetXFlag(row, (value == "8" || value == "X")); break; - case 12: Data.AddComment(Util.ConvertPCtoSNES(row), value, true); break; + case 0: + Data.AddLabel(Util.ConvertPCtoSNES(row), new Data.AliasInfo() {name = value}, true); + break; // todo (validate for valid label characters) + case 8: + if (int.TryParse(value, NumberStyles.HexNumber, null, out result)) Data.SetDataBank(row, result); + break; + case 9: + if (int.TryParse(value, NumberStyles.HexNumber, null, out result)) Data.SetDirectPage(row, result); + break; + case 10: + Data.SetMFlag(row, (value == "8" || value == "M")); + break; + case 11: + Data.SetXFlag(row, (value == "8" || value == "X")); + break; + case 12: + Data.AddComment(Util.ConvertPCtoSNES(row), value, true); + break; } + table.InvalidateRow(e.RowIndex); } @@ -490,12 +554,14 @@ public void SelectOffset(int offset, int column = -1) viewOffset = offset; UpdateDataGridView(); table.CurrentCell = table.Rows[0].Cells[col]; - } else if (offset >= viewOffset + rowsToShow) + } + else if (offset >= viewOffset + rowsToShow) { viewOffset = offset - rowsToShow + 1; UpdateDataGridView(); table.CurrentCell = table.Rows[rowsToShow - 1].Cells[col]; - } else + } + else { table.CurrentCell = table.Rows[offset - viewOffset].Cells[col]; } @@ -554,24 +620,26 @@ private void MarkMany(int offset, int column) switch (col) { case 0: - destination = Manager.Mark(mark.GetOffset(), (Data.FlagType)mark.GetValue(), mark.GetCount()); + destination = Manager.Mark(mark.GetOffset(), (Data.FlagType) mark.GetValue(), mark.GetCount()); break; case 1: - destination = Manager.MarkDataBank(mark.GetOffset(), (int)mark.GetValue(), mark.GetCount()); + destination = Manager.MarkDataBank(mark.GetOffset(), (int) mark.GetValue(), mark.GetCount()); break; case 2: - destination = Manager.MarkDirectPage(mark.GetOffset(), (int)mark.GetValue(), mark.GetCount()); + destination = Manager.MarkDirectPage(mark.GetOffset(), (int) mark.GetValue(), mark.GetCount()); break; case 3: - destination = Manager.MarkMFlag(mark.GetOffset(), (bool)mark.GetValue(), mark.GetCount()); + destination = Manager.MarkMFlag(mark.GetOffset(), (bool) mark.GetValue(), mark.GetCount()); break; case 4: - destination = Manager.MarkXFlag(mark.GetOffset(), (bool)mark.GetValue(), mark.GetCount()); + destination = Manager.MarkXFlag(mark.GetOffset(), (bool) mark.GetValue(), mark.GetCount()); break; case 5: - destination = Manager.MarkArchitechture(mark.GetOffset(), (Data.Architechture)mark.GetValue(), mark.GetCount()); + destination = Manager.MarkArchitechture(mark.GetOffset(), (Data.Architechture) mark.GetValue(), + mark.GetCount()); break; } + if (MoveWithStep) SelectOffset(destination); UpdatePercent(); UpdateWindowTitle(); @@ -600,9 +668,12 @@ private void GoToUnreached(bool end, bool direction) if (direction) { - if (!end) while (unreached < size - 1 && Data.GetFlag(unreached) == Data.FlagType.Unreached) unreached++; + if (!end) + while (unreached < size - 1 && Data.GetFlag(unreached) == Data.FlagType.Unreached) + unreached++; while (unreached < size - 1 && Data.GetFlag(unreached) != Data.FlagType.Unreached) unreached++; - } else + } + else { if (unreached > 0) unreached--; while (unreached > 0 && Data.GetFlag(unreached) != Data.FlagType.Unreached) unreached--; @@ -657,8 +728,10 @@ private void gotoToolStripMenuItem_Click(object sender, EventArgs e) if (result == DialogResult.OK) { int offset = go.GetPcOffset(); - if (offset >= 0 && offset < Data.GetROMSize()) SelectOffset(offset); - else MessageBox.Show("That offset is out of range.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + if (offset >= 0 && offset < Data.GetROMSize()) SelectOffset(offset); + else + MessageBox.Show("That offset is out of range.", "Error", MessageBoxButtons.OK, + MessageBoxIcon.Error); } } @@ -740,7 +813,8 @@ private void fixMisalignedInstructionsToolStripMenuItem_Click(object sender, Eve { int count = Manager.FixMisalignedFlags(); InvalidateTable(); - MessageBox.Show(string.Format("Modified {0} flags!", count), "Done!", MessageBoxButtons.OK, MessageBoxIcon.Information); + MessageBox.Show(string.Format("Modified {0} flags!", count), "Done!", MessageBoxButtons.OK, + MessageBoxIcon.Information); } } @@ -885,7 +959,7 @@ private void ImportTraceLogToolStripMenuItem_Click(object sender, EventArgs e) int total = 0; foreach (var filename in openTraceLogDialog.FileNames) { - total += Manager.ImportTraceLog(File.ReadAllLines(filename)); + total += Manager.ImportTraceLog(filename); } MessageBox.Show( @@ -894,4 +968,4 @@ private void ImportTraceLogToolStripMenuItem_Click(object sender, EventArgs e) MessageBoxButtons.OK, MessageBoxIcon.Information); } } -} +} \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs b/DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs new file mode 100644 index 00000000..0e1c3e4b --- /dev/null +++ b/DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs @@ -0,0 +1,89 @@ +namespace DiztinGUIsh.window.dialog +{ + partial class ProgressDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.progressBar1 = new System.Windows.Forms.ProgressBar(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(15, 11); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(69, 16); + this.label1.TabIndex = 0; + this.label1.Text = "Progress: "; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(90, 11); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(93, 16); + this.label2.TabIndex = 1; + this.label2.Text = "[progress text]"; + // + // progressBar1 + // + this.progressBar1.Location = new System.Drawing.Point(11, 42); + this.progressBar1.Name = "progressBar1"; + this.progressBar1.Size = new System.Drawing.Size(292, 23); + this.progressBar1.TabIndex = 2; + // + // ProgressDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(315, 78); + this.Controls.Add(this.progressBar1); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ProgressDialog"; + this.Padding = new System.Windows.Forms.Padding(12, 11, 12, 11); + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Working..."; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.ProgressBar progressBar1; + } +} diff --git a/DiztinGUIsh/window/dialog/ProgressDialog.cs b/DiztinGUIsh/window/dialog/ProgressDialog.cs new file mode 100644 index 00000000..ac08acee --- /dev/null +++ b/DiztinGUIsh/window/dialog/ProgressDialog.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace DiztinGUIsh.window.dialog +{ + public partial class ProgressDialog : Form + { + public ProgressDialog() + { + InitializeComponent(); + progressBar1.Value = 0; + progressBar1.Maximum = 100; + } + + public void UpdateProgress(int i) + { + this.InvokeIfRequired(() => + { + progressBar1.Value = i; + var percentDone = (int)((float)progressBar1.Value / (float)progressBar1.Maximum); + + label2.Text = $@"{percentDone}"; + }); + } + } +} + diff --git a/DiztinGUIsh/window/dialog/ProgressDialog.resx b/DiztinGUIsh/window/dialog/ProgressDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/DiztinGUIsh/window/dialog/ProgressDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file From 22ff9b10f375edffb898c06db1443fb19a3460e7 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 15 Sep 2020 19:13:07 -0400 Subject: [PATCH 024/136] fix progress bar display --- DiztinGUIsh/window/dialog/ProgressDialog.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DiztinGUIsh/window/dialog/ProgressDialog.cs b/DiztinGUIsh/window/dialog/ProgressDialog.cs index ac08acee..3b3318af 100644 --- a/DiztinGUIsh/window/dialog/ProgressDialog.cs +++ b/DiztinGUIsh/window/dialog/ProgressDialog.cs @@ -24,9 +24,9 @@ public void UpdateProgress(int i) this.InvokeIfRequired(() => { progressBar1.Value = i; - var percentDone = (int)((float)progressBar1.Value / (float)progressBar1.Maximum); + var percentDone = (int)(100*((float)progressBar1.Value / (float)progressBar1.Maximum)); - label2.Text = $@"{percentDone}"; + label2.Text = $@"{percentDone}%"; }); } } From ae9a93f6f442ee3468e057ad1702d52d4eeaf6c7 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 15 Sep 2020 19:13:32 -0400 Subject: [PATCH 025/136] progress bar now covers all files --- DiztinGUIsh/DiztinGUIsh.csproj | 2 +- DiztinGUIsh/LargeFileReader.cs | 55 -------------------------- DiztinGUIsh/LargeFilesReader.cs | 66 +++++++++++++++++++++++++++++++ DiztinGUIsh/static/diz/Manager.cs | 20 ++-------- DiztinGUIsh/window/MainWindow.cs | 16 ++++---- 5 files changed, 80 insertions(+), 79 deletions(-) delete mode 100644 DiztinGUIsh/LargeFileReader.cs create mode 100644 DiztinGUIsh/LargeFilesReader.cs diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 2e06a93c..89b77ee8 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -68,7 +68,7 @@ - + Form diff --git a/DiztinGUIsh/LargeFileReader.cs b/DiztinGUIsh/LargeFileReader.cs deleted file mode 100644 index 53c1a30a..00000000 --- a/DiztinGUIsh/LargeFileReader.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.IO; - -namespace DiztinGUIsh -{ - public class LargeFileReader : ProgressBarWorker - { - public string Filename { get; set; } - public Action LineReadCallback { get; set; } - - protected long FileLengthInBytes { get; set; } - - protected override void Thread_DoWork() - { - using (var fs = File.Open(Filename, FileMode.Open, FileAccess.Read)) - using (var bs = new BufferedStream(fs)) - using (var sr = new StreamReader(bs)) - { - FileLengthInBytes = fs.Length; - - string line; - while ((line = sr.ReadLine()) != null) - { - this.LineReadCallback(line); - this.UpdateProgress(fs.Position); - } - } - } - - private int previousProgress = 0; - - protected void UpdateProgress(long currentPositionInBytes) - { - float percent = (float)currentPositionInBytes / (float)FileLengthInBytes; - int progressValue = (int)(percent * 100); - - if (progressValue <= previousProgress) - return; - - // don't do this too often, kinda slow due to thread synchronization. - base.UpdateProgress(progressValue); - - previousProgress = progressValue; - } - public static void ReadFileLines(string filename, Action lineReadCallback) - { - var lfr = new LargeFileReader() - { - Filename = filename, - LineReadCallback = lineReadCallback, - }; - lfr.Run(); - } - } -} diff --git a/DiztinGUIsh/LargeFilesReader.cs b/DiztinGUIsh/LargeFilesReader.cs new file mode 100644 index 00000000..9e242ab6 --- /dev/null +++ b/DiztinGUIsh/LargeFilesReader.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace DiztinGUIsh +{ + public class LargeFilesReader : ProgressBarWorker + { + public List Filenames { get; set; } + public Action LineReadCallback { get; set; } + + protected long SumFileLengthsInBytes { get; set; } + protected long BytesReadFromPreviousFiles { get; set; } + + protected override void Thread_DoWork() + { + SumFileLengthsInBytes = 0L; + foreach (var filename in Filenames) + { + SumFileLengthsInBytes += Util.GetFileSizeInBytes(filename); + } + + BytesReadFromPreviousFiles = 0L; + foreach (var filename in Filenames) { + using (var fs = File.Open(filename, FileMode.Open, FileAccess.Read)) + using (var bs = new BufferedStream(fs)) + using (var sr = new StreamReader(bs)) + { + string line; + while ((line = sr.ReadLine()) != null) + { + this.LineReadCallback(line); + this.UpdateProgress(fs.Position); + } + + BytesReadFromPreviousFiles += fs.Length; + } + } + } + + private int previousProgress = 0; + + protected void UpdateProgress(long currentPositionInBytes) + { + float percent = (float)(BytesReadFromPreviousFiles + currentPositionInBytes) / (float)SumFileLengthsInBytes; + int progressValue = (int)(percent * 100); + + if (progressValue <= previousProgress) + return; + + // don't do this too often, kinda slow due to thread synchronization. + base.UpdateProgress(progressValue); + + previousProgress = progressValue; + } + public static void ReadFilesLines(string[] filenames, Action lineReadCallback) + { + var lfr = new LargeFilesReader() + { + Filenames = new List(filenames), + LineReadCallback = lineReadCallback, + }; + lfr.Run(); + } + } +} diff --git a/DiztinGUIsh/static/diz/Manager.cs b/DiztinGUIsh/static/diz/Manager.cs index d276a880..0a15c2a6 100644 --- a/DiztinGUIsh/static/diz/Manager.cs +++ b/DiztinGUIsh/static/diz/Manager.cs @@ -296,19 +296,6 @@ public static int ImportUsageMap(byte[] usageMap) return modified; } - public static int ImportTraceLog(string filename) - { - var numberOfAddressesModified = 0; - - // caution: trace logs can be gigantic, even a few seconds can be > 1GB - LargeFileReader.ReadFileLines(filename, delegate (string line) - { - numberOfAddressesModified += ImportTraceLogLine(line); - }); - - return numberOfAddressesModified; - } - // this class exists for performance optimization ONLY. // class representing offsets into a trace log // we calculate it once from sample data and hang onto it @@ -350,7 +337,7 @@ int SkipToken(string token) static CachedTraceLineIndex CachedIdx = new CachedTraceLineIndex(); - private static int ImportTraceLogLine(string line) + public static int ImportTraceLogLine(string line) { // caution: very performance-sensitive function, please take care when making modifications // string.IndexOf() is super-slow too. @@ -373,8 +360,9 @@ int GetHexValueAt(int startIndex, int length) { int directPage = GetHexValueAt(CachedIdx.D, 4); int dataBank = GetHexValueAt(CachedIdx.DB, 2); - bool xflag_set = line[CachedIdx.f_X] == 'x'; - bool mflag_set = line[CachedIdx.f_M] == 'm'; + + bool xflag_set = line[CachedIdx.f_X] != 'x'; // X = unchecked (8), x = checked (16) + bool mflag_set = line[CachedIdx.f_M] != 'm'; // M = unchecked (8), m = checked (16) Data.SetFlag(pc, Data.FlagType.Opcode); diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 278cfaad..a640f631 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -956,16 +956,18 @@ private void ImportTraceLogToolStripMenuItem_Click(object sender, EventArgs e) if (openTraceLogDialog.ShowDialog() != DialogResult.OK) return; - int total = 0; - foreach (var filename in openTraceLogDialog.FileNames) + var totalLinesSoFar = 0L; + + // caution: trace logs can be gigantic, even a few seconds can be > 1GB + LargeFilesReader.ReadFilesLines(openTraceLogDialog.FileNames, delegate (string line) { - total += Manager.ImportTraceLog(filename); - } + totalLinesSoFar += Manager.ImportTraceLogLine(line); + }); MessageBox.Show( - $"Modified total {total} flags from {openTraceLogDialog.FileNames.Length} files!", - "Done", - MessageBoxButtons.OK, MessageBoxIcon.Information); + $"Modified total {totalLinesSoFar} flags from {openTraceLogDialog.FileNames.Length} files!", + "Done", + MessageBoxButtons.OK, MessageBoxIcon.Information); } } } \ No newline at end of file From 8d2c1971ac51615efe3c220973c66fa2bb346825 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 15 Sep 2020 20:31:10 -0400 Subject: [PATCH 026/136] add progress bar suppot for exporting disassembly --- DiztinGUIsh/ProgressBarWorker.cs | 55 +++++++++++++++++++++++++++- DiztinGUIsh/static/LogCreator.cs | 63 +++++++++++++++++++------------- 2 files changed, 92 insertions(+), 26 deletions(-) diff --git a/DiztinGUIsh/ProgressBarWorker.cs b/DiztinGUIsh/ProgressBarWorker.cs index 4fa31fd7..c546216b 100644 --- a/DiztinGUIsh/ProgressBarWorker.cs +++ b/DiztinGUIsh/ProgressBarWorker.cs @@ -3,7 +3,8 @@ using DiztinGUIsh.window.dialog; namespace DiztinGUIsh -{ public abstract class ProgressBarWorker +{ + public abstract class ProgressBarWorker { private ProgressDialog Dialog = null; private bool IsRunning = false; @@ -77,3 +78,55 @@ private void SignalJobIsDone() } } } + + + +namespace DiztinGUIsh +{ + public class LongJob : ProgressBarWorker + { + public static void Loop(long maxProgress, NextAction callback) + { + var j = new LongJob() + { + MaxProgress = maxProgress, + Callback = callback, + }; + j.Run(); + } + + public NextAction Callback { get; set; } + public long MaxProgress { get; set; } + + protected override void Thread_DoWork() + { + var progress = -1L; + do { + progress = Callback(); + UpdateProgress(progress); + } while (progress > 0); + } + + private int previousProgress = 0; + + protected void UpdateProgress(long currentProgress) + { + if (MaxProgress <= 0) + return; + + float percent = (float)(currentProgress) / (float)MaxProgress; + int progressValue = (int)(percent * 100); + + if (progressValue <= previousProgress) + return; + + // don't do this too often, kinda slow due to thread synchronization. + base.UpdateProgress(progressValue); + + previousProgress = progressValue; + } + + // return > 0 to continue. return value will be used to indicate progress in range of [0 -> MaxProgress] + public delegate long NextAction(); + } +} \ No newline at end of file diff --git a/DiztinGUIsh/static/LogCreator.cs b/DiztinGUIsh/static/LogCreator.cs index 1bffced2..a7e0df36 100644 --- a/DiztinGUIsh/static/LogCreator.cs +++ b/DiztinGUIsh/static/LogCreator.cs @@ -100,33 +100,16 @@ public static int CreateLog(StreamWriter sw, StreamWriter er) sw.WriteLine(GetLine(pointer, "empty")); } - while (pointer < size) + // show a progress bar while this happens + LongJob.Loop(size, () => { - int snes = Util.ConvertPCtoSNES(pointer); - if ((snes >> 16) != bank) - { - if (structure == FormatStructure.OneBankPerFile) - { - sw.Close(); - sw = new StreamWriter(string.Format("{0}/bank_{1}.asm", folder, Util.NumberToBaseString((snes >> 16), Util.NumberBase.Hexadecimal, 2))); - } + if (pointer >= size) + return -1; // stop looping - sw.WriteLine(GetLine(pointer, "empty")); - sw.WriteLine(GetLine(pointer, "org")); - sw.WriteLine(GetLine(pointer, "empty")); - if ((snes % bankSize) != 0) err.WriteLine("({0}) Offset 0x{1:X}: An instruction crossed a bank boundary.", ++errorCount, pointer); - bank = snes >> 16; - } - - var c1 = (Data.GetInOutPoint(pointer) & (Data.InOutPoint.ReadPoint)) != 0; - var c2 = (tempAlias.TryGetValue(pointer, out var aliasInfo) && aliasInfo.name.Length > 0); - if (c1 || c2) - sw.WriteLine(GetLine(pointer, "empty")); - - sw.WriteLine(GetLine(pointer, null)); - if ((Data.GetInOutPoint(pointer) & (Data.InOutPoint.EndPoint)) != 0) sw.WriteLine(GetLine(pointer, "empty")); - pointer += GetLineByteLength(pointer); - } + WriteAddress(ref sw, ref pointer, tempAlias, ref bank); + + return (long) pointer; // report current address as the progress + }); WriteLabels(ref sw, pointer); @@ -136,6 +119,36 @@ public static int CreateLog(StreamWriter sw, StreamWriter er) return errorCount; } + private static void WriteAddress(ref StreamWriter sw, ref int pointer, Dictionary tempAlias, ref int bank) + { + int snes = Util.ConvertPCtoSNES(pointer); + if ((snes >> 16) != bank) + { + if (structure == FormatStructure.OneBankPerFile) + { + sw.Close(); + sw = new StreamWriter(string.Format("{0}/bank_{1}.asm", folder, + Util.NumberToBaseString((snes >> 16), Util.NumberBase.Hexadecimal, 2))); + } + + sw.WriteLine(GetLine(pointer, "empty")); + sw.WriteLine(GetLine(pointer, "org")); + sw.WriteLine(GetLine(pointer, "empty")); + if ((snes % bankSize) != 0) + err.WriteLine("({0}) Offset 0x{1:X}: An instruction crossed a bank boundary.", ++errorCount, pointer); + bank = snes >> 16; + } + + var c1 = (Data.GetInOutPoint(pointer) & (Data.InOutPoint.ReadPoint)) != 0; + var c2 = (tempAlias.TryGetValue(pointer, out var aliasInfo) && aliasInfo.name.Length > 0); + if (c1 || c2) + sw.WriteLine(GetLine(pointer, "empty")); + + sw.WriteLine(GetLine(pointer, null)); + if ((Data.GetInOutPoint(pointer) & (Data.InOutPoint.EndPoint)) != 0) sw.WriteLine(GetLine(pointer, "empty")); + pointer += GetLineByteLength(pointer); + } + private static void WriteLabels(ref StreamWriter sw, int pointer) { SwitchOutputFile(ref sw, pointer, $"{folder}/labels.asm"); From 370da169728b3ba2b5bbb98db2fccf35d7b6b775 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 19 Sep 2020 15:39:02 -0400 Subject: [PATCH 027/136] add delete all labels function --- DiztinGUIsh/static/Data.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/DiztinGUIsh/static/Data.cs b/DiztinGUIsh/static/Data.cs index 1409cf1e..b964b699 100644 --- a/DiztinGUIsh/static/Data.cs +++ b/DiztinGUIsh/static/Data.cs @@ -249,6 +249,11 @@ public static string GetLabelComment(int i) return ""; } + public static void DeleteAllLabels() + { + alias.Clear(); + } + public static void AddLabel(int i, AliasInfo v, bool overwrite) { if (v == null) From c890f2254cefb94a4632f089f1bf3f8e71d49af7 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 19 Sep 2020 15:39:19 -0400 Subject: [PATCH 028/136] add comment about where it insert some aliasing stuff later --- DiztinGUIsh/static/diz/CPU65C816.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DiztinGUIsh/static/diz/CPU65C816.cs b/DiztinGUIsh/static/diz/CPU65C816.cs index c7a70f9c..e9aad13b 100644 --- a/DiztinGUIsh/static/diz/CPU65C816.cs +++ b/DiztinGUIsh/static/diz/CPU65C816.cs @@ -145,6 +145,9 @@ public static string GetInstruction(int offset) } else { + // dom note: this is where we could inject expressions if needed. it gives stuff like "$F001". + // we could substitute our expression of "$#F000 + $#01" or "some_struct.member" like "player.hp" + // the expression must match the bytes in the file [unless we allow overriding] op1 = FormatOperandAddress(offset, mode); } return string.Format(format, mnemonic, op1, op2); From 0bd1eac3f8d4e66b5787ef0fb4a5207d2133cf00 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 19 Sep 2020 15:43:56 -0400 Subject: [PATCH 029/136] rename progressbarjob class --- DiztinGUIsh/ProgressBarWorker.cs | 4 ++-- DiztinGUIsh/static/LogCreator.cs | 2 +- .../window/dialog/ProgressDialog.Designer.cs | 24 +++++++++++-------- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/DiztinGUIsh/ProgressBarWorker.cs b/DiztinGUIsh/ProgressBarWorker.cs index c546216b..2a2854de 100644 --- a/DiztinGUIsh/ProgressBarWorker.cs +++ b/DiztinGUIsh/ProgressBarWorker.cs @@ -83,11 +83,11 @@ private void SignalJobIsDone() namespace DiztinGUIsh { - public class LongJob : ProgressBarWorker + public class ProgressBarJob : ProgressBarWorker { public static void Loop(long maxProgress, NextAction callback) { - var j = new LongJob() + var j = new ProgressBarJob() { MaxProgress = maxProgress, Callback = callback, diff --git a/DiztinGUIsh/static/LogCreator.cs b/DiztinGUIsh/static/LogCreator.cs index a7e0df36..b5184a6c 100644 --- a/DiztinGUIsh/static/LogCreator.cs +++ b/DiztinGUIsh/static/LogCreator.cs @@ -101,7 +101,7 @@ public static int CreateLog(StreamWriter sw, StreamWriter er) } // show a progress bar while this happens - LongJob.Loop(size, () => + ProgressBarJob.Loop(size, () => { if (pointer >= size) return -1; // stop looping diff --git a/DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs b/DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs index 0e1c3e4b..209cf50f 100644 --- a/DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs +++ b/DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs @@ -35,46 +35,50 @@ private void InitializeComponent() // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(15, 11); + this.label1.Location = new System.Drawing.Point(11, 9); + this.label1.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(69, 16); + this.label1.Size = new System.Drawing.Size(54, 13); this.label1.TabIndex = 0; this.label1.Text = "Progress: "; // // label2 // this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(90, 11); + this.label2.Location = new System.Drawing.Point(68, 9); + this.label2.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(93, 16); + this.label2.Size = new System.Drawing.Size(73, 13); this.label2.TabIndex = 1; this.label2.Text = "[progress text]"; // // progressBar1 // - this.progressBar1.Location = new System.Drawing.Point(11, 42); + this.progressBar1.Location = new System.Drawing.Point(8, 34); + this.progressBar1.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); this.progressBar1.Name = "progressBar1"; - this.progressBar1.Size = new System.Drawing.Size(292, 23); + this.progressBar1.Size = new System.Drawing.Size(219, 19); this.progressBar1.TabIndex = 2; // // ProgressDialog // - this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(315, 78); + this.ClientSize = new System.Drawing.Size(236, 63); + this.ControlBox = false; this.Controls.Add(this.progressBar1); this.Controls.Add(this.label2); this.Controls.Add(this.label1); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.MaximizeBox = false; this.MinimizeBox = false; this.Name = "ProgressDialog"; - this.Padding = new System.Windows.Forms.Padding(12, 11, 12, 11); + this.Padding = new System.Windows.Forms.Padding(9, 9, 9, 9); this.ShowIcon = false; this.ShowInTaskbar = false; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Working..."; + this.TopMost = true; this.ResumeLayout(false); this.PerformLayout(); From f780be05c29e980b7c6ca632085dc6a2c6a2bf0d Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 19 Sep 2020 15:46:19 -0400 Subject: [PATCH 030/136] add new way to read lines from file that: 1) saves a little memory 2) allows read-only access to files open in other apps (like CSV files when they're still open in Excel, which currently gives us a 'file in use' error) --- DiztinGUIsh/static/Util.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/DiztinGUIsh/static/Util.cs b/DiztinGUIsh/static/Util.cs index 95c38ce7..3c3c23f4 100644 --- a/DiztinGUIsh/static/Util.cs +++ b/DiztinGUIsh/static/Util.cs @@ -424,6 +424,19 @@ public static int TypeStepSize(Data.FlagType flag) return 0; } + public static IEnumerable ReadLines(string path) + { + using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 0x1000, FileOptions.SequentialScan)) + using (var sr = new StreamReader(fs, Encoding.UTF8)) + { + string line; + while ((line = sr.ReadLine()) != null) + { + yield return line; + } + } + } + public static string ArchToString(Data.Architechture arch) { switch (arch) From 1a165b8498fa46ff0185a4891f1485e819017c8d Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 19 Sep 2020 15:46:54 -0400 Subject: [PATCH 031/136] UX: add project-specific settings for: - remembering the last project open - remembering whether or not we want to re-open the last file on load --- DiztinGUIsh/App.config | 15 + DiztinGUIsh/Properties/Settings.Designer.cs | 46 +- DiztinGUIsh/Properties/Settings.settings | 17 +- DiztinGUIsh/window/MainWindow.Designer.cs | 542 ++++++++++---------- DiztinGUIsh/window/MainWindow.cs | 54 +- 5 files changed, 392 insertions(+), 282 deletions(-) diff --git a/DiztinGUIsh/App.config b/DiztinGUIsh/App.config index 731f6de6..92793b20 100644 --- a/DiztinGUIsh/App.config +++ b/DiztinGUIsh/App.config @@ -1,6 +1,21 @@  + + +
+ + + + + + + + + True + + + \ No newline at end of file diff --git a/DiztinGUIsh/Properties/Settings.Designer.cs b/DiztinGUIsh/Properties/Settings.Designer.cs index ef1c8d5b..23d8de68 100644 --- a/DiztinGUIsh/Properties/Settings.Designer.cs +++ b/DiztinGUIsh/Properties/Settings.Designer.cs @@ -8,23 +8,43 @@ // //------------------------------------------------------------------------------ -namespace DiztinGUIsh.Properties -{ - - +namespace DiztinGUIsh.Properties { + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase - { - + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.7.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default - { - get - { + + public static Settings Default { + get { return defaultInstance; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string LastOpenedFile { + get { + return ((string)(this["LastOpenedFile"])); + } + set { + this["LastOpenedFile"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool OpenLastFileAutomatically { + get { + return ((bool)(this["OpenLastFileAutomatically"])); + } + set { + this["OpenLastFileAutomatically"] = value; + } + } } } diff --git a/DiztinGUIsh/Properties/Settings.settings b/DiztinGUIsh/Properties/Settings.settings index 39645652..22889e56 100644 --- a/DiztinGUIsh/Properties/Settings.settings +++ b/DiztinGUIsh/Properties/Settings.settings @@ -1,7 +1,12 @@  - - - - - - + + + + + + + + True + + + \ No newline at end of file diff --git a/DiztinGUIsh/window/MainWindow.Designer.cs b/DiztinGUIsh/window/MainWindow.Designer.cs index bb20b135..4400a521 100644 --- a/DiztinGUIsh/window/MainWindow.Designer.cs +++ b/DiztinGUIsh/window/MainWindow.Designer.cs @@ -44,6 +44,19 @@ private void InitializeComponent() System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle13 = new System.Windows.Forms.DataGridViewCellStyle(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainWindow)); this.table = new System.Windows.Forms.DataGridView(); + this.ColumnAlias = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnPC = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnChar = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnHex = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnPoints = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnInstruction = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnIA = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnFlag = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnDB = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnDP = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnM = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnX = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ColumnComment = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.menuStrip1 = new System.Windows.Forms.MenuStrip(); this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.newProjectToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -106,6 +119,7 @@ private void InitializeComponent() this.binaryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.optionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.moveWithStepToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.labelListToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.viewHelpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.githubToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -120,23 +134,11 @@ private void InitializeComponent() this.vScrollBar1 = new System.Windows.Forms.VScrollBar(); this.saveLogSingleFile = new System.Windows.Forms.SaveFileDialog(); this.chooseLogFolder = new System.Windows.Forms.FolderBrowserDialog(); - this.labelListToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.openUsageMapFile = new System.Windows.Forms.OpenFileDialog(); - this.ColumnAlias = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnPC = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnChar = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnHex = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnPoints = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnInstruction = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnIA = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnFlag = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnDB = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnDP = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnM = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnX = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ColumnComment = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.openTraceLogDialog = new System.Windows.Forms.OpenFileDialog(); this.openCDLDialog = new System.Windows.Forms.OpenFileDialog(); + this.toolStripOpenLast = new System.Windows.Forms.ToolStripMenuItem(); + this.openLastProjectAutomaticallyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); ((System.ComponentModel.ISupportInitialize)(this.table)).BeginInit(); this.menuStrip1.SuspendLayout(); this.statusStrip1.SuspendLayout(); @@ -172,7 +174,7 @@ private void InitializeComponent() dataGridViewCellStyle14.SelectionForeColor = System.Drawing.SystemColors.HighlightText; dataGridViewCellStyle14.WrapMode = System.Windows.Forms.DataGridViewTriState.False; this.table.DefaultCellStyle = dataGridViewCellStyle14; - this.table.Location = new System.Drawing.Point(0, 30); + this.table.Location = new System.Drawing.Point(0, 24); this.table.Margin = new System.Windows.Forms.Padding(0); this.table.MultiSelect = false; this.table.Name = "table"; @@ -184,7 +186,7 @@ private void InitializeComponent() this.table.ShowCellToolTips = false; this.table.ShowEditingIcon = false; this.table.ShowRowErrors = false; - this.table.Size = new System.Drawing.Size(933, 615); + this.table.Size = new System.Drawing.Size(746, 492); this.table.TabIndex = 1; this.table.TabStop = false; this.table.VirtualMode = true; @@ -192,6 +194,164 @@ private void InitializeComponent() this.table.MouseDown += new System.Windows.Forms.MouseEventHandler(this.table_MouseDown); this.table.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.table_MouseWheel); // + // ColumnAlias + // + dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; + dataGridViewCellStyle1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnAlias.DefaultCellStyle = dataGridViewCellStyle1; + this.ColumnAlias.HeaderText = "Label"; + this.ColumnAlias.MaxInputLength = 60; + this.ColumnAlias.MinimumWidth = 6; + this.ColumnAlias.Name = "ColumnAlias"; + this.ColumnAlias.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnAlias.Width = 130; + // + // ColumnPC + // + dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle2.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnPC.DefaultCellStyle = dataGridViewCellStyle2; + this.ColumnPC.HeaderText = "PC"; + this.ColumnPC.MaxInputLength = 6; + this.ColumnPC.MinimumWidth = 6; + this.ColumnPC.Name = "ColumnPC"; + this.ColumnPC.ReadOnly = true; + this.ColumnPC.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnPC.Width = 58; + // + // ColumnChar + // + dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; + dataGridViewCellStyle3.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnChar.DefaultCellStyle = dataGridViewCellStyle3; + this.ColumnChar.HeaderText = "@"; + this.ColumnChar.MaxInputLength = 1; + this.ColumnChar.MinimumWidth = 6; + this.ColumnChar.Name = "ColumnChar"; + this.ColumnChar.ReadOnly = true; + this.ColumnChar.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnChar.Width = 26; + // + // ColumnHex + // + dataGridViewCellStyle4.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; + dataGridViewCellStyle4.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnHex.DefaultCellStyle = dataGridViewCellStyle4; + this.ColumnHex.HeaderText = "#"; + this.ColumnHex.MaxInputLength = 3; + this.ColumnHex.MinimumWidth = 6; + this.ColumnHex.Name = "ColumnHex"; + this.ColumnHex.ReadOnly = true; + this.ColumnHex.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnHex.Width = 26; + // + // ColumnPoints + // + dataGridViewCellStyle5.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle5.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnPoints.DefaultCellStyle = dataGridViewCellStyle5; + this.ColumnPoints.HeaderText = "<*>"; + this.ColumnPoints.MaxInputLength = 3; + this.ColumnPoints.MinimumWidth = 6; + this.ColumnPoints.Name = "ColumnPoints"; + this.ColumnPoints.ReadOnly = true; + this.ColumnPoints.Width = 34; + // + // ColumnInstruction + // + dataGridViewCellStyle6.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle6.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnInstruction.DefaultCellStyle = dataGridViewCellStyle6; + this.ColumnInstruction.HeaderText = "Instruction"; + this.ColumnInstruction.MaxInputLength = 64; + this.ColumnInstruction.MinimumWidth = 6; + this.ColumnInstruction.Name = "ColumnInstruction"; + this.ColumnInstruction.ReadOnly = true; + this.ColumnInstruction.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnInstruction.Width = 125; + // + // ColumnIA + // + dataGridViewCellStyle7.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle7.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnIA.DefaultCellStyle = dataGridViewCellStyle7; + this.ColumnIA.HeaderText = "IA"; + this.ColumnIA.MaxInputLength = 6; + this.ColumnIA.MinimumWidth = 6; + this.ColumnIA.Name = "ColumnIA"; + this.ColumnIA.ReadOnly = true; + this.ColumnIA.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnIA.Width = 58; + // + // ColumnFlag + // + dataGridViewCellStyle8.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnFlag.DefaultCellStyle = dataGridViewCellStyle8; + this.ColumnFlag.HeaderText = "Flag"; + this.ColumnFlag.MinimumWidth = 6; + this.ColumnFlag.Name = "ColumnFlag"; + this.ColumnFlag.ReadOnly = true; + this.ColumnFlag.Width = 86; + // + // ColumnDB + // + dataGridViewCellStyle9.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; + dataGridViewCellStyle9.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnDB.DefaultCellStyle = dataGridViewCellStyle9; + this.ColumnDB.HeaderText = "B"; + this.ColumnDB.MaxInputLength = 2; + this.ColumnDB.MinimumWidth = 6; + this.ColumnDB.Name = "ColumnDB"; + this.ColumnDB.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnDB.Width = 26; + // + // ColumnDP + // + dataGridViewCellStyle10.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle10.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnDP.DefaultCellStyle = dataGridViewCellStyle10; + this.ColumnDP.HeaderText = "D"; + this.ColumnDP.MaxInputLength = 4; + this.ColumnDP.MinimumWidth = 6; + this.ColumnDP.Name = "ColumnDP"; + this.ColumnDP.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.ColumnDP.Width = 42; + // + // ColumnM + // + dataGridViewCellStyle11.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle11.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnM.DefaultCellStyle = dataGridViewCellStyle11; + this.ColumnM.HeaderText = "M"; + this.ColumnM.MaxInputLength = 2; + this.ColumnM.MinimumWidth = 6; + this.ColumnM.Name = "ColumnM"; + this.ColumnM.ReadOnly = true; + this.ColumnM.Width = 26; + // + // ColumnX + // + dataGridViewCellStyle12.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle12.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnX.DefaultCellStyle = dataGridViewCellStyle12; + this.ColumnX.HeaderText = "X"; + this.ColumnX.MaxInputLength = 2; + this.ColumnX.MinimumWidth = 6; + this.ColumnX.Name = "ColumnX"; + this.ColumnX.ReadOnly = true; + this.ColumnX.Width = 26; + // + // ColumnComment + // + this.ColumnComment.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + dataGridViewCellStyle13.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle13.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ColumnComment.DefaultCellStyle = dataGridViewCellStyle13; + this.ColumnComment.HeaderText = "Comment"; + this.ColumnComment.MinimumWidth = 6; + this.ColumnComment.Name = "ColumnComment"; + this.ColumnComment.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + // // menuStrip1 // this.menuStrip1.ImageScalingSize = new System.Drawing.Size(20, 20); @@ -202,8 +362,7 @@ private void InitializeComponent() this.helpToolStripMenuItem}); this.menuStrip1.Location = new System.Drawing.Point(0, 0); this.menuStrip1.Name = "menuStrip1"; - this.menuStrip1.Padding = new System.Windows.Forms.Padding(8, 2, 0, 2); - this.menuStrip1.Size = new System.Drawing.Size(956, 28); + this.menuStrip1.Size = new System.Drawing.Size(765, 24); this.menuStrip1.TabIndex = 0; this.menuStrip1.Text = "menuStrip1"; // @@ -212,6 +371,7 @@ private void InitializeComponent() this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.newProjectToolStripMenuItem, this.openProjectToolStripMenuItem, + this.toolStripOpenLast, this.saveProjectToolStripMenuItem, this.saveProjectAsToolStripMenuItem, this.toolStripSeparator1, @@ -222,14 +382,14 @@ private void InitializeComponent() this.toolStripSeparator7, this.exitToolStripMenuItem}); this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; - this.fileToolStripMenuItem.Size = new System.Drawing.Size(46, 24); + this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); this.fileToolStripMenuItem.Text = "&File"; // // newProjectToolStripMenuItem // this.newProjectToolStripMenuItem.Name = "newProjectToolStripMenuItem"; this.newProjectToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.N))); - this.newProjectToolStripMenuItem.Size = new System.Drawing.Size(292, 26); + this.newProjectToolStripMenuItem.Size = new System.Drawing.Size(235, 22); this.newProjectToolStripMenuItem.Text = "New Project..."; this.newProjectToolStripMenuItem.Click += new System.EventHandler(this.newProjectToolStripMenuItem_Click); // @@ -237,7 +397,7 @@ private void InitializeComponent() // this.openProjectToolStripMenuItem.Name = "openProjectToolStripMenuItem"; this.openProjectToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O))); - this.openProjectToolStripMenuItem.Size = new System.Drawing.Size(292, 26); + this.openProjectToolStripMenuItem.Size = new System.Drawing.Size(235, 22); this.openProjectToolStripMenuItem.Text = "Open Project..."; this.openProjectToolStripMenuItem.Click += new System.EventHandler(this.openProjectToolStripMenuItem_Click); // @@ -246,7 +406,7 @@ private void InitializeComponent() this.saveProjectToolStripMenuItem.Enabled = false; this.saveProjectToolStripMenuItem.Name = "saveProjectToolStripMenuItem"; this.saveProjectToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S))); - this.saveProjectToolStripMenuItem.Size = new System.Drawing.Size(292, 26); + this.saveProjectToolStripMenuItem.Size = new System.Drawing.Size(235, 22); this.saveProjectToolStripMenuItem.Text = "Save Project"; this.saveProjectToolStripMenuItem.Click += new System.EventHandler(this.saveProjectToolStripMenuItem_Click); // @@ -256,21 +416,21 @@ private void InitializeComponent() this.saveProjectAsToolStripMenuItem.Name = "saveProjectAsToolStripMenuItem"; this.saveProjectAsToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) | System.Windows.Forms.Keys.S))); - this.saveProjectAsToolStripMenuItem.Size = new System.Drawing.Size(292, 26); + this.saveProjectAsToolStripMenuItem.Size = new System.Drawing.Size(235, 22); this.saveProjectAsToolStripMenuItem.Text = "Save Project As..."; this.saveProjectAsToolStripMenuItem.Click += new System.EventHandler(this.saveProjectAsToolStripMenuItem_Click); // // toolStripSeparator1 // this.toolStripSeparator1.Name = "toolStripSeparator1"; - this.toolStripSeparator1.Size = new System.Drawing.Size(289, 6); + this.toolStripSeparator1.Size = new System.Drawing.Size(232, 6); // // exportLogToolStripMenuItem // this.exportLogToolStripMenuItem.Enabled = false; this.exportLogToolStripMenuItem.Name = "exportLogToolStripMenuItem"; this.exportLogToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.E))); - this.exportLogToolStripMenuItem.Size = new System.Drawing.Size(292, 26); + this.exportLogToolStripMenuItem.Size = new System.Drawing.Size(235, 22); this.exportLogToolStripMenuItem.Text = "Export Disassembly..."; this.exportLogToolStripMenuItem.Click += new System.EventHandler(this.exportLogToolStripMenuItem_Click); // @@ -279,7 +439,7 @@ private void InitializeComponent() this.importCDLToolStripMenuItem.Enabled = false; this.importCDLToolStripMenuItem.Name = "importCDLToolStripMenuItem"; this.importCDLToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.I))); - this.importCDLToolStripMenuItem.Size = new System.Drawing.Size(292, 26); + this.importCDLToolStripMenuItem.Size = new System.Drawing.Size(235, 22); this.importCDLToolStripMenuItem.Text = "Import CDL..."; this.importCDLToolStripMenuItem.Click += new System.EventHandler(this.importCDLToolStripMenuItem_Click); // @@ -287,7 +447,7 @@ private void InitializeComponent() // this.importTraceLogToolStripMenuItem.Enabled = false; this.importTraceLogToolStripMenuItem.Name = "importTraceLogToolStripMenuItem"; - this.importTraceLogToolStripMenuItem.Size = new System.Drawing.Size(292, 26); + this.importTraceLogToolStripMenuItem.Size = new System.Drawing.Size(235, 22); this.importTraceLogToolStripMenuItem.Text = "Import Trace Log..."; this.importTraceLogToolStripMenuItem.Click += new System.EventHandler(this.ImportTraceLogToolStripMenuItem_Click); // @@ -295,20 +455,20 @@ private void InitializeComponent() // this.importUsageMapToolStripMenuItem.Enabled = false; this.importUsageMapToolStripMenuItem.Name = "importUsageMapToolStripMenuItem"; - this.importUsageMapToolStripMenuItem.Size = new System.Drawing.Size(292, 26); + this.importUsageMapToolStripMenuItem.Size = new System.Drawing.Size(235, 22); this.importUsageMapToolStripMenuItem.Text = "Import Usage Map..."; this.importUsageMapToolStripMenuItem.Click += new System.EventHandler(this.ImportUsageMapToolStripMenuItem_Click); // // toolStripSeparator7 // this.toolStripSeparator7.Name = "toolStripSeparator7"; - this.toolStripSeparator7.Size = new System.Drawing.Size(289, 6); + this.toolStripSeparator7.Size = new System.Drawing.Size(232, 6); // // exitToolStripMenuItem // this.exitToolStripMenuItem.Name = "exitToolStripMenuItem"; this.exitToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.F4))); - this.exitToolStripMenuItem.Size = new System.Drawing.Size(292, 26); + this.exitToolStripMenuItem.Size = new System.Drawing.Size(235, 22); this.exitToolStripMenuItem.Text = "Exit"; this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click); // @@ -342,32 +502,32 @@ private void InitializeComponent() this.fixMisalignedInstructionsToolStripMenuItem, this.rescanForInOutPointsToolStripMenuItem}); this.editToolStripMenuItem.Name = "editToolStripMenuItem"; - this.editToolStripMenuItem.Size = new System.Drawing.Size(49, 24); + this.editToolStripMenuItem.Size = new System.Drawing.Size(39, 20); this.editToolStripMenuItem.Text = "&Edit"; // // stepOverToolStripMenuItem // this.stepOverToolStripMenuItem.Name = "stepOverToolStripMenuItem"; - this.stepOverToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.stepOverToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.stepOverToolStripMenuItem.Text = "&Step"; this.stepOverToolStripMenuItem.Click += new System.EventHandler(this.stepOverToolStripMenuItem_Click); // // stepInToolStripMenuItem // this.stepInToolStripMenuItem.Name = "stepInToolStripMenuItem"; - this.stepInToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.stepInToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.stepInToolStripMenuItem.Text = "Step &In"; this.stepInToolStripMenuItem.Click += new System.EventHandler(this.stepInToolStripMenuItem_Click); // // toolStripSeparator2 // this.toolStripSeparator2.Name = "toolStripSeparator2"; - this.toolStripSeparator2.Size = new System.Drawing.Size(306, 6); + this.toolStripSeparator2.Size = new System.Drawing.Size(250, 6); // // autoStepSafeToolStripMenuItem // this.autoStepSafeToolStripMenuItem.Name = "autoStepSafeToolStripMenuItem"; - this.autoStepSafeToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.autoStepSafeToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.autoStepSafeToolStripMenuItem.Text = "&Auto Step (Safe)"; this.autoStepSafeToolStripMenuItem.Click += new System.EventHandler(this.autoStepSafeToolStripMenuItem_Click); // @@ -375,55 +535,55 @@ private void InitializeComponent() // this.autoStepHarshToolStripMenuItem.Name = "autoStepHarshToolStripMenuItem"; this.autoStepHarshToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.A))); - this.autoStepHarshToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.autoStepHarshToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.autoStepHarshToolStripMenuItem.Text = "Auto Step (Harsh)"; this.autoStepHarshToolStripMenuItem.Click += new System.EventHandler(this.autoStepHarshToolStripMenuItem_Click); // // toolStripSeparator3 // this.toolStripSeparator3.Name = "toolStripSeparator3"; - this.toolStripSeparator3.Size = new System.Drawing.Size(306, 6); + this.toolStripSeparator3.Size = new System.Drawing.Size(250, 6); // // gotoToolStripMenuItem // this.gotoToolStripMenuItem.Name = "gotoToolStripMenuItem"; this.gotoToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.G))); - this.gotoToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.gotoToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.gotoToolStripMenuItem.Text = "Goto..."; this.gotoToolStripMenuItem.Click += new System.EventHandler(this.gotoToolStripMenuItem_Click); // // gotoIntermediateAddressToolStripMenuItem // this.gotoIntermediateAddressToolStripMenuItem.Name = "gotoIntermediateAddressToolStripMenuItem"; - this.gotoIntermediateAddressToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.gotoIntermediateAddressToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.gotoIntermediateAddressToolStripMenuItem.Text = "Goto In&termediate Address"; this.gotoIntermediateAddressToolStripMenuItem.Click += new System.EventHandler(this.gotoIntermediateAddressToolStripMenuItem_Click); // // gotoFirstUnreachedToolStripMenuItem // this.gotoFirstUnreachedToolStripMenuItem.Name = "gotoFirstUnreachedToolStripMenuItem"; - this.gotoFirstUnreachedToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.gotoFirstUnreachedToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.gotoFirstUnreachedToolStripMenuItem.Text = "Goto First &Unreached"; this.gotoFirstUnreachedToolStripMenuItem.Click += new System.EventHandler(this.gotoFirstUnreachedToolStripMenuItem_Click); // // gotoNearUnreachedToolStripMenuItem // this.gotoNearUnreachedToolStripMenuItem.Name = "gotoNearUnreachedToolStripMenuItem"; - this.gotoNearUnreachedToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.gotoNearUnreachedToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.gotoNearUnreachedToolStripMenuItem.Text = "Goto Previous Unreac&hed"; this.gotoNearUnreachedToolStripMenuItem.Click += new System.EventHandler(this.gotoNearUnreachedToolStripMenuItem_Click); // // gotoNextUnreachedToolStripMenuItem // this.gotoNextUnreachedToolStripMenuItem.Name = "gotoNextUnreachedToolStripMenuItem"; - this.gotoNextUnreachedToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.gotoNextUnreachedToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.gotoNextUnreachedToolStripMenuItem.Text = "Goto &Next Unreached"; this.gotoNextUnreachedToolStripMenuItem.Click += new System.EventHandler(this.gotoNextUnreachedToolStripMenuItem_Click); // // toolStripSeparator4 // this.toolStripSeparator4.Name = "toolStripSeparator4"; - this.toolStripSeparator4.Size = new System.Drawing.Size(306, 6); + this.toolStripSeparator4.Size = new System.Drawing.Size(250, 6); // // selectMarkerToolStripMenuItem // @@ -443,14 +603,14 @@ private void InitializeComponent() this.dWordPointerToolStripMenuItem, this.textToolStripMenuItem}); this.selectMarkerToolStripMenuItem.Name = "selectMarkerToolStripMenuItem"; - this.selectMarkerToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.selectMarkerToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.selectMarkerToolStripMenuItem.Text = "Select Marker"; // // unreachedToolStripMenuItem // this.unreachedToolStripMenuItem.Name = "unreachedToolStripMenuItem"; this.unreachedToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.U))); - this.unreachedToolStripMenuItem.Size = new System.Drawing.Size(258, 26); + this.unreachedToolStripMenuItem.Size = new System.Drawing.Size(205, 22); this.unreachedToolStripMenuItem.Text = "Unreached"; this.unreachedToolStripMenuItem.Click += new System.EventHandler(this.unreachedToolStripMenuItem_Click); // @@ -458,7 +618,7 @@ private void InitializeComponent() // this.opcodeToolStripMenuItem.Name = "opcodeToolStripMenuItem"; this.opcodeToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.O))); - this.opcodeToolStripMenuItem.Size = new System.Drawing.Size(258, 26); + this.opcodeToolStripMenuItem.Size = new System.Drawing.Size(205, 22); this.opcodeToolStripMenuItem.Text = "Opcode"; this.opcodeToolStripMenuItem.Click += new System.EventHandler(this.opcodeToolStripMenuItem_Click); // @@ -466,7 +626,7 @@ private void InitializeComponent() // this.operandToolStripMenuItem.Name = "operandToolStripMenuItem"; this.operandToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.P))); - this.operandToolStripMenuItem.Size = new System.Drawing.Size(258, 26); + this.operandToolStripMenuItem.Size = new System.Drawing.Size(205, 22); this.operandToolStripMenuItem.Text = "Operand"; this.operandToolStripMenuItem.Click += new System.EventHandler(this.operandToolStripMenuItem_Click); // @@ -474,7 +634,7 @@ private void InitializeComponent() // this.bitDataToolStripMenuItem.Name = "bitDataToolStripMenuItem"; this.bitDataToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.D1))); - this.bitDataToolStripMenuItem.Size = new System.Drawing.Size(258, 26); + this.bitDataToolStripMenuItem.Size = new System.Drawing.Size(205, 22); this.bitDataToolStripMenuItem.Text = "8-Bit Data"; this.bitDataToolStripMenuItem.Click += new System.EventHandler(this.bitDataToolStripMenuItem_Click); // @@ -482,7 +642,7 @@ private void InitializeComponent() // this.graphicsToolStripMenuItem.Name = "graphicsToolStripMenuItem"; this.graphicsToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.G))); - this.graphicsToolStripMenuItem.Size = new System.Drawing.Size(258, 26); + this.graphicsToolStripMenuItem.Size = new System.Drawing.Size(205, 22); this.graphicsToolStripMenuItem.Text = " Graphics"; this.graphicsToolStripMenuItem.Click += new System.EventHandler(this.graphicsToolStripMenuItem_Click); // @@ -490,7 +650,7 @@ private void InitializeComponent() // this.musicToolStripMenuItem.Name = "musicToolStripMenuItem"; this.musicToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.M))); - this.musicToolStripMenuItem.Size = new System.Drawing.Size(258, 26); + this.musicToolStripMenuItem.Size = new System.Drawing.Size(205, 22); this.musicToolStripMenuItem.Text = " Music"; this.musicToolStripMenuItem.Click += new System.EventHandler(this.musicToolStripMenuItem_Click); // @@ -498,7 +658,7 @@ private void InitializeComponent() // this.emptyToolStripMenuItem.Name = "emptyToolStripMenuItem"; this.emptyToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.E))); - this.emptyToolStripMenuItem.Size = new System.Drawing.Size(258, 26); + this.emptyToolStripMenuItem.Size = new System.Drawing.Size(205, 22); this.emptyToolStripMenuItem.Text = " Empty"; this.emptyToolStripMenuItem.Click += new System.EventHandler(this.emptyToolStripMenuItem_Click); // @@ -506,7 +666,7 @@ private void InitializeComponent() // this.bitDataToolStripMenuItem1.Name = "bitDataToolStripMenuItem1"; this.bitDataToolStripMenuItem1.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.D2))); - this.bitDataToolStripMenuItem1.Size = new System.Drawing.Size(258, 26); + this.bitDataToolStripMenuItem1.Size = new System.Drawing.Size(205, 22); this.bitDataToolStripMenuItem1.Text = "16-Bit Data"; this.bitDataToolStripMenuItem1.Click += new System.EventHandler(this.bitDataToolStripMenuItem1_Click); // @@ -514,7 +674,7 @@ private void InitializeComponent() // this.wordPointerToolStripMenuItem.Name = "wordPointerToolStripMenuItem"; this.wordPointerToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.W))); - this.wordPointerToolStripMenuItem.Size = new System.Drawing.Size(258, 26); + this.wordPointerToolStripMenuItem.Size = new System.Drawing.Size(205, 22); this.wordPointerToolStripMenuItem.Text = " Word Pointer"; this.wordPointerToolStripMenuItem.Click += new System.EventHandler(this.wordPointerToolStripMenuItem_Click); // @@ -522,7 +682,7 @@ private void InitializeComponent() // this.bitDataToolStripMenuItem2.Name = "bitDataToolStripMenuItem2"; this.bitDataToolStripMenuItem2.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.D3))); - this.bitDataToolStripMenuItem2.Size = new System.Drawing.Size(258, 26); + this.bitDataToolStripMenuItem2.Size = new System.Drawing.Size(205, 22); this.bitDataToolStripMenuItem2.Text = "24-Bit Data"; this.bitDataToolStripMenuItem2.Click += new System.EventHandler(this.bitDataToolStripMenuItem2_Click); // @@ -530,7 +690,7 @@ private void InitializeComponent() // this.longPointerToolStripMenuItem.Name = "longPointerToolStripMenuItem"; this.longPointerToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.L))); - this.longPointerToolStripMenuItem.Size = new System.Drawing.Size(258, 26); + this.longPointerToolStripMenuItem.Size = new System.Drawing.Size(205, 22); this.longPointerToolStripMenuItem.Text = " Long Pointer"; this.longPointerToolStripMenuItem.Click += new System.EventHandler(this.longPointerToolStripMenuItem_Click); // @@ -538,7 +698,7 @@ private void InitializeComponent() // this.bitDataToolStripMenuItem3.Name = "bitDataToolStripMenuItem3"; this.bitDataToolStripMenuItem3.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.D4))); - this.bitDataToolStripMenuItem3.Size = new System.Drawing.Size(258, 26); + this.bitDataToolStripMenuItem3.Size = new System.Drawing.Size(205, 22); this.bitDataToolStripMenuItem3.Text = "32-Bit Data"; this.bitDataToolStripMenuItem3.Click += new System.EventHandler(this.bitDataToolStripMenuItem3_Click); // @@ -546,7 +706,7 @@ private void InitializeComponent() // this.dWordPointerToolStripMenuItem.Name = "dWordPointerToolStripMenuItem"; this.dWordPointerToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.D))); - this.dWordPointerToolStripMenuItem.Size = new System.Drawing.Size(258, 26); + this.dWordPointerToolStripMenuItem.Size = new System.Drawing.Size(205, 22); this.dWordPointerToolStripMenuItem.Text = " DWord Pointer"; this.dWordPointerToolStripMenuItem.Click += new System.EventHandler(this.dWordPointerToolStripMenuItem_Click); // @@ -554,14 +714,14 @@ private void InitializeComponent() // this.textToolStripMenuItem.Name = "textToolStripMenuItem"; this.textToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.T))); - this.textToolStripMenuItem.Size = new System.Drawing.Size(258, 26); + this.textToolStripMenuItem.Size = new System.Drawing.Size(205, 22); this.textToolStripMenuItem.Text = "Text"; this.textToolStripMenuItem.Click += new System.EventHandler(this.textToolStripMenuItem_Click); // // markOneToolStripMenuItem // this.markOneToolStripMenuItem.Name = "markOneToolStripMenuItem"; - this.markOneToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.markOneToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.markOneToolStripMenuItem.Text = "Mar&k One"; this.markOneToolStripMenuItem.Click += new System.EventHandler(this.markOneToolStripMenuItem_Click); // @@ -569,19 +729,19 @@ private void InitializeComponent() // this.markManyToolStripMenuItem.Name = "markManyToolStripMenuItem"; this.markManyToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.K))); - this.markManyToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.markManyToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.markManyToolStripMenuItem.Text = "Mark Many..."; this.markManyToolStripMenuItem.Click += new System.EventHandler(this.markManyToolStripMenuItem_Click); // // toolStripSeparator5 // this.toolStripSeparator5.Name = "toolStripSeparator5"; - this.toolStripSeparator5.Size = new System.Drawing.Size(306, 6); + this.toolStripSeparator5.Size = new System.Drawing.Size(250, 6); // // addLabelToolStripMenuItem // this.addLabelToolStripMenuItem.Name = "addLabelToolStripMenuItem"; - this.addLabelToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.addLabelToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.addLabelToolStripMenuItem.Text = "Add &Label"; this.addLabelToolStripMenuItem.Click += new System.EventHandler(this.addLabelToolStripMenuItem_Click); // @@ -589,7 +749,7 @@ private void InitializeComponent() // this.setDataBankToolStripMenuItem.Name = "setDataBankToolStripMenuItem"; this.setDataBankToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.B))); - this.setDataBankToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.setDataBankToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.setDataBankToolStripMenuItem.Text = "Set Data &Bank..."; this.setDataBankToolStripMenuItem.Click += new System.EventHandler(this.setDataBankToolStripMenuItem_Click); // @@ -597,7 +757,7 @@ private void InitializeComponent() // this.setDirectPageToolStripMenuItem.Name = "setDirectPageToolStripMenuItem"; this.setDirectPageToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.D))); - this.setDirectPageToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.setDirectPageToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.setDirectPageToolStripMenuItem.Text = "Set &Direct Page..."; this.setDirectPageToolStripMenuItem.Click += new System.EventHandler(this.setDirectPageToolStripMenuItem_Click); // @@ -605,7 +765,7 @@ private void InitializeComponent() // this.toggleAccumulatorSizeMToolStripMenuItem.Name = "toggleAccumulatorSizeMToolStripMenuItem"; this.toggleAccumulatorSizeMToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.M))); - this.toggleAccumulatorSizeMToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.toggleAccumulatorSizeMToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.toggleAccumulatorSizeMToolStripMenuItem.Text = "Set Accu&mulator Size..."; this.toggleAccumulatorSizeMToolStripMenuItem.Click += new System.EventHandler(this.toggleAccumulatorSizeMToolStripMenuItem_Click); // @@ -613,27 +773,27 @@ private void InitializeComponent() // this.toggleIndexSizeToolStripMenuItem.Name = "toggleIndexSizeToolStripMenuItem"; this.toggleIndexSizeToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.X))); - this.toggleIndexSizeToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.toggleIndexSizeToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.toggleIndexSizeToolStripMenuItem.Text = "Set Inde&x Size..."; this.toggleIndexSizeToolStripMenuItem.Click += new System.EventHandler(this.toggleIndexSizeToolStripMenuItem_Click); // // addCommentToolStripMenuItem // this.addCommentToolStripMenuItem.Name = "addCommentToolStripMenuItem"; - this.addCommentToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.addCommentToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.addCommentToolStripMenuItem.Text = "Add &Comment"; this.addCommentToolStripMenuItem.Click += new System.EventHandler(this.addCommentToolStripMenuItem_Click); // // toolStripSeparator6 // this.toolStripSeparator6.Name = "toolStripSeparator6"; - this.toolStripSeparator6.Size = new System.Drawing.Size(306, 6); + this.toolStripSeparator6.Size = new System.Drawing.Size(250, 6); // // fixMisalignedInstructionsToolStripMenuItem // this.fixMisalignedInstructionsToolStripMenuItem.Name = "fixMisalignedInstructionsToolStripMenuItem"; this.fixMisalignedInstructionsToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.F))); - this.fixMisalignedInstructionsToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.fixMisalignedInstructionsToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.fixMisalignedInstructionsToolStripMenuItem.Text = "Fix Misaligned Flags..."; this.fixMisalignedInstructionsToolStripMenuItem.Click += new System.EventHandler(this.fixMisalignedInstructionsToolStripMenuItem_Click); // @@ -641,7 +801,7 @@ private void InitializeComponent() // this.rescanForInOutPointsToolStripMenuItem.Name = "rescanForInOutPointsToolStripMenuItem"; this.rescanForInOutPointsToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.P))); - this.rescanForInOutPointsToolStripMenuItem.Size = new System.Drawing.Size(309, 26); + this.rescanForInOutPointsToolStripMenuItem.Size = new System.Drawing.Size(253, 22); this.rescanForInOutPointsToolStripMenuItem.Text = "Rescan for In/Out Points..."; this.rescanForInOutPointsToolStripMenuItem.Click += new System.EventHandler(this.rescanForInOutPointsToolStripMenuItem_Click); // @@ -654,7 +814,7 @@ private void InitializeComponent() this.optionsToolStripMenuItem, this.labelListToolStripMenuItem}); this.viewToolStripMenuItem.Name = "viewToolStripMenuItem"; - this.viewToolStripMenuItem.Size = new System.Drawing.Size(58, 24); + this.viewToolStripMenuItem.Size = new System.Drawing.Size(46, 20); this.viewToolStripMenuItem.Text = "&Tools"; // // visualMapToolStripMenuItem @@ -662,7 +822,7 @@ private void InitializeComponent() this.visualMapToolStripMenuItem.Enabled = false; this.visualMapToolStripMenuItem.Name = "visualMapToolStripMenuItem"; this.visualMapToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.V))); - this.visualMapToolStripMenuItem.Size = new System.Drawing.Size(264, 26); + this.visualMapToolStripMenuItem.Size = new System.Drawing.Size(212, 22); this.visualMapToolStripMenuItem.Text = "Visual Map"; this.visualMapToolStripMenuItem.Click += new System.EventHandler(this.visualMapToolStripMenuItem_Click); // @@ -671,7 +831,7 @@ private void InitializeComponent() this.graphicsWindowToolStripMenuItem.Enabled = false; this.graphicsWindowToolStripMenuItem.Name = "graphicsWindowToolStripMenuItem"; this.graphicsWindowToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.W))); - this.graphicsWindowToolStripMenuItem.Size = new System.Drawing.Size(264, 26); + this.graphicsWindowToolStripMenuItem.Size = new System.Drawing.Size(212, 22); this.graphicsWindowToolStripMenuItem.Text = "Graphics Window"; this.graphicsWindowToolStripMenuItem.Click += new System.EventHandler(this.graphicsWindowToolStripMenuItem_Click); // @@ -682,14 +842,14 @@ private void InitializeComponent() this.hexadecimalToolStripMenuItem, this.binaryToolStripMenuItem}); this.constantsToolStripMenuItem.Name = "constantsToolStripMenuItem"; - this.constantsToolStripMenuItem.Size = new System.Drawing.Size(264, 26); + this.constantsToolStripMenuItem.Size = new System.Drawing.Size(212, 22); this.constantsToolStripMenuItem.Text = "Constants"; // // decimalToolStripMenuItem // this.decimalToolStripMenuItem.Name = "decimalToolStripMenuItem"; this.decimalToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.C))); - this.decimalToolStripMenuItem.Size = new System.Drawing.Size(228, 26); + this.decimalToolStripMenuItem.Size = new System.Drawing.Size(182, 22); this.decimalToolStripMenuItem.Text = "Decimal"; this.decimalToolStripMenuItem.Click += new System.EventHandler(this.decimalToolStripMenuItem_Click); // @@ -699,7 +859,7 @@ private void InitializeComponent() this.hexadecimalToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; this.hexadecimalToolStripMenuItem.Name = "hexadecimalToolStripMenuItem"; this.hexadecimalToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.H))); - this.hexadecimalToolStripMenuItem.Size = new System.Drawing.Size(228, 26); + this.hexadecimalToolStripMenuItem.Size = new System.Drawing.Size(182, 22); this.hexadecimalToolStripMenuItem.Text = "Hexadecimal"; this.hexadecimalToolStripMenuItem.Click += new System.EventHandler(this.hexadecimalToolStripMenuItem_Click); // @@ -707,16 +867,17 @@ private void InitializeComponent() // this.binaryToolStripMenuItem.Name = "binaryToolStripMenuItem"; this.binaryToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.B))); - this.binaryToolStripMenuItem.Size = new System.Drawing.Size(228, 26); + this.binaryToolStripMenuItem.Size = new System.Drawing.Size(182, 22); this.binaryToolStripMenuItem.Text = "Binary"; this.binaryToolStripMenuItem.Click += new System.EventHandler(this.binaryToolStripMenuItem_Click); // // optionsToolStripMenuItem // this.optionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.moveWithStepToolStripMenuItem}); + this.moveWithStepToolStripMenuItem, + this.openLastProjectAutomaticallyToolStripMenuItem}); this.optionsToolStripMenuItem.Name = "optionsToolStripMenuItem"; - this.optionsToolStripMenuItem.Size = new System.Drawing.Size(264, 26); + this.optionsToolStripMenuItem.Size = new System.Drawing.Size(212, 22); this.optionsToolStripMenuItem.Text = "Options"; // // moveWithStepToolStripMenuItem @@ -724,10 +885,18 @@ private void InitializeComponent() this.moveWithStepToolStripMenuItem.Checked = true; this.moveWithStepToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; this.moveWithStepToolStripMenuItem.Name = "moveWithStepToolStripMenuItem"; - this.moveWithStepToolStripMenuItem.Size = new System.Drawing.Size(198, 26); + this.moveWithStepToolStripMenuItem.Size = new System.Drawing.Size(244, 22); this.moveWithStepToolStripMenuItem.Text = "Move With Step"; this.moveWithStepToolStripMenuItem.Click += new System.EventHandler(this.moveWithStepToolStripMenuItem_Click); // + // labelListToolStripMenuItem + // + this.labelListToolStripMenuItem.Enabled = false; + this.labelListToolStripMenuItem.Name = "labelListToolStripMenuItem"; + this.labelListToolStripMenuItem.Size = new System.Drawing.Size(212, 22); + this.labelListToolStripMenuItem.Text = "Label List"; + this.labelListToolStripMenuItem.Click += new System.EventHandler(this.labelListToolStripMenuItem_Click); + // // helpToolStripMenuItem // this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -735,28 +904,28 @@ private void InitializeComponent() this.githubToolStripMenuItem, this.aboutToolStripMenuItem}); this.helpToolStripMenuItem.Name = "helpToolStripMenuItem"; - this.helpToolStripMenuItem.Size = new System.Drawing.Size(55, 24); + this.helpToolStripMenuItem.Size = new System.Drawing.Size(44, 20); this.helpToolStripMenuItem.Text = "&Help"; // // viewHelpToolStripMenuItem // this.viewHelpToolStripMenuItem.Name = "viewHelpToolStripMenuItem"; this.viewHelpToolStripMenuItem.ShortcutKeys = System.Windows.Forms.Keys.F1; - this.viewHelpToolStripMenuItem.Size = new System.Drawing.Size(184, 26); + this.viewHelpToolStripMenuItem.Size = new System.Drawing.Size(146, 22); this.viewHelpToolStripMenuItem.Text = "View Help"; this.viewHelpToolStripMenuItem.Click += new System.EventHandler(this.viewHelpToolStripMenuItem_Click); // // githubToolStripMenuItem // this.githubToolStripMenuItem.Name = "githubToolStripMenuItem"; - this.githubToolStripMenuItem.Size = new System.Drawing.Size(184, 26); + this.githubToolStripMenuItem.Size = new System.Drawing.Size(146, 22); this.githubToolStripMenuItem.Text = "Github"; this.githubToolStripMenuItem.Click += new System.EventHandler(this.githubToolStripMenuItem_Click); // // aboutToolStripMenuItem // this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem"; - this.aboutToolStripMenuItem.Size = new System.Drawing.Size(184, 26); + this.aboutToolStripMenuItem.Size = new System.Drawing.Size(146, 22); this.aboutToolStripMenuItem.Text = "About"; this.aboutToolStripMenuItem.Click += new System.EventHandler(this.aboutToolStripMenuItem_Click); // @@ -767,10 +936,10 @@ private void InitializeComponent() this.percentComplete, this.seperator1, this.currentMarker}); - this.statusStrip1.Location = new System.Drawing.Point(0, 646); + this.statusStrip1.Location = new System.Drawing.Point(0, 516); this.statusStrip1.Name = "statusStrip1"; - this.statusStrip1.Padding = new System.Windows.Forms.Padding(1, 0, 19, 0); - this.statusStrip1.Size = new System.Drawing.Size(956, 26); + this.statusStrip1.Padding = new System.Windows.Forms.Padding(1, 0, 15, 0); + this.statusStrip1.Size = new System.Drawing.Size(765, 22); this.statusStrip1.TabIndex = 3; this.statusStrip1.Text = "statusStrip1"; // @@ -778,19 +947,19 @@ private void InitializeComponent() // this.percentComplete.Name = "percentComplete"; this.percentComplete.RightToLeft = System.Windows.Forms.RightToLeft.No; - this.percentComplete.Size = new System.Drawing.Size(92, 20); + this.percentComplete.Size = new System.Drawing.Size(72, 17); this.percentComplete.Text = "0.000% (0/0)"; // // seperator1 // this.seperator1.Name = "seperator1"; - this.seperator1.Size = new System.Drawing.Size(13, 20); + this.seperator1.Size = new System.Drawing.Size(10, 17); this.seperator1.Text = "|"; // // currentMarker // this.currentMarker.Name = "currentMarker"; - this.currentMarker.Size = new System.Drawing.Size(140, 20); + this.currentMarker.Size = new System.Drawing.Size(110, 17); this.currentMarker.Text = "Marker: Data (8-bit)"; // // openROMFile @@ -809,10 +978,10 @@ private void InitializeComponent() // vScrollBar1 // this.vScrollBar1.Enabled = false; - this.vScrollBar1.Location = new System.Drawing.Point(933, 30); + this.vScrollBar1.Location = new System.Drawing.Point(746, 24); this.vScrollBar1.Maximum = 32768; this.vScrollBar1.Name = "vScrollBar1"; - this.vScrollBar1.Size = new System.Drawing.Size(17, 615); + this.vScrollBar1.Size = new System.Drawing.Size(17, 492); this.vScrollBar1.TabIndex = 2; this.vScrollBar1.ValueChanged += new System.EventHandler(this.vScrollBar1_ValueChanged); // @@ -824,193 +993,40 @@ private void InitializeComponent() // this.openUsageMapFile.Filter = "bsnes-plus usage map files|*.bin"; // - // ColumnAlias - // - dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; - dataGridViewCellStyle1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnAlias.DefaultCellStyle = dataGridViewCellStyle1; - this.ColumnAlias.HeaderText = "Label"; - this.ColumnAlias.MaxInputLength = 60; - this.ColumnAlias.MinimumWidth = 6; - this.ColumnAlias.Name = "ColumnAlias"; - this.ColumnAlias.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnAlias.Width = 130; - // - // ColumnPC - // - dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle2.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnPC.DefaultCellStyle = dataGridViewCellStyle2; - this.ColumnPC.HeaderText = "PC"; - this.ColumnPC.MaxInputLength = 6; - this.ColumnPC.MinimumWidth = 6; - this.ColumnPC.Name = "ColumnPC"; - this.ColumnPC.ReadOnly = true; - this.ColumnPC.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnPC.Width = 58; - // - // ColumnChar - // - dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; - dataGridViewCellStyle3.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnChar.DefaultCellStyle = dataGridViewCellStyle3; - this.ColumnChar.HeaderText = "@"; - this.ColumnChar.MaxInputLength = 1; - this.ColumnChar.MinimumWidth = 6; - this.ColumnChar.Name = "ColumnChar"; - this.ColumnChar.ReadOnly = true; - this.ColumnChar.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnChar.Width = 26; - // - // ColumnHex - // - dataGridViewCellStyle4.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; - dataGridViewCellStyle4.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnHex.DefaultCellStyle = dataGridViewCellStyle4; - this.ColumnHex.HeaderText = "#"; - this.ColumnHex.MaxInputLength = 3; - this.ColumnHex.MinimumWidth = 6; - this.ColumnHex.Name = "ColumnHex"; - this.ColumnHex.ReadOnly = true; - this.ColumnHex.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnHex.Width = 26; - // - // ColumnPoints - // - dataGridViewCellStyle5.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; - dataGridViewCellStyle5.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnPoints.DefaultCellStyle = dataGridViewCellStyle5; - this.ColumnPoints.HeaderText = "<*>"; - this.ColumnPoints.MaxInputLength = 3; - this.ColumnPoints.MinimumWidth = 6; - this.ColumnPoints.Name = "ColumnPoints"; - this.ColumnPoints.ReadOnly = true; - this.ColumnPoints.Width = 34; - // - // ColumnInstruction - // - dataGridViewCellStyle6.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle6.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnInstruction.DefaultCellStyle = dataGridViewCellStyle6; - this.ColumnInstruction.HeaderText = "Instruction"; - this.ColumnInstruction.MaxInputLength = 64; - this.ColumnInstruction.MinimumWidth = 6; - this.ColumnInstruction.Name = "ColumnInstruction"; - this.ColumnInstruction.ReadOnly = true; - this.ColumnInstruction.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnInstruction.Width = 125; - // - // ColumnIA - // - dataGridViewCellStyle7.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle7.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnIA.DefaultCellStyle = dataGridViewCellStyle7; - this.ColumnIA.HeaderText = "IA"; - this.ColumnIA.MaxInputLength = 6; - this.ColumnIA.MinimumWidth = 6; - this.ColumnIA.Name = "ColumnIA"; - this.ColumnIA.ReadOnly = true; - this.ColumnIA.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnIA.Width = 58; - // - // ColumnFlag - // - dataGridViewCellStyle8.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnFlag.DefaultCellStyle = dataGridViewCellStyle8; - this.ColumnFlag.HeaderText = "Flag"; - this.ColumnFlag.MinimumWidth = 6; - this.ColumnFlag.Name = "ColumnFlag"; - this.ColumnFlag.ReadOnly = true; - this.ColumnFlag.Width = 86; - // - // ColumnDB - // - dataGridViewCellStyle9.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; - dataGridViewCellStyle9.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnDB.DefaultCellStyle = dataGridViewCellStyle9; - this.ColumnDB.HeaderText = "B"; - this.ColumnDB.MaxInputLength = 2; - this.ColumnDB.MinimumWidth = 6; - this.ColumnDB.Name = "ColumnDB"; - this.ColumnDB.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnDB.Width = 26; - // - // ColumnDP - // - dataGridViewCellStyle10.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle10.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnDP.DefaultCellStyle = dataGridViewCellStyle10; - this.ColumnDP.HeaderText = "D"; - this.ColumnDP.MaxInputLength = 4; - this.ColumnDP.MinimumWidth = 6; - this.ColumnDP.Name = "ColumnDP"; - this.ColumnDP.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.ColumnDP.Width = 42; - // - // ColumnM - // - dataGridViewCellStyle11.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; - dataGridViewCellStyle11.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnM.DefaultCellStyle = dataGridViewCellStyle11; - this.ColumnM.HeaderText = "M"; - this.ColumnM.MaxInputLength = 2; - this.ColumnM.MinimumWidth = 6; - this.ColumnM.Name = "ColumnM"; - this.ColumnM.ReadOnly = true; - this.ColumnM.Width = 26; - // - // ColumnX - // - dataGridViewCellStyle12.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; - dataGridViewCellStyle12.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnX.DefaultCellStyle = dataGridViewCellStyle12; - this.ColumnX.HeaderText = "X"; - this.ColumnX.MaxInputLength = 2; - this.ColumnX.MinimumWidth = 6; - this.ColumnX.Name = "ColumnX"; - this.ColumnX.ReadOnly = true; - this.ColumnX.Width = 26; - // - // ColumnComment - // - this.ColumnComment.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; - dataGridViewCellStyle13.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle13.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ColumnComment.DefaultCellStyle = dataGridViewCellStyle13; - this.ColumnComment.HeaderText = "Comment"; - this.ColumnComment.MinimumWidth = 6; - this.ColumnComment.Name = "ColumnComment"; - this.ColumnComment.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - // // openTraceLogDialog // this.openTraceLogDialog.Filter = "bsnes-plus trace log|*.log"; // - // labelListToolStripMenuItem - // - this.labelListToolStripMenuItem.Enabled = false; - this.labelListToolStripMenuItem.Name = "labelListToolStripMenuItem"; - this.labelListToolStripMenuItem.Size = new System.Drawing.Size(212, 22); - this.labelListToolStripMenuItem.Text = "Label List"; - this.labelListToolStripMenuItem.Click += new System.EventHandler(this.labelListToolStripMenuItem_Click); - // // openCDLDialog // this.openCDLDialog.Filter = "BizHawk Code Data Logger Files|*.cdl|All Files|*.*"; // + // toolStripOpenLast + // + this.toolStripOpenLast.Name = "toolStripOpenLast"; + this.toolStripOpenLast.Size = new System.Drawing.Size(235, 22); + this.toolStripOpenLast.Text = "Open Last Project"; + this.toolStripOpenLast.Click += new System.EventHandler(this.toolStripOpenLast_Click); + // + // openLastProjectAutomaticallyToolStripMenuItem + // + this.openLastProjectAutomaticallyToolStripMenuItem.Name = "openLastProjectAutomaticallyToolStripMenuItem"; + this.openLastProjectAutomaticallyToolStripMenuItem.Size = new System.Drawing.Size(244, 22); + this.openLastProjectAutomaticallyToolStripMenuItem.Text = "Open Last Project Automatically"; + this.openLastProjectAutomaticallyToolStripMenuItem.Click += new System.EventHandler(this.openLastProjectAutomaticallyToolStripMenuItem_Click); + // // MainWindow // - this.AutoScaleDimensions = new System.Drawing.SizeF(120F, 120F); + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.ClientSize = new System.Drawing.Size(956, 672); + this.ClientSize = new System.Drawing.Size(765, 538); this.Controls.Add(this.vScrollBar1); this.Controls.Add(this.statusStrip1); this.Controls.Add(this.table); this.Controls.Add(this.menuStrip1); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MainMenuStrip = this.menuStrip1; - this.Margin = new System.Windows.Forms.Padding(4); - this.MinimumSize = new System.Drawing.Size(971, 235); + this.MinimumSize = new System.Drawing.Size(780, 196); this.Name = "MainWindow"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "DiztinGUIsh"; @@ -1124,6 +1140,8 @@ private void InitializeComponent() private System.Windows.Forms.OpenFileDialog openTraceLogDialog; private System.Windows.Forms.ToolStripMenuItem labelListToolStripMenuItem; private System.Windows.Forms.OpenFileDialog openCDLDialog; + private System.Windows.Forms.ToolStripMenuItem toolStripOpenLast; + private System.Windows.Forms.ToolStripMenuItem openLastProjectAutomaticallyToolStripMenuItem; } } diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index a640f631..5363f33e 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -11,6 +11,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using DiztinGUIsh.Properties; namespace DiztinGUIsh { @@ -64,6 +65,16 @@ private void MainWindow_Load(object sender, EventArgs e) aliasList = new AliasList(this); UpdatePanels(); + UpdateUIFromSettings(); + + if (Settings.Default.OpenLastFileAutomatically) + openLastProject(); + } + + private void openLastProject() + { + if (Settings.Default.LastOpenedFile != "") + openProject(Settings.Default.LastOpenedFile); } public void UpdateWindowTitle() @@ -128,9 +139,36 @@ private void openProjectToolStripMenuItem_Click(object sender, EventArgs e) } } + public string LastProjectFilename + { + get => Settings.Default.LastOpenedFile; + set + { + Settings.Default.LastOpenedFile = value; + Settings.Default.Save(); + + UpdateUIFromSettings(); + } + } + + private void UpdateUIFromSettings() + { + bool lastOpenedFilePresent = Settings.Default.LastOpenedFile != ""; + toolStripOpenLast.Enabled = lastOpenedFilePresent; + toolStripOpenLast.Text = "Open Last File"; + if (lastOpenedFilePresent) + toolStripOpenLast.Text += $" ({Path.GetFileNameWithoutExtension(Settings.Default.LastOpenedFile)})"; + + openLastProjectAutomaticallyToolStripMenuItem.Checked = Settings.Default.OpenLastFileAutomatically; + } + public void openProject(string filename) { - if (Project.TryOpenProject(filename, openROMFile)) + if (!Project.TryOpenProject(filename, openROMFile)) + { + LastProjectFilename = ""; + } + else { importCDLToolStripMenuItem.Enabled = true; TriggerSaveOptions(true, true); @@ -139,6 +177,8 @@ public void openProject(string filename) UpdatePercent(); table.Invalidate(); EnableSubWindows(); + + LastProjectFilename = filename; } } @@ -969,5 +1009,17 @@ private void ImportTraceLogToolStripMenuItem_Click(object sender, EventArgs e) "Done", MessageBoxButtons.OK, MessageBoxIcon.Information); } + + private void openLastProjectAutomaticallyToolStripMenuItem_Click(object sender, EventArgs e) + { + Settings.Default.OpenLastFileAutomatically = openLastProjectAutomaticallyToolStripMenuItem.Checked; + Settings.Default.Save(); + UpdateUIFromSettings(); + } + + private void toolStripOpenLast_Click(object sender, EventArgs e) + { + openLastProject(); + } } } \ No newline at end of file From 9c69e4aafdc5e0f306433cd35f4f61a55c79c9da Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 19 Sep 2020 15:49:16 -0400 Subject: [PATCH 032/136] add more control over CSV importing options, validation - allows concept of 'delete all labels then re-import just what's in the CSV' vs 'append labels if not present, replace if present, keep anything remaining'. --- DiztinGUIsh/static/Project.cs | 6 +-- DiztinGUIsh/window/AliasList.Designer.cs | 58 +++++++++++++++--------- DiztinGUIsh/window/AliasList.cs | 58 ++++++++++++++++++++---- 3 files changed, 87 insertions(+), 35 deletions(-) diff --git a/DiztinGUIsh/static/Project.cs b/DiztinGUIsh/static/Project.cs index de80d4e5..bf92d883 100644 --- a/DiztinGUIsh/static/Project.cs +++ b/DiztinGUIsh/static/Project.cs @@ -41,7 +41,7 @@ public static bool NewProject(string filename) unsavedChanges = false; currentFile = null; - AliasList.me.Reset(); + AliasList.me.ResetDataGrid(); Dictionary generatedLabels = import.GetGeneratedLabels(); if (generatedLabels.Count > 0) { @@ -191,7 +191,7 @@ public static bool TryOpenProject(string filename, OpenFileDialog open) } catch (Exception e) { - MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show(e.Message, "Error opening project file", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } } @@ -249,7 +249,7 @@ private static void OpenProject(int version, byte[] unzipped, OpenFileDialog ope for (int i = 0; i < size; i++) Data.SetInOutPoint(i, (Data.InOutPoint)unzipped[pointer + 7 * size + i]); pointer += 8 * size; - AliasList.me.Reset(); + AliasList.me.ResetDataGrid(); ReadAliases(unzipped, ref pointer, converter, version >= 2); ReadComments(unzipped, ref pointer, converter); diff --git a/DiztinGUIsh/window/AliasList.Designer.cs b/DiztinGUIsh/window/AliasList.Designer.cs index ef2b68b6..f9e9ed89 100644 --- a/DiztinGUIsh/window/AliasList.Designer.cs +++ b/DiztinGUIsh/window/AliasList.Designer.cs @@ -28,10 +28,10 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle18 = new System.Windows.Forms.DataGridViewCellStyle(); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle16 = new System.Windows.Forms.DataGridViewCellStyle(); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle17 = new System.Windows.Forms.DataGridViewCellStyle(); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle15 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle8 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle5 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle6 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle7 = new System.Windows.Forms.DataGridViewCellStyle(); this.dataGridView1 = new System.Windows.Forms.DataGridView(); this.Address = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.Alias = new System.Windows.Forms.DataGridViewTextBoxColumn(); @@ -43,6 +43,7 @@ private void InitializeComponent() this.jump = new System.Windows.Forms.Button(); this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog(); this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog(); + this.btnImportReplace = new System.Windows.Forms.Button(); ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit(); this.statusStrip1.SuspendLayout(); this.SuspendLayout(); @@ -58,14 +59,14 @@ private void InitializeComponent() this.Address, this.Alias, this.Comment}); - dataGridViewCellStyle18.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle18.BackColor = System.Drawing.SystemColors.Window; - dataGridViewCellStyle18.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - dataGridViewCellStyle18.ForeColor = System.Drawing.SystemColors.ControlText; - dataGridViewCellStyle18.SelectionBackColor = System.Drawing.Color.CornflowerBlue; - dataGridViewCellStyle18.SelectionForeColor = System.Drawing.SystemColors.HighlightText; - dataGridViewCellStyle18.WrapMode = System.Windows.Forms.DataGridViewTriState.False; - this.dataGridView1.DefaultCellStyle = dataGridViewCellStyle18; + dataGridViewCellStyle8.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle8.BackColor = System.Drawing.SystemColors.Window; + dataGridViewCellStyle8.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + dataGridViewCellStyle8.ForeColor = System.Drawing.SystemColors.ControlText; + dataGridViewCellStyle8.SelectionBackColor = System.Drawing.Color.CornflowerBlue; + dataGridViewCellStyle8.SelectionForeColor = System.Drawing.SystemColors.HighlightText; + dataGridViewCellStyle8.WrapMode = System.Windows.Forms.DataGridViewTriState.False; + this.dataGridView1.DefaultCellStyle = dataGridViewCellStyle8; this.dataGridView1.Location = new System.Drawing.Point(0, 29); this.dataGridView1.Margin = new System.Windows.Forms.Padding(0); this.dataGridView1.Name = "dataGridView1"; @@ -88,8 +89,8 @@ private void InitializeComponent() // // Address // - dataGridViewCellStyle16.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.Address.DefaultCellStyle = dataGridViewCellStyle16; + dataGridViewCellStyle5.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Address.DefaultCellStyle = dataGridViewCellStyle5; this.Address.HeaderText = "PC"; this.Address.MaxInputLength = 6; this.Address.Name = "Address"; @@ -97,8 +98,8 @@ private void InitializeComponent() // // Alias // - dataGridViewCellStyle17.Font = new System.Drawing.Font("Arial Narrow", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.Alias.DefaultCellStyle = dataGridViewCellStyle17; + dataGridViewCellStyle6.Font = new System.Drawing.Font("Arial Narrow", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Alias.DefaultCellStyle = dataGridViewCellStyle6; this.Alias.HeaderText = "Label"; this.Alias.MaxInputLength = 60; this.Alias.Name = "Alias"; @@ -106,8 +107,8 @@ private void InitializeComponent() // // Comment // - dataGridViewCellStyle15.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.Comment.DefaultCellStyle = dataGridViewCellStyle15; + dataGridViewCellStyle7.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Comment.DefaultCellStyle = dataGridViewCellStyle7; this.Comment.HeaderText = "Comment"; this.Comment.MaxInputLength = 800; this.Comment.Name = "Comment"; @@ -118,15 +119,15 @@ private void InitializeComponent() this.import.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.import.Location = new System.Drawing.Point(70, 3); this.import.Name = "import"; - this.import.Size = new System.Drawing.Size(62, 23); + this.import.Size = new System.Drawing.Size(116, 23); this.import.TabIndex = 1; - this.import.Text = "Import..."; + this.import.Text = "Import (Append) ..."; this.import.UseVisualStyleBackColor = true; - this.import.Click += new System.EventHandler(this.import_Click); + this.import.Click += new System.EventHandler(this.importAppend_Click); // // export // - this.export.Location = new System.Drawing.Point(136, 3); + this.export.Location = new System.Drawing.Point(338, 3); this.export.Name = "export"; this.export.Size = new System.Drawing.Size(62, 23); this.export.TabIndex = 2; @@ -167,12 +168,24 @@ private void InitializeComponent() // this.saveFileDialog1.Filter = "Comma Separated Value Files|*.csv|Text Files|*.txt|All Files|*.*"; // + // btnImportReplace + // + this.btnImportReplace.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnImportReplace.Location = new System.Drawing.Point(192, 3); + this.btnImportReplace.Name = "btnImportReplace"; + this.btnImportReplace.Size = new System.Drawing.Size(132, 23); + this.btnImportReplace.TabIndex = 5; + this.btnImportReplace.Text = "Import (Replace) ..."; + this.btnImportReplace.UseVisualStyleBackColor = true; + this.btnImportReplace.Click += new System.EventHandler(this.btnImportReplace_Click); + // // AliasList // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.import; this.ClientSize = new System.Drawing.Size(402, 364); + this.Controls.Add(this.btnImportReplace); this.Controls.Add(this.jump); this.Controls.Add(this.statusStrip1); this.Controls.Add(this.export); @@ -209,5 +222,6 @@ private void InitializeComponent() private System.Windows.Forms.Button jump; private System.Windows.Forms.OpenFileDialog openFileDialog1; private System.Windows.Forms.SaveFileDialog saveFileDialog1; + private System.Windows.Forms.Button btnImportReplace; } } \ No newline at end of file diff --git a/DiztinGUIsh/window/AliasList.cs b/DiztinGUIsh/window/AliasList.cs index aabfc1e8..1d5c802a 100644 --- a/DiztinGUIsh/window/AliasList.cs +++ b/DiztinGUIsh/window/AliasList.cs @@ -7,6 +7,7 @@ using System.IO; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows.Forms; @@ -76,21 +77,24 @@ private static void SplitOnFirstComma(string instr, out string first_part, out s remainder = instr.Substring(instr.IndexOf(',') + 1); } - private void import_Click(object sender, EventArgs e) + private void ImportLabelsFromCSV(bool replaceAll) { DialogResult result = openFileDialog1.ShowDialog(); - if (result != DialogResult.OK || openFileDialog1.FileName == "") + if (result != DialogResult.OK || openFileDialog1.FileName == "") return; - + int errLine = 0; try { Dictionary newValues = new Dictionary(); - string[] lines = File.ReadAllLines(openFileDialog1.FileName); + string[] lines = Util.ReadLines(openFileDialog1.FileName).ToArray(); + + Regex valid_label_chars = new Regex(@"^([a-zA-Z0-9_\-]*)$"); // NOTE: this is kind of a risky way to parse CSV files, won't deal with weirdness in the comments // section. - for (int i = 0; i < lines.Length; i++) { + for (int i = 0; i < lines.Length; i++) + { var aliasInfo = new Data.AliasInfo(); errLine = i + 1; @@ -98,20 +102,31 @@ private void import_Click(object sender, EventArgs e) AliasList.SplitOnFirstComma(lines[i], out var labelAddress, out var remainder); AliasList.SplitOnFirstComma(remainder, out aliasInfo.name, out aliasInfo.comment); - // todo (validate for valid label characters) + aliasInfo.CleanUp(); + + aliasInfo.name = aliasInfo.name.Trim(); + if (!valid_label_chars.Match(aliasInfo.name).Success) + throw new InvalidDataException("invalid label name: " + aliasInfo.name); + newValues.Add(int.Parse(labelAddress, NumberStyles.HexNumber, null), aliasInfo); } + // everything read OK, modify the existing list now. point of no return + if (replaceAll) + Data.DeleteAllLabels(); + + ResetDataGrid(); + + // this will call AddRow() to add items back to the UI datagrid. foreach (KeyValuePair pair in newValues) { - pair.Value.CleanUp(); Data.AddLabel(pair.Key, pair.Value, true); } } - catch (Exception) + catch (Exception ex) { MessageBox.Show( - "An error occurred while parsing the file." + + "An error occurred while parsing the file.\n" + ex.Message + (errLine > 0 ? string.Format(" (Check line {0}.)", errLine) : ""), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } @@ -248,10 +263,33 @@ public void RemoveRow(int address) } } - public void Reset() + public void ResetDataGrid() { dataGridView1.Rows.Clear(); dataGridView1.Invalidate(); } + + private void importAppend_Click(object sender, EventArgs e) + { + if (MessageBox.Show("Info: Items in CSV will:\n" + + "1) CSV items will be added if their address doesn't already exist in this list\n" + + "2) CSV items will replace anything with the same address as items in the list\n" + + "3) any unmatched addresses in the list will be left alone\n" + + "\n" + + "Continue?\n", "Warning", MessageBoxButtons.OKCancel) != DialogResult.OK) + return; + + ImportLabelsFromCSV(false); + } + + private void btnImportReplace_Click(object sender, EventArgs e) + { + if (MessageBox.Show("Info: All list items will be deleted and replaced with the CSV file.\n" + + "\n" + + "Continue?\n", "Warning", MessageBoxButtons.OKCancel) != DialogResult.OK) + return; + + ImportLabelsFromCSV(true); + } } } From 3acf32e800cdeb1e72da5ff99e72c6d03cef3b1b Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 19 Sep 2020 15:58:04 -0400 Subject: [PATCH 033/136] add fork-specific documentation to README --- README.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ba976ce3..15796b11 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,20 @@ -# DiztinGUIsh +# DiztinGUIsh-FORK1 + +Note from fork author binary1230: +This is a fork of DiztinGUIsh https://github.com/Dotsarecool/DiztinGUIsh which adds some bells and whistles like: +- UX improvements (progress bars, easier GoTo search, open last project automatically, etc) +- Attach comments to labels themselves for documentation +- Integration and extension of functionality from @Gocha's fork: https://github.com/gocha/DiztinGUIsh for support for BSNESplus trace logs and usage maps. HIGHLY RECOMMEND if you're doing any serious disassembly work, it's super-useful. +- Various other small fixes/improvements + +Works fine with stock asar though, there's a bugfix you may want: +- https://github.com/binary1230/asar/tree/fix_relative_addressing/src/asar + +See discussion about the future of this fork here: +- https://github.com/Dotsarecool/DiztinGUIsh/issues/16 +- I hope to include all of the changes from this fork back upstream, but, maintaining this fork for the moment. + +# DiztinGUIsh original documentation follows A Super NES ROM Disassembler. @@ -45,4 +61,4 @@ Planned stuff: * Programmable data viewer to locate graphics easily * Setting a "base" per instruction for relocateable code * Option to put large data blocks into separate .bin files intead of in the .asm -* Scripting engine & API \ No newline at end of file +* Scripting engine & API From 0eb795c4e1d2180a01e34fde5d916671285bf652 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 19 Sep 2020 20:24:22 -0400 Subject: [PATCH 034/136] reverse direction of comparison to future-proof with BSNES --- DiztinGUIsh/static/diz/Manager.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/DiztinGUIsh/static/diz/Manager.cs b/DiztinGUIsh/static/diz/Manager.cs index 0a15c2a6..792fe1bf 100644 --- a/DiztinGUIsh/static/diz/Manager.cs +++ b/DiztinGUIsh/static/diz/Manager.cs @@ -361,8 +361,11 @@ int GetHexValueAt(int startIndex, int length) { int directPage = GetHexValueAt(CachedIdx.D, 4); int dataBank = GetHexValueAt(CachedIdx.DB, 2); - bool xflag_set = line[CachedIdx.f_X] != 'x'; // X = unchecked (8), x = checked (16) - bool mflag_set = line[CachedIdx.f_M] != 'm'; // M = unchecked (8), m = checked (16) + // 'X' = unchecked in bsnesplus debugger UI = (8bit), 'x' or '.' = checked (16bit) + bool xflag_set = line[CachedIdx.f_X] == 'X'; + + // 'M' = unchecked in bsnesplus debugger UI = (8bit), 'm' or '.' = checked (16bit) + bool mflag_set = line[CachedIdx.f_M] == 'M'; Data.SetFlag(pc, Data.FlagType.Opcode); From 3337338effb61f1f9b8e0d42dd804fbe3a5050a0 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 20 Sep 2020 10:59:53 -0400 Subject: [PATCH 035/136] make Data be singleton --- DiztinGUIsh/DiztinGUIsh.csproj | 1 + DiztinGUIsh/static/Class1.cs | 70 ++++++++++++ DiztinGUIsh/static/Data.cs | 84 ++++++++------- DiztinGUIsh/static/LogCreator.cs | 70 ++++++------ DiztinGUIsh/static/Project.cs | 60 +++++------ DiztinGUIsh/static/Util.cs | 64 +++++------ DiztinGUIsh/static/diz/CPU65C816.cs | 82 +++++++------- DiztinGUIsh/static/diz/Manager.cs | 88 +++++++-------- DiztinGUIsh/window/AliasList.cs | 16 +-- DiztinGUIsh/window/MainWindow.cs | 102 +++++++++--------- .../window/dialog/ExportDisassembly.cs | 14 +-- DiztinGUIsh/window/dialog/GotoDialog.cs | 2 +- DiztinGUIsh/window/dialog/HarshAutoStep.cs | 4 +- DiztinGUIsh/window/dialog/ImportROMDialog.cs | 2 +- DiztinGUIsh/window/dialog/MarkManyDialog.cs | 6 +- .../window/dialog/MisalignmentChecker.cs | 8 +- 16 files changed, 375 insertions(+), 298 deletions(-) create mode 100644 DiztinGUIsh/static/Class1.cs diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 89b77ee8..4682b46a 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -70,6 +70,7 @@ + Form diff --git a/DiztinGUIsh/static/Class1.cs b/DiztinGUIsh/static/Class1.cs new file mode 100644 index 00000000..5a3e8ee5 --- /dev/null +++ b/DiztinGUIsh/static/Class1.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DiztinGUIsh; + + +class TextLoader +{ + void Save() + { + int size = Data.Inst.GetROMSize(); + + // byte[] romSettings = new byte[31]; + //romSettings[0] = (byte)Data.Inst.GetROMMapMode(); + //romSettings[1] = (byte)Data.Inst.GetROMSpeed(); + + + + /*(Util.IntegerIntoByteArray(size, romSettings, 2); + for (int i = 0; i < 0x15; i++) romSettings[6 + i] = (byte)Data.Inst.GetROMByte(Util.ConvertSNEStoPC(0xFFC0 + i)); + for (int i = 0; i < 4; i++) romSettings[27 + i] = (byte)Data.Inst.GetROMByte(Util.ConvertSNEStoPC(0xFFDC + i)); + + // TODO put selected offset in save file + + List label = new List(), comment = new List(); + var all_labels = Data.Inst.GetAllLabels(); + var all_comments = Data.Inst.GetAllComments(); + + Util.IntegerIntoByteList(all_labels.Count, label); + foreach (var pair in all_labels) + { + Util.IntegerIntoByteList(pair.Key, label); + + SaveStringToBytes(pair.Value.name, label); + if (version >= 2) + { + SaveStringToBytes(pair.Value.comment, label); + } + } + + Util.IntegerIntoByteList(all_comments.Count, comment); + foreach (KeyValuePair pair in all_comments) + { + Util.IntegerIntoByteList(pair.Key, comment); + SaveStringToBytes(pair.Value, comment); + } + + byte[] romLocation = Util.StringToByteArray(currentROMFile); + + byte[] data = new byte[romSettings.Length + romLocation.Length + 8 * size + label.Count + comment.Count]; + romSettings.CopyTo(data, 0); + for (int i = 0; i < romLocation.Length; i++) data[romSettings.Length + i] = romLocation[i]; + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + i] = (byte)Data.Inst.GetDataBank(i); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + size + i] = (byte)Data.Inst.GetDirectPage(i); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 2 * size + i] = (byte)(Data.Inst.GetDirectPage(i) >> 8); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 3 * size + i] = (byte)(Data.Inst.GetXFlag(i) ? 1 : 0); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 4 * size + i] = (byte)(Data.Inst.GetMFlag(i) ? 1 : 0); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 5 * size + i] = (byte)Data.Inst.GetFlag(i); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 6 * size + i] = (byte)Data.Inst.GetArchitechture(i); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 7 * size + i] = (byte)Data.Inst.GetInOutPoint(i); + // ??? + label.CopyTo(data, romSettings.Length + romLocation.Length + 8 * size); + comment.CopyTo(data, romSettings.Length + romLocation.Length + 8 * size + label.Count); + // ??? + + return data;*/ + } +} diff --git a/DiztinGUIsh/static/Data.cs b/DiztinGUIsh/static/Data.cs index b964b699..13810c75 100644 --- a/DiztinGUIsh/static/Data.cs +++ b/DiztinGUIsh/static/Data.cs @@ -8,8 +8,14 @@ namespace DiztinGUIsh { - public static class Data + public class Data { + // singleton + private static readonly Lazy instance = new Lazy(() => new Data()); + public static Data Inst => instance.Value; + + private Data() {} + public enum FlagType : byte { Unreached = 0x00, @@ -71,10 +77,10 @@ public const int EXHIROM_SETTING_OFFSET = 0x40FFD5, EXLOROM_SETTING_OFFSET = 0x407FD5; - private static ROMMapMode rom_map_mode; - private static ROMSpeed rom_speed; - private static List table; - private static Dictionary comment; + private ROMMapMode rom_map_mode; + private ROMSpeed rom_speed; + private List table; + private Dictionary comment; public class AliasInfo { @@ -87,9 +93,9 @@ public void CleanUp() if (name == null) name = ""; } } - private static Dictionary alias; + private Dictionary alias; - public static void Initiate(byte[] data, ROMMapMode mode, ROMSpeed speed) + public void Initiate(byte[] data, ROMMapMode mode, ROMSpeed speed) { rom_map_mode = mode; rom_speed = speed; @@ -114,7 +120,7 @@ public static void Initiate(byte[] data, ROMMapMode mode, ROMSpeed speed) } } - public static void Restore(List l = null, ROMMapMode m = ROMMapMode.LoROM, ROMSpeed s = ROMSpeed.Unknown, Dictionary a = null, Dictionary c = null) + public void Restore(List l = null, ROMMapMode m = ROMMapMode.LoROM, ROMSpeed s = ROMSpeed.Unknown, Dictionary a = null, Dictionary c = null) { table = l ?? table; rom_map_mode = s == ROMSpeed.Unknown ? rom_map_mode : m; @@ -123,125 +129,125 @@ public static void Restore(List l = null, ROMMapMode m = ROMMapMode.LoR comment = c ?? comment; } - public static ROMMapMode GetROMMapMode() + public ROMMapMode GetROMMapMode() { return rom_map_mode; } - public static ROMSpeed GetROMSpeed() + public ROMSpeed GetROMSpeed() { return rom_speed; } - public static List GetTable() + public List GetTable() { return table; } - public static int GetROMByte(int i) + public int GetROMByte(int i) { return table[i].Rom; } - public static int GetROMSize() + public int GetROMSize() { return table == null ? 0 : table.Count; } - public static FlagType GetFlag(int i) + public FlagType GetFlag(int i) { return table[i].TypeFlag; } - public static void SetFlag(int i, FlagType flag) + public void SetFlag(int i, FlagType flag) { table[i].TypeFlag = flag; } - public static Architechture GetArchitechture(int i) + public Architechture GetArchitechture(int i) { return table[i].Arch; } - public static void SetArchitechture(int i, Architechture arch) + public void SetArchitechture(int i, Architechture arch) { table[i].Arch = arch; } - public static InOutPoint GetInOutPoint(int i) + public InOutPoint GetInOutPoint(int i) { return table[i].Point; } - public static void SetInOutPoint(int i, InOutPoint point) + public void SetInOutPoint(int i, InOutPoint point) { table[i].Point |= point; } - public static void ClearInOutPoint(int i) + public void ClearInOutPoint(int i) { table[i].Point = 0; } - public static int GetDataBank(int i) + public int GetDataBank(int i) { return table[i].DataBank; } - public static void SetDataBank(int i, int dbank) + public void SetDataBank(int i, int dbank) { table[i].DataBank = (byte)dbank; } - public static int GetDirectPage(int i) + public int GetDirectPage(int i) { return table[i].DirectPage; } - public static void SetDirectPage(int i, int dpage) + public void SetDirectPage(int i, int dpage) { table[i].DirectPage = 0xFFFF & dpage; } - public static bool GetXFlag(int i) + public bool GetXFlag(int i) { return table[i].XFlag; } - public static void SetXFlag(int i, bool x) + public void SetXFlag(int i, bool x) { table[i].XFlag = x; } - public static bool GetMFlag(int i) + public bool GetMFlag(int i) { return table[i].MFlag; } - public static void SetMFlag(int i, bool m) + public void SetMFlag(int i, bool m) { table[i].MFlag = m; } - public static int GetMXFlags(int i) + public int GetMXFlags(int i) { return (table[i].MFlag ? 0x20 : 0) | (table[i].XFlag ? 0x10 : 0); } - public static void SetMXFlags(int i, int mx) + public void SetMXFlags(int i, int mx) { table[i].MFlag = ((mx & 0x20) != 0); table[i].XFlag = ((mx & 0x10) != 0); } - public static string GetLabelName(int i) + public string GetLabelName(int i) { if (alias.TryGetValue(i, out AliasInfo val)) return val?.name ?? ""; return ""; } - public static string GetLabelComment(int i) + public string GetLabelComment(int i) { if (alias.TryGetValue(i, out AliasInfo val)) return val?.comment ?? ""; @@ -249,12 +255,12 @@ public static string GetLabelComment(int i) return ""; } - public static void DeleteAllLabels() + public void DeleteAllLabels() { alias.Clear(); } - public static void AddLabel(int i, AliasInfo v, bool overwrite) + public void AddLabel(int i, AliasInfo v, bool overwrite) { if (v == null) { @@ -279,19 +285,19 @@ public static void AddLabel(int i, AliasInfo v, bool overwrite) } } - public static Dictionary GetAllLabels() + public Dictionary GetAllLabels() { return alias; } - public static string GetComment(int i) + public string GetComment(int i) { string val; if (comment.TryGetValue(i, out val)) return val; return ""; } - public static void AddComment(int i, string v, bool overwrite) + public void AddComment(int i, string v, bool overwrite) { if (v == null) { @@ -303,12 +309,12 @@ public static void AddComment(int i, string v, bool overwrite) } } - public static Dictionary GetAllComments() + public Dictionary GetAllComments() { return comment; } - public static int GetRomSettingOffset(ROMMapMode mode) + public int GetRomSettingOffset(ROMMapMode mode) { switch (mode) { diff --git a/DiztinGUIsh/static/LogCreator.cs b/DiztinGUIsh/static/LogCreator.cs index b5184a6c..a365755d 100644 --- a/DiztinGUIsh/static/LogCreator.cs +++ b/DiztinGUIsh/static/LogCreator.cs @@ -61,10 +61,10 @@ public enum FormatStructure public static int CreateLog(StreamWriter sw, StreamWriter er) { - var tempAlias = Data.GetAllLabels(); - Data.Restore(a: new Dictionary(tempAlias)); + var tempAlias = Data.Inst.GetAllLabels(); + Data.Inst.Restore(a: new Dictionary(tempAlias)); AliasList.me.locked = true; - bankSize = Data.GetROMMapMode() == Data.ROMMapMode.LoROM ? 0x8000 : 0x10000; // todo + bankSize = Data.Inst.GetROMMapMode() == Data.ROMMapMode.LoROM ? 0x8000 : 0x10000; // todo AddTemporaryLabels(); @@ -85,7 +85,7 @@ public static int CreateLog(StreamWriter sw, StreamWriter er) } } - int pointer = 0, size = (Data.GetTable() == ExportDisassembly.sampleTable) ? 0x7B : Data.GetROMSize(), bank = -1; + int pointer = 0, size = (Data.Inst.GetTable() == ExportDisassembly.sampleTable) ? 0x7B : Data.Inst.GetROMSize(), bank = -1; if (structure == FormatStructure.OneBankPerFile) { @@ -114,7 +114,7 @@ public static int CreateLog(StreamWriter sw, StreamWriter er) WriteLabels(ref sw, pointer); if (structure == FormatStructure.OneBankPerFile) sw.Close(); - Data.Restore(a: tempAlias); + Data.Inst.Restore(a: tempAlias); AliasList.me.locked = false; return errorCount; } @@ -139,13 +139,13 @@ private static void WriteAddress(ref StreamWriter sw, ref int pointer, Dictionar bank = snes >> 16; } - var c1 = (Data.GetInOutPoint(pointer) & (Data.InOutPoint.ReadPoint)) != 0; + var c1 = (Data.Inst.GetInOutPoint(pointer) & (Data.InOutPoint.ReadPoint)) != 0; var c2 = (tempAlias.TryGetValue(pointer, out var aliasInfo) && aliasInfo.name.Length > 0); if (c1 || c2) sw.WriteLine(GetLine(pointer, "empty")); sw.WriteLine(GetLine(pointer, null)); - if ((Data.GetInOutPoint(pointer) & (Data.InOutPoint.EndPoint)) != 0) sw.WriteLine(GetLine(pointer, "empty")); + if ((Data.Inst.GetInOutPoint(pointer) & (Data.InOutPoint.EndPoint)) != 0) sw.WriteLine(GetLine(pointer, "empty")); pointer += GetLineByteLength(pointer); } @@ -156,7 +156,7 @@ private static void WriteLabels(ref StreamWriter sw, int pointer) Dictionary listToPrint = new Dictionary(); // part 1: important: include all labels we aren't defining somewhere else. needed for disassembly - foreach (var pair in Data.GetAllLabels()) + foreach (var pair in Data.Inst.GetAllLabels()) { if (usedLabels.Contains(pair.Key)) continue; @@ -176,7 +176,7 @@ private static void WriteLabels(ref StreamWriter sw, int pointer) if (includeUnusedLabels) { SwitchOutputFile(ref sw, pointer, $"{folder}/all-labels.txt"); - foreach (var pair in Data.GetAllLabels()) + foreach (var pair in Data.Inst.GetAllLabels()) { // not the best place to add formatting, TODO: cleanup var category = listToPrint.ContainsKey(pair.Key) ? "INLINE" : "EXTRA "; @@ -203,10 +203,10 @@ private static void AddTemporaryLabels() List addMe = new List(); int pointer = 0; - while (pointer < Data.GetROMSize()) + while (pointer < Data.Inst.GetROMSize()) { int length = GetLineByteLength(pointer); - Data.FlagType flag = Data.GetFlag(pointer); + Data.FlagType flag = Data.Inst.GetFlag(pointer); if (unlabeled == FormatUnlabeled.ShowAll) addMe.Add(Util.ConvertPCtoSNES(pointer)); else if (unlabeled != FormatUnlabeled.ShowNone && @@ -222,7 +222,7 @@ private static void AddTemporaryLabels() // TODO +/- labels for (int i = 0; i < addMe.Count; i++) { - Data.AddLabel(addMe[i], + Data.Inst.AddLabel(addMe[i], new Data.AliasInfo() { name = Util.GetDefaultLabel(addMe[i]) @@ -253,9 +253,9 @@ private static string GetLine(int offset, string special) if (special == null) { // throw out some errors if stuff looks fishy - Data.FlagType flag = Data.GetFlag(offset), check = flag == Data.FlagType.Opcode ? Data.FlagType.Operand : flag; - int step = flag == Data.FlagType.Opcode ? GetLineByteLength(offset) : Util.TypeStepSize(flag), size = Data.GetROMSize(); - if (flag == Data.FlagType.Operand) err.WriteLine("({0}) Offset 0x{1:X}: Bytes marked as operands formatted as data.", ++errorCount, offset); + Data.FlagType flag = Data.Inst.GetFlag(offset), check = flag == Data.FlagType.Opcode ? Data.FlagType.Operand : flag; + int step = flag == Data.FlagType.Opcode ? GetLineByteLength(offset) : Util.TypeStepSize(flag), size = Data.Inst.GetROMSize(); + if (flag == Data.FlagType.Operand) err.WriteLine("({0}) Offset 0x{1:X}: Bytes marked as operands formatted as Data.Inst.", ++errorCount, offset); else if (step > 1) { for (int i = 1; i < step; i++) @@ -265,15 +265,15 @@ private static string GetLine(int offset, string special) err.WriteLine("({0}) Offset 0x{1:X}: {2} extends past the end of the ROM.", ++errorCount, offset, Util.TypeToString(check)); break; } - else if (Data.GetFlag(offset + i) != check) + else if (Data.Inst.GetFlag(offset + i) != check) { - err.WriteLine("({0}) Offset 0x{1:X}: Expected {2}, but got {3} instead.", ++errorCount, offset + i, Util.TypeToString(check), Util.TypeToString(Data.GetFlag(offset + i))); + err.WriteLine("({0}) Offset 0x{1:X}: Expected {2}, but got {3} instead.", ++errorCount, offset + i, Util.TypeToString(check), Util.TypeToString(Data.Inst.GetFlag(offset + i))); break; } } } int ia = Util.GetIntermediateAddress(offset, true); - if (ia >= 0 && flag == Data.FlagType.Opcode && Data.GetInOutPoint(offset) == Data.InOutPoint.OutPoint && Data.GetFlag(Util.ConvertSNEStoPC(ia)) != Data.FlagType.Opcode) + if (ia >= 0 && flag == Data.FlagType.Opcode && Data.Inst.GetInOutPoint(offset) == Data.InOutPoint.OutPoint && Data.Inst.GetFlag(Util.ConvertSNEStoPC(ia)) != Data.FlagType.Opcode) { err.WriteLine("({0}) Offset 0x{1:X}: Branch or jump instruction to a non-instruction.", ++errorCount, offset); } @@ -285,12 +285,12 @@ private static string GetLine(int offset, string special) private static int GetLineByteLength(int offset) { int max = 1, step = 1; - int size = Data.GetROMSize(); + int size = Data.Inst.GetROMSize(); - switch (Data.GetFlag(offset)) + switch (Data.Inst.GetFlag(offset)) { case Data.FlagType.Opcode: - switch (Data.GetArchitechture(offset)) + switch (Data.Inst.GetArchitechture(offset)) { case Data.Architechture.CPU65C816: return CPU65C816.GetInstructionLength(offset); case Data.Architechture.APUSPC700: return 1; @@ -338,8 +338,8 @@ private static int GetLineByteLength(int offset) while ( min < max && offset + min < size && - Data.GetFlag(offset + min) == Data.GetFlag(offset) && - Data.GetLabelName(Util.ConvertPCtoSNES(offset + min)) == "" && + Data.Inst.GetFlag(offset + min) == Data.Inst.GetFlag(offset) && + Data.Inst.GetLabelName(Util.ConvertPCtoSNES(offset + min)) == "" && (offset + min) / bankSize == myBank ) min += step; return min; @@ -369,7 +369,7 @@ private static string GetEmpty(int offset, int length) private static string GetLabel(int offset, int length) { int snes = Util.ConvertPCtoSNES(offset); - string label = Data.GetLabelName(snes); + string label = Data.Inst.GetLabelName(snes); if (label == null) return ""; @@ -384,7 +384,7 @@ private static string GetCode(int offset, int length) int bytes = GetLineByteLength(offset); string code = ""; - switch (Data.GetFlag(offset)) + switch (Data.Inst.GetFlag(offset)) { case Data.FlagType.Opcode: code = Util.GetInstruction(offset); @@ -432,7 +432,7 @@ private static string GetORG(int offset, int length) private static string GetMap(int offset, int length) { string s = ""; - switch (Data.GetROMMapMode()) + switch (Data.Inst.GetROMMapMode()) { case Data.ROMMapMode.LoROM: s = "lorom"; break; case Data.ROMMapMode.HiROM: s = "hirom"; break; @@ -486,11 +486,11 @@ private static string GetOffset(int offset, int length) private static string GetRawBytes(int offset, int length) { string bytes = ""; - if (Data.GetFlag(offset) == Data.FlagType.Opcode) + if (Data.Inst.GetFlag(offset) == Data.FlagType.Opcode) { for (int i = 0; i < Manager.GetInstructionLength(offset); i++) { - bytes += Util.NumberToBaseString(Data.GetROMByte(offset + i), Util.NumberBase.Hexadecimal); + bytes += Util.NumberToBaseString(Data.Inst.GetROMByte(offset + i), Util.NumberBase.Hexadecimal); } } return string.Format("{0,-8}", bytes); @@ -499,25 +499,25 @@ private static string GetRawBytes(int offset, int length) // trim to length private static string GetComment(int offset, int length) { - return string.Format("{0," + (length * -1) + "}", Data.GetComment(Util.ConvertPCtoSNES(offset))); + return string.Format("{0," + (length * -1) + "}", Data.Inst.GetComment(Util.ConvertPCtoSNES(offset))); } // length forced to 2 private static string GetDataBank(int offset, int length) { - return Util.NumberToBaseString(Data.GetDataBank(offset), Util.NumberBase.Hexadecimal, 2); + return Util.NumberToBaseString(Data.Inst.GetDataBank(offset), Util.NumberBase.Hexadecimal, 2); } // length forced to 4 private static string GetDirectPage(int offset, int length) { - return Util.NumberToBaseString(Data.GetDirectPage(offset), Util.NumberBase.Hexadecimal, 4); + return Util.NumberToBaseString(Data.Inst.GetDirectPage(offset), Util.NumberBase.Hexadecimal, 4); } // if length == 1, M/m, else 08/16 private static string GetMFlag(int offset, int length) { - bool m = Data.GetMFlag(offset); + bool m = Data.Inst.GetMFlag(offset); if (length == 1) return m ? "M" : "m"; else return m ? "08" : "16"; } @@ -525,7 +525,7 @@ private static string GetMFlag(int offset, int length) // if length == 1, X/x, else 08/16 private static string GetXFlag(int offset, int length) { - bool x = Data.GetXFlag(offset); + bool x = Data.Inst.GetXFlag(offset); if (length == 1) return x ? "X" : "x"; else return x ? "08" : "16"; } @@ -533,9 +533,9 @@ private static string GetXFlag(int offset, int length) // output label at snes offset, and its value private static string GetLabelAssign(int offset, int length) { - var labelName = Data.GetLabelName(offset); + var labelName = Data.Inst.GetLabelName(offset); var offsetStr = Util.NumberToBaseString(offset, Util.NumberBase.Hexadecimal, 6, true); - var labelComment = Data.GetLabelComment(offset); + var labelComment = Data.Inst.GetLabelComment(offset); if (string.IsNullOrEmpty(labelName)) return ""; diff --git a/DiztinGUIsh/static/Project.cs b/DiztinGUIsh/static/Project.cs index bf92d883..c1d51c45 100644 --- a/DiztinGUIsh/static/Project.cs +++ b/DiztinGUIsh/static/Project.cs @@ -37,7 +37,7 @@ public static bool NewProject(string filename) DialogResult result = import.ShowDialog(); if (result == DialogResult.OK) { - Data.Initiate(rom, import.GetROMMapMode(), import.GetROMSpeed()); + Data.Inst.Initiate(rom, import.GetROMMapMode(), import.GetROMSpeed()); unsavedChanges = false; currentFile = null; @@ -45,14 +45,14 @@ public static bool NewProject(string filename) Dictionary generatedLabels = import.GetGeneratedLabels(); if (generatedLabels.Count > 0) { - foreach (KeyValuePair pair in generatedLabels) Data.AddLabel(pair.Key, pair.Value, true); + foreach (KeyValuePair pair in generatedLabels) Data.Inst.AddLabel(pair.Key, pair.Value, true); unsavedChanges = true; } Dictionary generatedFlags = import.GetHeaderFlags(); if (generatedFlags.Count > 0) { - foreach (KeyValuePair pair in generatedFlags) Data.SetFlag(pair.Key, pair.Value); + foreach (KeyValuePair pair in generatedFlags) Data.Inst.SetFlag(pair.Key, pair.Value); unsavedChanges = true; } @@ -112,19 +112,19 @@ void SaveStringToBytes(string str, List bytes) throw new ArgumentException($"Saving: Invalid save version requested for saving: {version}."); } - int size = Data.GetROMSize(); + int size = Data.Inst.GetROMSize(); byte[] romSettings = new byte[31]; - romSettings[0] = (byte)Data.GetROMMapMode(); - romSettings[1] = (byte)Data.GetROMSpeed(); + romSettings[0] = (byte)Data.Inst.GetROMMapMode(); + romSettings[1] = (byte)Data.Inst.GetROMSpeed(); Util.IntegerIntoByteArray(size, romSettings, 2); - for (int i = 0; i < 0x15; i++) romSettings[6 + i] = (byte)Data.GetROMByte(Util.ConvertSNEStoPC(0xFFC0 + i)); - for (int i = 0; i < 4; i++) romSettings[27 + i] = (byte)Data.GetROMByte(Util.ConvertSNEStoPC(0xFFDC + i)); + for (int i = 0; i < 0x15; i++) romSettings[6 + i] = (byte)Data.Inst.GetROMByte(Util.ConvertSNEStoPC(0xFFC0 + i)); + for (int i = 0; i < 4; i++) romSettings[27 + i] = (byte)Data.Inst.GetROMByte(Util.ConvertSNEStoPC(0xFFDC + i)); // TODO put selected offset in save file List label = new List(), comment = new List(); - var all_labels = Data.GetAllLabels(); - var all_comments = Data.GetAllComments(); + var all_labels = Data.Inst.GetAllLabels(); + var all_comments = Data.Inst.GetAllComments(); Util.IntegerIntoByteList(all_labels.Count, label); foreach (var pair in all_labels) @@ -150,14 +150,14 @@ void SaveStringToBytes(string str, List bytes) byte[] data = new byte[romSettings.Length + romLocation.Length + 8 * size + label.Count + comment.Count]; romSettings.CopyTo(data, 0); for (int i = 0; i < romLocation.Length; i++) data[romSettings.Length + i] = romLocation[i]; - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + i] = (byte)Data.GetDataBank(i); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + size + i] = (byte)Data.GetDirectPage(i); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 2 * size + i] = (byte)(Data.GetDirectPage(i) >> 8); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 3 * size + i] = (byte)(Data.GetXFlag(i) ? 1 : 0); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 4 * size + i] = (byte)(Data.GetMFlag(i) ? 1 : 0); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 5 * size + i] = (byte)Data.GetFlag(i); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 6 * size + i] = (byte)Data.GetArchitechture(i); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 7 * size + i] = (byte)Data.GetInOutPoint(i); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + i] = (byte)Data.Inst.GetDataBank(i); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + size + i] = (byte)Data.Inst.GetDirectPage(i); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 2 * size + i] = (byte)(Data.Inst.GetDirectPage(i) >> 8); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 3 * size + i] = (byte)(Data.Inst.GetXFlag(i) ? 1 : 0); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 4 * size + i] = (byte)(Data.Inst.GetMFlag(i) ? 1 : 0); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 5 * size + i] = (byte)Data.Inst.GetFlag(i); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 6 * size + i] = (byte)Data.Inst.GetArchitechture(i); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 7 * size + i] = (byte)Data.Inst.GetInOutPoint(i); // ??? label.CopyTo(data, romSettings.Length + romLocation.Length + 8 * size); comment.CopyTo(data, romSettings.Length + romLocation.Length + 8 * size + label.Count); @@ -238,15 +238,15 @@ private static void OpenProject(int version, byte[] unzipped, OpenFileDialog ope if (ValidateROM(romLocation, romName, checksums, mode, out rom, open)) { - Data.Initiate(rom, mode, speed); - - for (int i = 0; i < size; i++) Data.SetDataBank(i, unzipped[pointer + i]); - for (int i = 0; i < size; i++) Data.SetDirectPage(i, unzipped[pointer + size + i] | (unzipped[pointer + 2 * size + i] << 8)); - for (int i = 0; i < size; i++) Data.SetXFlag(i, unzipped[pointer + 3 * size + i] != 0); - for (int i = 0; i < size; i++) Data.SetMFlag(i, unzipped[pointer + 4 * size + i] != 0); - for (int i = 0; i < size; i++) Data.SetFlag(i, (Data.FlagType)unzipped[pointer + 5 * size + i]); - for (int i = 0; i < size; i++) Data.SetArchitechture(i, (Data.Architechture)unzipped[pointer + 6 * size + i]); - for (int i = 0; i < size; i++) Data.SetInOutPoint(i, (Data.InOutPoint)unzipped[pointer + 7 * size + i]); + Data.Inst.Initiate(rom, mode, speed); + + for (int i = 0; i < size; i++) Data.Inst.SetDataBank(i, unzipped[pointer + i]); + for (int i = 0; i < size; i++) Data.Inst.SetDirectPage(i, unzipped[pointer + size + i] | (unzipped[pointer + 2 * size + i] << 8)); + for (int i = 0; i < size; i++) Data.Inst.SetXFlag(i, unzipped[pointer + 3 * size + i] != 0); + for (int i = 0; i < size; i++) Data.Inst.SetMFlag(i, unzipped[pointer + 4 * size + i] != 0); + for (int i = 0; i < size; i++) Data.Inst.SetFlag(i, (Data.FlagType)unzipped[pointer + 5 * size + i]); + for (int i = 0; i < size; i++) Data.Inst.SetArchitechture(i, (Data.Architechture)unzipped[pointer + 6 * size + i]); + for (int i = 0; i < size; i++) Data.Inst.SetInOutPoint(i, (Data.InOutPoint)unzipped[pointer + 7 * size + i]); pointer += 8 * size; AliasList.me.ResetDataGrid(); @@ -274,7 +274,7 @@ private static void ReadComments(byte[] unzipped, ref int pointer, AddressConver var comment = Util.ReadZipString(unzipped, ref pointer); - Data.AddComment(offset, comment, true); + Data.Inst.AddComment(offset, comment, true); } } @@ -294,7 +294,7 @@ private static void ReadAliases(byte[] unzipped, ref int pointer, AddressConvert }; aliasInfo.CleanUp(); - Data.AddLabel(offset, aliasInfo, true); + Data.Inst.AddLabel(offset, aliasInfo, true); } } @@ -341,7 +341,7 @@ private static bool ValidateROM(string filename, string romName, int checksums, } validFile = false; - int offset = Data.GetRomSettingOffset(mode); + int offset = Data.Inst.GetRomSettingOffset(mode); if (rom.Length <= offset + 10) error = "The linked ROM is too small. It can't be opened."; string myName = ""; diff --git a/DiztinGUIsh/static/Util.cs b/DiztinGUIsh/static/Util.cs index 3c3c23f4..f24f886f 100644 --- a/DiztinGUIsh/static/Util.cs +++ b/DiztinGUIsh/static/Util.cs @@ -20,34 +20,34 @@ public enum NumberBase public static int GetROMWord(int offset) { - if (offset + 1 < Data.GetROMSize()) - return Data.GetROMByte(offset) + (Data.GetROMByte(offset + 1) << 8); + if (offset + 1 < Data.Inst.GetROMSize()) + return Data.Inst.GetROMByte(offset) + (Data.Inst.GetROMByte(offset + 1) << 8); return -1; } public static int GetROMLong(int offset) { - if (offset + 2 < Data.GetROMSize()) - return Data.GetROMByte(offset) + (Data.GetROMByte(offset + 1) << 8) + (Data.GetROMByte(offset + 2) << 16); + if (offset + 2 < Data.Inst.GetROMSize()) + return Data.Inst.GetROMByte(offset) + (Data.Inst.GetROMByte(offset + 1) << 8) + (Data.Inst.GetROMByte(offset + 2) << 16); return -1; } public static int GetROMDoubleWord(int offset) { - if (offset + 3 < Data.GetROMSize()) - return Data.GetROMByte(offset) + (Data.GetROMByte(offset + 1) << 8) + (Data.GetROMByte(offset + 2) << 16) + (Data.GetROMByte(offset + 3) << 24); + if (offset + 3 < Data.Inst.GetROMSize()) + return Data.Inst.GetROMByte(offset) + (Data.Inst.GetROMByte(offset + 1) << 8) + (Data.Inst.GetROMByte(offset + 2) << 16) + (Data.Inst.GetROMByte(offset + 3) << 24); return -1; } public static int GetIntermediateAddressOrPointer(int offset) { - switch (Data.GetFlag(offset)) + switch (Data.Inst.GetFlag(offset)) { case Data.FlagType.Unreached: case Data.FlagType.Opcode: return GetIntermediateAddress(offset, true); case Data.FlagType.Pointer16Bit: - int bank = Data.GetDataBank(offset); + int bank = Data.Inst.GetDataBank(offset); return (bank << 16) | GetROMWord(offset); case Data.FlagType.Pointer24Bit: case Data.FlagType.Pointer32Bit: @@ -59,7 +59,7 @@ public static int GetIntermediateAddressOrPointer(int offset) public static int GetIntermediateAddress(int offset, bool resolve = false) { // FIX ME: log and generation of dp opcodes. search references - switch (Data.GetArchitechture(offset)) + switch (Data.Inst.GetArchitechture(offset)) { case Data.Architechture.CPU65C816: return CPU65C816.GetIntermediateAddress(offset, resolve); case Data.Architechture.APUSPC700: return -1; @@ -70,7 +70,7 @@ public static int GetIntermediateAddress(int offset, bool resolve = false) public static string GetInstruction(int offset) { - switch (Data.GetArchitechture(offset)) + switch (Data.Inst.GetArchitechture(offset)) { case Data.Architechture.CPU65C816: return CPU65C816.GetInstruction(offset); case Data.Architechture.APUSPC700: return ""; @@ -96,7 +96,7 @@ public static string GetFormattedBytes(int offset, int step, int bytes) switch (step) { - case 1: res += NumberToBaseString(Data.GetROMByte(offset + i), NumberBase.Hexadecimal, 2, true); break; + case 1: res += NumberToBaseString(Data.Inst.GetROMByte(offset + i), NumberBase.Hexadecimal, 2, true); break; case 2: res += NumberToBaseString(GetROMWord(offset + i), NumberBase.Hexadecimal, 4, true); break; case 3: res += NumberToBaseString(GetROMLong(offset + i), NumberBase.Hexadecimal, 6, true); break; case 4: res += NumberToBaseString(GetROMDoubleWord(offset + i), NumberBase.Hexadecimal, 8, true); break; @@ -113,7 +113,7 @@ public static string GetPointer(int offset, int bytes) switch (bytes) { case 2: - ia = (Data.GetDataBank(offset) << 16) | GetROMWord(offset); + ia = (Data.Inst.GetDataBank(offset) << 16) | GetROMWord(offset); format = "dw {0}"; param = NumberToBaseString(GetROMWord(offset), NumberBase.Hexadecimal, 4, true); break; @@ -124,49 +124,49 @@ public static string GetPointer(int offset, int bytes) break; case 4: ia = GetROMLong(offset); - format = "dl {0}" + string.Format(" : db {0}", NumberToBaseString(Data.GetROMByte(offset + 3), NumberBase.Hexadecimal, 2, true)); + format = "dl {0}" + string.Format(" : db {0}", NumberToBaseString(Data.Inst.GetROMByte(offset + 3), NumberBase.Hexadecimal, 2, true)); param = NumberToBaseString(GetROMLong(offset), NumberBase.Hexadecimal, 6, true); break; } int pc = ConvertSNEStoPC(ia); - if (pc >= 0 && Data.GetLabelName(ia) != "") param = Data.GetLabelName(ia); + if (pc >= 0 && Data.Inst.GetLabelName(ia) != "") param = Data.Inst.GetLabelName(ia); return string.Format(format, param); } public static string GetFormattedText(int offset, int bytes) { string text = "db \""; - for (int i = 0; i < bytes; i++) text += (char)Data.GetROMByte(offset + i); + for (int i = 0; i < bytes; i++) text += (char)Data.Inst.GetROMByte(offset + i); return text + "\""; } public static string GetDefaultLabel(int address) { int pc = ConvertSNEStoPC(address); - return string.Format("{0}_{1}", TypeToLabel(Data.GetFlag(pc)), NumberToBaseString(address, NumberBase.Hexadecimal, 6)); + return string.Format("{0}_{1}", TypeToLabel(Data.Inst.GetFlag(pc)), NumberToBaseString(address, NumberBase.Hexadecimal, 6)); } public static int ConvertPCtoSNES(int offset) { - if (Data.GetROMMapMode() == Data.ROMMapMode.LoROM) + if (Data.Inst.GetROMMapMode() == Data.ROMMapMode.LoROM) { offset = ((offset & 0x3F8000) << 1) | 0x8000 | (offset & 0x7FFF); - if (Data.GetROMSpeed() == Data.ROMSpeed.FastROM || offset >= 0x7E0000) offset |= 0x800000; + if (Data.Inst.GetROMSpeed() == Data.ROMSpeed.FastROM || offset >= 0x7E0000) offset |= 0x800000; } - else if (Data.GetROMMapMode() == Data.ROMMapMode.HiROM) + else if (Data.Inst.GetROMMapMode() == Data.ROMMapMode.HiROM) { offset |= 0x400000; - if (Data.GetROMSpeed() == Data.ROMSpeed.FastROM || offset >= 0x7E0000) offset |= 0x800000; + if (Data.Inst.GetROMSpeed() == Data.ROMSpeed.FastROM || offset >= 0x7E0000) offset |= 0x800000; } - else if (Data.GetROMMapMode() == Data.ROMMapMode.ExHiROM) + else if (Data.Inst.GetROMMapMode() == Data.ROMMapMode.ExHiROM) { if (offset < 0x40000) offset |= 0xC00000; else if (offset >= 0x7E0000) offset &= 0x3FFFFF; } else { - if (offset >= 0x400000 && Data.GetROMMapMode() == Data.ROMMapMode.ExSA1ROM) + if (offset >= 0x400000 && Data.Inst.GetROMMapMode() == Data.ROMMapMode.ExSA1ROM) { offset += 0x800000; } @@ -187,7 +187,7 @@ public static int ConvertSNEStoPC(int address) // WRAM mirror & PPU regs are N/A to PC addressing if (((address & 0x400000) == 0) && ((address & 0x8000) == 0)) return -1; - switch (Data.GetROMMapMode()) + switch (Data.Inst.GetROMMapMode()) { case Data.ROMMapMode.LoROM: { @@ -212,7 +212,7 @@ public static int ConvertSNEStoPC(int address) if (address >= 0xC00000) { - if (Data.GetROMMapMode() == Data.ROMMapMode.ExSA1ROM) + if (Data.Inst.GetROMMapMode() == Data.ROMMapMode.ExSA1ROM) return UnmirroredOffset(address & 0x7FFFFF); else return UnmirroredOffset(address & 0x3FFFFF); @@ -275,7 +275,7 @@ public static string ReadZipString(byte[] unzipped, ref int pointer) private static int UnmirroredOffset(int offset) { - int size = Data.GetROMSize(); + int size = Data.Inst.GetROMSize(); // most of the time this is true; for efficiency if (offset < size) return offset; @@ -505,18 +505,18 @@ public static void PaintCell(int offset, DataGridViewCellStyle style, int column // editable cells show up green if (column == 0 || column == 8 || column == 9 || column == 12) style.SelectionBackColor = Color.Chartreuse; - switch (Data.GetFlag(offset)) + switch (Data.Inst.GetFlag(offset)) { case Data.FlagType.Unreached: style.BackColor = Color.LightGray; style.ForeColor = Color.DarkSlateGray; break; case Data.FlagType.Opcode: - int opcode = Data.GetROMByte(offset); + int opcode = Data.Inst.GetROMByte(offset); switch (column) { case 4: // <*> - Data.InOutPoint point = Data.GetInOutPoint(offset); + Data.InOutPoint point = Data.Inst.GetInOutPoint(offset); int r = 255, g = 255, b = 255; if ((point & (Data.InOutPoint.EndPoint | Data.InOutPoint.OutPoint)) != 0) g -= 50; if ((point & (Data.InOutPoint.InPoint)) != 0) r -= 50; @@ -544,7 +544,7 @@ public static void PaintCell(int offset, DataGridViewCellStyle style, int column case 11: // X Flag int mask = column == 10 ? 0x20 : 0x10; if (opcode == 0x28 || ((opcode == 0xC2 || opcode == 0xE2) // PLP SEP REP - && (Data.GetROMByte(offset + 1) & mask) != 0)) // relevant bit set + && (Data.Inst.GetROMByte(offset + 1) & mask) != 0)) // relevant bit set style.BackColor = Color.OrangeRed; if (opcode == 0x08) // PHP style.BackColor = Color.Yellow; @@ -580,15 +580,15 @@ public static void PaintCell(int offset, DataGridViewCellStyle style, int column break; } - if (selOffset >= 0 && selOffset < Data.GetROMSize()) + if (selOffset >= 0 && selOffset < Data.Inst.GetROMSize()) { if (column == 1 - //&& (Data.GetFlag(selOffset) == Data.FlagType.Opcode || Data.GetFlag(selOffset) == Data.FlagType.Unreached) + //&& (Data.Inst.GetFlag(selOffset) == Data.FlagType.Opcode || Data.Inst.GetFlag(selOffset) == Data.FlagType.Unreached) && ConvertSNEStoPC(GetIntermediateAddressOrPointer(selOffset)) == offset ) style.BackColor = Color.DeepPink; if (column == 6 - //&& (Data.GetFlag(offset) == Data.FlagType.Opcode || Data.GetFlag(offset) == Data.FlagType.Unreached) + //&& (Data.Inst.GetFlag(offset) == Data.FlagType.Opcode || Data.Inst.GetFlag(offset) == Data.FlagType.Unreached) && ConvertSNEStoPC(GetIntermediateAddressOrPointer(offset)) == selOffset ) style.BackColor = Color.DeepPink; } diff --git a/DiztinGUIsh/static/diz/CPU65C816.cs b/DiztinGUIsh/static/diz/CPU65C816.cs index e9aad13b..258a4b3e 100644 --- a/DiztinGUIsh/static/diz/CPU65C816.cs +++ b/DiztinGUIsh/static/diz/CPU65C816.cs @@ -10,42 +10,42 @@ public static class CPU65C816 { public static int Step(int offset, bool branch, bool force, int prevOffset) { - int opcode = Data.GetROMByte(offset); - int prevDirectPage = Data.GetDirectPage(offset); - int prevDataBank = Data.GetDataBank(offset); - bool prevX = Data.GetXFlag(offset), prevM = Data.GetMFlag(offset); + int opcode = Data.Inst.GetROMByte(offset); + int prevDirectPage = Data.Inst.GetDirectPage(offset); + int prevDataBank = Data.Inst.GetDataBank(offset); + bool prevX = Data.Inst.GetXFlag(offset), prevM = Data.Inst.GetMFlag(offset); - while (prevOffset >= 0 && Data.GetFlag(prevOffset) == Data.FlagType.Operand) prevOffset--; - if (prevOffset >= 0 && Data.GetFlag(prevOffset) == Data.FlagType.Opcode) + while (prevOffset >= 0 && Data.Inst.GetFlag(prevOffset) == Data.FlagType.Operand) prevOffset--; + if (prevOffset >= 0 && Data.Inst.GetFlag(prevOffset) == Data.FlagType.Opcode) { - prevDirectPage = Data.GetDirectPage(prevOffset); - prevDataBank = Data.GetDataBank(prevOffset); - prevX = Data.GetXFlag(prevOffset); - prevM = Data.GetMFlag(prevOffset); + prevDirectPage = Data.Inst.GetDirectPage(prevOffset); + prevDataBank = Data.Inst.GetDataBank(prevOffset); + prevX = Data.Inst.GetXFlag(prevOffset); + prevM = Data.Inst.GetMFlag(prevOffset); } if (opcode == 0xC2 || opcode == 0xE2) // REP SEP { - prevX = (Data.GetROMByte(offset + 1) & 0x10) != 0 ? opcode == 0xE2 : prevX; - prevM = (Data.GetROMByte(offset + 1) & 0x20) != 0 ? opcode == 0xE2 : prevM; + prevX = (Data.Inst.GetROMByte(offset + 1) & 0x10) != 0 ? opcode == 0xE2 : prevX; + prevM = (Data.Inst.GetROMByte(offset + 1) & 0x20) != 0 ? opcode == 0xE2 : prevM; } // set first byte first, so the instruction length is correct - Data.SetFlag(offset, Data.FlagType.Opcode); - Data.SetDataBank(offset, prevDataBank); - Data.SetDirectPage(offset, prevDirectPage); - Data.SetXFlag(offset, prevX); - Data.SetMFlag(offset, prevM); + Data.Inst.SetFlag(offset, Data.FlagType.Opcode); + Data.Inst.SetDataBank(offset, prevDataBank); + Data.Inst.SetDirectPage(offset, prevDirectPage); + Data.Inst.SetXFlag(offset, prevX); + Data.Inst.SetMFlag(offset, prevM); int length = GetInstructionLength(offset); for (int i = 1; i < length; i++) { - Data.SetFlag(offset + i, Data.FlagType.Operand); - Data.SetDataBank(offset + i, prevDataBank); - Data.SetDirectPage(offset + i, prevDirectPage); - Data.SetXFlag(offset + i, prevX); - Data.SetMFlag(offset + i, prevM); + Data.Inst.SetFlag(offset + i, Data.FlagType.Operand); + Data.Inst.SetDataBank(offset + i, prevDataBank); + Data.Inst.SetDirectPage(offset + i, prevDirectPage); + Data.Inst.SetXFlag(offset + i, prevX); + Data.Inst.SetMFlag(offset + i, prevM); } MarkInOutPoints(offset); @@ -67,7 +67,7 @@ public static int Step(int offset, bool branch, bool force, int prevOffset) public static int GetIntermediateAddress(int offset, bool resolve) { int bank, directPage, operand, programCounter; - int opcode = Data.GetROMByte(offset); + int opcode = Data.Inst.GetROMByte(offset); AddressMode mode = GetAddressMode(offset); switch (mode) @@ -82,8 +82,8 @@ public static int GetIntermediateAddress(int offset, bool resolve) case AddressMode.DIRECT_PAGE_LONG_INDIRECT_Y_INDEX: if (resolve) { - directPage = Data.GetDirectPage(offset); - operand = Data.GetROMByte(offset + 1); + directPage = Data.Inst.GetDirectPage(offset); + operand = Data.Inst.GetROMByte(offset + 1); return (directPage + operand) & 0xFFFF; } else @@ -92,14 +92,14 @@ public static int GetIntermediateAddress(int offset, bool resolve) } case AddressMode.DIRECT_PAGE_S_INDEX: case AddressMode.DIRECT_PAGE_S_INDEX_INDIRECT_Y_INDEX: - return Data.GetROMByte(offset + 1); + return Data.Inst.GetROMByte(offset + 1); case AddressMode.ADDRESS: case AddressMode.ADDRESS_X_INDEX: case AddressMode.ADDRESS_Y_INDEX: case AddressMode.ADDRESS_X_INDEX_INDIRECT: bank = (opcode == 0x20 || opcode == 0x4C || opcode == 0x7C || opcode == 0xFC) ? Util.ConvertPCtoSNES(offset) >> 16 : - Data.GetDataBank(offset); + Data.Inst.GetDataBank(offset); operand = Util.GetROMWord(offset + 1); return (bank << 16) | operand; case AddressMode.ADDRESS_INDIRECT: @@ -113,7 +113,7 @@ public static int GetIntermediateAddress(int offset, bool resolve) case AddressMode.RELATIVE_8: programCounter = Util.ConvertPCtoSNES(offset + 2); bank = programCounter >> 16; - offset = (sbyte)Data.GetROMByte(offset + 1); + offset = (sbyte)Data.Inst.GetROMByte(offset + 1); return (bank << 16) | ((programCounter + offset) & 0xFFFF); case AddressMode.RELATIVE_16: programCounter = Util.ConvertPCtoSNES(offset + 3); @@ -132,12 +132,12 @@ public static string GetInstruction(int offset) string op1 = "", op2 = ""; if (mode == AddressMode.BLOCK_MOVE) { - op1 = Util.NumberToBaseString(Data.GetROMByte(offset + 1), Util.NumberBase.Hexadecimal, 2, true); - op2 = Util.NumberToBaseString(Data.GetROMByte(offset + 2), Util.NumberBase.Hexadecimal, 2, true); + op1 = Util.NumberToBaseString(Data.Inst.GetROMByte(offset + 1), Util.NumberBase.Hexadecimal, 2, true); + op2 = Util.NumberToBaseString(Data.Inst.GetROMByte(offset + 2), Util.NumberBase.Hexadecimal, 2, true); } else if (mode == AddressMode.CONSTANT_8 || mode == AddressMode.IMMEDIATE_8) { - op1 = Util.NumberToBaseString(Data.GetROMByte(offset + 1), Util.NumberBase.Hexadecimal, 2, true); + op1 = Util.NumberToBaseString(Data.Inst.GetROMByte(offset + 1), Util.NumberBase.Hexadecimal, 2, true); } else if (mode == AddressMode.IMMEDIATE_16) { @@ -194,7 +194,7 @@ public static int GetInstructionLength(int offset) public static void MarkInOutPoints(int offset) { - int opcode = Data.GetROMByte(offset); + int opcode = Data.Inst.GetROMByte(offset); int iaOffsetPC = Util.ConvertSNEStoPC(Util.GetIntermediateAddress(offset, true)); // set read point on EA @@ -203,13 +203,13 @@ public static void MarkInOutPoints(int offset) ((opcode & 0x1F) == 0x12) || ((opcode & 0x1F) == 0x19)) && (opcode != 0x45) && (opcode != 0x55) && (opcode != 0xF5) && (opcode != 0x4C) && (opcode != 0x5C) && (opcode != 0x6C) && (opcode != 0x7C) && (opcode != 0xDC) && (opcode != 0xFC) - ) Data.SetInOutPoint(iaOffsetPC, Data.InOutPoint.ReadPoint); + ) Data.Inst.SetInOutPoint(iaOffsetPC, Data.InOutPoint.ReadPoint); // set end point on offset if (opcode == 0x40 || opcode == 0x4C || opcode == 0x5C || opcode == 0x60 // RTI JMP JML RTS || opcode == 0x6B || opcode == 0x6C || opcode == 0x7C || opcode == 0x80 // RTL JMP JMP BRA || opcode == 0x82 || opcode == 0xDB || opcode == 0xDC // BRL STP JML - ) Data.SetInOutPoint(offset, Data.InOutPoint.EndPoint); + ) Data.Inst.SetInOutPoint(offset, Data.InOutPoint.EndPoint); // set out point on offset // set in point on EA @@ -219,8 +219,8 @@ public static void MarkInOutPoints(int offset) || opcode == 0x90 || opcode == 0xB0 || opcode == 0xD0 || opcode == 0xF0 // BCC BCS BNE BEQ || opcode == 0x20 || opcode == 0x22)) // JSR JSL { - Data.SetInOutPoint(offset, Data.InOutPoint.OutPoint); - Data.SetInOutPoint(iaOffsetPC, Data.InOutPoint.InPoint); + Data.Inst.SetInOutPoint(offset, Data.InOutPoint.OutPoint); + Data.Inst.SetInOutPoint(iaOffsetPC, Data.InOutPoint.InPoint); } } @@ -228,7 +228,7 @@ private static string FormatOperandAddress(int offset, AddressMode mode) { int address = Util.GetIntermediateAddress(offset); if (address < 0) return ""; - if (Data.GetLabelName(address) != "") return Data.GetLabelName(address); + if (Data.Inst.GetLabelName(address) != "") return Data.Inst.GetLabelName(address); int count = BytesToShow(mode); if (mode == AddressMode.RELATIVE_8 || mode == AddressMode.RELATIVE_16) address = Util.GetROMWord(offset + 1); @@ -238,7 +238,7 @@ private static string FormatOperandAddress(int offset, AddressMode mode) private static string GetMnemonic(int offset, bool showHint = true) { - string mn = mnemonics[Data.GetROMByte(offset)]; + string mn = mnemonics[Data.Inst.GetROMByte(offset)]; if (showHint) { AddressMode mode = GetAddressMode(offset); @@ -344,9 +344,9 @@ private static string GetInstructionFormatString(int offset) private static AddressMode GetAddressMode(int offset) { - AddressMode mode = addressingModes[Data.GetROMByte(offset)]; - if (mode == AddressMode.IMMEDIATE_M_FLAG_DEPENDENT) return Data.GetMFlag(offset) ? AddressMode.IMMEDIATE_8 : AddressMode.IMMEDIATE_16; - else if (mode == AddressMode.IMMEDIATE_X_FLAG_DEPENDENT) return Data.GetXFlag(offset) ? AddressMode.IMMEDIATE_8 : AddressMode.IMMEDIATE_16; + AddressMode mode = addressingModes[Data.Inst.GetROMByte(offset)]; + if (mode == AddressMode.IMMEDIATE_M_FLAG_DEPENDENT) return Data.Inst.GetMFlag(offset) ? AddressMode.IMMEDIATE_8 : AddressMode.IMMEDIATE_16; + else if (mode == AddressMode.IMMEDIATE_X_FLAG_DEPENDENT) return Data.Inst.GetXFlag(offset) ? AddressMode.IMMEDIATE_8 : AddressMode.IMMEDIATE_16; return mode; } diff --git a/DiztinGUIsh/static/diz/Manager.cs b/DiztinGUIsh/static/diz/Manager.cs index 792fe1bf..2e18ee45 100644 --- a/DiztinGUIsh/static/diz/Manager.cs +++ b/DiztinGUIsh/static/diz/Manager.cs @@ -9,7 +9,7 @@ public class Manager public static int Step(int offset, bool branch, bool force, int prevOffset) { Project.unsavedChanges = true; - switch (Data.GetArchitechture(offset)) + switch (Data.Inst.GetArchitechture(offset)) { case Data.Architechture.CPU65C816: return CPU65C816.Step(offset, branch, force, prevOffset); case Data.Architechture.APUSPC700: return offset; @@ -38,7 +38,7 @@ public static int AutoStep(int offset, bool harsh, int amount) while (keepGoing) { - switch (Data.GetArchitechture(newOffset)) + switch (Data.Inst.GetArchitechture(newOffset)) { case Data.Architechture.CPU65C816: if (seenBranches.Contains(newOffset)) @@ -47,7 +47,7 @@ public static int AutoStep(int offset, bool harsh, int amount) break; } - int opcode = Data.GetROMByte(newOffset); + int opcode = Data.Inst.GetROMByte(newOffset); nextOffset = Step(newOffset, false, false, prevOffset); int jumpOffset = Step(newOffset, true, false, prevOffset); @@ -64,7 +64,7 @@ public static int AutoStep(int offset, bool harsh, int amount) if (opcode == 0x08) // PHP { - stack.Push(Data.GetMXFlags(newOffset)); + stack.Push(Data.Inst.GetMXFlags(newOffset)); } else if (opcode == 0x28) // PLP { if (stack.Count == 0) @@ -72,7 +72,7 @@ public static int AutoStep(int offset, bool harsh, int amount) keepGoing = false; break; } else { - Data.SetMXFlags(newOffset, stack.Pop()); + Data.Inst.SetMXFlags(newOffset, stack.Pop()); } } @@ -107,7 +107,7 @@ public static int AutoStep(int offset, bool harsh, int amount) break; } - Data.FlagType flag = Data.GetFlag(newOffset); + Data.FlagType flag = Data.Inst.GetFlag(newOffset); if (!(flag == Data.FlagType.Unreached || flag == Data.FlagType.Opcode || flag == Data.FlagType.Operand)) keepGoing = false; } } @@ -117,54 +117,54 @@ public static int AutoStep(int offset, bool harsh, int amount) public static int Mark(int offset, Data.FlagType type, int count) { Project.unsavedChanges = true; - int i, size = Data.GetROMSize(); - for (i = 0; i < count && offset + i < size; i++) Data.SetFlag(offset + i, type); + int i, size = Data.Inst.GetROMSize(); + for (i = 0; i < count && offset + i < size; i++) Data.Inst.SetFlag(offset + i, type); return offset + i < size ? offset + i : size - 1; } public static int MarkDataBank(int offset, int db, int count) { Project.unsavedChanges = true; - int i, size = Data.GetROMSize(); - for (i = 0; i < count && offset + i < size; i++) Data.SetDataBank(offset + i, db); + int i, size = Data.Inst.GetROMSize(); + for (i = 0; i < count && offset + i < size; i++) Data.Inst.SetDataBank(offset + i, db); return offset + i < size ? offset + i : size - 1; } public static int MarkDirectPage(int offset, int dp, int count) { Project.unsavedChanges = true; - int i, size = Data.GetROMSize(); - for (i = 0; i < count && offset + i < size; i++) Data.SetDirectPage(offset + i, dp); + int i, size = Data.Inst.GetROMSize(); + for (i = 0; i < count && offset + i < size; i++) Data.Inst.SetDirectPage(offset + i, dp); return offset + i < size ? offset + i : size - 1; } public static int MarkXFlag(int offset, bool x, int count) { Project.unsavedChanges = true; - int i, size = Data.GetROMSize(); - for (i = 0; i < count && offset + i < size; i++) Data.SetXFlag(offset + i, x); + int i, size = Data.Inst.GetROMSize(); + for (i = 0; i < count && offset + i < size; i++) Data.Inst.SetXFlag(offset + i, x); return offset + i < size ? offset + i : size - 1; } public static int MarkMFlag(int offset, bool m, int count) { Project.unsavedChanges = true; - int i, size = Data.GetROMSize(); - for (i = 0; i < count && offset + i < size; i++) Data.SetMFlag(offset + i, m); + int i, size = Data.Inst.GetROMSize(); + for (i = 0; i < count && offset + i < size; i++) Data.Inst.SetMFlag(offset + i, m); return offset + i < size ? offset + i : size - 1; } public static int MarkArchitechture(int offset, Data.Architechture arch, int count) { Project.unsavedChanges = true; - int i, size = Data.GetROMSize(); - for (i = 0; i < count && offset + i < size; i++) Data.SetArchitechture(offset + i, arch); + int i, size = Data.Inst.GetROMSize(); + for (i = 0; i < count && offset + i < size; i++) Data.Inst.SetArchitechture(offset + i, arch); return offset + i < size ? offset + i : size - 1; } public static int GetInstructionLength(int offset) { - switch (Data.GetArchitechture(offset)) + switch (Data.Inst.GetArchitechture(offset)) { case Data.Architechture.CPU65C816: return CPU65C816.GetInstructionLength(offset); case Data.Architechture.APUSPC700: return 1; @@ -175,27 +175,27 @@ public static int GetInstructionLength(int offset) public static int FixMisalignedFlags() { - int count = 0, size = Data.GetROMSize(); + int count = 0, size = Data.Inst.GetROMSize(); for (int i = 0; i < size; i++) { - Data.FlagType flag = Data.GetFlag(i); + Data.FlagType flag = Data.Inst.GetFlag(i); if (flag == Data.FlagType.Opcode) { int len = GetInstructionLength(i); for (int j = 1; j < len && i + j < size; j++) { - if (Data.GetFlag(i + j) != Data.FlagType.Operand) + if (Data.Inst.GetFlag(i + j) != Data.FlagType.Operand) { - Data.SetFlag(i + j, Data.FlagType.Operand); + Data.Inst.SetFlag(i + j, Data.FlagType.Operand); count++; } } i += len - 1; } else if (flag == Data.FlagType.Operand) { - Data.SetFlag(i, Data.FlagType.Opcode); + Data.Inst.SetFlag(i, Data.FlagType.Opcode); count++; i--; } else if (Util.TypeStepSize(flag) > 1) @@ -203,9 +203,9 @@ public static int FixMisalignedFlags() int step = Util.TypeStepSize(flag); for (int j = 1; j < step; j++) { - if (Data.GetFlag(i + j) != flag) + if (Data.Inst.GetFlag(i + j) != flag) { - Data.SetFlag(i + j, flag); + Data.Inst.SetFlag(i + j, flag); count++; } } @@ -220,13 +220,13 @@ public static int FixMisalignedFlags() public static void RescanInOutPoints() { - for (int i = 0; i < Data.GetROMSize(); i++) Data.ClearInOutPoint(i); + for (int i = 0; i < Data.Inst.GetROMSize(); i++) Data.Inst.ClearInOutPoint(i); - for (int i = 0; i < Data.GetROMSize(); i++) + for (int i = 0; i < Data.Inst.GetROMSize(); i++) { - if (Data.GetFlag(i) == Data.FlagType.Opcode) + if (Data.Inst.GetFlag(i) == Data.FlagType.Opcode) { - switch (Data.GetArchitechture(i)) + switch (Data.Inst.GetArchitechture(i)) { case Data.Architechture.CPU65C816: CPU65C816.MarkInOutPoints(i); break; case Data.Architechture.APUSPC700: break; @@ -240,7 +240,7 @@ public static void RescanInOutPoints() public static int ImportUsageMap(byte[] usageMap) { - int size = Data.GetROMSize(); + int size = Data.Inst.GetROMSize(); bool unsaved = false; int modified = 0; int prevFlags = 0; @@ -263,7 +263,7 @@ public static int ImportUsageMap(byte[] usageMap) continue; } - if (Data.GetFlag(i) != Data.FlagType.Unreached) + if (Data.Inst.GetFlag(i) != Data.FlagType.Unreached) { // skip if there is something already set.. continue; @@ -272,21 +272,21 @@ public static int ImportUsageMap(byte[] usageMap) // opcode: 0x30, operand: 0x20 if (flags.HasFlag(Data.BsnesPlusUsage.UsageExec)) { - Data.SetFlag(i, Data.FlagType.Operand); + Data.Inst.SetFlag(i, Data.FlagType.Operand); if (flags.HasFlag(Data.BsnesPlusUsage.UsageOpcode)) { prevFlags = ((int)flags & 3) << 4; - Data.SetFlag(i, Data.FlagType.Opcode); + Data.Inst.SetFlag(i, Data.FlagType.Opcode); } - Data.SetMXFlags(i, prevFlags); + Data.Inst.SetMXFlags(i, prevFlags); unsaved = true; modified++; } else if (flags.HasFlag(Data.BsnesPlusUsage.UsageRead)) { - Data.SetFlag(i, Data.FlagType.Data8Bit); + Data.Inst.SetFlag(i, Data.FlagType.Data8Bit); unsaved = true; modified++; } @@ -367,20 +367,20 @@ int GetHexValueAt(int startIndex, int length) { // 'M' = unchecked in bsnesplus debugger UI = (8bit), 'm' or '.' = checked (16bit) bool mflag_set = line[CachedIdx.f_M] == 'M'; - Data.SetFlag(pc, Data.FlagType.Opcode); + Data.Inst.SetFlag(pc, Data.FlagType.Opcode); int modified = 0; - int size = Data.GetROMSize(); + int size = Data.Inst.GetROMSize(); do { - Data.SetDataBank(pc, dataBank); - Data.SetDirectPage(pc, directPage); - Data.SetXFlag(pc, xflag_set); - Data.SetMFlag(pc, mflag_set); + Data.Inst.SetDataBank(pc, dataBank); + Data.Inst.SetDirectPage(pc, directPage); + Data.Inst.SetXFlag(pc, xflag_set); + Data.Inst.SetMFlag(pc, mflag_set); pc++; modified++; - } while (pc < size && Data.GetFlag(pc) == Data.FlagType.Operand); + } while (pc < size && Data.Inst.GetFlag(pc) == Data.FlagType.Operand); Project.unsavedChanges = true; return modified; } @@ -392,7 +392,7 @@ public static void ImportBizHawkCDL(BizHawkCdl cdl) throw new InvalidDataException("The CDL file does not contain CARTROM block."); } - var size = Math.Min(cdlRomFlags.Count, Data.GetROMSize()); + var size = Math.Min(cdlRomFlags.Count, Data.Inst.GetROMSize()); bool m = false; bool x = false; for (var offset = 0; offset < size; offset++) diff --git a/DiztinGUIsh/window/AliasList.cs b/DiztinGUIsh/window/AliasList.cs index 1d5c802a..d601fa06 100644 --- a/DiztinGUIsh/window/AliasList.cs +++ b/DiztinGUIsh/window/AliasList.cs @@ -113,14 +113,14 @@ private void ImportLabelsFromCSV(bool replaceAll) // everything read OK, modify the existing list now. point of no return if (replaceAll) - Data.DeleteAllLabels(); + Data.Inst.DeleteAllLabels(); ResetDataGrid(); // this will call AddRow() to add items back to the UI datagrid. foreach (KeyValuePair pair in newValues) { - Data.AddLabel(pair.Key, pair.Value, true); + Data.Inst.AddLabel(pair.Key, pair.Value, true); } } catch (Exception ex) @@ -141,7 +141,7 @@ private void export_Click(object sender, EventArgs e) { using (StreamWriter sw = new StreamWriter(saveFileDialog1.FileName)) { - foreach (var pair in Data.GetAllLabels()) + foreach (var pair in Data.Inst.GetAllLabels()) { sw.WriteLine( $"{Util.NumberToBaseString(pair.Key, Util.NumberBase.Hexadecimal, 6)},{pair.Value.name},{pair.Value.comment}"); @@ -159,7 +159,7 @@ private void dataGridView1_UserDeletingRow(object sender, DataGridViewRowCancelE if (int.TryParse((string)dataGridView1.Rows[e.Row.Index].Cells[0].Value, NumberStyles.HexNumber, null, out int val)) { locked = true; - Data.AddLabel(val, null, true); + Data.Inst.AddLabel(val, null, true); locked = false; mw.InvalidateTable(); } @@ -198,11 +198,11 @@ private void dataGridView1_CellValidating(object sender, DataGridViewCellValidat { e.Cancel = true; toolStripStatusLabel1.Text = "Must enter a valid hex address."; - } else if (oldAddress == -1 && Data.GetAllLabels().ContainsKey(val)) + } else if (oldAddress == -1 && Data.Inst.GetAllLabels().ContainsKey(val)) { e.Cancel = true; toolStripStatusLabel1.Text = "This address already has a label."; - var x = Data.GetAllLabels(); + var x = Data.Inst.GetAllLabels(); Console.WriteLine(Util.NumberToBaseString(val, Util.NumberBase.Hexadecimal)); } else if (dataGridView1.EditingControl != null) { @@ -229,8 +229,8 @@ private void dataGridView1_CellValidating(object sender, DataGridViewCellValidat locked = true; if (currentlyEditing >= 0) { - if (val >= 0) Data.AddLabel(oldAddress, null, true); - Data.AddLabel(val, labelAliasInfo, true); + if (val >= 0) Data.Inst.AddLabel(oldAddress, null, true); + Data.Inst.AddLabel(val, labelAliasInfo, true); } locked = false; diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 5363f33e..155be20b 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -335,9 +335,9 @@ private void UpdateBase(Util.NumberBase noBase) public void UpdatePercent() { - int totalUnreached = 0, size = Data.GetROMSize(); + int totalUnreached = 0, size = Data.Inst.GetROMSize(); for (int i = 0; i < size; i++) - if (Data.GetFlag(i) == Data.FlagType.Unreached) + if (Data.Inst.GetFlag(i) == Data.FlagType.Unreached) totalUnreached++; int reached = size - totalUnreached; percentComplete.Text = string.Format("{0:N3}% ({1:D}/{2:D})", reached * 100.0 / size, reached, size); @@ -360,13 +360,13 @@ public void InvalidateTable() private void UpdateDataGridView() { - if (Data.GetROMSize() > 0) + if (Data.Inst.GetROMSize() > 0) { rowsToShow = ((table.Height - table.ColumnHeadersHeight) / table.RowTemplate.Height); - if (viewOffset + rowsToShow > Data.GetROMSize()) viewOffset = Data.GetROMSize() - rowsToShow; + if (viewOffset + rowsToShow > Data.Inst.GetROMSize()) viewOffset = Data.Inst.GetROMSize() - rowsToShow; if (viewOffset < 0) viewOffset = 0; vScrollBar1.Enabled = true; - vScrollBar1.Maximum = Data.GetROMSize() - rowsToShow; + vScrollBar1.Maximum = Data.Inst.GetROMSize() - rowsToShow; vScrollBar1.Value = viewOffset; table.RowCount = rowsToShow; @@ -377,7 +377,7 @@ private void UpdateDataGridView() private void table_MouseWheel(object sender, MouseEventArgs e) { - if (Data.GetROMSize() <= 0) return; + if (Data.Inst.GetROMSize() <= 0) return; int selRow = table.CurrentCell.RowIndex + viewOffset, selCol = table.CurrentCell.ColumnIndex; int amount = e.Delta / 0x18; viewOffset -= amount; @@ -409,7 +409,7 @@ private void table_MouseDown(object sender, MouseEventArgs e) private void table_KeyDown(object sender, KeyEventArgs e) { - if (Data.GetROMSize() <= 0) return; + if (Data.Inst.GetROMSize() <= 0) return; int offset = table.CurrentCell.RowIndex + viewOffset; int newOffset = offset; @@ -431,7 +431,7 @@ private void table_KeyDown(object sender, KeyEventArgs e) case Keys.Down: amount = e.KeyCode == Keys.Down ? 0x01 : e.KeyCode == Keys.PageDown ? 0x10 : 0x100; newOffset = offset + amount; - if (newOffset >= Data.GetROMSize()) newOffset = Data.GetROMSize() - 1; + if (newOffset >= Data.Inst.GetROMSize()) newOffset = Data.Inst.GetROMSize() - 1; SelectOffset(newOffset); break; case Keys.Left: @@ -481,10 +481,10 @@ private void table_KeyDown(object sender, KeyEventArgs e) table.BeginEdit(true); break; case Keys.M: - Data.SetMFlag(offset, !Data.GetMFlag(offset)); + Data.Inst.SetMFlag(offset, !Data.Inst.GetMFlag(offset)); break; case Keys.X: - Data.SetXFlag(offset, !Data.GetXFlag(offset)); + Data.Inst.SetXFlag(offset, !Data.Inst.GetXFlag(offset)); break; case Keys.C: table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[12]; @@ -499,27 +499,27 @@ private void table_KeyDown(object sender, KeyEventArgs e) private void table_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) { int row = e.RowIndex + viewOffset; - if (row >= Data.GetROMSize()) return; + if (row >= Data.Inst.GetROMSize()) return; switch (e.ColumnIndex) { case 0: - e.Value = Data.GetLabelName(Util.ConvertPCtoSNES(row)); + e.Value = Data.Inst.GetLabelName(Util.ConvertPCtoSNES(row)); break; case 1: e.Value = Util.NumberToBaseString(Util.ConvertPCtoSNES(row), Util.NumberBase.Hexadecimal, 6); break; case 2: - e.Value = (char) Data.GetROMByte(row); + e.Value = (char) Data.Inst.GetROMByte(row); break; case 3: - e.Value = Util.NumberToBaseString(Data.GetROMByte(row), DisplayBase); + e.Value = Util.NumberToBaseString(Data.Inst.GetROMByte(row), DisplayBase); break; case 4: - e.Value = Util.PointToString(Data.GetInOutPoint(row)); + e.Value = Util.PointToString(Data.Inst.GetInOutPoint(row)); break; case 5: int len = Manager.GetInstructionLength(row); - if (row + len <= Data.GetROMSize()) e.Value = Util.GetInstruction(row); + if (row + len <= Data.Inst.GetROMSize()) e.Value = Util.GetInstruction(row); else e.Value = ""; break; case 6: @@ -528,22 +528,22 @@ private void table_CellValueNeeded(object sender, DataGridViewCellValueEventArgs else e.Value = ""; break; case 7: - e.Value = Util.TypeToString(Data.GetFlag(row)); + e.Value = Util.TypeToString(Data.Inst.GetFlag(row)); break; case 8: - e.Value = Util.NumberToBaseString(Data.GetDataBank(row), Util.NumberBase.Hexadecimal, 2); + e.Value = Util.NumberToBaseString(Data.Inst.GetDataBank(row), Util.NumberBase.Hexadecimal, 2); break; case 9: - e.Value = Util.NumberToBaseString(Data.GetDirectPage(row), Util.NumberBase.Hexadecimal, 4); + e.Value = Util.NumberToBaseString(Data.Inst.GetDirectPage(row), Util.NumberBase.Hexadecimal, 4); break; case 10: - e.Value = Util.BoolToSize(Data.GetMFlag(row)); + e.Value = Util.BoolToSize(Data.Inst.GetMFlag(row)); break; case 11: - e.Value = Util.BoolToSize(Data.GetXFlag(row)); + e.Value = Util.BoolToSize(Data.Inst.GetXFlag(row)); break; case 12: - e.Value = Data.GetComment(Util.ConvertPCtoSNES(row)); + e.Value = Data.Inst.GetComment(Util.ConvertPCtoSNES(row)); break; } } @@ -553,26 +553,26 @@ private void table_CellValuePushed(object sender, DataGridViewCellValueEventArgs string value = e.Value as string; int result; int row = e.RowIndex + viewOffset; - if (row >= Data.GetROMSize()) return; + if (row >= Data.Inst.GetROMSize()) return; switch (e.ColumnIndex) { case 0: - Data.AddLabel(Util.ConvertPCtoSNES(row), new Data.AliasInfo() {name = value}, true); + Data.Inst.AddLabel(Util.ConvertPCtoSNES(row), new Data.AliasInfo() {name = value}, true); break; // todo (validate for valid label characters) case 8: - if (int.TryParse(value, NumberStyles.HexNumber, null, out result)) Data.SetDataBank(row, result); + if (int.TryParse(value, NumberStyles.HexNumber, null, out result)) Data.Inst.SetDataBank(row, result); break; case 9: - if (int.TryParse(value, NumberStyles.HexNumber, null, out result)) Data.SetDirectPage(row, result); + if (int.TryParse(value, NumberStyles.HexNumber, null, out result)) Data.Inst.SetDirectPage(row, result); break; case 10: - Data.SetMFlag(row, (value == "8" || value == "M")); + Data.Inst.SetMFlag(row, (value == "8" || value == "M")); break; case 11: - Data.SetXFlag(row, (value == "8" || value == "X")); + Data.Inst.SetXFlag(row, (value == "8" || value == "X")); break; case 12: - Data.AddComment(Util.ConvertPCtoSNES(row), value, true); + Data.Inst.AddComment(Util.ConvertPCtoSNES(row), value, true); break; } @@ -582,7 +582,7 @@ private void table_CellValuePushed(object sender, DataGridViewCellValueEventArgs private void table_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) { int row = e.RowIndex + viewOffset; - if (row < 0 || row >= Data.GetROMSize()) return; + if (row < 0 || row >= Data.Inst.GetROMSize()) return; Util.PaintCell(row, e.CellStyle, e.ColumnIndex, table.CurrentCell.RowIndex + viewOffset); } @@ -703,25 +703,25 @@ private void GoToIntermediateAddress(int offset) private void GoToUnreached(bool end, bool direction) { int offset = table.CurrentCell.RowIndex + viewOffset; - int size = Data.GetROMSize(); + int size = Data.Inst.GetROMSize(); int unreached = end ? (direction ? 0 : size - 1) : offset; if (direction) { if (!end) - while (unreached < size - 1 && Data.GetFlag(unreached) == Data.FlagType.Unreached) + while (unreached < size - 1 && Data.Inst.GetFlag(unreached) == Data.FlagType.Unreached) unreached++; - while (unreached < size - 1 && Data.GetFlag(unreached) != Data.FlagType.Unreached) unreached++; + while (unreached < size - 1 && Data.Inst.GetFlag(unreached) != Data.FlagType.Unreached) unreached++; } else { if (unreached > 0) unreached--; - while (unreached > 0 && Data.GetFlag(unreached) != Data.FlagType.Unreached) unreached--; + while (unreached > 0 && Data.Inst.GetFlag(unreached) != Data.FlagType.Unreached) unreached--; } - while (unreached > 0 && Data.GetFlag(unreached - 1) == Data.FlagType.Unreached) unreached--; + while (unreached > 0 && Data.Inst.GetFlag(unreached - 1) == Data.FlagType.Unreached) unreached--; - if (Data.GetFlag(unreached) == Data.FlagType.Unreached) SelectOffset(unreached, 1); + if (Data.Inst.GetFlag(unreached) == Data.FlagType.Unreached) SelectOffset(unreached, 1); } private void visualMapToolStripMenuItem_Click(object sender, EventArgs e) @@ -738,37 +738,37 @@ private void graphicsWindowToolStripMenuItem_Click(object sender, EventArgs e) private void stepOverToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.GetROMSize() <= 0) return; + if (Data.Inst.GetROMSize() <= 0) return; Step(table.CurrentCell.RowIndex + viewOffset); } private void stepInToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.GetROMSize() <= 0) return; + if (Data.Inst.GetROMSize() <= 0) return; StepIn(table.CurrentCell.RowIndex + viewOffset); } private void autoStepSafeToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.GetROMSize() <= 0) return; + if (Data.Inst.GetROMSize() <= 0) return; AutoStepSafe(table.CurrentCell.RowIndex + viewOffset); } private void autoStepHarshToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.GetROMSize() <= 0) return; + if (Data.Inst.GetROMSize() <= 0) return; AutoStepHarsh(table.CurrentCell.RowIndex + viewOffset); } private void gotoToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.GetROMSize() <= 0) return; + if (Data.Inst.GetROMSize() <= 0) return; GotoDialog go = new GotoDialog(viewOffset + table.CurrentCell.RowIndex); DialogResult result = go.ShowDialog(); if (result == DialogResult.OK) { int offset = go.GetPcOffset(); - if (offset >= 0 && offset < Data.GetROMSize()) SelectOffset(offset); + if (offset >= 0 && offset < Data.Inst.GetROMSize()) SelectOffset(offset); else MessageBox.Show("That offset is out of range.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); @@ -777,7 +777,7 @@ private void gotoToolStripMenuItem_Click(object sender, EventArgs e) private void gotoIntermediateAddressToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.GetROMSize() <= 0) return; + if (Data.Inst.GetROMSize() <= 0) return; GoToIntermediateAddress(table.CurrentCell.RowIndex + viewOffset); } @@ -798,13 +798,13 @@ private void gotoNextUnreachedToolStripMenuItem_Click(object sender, EventArgs e private void markOneToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.GetROMSize() <= 0) return; + if (Data.Inst.GetROMSize() <= 0) return; Mark(table.CurrentCell.RowIndex + viewOffset); } private void markManyToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.GetROMSize() <= 0) return; + if (Data.Inst.GetROMSize() <= 0) return; MarkMany(table.CurrentCell.RowIndex + viewOffset, 7); } @@ -816,25 +816,25 @@ private void addLabelToolStripMenuItem_Click(object sender, EventArgs e) private void setDataBankToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.GetROMSize() <= 0) return; + if (Data.Inst.GetROMSize() <= 0) return; MarkMany(table.CurrentCell.RowIndex + viewOffset, 8); } private void setDirectPageToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.GetROMSize() <= 0) return; + if (Data.Inst.GetROMSize() <= 0) return; MarkMany(table.CurrentCell.RowIndex + viewOffset, 9); } private void toggleAccumulatorSizeMToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.GetROMSize() <= 0) return; + if (Data.Inst.GetROMSize() <= 0) return; MarkMany(table.CurrentCell.RowIndex + viewOffset, 10); } private void toggleIndexSizeToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.GetROMSize() <= 0) return; + if (Data.Inst.GetROMSize() <= 0) return; MarkMany(table.CurrentCell.RowIndex + viewOffset, 11); } @@ -846,7 +846,7 @@ private void addCommentToolStripMenuItem_Click(object sender, EventArgs e) private void fixMisalignedInstructionsToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.GetROMSize() <= 0) return; + if (Data.Inst.GetROMSize() <= 0) return; MisalignmentChecker mis = new MisalignmentChecker(); DialogResult result = mis.ShowDialog(); if (result == DialogResult.OK) @@ -860,7 +860,7 @@ private void fixMisalignedInstructionsToolStripMenuItem_Click(object sender, Eve private void rescanForInOutPointsToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.GetROMSize() <= 0) return; + if (Data.Inst.GetROMSize() <= 0) return; InOutPointChecker point = new InOutPointChecker(); DialogResult result = point.ShowDialog(); if (result == DialogResult.OK) diff --git a/DiztinGUIsh/window/dialog/ExportDisassembly.cs b/DiztinGUIsh/window/dialog/ExportDisassembly.cs index 76c24af6..6fa7d5db 100644 --- a/DiztinGUIsh/window/dialog/ExportDisassembly.cs +++ b/DiztinGUIsh/window/dialog/ExportDisassembly.cs @@ -98,18 +98,18 @@ private void UpdateSample() using (MemoryStream mem = new MemoryStream()) using (StreamWriter sw = new StreamWriter(mem)) { - List tempTable = Data.GetTable(); - Data.ROMMapMode tempMode = Data.GetROMMapMode(); - Data.ROMSpeed tempSpeed = Data.GetROMSpeed(); - var tempAlias = Data.GetAllLabels(); - var tempComment = Data.GetAllComments(); + List tempTable = Data.Inst.GetTable(); + Data.ROMMapMode tempMode = Data.Inst.GetROMMapMode(); + Data.ROMSpeed tempSpeed = Data.Inst.GetROMSpeed(); + var tempAlias = Data.Inst.GetAllLabels(); + var tempComment = Data.Inst.GetAllComments(); LogCreator.FormatStructure tempStructure = LogCreator.structure; - Data.Restore(sampleTable, Data.ROMMapMode.LoROM, Data.ROMSpeed.FastROM, sampleAlias, sampleComment); + Data.Inst.Restore(sampleTable, Data.ROMMapMode.LoROM, Data.ROMSpeed.FastROM, sampleAlias, sampleComment); LogCreator.structure = LogCreator.FormatStructure.SingleFile; LogCreator.CreateLog(sw, StreamWriter.Null); - Data.Restore(tempTable, tempMode, tempSpeed, tempAlias, tempComment); + Data.Inst.Restore(tempTable, tempMode, tempSpeed, tempAlias, tempComment); LogCreator.structure = tempStructure; sw.Flush(); diff --git a/DiztinGUIsh/window/dialog/GotoDialog.cs b/DiztinGUIsh/window/dialog/GotoDialog.cs index 6645b779..9f22e03b 100644 --- a/DiztinGUIsh/window/dialog/GotoDialog.cs +++ b/DiztinGUIsh/window/dialog/GotoDialog.cs @@ -92,7 +92,7 @@ private void UpdateUI() private bool IsValidPCAddress(int pc) { - return pc >= 0 && pc < Data.GetROMSize(); + return pc >= 0 && pc < Data.Inst.GetROMSize(); } private bool IsPCOffsetValid() diff --git a/DiztinGUIsh/window/dialog/HarshAutoStep.cs b/DiztinGUIsh/window/dialog/HarshAutoStep.cs index 3ca960f1..6be4d58e 100644 --- a/DiztinGUIsh/window/dialog/HarshAutoStep.cs +++ b/DiztinGUIsh/window/dialog/HarshAutoStep.cs @@ -20,7 +20,7 @@ public HarshAutoStep(int offset) InitializeComponent(); start = offset; - int rest = Data.GetROMSize() - start; + int rest = Data.Inst.GetROMSize() - start; count = rest < 0x100 ? rest : 0x100; end = start + count; @@ -43,7 +43,7 @@ private void UpdateText(TextBox selected) { Util.NumberBase noBase = radioDec.Checked ? Util.NumberBase.Decimal : Util.NumberBase.Hexadecimal; int digits = noBase == Util.NumberBase.Hexadecimal && radioROM.Checked ? 6 : 0; - int size = Data.GetROMSize(); + int size = Data.Inst.GetROMSize(); if (start < 0) start = 0; if (end >= size) end = size - 1; diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.cs b/DiztinGUIsh/window/dialog/ImportROMDialog.cs index 2133591b..47ad768b 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.cs @@ -166,7 +166,7 @@ public Data.ROMSpeed GetROMSpeed() private void UpdateOffsetAndSpeed() { - offset = Data.GetRomSettingOffset(mode); + offset = Data.Inst.GetRomSettingOffset(mode); if (offset >= data.Length) { speed = Data.ROMSpeed.Unknown; diff --git a/DiztinGUIsh/window/dialog/MarkManyDialog.cs b/DiztinGUIsh/window/dialog/MarkManyDialog.cs index 63b426f7..d88878c2 100644 --- a/DiztinGUIsh/window/dialog/MarkManyDialog.cs +++ b/DiztinGUIsh/window/dialog/MarkManyDialog.cs @@ -27,7 +27,7 @@ public MarkManyDialog(int offset, int column) default: property.SelectedIndex = 0; break; } start = offset; - int rest = Data.GetROMSize() - start; + int rest = Data.Inst.GetROMSize() - start; count = rest < 0x10 ? rest : 0x10; end = start + count; @@ -102,7 +102,7 @@ private void UpdateGroup() mxCombo.Visible = (property.SelectedIndex == 3 || property.SelectedIndex == 4); archCombo.Visible = (property.SelectedIndex == 5); regValue.MaxLength = (property.SelectedIndex == 1 ? 3 : 5); - value = property.SelectedIndex == 1 ? Data.GetDataBank(start) : Data.GetDirectPage(start); + value = property.SelectedIndex == 1 ? Data.Inst.GetDataBank(start) : Data.Inst.GetDirectPage(start); } private bool updatingText = false; @@ -111,7 +111,7 @@ private void UpdateText(TextBox selected) { Util.NumberBase noBase = radioDec.Checked ? Util.NumberBase.Decimal : Util.NumberBase.Hexadecimal; int digits = noBase == Util.NumberBase.Hexadecimal && radioROM.Checked ? 6 : 0; - int size = Data.GetROMSize(); + int size = Data.Inst.GetROMSize(); int maxValue = property.SelectedIndex == 1 ? 0x100 : 0x10000; if (start < 0) start = 0; diff --git a/DiztinGUIsh/window/dialog/MisalignmentChecker.cs b/DiztinGUIsh/window/dialog/MisalignmentChecker.cs index 7a403378..fad4b02e 100644 --- a/DiztinGUIsh/window/dialog/MisalignmentChecker.cs +++ b/DiztinGUIsh/window/dialog/MisalignmentChecker.cs @@ -27,9 +27,9 @@ private void buttonScan_Click(object sender, EventArgs e) textLog.Text = ""; int found = 0, offset = 0; - while (found < 500 && offset < Data.GetROMSize()) + while (found < 500 && offset < Data.Inst.GetROMSize()) { - Data.FlagType flag = Data.GetFlag(offset), check = flag == Data.FlagType.Opcode ? Data.FlagType.Operand : flag; + Data.FlagType flag = Data.Inst.GetFlag(offset), check = flag == Data.FlagType.Opcode ? Data.FlagType.Operand : flag; int step = flag == Data.FlagType.Opcode ? Manager.GetInstructionLength(offset) : Util.TypeStepSize(flag); if (flag == Data.FlagType.Operand) @@ -42,13 +42,13 @@ private void buttonScan_Click(object sender, EventArgs e) { for (int i = 1; i < step; i++) { - if (Data.GetFlag(offset + i) != check) + if (Data.Inst.GetFlag(offset + i) != check) { found++; textLog.Text += string.Format("{0} (0x{1}): {2} is not {3}\r\n", Util.NumberToBaseString(Util.ConvertPCtoSNES(offset + i), Util.NumberBase.Hexadecimal, 6, true), Util.NumberToBaseString(offset + i, Util.NumberBase.Hexadecimal, 0), - Util.TypeToString(Data.GetFlag(offset + i)), + Util.TypeToString(Data.Inst.GetFlag(offset + i)), Util.TypeToString(check)); } } From 73208d40f59026f5b76bb55a14bb9b335225cd7e Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 20 Sep 2020 20:03:56 -0400 Subject: [PATCH 036/136] starting on XML based save/load --- DiztinGUIsh/App.config | 12 +- DiztinGUIsh/DiztinGUIsh.csproj | 39 +++ DiztinGUIsh/packages.config | 14 + DiztinGUIsh/static/Class1.cs | 14 +- DiztinGUIsh/static/Data.cs | 37 ++- DiztinGUIsh/static/LogCreator.cs | 4 +- DiztinGUIsh/static/Project.cs | 266 ++++++++++++++++++ DiztinGUIsh/static/Util.cs | 12 +- .../window/dialog/ExportDisassembly.cs | 12 +- 9 files changed, 377 insertions(+), 33 deletions(-) create mode 100644 DiztinGUIsh/packages.config diff --git a/DiztinGUIsh/App.config b/DiztinGUIsh/App.config index 92793b20..d804381b 100644 --- a/DiztinGUIsh/App.config +++ b/DiztinGUIsh/App.config @@ -1,7 +1,7 @@ - + - +
@@ -18,4 +18,12 @@ + + + + + + + + \ No newline at end of file diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 4682b46a..1f501868 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -54,8 +54,46 @@ DiztinGUIsh.Program + + ..\packages\ExtendedXmlSerializer.3.2.7\lib\net452\ExtendedXmlSerializer.dll + + + ..\packages\LightInject.6.2.0\lib\net46\LightInject.dll + + + ..\packages\NReco.LambdaParser.1.0.11\lib\net45\NReco.LambdaParser.dll + + + ..\packages\Sprache.2.2.0\lib\net45\Sprache.dll + + + ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll + + + ..\packages\System.Collections.Immutable.1.7.0\lib\netstandard2.0\System.Collections.Immutable.dll + + + ..\packages\System.Interactive.4.0.0\lib\net45\System.Interactive.dll + + + + + ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll + + + + ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll + + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + + + ..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll + @@ -188,6 +226,7 @@ True Resources.resx + SettingsSingleFileGenerator diff --git a/DiztinGUIsh/packages.config b/DiztinGUIsh/packages.config new file mode 100644 index 00000000..08b1cc2f --- /dev/null +++ b/DiztinGUIsh/packages.config @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DiztinGUIsh/static/Class1.cs b/DiztinGUIsh/static/Class1.cs index 5a3e8ee5..8dc7b3be 100644 --- a/DiztinGUIsh/static/Class1.cs +++ b/DiztinGUIsh/static/Class1.cs @@ -1,23 +1,31 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Xml.Serialization; using DiztinGUIsh; class TextLoader { - void Save() + void Save(string filename) { - int size = Data.Inst.GetROMSize(); + XmlSerializer serializer = new XmlSerializer(typeof(Data)); + TextWriter writer = new StreamWriter(filename); + + serializer.Serialize(writer, Data.Inst); + writer.Close(); + + // int size = Data.Inst.GetROMSize(); // byte[] romSettings = new byte[31]; //romSettings[0] = (byte)Data.Inst.GetROMMapMode(); //romSettings[1] = (byte)Data.Inst.GetROMSpeed(); - + /*(Util.IntegerIntoByteArray(size, romSettings, 2); for (int i = 0; i < 0x15; i++) romSettings[6 + i] = (byte)Data.Inst.GetROMByte(Util.ConvertSNEStoPC(0xFFC0 + i)); for (int i = 0; i < 4; i++) romSettings[27 + i] = (byte)Data.Inst.GetROMByte(Util.ConvertSNEStoPC(0xFFDC + i)); diff --git a/DiztinGUIsh/static/Data.cs b/DiztinGUIsh/static/Data.cs index 13810c75..6cd151ef 100644 --- a/DiztinGUIsh/static/Data.cs +++ b/DiztinGUIsh/static/Data.cs @@ -8,13 +8,22 @@ namespace DiztinGUIsh { + public class TableData + { + public List RomBytes { get; } = new List(); + public ROMByte this[int i] { + get => RomBytes[i]; + set => RomBytes[i] = value; + } + } + public class Data { // singleton private static readonly Lazy instance = new Lazy(() => new Data()); public static Data Inst => instance.Value; - private Data() {} + public Data() {} // should be non-public but whatev public enum FlagType : byte { @@ -77,10 +86,10 @@ public const int EXHIROM_SETTING_OFFSET = 0x40FFD5, EXLOROM_SETTING_OFFSET = 0x407FD5; - private ROMMapMode rom_map_mode; - private ROMSpeed rom_speed; - private List table; - private Dictionary comment; + public ROMMapMode RomMapMode { get; set; } + public ROMSpeed rom_speed { get; set; } + public TableData table { get; set; } + public Dictionary comment { get; set; } public class AliasInfo { @@ -93,16 +102,16 @@ public void CleanUp() if (name == null) name = ""; } } - private Dictionary alias; + public Dictionary alias; public void Initiate(byte[] data, ROMMapMode mode, ROMSpeed speed) { - rom_map_mode = mode; + RomMapMode = mode; rom_speed = speed; int size = data.Length; alias = new Dictionary(); comment = new Dictionary(); - table = new List(); + table = new TableData(); for (int i = 0; i < size; i++) { ROMByte r = new ROMByte @@ -116,14 +125,14 @@ public void Initiate(byte[] data, ROMMapMode mode, ROMSpeed speed) Arch = Architechture.CPU65C816, Point = 0 }; - table.Add(r); + table.RomBytes.Add(r); } } - public void Restore(List l = null, ROMMapMode m = ROMMapMode.LoROM, ROMSpeed s = ROMSpeed.Unknown, Dictionary a = null, Dictionary c = null) + public void Restore(TableData l = null, ROMMapMode m = ROMMapMode.LoROM, ROMSpeed s = ROMSpeed.Unknown, Dictionary a = null, Dictionary c = null) { table = l ?? table; - rom_map_mode = s == ROMSpeed.Unknown ? rom_map_mode : m; + RomMapMode = s == ROMSpeed.Unknown ? RomMapMode : m; rom_speed = s == ROMSpeed.Unknown ? rom_speed : s; alias = a ?? alias; comment = c ?? comment; @@ -131,7 +140,7 @@ public void Restore(List l = null, ROMMapMode m = ROMMapMode.LoROM, ROM public ROMMapMode GetROMMapMode() { - return rom_map_mode; + return RomMapMode; } public ROMSpeed GetROMSpeed() @@ -139,7 +148,7 @@ public ROMSpeed GetROMSpeed() return rom_speed; } - public List GetTable() + public TableData GetTable() { return table; } @@ -151,7 +160,7 @@ public int GetROMByte(int i) public int GetROMSize() { - return table == null ? 0 : table.Count; + return table == null ? 0 : table.RomBytes.Count; } public FlagType GetFlag(int i) diff --git a/DiztinGUIsh/static/LogCreator.cs b/DiztinGUIsh/static/LogCreator.cs index a365755d..30c74a5e 100644 --- a/DiztinGUIsh/static/LogCreator.cs +++ b/DiztinGUIsh/static/LogCreator.cs @@ -64,7 +64,7 @@ public static int CreateLog(StreamWriter sw, StreamWriter er) var tempAlias = Data.Inst.GetAllLabels(); Data.Inst.Restore(a: new Dictionary(tempAlias)); AliasList.me.locked = true; - bankSize = Data.Inst.GetROMMapMode() == Data.ROMMapMode.LoROM ? 0x8000 : 0x10000; // todo + bankSize = Data.Inst.RomMapMode == Data.ROMMapMode.LoROM ? 0x8000 : 0x10000; // todo AddTemporaryLabels(); @@ -432,7 +432,7 @@ private static string GetORG(int offset, int length) private static string GetMap(int offset, int length) { string s = ""; - switch (Data.Inst.GetROMMapMode()) + switch (Data.Inst.RomMapMode) { case Data.ROMMapMode.LoROM: s = "lorom"; break; case Data.ROMMapMode.HiROM: s = "hirom"; break; diff --git a/DiztinGUIsh/static/Project.cs b/DiztinGUIsh/static/Project.cs index c1d51c45..88622ee1 100644 --- a/DiztinGUIsh/static/Project.cs +++ b/DiztinGUIsh/static/Project.cs @@ -1,12 +1,22 @@ using DiztinGUIsh.window; using System; +using System.Buffers.Text; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Linq; +using System.Runtime.InteropServices; +using System.Security.Policy; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using System.Xml; +using System.Xml.Serialization; +using ExtendedXmlSerializer; +using ExtendedXmlSerializer.Configuration; +using ExtendedXmlSerializer.ContentModel; +using ExtendedXmlSerializer.ContentModel.Format; namespace DiztinGUIsh { @@ -68,7 +78,262 @@ public static bool NewProject(string filename) private const int LATEST_FILE_FORMAT_VERSION = 2; + /*sealed class RomByteSerializer : ISerializer + { + public static RomByteSerializer Default { get; } = new RomByteSerializer(); + + RomByteSerializer() { } + + public ROMByte Get(IFormatReader parameter) + { + //var parts = parameter.Content().Split('|'); + //var result = new ROMByte(parts[0], int.Parse(parts[1])); + //return result; + throw new NotImplementedException(); + } + + public void Write(IFormatWriter writer, ROMByte instance) + { + // use a custom formatter here to save space. there are a LOT of ROMBytes. + // despite that we're still going for: + // 1) text only for slightly human readability + // 2) mergability in git/etc + // + // some of this can be unpacked further to increase readibility without + // hurting the filesize too much. figure out what's useful. + + string flagTxt; + switch (instance.TypeFlag) + { + case Data.FlagType.Unreached: flagTxt = "?"; break; + case Data.FlagType.Opcode: flagTxt = "="; break; + case Data.FlagType.Operand: flagTxt = "-"; break; + case Data.FlagType.Graphics: flagTxt = "G"; break; + case Data.FlagType.Music: flagTxt = "M"; break; + case Data.FlagType.Empty: flagTxt = "E"; break; + case Data.FlagType.Text: flagTxt = "T"; break; + + case Data.FlagType.Data8Bit: flagTxt = "1"; break; + case Data.FlagType.Data16Bit: flagTxt = "2"; break; + case Data.FlagType.Data24Bit: flagTxt = "3"; break; + case Data.FlagType.Data32Bit: flagTxt = "4"; break; + + case Data.FlagType.Pointer16Bit: flagTxt = "p"; break; + case Data.FlagType.Pointer24Bit: flagTxt = "P"; break; + case Data.FlagType.Pointer32Bit: flagTxt = "X"; break; + + default: throw new InvalidDataException("Unknown FlagType"); + } + + // max 8 bits + byte otherFlags = (byte) ( + (instance.XFlag ? 0 : 1) << 0 | // 1 bit + (instance.MFlag ? 0 : 1) << 1 | // 1 bit + (byte)instance.Point << 2 | // 4 bits + (byte)instance.Arch << 6 // 2 bits + ); + + string data = + flagTxt + + instance.DataBank.ToString("X2") + + instance.DirectPage.ToString("X4") + + otherFlags.ToString("X2"); + + Debug.Assert(data.Length == 9); + writer.Content(data); + } + }*/ + + sealed class TableDataSerializer : ISerializer + { + public static TableDataSerializer Default { get; } = new TableDataSerializer(); + + TableDataSerializer() { } + + public TableData Get(IFormatReader parameter) + { + /*var parts = parameter.Content().Split('|'); + var result = new ROMByte(parts[0], int.Parse(parts[1])); + return result;*/ + throw new NotImplementedException(); + } + + public void Write(IFormatWriter writer, TableData instance) + { + const bool compress_groupblock = true; + + var lines = new List(); + foreach (var rb in instance.RomBytes) + { + lines.Add(EncodeByte(rb)); + } + + var options = new List(); + + if (compress_groupblock) + { + options.Add("compress_groupblocks"); + ApplyCompression_GroupsBlocks(ref lines); + } + + writer.Content($"\n{string.Join(",", options)}\n"); + + foreach (var line in lines) + { + writer.Content(line + "\n"); + } + } + + public static void ApplyCompression_GroupsBlocks(ref List lines) + { + if (lines.Count < 8) + return; // forget it, too small to care. + + var output = new List(); + + var lastline = lines[0]; + var consecutive = 1; + + // adjustable, just pick something > 8 or it's not worth the optimization. + // we want to catch large consecutive blocks of data. + const int min_number_repeats_before_we_bother = 8; + + for (var i = 0; i < lines.Count; ++i) { + var line = lines[i]; + + bool different = line != lastline; + if (!different) + consecutive++; + + if (!different && i != lines.Count) + continue; + + if (consecutive >= min_number_repeats_before_we_bother) { + // replace multiple repeated lines with one new statement + output.Add($"r {consecutive.ToString()} {lastline}"); + } else { + // output 1 or more copies of the last line + // this is also how we print single lines too + output.AddRange(Enumerable.Repeat(lastline, consecutive).ToList()); + } + + lastline = line; + consecutive = 1; + } + + lines = output; + } + + public string EncodeByte(ROMByte instance) + { + // use a custom formatter here to save space. there are a LOT of ROMBytes. + // despite that we're still going for: + // 1) text only for slightly human readability + // 2) mergability in git/etc + // + // some of this can be unpacked further to increase readability without + // hurting the filesize too much. figure out what's useful. + // + // sorry, I know the encoding looks insane and weird and specific. this reduced my + // save file size from 42MB to less than 13MB + + // NOTE: must be uppercase letter or "=" or "-" + // if you add things here, make sure you understand the compression settings above. + string flagTxt; + switch (instance.TypeFlag) + { + case Data.FlagType.Unreached: flagTxt = "U"; break; + + case Data.FlagType.Opcode: flagTxt = "-"; break; + case Data.FlagType.Operand: flagTxt = "="; break; + + case Data.FlagType.Graphics: flagTxt = "G"; break; + case Data.FlagType.Music: flagTxt = "M"; break; + case Data.FlagType.Empty: flagTxt = "E"; break; + case Data.FlagType.Text: flagTxt = "T"; break; + + case Data.FlagType.Data8Bit: flagTxt = "A"; break; + case Data.FlagType.Data16Bit: flagTxt = "B"; break; + case Data.FlagType.Data24Bit: flagTxt = "C"; break; + case Data.FlagType.Data32Bit: flagTxt = "D"; break; + + case Data.FlagType.Pointer16Bit: flagTxt = "E"; break; + case Data.FlagType.Pointer24Bit: flagTxt = "F"; break; + case Data.FlagType.Pointer32Bit: flagTxt = "G"; break; + + default: throw new InvalidDataException("Unknown FlagType"); + } + + // max 6 bits if we want to fit in 1 base64 ASCII digit + byte otherFlags1 = (byte) ( + (instance.XFlag ? 1 : 0) << 0 | // 1 bit + (instance.MFlag ? 1 : 0) << 1 | // 1 bit + (byte)instance.Point << 2 // 4 bits + ); + // reminder: when decoding, have to cut off all but the first 6 bits + var o1_str = System.Convert.ToBase64String(new byte[] { otherFlags1 }); + Debug.Assert(o1_str.Length == 4); + o1_str = o1_str.Remove(1); + + if (!instance.XFlag && !instance.MFlag && instance.Point == 0) + Debug.Assert(o1_str == "A"); // sanity + + // dumbest thing in the entire world. + // the more zeroes we output, the more compressed we get. + // let's swap "A" (index 0) for "0" (index 52). + // if you got here after being really fucking confused about why + // your Base64 encoding algo wasn't working, then I owe you a beer. super-sorry. + // you are now allowed to flip your desk over. say it with me + // "Damnit Dom!!! Y U DO THIS" + if (o1_str == "A") + o1_str = "0"; // get me that sweet, sweet zero + else if (o1_str == "0") + o1_str = "A"; + + // this is basically going to be "0" almost 100% of the time. + // we'll put it on the end of the string so it's most likely not output + byte otherFlags2 = (byte)( + (byte)instance.Arch << 0 // 2 bits + ); + var o2_str = otherFlags2.ToString("X1"); Debug.Assert(o2_str.Length == 1); + + // ordering: put DB and D on the end, they're likely to be zero and compressible + string data = + flagTxt + // 1 + o1_str + // 1 + instance.DataBank.ToString("X2") + // 2 + instance.DirectPage.ToString("X4") + // 4 + o2_str; // 1 + + Debug.Assert(data.Length == 9); + + // light compression: chop off any trailing zeroes. + // this alone saves a giant amount of space. + data = data.TrimEnd(new Char[] {'0'}); + + // future compression but dilutes readability: + // if type is opcode or operand, combine + + return data; + } + } + public static void SaveProject(string filename) + { + var serializer = new ConfigurationContainer() + .Type().Register().Serializer().Using(TableDataSerializer.Default) + .UseOptimizedNamespaces() //If you want to have all namespaces in root element + .Create(); + + var xml = serializer.Serialize( + new XmlWriterSettings { + Indent = true + }, Data.Inst); + + File.WriteAllText(filename + ".xml", xml); + } + + public static void SaveProjectORIG(string filename) { try { @@ -150,6 +415,7 @@ void SaveStringToBytes(string str, List bytes) byte[] data = new byte[romSettings.Length + romLocation.Length + 8 * size + label.Count + comment.Count]; romSettings.CopyTo(data, 0); for (int i = 0; i < romLocation.Length; i++) data[romSettings.Length + i] = romLocation[i]; + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + i] = (byte)Data.Inst.GetDataBank(i); for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + size + i] = (byte)Data.Inst.GetDirectPage(i); for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 2 * size + i] = (byte)(Data.Inst.GetDirectPage(i) >> 8); diff --git a/DiztinGUIsh/static/Util.cs b/DiztinGUIsh/static/Util.cs index f24f886f..7ec9f554 100644 --- a/DiztinGUIsh/static/Util.cs +++ b/DiztinGUIsh/static/Util.cs @@ -149,24 +149,24 @@ public static string GetDefaultLabel(int address) public static int ConvertPCtoSNES(int offset) { - if (Data.Inst.GetROMMapMode() == Data.ROMMapMode.LoROM) + if (Data.Inst.RomMapMode == Data.ROMMapMode.LoROM) { offset = ((offset & 0x3F8000) << 1) | 0x8000 | (offset & 0x7FFF); if (Data.Inst.GetROMSpeed() == Data.ROMSpeed.FastROM || offset >= 0x7E0000) offset |= 0x800000; } - else if (Data.Inst.GetROMMapMode() == Data.ROMMapMode.HiROM) + else if (Data.Inst.RomMapMode == Data.ROMMapMode.HiROM) { offset |= 0x400000; if (Data.Inst.GetROMSpeed() == Data.ROMSpeed.FastROM || offset >= 0x7E0000) offset |= 0x800000; } - else if (Data.Inst.GetROMMapMode() == Data.ROMMapMode.ExHiROM) + else if (Data.Inst.RomMapMode == Data.ROMMapMode.ExHiROM) { if (offset < 0x40000) offset |= 0xC00000; else if (offset >= 0x7E0000) offset &= 0x3FFFFF; } else { - if (offset >= 0x400000 && Data.Inst.GetROMMapMode() == Data.ROMMapMode.ExSA1ROM) + if (offset >= 0x400000 && Data.Inst.RomMapMode == Data.ROMMapMode.ExSA1ROM) { offset += 0x800000; } @@ -187,7 +187,7 @@ public static int ConvertSNEStoPC(int address) // WRAM mirror & PPU regs are N/A to PC addressing if (((address & 0x400000) == 0) && ((address & 0x8000) == 0)) return -1; - switch (Data.Inst.GetROMMapMode()) + switch (Data.Inst.RomMapMode) { case Data.ROMMapMode.LoROM: { @@ -212,7 +212,7 @@ public static int ConvertSNEStoPC(int address) if (address >= 0xC00000) { - if (Data.Inst.GetROMMapMode() == Data.ROMMapMode.ExSA1ROM) + if (Data.Inst.RomMapMode == Data.ROMMapMode.ExSA1ROM) return UnmirroredOffset(address & 0x7FFFFF); else return UnmirroredOffset(address & 0x3FFFFF); diff --git a/DiztinGUIsh/window/dialog/ExportDisassembly.cs b/DiztinGUIsh/window/dialog/ExportDisassembly.cs index 6fa7d5db..63fae64c 100644 --- a/DiztinGUIsh/window/dialog/ExportDisassembly.cs +++ b/DiztinGUIsh/window/dialog/ExportDisassembly.cs @@ -93,13 +93,13 @@ private bool ValidateFormat() private void UpdateSample() { // cheeky way of using the same methods for disassembling a different set of data :^) - while (sampleTable.Count < 0x8000) sampleTable.Add(new ROMByte()); + while (sampleTable.RomBytes.Count < 0x8000) sampleTable.RomBytes.Add(new ROMByte()); using (MemoryStream mem = new MemoryStream()) using (StreamWriter sw = new StreamWriter(mem)) { - List tempTable = Data.Inst.GetTable(); - Data.ROMMapMode tempMode = Data.Inst.GetROMMapMode(); + var tempTable = Data.Inst.GetTable(); + Data.ROMMapMode tempMode = Data.Inst.RomMapMode; Data.ROMSpeed tempSpeed = Data.Inst.GetROMSpeed(); var tempAlias = Data.Inst.GetAllLabels(); var tempComment = Data.Inst.GetAllComments(); @@ -121,8 +121,8 @@ private void UpdateSample() // random sample code I made up; hopefully it shows a little bit of // everything so you can see how the settings will effect the output - public static List sampleTable = new List - { + public static TableData sampleTable = new TableData + { RomBytes = { new ROMByte {Rom = 0x78, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true, Point = Data.InOutPoint.InPoint}, new ROMByte {Rom = 0xA9, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true}, new ROMByte {Rom = 0x01, TypeFlag = Data.FlagType.Operand}, @@ -246,7 +246,7 @@ private void UpdateSample() new ROMByte {Rom = 0x83, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, new ROMByte {Rom = 0x34, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, new ROMByte {Rom = 0x6D, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - }; + }}; public static Dictionary sampleAlias = new Dictionary { From 76a1b6ae2b4eb0d6f8b05b96871bb851182b2298 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Mon, 21 Sep 2020 03:41:20 -0400 Subject: [PATCH 037/136] WIP load/save XML almost working --- DiztinGUIsh/DiztinGUIsh.csproj | 2 +- DiztinGUIsh/ROMByte.cs | 31 +- DiztinGUIsh/static/Class1.cs | 78 ----- DiztinGUIsh/static/Data.cs | 91 +++++- DiztinGUIsh/static/DataSerializer.cs | 393 ++++++++++++++++++++++++++ DiztinGUIsh/static/Project.cs | 407 ++++++++++----------------- DiztinGUIsh/static/diz/Manager.cs | 24 +- DiztinGUIsh/window/MainWindow.cs | 26 +- 8 files changed, 683 insertions(+), 369 deletions(-) delete mode 100644 DiztinGUIsh/static/Class1.cs create mode 100644 DiztinGUIsh/static/DataSerializer.cs diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 1f501868..7c20184c 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -108,7 +108,7 @@ - + Form diff --git a/DiztinGUIsh/ROMByte.cs b/DiztinGUIsh/ROMByte.cs index b1a9a25f..6144b6b2 100644 --- a/DiztinGUIsh/ROMByte.cs +++ b/DiztinGUIsh/ROMByte.cs @@ -8,7 +8,36 @@ namespace DiztinGUIsh { public class ROMByte { - public byte Rom { get; set; } + protected bool Equals(ROMByte other) + { + return Rom == other.Rom && DataBank == other.DataBank && DirectPage == other.DirectPage && XFlag == other.XFlag && MFlag == other.MFlag && TypeFlag == other.TypeFlag && Arch == other.Arch && Point == other.Point; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((ROMByte) obj); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = Rom.GetHashCode(); + hashCode = (hashCode * 397) ^ DataBank.GetHashCode(); + hashCode = (hashCode * 397) ^ DirectPage; + hashCode = (hashCode * 397) ^ XFlag.GetHashCode(); + hashCode = (hashCode * 397) ^ MFlag.GetHashCode(); + hashCode = (hashCode * 397) ^ (int) TypeFlag; + hashCode = (hashCode * 397) ^ (int) Arch; + hashCode = (hashCode * 397) ^ (int) Point; + return hashCode; + } + } + + public byte Rom { get; set; } // never serialize this, read from ROM on load. for copyright reasons. public byte DataBank { get; set; } public int DirectPage { get; set; } public bool XFlag { get; set; } diff --git a/DiztinGUIsh/static/Class1.cs b/DiztinGUIsh/static/Class1.cs deleted file mode 100644 index 8dc7b3be..00000000 --- a/DiztinGUIsh/static/Class1.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml.Serialization; -using DiztinGUIsh; - - -class TextLoader -{ - void Save(string filename) - { - XmlSerializer serializer = new XmlSerializer(typeof(Data)); - TextWriter writer = new StreamWriter(filename); - - serializer.Serialize(writer, Data.Inst); - writer.Close(); - - // int size = Data.Inst.GetROMSize(); - - // byte[] romSettings = new byte[31]; - //romSettings[0] = (byte)Data.Inst.GetROMMapMode(); - //romSettings[1] = (byte)Data.Inst.GetROMSpeed(); - - - - /*(Util.IntegerIntoByteArray(size, romSettings, 2); - for (int i = 0; i < 0x15; i++) romSettings[6 + i] = (byte)Data.Inst.GetROMByte(Util.ConvertSNEStoPC(0xFFC0 + i)); - for (int i = 0; i < 4; i++) romSettings[27 + i] = (byte)Data.Inst.GetROMByte(Util.ConvertSNEStoPC(0xFFDC + i)); - - // TODO put selected offset in save file - - List label = new List(), comment = new List(); - var all_labels = Data.Inst.GetAllLabels(); - var all_comments = Data.Inst.GetAllComments(); - - Util.IntegerIntoByteList(all_labels.Count, label); - foreach (var pair in all_labels) - { - Util.IntegerIntoByteList(pair.Key, label); - - SaveStringToBytes(pair.Value.name, label); - if (version >= 2) - { - SaveStringToBytes(pair.Value.comment, label); - } - } - - Util.IntegerIntoByteList(all_comments.Count, comment); - foreach (KeyValuePair pair in all_comments) - { - Util.IntegerIntoByteList(pair.Key, comment); - SaveStringToBytes(pair.Value, comment); - } - - byte[] romLocation = Util.StringToByteArray(currentROMFile); - - byte[] data = new byte[romSettings.Length + romLocation.Length + 8 * size + label.Count + comment.Count]; - romSettings.CopyTo(data, 0); - for (int i = 0; i < romLocation.Length; i++) data[romSettings.Length + i] = romLocation[i]; - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + i] = (byte)Data.Inst.GetDataBank(i); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + size + i] = (byte)Data.Inst.GetDirectPage(i); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 2 * size + i] = (byte)(Data.Inst.GetDirectPage(i) >> 8); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 3 * size + i] = (byte)(Data.Inst.GetXFlag(i) ? 1 : 0); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 4 * size + i] = (byte)(Data.Inst.GetMFlag(i) ? 1 : 0); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 5 * size + i] = (byte)Data.Inst.GetFlag(i); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 6 * size + i] = (byte)Data.Inst.GetArchitechture(i); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 7 * size + i] = (byte)Data.Inst.GetInOutPoint(i); - // ??? - label.CopyTo(data, romSettings.Length + romLocation.Length + 8 * size); - comment.CopyTo(data, romSettings.Length + romLocation.Length + 8 * size + label.Count); - // ??? - - return data;*/ - } -} diff --git a/DiztinGUIsh/static/Data.cs b/DiztinGUIsh/static/Data.cs index 6cd151ef..7c3ac059 100644 --- a/DiztinGUIsh/static/Data.cs +++ b/DiztinGUIsh/static/Data.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -10,6 +11,24 @@ namespace DiztinGUIsh { public class TableData { + protected bool Equals(TableData other) + { + return Equals(RomBytes, other.RomBytes); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((TableData) obj); + } + + public override int GetHashCode() + { + return (RomBytes != null ? RomBytes.GetHashCode() : 0); + } + public List RomBytes { get; } = new List(); public ROMByte this[int i] { get => RomBytes[i]; @@ -19,11 +38,42 @@ public ROMByte this[int i] { public class Data { + protected bool Equals(Data other) + { + return alias.Equals(other.alias) && RomMapMode == other.RomMapMode && rom_speed == other.rom_speed && comment.Equals(other.comment) && table.Equals(other.table); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((Data) obj); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = alias.GetHashCode(); + hashCode = (hashCode * 397) ^ (int) RomMapMode; + hashCode = (hashCode * 397) ^ (int) rom_speed; + hashCode = (hashCode * 397) ^ comment.GetHashCode(); + hashCode = (hashCode * 397) ^ table.GetHashCode(); + return hashCode; + } + } + // singleton - private static readonly Lazy instance = new Lazy(() => new Data()); - public static Data Inst => instance.Value; + // private static readonly Lazy instance = new Lazy(() => new Data()); + // public static Data Inst => instance.Value; + + // backwards compatibility only. from here on out, everything should reference Project.Inst.Data + public static Data Inst => Project.Inst.Data; + - public Data() {} // should be non-public but whatev + // public Data() {} // should be non-public for singleton but whatev for now. + // we shouldn't use singleton anyway, we should just pass around Data. public enum FlagType : byte { @@ -86,13 +136,36 @@ public const int EXHIROM_SETTING_OFFSET = 0x40FFD5, EXLOROM_SETTING_OFFSET = 0x407FD5; + // Note: order of these properties matters for the load/save process. Keep 'table' LAST public ROMMapMode RomMapMode { get; set; } public ROMSpeed rom_speed { get; set; } - public TableData table { get; set; } public Dictionary comment { get; set; } + public TableData table { get; set; } + public class AliasInfo { + protected bool Equals(AliasInfo other) + { + return name == other.name && comment == other.comment; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((AliasInfo) obj); + } + + public override int GetHashCode() + { + unchecked + { + return ((name != null ? name.GetHashCode() : 0) * 397) ^ (comment != null ? comment.GetHashCode() : 0); + } + } + public string name = ""; // name of the label public string comment = ""; // user-generated text, comment only @@ -129,6 +202,16 @@ public void Initiate(byte[] data, ROMMapMode mode, ROMSpeed speed) } } + public void CopyRomDataIn(byte[] data) + { + int size = data.Length; + Debug.Assert(table.RomBytes.Count == size); + for (int i = 0; i < size; i++) + { + table[i].Rom = data[i]; + } + } + public void Restore(TableData l = null, ROMMapMode m = ROMMapMode.LoROM, ROMSpeed s = ROMSpeed.Unknown, Dictionary a = null, Dictionary c = null) { table = l ?? table; diff --git a/DiztinGUIsh/static/DataSerializer.cs b/DiztinGUIsh/static/DataSerializer.cs new file mode 100644 index 00000000..f310eb24 --- /dev/null +++ b/DiztinGUIsh/static/DataSerializer.cs @@ -0,0 +1,393 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using ExtendedXmlSerializer.ContentModel; +using ExtendedXmlSerializer.ContentModel.Format; +using DiztinGUIsh; + +// everything else in the savefiles is straight up normal XML, but, +// the amount of bytes for the ROM metadata can be huge. +// by using a custom serializer for this one section, we can cut a 4MB rom savefile down from ~45MB to ~1.5MB +// +// This uses some hacky compression methods designed to preserve: +// 1) newlines +// 2) slight human readability for merging +// 3) using pattern substitution tables that won't change from PC to PC. +// +// The easiest thing would be use zlib (and we can use it with the output of the entire XML if we want) +// but, for projects with multiple collaborators using diztinGUIsh, mergability in text/git/editors/etc +// is a must. We aim for a tradeoff between decent compression and some small semblance of human readability. +// +// It's not.. super-pretty but it gets the job done. +sealed class TableDataSerializer : ISerializer +{ + + public static TableDataSerializer Default { get; } = new TableDataSerializer(); + + TableDataSerializer() { } + + public bool compress_groupblock = true; + public bool compress_using_table_1 = true; + + public TableData Get(IFormatReader parameter) + { + var tableDataOut = new TableData(); + + var lines = parameter.Content().Split(new char[] { '\n' }, 3).ToList(); + var options = lines[1].Split(new char[] { ',' }).ToList(); + lines = lines[2].Split(new char[] { '\n' }).ToList(); + if (lines[lines.Count - 1] == "") + lines.RemoveAt(lines.Count - 1); + + // always apply options in same order here and in saving function + if (options.Exists(s => s == "compress_table_1")) + UndoCompression_Table1(ref lines); + + if (options.Exists(s => s == "compress_groupblocks")) + UndoCompression_GroupsBlocks(ref lines); + + int lineNum = 0; + try + { + foreach (var line in lines) + { + tableDataOut.RomBytes.Add(DecodeRomByte(line)); + lineNum++; + } + } + catch (Exception ex) + { + ex.Data.Add("ParseLineNum", "Near line#" + lineNum); + throw; + } + + return tableDataOut; + } + + public void Write(IFormatWriter writer, TableData instance) + { + var options = new List(); + + var lines = new List(); + foreach (var rb in instance.RomBytes) + { + lines.Add(EncodeByte(rb)); + } + + if (compress_groupblock) + { + options.Add("compress_groupblocks"); + ApplyCompression_GroupsBlocks(ref lines); + } + + if (compress_using_table_1) + { + options.Add("compress_table_1"); + ApplyCompression_Table1(ref lines); + } + + writer.Content($"\n{string.Join(",", options)}\n"); + + foreach (var line in lines) + { + writer.Content(line + "\n"); + } + } + + class CompressionEntry + { + public string Pattern; + public string c; + } + + private static List table1 = new List + { + new CompressionEntry() {Pattern = "0001E", c="ZQ"}, + new CompressionEntry() {Pattern = "B0001", c="Zq"}, + new CompressionEntry() {Pattern = "C0001", c="ZX"}, + new CompressionEntry() {Pattern = "B7E", c="Zx"}, + new CompressionEntry() {Pattern = "07F01", c="ZY"}, + new CompressionEntry() {Pattern = "0001D", c="Zy"}, + new CompressionEntry() {Pattern = "C7E", c="ZZ"}, + new CompressionEntry() {Pattern = "07E", c="Zz"}, + new CompressionEntry() {Pattern = "00001", c="ZS"}, + new CompressionEntry() {Pattern = "0001", c="Zs"}, + }; + + private void UndoCompression_Table1(ref List lines) + { + for (int i = 0; i < lines.Count; ++i) + { + foreach (var e in table1.Reverse()) + { + lines[i] = lines[i].Replace(e.c, e.Pattern); + } + } + } + + private void ApplyCompression_Table1(ref List lines) + { + // kind of a manually made / crappy huffman table encoding type thing. + // this is no great work of genius, more just some cheap hacks to reduce filesize + // these are based on one half-assembled ROM i was using and probably don't + // universally work perfectly. I expect at some point we could collect a bunch of projects + // and make a Table2, add that here without having to bump the file version. + for (int i = 0; i < lines.Count; ++i) + { + foreach (var e in table1) + { + Debug.Assert(!lines[i].Contains(e.c)); + lines[i] = lines[i].Replace(e.Pattern, e.c); + } + } + } + + private void UndoCompression_GroupsBlocks(ref List lines) + { + var output = new List(); + + foreach (var line in lines) + { + if (!line.StartsWith("r")) + { + output.Add(line); + continue; + } + + var split = line.Split(' '); + if (split.Length != 3) + throw new InvalidDataException("Invalid repeater command"); + + var count = int.Parse(split[1]); + for (int i = 0; i < count; ++i) + { + output.Add(split[2]); + } + } + + lines = output; + } + + private void ApplyCompression_GroupsBlocks(ref List lines) + { + if (lines.Count < 8) + return; // forget it, too small to care. + + var output = new List(); + + var lastline = lines[0]; + var consecutive = 1; + + // adjustable, just pick something > 8 or it's not worth the optimization. + // we want to catch large consecutive blocks of data. + const int min_number_repeats_before_we_bother = 8; + + int totalLinesDebug = 0; + + for (var i = 1; i < lines.Count; ++i) + { + var line = lines[i]; + Debug.Assert(!line.StartsWith("r")); + + bool different = line != lastline; + bool finalLine = i == lines.Count-1; + + if (!different) { + consecutive++; + + if (!finalLine) + continue; + + // special case for the final line. + // since our loop only ever prints out the LAST line, we have to handle this separately. + consecutive++; + } + + if (consecutive >= min_number_repeats_before_we_bother) + { + // replace multiple repeated lines with one new statement + output.Add($"r {consecutive.ToString()} {lastline}"); + } + else + { + // output 1 or more copies of the last line + // this is also how we print single lines too + output.AddRange(Enumerable.Repeat(lastline, consecutive).ToList()); + } + + if (finalLine && different) { + output.Add(line); + totalLinesDebug++; + } + + totalLinesDebug += consecutive; + + lastline = line; + consecutive = 1; + } + + Debug.Assert(totalLinesDebug == lines.Count); + + lines = output; + } + + public class FlagEncodeEntry + { + public string c; + public Data.FlagType f; + }; + + private static List flagEncodeTable = new List { + new FlagEncodeEntry() {f = Data.FlagType.Unreached, c = "U"}, + + new FlagEncodeEntry() {f = Data.FlagType.Opcode, c = "+"}, + new FlagEncodeEntry() {f = Data.FlagType.Operand, c = "."}, + + new FlagEncodeEntry() {f = Data.FlagType.Graphics, c = "G"}, + new FlagEncodeEntry() {f = Data.FlagType.Music, c = "M"}, + new FlagEncodeEntry() {f = Data.FlagType.Empty, c = "X"}, + new FlagEncodeEntry() {f = Data.FlagType.Text, c = "T"}, + + new FlagEncodeEntry() {f = Data.FlagType.Data8Bit, c = "A"}, + new FlagEncodeEntry() {f = Data.FlagType.Data16Bit, c = "B"}, + new FlagEncodeEntry() {f = Data.FlagType.Data24Bit, c = "C"}, + new FlagEncodeEntry() {f = Data.FlagType.Data32Bit, c = "D"}, + + new FlagEncodeEntry() {f = Data.FlagType.Pointer16Bit, c = "E"}, + new FlagEncodeEntry() {f = Data.FlagType.Pointer24Bit, c = "F"}, + new FlagEncodeEntry() {f = Data.FlagType.Pointer32Bit, c = "G"}, + }; + + private ROMByte DecodeRomByte(string line) + { + var newByte = new ROMByte(); + + // light decompression. always 9 chars long + line = line.PadRight(9, '0'); + Debug.Assert(line.Length == 9); + + var asHex = System.Globalization.NumberStyles.HexNumber; + + var flagTxt = line.Substring(0, 1); + var o1_str = line.Substring(1, 1); + newByte.DataBank = byte.Parse(line.Substring(2, 2), asHex); + newByte.DirectPage = int.Parse(line.Substring(4, 4), asHex); + var o2_str = byte.Parse(line.Substring(8, 1), asHex); + + newByte.Arch = (Data.Architechture)((o2_str >> 0) & 0x3); + + // un-screw-up the base64 dumb thing we do on the encode + if (o1_str == "A") o1_str = "0"; else if (o1_str == "0") o1_str = "A"; + + var superHackyBase64 = o1_str + "A=="; // we dont care about > 6 bits. + var originalBytes = Convert.FromBase64CharArray(superHackyBase64.ToCharArray(), 0, superHackyBase64.Length); + Debug.Assert(originalBytes.Length == 1); + byte otherFlags1 = originalBytes[0]; + + newByte.XFlag = ((otherFlags1 >> 2) & 0x1) != 0; + newByte.MFlag = ((otherFlags1 >> 3) & 0x1) != 0; + newByte.Point = (Data.InOutPoint)((otherFlags1 >> 4) & 0xF); + + bool found = false; + foreach (var e in flagEncodeTable) + { + if (e.c == flagTxt) + { + newByte.TypeFlag = e.f; + found = true; + break; + } + } + if (!found) + throw new InvalidDataException("Unknown FlagType"); + + return newByte; + } + + private string EncodeByte(ROMByte instance) + { + // use a custom formatter here to save space. there are a LOT of ROMBytes. + // despite that we're still going for: + // 1) text only for slightly human readability + // 2) mergability in git/etc + // + // some of this can be unpacked further to increase readability without + // hurting the filesize too much. figure out what's useful. + // + // sorry, I know the encoding looks insane and weird and specific. this reduced my + // save file size from 42MB to less than 13MB + + // NOTE: must be uppercase letter or "=" or "-" + // if you add things here, make sure you understand the compression settings above. + string flagTxt = ""; + foreach (var e in flagEncodeTable) + { + if (e.f == instance.TypeFlag) + { + flagTxt = e.c; + break; + } + } + + if (flagTxt == "") + throw new InvalidDataException("Unknown FlagType"); + + // max 6 bits if we want to fit in 1 base64 ASCII digit + byte otherFlags1 = (byte)( + (instance.XFlag ? 1 : 0) << 2 | // 1 bit + (instance.MFlag ? 1 : 0) << 3 | // 1 bit + (byte)instance.Point << 4 // 4 bits + // LEAVE OFF THE LAST 2 BITS. it'll mess with the base64 below + ); + // reminder: when decoding, have to cut off all but the first 6 bits + var o1_str = System.Convert.ToBase64String(new byte[] { otherFlags1 }); + Debug.Assert(o1_str.Length == 4); + Debug.Assert(o1_str.Substring(1) == "A=="); + o1_str = o1_str.Remove(1); + + if (!instance.XFlag && !instance.MFlag && instance.Point == 0) + Debug.Assert(o1_str == "A"); // sanity + + // dumbest thing in the entire world. + // the more zeroes we output, the more compressed we get. + // let's swap "A" (index 0) for "0" (index 52). + // if you got here after being really fucking confused about why + // your Base64 encoding algo wasn't working, then I owe you a beer. super-sorry. + // you are now allowed to flip your desk over. say it with me + // "Damnit Dom!!! Y U DO THIS" + if (o1_str == "A") + o1_str = "0"; // get me that sweet, sweet zero + else if (o1_str == "0") + o1_str = "A"; + + // this is basically going to be "0" almost 100% of the time. + // we'll put it on the end of the string so it's most likely not output + byte otherFlags2 = (byte)( + (byte)instance.Arch << 0 // 2 bits + ); + var o2_str = otherFlags2.ToString("X1"); Debug.Assert(o2_str.Length == 1); + + // ordering: put DB and D on the end, they're likely to be zero and compressible + string data = + flagTxt + // 1 + o1_str + // 1 + instance.DataBank.ToString("X2") + // 2 + instance.DirectPage.ToString("X4") + // 4 + o2_str; // 1 + + Debug.Assert(data.Length == 9); + + // light compression: chop off any trailing zeroes. + // this alone saves a giant amount of space. + data = data.TrimEnd(new Char[] { '0' }); + + // future compression but dilutes readability: + // if type is opcode or operand with same flags, combine those into 1 type. + // i.e. take an opcode with 3 operands, represent it using one digit in the file. + // instead of "=---", we swap with "+" or something. small optimization. + + return data; + } +} \ No newline at end of file diff --git a/DiztinGUIsh/static/Project.cs b/DiztinGUIsh/static/Project.cs index 88622ee1..587ca383 100644 --- a/DiztinGUIsh/static/Project.cs +++ b/DiztinGUIsh/static/Project.cs @@ -7,6 +7,7 @@ using System.IO.Compression; using System.Linq; using System.Runtime.InteropServices; +using System.Security.Cryptography; using System.Security.Policy; using System.Text; using System.Threading.Tasks; @@ -20,15 +21,23 @@ namespace DiztinGUIsh { - public static class Project + public class Project { public const int HEADER_SIZE = 0x100; - public static string currentFile = null, currentROMFile = null; - public static bool unsavedChanges = false; - public static string watermark = "DiztinGUIsh"; + public string currentProjectFile = null, currentROMFile = null; + public bool unsavedChanges = false; + public const string watermark = "DiztinGUIsh"; - public static bool NewProject(string filename) + // these must always match the same bytes in the ROM + public string InternalRomTitleName { get; set; } = ""; + public int InternalCheckSum { get; set; } = -1; + public int InternalRomSize { get; set; } = -1; + + // needs to come last for serialization + public Data Data = new Data(); + + public bool NewProject(string filename) { try { @@ -49,7 +58,7 @@ public static bool NewProject(string filename) { Data.Inst.Initiate(rom, import.GetROMMapMode(), import.GetROMSpeed()); unsavedChanges = false; - currentFile = null; + currentProjectFile = null; AliasList.me.ResetDataGrid(); Dictionary generatedLabels = import.GetGeneratedLabels(); @@ -66,6 +75,10 @@ public static bool NewProject(string filename) unsavedChanges = true; } + InternalCheckSum = GetRomCheckSumsFromRomBytes(); + InternalRomTitleName = GetRomNameFromRomBytes(); + InternalRomSize = Data.Inst.GetROMSize(); + return true; } } @@ -78,262 +91,64 @@ public static bool NewProject(string filename) private const int LATEST_FILE_FORMAT_VERSION = 2; - /*sealed class RomByteSerializer : ISerializer + public IExtendedXmlSerializer GetSerializer() { - public static RomByteSerializer Default { get; } = new RomByteSerializer(); - - RomByteSerializer() { } + return new ConfigurationContainer() + .Type().Register().Serializer().Using(TableDataSerializer.Default) + .UseOptimizedNamespaces() + .UseAutoFormatting() + .EnableImplicitTyping(typeof(Data)) + .EnableImplicitTyping(typeof(Data.AliasInfo)) + .Create(); + } - public ROMByte Get(IFormatReader parameter) - { - //var parts = parameter.Content().Split('|'); - //var result = new ROMByte(parts[0], int.Parse(parts[1])); - //return result; - throw new NotImplementedException(); - } + public void SaveProject(string filename) + { + // TODO: figure out how to not save Project.unsavedChanges property in XML - public void Write(IFormatWriter writer, ROMByte instance) + var file = filename + ".xml"; { - // use a custom formatter here to save space. there are a LOT of ROMBytes. - // despite that we're still going for: - // 1) text only for slightly human readability - // 2) mergability in git/etc - // - // some of this can be unpacked further to increase readibility without - // hurting the filesize too much. figure out what's useful. - - string flagTxt; - switch (instance.TypeFlag) - { - case Data.FlagType.Unreached: flagTxt = "?"; break; - case Data.FlagType.Opcode: flagTxt = "="; break; - case Data.FlagType.Operand: flagTxt = "-"; break; - case Data.FlagType.Graphics: flagTxt = "G"; break; - case Data.FlagType.Music: flagTxt = "M"; break; - case Data.FlagType.Empty: flagTxt = "E"; break; - case Data.FlagType.Text: flagTxt = "T"; break; - - case Data.FlagType.Data8Bit: flagTxt = "1"; break; - case Data.FlagType.Data16Bit: flagTxt = "2"; break; - case Data.FlagType.Data24Bit: flagTxt = "3"; break; - case Data.FlagType.Data32Bit: flagTxt = "4"; break; - - case Data.FlagType.Pointer16Bit: flagTxt = "p"; break; - case Data.FlagType.Pointer24Bit: flagTxt = "P"; break; - case Data.FlagType.Pointer32Bit: flagTxt = "X"; break; - - default: throw new InvalidDataException("Unknown FlagType"); - } + var xml = GetSerializer().Serialize( + new XmlWriterSettings + { + Indent = true + }, Project.Inst); - // max 8 bits - byte otherFlags = (byte) ( - (instance.XFlag ? 0 : 1) << 0 | // 1 bit - (instance.MFlag ? 0 : 1) << 1 | // 1 bit - (byte)instance.Point << 2 | // 4 bits - (byte)instance.Arch << 6 // 2 bits - ); - - string data = - flagTxt + - instance.DataBank.ToString("X2") + - instance.DirectPage.ToString("X4") + - otherFlags.ToString("X2"); - - Debug.Assert(data.Length == 9); - writer.Content(data); + File.WriteAllText(file, xml); } - }*/ - - sealed class TableDataSerializer : ISerializer - { - public static TableDataSerializer Default { get; } = new TableDataSerializer(); - TableDataSerializer() { } + var dataRead = OpenProjectXml(file); + bool equal = dataRead.Equals(Project.Inst); - public TableData Get(IFormatReader parameter) + for (int i = 0; i < dataRead.Data.table.RomBytes.Count; ++i) { - /*var parts = parameter.Content().Split('|'); - var result = new ROMByte(parts[0], int.Parse(parts[1])); - return result;*/ - throw new NotImplementedException(); - } - - public void Write(IFormatWriter writer, TableData instance) - { - const bool compress_groupblock = true; - - var lines = new List(); - foreach (var rb in instance.RomBytes) - { - lines.Add(EncodeByte(rb)); - } - - var options = new List(); - - if (compress_groupblock) - { - options.Add("compress_groupblocks"); - ApplyCompression_GroupsBlocks(ref lines); - } - - writer.Content($"\n{string.Join(",", options)}\n"); - - foreach (var line in lines) + if (!dataRead.Data.table[i].Equals(Project.Inst.Data.table[i])) { - writer.Content(line + "\n"); + int y = 3; } } - public static void ApplyCompression_GroupsBlocks(ref List lines) - { - if (lines.Count < 8) - return; // forget it, too small to care. - - var output = new List(); - - var lastline = lines[0]; - var consecutive = 1; - - // adjustable, just pick something > 8 or it's not worth the optimization. - // we want to catch large consecutive blocks of data. - const int min_number_repeats_before_we_bother = 8; - - for (var i = 0; i < lines.Count; ++i) { - var line = lines[i]; - - bool different = line != lastline; - if (!different) - consecutive++; + int x = 3; + } - if (!different && i != lines.Count) - continue; + public Project OpenProjectXml(string filename) + { + var loadingProject = GetSerializer().Deserialize(File.ReadAllText(filename)); - if (consecutive >= min_number_repeats_before_we_bother) { - // replace multiple repeated lines with one new statement - output.Add($"r {consecutive.ToString()} {lastline}"); - } else { - // output 1 or more copies of the last line - // this is also how we print single lines too - output.AddRange(Enumerable.Repeat(lastline, consecutive).ToList()); - } + byte[] rom; - lastline = line; - consecutive = 1; - } + // tmp + OpenFileDialog open = new OpenFileDialog(); - lines = output; - } - - public string EncodeByte(ROMByte instance) + if (ValidateROM(this.currentROMFile, InternalRomTitleName, InternalCheckSum, Project.Inst.Data.RomMapMode, out rom, open)) { - // use a custom formatter here to save space. there are a LOT of ROMBytes. - // despite that we're still going for: - // 1) text only for slightly human readability - // 2) mergability in git/etc - // - // some of this can be unpacked further to increase readability without - // hurting the filesize too much. figure out what's useful. - // - // sorry, I know the encoding looks insane and weird and specific. this reduced my - // save file size from 42MB to less than 13MB - - // NOTE: must be uppercase letter or "=" or "-" - // if you add things here, make sure you understand the compression settings above. - string flagTxt; - switch (instance.TypeFlag) - { - case Data.FlagType.Unreached: flagTxt = "U"; break; - - case Data.FlagType.Opcode: flagTxt = "-"; break; - case Data.FlagType.Operand: flagTxt = "="; break; - - case Data.FlagType.Graphics: flagTxt = "G"; break; - case Data.FlagType.Music: flagTxt = "M"; break; - case Data.FlagType.Empty: flagTxt = "E"; break; - case Data.FlagType.Text: flagTxt = "T"; break; - - case Data.FlagType.Data8Bit: flagTxt = "A"; break; - case Data.FlagType.Data16Bit: flagTxt = "B"; break; - case Data.FlagType.Data24Bit: flagTxt = "C"; break; - case Data.FlagType.Data32Bit: flagTxt = "D"; break; - - case Data.FlagType.Pointer16Bit: flagTxt = "E"; break; - case Data.FlagType.Pointer24Bit: flagTxt = "F"; break; - case Data.FlagType.Pointer32Bit: flagTxt = "G"; break; - - default: throw new InvalidDataException("Unknown FlagType"); - } - - // max 6 bits if we want to fit in 1 base64 ASCII digit - byte otherFlags1 = (byte) ( - (instance.XFlag ? 1 : 0) << 0 | // 1 bit - (instance.MFlag ? 1 : 0) << 1 | // 1 bit - (byte)instance.Point << 2 // 4 bits - ); - // reminder: when decoding, have to cut off all but the first 6 bits - var o1_str = System.Convert.ToBase64String(new byte[] { otherFlags1 }); - Debug.Assert(o1_str.Length == 4); - o1_str = o1_str.Remove(1); - - if (!instance.XFlag && !instance.MFlag && instance.Point == 0) - Debug.Assert(o1_str == "A"); // sanity - - // dumbest thing in the entire world. - // the more zeroes we output, the more compressed we get. - // let's swap "A" (index 0) for "0" (index 52). - // if you got here after being really fucking confused about why - // your Base64 encoding algo wasn't working, then I owe you a beer. super-sorry. - // you are now allowed to flip your desk over. say it with me - // "Damnit Dom!!! Y U DO THIS" - if (o1_str == "A") - o1_str = "0"; // get me that sweet, sweet zero - else if (o1_str == "0") - o1_str = "A"; - - // this is basically going to be "0" almost 100% of the time. - // we'll put it on the end of the string so it's most likely not output - byte otherFlags2 = (byte)( - (byte)instance.Arch << 0 // 2 bits - ); - var o2_str = otherFlags2.ToString("X1"); Debug.Assert(o2_str.Length == 1); - - // ordering: put DB and D on the end, they're likely to be zero and compressible - string data = - flagTxt + // 1 - o1_str + // 1 - instance.DataBank.ToString("X2") + // 2 - instance.DirectPage.ToString("X4") + // 4 - o2_str; // 1 - - Debug.Assert(data.Length == 9); - - // light compression: chop off any trailing zeroes. - // this alone saves a giant amount of space. - data = data.TrimEnd(new Char[] {'0'}); - - // future compression but dilutes readability: - // if type is opcode or operand, combine - - return data; + loadingProject.Data.CopyRomDataIn(rom); } - } - public static void SaveProject(string filename) - { - var serializer = new ConfigurationContainer() - .Type().Register().Serializer().Using(TableDataSerializer.Default) - .UseOptimizedNamespaces() //If you want to have all namespaces in root element - .Create(); - - var xml = serializer.Serialize( - new XmlWriterSettings { - Indent = true - }, Data.Inst); - - File.WriteAllText(filename + ".xml", xml); + return loadingProject; } - public static void SaveProjectORIG(string filename) + public void SaveProjectORIG(string filename) { try { @@ -349,7 +164,7 @@ public static void SaveProjectORIG(string filename) File.WriteAllBytes(filename, everything); unsavedChanges = false; - currentFile = filename; + currentProjectFile = filename; } catch (Exception e) { @@ -357,7 +172,7 @@ public static void SaveProjectORIG(string filename) } } - private static byte[] SaveVersion(int version) + private byte[] SaveVersion(int version) { void SaveStringToBytes(string str, List bytes) { @@ -379,14 +194,23 @@ void SaveStringToBytes(string str, List bytes) int size = Data.Inst.GetROMSize(); byte[] romSettings = new byte[31]; + + // save these two romSettings[0] = (byte)Data.Inst.GetROMMapMode(); romSettings[1] = (byte)Data.Inst.GetROMSpeed(); + + // save the size, 4 bytes Util.IntegerIntoByteArray(size, romSettings, 2); - for (int i = 0; i < 0x15; i++) romSettings[6 + i] = (byte)Data.Inst.GetROMByte(Util.ConvertSNEStoPC(0xFFC0 + i)); - for (int i = 0; i < 4; i++) romSettings[27 + i] = (byte)Data.Inst.GetROMByte(Util.ConvertSNEStoPC(0xFFDC + i)); + + var romName = GetRomNameFromRomBytes(); + romName.ToCharArray().CopyTo(romSettings, 6); + + var romChecksum = GetRomCheckSumsFromRomBytes(); + BitConverter.GetBytes(romChecksum).CopyTo(romSettings, 27); // TODO put selected offset in save file + // save all labels ad comments List label = new List(), comment = new List(); var all_labels = Data.Inst.GetAllLabels(); var all_comments = Data.Inst.GetAllComments(); @@ -410,6 +234,7 @@ void SaveStringToBytes(string str, List bytes) SaveStringToBytes(pair.Value, comment); } + // save current Rom full path - "D:\projects\cthack\rom\ct-orig.smc" byte[] romLocation = Util.StringToByteArray(currentROMFile); byte[] data = new byte[romSettings.Length + romLocation.Length + 8 * size + label.Count + comment.Count]; @@ -432,7 +257,26 @@ void SaveStringToBytes(string str, List bytes) return data; } - public static bool TryOpenProject(string filename, OpenFileDialog open) + private static byte[] GetRomBytes(int pcOffset, int count) + { + byte[] output = new byte[count]; + for (int i = 0; i < output.Length; i++) + output[i] = (byte)Data.Inst.GetROMByte(Util.ConvertSNEStoPC(pcOffset + i)); + + return output; + } + + private static string GetRomNameFromRomBytes() + { + return System.Text.Encoding.UTF8.GetString(GetRomBytes(0xFFC0, 21)); + } + + private static int GetRomCheckSumsFromRomBytes() + { + return Util.ByteArrayToInteger(GetRomBytes(0xFFDC, 4)); + } + + public bool TryOpenProject(string filename, OpenFileDialog open) { try { @@ -452,7 +296,7 @@ public static bool TryOpenProject(string filename, OpenFileDialog open) OpenProject(version, data, open); unsavedChanges = false; - currentFile = filename; + currentProjectFile = filename; return true; } catch (Exception e) @@ -464,7 +308,7 @@ public static bool TryOpenProject(string filename, OpenFileDialog open) private delegate int AddressConverter(int address); - private static void OpenProject(int version, byte[] unzipped, OpenFileDialog open) + private void OpenProject(int version, byte[] unzipped, OpenFileDialog open) { if (version > LATEST_FILE_FORMAT_VERSION) { @@ -489,20 +333,28 @@ private static void OpenProject(int version, byte[] unzipped, OpenFileDialog ope if (version == 0) converter = Util.ConvertPCtoSNES; + // read mode, speed, size Data.ROMMapMode mode = (Data.ROMMapMode)unzipped[HEADER_SIZE]; Data.ROMSpeed speed = (Data.ROMSpeed)unzipped[HEADER_SIZE + 1]; int size = Util.ByteArrayToInteger(unzipped, HEADER_SIZE + 2); - string romName = "", romLocation = ""; - byte[] rom; + // read internal title + string romInternalTitle = ""; int pointer = HEADER_SIZE + 6; - for (int i = 0; i < 0x15; i++) romName += (char) unzipped[pointer++]; + for (int i = 0; i < 0x15; i++) romInternalTitle += (char) unzipped[pointer++]; + + // read checksums int checksums = Util.ByteArrayToInteger(unzipped, pointer); pointer += 4; - while (unzipped[pointer] != 0) romLocation += (char) unzipped[pointer++]; + + // read full filepath to the ROM .sfc file + string romFullFilepath = ""; + while (unzipped[pointer] != 0) romFullFilepath += (char) unzipped[pointer++]; pointer++; - if (ValidateROM(romLocation, romName, checksums, mode, out rom, open)) + byte[] rom; + + if (ValidateROM(romFullFilepath, romInternalTitle, checksums, mode, out rom, open)) { Data.Inst.Initiate(rom, mode, speed); @@ -517,8 +369,12 @@ private static void OpenProject(int version, byte[] unzipped, OpenFileDialog ope AliasList.me.ResetDataGrid(); ReadAliases(unzipped, ref pointer, converter, version >= 2); - ReadComments(unzipped, ref pointer, converter); + + // redundant but, needed for forwards-compatibility + InternalCheckSum = GetRomCheckSumsFromRomBytes(); + InternalRomTitleName = GetRomNameFromRomBytes(); + InternalRomSize = Data.Inst.GetROMSize(); } else { @@ -528,7 +384,7 @@ private static void OpenProject(int version, byte[] unzipped, OpenFileDialog ope // TODO: refactor ReadComments and ReadAliases into one generic list-reading function - private static void ReadComments(byte[] unzipped, ref int pointer, AddressConverter converter) + private void ReadComments(byte[] unzipped, ref int pointer, AddressConverter converter) { var count = Util.ByteArrayToInteger(unzipped, pointer); pointer += 4; @@ -544,7 +400,7 @@ private static void ReadComments(byte[] unzipped, ref int pointer, AddressConver } } - private static void ReadAliases(byte[] unzipped, ref int pointer, AddressConverter converter, bool readAliasComments) + private void ReadAliases(byte[] unzipped, ref int pointer, AddressConverter converter, bool readAliasComments) { int count = Util.ByteArrayToInteger(unzipped, pointer); pointer += 4; @@ -564,11 +420,11 @@ private static void ReadAliases(byte[] unzipped, ref int pointer, AddressConvert } } - private static bool ValidateROM(string filename, string romName, int checksums, Data.ROMMapMode mode, out byte[] rom, OpenFileDialog open) + private bool ValidateROM(string filename, string romName, int checksums, Data.ROMMapMode mode, out byte[] rom, OpenFileDialog open) { bool validFile = false, matchingROM = false; rom = null; - open.InitialDirectory = currentFile; + open.InitialDirectory = currentProjectFile; while (!matchingROM) { @@ -637,13 +493,13 @@ private static bool ValidateROM(string filename, string romName, int checksums, return true; } - private static bool IsUncompressedProject(string filename) + private bool IsUncompressedProject(string filename) { return Path.GetExtension(filename).Equals(".dizraw", StringComparison.InvariantCultureIgnoreCase); } // https://stackoverflow.com/questions/33119119/unzip-byte-array-in-c-sharp - private static byte[] TryUnzip(byte[] data) + private byte[] TryUnzip(byte[] data) { try { @@ -661,7 +517,7 @@ private static byte[] TryUnzip(byte[] data) } } - private static byte[] TryZip(byte[] data) + private byte[] TryZip(byte[] data) { try { @@ -678,5 +534,36 @@ private static byte[] TryZip(byte[] data) return null; } } + + protected bool Equals(Project other) + { + return currentProjectFile == other.currentProjectFile && currentROMFile == other.currentROMFile && Equals(Data, other.Data) && InternalRomTitleName == other.InternalRomTitleName && InternalCheckSum == other.InternalCheckSum && InternalRomSize == other.InternalRomSize; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((Project) obj); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = (currentProjectFile != null ? currentProjectFile.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (currentROMFile != null ? currentROMFile.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (Data != null ? Data.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (InternalRomTitleName != null ? InternalRomTitleName.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ InternalCheckSum; + hashCode = (hashCode * 397) ^ InternalRomSize; + return hashCode; + } + } + + // singleton + private static readonly Lazy instance = new Lazy(() => new Project()); + public static Project Inst => instance.Value; } } diff --git a/DiztinGUIsh/static/diz/Manager.cs b/DiztinGUIsh/static/diz/Manager.cs index 2e18ee45..385eaaec 100644 --- a/DiztinGUIsh/static/diz/Manager.cs +++ b/DiztinGUIsh/static/diz/Manager.cs @@ -8,7 +8,7 @@ public class Manager { public static int Step(int offset, bool branch, bool force, int prevOffset) { - Project.unsavedChanges = true; + Project.Inst.unsavedChanges = true; switch (Data.Inst.GetArchitechture(offset)) { case Data.Architechture.CPU65C816: return CPU65C816.Step(offset, branch, force, prevOffset); @@ -20,7 +20,7 @@ public static int Step(int offset, bool branch, bool force, int prevOffset) public static int AutoStep(int offset, bool harsh, int amount) { - Project.unsavedChanges = true; + Project.Inst.unsavedChanges = true; int newOffset = offset, prevOffset = offset - 1, nextOffset = offset; if (harsh) { @@ -116,7 +116,7 @@ public static int AutoStep(int offset, bool harsh, int amount) public static int Mark(int offset, Data.FlagType type, int count) { - Project.unsavedChanges = true; + Project.Inst.unsavedChanges = true; int i, size = Data.Inst.GetROMSize(); for (i = 0; i < count && offset + i < size; i++) Data.Inst.SetFlag(offset + i, type); return offset + i < size ? offset + i : size - 1; @@ -124,7 +124,7 @@ public static int Mark(int offset, Data.FlagType type, int count) public static int MarkDataBank(int offset, int db, int count) { - Project.unsavedChanges = true; + Project.Inst.unsavedChanges = true; int i, size = Data.Inst.GetROMSize(); for (i = 0; i < count && offset + i < size; i++) Data.Inst.SetDataBank(offset + i, db); return offset + i < size ? offset + i : size - 1; @@ -132,7 +132,7 @@ public static int MarkDataBank(int offset, int db, int count) public static int MarkDirectPage(int offset, int dp, int count) { - Project.unsavedChanges = true; + Project.Inst.unsavedChanges = true; int i, size = Data.Inst.GetROMSize(); for (i = 0; i < count && offset + i < size; i++) Data.Inst.SetDirectPage(offset + i, dp); return offset + i < size ? offset + i : size - 1; @@ -140,7 +140,7 @@ public static int MarkDirectPage(int offset, int dp, int count) public static int MarkXFlag(int offset, bool x, int count) { - Project.unsavedChanges = true; + Project.Inst.unsavedChanges = true; int i, size = Data.Inst.GetROMSize(); for (i = 0; i < count && offset + i < size; i++) Data.Inst.SetXFlag(offset + i, x); return offset + i < size ? offset + i : size - 1; @@ -148,7 +148,7 @@ public static int MarkXFlag(int offset, bool x, int count) public static int MarkMFlag(int offset, bool m, int count) { - Project.unsavedChanges = true; + Project.Inst.unsavedChanges = true; int i, size = Data.Inst.GetROMSize(); for (i = 0; i < count && offset + i < size; i++) Data.Inst.SetMFlag(offset + i, m); return offset + i < size ? offset + i : size - 1; @@ -156,7 +156,7 @@ public static int MarkMFlag(int offset, bool m, int count) public static int MarkArchitechture(int offset, Data.Architechture arch, int count) { - Project.unsavedChanges = true; + Project.Inst.unsavedChanges = true; int i, size = Data.Inst.GetROMSize(); for (i = 0; i < count && offset + i < size; i++) Data.Inst.SetArchitechture(offset + i, arch); return offset + i < size ? offset + i : size - 1; @@ -213,7 +213,7 @@ public static int FixMisalignedFlags() } } - if (count > 0) Project.unsavedChanges = true; + if (count > 0) Project.Inst.unsavedChanges = true; return count; } @@ -235,7 +235,7 @@ public static void RescanInOutPoints() } } - Project.unsavedChanges = true; + Project.Inst.unsavedChanges = true; } public static int ImportUsageMap(byte[] usageMap) @@ -292,7 +292,7 @@ public static int ImportUsageMap(byte[] usageMap) } } - Project.unsavedChanges |= unsaved; + Project.Inst.unsavedChanges |= unsaved; return modified; } @@ -381,7 +381,7 @@ int GetHexValueAt(int startIndex, int length) { pc++; modified++; } while (pc < size && Data.Inst.GetFlag(pc) == Data.FlagType.Operand); - Project.unsavedChanges = true; + Project.Inst.unsavedChanges = true; return modified; } diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 155be20b..80dcc278 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -80,14 +80,14 @@ private void openLastProject() public void UpdateWindowTitle() { this.Text = - (Project.unsavedChanges ? "*" : "") + - (Project.currentFile == null ? "New Project" : Project.currentFile) + + (Project.Inst.unsavedChanges ? "*" : "") + + (Project.Inst.currentProjectFile == null ? "New Project" : Project.Inst.currentProjectFile) + " - DiztinGUIsh"; } private bool ContinueUnsavedChanges() { - if (Project.unsavedChanges) + if (Project.Inst.unsavedChanges) { DialogResult confirm = MessageBox.Show("You have unsaved changes. They will be lost if you continue.", "Unsaved Changes", MessageBoxButtons.OKCancel); @@ -108,11 +108,11 @@ private void newProjectToolStripMenuItem_Click(object sender, EventArgs e) { if (ContinueUnsavedChanges()) { - openROMFile.InitialDirectory = Project.currentFile; + openROMFile.InitialDirectory = Project.Inst.currentProjectFile; DialogResult result = openROMFile.ShowDialog(); if (result == DialogResult.OK) { - if (Project.NewProject(openROMFile.FileName)) + if (Project.Inst.NewProject(openROMFile.FileName)) { importCDLToolStripMenuItem.Enabled = true; TriggerSaveOptions(false, true); @@ -130,7 +130,7 @@ private void openProjectToolStripMenuItem_Click(object sender, EventArgs e) { if (ContinueUnsavedChanges()) { - openProjectFile.InitialDirectory = Project.currentFile; + openProjectFile.InitialDirectory = Project.Inst.currentProjectFile; DialogResult result = openProjectFile.ShowDialog(); if (result == DialogResult.OK) { @@ -164,7 +164,7 @@ private void UpdateUIFromSettings() public void openProject(string filename) { - if (!Project.TryOpenProject(filename, openROMFile)) + if (!Project.Inst.TryOpenProject(filename, openROMFile)) { LastProjectFilename = ""; } @@ -184,17 +184,17 @@ public void openProject(string filename) private void saveProjectToolStripMenuItem_Click(object sender, EventArgs e) { - Project.SaveProject(Project.currentFile); + Project.Inst.SaveProject(Project.Inst.currentProjectFile); UpdateWindowTitle(); } private void saveProjectAsToolStripMenuItem_Click(object sender, EventArgs e) { - saveProjectFile.InitialDirectory = Project.currentROMFile; + saveProjectFile.InitialDirectory = Project.Inst.currentROMFile; DialogResult result = saveProjectFile.ShowDialog(); if (result == DialogResult.OK && saveProjectFile.FileName != "") { - Project.SaveProject(saveProjectFile.FileName); + Project.Inst.SaveProject(saveProjectFile.FileName); TriggerSaveOptions(true, true); UpdateWindowTitle(); } @@ -202,7 +202,7 @@ private void saveProjectAsToolStripMenuItem_Click(object sender, EventArgs e) private void importCDLToolStripMenuItem_Click(object sender, EventArgs e) { - openCDLDialog.InitialDirectory = Project.currentFile; + openCDLDialog.InitialDirectory = Project.Inst.currentProjectFile; DialogResult result = openCDLDialog.ShowDialog(); if (result == DialogResult.OK) { @@ -238,7 +238,7 @@ private void exportLogToolStripMenuItem_Click(object sender, EventArgs e) string file = null, error = null; if (LogCreator.structure == LogCreator.FormatStructure.SingleFile) { - saveLogSingleFile.InitialDirectory = Project.currentFile; + saveLogSingleFile.InitialDirectory = Project.Inst.currentProjectFile; result = saveLogSingleFile.ShowDialog(); if (result == DialogResult.OK && saveLogSingleFile.FileName != "") { @@ -248,7 +248,7 @@ private void exportLogToolStripMenuItem_Click(object sender, EventArgs e) } else { - chooseLogFolder.SelectedPath = Path.GetDirectoryName(Project.currentFile); + chooseLogFolder.SelectedPath = Path.GetDirectoryName(Project.Inst.currentProjectFile); result = chooseLogFolder.ShowDialog(); if (result == DialogResult.OK && chooseLogFolder.SelectedPath != "") { From 32926b9d3ab318e55b25269ac062817e3a3508ac Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 22 Sep 2020 21:12:40 -0400 Subject: [PATCH 038/136] new load/save XML 100% working. just need to hook it up for real. --- DiztinGUIsh/ROMByte.cs | 7 +- DiztinGUIsh/static/Data.cs | 4 +- DiztinGUIsh/static/DataSerializer.cs | 111 ++++++++++++++++----------- DiztinGUIsh/static/Project.cs | 40 ++++------ 4 files changed, 88 insertions(+), 74 deletions(-) diff --git a/DiztinGUIsh/ROMByte.cs b/DiztinGUIsh/ROMByte.cs index 6144b6b2..ba376bcc 100644 --- a/DiztinGUIsh/ROMByte.cs +++ b/DiztinGUIsh/ROMByte.cs @@ -10,7 +10,12 @@ public class ROMByte { protected bool Equals(ROMByte other) { - return Rom == other.Rom && DataBank == other.DataBank && DirectPage == other.DirectPage && XFlag == other.XFlag && MFlag == other.MFlag && TypeFlag == other.TypeFlag && Arch == other.Arch && Point == other.Point; + return Rom == other.Rom && EqualsButNoRomByte(other); + } + + public bool EqualsButNoRomByte(ROMByte other) + { + return DataBank == other.DataBank && DirectPage == other.DirectPage && XFlag == other.XFlag && MFlag == other.MFlag && TypeFlag == other.TypeFlag && Arch == other.Arch && Point == other.Point; } public override bool Equals(object obj) diff --git a/DiztinGUIsh/static/Data.cs b/DiztinGUIsh/static/Data.cs index 7c3ac059..d05fa676 100644 --- a/DiztinGUIsh/static/Data.cs +++ b/DiztinGUIsh/static/Data.cs @@ -13,7 +13,7 @@ public class TableData { protected bool Equals(TableData other) { - return Equals(RomBytes, other.RomBytes); + return RomBytes.SequenceEqual(other.RomBytes); } public override bool Equals(object obj) @@ -40,7 +40,7 @@ public class Data { protected bool Equals(Data other) { - return alias.Equals(other.alias) && RomMapMode == other.RomMapMode && rom_speed == other.rom_speed && comment.Equals(other.comment) && table.Equals(other.table); + return alias.SequenceEqual(other.alias) && RomMapMode == other.RomMapMode && rom_speed == other.rom_speed && comment.SequenceEqual(other.comment) && table.Equals(other.table); } public override bool Equals(object obj) diff --git a/DiztinGUIsh/static/DataSerializer.cs b/DiztinGUIsh/static/DataSerializer.cs index f310eb24..fa49fbc6 100644 --- a/DiztinGUIsh/static/DataSerializer.cs +++ b/DiztinGUIsh/static/DataSerializer.cs @@ -20,10 +20,9 @@ // but, for projects with multiple collaborators using diztinGUIsh, mergability in text/git/editors/etc // is a must. We aim for a tradeoff between decent compression and some small semblance of human readability. // -// It's not.. super-pretty but it gets the job done. +// It's not.. super-pretty code, but it compresses well. sealed class TableDataSerializer : ISerializer { - public static TableDataSerializer Default { get; } = new TableDataSerializer(); TableDataSerializer() { } @@ -43,7 +42,7 @@ public TableData Get(IFormatReader parameter) // always apply options in same order here and in saving function if (options.Exists(s => s == "compress_table_1")) - UndoCompression_Table1(ref lines); + DecodeCompression_Table1(ref lines); if (options.Exists(s => s == "compress_groupblocks")) UndoCompression_GroupsBlocks(ref lines); @@ -73,7 +72,12 @@ public void Write(IFormatWriter writer, TableData instance) var lines = new List(); foreach (var rb in instance.RomBytes) { - lines.Add(EncodeByte(rb)); + var encoded = EncodeByte(rb); + lines.Add(encoded); + + // debug check, optional: + var decoded = DecodeRomByte(encoded); + Debug.Assert(decoded.EqualsButNoRomByte(rb)); } if (compress_groupblock) @@ -85,7 +89,7 @@ public void Write(IFormatWriter writer, TableData instance) if (compress_using_table_1) { options.Add("compress_table_1"); - ApplyCompression_Table1(ref lines); + EncodeCompression_Table1(ref lines); } writer.Content($"\n{string.Join(",", options)}\n"); @@ -101,22 +105,23 @@ class CompressionEntry public string Pattern; public string c; } - private static List table1 = new List - { - new CompressionEntry() {Pattern = "0001E", c="ZQ"}, - new CompressionEntry() {Pattern = "B0001", c="Zq"}, - new CompressionEntry() {Pattern = "C0001", c="ZX"}, - new CompressionEntry() {Pattern = "B7E", c="Zx"}, - new CompressionEntry() {Pattern = "07F01", c="ZY"}, - new CompressionEntry() {Pattern = "0001D", c="Zy"}, - new CompressionEntry() {Pattern = "C7E", c="ZZ"}, - new CompressionEntry() {Pattern = "07E", c="Zz"}, - new CompressionEntry() {Pattern = "00001", c="ZS"}, - new CompressionEntry() {Pattern = "0001", c="Zs"}, - }; - - private void UndoCompression_Table1(ref List lines) + { + new CompressionEntry() {Pattern = "0001E", c="ZQ"}, + new CompressionEntry() {Pattern = "B0001", c="Zq"}, + new CompressionEntry() {Pattern = "C0001", c="ZX"}, + new CompressionEntry() {Pattern = "B7E", c="Zx"}, + new CompressionEntry() {Pattern = "07F01", c="ZY"}, + new CompressionEntry() {Pattern = "0001D", c="Zy"}, + new CompressionEntry() {Pattern = "C7E", c="ZZ"}, + new CompressionEntry() {Pattern = "07E", c="Zz"}, + new CompressionEntry() {Pattern = "00001", c="ZS"}, + new CompressionEntry() {Pattern = "0001", c="Zs"}, + }; + + + + private void DecodeCompression_Table1(ref List lines) { for (int i = 0; i < lines.Count; ++i) { @@ -127,7 +132,7 @@ private void UndoCompression_Table1(ref List lines) } } - private void ApplyCompression_Table1(ref List lines) + private void EncodeCompression_Table1(ref List lines) { // kind of a manually made / crappy huffman table encoding type thing. // this is no great work of genius, more just some cheap hacks to reduce filesize @@ -278,13 +283,8 @@ private ROMByte DecodeRomByte(string line) newByte.Arch = (Data.Architechture)((o2_str >> 0) & 0x3); - // un-screw-up the base64 dumb thing we do on the encode - if (o1_str == "A") o1_str = "0"; else if (o1_str == "0") o1_str = "A"; - - var superHackyBase64 = o1_str + "A=="; // we dont care about > 6 bits. - var originalBytes = Convert.FromBase64CharArray(superHackyBase64.ToCharArray(), 0, superHackyBase64.Length); - Debug.Assert(originalBytes.Length == 1); - byte otherFlags1 = originalBytes[0]; + var otherFlags1 = DecodeHackyBase64(o1_str); + Debug.Assert(EncodeHackyBase64(otherFlags1) == o1_str); newByte.XFlag = ((otherFlags1 >> 2) & 0x1) != 0; newByte.MFlag = ((otherFlags1 >> 3) & 0x1) != 0; @@ -306,6 +306,7 @@ private ROMByte DecodeRomByte(string line) return newByte; } + private string EncodeByte(ROMByte instance) { // use a custom formatter here to save space. there are a LOT of ROMBytes. @@ -342,25 +343,11 @@ private string EncodeByte(ROMByte instance) // LEAVE OFF THE LAST 2 BITS. it'll mess with the base64 below ); // reminder: when decoding, have to cut off all but the first 6 bits - var o1_str = System.Convert.ToBase64String(new byte[] { otherFlags1 }); - Debug.Assert(o1_str.Length == 4); - Debug.Assert(o1_str.Substring(1) == "A=="); - o1_str = o1_str.Remove(1); + var o1_str = EncodeHackyBase64(otherFlags1); + Debug.Assert(DecodeHackyBase64(o1_str) == otherFlags1); if (!instance.XFlag && !instance.MFlag && instance.Point == 0) - Debug.Assert(o1_str == "A"); // sanity - - // dumbest thing in the entire world. - // the more zeroes we output, the more compressed we get. - // let's swap "A" (index 0) for "0" (index 52). - // if you got here after being really fucking confused about why - // your Base64 encoding algo wasn't working, then I owe you a beer. super-sorry. - // you are now allowed to flip your desk over. say it with me - // "Damnit Dom!!! Y U DO THIS" - if (o1_str == "A") - o1_str = "0"; // get me that sweet, sweet zero - else if (o1_str == "0") - o1_str = "A"; + Debug.Assert(o1_str == "0"); // sanity // this is basically going to be "0" almost 100% of the time. // we'll put it on the end of the string so it's most likely not output @@ -390,4 +377,38 @@ private string EncodeByte(ROMByte instance) return data; } + + private static void Swap0forA(ref string input) + { + // dumbest thing in the entire world. + // the more zeroes we output, the more compressed we get. + // let's swap "A" (index 0) for "0" (index 52). + // if you got here after being really fucking confused about why + // your Base64 encoding algo wasn't working, then I owe you a beer. super-sorry. + // you are now allowed to flip your desk over. say it with me + // "Damnit Dom!!! Y U DO THIS" + if (input == "A") + input = "0"; + else if (input == "0") + input = "A"; + } + + private static byte DecodeHackyBase64(string input) + { + Swap0forA(ref input); + var superHackyBase64 = input + "A=="; // we dont care about > 6 bits, so we can fake this. + var result = Convert.FromBase64CharArray(superHackyBase64.ToCharArray(), 0, superHackyBase64.Length); + Debug.Assert(result.Length == 1); + return result[0]; + } + + private static string EncodeHackyBase64(byte input) + { + var output = System.Convert.ToBase64String(new byte[] {input}); + Debug.Assert(output.Length == 4); + Debug.Assert(output.Substring(1) == "A=="); + output = output.Remove(1); + Swap0forA(ref output); + return output; + } } \ No newline at end of file diff --git a/DiztinGUIsh/static/Project.cs b/DiztinGUIsh/static/Project.cs index 587ca383..8c54fd40 100644 --- a/DiztinGUIsh/static/Project.cs +++ b/DiztinGUIsh/static/Project.cs @@ -1,23 +1,13 @@ using DiztinGUIsh.window; using System; -using System.Buffers.Text; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; -using System.Linq; -using System.Runtime.InteropServices; -using System.Security.Cryptography; -using System.Security.Policy; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; using System.Xml; -using System.Xml.Serialization; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; -using ExtendedXmlSerializer.ContentModel; -using ExtendedXmlSerializer.ContentModel.Format; namespace DiztinGUIsh { @@ -107,28 +97,26 @@ public void SaveProject(string filename) // TODO: figure out how to not save Project.unsavedChanges property in XML var file = filename + ".xml"; - { - var xml = GetSerializer().Serialize( - new XmlWriterSettings - { - Indent = true - }, Project.Inst); - - File.WriteAllText(file, xml); - } + var xml = GetSerializer().Serialize(new XmlWriterSettings { Indent = true }, Project.Inst); + File.WriteAllText(file, xml); - var dataRead = OpenProjectXml(file); - bool equal = dataRead.Equals(Project.Inst); + var project = OpenProjectXml(file); + DebugVerifyProjectEquality(Project.Inst, project); + } - for (int i = 0; i < dataRead.Data.table.RomBytes.Count; ++i) + private void DebugVerifyProjectEquality(Project project1, Project project2, bool deepcut=true) + { + if (deepcut) { - if (!dataRead.Data.table[i].Equals(Project.Inst.Data.table[i])) + for (int i = 0; i < project1.Data.table.RomBytes.Count; ++i) { - int y = 3; + Debug.Assert(project1.Data.table[i].Equals(project2.Data.table[i])); } - } - int x = 3; + Debug.Assert(project1.Data.table.Equals(project2.Data.table)); + Debug.Assert(project1.Data.Equals(project2.Data)); + } + Debug.Assert(project1.Equals(Project.Inst)); } public Project OpenProjectXml(string filename) From 881b091cfa88d32407fad57af1bdffd21eaacd25 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 26 Sep 2020 17:41:49 -0400 Subject: [PATCH 039/136] major refactoring completed, now just need to test more. default save format is XML all singleton access removed major rewrite to remove static access from everything, now uses regular class objects pave the way for MVC and undo/redo, multiple views of same data. --- DiztinGUIsh/DiztinGUIsh.csproj | 10 +- DiztinGUIsh/loadsave/ProjectFileManager.cs | 80 ++ DiztinGUIsh/loadsave/ProjectSerializer.cs | 43 + .../binary_serializer_old/BinarySerializer.cs | 237 +++++ .../xml_serializer}/DataSerializer.cs | 68 +- .../xml_serializer/ProjectXMLSerializer.cs | 111 +++ DiztinGUIsh/static/Data.cs | 844 ++++++++++++++---- DiztinGUIsh/static/Label.cs | 40 + DiztinGUIsh/static/LogCreator.cs | 260 +++--- DiztinGUIsh/static/Project.cs | 572 +++--------- DiztinGUIsh/static/RomBytes.cs | 60 ++ DiztinGUIsh/static/Util.cs | 523 +++++------ DiztinGUIsh/static/diz/CPU65C816.cs | 138 +-- DiztinGUIsh/static/diz/Manager.cs | 423 +-------- DiztinGUIsh/window/AliasList.cs | 66 +- DiztinGUIsh/window/MainWindow.Designer.cs | 6 +- DiztinGUIsh/window/MainWindow.cs | 617 ++++++++----- DiztinGUIsh/window/MainWindow.resx | 2 +- .../window/dialog/ExportDisassembly.cs | 46 +- DiztinGUIsh/window/dialog/GotoDialog.cs | 14 +- DiztinGUIsh/window/dialog/HarshAutoStep.cs | 71 +- DiztinGUIsh/window/dialog/ImportROMDialog.cs | 189 ++-- DiztinGUIsh/window/dialog/MarkManyDialog.cs | 20 +- .../window/dialog/MisalignmentChecker.cs | 18 +- 24 files changed, 2476 insertions(+), 1982 deletions(-) create mode 100644 DiztinGUIsh/loadsave/ProjectFileManager.cs create mode 100644 DiztinGUIsh/loadsave/ProjectSerializer.cs create mode 100644 DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs rename DiztinGUIsh/{static => loadsave/xml_serializer}/DataSerializer.cs (85%) create mode 100644 DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs create mode 100644 DiztinGUIsh/static/Label.cs create mode 100644 DiztinGUIsh/static/RomBytes.cs diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 7c20184c..33b131d6 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -107,8 +107,14 @@ + + + + - + + + Form @@ -210,6 +216,7 @@ MainWindow.cs + Designer MarkManyDialog.cs @@ -256,5 +263,6 @@ false + \ No newline at end of file diff --git a/DiztinGUIsh/loadsave/ProjectFileManager.cs b/DiztinGUIsh/loadsave/ProjectFileManager.cs new file mode 100644 index 00000000..0d9d5d45 --- /dev/null +++ b/DiztinGUIsh/loadsave/ProjectFileManager.cs @@ -0,0 +1,80 @@ +using System; +using System.IO; +using System.Windows.Forms; +using DiztinGUIsh.loadsave.binary_serializer_old; +using DiztinGUIsh.loadsave.xml_serializer; + +namespace DiztinGUIsh.loadsave +{ + static class ProjectFileManager + { + public static Project Open(string filename) + { + try + { + return DoOpen(filename); + } + catch (Exception e) + { + MessageBox.Show(e.Message, "Error opening project file", MessageBoxButtons.OK, MessageBoxIcon.Error); + return null; + } + } + + private static Project DoOpen(string filename) + { + var data = File.ReadAllBytes(filename); + + if (!IsUncompressedProject(filename)) + data = Util.TryUnzip(data); + + var serializer = GetSerializerForFormat(data); + var project = serializer.Load(data); + + project.ProjectFileName = filename; + + return project; + } + + private static ProjectSerializer GetSerializerForFormat(byte[] data) + { + if (BinarySerializer.IsBinaryFileFormat(data)) + return new BinarySerializer(); + + return new ProjectXmlSerializer(); + } + + private static bool IsUncompressedProject(string filename) + { + return Path.GetExtension(filename).Equals(".dizraw", StringComparison.InvariantCultureIgnoreCase); + } + + public static void Save(Project project, string filename) + { + // Everything saves in XML format from here on out. + // Binary format is deprecated. + ProjectSerializer defaultSerializer = new ProjectXmlSerializer(); + + Save(project, filename, defaultSerializer); + } + + private static void Save(Project project, string filename, ProjectSerializer serializer) + { + var data = DoSave(project, filename, serializer); + + File.WriteAllBytes(filename, data); + project.UnsavedChanges = false; + project.ProjectFileName = filename; + } + + private static byte[] DoSave(Project project, string filename, ProjectSerializer serializer) + { + var data = serializer.Save(project); + + if (!IsUncompressedProject(filename)) + data = Util.TryZip(data); + + return data; + } + } +} diff --git a/DiztinGUIsh/loadsave/ProjectSerializer.cs b/DiztinGUIsh/loadsave/ProjectSerializer.cs new file mode 100644 index 00000000..e09a6271 --- /dev/null +++ b/DiztinGUIsh/loadsave/ProjectSerializer.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DiztinGUIsh.loadsave +{ + abstract class ProjectSerializer + { + public const string Watermark = "DiztinGUIsh"; + + public abstract byte[] Save(Project project); + public abstract Project Load(byte[] data); + + public void SaveToFile(Project project, string filename) + { + File.WriteAllBytes(filename, Save(project)); + } + + public Project LoadFromFile(string filename) + { + return Load(File.ReadAllBytes(filename)); + } + + private void DebugVerifyProjectEquality(Project project1, Project project2, bool deepcut = true) + { + if (deepcut) + { + for (int i = 0; i < project1.Data.RomBytes.Count; ++i) + { + Debug.Assert(project1.Data.RomBytes[i].Equals(project2.Data.RomBytes[i])); + } + + Debug.Assert(project1.Data.RomBytes.Equals(project2.Data.RomBytes)); + Debug.Assert(project1.Data.Equals(project2.Data)); + } + Debug.Assert(project1.Equals(project2)); + } + } +} diff --git a/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs b/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs new file mode 100644 index 00000000..7ba9837f --- /dev/null +++ b/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs @@ -0,0 +1,237 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using DiztinGUIsh.window; + +namespace DiztinGUIsh.loadsave.binary_serializer_old +{ + internal class BinarySerializer : ProjectSerializer + { + public const int HEADER_SIZE = 0x100; + private const int LATEST_FILE_FORMAT_VERSION = 2; + + public static bool IsBinaryFileFormat(byte[] data) + { + for (var i = 0; i < Watermark.Length; i++) { + if (data[i + 1] != (byte) Watermark[i]) + return false; + } + return true; + } + + public override byte[] Save(Project project) + { + const int versionToSave = LATEST_FILE_FORMAT_VERSION; + byte[] data = SaveVersion(project, versionToSave); + + byte[] everything = new byte[HEADER_SIZE + data.Length]; + everything[0] = versionToSave; + Util.StringToByteArray(Watermark).CopyTo(everything, 1); + data.CopyTo(everything, HEADER_SIZE); + + return data; + } + + public override Project Load(byte[] data) + { + if (!IsBinaryFileFormat(data)) + throw new InvalidDataException($"This is not a binary serialized project file!"); + + byte version = data[0]; + ValidateProjectFileVersion(version); + + var project = new Project(); + project.Data = new Data(); + + // version 0 needs to convert PC to SNES for some addresses + Util.AddressConverter converter = address => address; + if (version == 0) + converter = project.Data.ConvertPCtoSNES; + + // read mode, speed, size + project.Data.RomMapMode = (Data.ROMMapMode)data[HEADER_SIZE]; + project.Data.RomSpeed = (Data.ROMSpeed)data[HEADER_SIZE + 1]; + var size = Util.ByteArrayToInteger(data, HEADER_SIZE + 2); + + // read internal title + var pointer = HEADER_SIZE + 6; + for (var i = 0; i < 0x15; i++) + project.InternalRomGameName += (char)data[pointer++]; + + // read checksums + project.InternalCheckSum = Util.ByteArrayToInteger(data, pointer); + pointer += 4; + + // read full filepath to the ROM .sfc file + while (data[pointer] != 0) + project.AttachedRomFilename += (char)data[pointer++]; + pointer++; + + var rom = project.ReadFromOriginalRom(); + if (rom == null) + throw new Exception("Couldn't open the ROM file!"); + + project.Data.Initiate(rom, project.Data.RomMapMode, project.Data.RomSpeed); + + for (int i = 0; i < size; i++) project.Data.SetDataBank(i, data[pointer + i]); + for (int i = 0; i < size; i++) project.Data.SetDirectPage(i, data[pointer + size + i] | (data[pointer + 2 * size + i] << 8)); + for (int i = 0; i < size; i++) project.Data.SetXFlag(i, data[pointer + 3 * size + i] != 0); + for (int i = 0; i < size; i++) project.Data.SetMFlag(i, data[pointer + 4 * size + i] != 0); + for (int i = 0; i < size; i++) project.Data.SetFlag(i, (Data.FlagType)data[pointer + 5 * size + i]); + for (int i = 0; i < size; i++) project.Data.SetArchitechture(i, (Data.Architechture)data[pointer + 6 * size + i]); + for (int i = 0; i < size; i++) project.Data.SetInOutPoint(i, (Data.InOutPoint)data[pointer + 7 * size + i]); + pointer += 8 * size; + + AliasList.me.ResetDataGrid(); + ReadLabels(project, data, ref pointer, converter, version >= 2); + ReadComments(project, data, ref pointer, converter); + + // redundant but, needed for forwards-compatibility + // project.InternalRomSize = project.Data.GetROMSize(); + project.UnsavedChanges = false; + + return project; + } + + private static void SaveStringToBytes(string str, List bytes) + { + // TODO: combine with Util.StringToByteArray() probably. + if (str != null) { + foreach (var c in str) { + bytes.Add((byte)c); + } + } + bytes.Add(0); + } + + private byte[] SaveVersion(Project project, int version) + { + ValidateSaveVersion(version); + + int size = project.Data.GetROMSize(); + byte[] romSettings = new byte[31]; + + // save these two + romSettings[0] = (byte)project.Data.GetROMMapMode(); + romSettings[1] = (byte)project.Data.GetROMSpeed(); + + // save the size, 4 bytes + Util.IntegerIntoByteArray(size, romSettings, 2); + + var romName = project.Data.GetRomNameFromRomBytes(); + romName.ToCharArray().CopyTo(romSettings, 6); + + var romChecksum = project.Data.GetRomCheckSumsFromRomBytes(); + BitConverter.GetBytes(romChecksum).CopyTo(romSettings, 27); + + // TODO put selected offset in save file + + // save all labels ad comments + List label = new List(), comment = new List(); + var all_labels = project.Data.GetAllLabels(); + var all_comments = project.Data.GetAllComments(); + + Util.IntegerIntoByteList(all_labels.Count, label); + foreach (var pair in all_labels) + { + Util.IntegerIntoByteList(pair.Key, label); + + SaveStringToBytes(pair.Value.name, label); + if (version >= 2) + { + SaveStringToBytes(pair.Value.comment, label); + } + } + + Util.IntegerIntoByteList(all_comments.Count, comment); + foreach (KeyValuePair pair in all_comments) + { + Util.IntegerIntoByteList(pair.Key, comment); + SaveStringToBytes(pair.Value, comment); + } + + // save current Rom full path - "c:\whatever\someRom.sfc" + byte[] romLocation = Util.StringToByteArray(project.AttachedRomFilename); + + byte[] data = new byte[romSettings.Length + romLocation.Length + 8 * size + label.Count + comment.Count]; + romSettings.CopyTo(data, 0); + for (int i = 0; i < romLocation.Length; i++) data[romSettings.Length + i] = romLocation[i]; + + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + i] = (byte)project.Data.GetDataBank(i); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + size + i] = (byte)project.Data.GetDirectPage(i); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 2 * size + i] = (byte)(project.Data.GetDirectPage(i) >> 8); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 3 * size + i] = (byte)(project.Data.GetXFlag(i) ? 1 : 0); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 4 * size + i] = (byte)(project.Data.GetMFlag(i) ? 1 : 0); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 5 * size + i] = (byte)project.Data.GetFlag(i); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 6 * size + i] = (byte)project.Data.GetArchitechture(i); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 7 * size + i] = (byte)project.Data.GetInOutPoint(i); + // ??? + label.CopyTo(data, romSettings.Length + romLocation.Length + 8 * size); + comment.CopyTo(data, romSettings.Length + romLocation.Length + 8 * size + label.Count); + // ??? + + return data; + } + + private static void ValidateSaveVersion(int version) { + if (version < 1 || version > LATEST_FILE_FORMAT_VERSION) { + throw new ArgumentException($"Saving: Invalid save version requested for saving: {version}."); + } + } + + private static void ValidateProjectFileVersion(int version) + { + if (version > LATEST_FILE_FORMAT_VERSION) + { + throw new ArgumentException( + "This DiztinGUIsh file uses a newer file format! You'll need to download the newest version of DiztinGUIsh to open it."); + } + else if (version != LATEST_FILE_FORMAT_VERSION) + { + MessageBox.Show( + "This project file is in an older format.\n" + + "You may want to back up your work or 'Save As' in case the conversion goes wrong.\n" + + "The project file will be untouched until it is saved again.", + "Project File Out of Date", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + + if (version < 0) + { + throw new ArgumentException($"Invalid project file version detected: {version}."); + } + } + + private void ReadComments(Project project, byte[] bytes, ref int pointer, Util.AddressConverter converter) + { + const int stringsPerEntry = 1; + pointer += Util.ReadStringsTable(bytes, pointer, stringsPerEntry, converter, + (int offset, string[] strings) => + { + Debug.Assert(strings.Length == 1); + project.Data.AddComment(offset, strings[0], true); + }); + } + + private void ReadLabels(Project project, byte[] bytes, ref int pointer, Util.AddressConverter converter, bool readAliasComments) + { + var stringsPerEntry = readAliasComments ? 2 : 1; + pointer += Util.ReadStringsTable(bytes, pointer, stringsPerEntry, converter, + (int offset, string[] strings) => + { + Debug.Assert(strings.Length == stringsPerEntry); + var label = new Label + { + name = strings[0], + comment = strings.ElementAtOrDefault(1) + }; + label.CleanUp(); + project.Data.AddLabel(offset, label, true); + }); + } + } +} diff --git a/DiztinGUIsh/static/DataSerializer.cs b/DiztinGUIsh/loadsave/xml_serializer/DataSerializer.cs similarity index 85% rename from DiztinGUIsh/static/DataSerializer.cs rename to DiztinGUIsh/loadsave/xml_serializer/DataSerializer.cs index fa49fbc6..c85e3808 100644 --- a/DiztinGUIsh/static/DataSerializer.cs +++ b/DiztinGUIsh/loadsave/xml_serializer/DataSerializer.cs @@ -21,18 +21,22 @@ // is a must. We aim for a tradeoff between decent compression and some small semblance of human readability. // // It's not.. super-pretty code, but it compresses well. -sealed class TableDataSerializer : ISerializer +sealed class RomBytesSerializer : ISerializer { - public static TableDataSerializer Default { get; } = new TableDataSerializer(); + // let the outer XML class do the heavy lifting on versioning. + // but, let's add one here just because this specific class is complex. + private const int CURRENT_DATA_FORMAT_VERSION = 200; - TableDataSerializer() { } + public static RomBytesSerializer Default { get; } = new RomBytesSerializer(); + + RomBytesSerializer() { } public bool compress_groupblock = true; public bool compress_using_table_1 = true; - public TableData Get(IFormatReader parameter) + public RomBytes Get(IFormatReader parameter) { - var tableDataOut = new TableData(); + var romBytesOut = new RomBytes(); var lines = parameter.Content().Split(new char[] { '\n' }, 3).ToList(); var options = lines[1].Split(new char[] { ',' }).ToList(); @@ -40,19 +44,21 @@ public TableData Get(IFormatReader parameter) if (lines[lines.Count - 1] == "") lines.RemoveAt(lines.Count - 1); + CheckForCompatibleVersion(options); + // always apply options in same order here and in saving function if (options.Exists(s => s == "compress_table_1")) DecodeCompression_Table1(ref lines); if (options.Exists(s => s == "compress_groupblocks")) - UndoCompression_GroupsBlocks(ref lines); + DecodeCompression_GroupsBlocks(ref lines); int lineNum = 0; try { foreach (var line in lines) { - tableDataOut.RomBytes.Add(DecodeRomByte(line)); + romBytesOut.Add(DecodeRomByte(line)); lineNum++; } } @@ -62,15 +68,51 @@ public TableData Get(IFormatReader parameter) throw; } - return tableDataOut; + return romBytesOut; + } + + private static void CheckForCompatibleVersion(IEnumerable options) + { + try + { + var versionOption = options.SingleOrDefault(s => s.Contains("version:")); + + if (versionOption == null) + { + throw new InvalidDataException( + $"Exactly 1 'version' tag must be in options, unable to continue"); + } + + var split = versionOption.Split(':'); + Debug.Assert(split.Length == 2); + if (!int.TryParse(split[1], out var version_num)) + throw new InvalidDataException( + $"Couldn't parse version # from version tag"); + + if (version_num > CURRENT_DATA_FORMAT_VERSION) + throw new InvalidDataException( + $"Newer file format detected: {version_num}. This version of distinguish only supports data table formats up to {CURRENT_DATA_FORMAT_VERSION}."); + + // In the future, we can add migrations here for older version. For now, just reject it. + if (version_num < CURRENT_DATA_FORMAT_VERSION) + throw new InvalidDataException( + $"Newer file format detected: {version_num}. This version of distinguish only supports data table formats up to {CURRENT_DATA_FORMAT_VERSION}."); + } + catch (Exception ex) + { + throw new InvalidDataException($"Data table loader: Version error: {ex.Message}"); + } } - public void Write(IFormatWriter writer, TableData instance) + public void Write(IFormatWriter writer, RomBytes instance) { - var options = new List(); + var options = new List + { + $"version:{CURRENT_DATA_FORMAT_VERSION}", + }; var lines = new List(); - foreach (var rb in instance.RomBytes) + foreach (var rb in instance) { var encoded = EncodeByte(rb); lines.Add(encoded); @@ -119,8 +161,6 @@ class CompressionEntry new CompressionEntry() {Pattern = "0001", c="Zs"}, }; - - private void DecodeCompression_Table1(ref List lines) { for (int i = 0; i < lines.Count; ++i) @@ -149,7 +189,7 @@ private void EncodeCompression_Table1(ref List lines) } } - private void UndoCompression_GroupsBlocks(ref List lines) + private void DecodeCompression_GroupsBlocks(ref List lines) { var output = new List(); diff --git a/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs b/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs new file mode 100644 index 00000000..12aa87fd --- /dev/null +++ b/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Xml; +using ExtendedXmlSerializer; +using ExtendedXmlSerializer.Configuration; + +namespace DiztinGUIsh.loadsave.xml_serializer +{ + internal class ProjectXmlSerializer : ProjectSerializer + { + // NEVER CHANGE THIS ONE. + private const int FIRST_SAVE_FORMAT_VERSION = 100; + + // increment this if you change the XML file format + private const int CURRENT_SAVE_FORMAT_VERSION = FIRST_SAVE_FORMAT_VERSION; + + // update this if we are dropped support for really old save formats. + private const int EARLIEST_SUPPORTED_SAVE_FORMAT_VERSION = FIRST_SAVE_FORMAT_VERSION; + + private static IExtendedXmlSerializer GetSerializer() + { + return new ConfigurationContainer() + .Type().Register().Serializer().Using(RomBytesSerializer.Default) + .UseOptimizedNamespaces() + .UseAutoFormatting() + .EnableImplicitTyping(typeof(Data)) + .EnableImplicitTyping(typeof(Label)) + .Create(); + } + + internal class Root + { + // XML serializer specific metadata, top-level deserializer. + // This is unique to JUST the XML serializer, doesn't affect any other types of serializers. + // i.e. there is no global 'save format version' number, it's serializer-specific. + // + // NOTE: Please try and keep 'Root' unchanged and as generic as possible. It's way better + // to change 'Project' + public int SaveVersion { get; set; } = -1; + public string Watermark { get; set; } + + + // The actual project itself. Almost any change you want to make should go in here. + public Project Project { get; set; } + }; + + public override byte[] Save(Project project) + { + // TODO: figure out how to not save Project.unsavedChanges property in XML + + // Wrap the project in a top-level root element with some info about the XML file + // format version. Note that each serializer has its own implementation of this. + + var rootElement = new Root() + { + SaveVersion = CURRENT_SAVE_FORMAT_VERSION, + Watermark = ProjectSerializer.Watermark, + Project = project, + }; + + var xml_str = GetSerializer().Serialize( + new XmlWriterSettings { Indent = true }, + rootElement); + + var final_bytes = Encoding.UTF8.GetBytes(xml_str); + + // if you want some sanity checking, run this to verify everything saved correctly + // DebugVerifyProjectEquality(OpenProjectXml(file), project); + + return final_bytes; + } + + public override Project Load(byte[] data) + { + // TODO: it would be much more reliable if we could deserialize the Root element ALONE + // first, check for version/watermark, and only then try to deserialize the rest of the doc. + // + // Also, we can do data migrations based on versioning, and ExtendedXmlSerializer + + var text = Encoding.UTF8.GetString(data); + var root = GetSerializer().Deserialize(text); + + if (root.Watermark != Watermark) + throw new InvalidDataException("This file doesn't appear to be a valid DiztinGUIsh XML file (missing/invalid watermark element in XML)"); + + if (root.SaveVersion > CURRENT_SAVE_FORMAT_VERSION) + throw new InvalidDataException($"Save file version is newer than this version of DiztinGUIsh, likely can't be opened safely. This save file version = '{root.SaveVersion}', our highest supported version is {CURRENT_SAVE_FORMAT_VERSION}"); + + // Apply any migrations here for older save file formats. Right now, + // there aren't any because we're on the first revision. + // The XML serialization might be fairly forgiving of most kinds of changes, + // so you may not have to write migrations unless properties are renamed or deleted. + if (root.SaveVersion < CURRENT_SAVE_FORMAT_VERSION) + { + throw new InvalidDataException($"Save file version is newer than this version of DiztinGUIsh, likely can't be opened safely. This save file version = '{root.SaveVersion}', our highest supported version is {CURRENT_SAVE_FORMAT_VERSION}"); + } + + var project = root.Project; + + project.PostSerializationLoad(); + return project; + } + } +} diff --git a/DiztinGUIsh/static/Data.cs b/DiztinGUIsh/static/Data.cs index d05fa676..ceb06187 100644 --- a/DiztinGUIsh/static/Data.cs +++ b/DiztinGUIsh/static/Data.cs @@ -3,78 +3,16 @@ using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; +using System.IO; using System.Linq; +using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; namespace DiztinGUIsh { - public class TableData - { - protected bool Equals(TableData other) - { - return RomBytes.SequenceEqual(other.RomBytes); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((TableData) obj); - } - - public override int GetHashCode() - { - return (RomBytes != null ? RomBytes.GetHashCode() : 0); - } - - public List RomBytes { get; } = new List(); - public ROMByte this[int i] { - get => RomBytes[i]; - set => RomBytes[i] = value; - } - } - public class Data { - protected bool Equals(Data other) - { - return alias.SequenceEqual(other.alias) && RomMapMode == other.RomMapMode && rom_speed == other.rom_speed && comment.SequenceEqual(other.comment) && table.Equals(other.table); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((Data) obj); - } - - public override int GetHashCode() - { - unchecked - { - var hashCode = alias.GetHashCode(); - hashCode = (hashCode * 397) ^ (int) RomMapMode; - hashCode = (hashCode * 397) ^ (int) rom_speed; - hashCode = (hashCode * 397) ^ comment.GetHashCode(); - hashCode = (hashCode * 397) ^ table.GetHashCode(); - return hashCode; - } - } - - // singleton - // private static readonly Lazy instance = new Lazy(() => new Data()); - // public static Data Inst => instance.Value; - - // backwards compatibility only. from here on out, everything should reference Project.Inst.Data - public static Data Inst => Project.Inst.Data; - - - // public Data() {} // should be non-public for singleton but whatev for now. - // we shouldn't use singleton anyway, we should just pass around Data. - public enum FlagType : byte { Unreached = 0x00, @@ -109,6 +47,7 @@ public enum InOutPoint : byte ReadPoint = 0x08 } + // TODO: move BsnesPlusUsage stuff to its own class outside of Data [Flags] public enum BsnesPlusUsage : byte { @@ -136,58 +75,25 @@ public const int EXHIROM_SETTING_OFFSET = 0x40FFD5, EXLOROM_SETTING_OFFSET = 0x407FD5; - // Note: order of these properties matters for the load/save process. Keep 'table' LAST + // Note: order of these properties matters for the load/save process. Keep 'RomBytes' LAST public ROMMapMode RomMapMode { get; set; } - public ROMSpeed rom_speed { get; set; } - public Dictionary comment { get; set; } - public TableData table { get; set; } + public ROMSpeed RomSpeed { get; set; } + public Dictionary Comments { get; set; } + public RomBytes RomBytes { get; set; } - - public class AliasInfo - { - protected bool Equals(AliasInfo other) - { - return name == other.name && comment == other.comment; - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((AliasInfo) obj); - } - - public override int GetHashCode() - { - unchecked - { - return ((name != null ? name.GetHashCode() : 0) * 397) ^ (comment != null ? comment.GetHashCode() : 0); - } - } - - public string name = ""; // name of the label - public string comment = ""; // user-generated text, comment only - - public void CleanUp() - { - if (comment == null) comment = ""; - if (name == null) name = ""; - } - } - public Dictionary alias; + public Dictionary alias; public void Initiate(byte[] data, ROMMapMode mode, ROMSpeed speed) { RomMapMode = mode; - rom_speed = speed; + RomSpeed = speed; int size = data.Length; - alias = new Dictionary(); - comment = new Dictionary(); - table = new TableData(); + alias = new Dictionary(); + Comments = new Dictionary(); + RomBytes = new RomBytes(); for (int i = 0; i < size; i++) { - ROMByte r = new ROMByte + var r = new ROMByte { Rom = data[i], DataBank = 0, @@ -198,27 +104,46 @@ public void Initiate(byte[] data, ROMMapMode mode, ROMSpeed speed) Arch = Architechture.CPU65C816, Point = 0 }; - table.RomBytes.Add(r); + RomBytes.Add(r); } } + private byte[] GetRomBytes(int pcOffset, int count) + { + byte[] output = new byte[count]; + for (int i = 0; i < output.Length; i++) + output[i] = (byte)GetROMByte(ConvertSNEStoPC(pcOffset + i)); + + return output; + } + + public string GetRomNameFromRomBytes() + { + return System.Text.Encoding.UTF8.GetString(GetRomBytes(0xFFC0, 21)); + } + + public int GetRomCheckSumsFromRomBytes() + { + return Util.ByteArrayToInteger(GetRomBytes(0xFFDC, 4)); + } + public void CopyRomDataIn(byte[] data) { int size = data.Length; - Debug.Assert(table.RomBytes.Count == size); + Debug.Assert(RomBytes.Count == size); for (int i = 0; i < size; i++) { - table[i].Rom = data[i]; + RomBytes[i].Rom = data[i]; } } - public void Restore(TableData l = null, ROMMapMode m = ROMMapMode.LoROM, ROMSpeed s = ROMSpeed.Unknown, Dictionary a = null, Dictionary c = null) + public void Restore(RomBytes l = null, ROMMapMode m = ROMMapMode.LoROM, ROMSpeed s = ROMSpeed.Unknown, Dictionary a = null, Dictionary c = null) { - table = l ?? table; + RomBytes = l ?? RomBytes; RomMapMode = s == ROMSpeed.Unknown ? RomMapMode : m; - rom_speed = s == ROMSpeed.Unknown ? rom_speed : s; + RomSpeed = s == ROMSpeed.Unknown ? RomSpeed : s; alias = a ?? alias; - comment = c ?? comment; + Comments = c ?? Comments; } public ROMMapMode GetROMMapMode() @@ -228,120 +153,120 @@ public ROMMapMode GetROMMapMode() public ROMSpeed GetROMSpeed() { - return rom_speed; + return RomSpeed; } - public TableData GetTable() + public RomBytes GetTable() { - return table; + return RomBytes; } public int GetROMByte(int i) { - return table[i].Rom; + return RomBytes[i].Rom; } public int GetROMSize() { - return table == null ? 0 : table.RomBytes.Count; + return RomBytes?.Count ?? 0; } public FlagType GetFlag(int i) { - return table[i].TypeFlag; + return RomBytes[i].TypeFlag; } public void SetFlag(int i, FlagType flag) { - table[i].TypeFlag = flag; + RomBytes[i].TypeFlag = flag; } public Architechture GetArchitechture(int i) { - return table[i].Arch; + return RomBytes[i].Arch; } public void SetArchitechture(int i, Architechture arch) { - table[i].Arch = arch; + RomBytes[i].Arch = arch; } public InOutPoint GetInOutPoint(int i) { - return table[i].Point; + return RomBytes[i].Point; } public void SetInOutPoint(int i, InOutPoint point) { - table[i].Point |= point; + RomBytes[i].Point |= point; } public void ClearInOutPoint(int i) { - table[i].Point = 0; + RomBytes[i].Point = 0; } public int GetDataBank(int i) { - return table[i].DataBank; + return RomBytes[i].DataBank; } public void SetDataBank(int i, int dbank) { - table[i].DataBank = (byte)dbank; + RomBytes[i].DataBank = (byte)dbank; } public int GetDirectPage(int i) { - return table[i].DirectPage; + return RomBytes[i].DirectPage; } public void SetDirectPage(int i, int dpage) { - table[i].DirectPage = 0xFFFF & dpage; + RomBytes[i].DirectPage = 0xFFFF & dpage; } public bool GetXFlag(int i) { - return table[i].XFlag; + return RomBytes[i].XFlag; } public void SetXFlag(int i, bool x) { - table[i].XFlag = x; + RomBytes[i].XFlag = x; } public bool GetMFlag(int i) { - return table[i].MFlag; + return RomBytes[i].MFlag; } public void SetMFlag(int i, bool m) { - table[i].MFlag = m; + RomBytes[i].MFlag = m; } public int GetMXFlags(int i) { - return (table[i].MFlag ? 0x20 : 0) | (table[i].XFlag ? 0x10 : 0); + return (RomBytes[i].MFlag ? 0x20 : 0) | (RomBytes[i].XFlag ? 0x10 : 0); } public void SetMXFlags(int i, int mx) { - table[i].MFlag = ((mx & 0x20) != 0); - table[i].XFlag = ((mx & 0x10) != 0); + RomBytes[i].MFlag = ((mx & 0x20) != 0); + RomBytes[i].XFlag = ((mx & 0x10) != 0); } public string GetLabelName(int i) { - if (alias.TryGetValue(i, out AliasInfo val)) + if (alias.TryGetValue(i, out var val)) return val?.name ?? ""; return ""; } public string GetLabelComment(int i) { - if (alias.TryGetValue(i, out AliasInfo val)) + if (alias.TryGetValue(i, out var val)) return val?.comment ?? ""; return ""; @@ -352,7 +277,7 @@ public void DeleteAllLabels() alias.Clear(); } - public void AddLabel(int i, AliasInfo v, bool overwrite) + public void AddLabel(int i, Label v, bool overwrite) { if (v == null) { @@ -367,25 +292,25 @@ public void AddLabel(int i, AliasInfo v, bool overwrite) alias.Remove(i); AliasList.me.RemoveRow(i); } - if (!alias.ContainsKey(i)) - { - v.CleanUp(); - alias.Add(i, v); - AliasList.me.AddRow(i, v); - } + if (alias.ContainsKey(i)) + return; + + v.CleanUp(); + + alias.Add(i, v); + AliasList.me.AddRow(i, v); } } - public Dictionary GetAllLabels() + public Dictionary GetAllLabels() { return alias; } public string GetComment(int i) { - string val; - if (comment.TryGetValue(i, out val)) return val; + if (Comments.TryGetValue(i, out var val)) return val; return ""; } @@ -393,20 +318,20 @@ public void AddComment(int i, string v, bool overwrite) { if (v == null) { - if (comment.ContainsKey(i)) comment.Remove(i); + if (Comments.ContainsKey(i)) Comments.Remove(i); } else { - if (comment.ContainsKey(i) && overwrite) comment.Remove(i); - if (!comment.ContainsKey(i)) comment.Add(i, v); + if (Comments.ContainsKey(i) && overwrite) Comments.Remove(i); + if (!Comments.ContainsKey(i)) Comments.Add(i, v); } } public Dictionary GetAllComments() { - return comment; + return Comments; } - public int GetRomSettingOffset(ROMMapMode mode) + public static int GetRomSettingOffset(ROMMapMode mode) { switch (mode) { @@ -417,5 +342,616 @@ public int GetRomSettingOffset(ROMMapMode mode) } return LOROM_SETTING_OFFSET; } + + + public int ConvertPCtoSNES(int offset) + { + return Util.ConvertPCtoSNES(offset, RomMapMode, GetROMSpeed()); + } + + public int GetROMWord(int offset) + { + if (offset + 1 < GetROMSize()) + return GetROMByte(offset) + (GetROMByte(offset + 1) << 8); + return -1; + } + + public int GetROMLong(int offset) + { + if (offset + 2 < GetROMSize()) + return GetROMByte(offset) + (GetROMByte(offset + 1) << 8) + (GetROMByte(offset + 2) << 16); + return -1; + } + + public int GetROMDoubleWord(int offset) + { + if (offset + 3 < GetROMSize()) + return GetROMByte(offset) + (GetROMByte(offset + 1) << 8) + (GetROMByte(offset + 2) << 16) + (GetROMByte(offset + 3) << 24); + return -1; + } + + public int GetIntermediateAddressOrPointer(int offset) + { + switch (GetFlag(offset)) + { + case Data.FlagType.Unreached: + case Data.FlagType.Opcode: + return GetIntermediateAddress(offset, true); + case Data.FlagType.Pointer16Bit: + int bank = GetDataBank(offset); + return (bank << 16) | GetROMWord(offset); + case Data.FlagType.Pointer24Bit: + case Data.FlagType.Pointer32Bit: + return GetROMLong(offset); + } + return -1; + } + + public int OpcodeByteLength(int offset) + { + switch (GetArchitechture(offset)) + { + case Data.Architechture.CPU65C816: return CPU65C816.GetInstructionLength(offset); + case Data.Architechture.APUSPC700: return 1; + case Data.Architechture.GPUSuperFX: return 1; + } + + return 1; + } + + private int UnmirroredOffset(int offset) + { + return Util.UnmirroredOffset(offset, GetROMSize()); + } + + public string GetFormattedBytes(int offset, int step, int bytes) + { + string res = ""; + switch (step) + { + case 1: res = "db "; break; + case 2: res = "dw "; break; + case 3: res = "dl "; break; + case 4: res = "dd "; break; + } + + for (int i = 0; i < bytes; i += step) + { + if (i > 0) res += ","; + + switch (step) + { + case 1: res += Util.NumberToBaseString(GetROMByte(offset + i), Util.NumberBase.Hexadecimal, 2, true); break; + case 2: res += Util.NumberToBaseString(GetROMWord(offset + i), Util.NumberBase.Hexadecimal, 4, true); break; + case 3: res += Util.NumberToBaseString(GetROMLong(offset + i), Util.NumberBase.Hexadecimal, 6, true); break; + case 4: res += Util.NumberToBaseString(GetROMDoubleWord(offset + i), Util.NumberBase.Hexadecimal, 8, true); break; + } + } + + return res; + } + + public int ConvertSNEStoPC(int address) + { + return Util.ConvertSNESToPC(address, RomMapMode, GetROMSize()); + } + + public string GetPointer(int offset, int bytes) + { + int ia = -1; + string format = "", param = ""; + switch (bytes) + { + case 2: + ia = (GetDataBank(offset) << 16) | GetROMWord(offset); + format = "dw {0}"; + param = Util.NumberToBaseString(GetROMWord(offset), Util.NumberBase.Hexadecimal, 4, true); + break; + case 3: + ia = GetROMLong(offset); + format = "dl {0}"; + param = Util.NumberToBaseString(GetROMLong(offset), Util.NumberBase.Hexadecimal, 6, true); + break; + case 4: + ia = GetROMLong(offset); + format = "dl {0}" + string.Format(" : db {0}", Util.NumberToBaseString(GetROMByte(offset + 3), Util.NumberBase.Hexadecimal, 2, true)); + param = Util.NumberToBaseString(GetROMLong(offset), Util.NumberBase.Hexadecimal, 6, true); + break; + } + + int pc = ConvertSNEStoPC(ia); + if (pc >= 0 && GetLabelName(ia) != "") param = GetLabelName(ia); + return string.Format(format, param); + } + + public string GetFormattedText(int offset, int bytes) + { + string text = "db \""; + for (int i = 0; i < bytes; i++) text += (char)GetROMByte(offset + i); + return text + "\""; + } + + public string GetDefaultLabel(int address) + { + var pc = ConvertSNEStoPC(address); + return + $"{Util.TypeToLabel(GetFlag(pc))}_{Util.NumberToBaseString(address, Util.NumberBase.Hexadecimal, 6)}"; + } + + + //private Project Project { get; set; } + + //private Data Data => Project.Data; + private CPU65C816 CPU65C816 { get; set; } + + public Data() + { + // Project = project; + CPU65C816 = new CPU65C816(this); + } + + public int Step(int offset, bool branch, bool force, int prevOffset) + { + switch (GetArchitechture(offset)) + { + case Data.Architechture.CPU65C816: return CPU65C816.Step(offset, branch, force, prevOffset); + case Data.Architechture.APUSPC700: return offset; + case Data.Architechture.GPUSuperFX: return offset; + } + return offset; + } + + public int AutoStep(int offset, bool harsh, int amount) + { + int newOffset = offset, prevOffset = offset - 1, nextOffset = offset; + if (harsh) + { + while (newOffset < offset + amount) + { + nextOffset = Step(newOffset, false, true, prevOffset); + prevOffset = newOffset; + newOffset = nextOffset; + } + } + else + { + Stack stack = new Stack(); + List seenBranches = new List(); + bool keepGoing = true; + + while (keepGoing) + { + switch (GetArchitechture(newOffset)) + { + case Data.Architechture.CPU65C816: + if (seenBranches.Contains(newOffset)) + { + keepGoing = false; + break; + } + + int opcode = GetROMByte(newOffset); + + nextOffset = Step(newOffset, false, false, prevOffset); + int jumpOffset = Step(newOffset, true, false, prevOffset); + + if (opcode == 0x40 || opcode == 0xCB || opcode == 0xDB || opcode == 0xF8 // RTI WAI STP SED + || opcode == 0xFB || opcode == 0x00 || opcode == 0x02 || opcode == 0x42 // XCE BRK COP WDM + || opcode == 0x6C || opcode == 0x7C || opcode == 0xDC || opcode == 0xFC // JMP JMP JML JSR + ) keepGoing = false; + + if (opcode == 0x4C || opcode == 0x5C || opcode == 0x80 || opcode == 0x82 // JMP JML BRA BRL + || opcode == 0x10 || opcode == 0x30 || opcode == 0x50 || opcode == 0x70 // BPL BMI BVC BVS + || opcode == 0x90 || opcode == 0xB0 || opcode == 0xD0 || opcode == 0xF0 // BCC BCS BNE BEQ + ) seenBranches.Add(newOffset); + + if (opcode == 0x08) // PHP + { + stack.Push(GetMXFlags(newOffset)); + } + else if (opcode == 0x28) // PLP + { + if (stack.Count == 0) + { + keepGoing = false; break; + } + else + { + SetMXFlags(newOffset, stack.Pop()); + } + } + + if (opcode == 0x60 || opcode == 0x6B) // RTS RTL + { + if (stack.Count == 0) + { + keepGoing = false; + break; + } + else + { + prevOffset = newOffset; + newOffset = stack.Pop(); + } + } + else if (opcode == 0x20 || opcode == 0x22) // JSR JSL + { + stack.Push(nextOffset); + prevOffset = newOffset; + newOffset = jumpOffset; + } + else + { + prevOffset = newOffset; + newOffset = nextOffset; + } + break; + case Data.Architechture.APUSPC700: + case Data.Architechture.GPUSuperFX: + nextOffset = Step(newOffset, false, true, prevOffset); + prevOffset = newOffset; + newOffset = nextOffset; + break; + } + + Data.FlagType flag = GetFlag(newOffset); + if (!(flag == Data.FlagType.Unreached || flag == Data.FlagType.Opcode || flag == Data.FlagType.Operand)) keepGoing = false; + } + } + return newOffset; + } + + public int Mark(int offset, Data.FlagType type, int count) + { + int i, size = GetROMSize(); + for (i = 0; i < count && offset + i < size; i++) SetFlag(offset + i, type); + return offset + i < size ? offset + i : size - 1; + } + + public int MarkDataBank(int offset, int db, int count) + { + int i, size = GetROMSize(); + for (i = 0; i < count && offset + i < size; i++) SetDataBank(offset + i, db); + return offset + i < size ? offset + i : size - 1; + } + + public int MarkDirectPage(int offset, int dp, int count) + { + int i, size = GetROMSize(); + for (i = 0; i < count && offset + i < size; i++) SetDirectPage(offset + i, dp); + return offset + i < size ? offset + i : size - 1; + } + + public int MarkXFlag(int offset, bool x, int count) + { + int i, size = GetROMSize(); + for (i = 0; i < count && offset + i < size; i++) SetXFlag(offset + i, x); + return offset + i < size ? offset + i : size - 1; + } + + public int MarkMFlag(int offset, bool m, int count) + { + int i, size = GetROMSize(); + for (i = 0; i < count && offset + i < size; i++) SetMFlag(offset + i, m); + return offset + i < size ? offset + i : size - 1; + } + + public int MarkArchitechture(int offset, Data.Architechture arch, int count) + { + int i, size = GetROMSize(); + for (i = 0; i < count && offset + i < size; i++) SetArchitechture(offset + i, arch); + return offset + i < size ? offset + i : size - 1; + } + + public int GetInstructionLength(int offset) + { + switch (GetArchitechture(offset)) + { + case Data.Architechture.CPU65C816: return CPU65C816.GetInstructionLength(offset); + case Data.Architechture.APUSPC700: return 1; + case Data.Architechture.GPUSuperFX: return 1; + } + return 1; + } + + public int FixMisalignedFlags() + { + int count = 0, size = GetROMSize(); + + for (int i = 0; i < size; i++) + { + Data.FlagType flag = GetFlag(i); + + if (flag == Data.FlagType.Opcode) + { + int len = GetInstructionLength(i); + for (int j = 1; j < len && i + j < size; j++) + { + if (GetFlag(i + j) != Data.FlagType.Operand) + { + SetFlag(i + j, Data.FlagType.Operand); + count++; + } + } + i += len - 1; + } + else if (flag == Data.FlagType.Operand) + { + SetFlag(i, Data.FlagType.Opcode); + count++; + i--; + } + else if (Util.TypeStepSize(flag) > 1) + { + int step = Util.TypeStepSize(flag); + for (int j = 1; j < step; j++) + { + if (GetFlag(i + j) != flag) + { + SetFlag(i + j, flag); + count++; + } + } + i += step - 1; + } + } + + return count; + } + + public void RescanInOutPoints() + { + for (int i = 0; i < GetROMSize(); i++) ClearInOutPoint(i); + + for (int i = 0; i < GetROMSize(); i++) + { + if (GetFlag(i) == Data.FlagType.Opcode) + { + switch (GetArchitechture(i)) + { + case Data.Architechture.CPU65C816: CPU65C816.MarkInOutPoints(i); break; + case Data.Architechture.APUSPC700: break; + case Data.Architechture.GPUSuperFX: break; + } + } + } + } + + public int ImportUsageMap(byte[] usageMap) + { + int size = GetROMSize(); + int modified = 0; + int prevFlags = 0; + + for (int map = 0; map <= 0xFFFFFF; map++) + { + var i = ConvertSNEStoPC(map); + + if (i == -1 || i >= size) + { + // branch predictor may optimize this + continue; + } + + var flags = (Data.BsnesPlusUsage)usageMap[map]; + + if (flags == 0) + { + // no information available + continue; + } + + if (GetFlag(i) != Data.FlagType.Unreached) + { + // skip if there is something already set.. + continue; + } + + // opcode: 0x30, operand: 0x20 + if (flags.HasFlag(Data.BsnesPlusUsage.UsageExec)) + { + SetFlag(i, Data.FlagType.Operand); + + if (flags.HasFlag(Data.BsnesPlusUsage.UsageOpcode)) + { + prevFlags = ((int)flags & 3) << 4; + SetFlag(i, Data.FlagType.Opcode); + } + + SetMXFlags(i, prevFlags); + modified++; + } + else if (flags.HasFlag(Data.BsnesPlusUsage.UsageRead)) + { + SetFlag(i, Data.FlagType.Data8Bit); + modified++; + } + } + + return modified; + } + + + public int GetIntermediateAddress(int offset, bool resolve = false) + { + // FIX ME: log and generation of dp opcodes. search references + switch (GetArchitechture(offset)) + { + case Data.Architechture.CPU65C816: return CPU65C816.GetIntermediateAddress(offset, resolve); + case Data.Architechture.APUSPC700: return -1; + case Data.Architechture.GPUSuperFX: return -1; + } + return -1; + } + + public string GetInstruction(int offset) + { + switch (GetArchitechture(offset)) + { + case Data.Architechture.CPU65C816: return CPU65C816.GetInstruction(offset); + case Data.Architechture.APUSPC700: return ""; + case Data.Architechture.GPUSuperFX: return ""; + } + return ""; + } + + // this class exists for performance optimization ONLY. + // class representing offsets into a trace log + // we calculate it once from sample data and hang onto it + private class CachedTraceLineIndex + { + private string sample = + "028cde rep #$30 A:0004 X:0000 Y:0004 S:1fdd D:0000 DB:02 nvmxdiZC V:133 H: 654 F:36"; + + // index of the start of the info + public readonly int + addr, + D, DB, + flags, + f_N, f_V, f_M, f_X, f_D, f_I, f_Z, f_C; + + public CachedTraceLineIndex() + { + int SkipToken(string token) + { + return sample.IndexOf(token) + token.Length; + } + + addr = 0; + D = SkipToken("D:"); + DB = SkipToken("DB:"); + flags = DB + 3; + + // flags: nvmxdizc + f_N = flags + 0; + f_V = flags + 1; + f_M = flags + 2; + f_X = flags + 3; + f_D = flags + 4; + f_I = flags + 5; + f_Z = flags + 6; + f_C = flags + 7; + } + } + + private static readonly CachedTraceLineIndex CachedIdx = new CachedTraceLineIndex(); + + public int ImportTraceLogLine(string line) + { + // caution: very performance-sensitive function, please take care when making modifications + // string.IndexOf() is super-slow too. + // Input lines must follow this strict format and be this exact formatting and column indices. + // 028cde rep #$30 A:0004 X:0000 Y:0004 S:1fdd D:0000 DB:02 nvmxdiZC V:133 H: 654 F:36 + + int GetHexValueAt(int startIndex, int length) + { + return Convert.ToInt32(line.Substring(startIndex, length), 16); + } + + if (line.Length < 80) + return 0; + + int snesAddress = GetHexValueAt(0, 6); + int pc = ConvertSNEStoPC(snesAddress); + if (pc == -1) + return 0; + + // TODO: error treatment + + int directPage = GetHexValueAt(CachedIdx.D, 4); + int dataBank = GetHexValueAt(CachedIdx.DB, 2); + + // 'X' = unchecked in bsnesplus debugger UI = (8bit), 'x' or '.' = checked (16bit) + bool xflag_set = line[CachedIdx.f_X] == 'X'; + + // 'M' = unchecked in bsnesplus debugger UI = (8bit), 'm' or '.' = checked (16bit) + bool mflag_set = line[CachedIdx.f_M] == 'M'; + + SetFlag(pc, Data.FlagType.Opcode); + + int modified = 0; + int size = GetROMSize(); + do + { + SetDataBank(pc, dataBank); + SetDirectPage(pc, directPage); + SetXFlag(pc, xflag_set); + SetMFlag(pc, mflag_set); + + pc++; + modified++; + } while (pc < size && GetFlag(pc) == Data.FlagType.Operand); + + return modified; + } + + public void ImportBizHawkCDL(BizHawkCdl cdl) + { + if (!cdl.TryGetValue("CARTROM", out var cdlRomFlags)) + { + throw new InvalidDataException("The CDL file does not contain CARTROM block."); + } + + var size = Math.Min(cdlRomFlags.Count, GetROMSize()); + bool m = false; + bool x = false; + for (var offset = 0; offset < size; offset++) + { + var cdlFlag = cdlRomFlags[offset]; + if (cdlFlag == BizHawkCdl.Flag.None) + continue; + + var type = Data.FlagType.Unreached; + if ((cdlFlag & BizHawkCdl.Flag.ExecFirst) != 0) + { + type = Data.FlagType.Opcode; + m = (cdlFlag & BizHawkCdl.Flag.CPUMFlag) != 0; + x = (cdlFlag & BizHawkCdl.Flag.CPUXFlag) != 0; + } + else if ((cdlFlag & BizHawkCdl.Flag.ExecOperand) != 0) + type = Data.FlagType.Operand; + else if ((cdlFlag & BizHawkCdl.Flag.CPUData) != 0) + type = Data.FlagType.Data8Bit; + else if ((cdlFlag & BizHawkCdl.Flag.DMAData) != 0) + type = Data.FlagType.Data8Bit; + Mark(offset, type, 1); + + if (type == Data.FlagType.Opcode || type == Data.FlagType.Operand) + { + // Operand reuses the last M and X flag values used in Opcode, + // since BizHawk CDL records M and X flags only in Opcode. + MarkMFlag(offset, m, 1); + MarkXFlag(offset, x, 1); + } + } + } + #region Equality + + protected bool Equals(Data other) + { + return alias.SequenceEqual(other.alias) && RomMapMode == other.RomMapMode && RomSpeed == other.RomSpeed && Comments.SequenceEqual(other.Comments) && RomBytes.Equals(other.RomBytes); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((Data)obj); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = alias.GetHashCode(); + hashCode = (hashCode * 397) ^ (int)RomMapMode; + hashCode = (hashCode * 397) ^ (int)RomSpeed; + hashCode = (hashCode * 397) ^ Comments.GetHashCode(); + hashCode = (hashCode * 397) ^ RomBytes.GetHashCode(); + return hashCode; + } + } + #endregion } } diff --git a/DiztinGUIsh/static/Label.cs b/DiztinGUIsh/static/Label.cs new file mode 100644 index 00000000..803b0e78 --- /dev/null +++ b/DiztinGUIsh/static/Label.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DiztinGUIsh +{ + public class Label + { + protected bool Equals(Label other) + { + return name == other.name && comment == other.comment; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((Label)obj); + } + public override int GetHashCode() + { + unchecked + { + return ((name != null ? name.GetHashCode() : 0) * 397) ^ (comment != null ? comment.GetHashCode() : 0); + } + } + + public string name = ""; // name of the label + public string comment = ""; // user-generated text, comment only + + public void CleanUp() + { + if (comment == null) comment = ""; + if (name == null) name = ""; + } + } +} diff --git a/DiztinGUIsh/static/LogCreator.cs b/DiztinGUIsh/static/LogCreator.cs index 30c74a5e..78b45d14 100644 --- a/DiztinGUIsh/static/LogCreator.cs +++ b/DiztinGUIsh/static/LogCreator.cs @@ -9,8 +9,38 @@ namespace DiztinGUIsh { - public static class LogCreator + public class LogCreator { + public Data Data => Project.Data; + public Project Project { get; set; } + + public LogCreator(Project project) + { + Project = project; + + parameters = new Dictionary, int>> + { + { "", Tuple.Create, int>(GetPercent, 1) }, + { "label", Tuple.Create, int>(GetLabel, -22) }, + { "code", Tuple.Create, int>(GetCode, 37) }, + { "ia", Tuple.Create, int>(GetIntermediateAddress, 6) }, + { "pc", Tuple.Create, int>(GetProgramCounter, 6) }, + { "offset", Tuple.Create, int>(GetOffset, -6) }, + { "bytes", Tuple.Create, int>(GetRawBytes, 8) }, + { "comment", Tuple.Create, int>(GetComment, 1) }, + { "b", Tuple.Create, int>(GetDataBank, 2) }, + { "d", Tuple.Create, int>(GetDirectPage, 4) }, + { "m", Tuple.Create, int>(GetMFlag, 1) }, + { "x", Tuple.Create, int>(GetXFlag, 1) }, + { "%org", Tuple.Create, int>(GetORG, 37) }, + { "%map", Tuple.Create, int>(GetMap, 37) }, + { "%empty", Tuple.Create, int>(GetEmpty, 1) }, + { "%incsrc", Tuple.Create, int>(GetIncSrc, 1) }, + { "%bankcross", Tuple.Create, int>(GetBankCross, 1) }, + { "%labelassign", Tuple.Create, int>(GetLabelAssign, 1) }, + }; + } + public enum FormatUnlabeled { ShowAll = 0, @@ -24,47 +54,30 @@ public enum FormatStructure OneBankPerFile = 1 } - public static Dictionary, int>> parameters = new Dictionary, int>> - { - { "", Tuple.Create, int>(GetPercent, 1) }, - { "label", Tuple.Create, int>(GetLabel, -22) }, - { "code", Tuple.Create, int>(GetCode, 37) }, - { "ia", Tuple.Create, int>(GetIntermediateAddress, 6) }, - { "pc", Tuple.Create, int>(GetProgramCounter, 6) }, - { "offset", Tuple.Create, int>(GetOffset, -6) }, - { "bytes", Tuple.Create, int>(GetRawBytes, 8) }, - { "comment", Tuple.Create, int>(GetComment, 1) }, - { "b", Tuple.Create, int>(GetDataBank, 2) }, - { "d", Tuple.Create, int>(GetDirectPage, 4) }, - { "m", Tuple.Create, int>(GetMFlag, 1) }, - { "x", Tuple.Create, int>(GetXFlag, 1) }, - { "%org", Tuple.Create, int>(GetORG, 37) }, - { "%map", Tuple.Create, int>(GetMap, 37) }, - { "%empty", Tuple.Create, int>(GetEmpty, 1) }, - { "%incsrc", Tuple.Create, int>(GetIncSrc, 1) }, - { "%bankcross", Tuple.Create, int>(GetBankCross, 1) }, - { "%labelassign", Tuple.Create, int>(GetLabelAssign, 1) }, - }; - - public static string format = "%label:-22% %code:37%;%pc%|%bytes%|%ia%; %comment%"; - public static int dataPerLine = 8; - public static FormatUnlabeled unlabeled = FormatUnlabeled.ShowInPoints; - public static FormatStructure structure = FormatStructure.OneBankPerFile; - public static bool includeUnusedLabels; - public static bool printLabelSpecificComments; - - private static List> list; - private static List usedLabels; - private static StreamWriter err; - private static int errorCount, bankSize; - private static string folder; - - public static int CreateLog(StreamWriter sw, StreamWriter er) + public Dictionary, int>> parameters; + + public string format = "%label:-22% %code:37%;%pc%|%bytes%|%ia%; %comment%"; + public int dataPerLine = 8; + public FormatUnlabeled unlabeled = FormatUnlabeled.ShowInPoints; + public FormatStructure structure = FormatStructure.OneBankPerFile; + public bool includeUnusedLabels; + public bool printLabelSpecificComments; + + private List> list; + private List usedLabels; + private StreamWriter err; + private int errorCount, bankSize; + private string folder; + + public int CreateLog(StreamWriter sw, StreamWriter er) { - var tempAlias = Data.Inst.GetAllLabels(); - Data.Inst.Restore(a: new Dictionary(tempAlias)); + // TODO: now that we aren't using one gloabl instance, we don't have to Restore()/etc. + // we can just create a new Data() here nd use that. + + var tempAlias = Data.GetAllLabels(); + Data.Restore(a: new Dictionary(tempAlias)); AliasList.me.locked = true; - bankSize = Data.Inst.RomMapMode == Data.ROMMapMode.LoROM ? 0x8000 : 0x10000; // todo + bankSize = Data.RomMapMode == Data.ROMMapMode.LoROM ? 0x8000 : 0x10000; // todo AddTemporaryLabels(); @@ -85,7 +98,7 @@ public static int CreateLog(StreamWriter sw, StreamWriter er) } } - int pointer = 0, size = (Data.Inst.GetTable() == ExportDisassembly.sampleTable) ? 0x7B : Data.Inst.GetROMSize(), bank = -1; + int pointer = 0, size = (ReferenceEquals(Data.GetTable(), ExportDisassembly.sampleTable)) ? 0x7B : Data.GetROMSize(), bank = -1; if (structure == FormatStructure.OneBankPerFile) { @@ -114,14 +127,14 @@ public static int CreateLog(StreamWriter sw, StreamWriter er) WriteLabels(ref sw, pointer); if (structure == FormatStructure.OneBankPerFile) sw.Close(); - Data.Inst.Restore(a: tempAlias); + Data.Restore(a: tempAlias); AliasList.me.locked = false; return errorCount; } - private static void WriteAddress(ref StreamWriter sw, ref int pointer, Dictionary tempAlias, ref int bank) + private void WriteAddress(ref StreamWriter sw, ref int pointer, Dictionary tempAlias, ref int bank) { - int snes = Util.ConvertPCtoSNES(pointer); + int snes = Data.ConvertPCtoSNES(pointer); if ((snes >> 16) != bank) { if (structure == FormatStructure.OneBankPerFile) @@ -139,24 +152,24 @@ private static void WriteAddress(ref StreamWriter sw, ref int pointer, Dictionar bank = snes >> 16; } - var c1 = (Data.Inst.GetInOutPoint(pointer) & (Data.InOutPoint.ReadPoint)) != 0; - var c2 = (tempAlias.TryGetValue(pointer, out var aliasInfo) && aliasInfo.name.Length > 0); + var c1 = (Data.GetInOutPoint(pointer) & (Data.InOutPoint.ReadPoint)) != 0; + var c2 = (tempAlias.TryGetValue(pointer, out var Label) && Label.name.Length > 0); if (c1 || c2) sw.WriteLine(GetLine(pointer, "empty")); sw.WriteLine(GetLine(pointer, null)); - if ((Data.Inst.GetInOutPoint(pointer) & (Data.InOutPoint.EndPoint)) != 0) sw.WriteLine(GetLine(pointer, "empty")); + if ((Data.GetInOutPoint(pointer) & (Data.InOutPoint.EndPoint)) != 0) sw.WriteLine(GetLine(pointer, "empty")); pointer += GetLineByteLength(pointer); } - private static void WriteLabels(ref StreamWriter sw, int pointer) + private void WriteLabels(ref StreamWriter sw, int pointer) { SwitchOutputFile(ref sw, pointer, $"{folder}/labels.asm"); - Dictionary listToPrint = new Dictionary(); + Dictionary listToPrint = new Dictionary(); // part 1: important: include all labels we aren't defining somewhere else. needed for disassembly - foreach (var pair in Data.Inst.GetAllLabels()) + foreach (var pair in Data.GetAllLabels()) { if (usedLabels.Contains(pair.Key)) continue; @@ -176,7 +189,7 @@ private static void WriteLabels(ref StreamWriter sw, int pointer) if (includeUnusedLabels) { SwitchOutputFile(ref sw, pointer, $"{folder}/all-labels.txt"); - foreach (var pair in Data.Inst.GetAllLabels()) + foreach (var pair in Data.GetAllLabels()) { // not the best place to add formatting, TODO: cleanup var category = listToPrint.ContainsKey(pair.Key) ? "INLINE" : "EXTRA "; @@ -185,7 +198,7 @@ private static void WriteLabels(ref StreamWriter sw, int pointer) } } - private static void SwitchOutputFile(ref StreamWriter sw, int pointer, string path) + private void SwitchOutputFile(ref StreamWriter sw, int pointer, string path) { if (structure == FormatStructure.OneBankPerFile) { @@ -198,22 +211,22 @@ private static void SwitchOutputFile(ref StreamWriter sw, int pointer, string pa } } - private static void AddTemporaryLabels() + private void AddTemporaryLabels() { List addMe = new List(); int pointer = 0; - while (pointer < Data.Inst.GetROMSize()) + while (pointer < Data.GetROMSize()) { int length = GetLineByteLength(pointer); - Data.FlagType flag = Data.Inst.GetFlag(pointer); + Data.FlagType flag = Data.GetFlag(pointer); - if (unlabeled == FormatUnlabeled.ShowAll) addMe.Add(Util.ConvertPCtoSNES(pointer)); + if (unlabeled == FormatUnlabeled.ShowAll) addMe.Add(Data.ConvertPCtoSNES(pointer)); else if (unlabeled != FormatUnlabeled.ShowNone && (flag == Data.FlagType.Opcode || flag == Data.FlagType.Pointer16Bit || flag == Data.FlagType.Pointer24Bit || flag == Data.FlagType.Pointer32Bit)) { - int ia = Util.GetIntermediateAddressOrPointer(pointer); - if (ia >= 0 && Util.ConvertSNEStoPC(ia) >= 0) addMe.Add(ia); + int ia = Data.GetIntermediateAddressOrPointer(pointer); + if (ia >= 0 && Data.ConvertSNEStoPC(ia) >= 0) addMe.Add(ia); } pointer += length; @@ -222,16 +235,16 @@ private static void AddTemporaryLabels() // TODO +/- labels for (int i = 0; i < addMe.Count; i++) { - Data.Inst.AddLabel(addMe[i], - new Data.AliasInfo() + Data.AddLabel(addMe[i], + new Label() { - name = Util.GetDefaultLabel(addMe[i]) + name = Data.GetDefaultLabel(addMe[i]) }, false); } } - private static string GetLine(int offset, string special) + private string GetLine(int offset, string special) { string line = ""; for (int i = 0; i < list.Count; i++) @@ -253,9 +266,9 @@ private static string GetLine(int offset, string special) if (special == null) { // throw out some errors if stuff looks fishy - Data.FlagType flag = Data.Inst.GetFlag(offset), check = flag == Data.FlagType.Opcode ? Data.FlagType.Operand : flag; - int step = flag == Data.FlagType.Opcode ? GetLineByteLength(offset) : Util.TypeStepSize(flag), size = Data.Inst.GetROMSize(); - if (flag == Data.FlagType.Operand) err.WriteLine("({0}) Offset 0x{1:X}: Bytes marked as operands formatted as Data.Inst.", ++errorCount, offset); + Data.FlagType flag = Data.GetFlag(offset), check = flag == Data.FlagType.Opcode ? Data.FlagType.Operand : flag; + int step = flag == Data.FlagType.Opcode ? GetLineByteLength(offset) : Util.TypeStepSize(flag), size = Data.GetROMSize(); + if (flag == Data.FlagType.Operand) err.WriteLine("({0}) Offset 0x{1:X}: Bytes marked as operands formatted as Data.", ++errorCount, offset); else if (step > 1) { for (int i = 1; i < step; i++) @@ -265,15 +278,15 @@ private static string GetLine(int offset, string special) err.WriteLine("({0}) Offset 0x{1:X}: {2} extends past the end of the ROM.", ++errorCount, offset, Util.TypeToString(check)); break; } - else if (Data.Inst.GetFlag(offset + i) != check) + else if (Data.GetFlag(offset + i) != check) { - err.WriteLine("({0}) Offset 0x{1:X}: Expected {2}, but got {3} instead.", ++errorCount, offset + i, Util.TypeToString(check), Util.TypeToString(Data.Inst.GetFlag(offset + i))); + err.WriteLine("({0}) Offset 0x{1:X}: Expected {2}, but got {3} instead.", ++errorCount, offset + i, Util.TypeToString(check), Util.TypeToString(Data.GetFlag(offset + i))); break; } } } - int ia = Util.GetIntermediateAddress(offset, true); - if (ia >= 0 && flag == Data.FlagType.Opcode && Data.Inst.GetInOutPoint(offset) == Data.InOutPoint.OutPoint && Data.Inst.GetFlag(Util.ConvertSNEStoPC(ia)) != Data.FlagType.Opcode) + int ia = Data.GetIntermediateAddress(offset, true); + if (ia >= 0 && flag == Data.FlagType.Opcode && Data.GetInOutPoint(offset) == Data.InOutPoint.OutPoint && Data.GetFlag(Data.ConvertSNEStoPC(ia)) != Data.FlagType.Opcode) { err.WriteLine("({0}) Offset 0x{1:X}: Branch or jump instruction to a non-instruction.", ++errorCount, offset); } @@ -282,21 +295,15 @@ private static string GetLine(int offset, string special) return line; } - private static int GetLineByteLength(int offset) + private int GetLineByteLength(int offset) { int max = 1, step = 1; - int size = Data.Inst.GetROMSize(); + int size = Data.GetROMSize(); - switch (Data.Inst.GetFlag(offset)) + switch (Data.GetFlag(offset)) { case Data.FlagType.Opcode: - switch (Data.Inst.GetArchitechture(offset)) - { - case Data.Architechture.CPU65C816: return CPU65C816.GetInstructionLength(offset); - case Data.Architechture.APUSPC700: return 1; - case Data.Architechture.GPUSuperFX: return 1; - } - return 1; + return Project.Data.OpcodeByteLength(offset); case Data.FlagType.Unreached: case Data.FlagType.Operand: case Data.FlagType.Data8Bit: @@ -338,17 +345,18 @@ private static int GetLineByteLength(int offset) while ( min < max && offset + min < size && - Data.Inst.GetFlag(offset + min) == Data.Inst.GetFlag(offset) && - Data.Inst.GetLabelName(Util.ConvertPCtoSNES(offset + min)) == "" && + Data.GetFlag(offset + min) == Data.GetFlag(offset) && + Data.GetLabelName(Data.ConvertPCtoSNES(offset + min)) == "" && (offset + min) / bankSize == myBank ) min += step; return min; } - public static string GetParameter(int offset, string parameter, int length) + public string GetParameter(int offset, string parameter, int length) { Tuple, int> tup; - if (parameters.TryGetValue(parameter, out tup)) return tup.Item1.Invoke(offset, length); + if (parameters.TryGetValue(parameter, out tup)) + return tup.Item1.Invoke(offset, length); return ""; } @@ -366,10 +374,10 @@ private static string GetEmpty(int offset, int length) // trim to length // negative length = right justified - private static string GetLabel(int offset, int length) + private string GetLabel(int offset, int length) { - int snes = Util.ConvertPCtoSNES(offset); - string label = Data.Inst.GetLabelName(snes); + int snes = Data.ConvertPCtoSNES(offset); + string label = Data.GetLabelName(snes); if (label == null) return ""; @@ -379,15 +387,15 @@ private static string GetLabel(int offset, int length) } // trim to length - private static string GetCode(int offset, int length) + private string GetCode(int offset, int length) { int bytes = GetLineByteLength(offset); string code = ""; - switch (Data.Inst.GetFlag(offset)) + switch (Data.GetFlag(offset)) { case Data.FlagType.Opcode: - code = Util.GetInstruction(offset); + code = Project.Data.GetInstruction(offset); break; case Data.FlagType.Unreached: case Data.FlagType.Operand: @@ -395,44 +403,44 @@ private static string GetCode(int offset, int length) case Data.FlagType.Graphics: case Data.FlagType.Music: case Data.FlagType.Empty: - code = Util.GetFormattedBytes(offset, 1, bytes); + code = Project.Data.GetFormattedBytes(offset, 1, bytes); break; case Data.FlagType.Data16Bit: - code = Util.GetFormattedBytes(offset, 2, bytes); + code = Project.Data.GetFormattedBytes(offset, 2, bytes); break; case Data.FlagType.Data24Bit: - code = Util.GetFormattedBytes(offset, 3, bytes); + code = Project.Data.GetFormattedBytes(offset, 3, bytes); break; case Data.FlagType.Data32Bit: - code = Util.GetFormattedBytes(offset, 4, bytes); + code = Project.Data.GetFormattedBytes(offset, 4, bytes); break; case Data.FlagType.Pointer16Bit: - code = Util.GetPointer(offset, 2); + code = Project.Data.GetPointer(offset, 2); break; case Data.FlagType.Pointer24Bit: - code = Util.GetPointer(offset, 3); + code = Project.Data.GetPointer(offset, 3); break; case Data.FlagType.Pointer32Bit: - code = Util.GetPointer(offset, 4); + code = Project.Data.GetPointer(offset, 4); break; case Data.FlagType.Text: - code = Util.GetFormattedText(offset, bytes); + code = Project.Data.GetFormattedText(offset, bytes); break; } return string.Format("{0," + (length * -1) + "}", code); } - private static string GetORG(int offset, int length) + private string GetORG(int offset, int length) { - string org = "ORG " + Util.NumberToBaseString(Util.ConvertPCtoSNES(offset), Util.NumberBase.Hexadecimal, 6, true); + string org = "ORG " + Util.NumberToBaseString(Data.ConvertPCtoSNES(offset), Util.NumberBase.Hexadecimal, 6, true); return string.Format("{0," + (length * -1) + "}", org); } - private static string GetMap(int offset, int length) + private string GetMap(int offset, int length) { string s = ""; - switch (Data.Inst.RomMapMode) + switch (Data.RomMapMode) { case Data.ROMMapMode.LoROM: s = "lorom"; break; case Data.ROMMapMode.HiROM: s = "hirom"; break; @@ -446,96 +454,96 @@ private static string GetMap(int offset, int length) } // 0+ = bank_xx.asm, -1 = labels.asm - private static string GetIncSrc(int offset, int length) + private string GetIncSrc(int offset, int length) { string s = "incsrc \"labels.asm\""; if (offset >= 0) { - int bank = Util.ConvertPCtoSNES(offset) >> 16; + int bank = Data.ConvertPCtoSNES(offset) >> 16; s = string.Format("incsrc \"bank_{0}.asm\"", Util.NumberToBaseString(bank, Util.NumberBase.Hexadecimal, 2)); } return string.Format("{0," + (length * -1) + "}", s); } - private static string GetBankCross(int offset, int length) + private string GetBankCross(int offset, int length) { string s = "check bankcross off"; return string.Format("{0," + (length * -1) + "}", s); } // length forced to 6 - private static string GetIntermediateAddress(int offset, int length) + private string GetIntermediateAddress(int offset, int length) { - int ia = Util.GetIntermediateAddressOrPointer(offset); + int ia = Project.Data.GetIntermediateAddressOrPointer(offset); return ia >= 0 ? Util.NumberToBaseString(ia, Util.NumberBase.Hexadecimal, 6) : " "; } // length forced to 6 - private static string GetProgramCounter(int offset, int length) + private string GetProgramCounter(int offset, int length) { - return Util.NumberToBaseString(Util.ConvertPCtoSNES(offset), Util.NumberBase.Hexadecimal, 6); + return Util.NumberToBaseString(Data.ConvertPCtoSNES(offset), Util.NumberBase.Hexadecimal, 6); } // trim to length - private static string GetOffset(int offset, int length) + private string GetOffset(int offset, int length) { return string.Format("{0," + (length * -1) + "}", Util.NumberToBaseString(offset, Util.NumberBase.Hexadecimal, 0)); } // length forced to 8 - private static string GetRawBytes(int offset, int length) + private string GetRawBytes(int offset, int length) { string bytes = ""; - if (Data.Inst.GetFlag(offset) == Data.FlagType.Opcode) + if (Data.GetFlag(offset) == Data.FlagType.Opcode) { - for (int i = 0; i < Manager.GetInstructionLength(offset); i++) + for (int i = 0; i < Data.GetInstructionLength(offset); i++) { - bytes += Util.NumberToBaseString(Data.Inst.GetROMByte(offset + i), Util.NumberBase.Hexadecimal); + bytes += Util.NumberToBaseString(Data.GetROMByte(offset + i), Util.NumberBase.Hexadecimal); } } return string.Format("{0,-8}", bytes); } // trim to length - private static string GetComment(int offset, int length) + private string GetComment(int offset, int length) { - return string.Format("{0," + (length * -1) + "}", Data.Inst.GetComment(Util.ConvertPCtoSNES(offset))); + return string.Format("{0," + (length * -1) + "}", Data.GetComment(Data.ConvertPCtoSNES(offset))); } // length forced to 2 - private static string GetDataBank(int offset, int length) + private string GetDataBank(int offset, int length) { - return Util.NumberToBaseString(Data.Inst.GetDataBank(offset), Util.NumberBase.Hexadecimal, 2); + return Util.NumberToBaseString(Data.GetDataBank(offset), Util.NumberBase.Hexadecimal, 2); } // length forced to 4 - private static string GetDirectPage(int offset, int length) + private string GetDirectPage(int offset, int length) { - return Util.NumberToBaseString(Data.Inst.GetDirectPage(offset), Util.NumberBase.Hexadecimal, 4); + return Util.NumberToBaseString(Data.GetDirectPage(offset), Util.NumberBase.Hexadecimal, 4); } // if length == 1, M/m, else 08/16 - private static string GetMFlag(int offset, int length) + private string GetMFlag(int offset, int length) { - bool m = Data.Inst.GetMFlag(offset); + bool m = Data.GetMFlag(offset); if (length == 1) return m ? "M" : "m"; else return m ? "08" : "16"; } // if length == 1, X/x, else 08/16 - private static string GetXFlag(int offset, int length) + private string GetXFlag(int offset, int length) { - bool x = Data.Inst.GetXFlag(offset); + bool x = Data.GetXFlag(offset); if (length == 1) return x ? "X" : "x"; else return x ? "08" : "16"; } // output label at snes offset, and its value - private static string GetLabelAssign(int offset, int length) + private string GetLabelAssign(int offset, int length) { - var labelName = Data.Inst.GetLabelName(offset); + var labelName = Data.GetLabelName(offset); var offsetStr = Util.NumberToBaseString(offset, Util.NumberBase.Hexadecimal, 6, true); - var labelComment = Data.Inst.GetLabelComment(offset); + var labelComment = Data.GetLabelComment(offset); if (string.IsNullOrEmpty(labelName)) return ""; diff --git a/DiztinGUIsh/static/Project.cs b/DiztinGUIsh/static/Project.cs index 8c54fd40..c46ba72b 100644 --- a/DiztinGUIsh/static/Project.cs +++ b/DiztinGUIsh/static/Project.cs @@ -1,531 +1,181 @@ using DiztinGUIsh.window; using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; -using System.IO.Compression; using System.Windows.Forms; -using System.Xml; -using ExtendedXmlSerializer; -using ExtendedXmlSerializer.Configuration; namespace DiztinGUIsh { public class Project { - public const int HEADER_SIZE = 0x100; + // Any public properties will be automatically serialized to XML. + // They require a get AND set. - public string currentProjectFile = null, currentROMFile = null; - public bool unsavedChanges = false; - public const string watermark = "DiztinGUIsh"; + public string ProjectFileName { get; set; } + public string AttachedRomFilename { get; set; } + public bool UnsavedChanges { get; set; } - // these must always match the same bytes in the ROM - public string InternalRomTitleName { get; set; } = ""; + // safety check: these are copies of data in the ROM, they must always match the ROM on project load + // or else we might be looking at the wrong file. + public string InternalRomGameName { get; set; } public int InternalCheckSum { get; set; } = -1; - public int InternalRomSize { get; set; } = -1; // needs to come last for serialization - public Data Data = new Data(); + public Data Data { get; set; } - public bool NewProject(string filename) + public class ImportRomSettings { - try - { - byte[] smc = File.ReadAllBytes(filename); - byte[] rom = new byte[smc.Length & 0x7FFFFC00]; - - if ((smc.Length & 0x3FF) == 0x200) for (int i = 0; i < rom.Length; i++) rom[i] = smc[i + 0x200]; - else if ((smc.Length & 0x3FF) != 0) throw new Exception("This ROM has an unusual size. It can't be opened."); - else rom = smc; - - if (rom.Length < 0x8000) throw new Exception("This ROM is too small. It can't be opened."); + public Data.ROMMapMode ROMMapMode; + public Data.ROMSpeed ROMSpeed; - currentROMFile = filename; + public Dictionary InitialLabels; + public Dictionary InitialHeaderFlags; - ImportROMDialog import = new ImportROMDialog(rom); - DialogResult result = import.ShowDialog(); - if (result == DialogResult.OK) - { - Data.Inst.Initiate(rom, import.GetROMMapMode(), import.GetROMSpeed()); - unsavedChanges = false; - currentProjectFile = null; - - AliasList.me.ResetDataGrid(); - Dictionary generatedLabels = import.GetGeneratedLabels(); - if (generatedLabels.Count > 0) - { - foreach (KeyValuePair pair in generatedLabels) Data.Inst.AddLabel(pair.Key, pair.Value, true); - unsavedChanges = true; - } - - Dictionary generatedFlags = import.GetHeaderFlags(); - if (generatedFlags.Count > 0) - { - foreach (KeyValuePair pair in generatedFlags) Data.Inst.SetFlag(pair.Key, pair.Value); - unsavedChanges = true; - } - - InternalCheckSum = GetRomCheckSumsFromRomBytes(); - InternalRomTitleName = GetRomNameFromRomBytes(); - InternalRomSize = Data.Inst.GetROMSize(); - - return true; - } - } - catch (Exception e) - { - MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - return false; + public byte[] rom_bytes; + public string rom_filename; } - private const int LATEST_FILE_FORMAT_VERSION = 2; - - public IExtendedXmlSerializer GetSerializer() + public Project ImportRomAndCreateNewProject(ImportRomSettings importSettings) { - return new ConfigurationContainer() - .Type().Register().Serializer().Using(TableDataSerializer.Default) - .UseOptimizedNamespaces() - .UseAutoFormatting() - .EnableImplicitTyping(typeof(Data)) - .EnableImplicitTyping(typeof(Data.AliasInfo)) - .Create(); + var project = new Project(); + project.DoImportRomAndCreateNewProject(importSettings); + return project; } - - public void SaveProject(string filename) + private void DoImportRomAndCreateNewProject(ImportRomSettings importSettings) { - // TODO: figure out how to not save Project.unsavedChanges property in XML + AttachedRomFilename = importSettings.rom_filename; + UnsavedChanges = false; + ProjectFileName = null; - var file = filename + ".xml"; - var xml = GetSerializer().Serialize(new XmlWriterSettings { Indent = true }, Project.Inst); - File.WriteAllText(file, xml); + Data = new Data(); + Data.Initiate(importSettings.rom_bytes, importSettings.ROMMapMode, importSettings.ROMSpeed); - var project = OpenProjectXml(file); - DebugVerifyProjectEquality(Project.Inst, project); - } + // TODO: get this UI out of here. probably just use databinding instead + AliasList.me.ResetDataGrid(); - private void DebugVerifyProjectEquality(Project project1, Project project2, bool deepcut=true) - { - if (deepcut) + if (importSettings.InitialLabels.Count > 0) { - for (int i = 0; i < project1.Data.table.RomBytes.Count; ++i) - { - Debug.Assert(project1.Data.table[i].Equals(project2.Data.table[i])); - } - - Debug.Assert(project1.Data.table.Equals(project2.Data.table)); - Debug.Assert(project1.Data.Equals(project2.Data)); + foreach (var pair in importSettings.InitialLabels) + Data.AddLabel(pair.Key, pair.Value, true); + UnsavedChanges = true; } - Debug.Assert(project1.Equals(Project.Inst)); - } - public Project OpenProjectXml(string filename) - { - var loadingProject = GetSerializer().Deserialize(File.ReadAllText(filename)); - - byte[] rom; - - // tmp - OpenFileDialog open = new OpenFileDialog(); - - if (ValidateROM(this.currentROMFile, InternalRomTitleName, InternalCheckSum, Project.Inst.Data.RomMapMode, out rom, open)) + if (importSettings.InitialHeaderFlags.Count > 0) { - loadingProject.Data.CopyRomDataIn(rom); + foreach (var pair in importSettings.InitialHeaderFlags) + Data.SetFlag(pair.Key, pair.Value); + UnsavedChanges = true; } - return loadingProject; - } - - public void SaveProjectORIG(string filename) - { - try - { - const int versionToSave = LATEST_FILE_FORMAT_VERSION; - - byte[] data = SaveVersion(versionToSave); - byte[] everything = new byte[HEADER_SIZE + data.Length]; - everything[0] = versionToSave; - Util.StringToByteArray(watermark).CopyTo(everything, 1); - data.CopyTo(everything, HEADER_SIZE); - - if (!IsUncompressedProject(filename)) everything = TryZip(everything); - - File.WriteAllBytes(filename, everything); - unsavedChanges = false; - currentProjectFile = filename; - } - catch (Exception e) - { - MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } + // Save a copy of these identifying ROM bytes with the project file itself. + // When we reload, we will make sure the linked ROM still matches them. + InternalCheckSum = Data.GetRomCheckSumsFromRomBytes(); + InternalRomGameName = Data.GetRomNameFromRomBytes(); } - private byte[] SaveVersion(int version) + public byte[] ReadFromOriginalRom() { - void SaveStringToBytes(string str, List bytes) - { - // TODO: combine with Util.StringToByteArray() probably. - if (str != null) - { - foreach (var c in str) - { - bytes.Add((byte)c); - } - } - bytes.Add(0); - } - - if (version < 1 || version > LATEST_FILE_FORMAT_VERSION) - { - throw new ArgumentException($"Saving: Invalid save version requested for saving: {version}."); - } - - int size = Data.Inst.GetROMSize(); - byte[] romSettings = new byte[31]; + string firstRomFileWeTried; + var nextFileToTry = firstRomFileWeTried = AttachedRomFilename; + byte[] rom = null; - // save these two - romSettings[0] = (byte)Data.Inst.GetROMMapMode(); - romSettings[1] = (byte)Data.Inst.GetROMSpeed(); + do { + var error = ReadROMIfMatchesProject(nextFileToTry, out rom); + if (error == null) + break; - // save the size, 4 bytes - Util.IntegerIntoByteArray(size, romSettings, 2); + nextFileToTry = PromptForNewRom($"{error} Link a new ROM now?"); + if (nextFileToTry == null) + return null; + } while (true); - var romName = GetRomNameFromRomBytes(); - romName.ToCharArray().CopyTo(romSettings, 6); + AttachedRomFilename = nextFileToTry; - var romChecksum = GetRomCheckSumsFromRomBytes(); - BitConverter.GetBytes(romChecksum).CopyTo(romSettings, 27); - - // TODO put selected offset in save file - - // save all labels ad comments - List label = new List(), comment = new List(); - var all_labels = Data.Inst.GetAllLabels(); - var all_comments = Data.Inst.GetAllComments(); - - Util.IntegerIntoByteList(all_labels.Count, label); - foreach (var pair in all_labels) - { - Util.IntegerIntoByteList(pair.Key, label); + if (AttachedRomFilename != firstRomFileWeTried) + UnsavedChanges = true; - SaveStringToBytes(pair.Value.name, label); - if (version >= 2) - { - SaveStringToBytes(pair.Value.comment, label); - } - } - - Util.IntegerIntoByteList(all_comments.Count, comment); - foreach (KeyValuePair pair in all_comments) - { - Util.IntegerIntoByteList(pair.Key, comment); - SaveStringToBytes(pair.Value, comment); - } - - // save current Rom full path - "D:\projects\cthack\rom\ct-orig.smc" - byte[] romLocation = Util.StringToByteArray(currentROMFile); - - byte[] data = new byte[romSettings.Length + romLocation.Length + 8 * size + label.Count + comment.Count]; - romSettings.CopyTo(data, 0); - for (int i = 0; i < romLocation.Length; i++) data[romSettings.Length + i] = romLocation[i]; - - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + i] = (byte)Data.Inst.GetDataBank(i); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + size + i] = (byte)Data.Inst.GetDirectPage(i); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 2 * size + i] = (byte)(Data.Inst.GetDirectPage(i) >> 8); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 3 * size + i] = (byte)(Data.Inst.GetXFlag(i) ? 1 : 0); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 4 * size + i] = (byte)(Data.Inst.GetMFlag(i) ? 1 : 0); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 5 * size + i] = (byte)Data.Inst.GetFlag(i); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 6 * size + i] = (byte)Data.Inst.GetArchitechture(i); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 7 * size + i] = (byte)Data.Inst.GetInOutPoint(i); - // ??? - label.CopyTo(data, romSettings.Length + romLocation.Length + 8 * size); - comment.CopyTo(data, romSettings.Length + romLocation.Length + 8 * size + label.Count); - // ??? - - return data; + return rom; } - private static byte[] GetRomBytes(int pcOffset, int count) + private string ReadROMIfMatchesProject(string filename, out byte[] rom_bytes) { - byte[] output = new byte[count]; - for (int i = 0; i < output.Length; i++) - output[i] = (byte)Data.Inst.GetROMByte(Util.ConvertSNEStoPC(pcOffset + i)); + string error_msg = null; - return output; - } - - private static string GetRomNameFromRomBytes() - { - return System.Text.Encoding.UTF8.GetString(GetRomBytes(0xFFC0, 21)); - } - - private static int GetRomCheckSumsFromRomBytes() - { - return Util.ByteArrayToInteger(GetRomBytes(0xFFDC, 4)); - } - - public bool TryOpenProject(string filename, OpenFileDialog open) - { - try - { - byte[] data = File.ReadAllBytes(filename); - - if (!IsUncompressedProject(filename)) data = TryUnzip(data); - - for (int i = 0; i < watermark.Length; i++) + try { + rom_bytes = Util.ReadAllRomBytesFromFile(filename); + if (rom_bytes != null) { - if (data[i + 1] != (byte)watermark[i]) - { - throw new Exception("This is not a valid DiztinGUIsh file!"); - } + error_msg = IsThisRomIsIdenticalToUs(rom_bytes); + if (error_msg == null) + return null; } - - byte version = data[0]; - OpenProject(version, data, open); - - unsavedChanges = false; - currentProjectFile = filename; - return true; - } - catch (Exception e) - { - MessageBox.Show(e.Message, "Error opening project file", MessageBoxButtons.OK, MessageBoxIcon.Error); - return false; + } catch (Exception ex) { + error_msg = ex.Message; } - } - private delegate int AddressConverter(int address); + rom_bytes = null; + return error_msg; + } - private void OpenProject(int version, byte[] unzipped, OpenFileDialog open) + // returns error message if it's not identical, or null if everything is OK. + private string IsThisRomIsIdenticalToUs(byte[] rom) { - if (version > LATEST_FILE_FORMAT_VERSION) - { - throw new ArgumentException("This DiztinGUIsh file uses a newer file format! You'll need to download the newest version of DiztinGUIsh to open it."); - } - else if (version != LATEST_FILE_FORMAT_VERSION) - { - MessageBox.Show( - "This project file is in an older format.\n" + - "You may want to back up your work or 'Save As' in case the conversion goes wrong.\n" + - "The project file will be untouched until it is saved again.", - "Project File Out of Date", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); - } - - if (version < 0) - { - throw new ArgumentException($"Invalid project file version detected: {version}."); - } + var offset = Data.GetRomSettingOffset(Data.RomMapMode); + if (rom.Length <= offset + 10) + return "The linked ROM is too small. It can't be opened."; - // version 0 needs to convert PC to SNES for some addresses - AddressConverter converter = address => address; - if (version == 0) - converter = Util.ConvertPCtoSNES; + var romInternalGameName = Util.ReadStringFromByteArray(rom, 0x15, offset); - // read mode, speed, size - Data.ROMMapMode mode = (Data.ROMMapMode)unzipped[HEADER_SIZE]; - Data.ROMSpeed speed = (Data.ROMSpeed)unzipped[HEADER_SIZE + 1]; - int size = Util.ByteArrayToInteger(unzipped, HEADER_SIZE + 2); + var myChecksums = Util.ByteArrayToInteger(rom, offset + 7); - // read internal title - string romInternalTitle = ""; - int pointer = HEADER_SIZE + 6; - for (int i = 0; i < 0x15; i++) romInternalTitle += (char) unzipped[pointer++]; - - // read checksums - int checksums = Util.ByteArrayToInteger(unzipped, pointer); - pointer += 4; - - // read full filepath to the ROM .sfc file - string romFullFilepath = ""; - while (unzipped[pointer] != 0) romFullFilepath += (char) unzipped[pointer++]; - pointer++; - - byte[] rom; + if (romInternalGameName != InternalRomGameName) + return $"The linked ROM's internal name '{romInternalGameName}' doesn't " + + $"match the project's internal name of '{InternalRomGameName}'."; + + if (myChecksums != InternalCheckSum) + return $"The linked ROM's checksums '{myChecksums:X8}' " + + $"don't match the project's checksums of '{InternalCheckSum:X8}'."; - if (ValidateROM(romFullFilepath, romInternalTitle, checksums, mode, out rom, open)) - { - Data.Inst.Initiate(rom, mode, speed); - - for (int i = 0; i < size; i++) Data.Inst.SetDataBank(i, unzipped[pointer + i]); - for (int i = 0; i < size; i++) Data.Inst.SetDirectPage(i, unzipped[pointer + size + i] | (unzipped[pointer + 2 * size + i] << 8)); - for (int i = 0; i < size; i++) Data.Inst.SetXFlag(i, unzipped[pointer + 3 * size + i] != 0); - for (int i = 0; i < size; i++) Data.Inst.SetMFlag(i, unzipped[pointer + 4 * size + i] != 0); - for (int i = 0; i < size; i++) Data.Inst.SetFlag(i, (Data.FlagType)unzipped[pointer + 5 * size + i]); - for (int i = 0; i < size; i++) Data.Inst.SetArchitechture(i, (Data.Architechture)unzipped[pointer + 6 * size + i]); - for (int i = 0; i < size; i++) Data.Inst.SetInOutPoint(i, (Data.InOutPoint)unzipped[pointer + 7 * size + i]); - pointer += 8 * size; - - AliasList.me.ResetDataGrid(); - ReadAliases(unzipped, ref pointer, converter, version >= 2); - ReadComments(unzipped, ref pointer, converter); - - // redundant but, needed for forwards-compatibility - InternalCheckSum = GetRomCheckSumsFromRomBytes(); - InternalRomTitleName = GetRomNameFromRomBytes(); - InternalRomSize = Data.Inst.GetROMSize(); - } - else - { - throw new Exception("Couldn't open the ROM file!"); - } + return null; } - // TODO: refactor ReadComments and ReadAliases into one generic list-reading function - - private void ReadComments(byte[] unzipped, ref int pointer, AddressConverter converter) + private string PromptForNewRom(string promptText) { - var count = Util.ByteArrayToInteger(unzipped, pointer); - pointer += 4; - - for (var i = 0; i < count; i++) - { - int offset = converter(Util.ByteArrayToInteger(unzipped, pointer)); - pointer += 4; + var dialogResult = MessageBox.Show(promptText, "Error", + MessageBoxButtons.YesNo, MessageBoxIcon.Error); - var comment = Util.ReadZipString(unzipped, ref pointer); + if (dialogResult == DialogResult.No) + return null; - Data.Inst.AddComment(offset, comment, true); - } + return PromptToSelectFile(); } - private void ReadAliases(byte[] unzipped, ref int pointer, AddressConverter converter, bool readAliasComments) + private string PromptToSelectFile() { - int count = Util.ByteArrayToInteger(unzipped, pointer); - pointer += 4; - - for (int i = 0; i < count; i++) - { - int offset = converter(Util.ByteArrayToInteger(unzipped, pointer)); - pointer += 4; - - var aliasInfo = new Data.AliasInfo { - name = Util.ReadZipString(unzipped, ref pointer), - comment = readAliasComments ? Util.ReadZipString(unzipped, ref pointer) : "", - }; - aliasInfo.CleanUp(); - - Data.Inst.AddLabel(offset, aliasInfo, true); - } + return Util.PromptToSelectFile(ProjectFileName); } - private bool ValidateROM(string filename, string romName, int checksums, Data.ROMMapMode mode, out byte[] rom, OpenFileDialog open) + public bool PostSerializationLoad() { - bool validFile = false, matchingROM = false; - rom = null; - open.InitialDirectory = currentProjectFile; - - while (!matchingROM) - { - string error = null; - matchingROM = false; - - while (!validFile) - { - error = null; - validFile = false; - - try - { - byte[] smc = File.ReadAllBytes(filename); - rom = new byte[smc.Length & 0x7FFFFC00]; - - if ((smc.Length & 0x3FF) == 0x200) for (int i = 0; i < rom.Length; i++) rom[i] = smc[i + 0x200]; - else if ((smc.Length & 0x3FF) != 0) error = "The linked ROM has an unusual size. It can't be opened."; - else rom = smc; - - if (error == null) validFile = true; - } - catch (Exception) - { - error = string.Format("The linked ROM file '{0}' couldn't be found.", filename); - } - - if (!validFile) - { - DialogResult result = MessageBox.Show(string.Format("{0} Link a new ROM now?", error), "Error", MessageBoxButtons.YesNo, MessageBoxIcon.Error); - if (result == DialogResult.No) return false; - result = open.ShowDialog(); - if (result == DialogResult.OK) filename = open.FileName; - else return false; - } - } - - validFile = false; - int offset = Data.Inst.GetRomSettingOffset(mode); - if (rom.Length <= offset + 10) error = "The linked ROM is too small. It can't be opened."; + // at this stage, 'Data' is populated with everything EXCEPT the actual ROM bytes. + // It would be easy to store the ROM bytes in the save file, but, for copyright reasons, + // we leave it out. + // + // So now, with all our metadata loaded successfully, we now open the .smc file on disk + // and marry the original rom's bytes with all of our metadata loaded from the project file. - string myName = ""; - for (int i = 0; i < 0x15; i++) myName += (char)rom[offset - 0x15 + i]; - int myChecksums = Util.ByteArrayToInteger(rom, offset + 7); - - if (myName != romName) error = string.Format("The linked ROM's internal name '{0}' doesn't match the project's internal name of '{1}'.", myName, romName); - else if (checksums != myChecksums) error = string.Format("The linked ROM's checksums '{0:X8}' don't match the project's checksums of '{1:X8}'.", myChecksums, checksums); - - if (error == null) matchingROM = true; - - if (!matchingROM) - { - DialogResult result = MessageBox.Show(string.Format("{0} Link a new ROM now?", error), "Error", MessageBoxButtons.YesNo, MessageBoxIcon.Error); - if (result == DialogResult.No) return false; - result = open.ShowDialog(); - if (result == DialogResult.OK) filename = open.FileName; - else return false; - } - } + var rom = ReadFromOriginalRom(); + if (rom == null) + return false; - if (currentROMFile != filename) - { - currentROMFile = filename; - unsavedChanges = true; - } + Data.CopyRomDataIn(rom); return true; } - private bool IsUncompressedProject(string filename) - { - return Path.GetExtension(filename).Equals(".dizraw", StringComparison.InvariantCultureIgnoreCase); - } - - // https://stackoverflow.com/questions/33119119/unzip-byte-array-in-c-sharp - private byte[] TryUnzip(byte[] data) - { - try - { - using (MemoryStream comp = new MemoryStream(data)) - using (GZipStream gzip = new GZipStream(comp, CompressionMode.Decompress)) - using (MemoryStream res = new MemoryStream()) - { - gzip.CopyTo(res); - return res.ToArray(); - } - } - catch (Exception) - { - return null; - } - } - - private byte[] TryZip(byte[] data) - { - try - { - using (MemoryStream comp = new MemoryStream()) - using (GZipStream gzip = new GZipStream(comp, CompressionMode.Compress)) - { - gzip.Write(data, 0, data.Length); - gzip.Close(); - return comp.ToArray(); - } - } - catch (Exception) - { - return null; - } - } - + #region Equality protected bool Equals(Project other) { - return currentProjectFile == other.currentProjectFile && currentROMFile == other.currentROMFile && Equals(Data, other.Data) && InternalRomTitleName == other.InternalRomTitleName && InternalCheckSum == other.InternalCheckSum && InternalRomSize == other.InternalRomSize; + return ProjectFileName == other.ProjectFileName && AttachedRomFilename == other.AttachedRomFilename && Equals(Data, other.Data) && InternalRomGameName == other.InternalRomGameName && InternalCheckSum == other.InternalCheckSum; } public override bool Equals(object obj) @@ -540,18 +190,14 @@ public override int GetHashCode() { unchecked { - var hashCode = (currentProjectFile != null ? currentProjectFile.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (currentROMFile != null ? currentROMFile.GetHashCode() : 0); + var hashCode = (ProjectFileName != null ? ProjectFileName.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (AttachedRomFilename != null ? AttachedRomFilename.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (Data != null ? Data.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (InternalRomTitleName != null ? InternalRomTitleName.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (InternalRomGameName != null ? InternalRomGameName.GetHashCode() : 0); hashCode = (hashCode * 397) ^ InternalCheckSum; - hashCode = (hashCode * 397) ^ InternalRomSize; return hashCode; } } - - // singleton - private static readonly Lazy instance = new Lazy(() => new Project()); - public static Project Inst => instance.Value; + #endregion } } diff --git a/DiztinGUIsh/static/RomBytes.cs b/DiztinGUIsh/static/RomBytes.cs new file mode 100644 index 00000000..99c4936f --- /dev/null +++ b/DiztinGUIsh/static/RomBytes.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ExtendedXmlSerializer; + +namespace DiztinGUIsh +{ + public class RomBytes : IEnumerable + { + // TODO: might be able to do something more generic now that other refactorings are completed. + // + // This class needs to do these things that are special: + // 1) Be handled specially by our custom XML serializer (compresses to save disk space) + // 2) Handle Equals() by comparing each element in the list (SequenceEqual) + public List Bytes { get; } = new List(); + public ROMByte this[int i] + { + get => Bytes[i]; + set => Bytes[i] = value; + } + + public int Count => Bytes.Count; + + protected bool Equals(RomBytes other) + { + return Bytes.SequenceEqual(other.Bytes); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((RomBytes)obj); + } + + public override int GetHashCode() + { + return (Bytes != null ? Bytes.GetHashCode() : 0); + } + + public IEnumerator GetEnumerator() + { + return Bytes.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void Add(ROMByte romByte) + { + Bytes.Add(romByte); + } + } +} diff --git a/DiztinGUIsh/static/Util.cs b/DiztinGUIsh/static/Util.cs index 7ec9f554..008b8ecf 100644 --- a/DiztinGUIsh/static/Util.cs +++ b/DiztinGUIsh/static/Util.cs @@ -1,12 +1,10 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.Drawing; using System.Globalization; using System.IO; -using System.Linq; +using System.IO.Compression; using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; namespace DiztinGUIsh @@ -18,191 +16,35 @@ public enum NumberBase Decimal = 3, Hexadecimal = 2, Binary = 8 } - public static int GetROMWord(int offset) + public static int ConvertSNESToPC(int address, Data.ROMMapMode mode, int size) { - if (offset + 1 < Data.Inst.GetROMSize()) - return Data.Inst.GetROMByte(offset) + (Data.Inst.GetROMByte(offset + 1) << 8); - return -1; - } - - public static int GetROMLong(int offset) - { - if (offset + 2 < Data.Inst.GetROMSize()) - return Data.Inst.GetROMByte(offset) + (Data.Inst.GetROMByte(offset + 1) << 8) + (Data.Inst.GetROMByte(offset + 2) << 16); - return -1; - } - - public static int GetROMDoubleWord(int offset) - { - if (offset + 3 < Data.Inst.GetROMSize()) - return Data.Inst.GetROMByte(offset) + (Data.Inst.GetROMByte(offset + 1) << 8) + (Data.Inst.GetROMByte(offset + 2) << 16) + (Data.Inst.GetROMByte(offset + 3) << 24); - return -1; - } - - public static int GetIntermediateAddressOrPointer(int offset) - { - switch (Data.Inst.GetFlag(offset)) - { - case Data.FlagType.Unreached: - case Data.FlagType.Opcode: - return GetIntermediateAddress(offset, true); - case Data.FlagType.Pointer16Bit: - int bank = Data.Inst.GetDataBank(offset); - return (bank << 16) | GetROMWord(offset); - case Data.FlagType.Pointer24Bit: - case Data.FlagType.Pointer32Bit: - return GetROMLong(offset); - } - return -1; - } - - public static int GetIntermediateAddress(int offset, bool resolve = false) - { - // FIX ME: log and generation of dp opcodes. search references - switch (Data.Inst.GetArchitechture(offset)) - { - case Data.Architechture.CPU65C816: return CPU65C816.GetIntermediateAddress(offset, resolve); - case Data.Architechture.APUSPC700: return -1; - case Data.Architechture.GPUSuperFX: return -1; - } - return -1; - } - - public static string GetInstruction(int offset) - { - switch (Data.Inst.GetArchitechture(offset)) - { - case Data.Architechture.CPU65C816: return CPU65C816.GetInstruction(offset); - case Data.Architechture.APUSPC700: return ""; - case Data.Architechture.GPUSuperFX: return ""; - } - return ""; - } - - public static string GetFormattedBytes(int offset, int step, int bytes) - { - string res = ""; - switch (step) - { - case 1: res = "db "; break; - case 2: res = "dw "; break; - case 3: res = "dl "; break; - case 4: res = "dd "; break; - } - - for (int i = 0; i < bytes; i += step) - { - if (i > 0) res += ","; - - switch (step) - { - case 1: res += NumberToBaseString(Data.Inst.GetROMByte(offset + i), NumberBase.Hexadecimal, 2, true); break; - case 2: res += NumberToBaseString(GetROMWord(offset + i), NumberBase.Hexadecimal, 4, true); break; - case 3: res += NumberToBaseString(GetROMLong(offset + i), NumberBase.Hexadecimal, 6, true); break; - case 4: res += NumberToBaseString(GetROMDoubleWord(offset + i), NumberBase.Hexadecimal, 8, true); break; - } - } - - return res; - } - - public static string GetPointer(int offset, int bytes) - { - int ia = -1; - string format = "", param = ""; - switch (bytes) - { - case 2: - ia = (Data.Inst.GetDataBank(offset) << 16) | GetROMWord(offset); - format = "dw {0}"; - param = NumberToBaseString(GetROMWord(offset), NumberBase.Hexadecimal, 4, true); - break; - case 3: - ia = GetROMLong(offset); - format = "dl {0}"; - param = NumberToBaseString(GetROMLong(offset), NumberBase.Hexadecimal, 6, true); - break; - case 4: - ia = GetROMLong(offset); - format = "dl {0}" + string.Format(" : db {0}", NumberToBaseString(Data.Inst.GetROMByte(offset + 3), NumberBase.Hexadecimal, 2, true)); - param = NumberToBaseString(GetROMLong(offset), NumberBase.Hexadecimal, 6, true); - break; - } - - int pc = ConvertSNEStoPC(ia); - if (pc >= 0 && Data.Inst.GetLabelName(ia) != "") param = Data.Inst.GetLabelName(ia); - return string.Format(format, param); - } - - public static string GetFormattedText(int offset, int bytes) - { - string text = "db \""; - for (int i = 0; i < bytes; i++) text += (char)Data.Inst.GetROMByte(offset + i); - return text + "\""; - } - - public static string GetDefaultLabel(int address) - { - int pc = ConvertSNEStoPC(address); - return string.Format("{0}_{1}", TypeToLabel(Data.Inst.GetFlag(pc)), NumberToBaseString(address, NumberBase.Hexadecimal, 6)); - } - - public static int ConvertPCtoSNES(int offset) - { - if (Data.Inst.RomMapMode == Data.ROMMapMode.LoROM) - { - offset = ((offset & 0x3F8000) << 1) | 0x8000 | (offset & 0x7FFF); - if (Data.Inst.GetROMSpeed() == Data.ROMSpeed.FastROM || offset >= 0x7E0000) offset |= 0x800000; - } - else if (Data.Inst.RomMapMode == Data.ROMMapMode.HiROM) - { - offset |= 0x400000; - if (Data.Inst.GetROMSpeed() == Data.ROMSpeed.FastROM || offset >= 0x7E0000) offset |= 0x800000; - } - else if (Data.Inst.RomMapMode == Data.ROMMapMode.ExHiROM) - { - if (offset < 0x40000) offset |= 0xC00000; - else if (offset >= 0x7E0000) offset &= 0x3FFFFF; - } - else + int _UnmirroredOffset(int offset) { - if (offset >= 0x400000 && Data.Inst.RomMapMode == Data.ROMMapMode.ExSA1ROM) - { - offset += 0x800000; - } - else - { - offset = ((offset & 0x3F8000) << 1) | 0x8000 | (offset & 0x7FFF); - if (offset >= 0x400000) offset += 0x400000; - } + return Util.UnmirroredOffset(offset, size); } - return offset; - } - public static int ConvertSNEStoPC(int address) - { // WRAM is N/A to PC addressing if ((address & 0xFE0000) == 0x7E0000) return -1; // WRAM mirror & PPU regs are N/A to PC addressing if (((address & 0x400000) == 0) && ((address & 0x8000) == 0)) return -1; - switch (Data.Inst.RomMapMode) + switch (mode) { case Data.ROMMapMode.LoROM: { // SRAM is N/A to PC addressing if (((address & 0x700000) == 0x700000) && ((address & 0x8000) == 0)) return -1; - return UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); + return _UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); } case Data.ROMMapMode.HiROM: { - return UnmirroredOffset(address & 0x3FFFFF); + return _UnmirroredOffset(address & 0x3FFFFF); } case Data.ROMMapMode.SuperMMC: { - return UnmirroredOffset(address & 0x3FFFFF); // todo, treated as hirom atm + return _UnmirroredOffset(address & 0x3FFFFF); // todo, treated as hirom atm } case Data.ROMMapMode.SA1ROM: case Data.ROMMapMode.ExSA1ROM: @@ -212,10 +54,10 @@ public static int ConvertSNEStoPC(int address) if (address >= 0xC00000) { - if (Data.Inst.RomMapMode == Data.ROMMapMode.ExSA1ROM) - return UnmirroredOffset(address & 0x7FFFFF); + if (mode == Data.ROMMapMode.ExSA1ROM) + return _UnmirroredOffset(address & 0x7FFFFF); else - return UnmirroredOffset(address & 0x3FFFFF); + return _UnmirroredOffset(address & 0x3FFFFF); } else { @@ -224,7 +66,7 @@ public static int ConvertSNEStoPC(int address) // SRAM is N/A to PC addressing if (((address & 0x8000) == 0)) return -1; - return UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); + return _UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); } } case Data.ROMMapMode.SuperFX: @@ -234,28 +76,31 @@ public static int ConvertSNEStoPC(int address) if (address < 0x400000) { - return UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); - } else if (address < 0x600000) + return _UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); + } + else if (address < 0x600000) { - return UnmirroredOffset(address & 0x3FFFFF); - } else if (address < 0xC00000) + return _UnmirroredOffset(address & 0x3FFFFF); + } + else if (address < 0xC00000) { - return 0x200000 + UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); - } else + return 0x200000 + _UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); + } + else { - return 0x400000 + UnmirroredOffset(address & 0x3FFFFF); + return 0x400000 + _UnmirroredOffset(address & 0x3FFFFF); } } case Data.ROMMapMode.ExHiROM: { - return UnmirroredOffset(((~address & 0x800000) >> 1) | (address & 0x3FFFFF)); + return _UnmirroredOffset(((~address & 0x800000) >> 1) | (address & 0x3FFFFF)); } case Data.ROMMapMode.ExLoROM: { // SRAM is N/A to PC addressing if (((address & 0x700000) == 0x700000) && ((address & 0x8000) == 0)) return -1; - return UnmirroredOffset((((address ^ 0x800000) & 0xFF0000) >> 1) | (address & 0x7FFF)); + return _UnmirroredOffset((((address ^ 0x800000) & 0xFF0000) >> 1) | (address & 0x7FFF)); } default: { @@ -264,36 +109,70 @@ public static int ConvertSNEStoPC(int address) } } - public static string ReadZipString(byte[] unzipped, ref int pointer) + public static int ConvertPCtoSNES(int offset, Data.ROMMapMode romMapMode, Data.ROMSpeed romSpeed) { - var label = ""; - while (unzipped[pointer] != 0) - label += (char)unzipped[pointer++]; - pointer++; - return label; + switch (romMapMode) + { + case Data.ROMMapMode.LoROM: + offset = ((offset & 0x3F8000) << 1) | 0x8000 | (offset & 0x7FFF); + if (romSpeed == Data.ROMSpeed.FastROM || offset >= 0x7E0000) offset |= 0x800000; + return offset; + case Data.ROMMapMode.HiROM: + offset |= 0x400000; + if (romSpeed == Data.ROMSpeed.FastROM || offset >= 0x7E0000) offset |= 0x800000; + return offset; + case Data.ROMMapMode.ExHiROM when offset < 0x40000: + offset |= 0xC00000; + return offset; + case Data.ROMMapMode.ExHiROM: + if (offset >= 0x7E0000) offset &= 0x3FFFFF; + return offset; + case Data.ROMMapMode.ExSA1ROM when offset >= 0x400000: + offset += 0x800000; + return offset; + } + + offset = ((offset & 0x3F8000) << 1) | 0x8000 | (offset & 0x7FFF); + if (offset >= 0x400000) offset += 0x400000; + + return offset; } - private static int UnmirroredOffset(int offset) - { - int size = Data.Inst.GetROMSize(); + public delegate int AddressConverter(int address); - // most of the time this is true; for efficiency - if (offset < size) return offset; + public static int ReadStringsTable(byte[] bytes, int starting_index, int stringsPerEntry, AddressConverter converter, Action processTableEntry) + { + var strings = new List(); - int repeatSize = 0x8000; - while (repeatSize < size) repeatSize <<= 1; + var pos = starting_index; + var num_table_entries = Util.ByteArrayToInteger(bytes, pos); + pos += 4; - int repeatedOffset = offset % repeatSize; + for (var entry = 0; entry < num_table_entries; ++entry) + { + var offset = converter(Util.ByteArrayToInteger(bytes, pos)); + pos += 4; - // this will then be true for ROM sizes of powers of 2 - if (repeatedOffset < size) return repeatedOffset; + strings.Clear(); + for (var j = 0; j < stringsPerEntry; ++j) + { + pos += Util.ReadNullTerminatedString(bytes, pos, out var str); + strings.Add(str); + } + processTableEntry(offset, strings.ToArray()); + } - // for ROM sizes not powers of 2, it's kinda ugly - int sizeOfSmallerSection = 0x8000; - while (size % (sizeOfSmallerSection << 1) == 0) sizeOfSmallerSection <<= 1; + return pos - starting_index; + } - while (repeatedOffset >= size) repeatedOffset -= sizeOfSmallerSection; - return repeatedOffset; + public static int ReadNullTerminatedString(byte[] bytes, int starting_offset, out string str) + { + str = ""; + var pos = starting_offset; + while (bytes[pos] != 0) + str += (char)bytes[pos++]; + pos++; + return pos - starting_offset; } public static byte[] IntegerToByteArray(int a) @@ -376,6 +255,60 @@ public static string TypeToString(Data.FlagType flag) return ""; } + public static int UnmirroredOffset(int offset, int size) + { + // most of the time this is true; for efficiency + if (offset < size) return offset; + + int repeatSize = 0x8000; + while (repeatSize < size) repeatSize <<= 1; + + int repeatedOffset = offset % repeatSize; + + // this will then be true for ROM sizes of powers of 2 + if (repeatedOffset < size) return repeatedOffset; + + // for ROM sizes not powers of 2, it's kinda ugly + int sizeOfSmallerSection = 0x8000; + while (size % (sizeOfSmallerSection << 1) == 0) sizeOfSmallerSection <<= 1; + + while (repeatedOffset >= size) repeatedOffset -= sizeOfSmallerSection; + return repeatedOffset; + } + + public static string GetRomMapModeName(Data.ROMMapMode mode) + { + switch (mode) + { + case Data.ROMMapMode.ExSA1ROM: + return "SA-1 ROM (FuSoYa's 8MB mapper)"; + + case Data.ROMMapMode.SA1ROM: + return "SA-1 ROM"; + + case Data.ROMMapMode.SuperFX: + return "SuperFX"; + + case Data.ROMMapMode.LoROM: + return "LoROM"; + + case Data.ROMMapMode.HiROM: + return "HiROM"; + + case Data.ROMMapMode.SuperMMC: + return "Super MMC"; + + case Data.ROMMapMode.ExHiROM: + return "ExHiROM"; + + case Data.ROMMapMode.ExLoROM: + return "ExLoROM"; + + default: + return "Unknown mapping"; + } + } + public static string TypeToLabel(Data.FlagType flag) { switch (flag) @@ -424,6 +357,38 @@ public static int TypeStepSize(Data.FlagType flag) return 0; } + public static Data.ROMMapMode DetectROMMapMode(IReadOnlyList rom_bytes, out bool couldnt_detect) + { + couldnt_detect = false; + + if ((rom_bytes[Data.LOROM_SETTING_OFFSET] & 0xEF) == 0x23) + { + return rom_bytes.Count > 0x400000 ? Data.ROMMapMode.ExSA1ROM : Data.ROMMapMode.SA1ROM; + } + else if ((rom_bytes[Data.LOROM_SETTING_OFFSET] & 0xEC) == 0x20) + { + return (rom_bytes[Data.LOROM_SETTING_OFFSET + 1] & 0xF0) == 0x10 ? Data.ROMMapMode.SuperFX : Data.ROMMapMode.LoROM; + } + else if (rom_bytes.Count >= 0x10000 && (rom_bytes[Data.HIROM_SETTING_OFFSET] & 0xEF) == 0x21) + { + return Data.ROMMapMode.HiROM; + } + else if (rom_bytes.Count >= 0x10000 && (rom_bytes[Data.HIROM_SETTING_OFFSET] & 0xE7) == 0x22) + { + return Data.ROMMapMode.SuperMMC; + } + else if (rom_bytes.Count >= 0x410000 && (rom_bytes[Data.EXHIROM_SETTING_OFFSET] & 0xEF) == 0x25) + { + return Data.ROMMapMode.ExHiROM; + } + else + { + // detection failed. take our best guess..... + couldnt_detect = true; + return rom_bytes.Count > 0x40000 ? Data.ROMMapMode.ExLoROM : Data.ROMMapMode.LoROM; + } + } + public static IEnumerable ReadLines(string path) { using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 0x1000, FileOptions.SequentialScan)) @@ -500,98 +465,13 @@ public static byte[] StringToByteArray(string s) return array; } - public static void PaintCell(int offset, DataGridViewCellStyle style, int column, int selOffset) + // read a fixed length string from an array of bytes. does not check for null termination + public static string ReadStringFromByteArray(byte[] bytes, int count, int offset) { - // editable cells show up green - if (column == 0 || column == 8 || column == 9 || column == 12) style.SelectionBackColor = Color.Chartreuse; - - switch (Data.Inst.GetFlag(offset)) - { - case Data.FlagType.Unreached: - style.BackColor = Color.LightGray; - style.ForeColor = Color.DarkSlateGray; - break; - case Data.FlagType.Opcode: - int opcode = Data.Inst.GetROMByte(offset); - switch (column) - { - case 4: // <*> - Data.InOutPoint point = Data.Inst.GetInOutPoint(offset); - int r = 255, g = 255, b = 255; - if ((point & (Data.InOutPoint.EndPoint | Data.InOutPoint.OutPoint)) != 0) g -= 50; - if ((point & (Data.InOutPoint.InPoint)) != 0) r -= 50; - if ((point & (Data.InOutPoint.ReadPoint)) != 0) b -= 50; - style.BackColor = Color.FromArgb(r, g, b); - break; - case 5: // Instruction - if (opcode == 0x40 || opcode == 0xCB || opcode == 0xDB || opcode == 0xF8 // RTI WAI STP SED - || opcode == 0xFB || opcode == 0x00 || opcode == 0x02 || opcode == 0x42 // XCE BRK COP WDM - ) style.BackColor = Color.Yellow; - break; - case 8: // Data Bank - if (opcode == 0xAB || opcode == 0x44 || opcode == 0x54) // PLB MVP MVN - style.BackColor = Color.OrangeRed; - else if (opcode == 0x8B) // PHB - style.BackColor = Color.Yellow; - break; - case 9: // Direct Page - if (opcode == 0x2B || opcode == 0x5B) // PLD TCD - style.BackColor = Color.OrangeRed; - if (opcode == 0x0B || opcode == 0x7B) // PHD TDC - style.BackColor = Color.Yellow; - break; - case 10: // M Flag - case 11: // X Flag - int mask = column == 10 ? 0x20 : 0x10; - if (opcode == 0x28 || ((opcode == 0xC2 || opcode == 0xE2) // PLP SEP REP - && (Data.Inst.GetROMByte(offset + 1) & mask) != 0)) // relevant bit set - style.BackColor = Color.OrangeRed; - if (opcode == 0x08) // PHP - style.BackColor = Color.Yellow; - break; - } - break; - case Data.FlagType.Operand: - style.ForeColor = Color.LightGray; - break; - case Data.FlagType.Graphics: - style.BackColor = Color.LightPink; - break; - case Data.FlagType.Music: - style.BackColor = Color.PowderBlue; - break; - case Data.FlagType.Data8Bit: - case Data.FlagType.Data16Bit: - case Data.FlagType.Data24Bit: - case Data.FlagType.Data32Bit: - style.BackColor = Color.NavajoWhite; - break; - case Data.FlagType.Pointer16Bit: - case Data.FlagType.Pointer24Bit: - case Data.FlagType.Pointer32Bit: - style.BackColor = Color.Orchid; - break; - case Data.FlagType.Text: - style.BackColor = Color.Aquamarine; - break; - case Data.FlagType.Empty: - style.BackColor = Color.DarkSlateGray; - style.ForeColor = Color.LightGray; - break; - } - - if (selOffset >= 0 && selOffset < Data.Inst.GetROMSize()) - { - if (column == 1 - //&& (Data.Inst.GetFlag(selOffset) == Data.FlagType.Opcode || Data.Inst.GetFlag(selOffset) == Data.FlagType.Unreached) - && ConvertSNEStoPC(GetIntermediateAddressOrPointer(selOffset)) == offset - ) style.BackColor = Color.DeepPink; - - if (column == 6 - //&& (Data.Inst.GetFlag(offset) == Data.FlagType.Opcode || Data.Inst.GetFlag(offset) == Data.FlagType.Unreached) - && ConvertSNEStoPC(GetIntermediateAddressOrPointer(offset)) == selOffset - ) style.BackColor = Color.DeepPink; - } + var myName = ""; + for (var i = 0; i < count; i++) + myName += (char)bytes[offset - count + i]; + return myName; } public static long GetFileSizeInBytes(string filename) @@ -614,5 +494,66 @@ public static void InvokeIfRequired(this ISynchronizeInvoke obj, MethodInvoker a action(); } } + + + // https://stackoverflow.com/questions/33119119/unzip-byte-array-in-c-sharp + public static byte[] TryUnzip(byte[] data) + { + try + { + using (MemoryStream comp = new MemoryStream(data)) + using (GZipStream gzip = new GZipStream(comp, CompressionMode.Decompress)) + using (MemoryStream res = new MemoryStream()) + { + gzip.CopyTo(res); + return res.ToArray(); + } + } + catch (Exception) + { + return null; + } + } + public static byte[] TryZip(byte[] data) + { + try + { + using (MemoryStream comp = new MemoryStream()) + using (GZipStream gzip = new GZipStream(comp, CompressionMode.Compress)) + { + gzip.Write(data, 0, data.Length); + gzip.Close(); + return comp.ToArray(); + } + } + catch (Exception) + { + return null; + } + } + + public static byte[] ReadAllRomBytesFromFile(string filename) + { + var smc = File.ReadAllBytes(filename); + var rom = new byte[smc.Length & 0x7FFFFC00]; + + if ((smc.Length & 0x3FF) == 0x200) + for (int i = 0; i < rom.Length; i++) + rom[i] = smc[i + 0x200]; + else if ((smc.Length & 0x3FF) != 0) + throw new InvalidDataException("This ROM has an unusual size. It can't be opened."); + else + rom = smc; + + if (rom.Length < 0x8000) + throw new InvalidDataException("This ROM is too small. It can't be opened."); + + return rom; + } + public static string PromptToSelectFile(string initialDirectory = null) + { + var open = new OpenFileDialog { InitialDirectory = initialDirectory }; + return open.ShowDialog() == DialogResult.OK ? open.FileName : null; + } } } diff --git a/DiztinGUIsh/static/diz/CPU65C816.cs b/DiztinGUIsh/static/diz/CPU65C816.cs index 258a4b3e..c9f878d3 100644 --- a/DiztinGUIsh/static/diz/CPU65C816.cs +++ b/DiztinGUIsh/static/diz/CPU65C816.cs @@ -6,46 +6,51 @@ namespace DiztinGUIsh { - public static class CPU65C816 + public class CPU65C816 { - public static int Step(int offset, bool branch, bool force, int prevOffset) + private readonly Data Data; + public CPU65C816(Data data) { - int opcode = Data.Inst.GetROMByte(offset); - int prevDirectPage = Data.Inst.GetDirectPage(offset); - int prevDataBank = Data.Inst.GetDataBank(offset); - bool prevX = Data.Inst.GetXFlag(offset), prevM = Data.Inst.GetMFlag(offset); + Data = data; + } + public int Step(int offset, bool branch, bool force, int prevOffset) + { + int opcode = Data.GetROMByte(offset); + int prevDirectPage = Data.GetDirectPage(offset); + int prevDataBank = Data.GetDataBank(offset); + bool prevX = Data.GetXFlag(offset), prevM = Data.GetMFlag(offset); - while (prevOffset >= 0 && Data.Inst.GetFlag(prevOffset) == Data.FlagType.Operand) prevOffset--; - if (prevOffset >= 0 && Data.Inst.GetFlag(prevOffset) == Data.FlagType.Opcode) + while (prevOffset >= 0 && Data.GetFlag(prevOffset) == Data.FlagType.Operand) prevOffset--; + if (prevOffset >= 0 && Data.GetFlag(prevOffset) == Data.FlagType.Opcode) { - prevDirectPage = Data.Inst.GetDirectPage(prevOffset); - prevDataBank = Data.Inst.GetDataBank(prevOffset); - prevX = Data.Inst.GetXFlag(prevOffset); - prevM = Data.Inst.GetMFlag(prevOffset); + prevDirectPage = Data.GetDirectPage(prevOffset); + prevDataBank = Data.GetDataBank(prevOffset); + prevX = Data.GetXFlag(prevOffset); + prevM = Data.GetMFlag(prevOffset); } if (opcode == 0xC2 || opcode == 0xE2) // REP SEP { - prevX = (Data.Inst.GetROMByte(offset + 1) & 0x10) != 0 ? opcode == 0xE2 : prevX; - prevM = (Data.Inst.GetROMByte(offset + 1) & 0x20) != 0 ? opcode == 0xE2 : prevM; + prevX = (Data.GetROMByte(offset + 1) & 0x10) != 0 ? opcode == 0xE2 : prevX; + prevM = (Data.GetROMByte(offset + 1) & 0x20) != 0 ? opcode == 0xE2 : prevM; } // set first byte first, so the instruction length is correct - Data.Inst.SetFlag(offset, Data.FlagType.Opcode); - Data.Inst.SetDataBank(offset, prevDataBank); - Data.Inst.SetDirectPage(offset, prevDirectPage); - Data.Inst.SetXFlag(offset, prevX); - Data.Inst.SetMFlag(offset, prevM); + Data.SetFlag(offset, Data.FlagType.Opcode); + Data.SetDataBank(offset, prevDataBank); + Data.SetDirectPage(offset, prevDirectPage); + Data.SetXFlag(offset, prevX); + Data.SetMFlag(offset, prevM); int length = GetInstructionLength(offset); for (int i = 1; i < length; i++) { - Data.Inst.SetFlag(offset + i, Data.FlagType.Operand); - Data.Inst.SetDataBank(offset + i, prevDataBank); - Data.Inst.SetDirectPage(offset + i, prevDirectPage); - Data.Inst.SetXFlag(offset + i, prevX); - Data.Inst.SetMFlag(offset + i, prevM); + Data.SetFlag(offset + i, Data.FlagType.Operand); + Data.SetDataBank(offset + i, prevDataBank); + Data.SetDirectPage(offset + i, prevDirectPage); + Data.SetXFlag(offset + i, prevX); + Data.SetMFlag(offset + i, prevM); } MarkInOutPoints(offset); @@ -57,19 +62,20 @@ public static int Step(int offset, bool branch, bool force, int prevOffset) || opcode == 0x70 || opcode == 0x90 || opcode == 0xB0 || opcode == 0xD0 // BVS BCC BCS BNE || opcode == 0xF0 || opcode == 0x20 || opcode == 0x22)))) // BEQ JSR JSL { - int iaNextOffsetPC = Util.ConvertSNEStoPC(Util.GetIntermediateAddress(offset, true)); - if (iaNextOffsetPC >= 0) nextOffset = iaNextOffsetPC; + int iaNextOffsetPC = Data.ConvertSNEStoPC(GetIntermediateAddress(offset, true)); + if (iaNextOffsetPC >= 0) + nextOffset = iaNextOffsetPC; } return nextOffset; } - public static int GetIntermediateAddress(int offset, bool resolve) + public int GetIntermediateAddress(int offset, bool resolve) { int bank, directPage, operand, programCounter; - int opcode = Data.Inst.GetROMByte(offset); + int opcode = Data.GetROMByte(offset); - AddressMode mode = GetAddressMode(offset); + var mode = GetAddressMode(offset); switch (mode) { case AddressMode.DIRECT_PAGE: @@ -82,8 +88,8 @@ public static int GetIntermediateAddress(int offset, bool resolve) case AddressMode.DIRECT_PAGE_LONG_INDIRECT_Y_INDEX: if (resolve) { - directPage = Data.Inst.GetDirectPage(offset); - operand = Data.Inst.GetROMByte(offset + 1); + directPage = Data.GetDirectPage(offset); + operand = Data.GetROMByte(offset + 1); return (directPage + operand) & 0xFFFF; } else @@ -92,39 +98,39 @@ public static int GetIntermediateAddress(int offset, bool resolve) } case AddressMode.DIRECT_PAGE_S_INDEX: case AddressMode.DIRECT_PAGE_S_INDEX_INDIRECT_Y_INDEX: - return Data.Inst.GetROMByte(offset + 1); + return Data.GetROMByte(offset + 1); case AddressMode.ADDRESS: case AddressMode.ADDRESS_X_INDEX: case AddressMode.ADDRESS_Y_INDEX: case AddressMode.ADDRESS_X_INDEX_INDIRECT: bank = (opcode == 0x20 || opcode == 0x4C || opcode == 0x7C || opcode == 0xFC) ? - Util.ConvertPCtoSNES(offset) >> 16 : - Data.Inst.GetDataBank(offset); - operand = Util.GetROMWord(offset + 1); + Data.ConvertPCtoSNES(offset) >> 16 : + Data.GetDataBank(offset); + operand = Data.GetROMWord(offset + 1); return (bank << 16) | operand; case AddressMode.ADDRESS_INDIRECT: case AddressMode.ADDRESS_LONG_INDIRECT: - operand = Util.GetROMWord(offset + 1); + operand = Data.GetROMWord(offset + 1); return operand; case AddressMode.LONG: case AddressMode.LONG_X_INDEX: - operand = Util.GetROMLong(offset + 1); + operand = Data.GetROMLong(offset + 1); return operand; case AddressMode.RELATIVE_8: - programCounter = Util.ConvertPCtoSNES(offset + 2); + programCounter = Data.ConvertPCtoSNES(offset + 2); bank = programCounter >> 16; - offset = (sbyte)Data.Inst.GetROMByte(offset + 1); + offset = (sbyte)Data.GetROMByte(offset + 1); return (bank << 16) | ((programCounter + offset) & 0xFFFF); case AddressMode.RELATIVE_16: - programCounter = Util.ConvertPCtoSNES(offset + 3); + programCounter = Data.ConvertPCtoSNES(offset + 3); bank = programCounter >> 16; - offset = (short)Util.GetROMWord(offset + 1); + offset = (short)Data.GetROMWord(offset + 1); return (bank << 16) | ((programCounter + offset) & 0xFFFF); } return -1; } - public static string GetInstruction(int offset) + public string GetInstruction(int offset) { AddressMode mode = GetAddressMode(offset); string format = GetInstructionFormatString(offset); @@ -132,16 +138,16 @@ public static string GetInstruction(int offset) string op1 = "", op2 = ""; if (mode == AddressMode.BLOCK_MOVE) { - op1 = Util.NumberToBaseString(Data.Inst.GetROMByte(offset + 1), Util.NumberBase.Hexadecimal, 2, true); - op2 = Util.NumberToBaseString(Data.Inst.GetROMByte(offset + 2), Util.NumberBase.Hexadecimal, 2, true); + op1 = Util.NumberToBaseString(Data.GetROMByte(offset + 1), Util.NumberBase.Hexadecimal, 2, true); + op2 = Util.NumberToBaseString(Data.GetROMByte(offset + 2), Util.NumberBase.Hexadecimal, 2, true); } else if (mode == AddressMode.CONSTANT_8 || mode == AddressMode.IMMEDIATE_8) { - op1 = Util.NumberToBaseString(Data.Inst.GetROMByte(offset + 1), Util.NumberBase.Hexadecimal, 2, true); + op1 = Util.NumberToBaseString(Data.GetROMByte(offset + 1), Util.NumberBase.Hexadecimal, 2, true); } else if (mode == AddressMode.IMMEDIATE_16) { - op1 = Util.NumberToBaseString(Util.GetROMWord(offset + 1), Util.NumberBase.Hexadecimal, 4, true); + op1 = Util.NumberToBaseString(Data.GetROMWord(offset + 1), Util.NumberBase.Hexadecimal, 4, true); } else { @@ -153,7 +159,7 @@ public static string GetInstruction(int offset) return string.Format(format, mnemonic, op1, op2); } - public static int GetInstructionLength(int offset) + public int GetInstructionLength(int offset) { AddressMode mode = GetAddressMode(offset); switch (mode) @@ -192,10 +198,10 @@ public static int GetInstructionLength(int offset) return 1; } - public static void MarkInOutPoints(int offset) + public void MarkInOutPoints(int offset) { - int opcode = Data.Inst.GetROMByte(offset); - int iaOffsetPC = Util.ConvertSNEStoPC(Util.GetIntermediateAddress(offset, true)); + int opcode = Data.GetROMByte(offset); + int iaOffsetPC = Data.ConvertSNEStoPC(Data.GetIntermediateAddress(offset, true)); // set read point on EA if (iaOffsetPC >= 0 && ( // these are all read/write/math instructions @@ -203,13 +209,13 @@ public static void MarkInOutPoints(int offset) ((opcode & 0x1F) == 0x12) || ((opcode & 0x1F) == 0x19)) && (opcode != 0x45) && (opcode != 0x55) && (opcode != 0xF5) && (opcode != 0x4C) && (opcode != 0x5C) && (opcode != 0x6C) && (opcode != 0x7C) && (opcode != 0xDC) && (opcode != 0xFC) - ) Data.Inst.SetInOutPoint(iaOffsetPC, Data.InOutPoint.ReadPoint); + ) Data.SetInOutPoint(iaOffsetPC, Data.InOutPoint.ReadPoint); // set end point on offset if (opcode == 0x40 || opcode == 0x4C || opcode == 0x5C || opcode == 0x60 // RTI JMP JML RTS || opcode == 0x6B || opcode == 0x6C || opcode == 0x7C || opcode == 0x80 // RTL JMP JMP BRA || opcode == 0x82 || opcode == 0xDB || opcode == 0xDC // BRL STP JML - ) Data.Inst.SetInOutPoint(offset, Data.InOutPoint.EndPoint); + ) Data.SetInOutPoint(offset, Data.InOutPoint.EndPoint); // set out point on offset // set in point on EA @@ -219,26 +225,26 @@ public static void MarkInOutPoints(int offset) || opcode == 0x90 || opcode == 0xB0 || opcode == 0xD0 || opcode == 0xF0 // BCC BCS BNE BEQ || opcode == 0x20 || opcode == 0x22)) // JSR JSL { - Data.Inst.SetInOutPoint(offset, Data.InOutPoint.OutPoint); - Data.Inst.SetInOutPoint(iaOffsetPC, Data.InOutPoint.InPoint); + Data.SetInOutPoint(offset, Data.InOutPoint.OutPoint); + Data.SetInOutPoint(iaOffsetPC, Data.InOutPoint.InPoint); } } - private static string FormatOperandAddress(int offset, AddressMode mode) + private string FormatOperandAddress(int offset, AddressMode mode) { - int address = Util.GetIntermediateAddress(offset); + int address = Data.GetIntermediateAddress(offset); if (address < 0) return ""; - if (Data.Inst.GetLabelName(address) != "") return Data.Inst.GetLabelName(address); + if (Data.GetLabelName(address) != "") return Data.GetLabelName(address); int count = BytesToShow(mode); - if (mode == AddressMode.RELATIVE_8 || mode == AddressMode.RELATIVE_16) address = Util.GetROMWord(offset + 1); + if (mode == AddressMode.RELATIVE_8 || mode == AddressMode.RELATIVE_16) address = Data.GetROMWord(offset + 1); address &= ~(-1 << (8 * count)); return Util.NumberToBaseString(address, Util.NumberBase.Hexadecimal, 2 * count, true); } - private static string GetMnemonic(int offset, bool showHint = true) + private string GetMnemonic(int offset, bool showHint = true) { - string mn = mnemonics[Data.Inst.GetROMByte(offset)]; + string mn = mnemonics[Data.GetROMByte(offset)]; if (showHint) { AddressMode mode = GetAddressMode(offset); @@ -256,7 +262,7 @@ private static string GetMnemonic(int offset, bool showHint = true) return mn; } - private static int BytesToShow(AddressMode mode) + private int BytesToShow(AddressMode mode) { switch (mode) { @@ -293,7 +299,7 @@ private static int BytesToShow(AddressMode mode) // {0} = mnemonic // {1} = intermediate address / label OR operand 1 for block move // {2} = operand 2 for block move - private static string GetInstructionFormatString(int offset) + private string GetInstructionFormatString(int offset) { AddressMode mode = GetAddressMode(offset); switch (mode) @@ -342,11 +348,11 @@ private static string GetInstructionFormatString(int offset) return ""; } - private static AddressMode GetAddressMode(int offset) + private AddressMode GetAddressMode(int offset) { - AddressMode mode = addressingModes[Data.Inst.GetROMByte(offset)]; - if (mode == AddressMode.IMMEDIATE_M_FLAG_DEPENDENT) return Data.Inst.GetMFlag(offset) ? AddressMode.IMMEDIATE_8 : AddressMode.IMMEDIATE_16; - else if (mode == AddressMode.IMMEDIATE_X_FLAG_DEPENDENT) return Data.Inst.GetXFlag(offset) ? AddressMode.IMMEDIATE_8 : AddressMode.IMMEDIATE_16; + AddressMode mode = addressingModes[Data.GetROMByte(offset)]; + if (mode == AddressMode.IMMEDIATE_M_FLAG_DEPENDENT) return Data.GetMFlag(offset) ? AddressMode.IMMEDIATE_8 : AddressMode.IMMEDIATE_16; + else if (mode == AddressMode.IMMEDIATE_X_FLAG_DEPENDENT) return Data.GetXFlag(offset) ? AddressMode.IMMEDIATE_8 : AddressMode.IMMEDIATE_16; return mode; } diff --git a/DiztinGUIsh/static/diz/Manager.cs b/DiztinGUIsh/static/diz/Manager.cs index 385eaaec..5d416f5e 100644 --- a/DiztinGUIsh/static/diz/Manager.cs +++ b/DiztinGUIsh/static/diz/Manager.cs @@ -4,426 +4,7 @@ namespace DiztinGUIsh { - public class Manager + /*public class Manager { - public static int Step(int offset, bool branch, bool force, int prevOffset) - { - Project.Inst.unsavedChanges = true; - switch (Data.Inst.GetArchitechture(offset)) - { - case Data.Architechture.CPU65C816: return CPU65C816.Step(offset, branch, force, prevOffset); - case Data.Architechture.APUSPC700: return offset; - case Data.Architechture.GPUSuperFX: return offset; - } - return offset; - } - - public static int AutoStep(int offset, bool harsh, int amount) - { - Project.Inst.unsavedChanges = true; - int newOffset = offset, prevOffset = offset - 1, nextOffset = offset; - if (harsh) - { - while (newOffset < offset + amount) - { - nextOffset = Step(newOffset, false, true, prevOffset); - prevOffset = newOffset; - newOffset = nextOffset; - } - } else - { - Stack stack = new Stack(); - List seenBranches = new List(); - bool keepGoing = true; - - while (keepGoing) - { - switch (Data.Inst.GetArchitechture(newOffset)) - { - case Data.Architechture.CPU65C816: - if (seenBranches.Contains(newOffset)) - { - keepGoing = false; - break; - } - - int opcode = Data.Inst.GetROMByte(newOffset); - - nextOffset = Step(newOffset, false, false, prevOffset); - int jumpOffset = Step(newOffset, true, false, prevOffset); - - if (opcode == 0x40 || opcode == 0xCB || opcode == 0xDB || opcode == 0xF8 // RTI WAI STP SED - || opcode == 0xFB || opcode == 0x00 || opcode == 0x02 || opcode == 0x42 // XCE BRK COP WDM - || opcode == 0x6C || opcode == 0x7C || opcode == 0xDC || opcode == 0xFC // JMP JMP JML JSR - ) keepGoing = false; - - if (opcode == 0x4C || opcode == 0x5C || opcode == 0x80 || opcode == 0x82 // JMP JML BRA BRL - || opcode == 0x10 || opcode == 0x30 || opcode == 0x50 || opcode == 0x70 // BPL BMI BVC BVS - || opcode == 0x90 || opcode == 0xB0 || opcode == 0xD0 || opcode == 0xF0 // BCC BCS BNE BEQ - ) seenBranches.Add(newOffset); - - if (opcode == 0x08) // PHP - { - stack.Push(Data.Inst.GetMXFlags(newOffset)); - } else if (opcode == 0x28) // PLP - { - if (stack.Count == 0) - { - keepGoing = false; break; - } else - { - Data.Inst.SetMXFlags(newOffset, stack.Pop()); - } - } - - if (opcode == 0x60 || opcode == 0x6B) // RTS RTL - { - if (stack.Count == 0) - { - keepGoing = false; - break; - } - else - { - prevOffset = newOffset; - newOffset = stack.Pop(); - } - } else if (opcode == 0x20 || opcode == 0x22) // JSR JSL - { - stack.Push(nextOffset); - prevOffset = newOffset; - newOffset = jumpOffset; - } else - { - prevOffset = newOffset; - newOffset = nextOffset; - } - break; - case Data.Architechture.APUSPC700: - case Data.Architechture.GPUSuperFX: - nextOffset = Step(newOffset, false, true, prevOffset); - prevOffset = newOffset; - newOffset = nextOffset; - break; - } - - Data.FlagType flag = Data.Inst.GetFlag(newOffset); - if (!(flag == Data.FlagType.Unreached || flag == Data.FlagType.Opcode || flag == Data.FlagType.Operand)) keepGoing = false; - } - } - return newOffset; - } - - public static int Mark(int offset, Data.FlagType type, int count) - { - Project.Inst.unsavedChanges = true; - int i, size = Data.Inst.GetROMSize(); - for (i = 0; i < count && offset + i < size; i++) Data.Inst.SetFlag(offset + i, type); - return offset + i < size ? offset + i : size - 1; - } - - public static int MarkDataBank(int offset, int db, int count) - { - Project.Inst.unsavedChanges = true; - int i, size = Data.Inst.GetROMSize(); - for (i = 0; i < count && offset + i < size; i++) Data.Inst.SetDataBank(offset + i, db); - return offset + i < size ? offset + i : size - 1; - } - - public static int MarkDirectPage(int offset, int dp, int count) - { - Project.Inst.unsavedChanges = true; - int i, size = Data.Inst.GetROMSize(); - for (i = 0; i < count && offset + i < size; i++) Data.Inst.SetDirectPage(offset + i, dp); - return offset + i < size ? offset + i : size - 1; - } - - public static int MarkXFlag(int offset, bool x, int count) - { - Project.Inst.unsavedChanges = true; - int i, size = Data.Inst.GetROMSize(); - for (i = 0; i < count && offset + i < size; i++) Data.Inst.SetXFlag(offset + i, x); - return offset + i < size ? offset + i : size - 1; - } - - public static int MarkMFlag(int offset, bool m, int count) - { - Project.Inst.unsavedChanges = true; - int i, size = Data.Inst.GetROMSize(); - for (i = 0; i < count && offset + i < size; i++) Data.Inst.SetMFlag(offset + i, m); - return offset + i < size ? offset + i : size - 1; - } - - public static int MarkArchitechture(int offset, Data.Architechture arch, int count) - { - Project.Inst.unsavedChanges = true; - int i, size = Data.Inst.GetROMSize(); - for (i = 0; i < count && offset + i < size; i++) Data.Inst.SetArchitechture(offset + i, arch); - return offset + i < size ? offset + i : size - 1; - } - - public static int GetInstructionLength(int offset) - { - switch (Data.Inst.GetArchitechture(offset)) - { - case Data.Architechture.CPU65C816: return CPU65C816.GetInstructionLength(offset); - case Data.Architechture.APUSPC700: return 1; - case Data.Architechture.GPUSuperFX: return 1; - } - return 1; - } - - public static int FixMisalignedFlags() - { - int count = 0, size = Data.Inst.GetROMSize(); - - for (int i = 0; i < size; i++) - { - Data.FlagType flag = Data.Inst.GetFlag(i); - - if (flag == Data.FlagType.Opcode) - { - int len = GetInstructionLength(i); - for (int j = 1; j < len && i + j < size; j++) - { - if (Data.Inst.GetFlag(i + j) != Data.FlagType.Operand) - { - Data.Inst.SetFlag(i + j, Data.FlagType.Operand); - count++; - } - } - i += len - 1; - } else if (flag == Data.FlagType.Operand) - { - Data.Inst.SetFlag(i, Data.FlagType.Opcode); - count++; - i--; - } else if (Util.TypeStepSize(flag) > 1) - { - int step = Util.TypeStepSize(flag); - for (int j = 1; j < step; j++) - { - if (Data.Inst.GetFlag(i + j) != flag) - { - Data.Inst.SetFlag(i + j, flag); - count++; - } - } - i += step - 1; - } - } - - if (count > 0) Project.Inst.unsavedChanges = true; - - return count; - } - - public static void RescanInOutPoints() - { - for (int i = 0; i < Data.Inst.GetROMSize(); i++) Data.Inst.ClearInOutPoint(i); - - for (int i = 0; i < Data.Inst.GetROMSize(); i++) - { - if (Data.Inst.GetFlag(i) == Data.FlagType.Opcode) - { - switch (Data.Inst.GetArchitechture(i)) - { - case Data.Architechture.CPU65C816: CPU65C816.MarkInOutPoints(i); break; - case Data.Architechture.APUSPC700: break; - case Data.Architechture.GPUSuperFX: break; - } - } - } - - Project.Inst.unsavedChanges = true; - } - - public static int ImportUsageMap(byte[] usageMap) - { - int size = Data.Inst.GetROMSize(); - bool unsaved = false; - int modified = 0; - int prevFlags = 0; - - for (int map = 0; map <= 0xFFFFFF; map++) - { - var i = Util.ConvertSNEStoPC(map); - - if (i == -1 || i >= size) - { - // branch predictor may optimize this - continue; - } - - var flags = (Data.BsnesPlusUsage)usageMap[map]; - - if (flags == 0) - { - // no information available - continue; - } - - if (Data.Inst.GetFlag(i) != Data.FlagType.Unreached) - { - // skip if there is something already set.. - continue; - } - - // opcode: 0x30, operand: 0x20 - if (flags.HasFlag(Data.BsnesPlusUsage.UsageExec)) - { - Data.Inst.SetFlag(i, Data.FlagType.Operand); - - if (flags.HasFlag(Data.BsnesPlusUsage.UsageOpcode)) - { - prevFlags = ((int)flags & 3) << 4; - Data.Inst.SetFlag(i, Data.FlagType.Opcode); - } - - Data.Inst.SetMXFlags(i, prevFlags); - unsaved = true; - modified++; - } - else if (flags.HasFlag(Data.BsnesPlusUsage.UsageRead)) - { - Data.Inst.SetFlag(i, Data.FlagType.Data8Bit); - unsaved = true; - modified++; - } - } - - Project.Inst.unsavedChanges |= unsaved; - return modified; - } - - // this class exists for performance optimization ONLY. - // class representing offsets into a trace log - // we calculate it once from sample data and hang onto it - private class CachedTraceLineIndex - { - private string sample = - "028cde rep #$30 A:0004 X:0000 Y:0004 S:1fdd D:0000 DB:02 nvmxdiZC V:133 H: 654 F:36"; - - // index of the start of the info - public readonly int - addr, - D, DB, - flags, - f_N, f_V, f_M, f_X, f_D, f_I, f_Z, f_C; - - public CachedTraceLineIndex() - { - int SkipToken(string token) - { - return sample.IndexOf(token) + token.Length; - } - - addr = 0; - D = SkipToken("D:"); - DB = SkipToken("DB:"); - flags = DB + 3; - - // flags: nvmxdizc - f_N = flags + 0; - f_V = flags + 1; - f_M = flags + 2; - f_X = flags + 3; - f_D = flags + 4; - f_I = flags + 5; - f_Z = flags + 6; - f_C = flags + 7; - } - } - - static CachedTraceLineIndex CachedIdx = new CachedTraceLineIndex(); - - public static int ImportTraceLogLine(string line) - { - // caution: very performance-sensitive function, please take care when making modifications - // string.IndexOf() is super-slow too. - // Input lines must follow this strict format and be this exact formatting and column indices. - // 028cde rep #$30 A:0004 X:0000 Y:0004 S:1fdd D:0000 DB:02 nvmxdiZC V:133 H: 654 F:36 - - int GetHexValueAt(int startIndex, int length) { - return Convert.ToInt32(line.Substring(startIndex, length), 16); - } - - if (line.Length < 80) - return 0; - - int snesAddress = GetHexValueAt(0, 6); - int pc = Util.ConvertSNEStoPC(snesAddress); - if (pc == -1) - return 0; - - // TODO: error treatment - - int directPage = GetHexValueAt(CachedIdx.D, 4); - int dataBank = GetHexValueAt(CachedIdx.DB, 2); - - // 'X' = unchecked in bsnesplus debugger UI = (8bit), 'x' or '.' = checked (16bit) - bool xflag_set = line[CachedIdx.f_X] == 'X'; - - // 'M' = unchecked in bsnesplus debugger UI = (8bit), 'm' or '.' = checked (16bit) - bool mflag_set = line[CachedIdx.f_M] == 'M'; - - Data.Inst.SetFlag(pc, Data.FlagType.Opcode); - - int modified = 0; - int size = Data.Inst.GetROMSize(); - do - { - Data.Inst.SetDataBank(pc, dataBank); - Data.Inst.SetDirectPage(pc, directPage); - Data.Inst.SetXFlag(pc, xflag_set); - Data.Inst.SetMFlag(pc, mflag_set); - - pc++; - modified++; - } while (pc < size && Data.Inst.GetFlag(pc) == Data.FlagType.Operand); - Project.Inst.unsavedChanges = true; - return modified; - } - - public static void ImportBizHawkCDL(BizHawkCdl cdl) - { - if (!cdl.TryGetValue("CARTROM", out var cdlRomFlags)) - { - throw new InvalidDataException("The CDL file does not contain CARTROM block."); - } - - var size = Math.Min(cdlRomFlags.Count, Data.Inst.GetROMSize()); - bool m = false; - bool x = false; - for (var offset = 0; offset < size; offset++) - { - var cdlFlag = cdlRomFlags[offset]; - if (cdlFlag == BizHawkCdl.Flag.None) - continue; - - var type = Data.FlagType.Unreached; - if ((cdlFlag & BizHawkCdl.Flag.ExecFirst) != 0) - { - type = Data.FlagType.Opcode; - m = (cdlFlag & BizHawkCdl.Flag.CPUMFlag) != 0; - x = (cdlFlag & BizHawkCdl.Flag.CPUXFlag) != 0; - } - else if ((cdlFlag & BizHawkCdl.Flag.ExecOperand) != 0) - type = Data.FlagType.Operand; - else if ((cdlFlag & BizHawkCdl.Flag.CPUData) != 0) - type = Data.FlagType.Data8Bit; - else if ((cdlFlag & BizHawkCdl.Flag.DMAData) != 0) - type = Data.FlagType.Data8Bit; - Mark(offset, type, 1); - - if (type == Data.FlagType.Opcode || type == Data.FlagType.Operand) - { - // Operand reuses the last M and X flag values used in Opcode, - // since BizHawk CDL records M and X flags only in Opcode. - MarkMFlag(offset, m, 1); - MarkXFlag(offset, x, 1); - } - } - } - } + }*/ } diff --git a/DiztinGUIsh/window/AliasList.cs b/DiztinGUIsh/window/AliasList.cs index d601fa06..9037d754 100644 --- a/DiztinGUIsh/window/AliasList.cs +++ b/DiztinGUIsh/window/AliasList.cs @@ -16,10 +16,10 @@ namespace DiztinGUIsh.window public partial class AliasList : Form { // single instance - public static AliasList me; + public static AliasList me; // TODO: get rid of static field and access via MainWindow + private MainWindow mw; public bool locked = false; - private MainWindow mw; private int currentlyEditing = -1; public AliasList(MainWindow main) @@ -54,13 +54,13 @@ private void AliasList_Resize(object sender, EventArgs e) private void jump_Click(object sender, EventArgs e) { - if (int.TryParse((string)dataGridView1.SelectedRows[0].Cells[0].Value, NumberStyles.HexNumber, null, out int val)) + if (!int.TryParse((string) dataGridView1.SelectedRows[0].Cells[0].Value, NumberStyles.HexNumber, null, + out int val)) return; + + int offset = mw.Project.Data.ConvertSNEStoPC(val); + if (offset >= 0) { - int offset = Util.ConvertSNEStoPC(val); - if (offset >= 0) - { - mw.SelectOffset(offset); - } + mw.SelectOffset(offset); } } @@ -79,14 +79,14 @@ private static void SplitOnFirstComma(string instr, out string first_part, out s private void ImportLabelsFromCSV(bool replaceAll) { - DialogResult result = openFileDialog1.ShowDialog(); + var result = openFileDialog1.ShowDialog(); if (result != DialogResult.OK || openFileDialog1.FileName == "") return; int errLine = 0; try { - Dictionary newValues = new Dictionary(); + Dictionary newValues = new Dictionary(); string[] lines = Util.ReadLines(openFileDialog1.FileName).ToArray(); Regex valid_label_chars = new Regex(@"^([a-zA-Z0-9_\-]*)$"); @@ -95,32 +95,32 @@ private void ImportLabelsFromCSV(bool replaceAll) // section. for (int i = 0; i < lines.Length; i++) { - var aliasInfo = new Data.AliasInfo(); + var Label = new Label(); errLine = i + 1; - AliasList.SplitOnFirstComma(lines[i], out var labelAddress, out var remainder); - AliasList.SplitOnFirstComma(remainder, out aliasInfo.name, out aliasInfo.comment); + SplitOnFirstComma(lines[i], out var labelAddress, out var remainder); + SplitOnFirstComma(remainder, out Label.name, out Label.comment); - aliasInfo.CleanUp(); + Label.CleanUp(); - aliasInfo.name = aliasInfo.name.Trim(); - if (!valid_label_chars.Match(aliasInfo.name).Success) - throw new InvalidDataException("invalid label name: " + aliasInfo.name); + Label.name = Label.name.Trim(); + if (!valid_label_chars.Match(Label.name).Success) + throw new InvalidDataException("invalid label name: " + Label.name); - newValues.Add(int.Parse(labelAddress, NumberStyles.HexNumber, null), aliasInfo); + newValues.Add(int.Parse(labelAddress, NumberStyles.HexNumber, null), Label); } // everything read OK, modify the existing list now. point of no return if (replaceAll) - Data.Inst.DeleteAllLabels(); + mw.Project.Data.DeleteAllLabels(); ResetDataGrid(); // this will call AddRow() to add items back to the UI datagrid. - foreach (KeyValuePair pair in newValues) + foreach (KeyValuePair pair in newValues) { - Data.Inst.AddLabel(pair.Key, pair.Value, true); + mw.Project.Data.AddLabel(pair.Key, pair.Value, true); } } catch (Exception ex) @@ -141,7 +141,7 @@ private void export_Click(object sender, EventArgs e) { using (StreamWriter sw = new StreamWriter(saveFileDialog1.FileName)) { - foreach (var pair in Data.Inst.GetAllLabels()) + foreach (var pair in mw.Project.Data.GetAllLabels()) { sw.WriteLine( $"{Util.NumberToBaseString(pair.Key, Util.NumberBase.Hexadecimal, 6)},{pair.Value.name},{pair.Value.comment}"); @@ -159,7 +159,7 @@ private void dataGridView1_UserDeletingRow(object sender, DataGridViewRowCancelE if (int.TryParse((string)dataGridView1.Rows[e.Row.Index].Cells[0].Value, NumberStyles.HexNumber, null, out int val)) { locked = true; - Data.Inst.AddLabel(val, null, true); + mw.Project.Data.AddLabel(val, null, true); locked = false; mw.InvalidateTable(); } @@ -179,10 +179,10 @@ private void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEv private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) { if (dataGridView1.Rows[e.RowIndex].IsNewRow) return; - int val = -1, oldAddress = -1; - int.TryParse((string)dataGridView1.Rows[e.RowIndex].Cells[0].Value, NumberStyles.HexNumber, null, out oldAddress); + int val = -1; + int.TryParse((string)dataGridView1.Rows[e.RowIndex].Cells[0].Value, NumberStyles.HexNumber, null, out var oldAddress); - var labelAliasInfo = new Data.AliasInfo + var labelLabel = new Label { name = (string) dataGridView1.Rows[e.RowIndex].Cells[1].Value, comment = (string)dataGridView1.Rows[e.RowIndex].Cells[2].Value, @@ -198,11 +198,11 @@ private void dataGridView1_CellValidating(object sender, DataGridViewCellValidat { e.Cancel = true; toolStripStatusLabel1.Text = "Must enter a valid hex address."; - } else if (oldAddress == -1 && Data.Inst.GetAllLabels().ContainsKey(val)) + } else if (oldAddress == -1 && mw.Project.Data.GetAllLabels().ContainsKey(val)) { e.Cancel = true; toolStripStatusLabel1.Text = "This address already has a label."; - var x = Data.Inst.GetAllLabels(); + var x = mw.Project.Data.GetAllLabels(); Console.WriteLine(Util.NumberToBaseString(val, Util.NumberBase.Hexadecimal)); } else if (dataGridView1.EditingControl != null) { @@ -213,14 +213,14 @@ private void dataGridView1_CellValidating(object sender, DataGridViewCellValidat case 1: { val = oldAddress; - labelAliasInfo.name = e.FormattedValue.ToString(); + labelLabel.name = e.FormattedValue.ToString(); // todo (validate for valid label characters) break; } case 2: { val = oldAddress; - labelAliasInfo.comment = e.FormattedValue.ToString(); + labelLabel.comment = e.FormattedValue.ToString(); // todo (validate for valid comment characters, if any) break; } @@ -229,8 +229,8 @@ private void dataGridView1_CellValidating(object sender, DataGridViewCellValidat locked = true; if (currentlyEditing >= 0) { - if (val >= 0) Data.Inst.AddLabel(oldAddress, null, true); - Data.Inst.AddLabel(val, labelAliasInfo, true); + if (val >= 0) mw.Project.Data.AddLabel(oldAddress, null, true); + mw.Project.Data.AddLabel(val, labelLabel, true); } locked = false; @@ -238,7 +238,7 @@ private void dataGridView1_CellValidating(object sender, DataGridViewCellValidat mw.InvalidateTable(); } - public void AddRow(int address, Data.AliasInfo alias) + public void AddRow(int address, Label alias) { if (!locked) { diff --git a/DiztinGUIsh/window/MainWindow.Designer.cs b/DiztinGUIsh/window/MainWindow.Designer.cs index 4400a521..64acb053 100644 --- a/DiztinGUIsh/window/MainWindow.Designer.cs +++ b/DiztinGUIsh/window/MainWindow.Designer.cs @@ -128,7 +128,7 @@ private void InitializeComponent() this.percentComplete = new System.Windows.Forms.ToolStripStatusLabel(); this.seperator1 = new System.Windows.Forms.ToolStripStatusLabel(); this.currentMarker = new System.Windows.Forms.ToolStripStatusLabel(); - this.openROMFile = new System.Windows.Forms.OpenFileDialog(); + this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); this.openProjectFile = new System.Windows.Forms.OpenFileDialog(); this.saveProjectFile = new System.Windows.Forms.SaveFileDialog(); this.vScrollBar1 = new System.Windows.Forms.VScrollBar(); @@ -964,7 +964,7 @@ private void InitializeComponent() // // openROMFile // - this.openROMFile.Filter = "SNES ROM Images|*.smc;*.sfc|All files|*.*"; + this.openFileDialog.Filter = "SNES ROM Images|*.smc;*.sfc|All files|*.*"; // // openProjectFile // @@ -1106,7 +1106,7 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem viewHelpToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem aboutToolStripMenuItem; private System.Windows.Forms.ToolStripStatusLabel percentComplete; - private System.Windows.Forms.OpenFileDialog openROMFile; + private System.Windows.Forms.OpenFileDialog openFileDialog; private System.Windows.Forms.OpenFileDialog openProjectFile; private System.Windows.Forms.SaveFileDialog saveProjectFile; private System.Windows.Forms.ToolStripSeparator toolStripSeparator7; diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 80dcc278..c7eb55e0 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -1,22 +1,18 @@ using DiztinGUIsh.window; using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; using System.Drawing; using System.Globalization; using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; +using DiztinGUIsh.loadsave; using DiztinGUIsh.Properties; namespace DiztinGUIsh { public partial class MainWindow : Form { + public Project Project { get; set; } + public MainWindow() { InitializeComponent(); @@ -80,21 +76,20 @@ private void openLastProject() public void UpdateWindowTitle() { this.Text = - (Project.Inst.unsavedChanges ? "*" : "") + - (Project.Inst.currentProjectFile == null ? "New Project" : Project.Inst.currentProjectFile) + + (Project.UnsavedChanges ? "*" : "") + + (Project.ProjectFileName == null ? "New Project" : Project.ProjectFileName) + " - DiztinGUIsh"; } private bool ContinueUnsavedChanges() { - if (Project.Inst.unsavedChanges) - { - DialogResult confirm = MessageBox.Show("You have unsaved changes. They will be lost if you continue.", - "Unsaved Changes", MessageBoxButtons.OKCancel); - return confirm == DialogResult.OK; - } + if (Project == null || !Project.UnsavedChanges) + return true; + + return DialogResult.OK == MessageBox.Show( + "You have unsaved changes. They will be lost if you continue.", + "Unsaved Changes", MessageBoxButtons.OKCancel); - return true; } public void TriggerSaveOptions(bool save, bool saveas) @@ -106,37 +101,66 @@ public void TriggerSaveOptions(bool save, bool saveas) private void newProjectToolStripMenuItem_Click(object sender, EventArgs e) { - if (ContinueUnsavedChanges()) + if (!ContinueUnsavedChanges()) + return; + + var romFilename = PromptForOpenFilename(); + if (string.IsNullOrEmpty(romFilename)) + return; + + if (!TryImportProject(openFileDialog.FileName)) + return; + + OnImportedProjectSuccess(); + } + + private string PromptForOpenFilename() + { + // TODO: combine with another function in Project that looks like this + openFileDialog.InitialDirectory = Project.ProjectFileName; + return openFileDialog.ShowDialog() != DialogResult.OK ? openFileDialog.FileName : null; + } + + private void OnImportedProjectSuccess() + { + importCDLToolStripMenuItem.Enabled = true; + TriggerSaveOptions(false, true); + UpdateWindowTitle(); + UpdateDataGridView(); + UpdatePercent(); + table.Invalidate(); + EnableSubWindows(); + } + + private bool TryImportProject(string romFileToOpen) + { + try { - openROMFile.InitialDirectory = Project.Inst.currentProjectFile; - DialogResult result = openROMFile.ShowDialog(); - if (result == DialogResult.OK) - { - if (Project.Inst.NewProject(openROMFile.FileName)) - { - importCDLToolStripMenuItem.Enabled = true; - TriggerSaveOptions(false, true); - UpdateWindowTitle(); - UpdateDataGridView(); - UpdatePercent(); - table.Invalidate(); - EnableSubWindows(); - } - } + var importSettings = new ImportROMDialog().PromptForImportSettings(romFileToOpen); + if (importSettings == null) + return false; + + Project.ImportRomAndCreateNewProject(importSettings); + return true; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } + + return false; } private void openProjectToolStripMenuItem_Click(object sender, EventArgs e) { - if (ContinueUnsavedChanges()) - { - openProjectFile.InitialDirectory = Project.Inst.currentProjectFile; - DialogResult result = openProjectFile.ShowDialog(); - if (result == DialogResult.OK) - { - openProject(openProjectFile.FileName); - } - } + if (!ContinueUnsavedChanges()) + return; + + openProjectFile.InitialDirectory = Project?.ProjectFileName; + if (openProjectFile.ShowDialog() != DialogResult.OK) + return; + + openProject(openProjectFile.FileName); } public string LastProjectFilename @@ -164,37 +188,38 @@ private void UpdateUIFromSettings() public void openProject(string filename) { - if (!Project.Inst.TryOpenProject(filename, openROMFile)) + var project = ProjectFileManager.Open(filename); + if (project == null) { LastProjectFilename = ""; - } - else - { - importCDLToolStripMenuItem.Enabled = true; - TriggerSaveOptions(true, true); - UpdateWindowTitle(); - UpdateDataGridView(); - UpdatePercent(); - table.Invalidate(); - EnableSubWindows(); - - LastProjectFilename = filename; + return; } + + Project = project; + + importCDLToolStripMenuItem.Enabled = true; + TriggerSaveOptions(true, true); + UpdateWindowTitle(); + UpdateDataGridView(); + UpdatePercent(); + table.Invalidate(); + EnableSubWindows(); + LastProjectFilename = filename; } private void saveProjectToolStripMenuItem_Click(object sender, EventArgs e) { - Project.Inst.SaveProject(Project.Inst.currentProjectFile); + ProjectFileManager.Save(Project, Project.ProjectFileName); UpdateWindowTitle(); } private void saveProjectAsToolStripMenuItem_Click(object sender, EventArgs e) { - saveProjectFile.InitialDirectory = Project.Inst.currentROMFile; + saveProjectFile.InitialDirectory = Project.AttachedRomFilename; DialogResult result = saveProjectFile.ShowDialog(); if (result == DialogResult.OK && saveProjectFile.FileName != "") { - Project.Inst.SaveProject(saveProjectFile.FileName); + ProjectFileManager.Save(Project, saveProjectFile.FileName); TriggerSaveOptions(true, true); UpdateWindowTitle(); } @@ -202,7 +227,7 @@ private void saveProjectAsToolStripMenuItem_Click(object sender, EventArgs e) private void importCDLToolStripMenuItem_Click(object sender, EventArgs e) { - openCDLDialog.InitialDirectory = Project.Inst.currentProjectFile; + openCDLDialog.InitialDirectory = Project.ProjectFileName; DialogResult result = openCDLDialog.ShowDialog(); if (result == DialogResult.OK) { @@ -211,7 +236,7 @@ private void importCDLToolStripMenuItem_Click(object sender, EventArgs e) try { var cdl = BizHawkCdl.LoadFromFile(openCDLDialog.FileName); - Manager.ImportBizHawkCDL(cdl); + Project.Data.ImportBizHawkCDL(cdl); } catch (InvalidDataException ex) { @@ -231,50 +256,52 @@ private void importCDLToolStripMenuItem_Click(object sender, EventArgs e) private void exportLogToolStripMenuItem_Click(object sender, EventArgs e) { - ExportDisassembly export = new ExportDisassembly(); - DialogResult result = export.ShowDialog(); - if (result == DialogResult.OK) + var lc = new LogCreator(Project); + + var export = new ExportDisassembly(lc); + if (export.ShowDialog() != DialogResult.OK) + return; + + string file = null, error = null; + + // TODO: save this as a setting in the project file + if (lc.structure == LogCreator.FormatStructure.SingleFile) { - string file = null, error = null; - if (LogCreator.structure == LogCreator.FormatStructure.SingleFile) + saveLogSingleFile.InitialDirectory = Project.ProjectFileName; + if (saveLogSingleFile.ShowDialog() == DialogResult.OK && saveLogSingleFile.FileName != "") { - saveLogSingleFile.InitialDirectory = Project.Inst.currentProjectFile; - result = saveLogSingleFile.ShowDialog(); - if (result == DialogResult.OK && saveLogSingleFile.FileName != "") - { - file = saveLogSingleFile.FileName; - error = Path.GetDirectoryName(file) + "/error.txt"; - } + file = saveLogSingleFile.FileName; + error = Path.GetDirectoryName(file) + "/error.txt"; } - else + } + else + { + chooseLogFolder.SelectedPath = Path.GetDirectoryName(Project.ProjectFileName); + if (chooseLogFolder.ShowDialog() == DialogResult.OK && chooseLogFolder.SelectedPath != "") { - chooseLogFolder.SelectedPath = Path.GetDirectoryName(Project.Inst.currentProjectFile); - result = chooseLogFolder.ShowDialog(); - if (result == DialogResult.OK && chooseLogFolder.SelectedPath != "") - { - file = chooseLogFolder.SelectedPath + "/main.asm"; - error = Path.GetDirectoryName(file) + "/error.txt"; - } + file = chooseLogFolder.SelectedPath + "/main.asm"; + error = Path.GetDirectoryName(file) + "/error.txt"; } + } - if (file != null) - { - int errors = 0; - using (StreamWriter sw = new StreamWriter(file)) - using (StreamWriter er = new StreamWriter(error)) - { - errors = LogCreator.CreateLog(sw, er); - if (errors > 0) - MessageBox.Show("Disassembly created with errors. See errors.txt for details.", "Warning", - MessageBoxButtons.OK, MessageBoxIcon.Warning); - else - MessageBox.Show("Disassembly created successfully!", "Complete", MessageBoxButtons.OK, - MessageBoxIcon.Asterisk); - } + if (file == null) + return; - if (errors == 0) File.Delete(error); - } + int errors = 0; + using (StreamWriter sw = new StreamWriter(file)) + using (StreamWriter er = new StreamWriter(error)) + { + errors = lc.CreateLog(sw, er); + if (errors > 0) + MessageBox.Show("Disassembly created with errors. See errors.txt for details.", "Warning", + MessageBoxButtons.OK, MessageBoxIcon.Warning); + else + MessageBox.Show("Disassembly created successfully!", "Complete", MessageBoxButtons.OK, + MessageBoxIcon.Asterisk); } + + if (errors == 0) + File.Delete(error); } private void viewHelpToolStripMenuItem_Click(object sender, EventArgs e) @@ -296,7 +323,7 @@ private void githubToolStripMenuItem_Click(object sender, EventArgs e) private void aboutToolStripMenuItem_Click(object sender, EventArgs e) { - About about = new About(); + var about = new About(); about.ShowDialog(); } @@ -335,9 +362,9 @@ private void UpdateBase(Util.NumberBase noBase) public void UpdatePercent() { - int totalUnreached = 0, size = Data.Inst.GetROMSize(); + int totalUnreached = 0, size = Project.Data.GetROMSize(); for (int i = 0; i < size; i++) - if (Data.Inst.GetFlag(i) == Data.FlagType.Unreached) + if (Project.Data.GetFlag(i) == Data.FlagType.Unreached) totalUnreached++; int reached = size - totalUnreached; percentComplete.Text = string.Format("{0:N3}% ({1:D}/{2:D})", reached * 100.0 / size, reached, size); @@ -360,13 +387,13 @@ public void InvalidateTable() private void UpdateDataGridView() { - if (Data.Inst.GetROMSize() > 0) + if (Project.Data.GetROMSize() > 0) { rowsToShow = ((table.Height - table.ColumnHeadersHeight) / table.RowTemplate.Height); - if (viewOffset + rowsToShow > Data.Inst.GetROMSize()) viewOffset = Data.Inst.GetROMSize() - rowsToShow; + if (viewOffset + rowsToShow > Project.Data.GetROMSize()) viewOffset = Project.Data.GetROMSize() - rowsToShow; if (viewOffset < 0) viewOffset = 0; vScrollBar1.Enabled = true; - vScrollBar1.Maximum = Data.Inst.GetROMSize() - rowsToShow; + vScrollBar1.Maximum = Project.Data.GetROMSize() - rowsToShow; vScrollBar1.Value = viewOffset; table.RowCount = rowsToShow; @@ -377,7 +404,7 @@ private void UpdateDataGridView() private void table_MouseWheel(object sender, MouseEventArgs e) { - if (Data.Inst.GetROMSize() <= 0) return; + if (Project.Data.GetROMSize() <= 0) return; int selRow = table.CurrentCell.RowIndex + viewOffset, selCol = table.CurrentCell.ColumnIndex; int amount = e.Delta / 0x18; viewOffset -= amount; @@ -409,7 +436,7 @@ private void table_MouseDown(object sender, MouseEventArgs e) private void table_KeyDown(object sender, KeyEventArgs e) { - if (Data.Inst.GetROMSize() <= 0) return; + if (Project.Data.GetROMSize() <= 0) return; int offset = table.CurrentCell.RowIndex + viewOffset; int newOffset = offset; @@ -431,7 +458,7 @@ private void table_KeyDown(object sender, KeyEventArgs e) case Keys.Down: amount = e.KeyCode == Keys.Down ? 0x01 : e.KeyCode == Keys.PageDown ? 0x10 : 0x100; newOffset = offset + amount; - if (newOffset >= Data.Inst.GetROMSize()) newOffset = Data.Inst.GetROMSize() - 1; + if (newOffset >= Project.Data.GetROMSize()) newOffset = Project.Data.GetROMSize() - 1; SelectOffset(newOffset); break; case Keys.Left: @@ -481,10 +508,10 @@ private void table_KeyDown(object sender, KeyEventArgs e) table.BeginEdit(true); break; case Keys.M: - Data.Inst.SetMFlag(offset, !Data.Inst.GetMFlag(offset)); + Project.Data.SetMFlag(offset, !Project.Data.GetMFlag(offset)); break; case Keys.X: - Data.Inst.SetXFlag(offset, !Data.Inst.GetXFlag(offset)); + Project.Data.SetXFlag(offset, !Project.Data.GetXFlag(offset)); break; case Keys.C: table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[12]; @@ -499,51 +526,51 @@ private void table_KeyDown(object sender, KeyEventArgs e) private void table_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) { int row = e.RowIndex + viewOffset; - if (row >= Data.Inst.GetROMSize()) return; + if (row >= Project.Data.GetROMSize()) return; switch (e.ColumnIndex) { case 0: - e.Value = Data.Inst.GetLabelName(Util.ConvertPCtoSNES(row)); + e.Value = Project.Data.GetLabelName(Project.Data.ConvertPCtoSNES(row)); break; case 1: - e.Value = Util.NumberToBaseString(Util.ConvertPCtoSNES(row), Util.NumberBase.Hexadecimal, 6); + e.Value = Util.NumberToBaseString(Project.Data.ConvertPCtoSNES(row), Util.NumberBase.Hexadecimal, 6); break; case 2: - e.Value = (char) Data.Inst.GetROMByte(row); + e.Value = (char) Project.Data.GetROMByte(row); break; case 3: - e.Value = Util.NumberToBaseString(Data.Inst.GetROMByte(row), DisplayBase); + e.Value = Util.NumberToBaseString(Project.Data.GetROMByte(row), DisplayBase); break; case 4: - e.Value = Util.PointToString(Data.Inst.GetInOutPoint(row)); + e.Value = Util.PointToString(Project.Data.GetInOutPoint(row)); break; case 5: - int len = Manager.GetInstructionLength(row); - if (row + len <= Data.Inst.GetROMSize()) e.Value = Util.GetInstruction(row); + int len = Project.Data.GetInstructionLength(row); + if (row + len <= Project.Data.GetROMSize()) e.Value = Project.Data.GetInstruction(row); else e.Value = ""; break; case 6: - int ia = Util.GetIntermediateAddressOrPointer(row); + int ia = Project.Data.GetIntermediateAddressOrPointer(row); if (ia >= 0) e.Value = Util.NumberToBaseString(ia, Util.NumberBase.Hexadecimal, 6); else e.Value = ""; break; case 7: - e.Value = Util.TypeToString(Data.Inst.GetFlag(row)); + e.Value = Util.TypeToString(Project.Data.GetFlag(row)); break; case 8: - e.Value = Util.NumberToBaseString(Data.Inst.GetDataBank(row), Util.NumberBase.Hexadecimal, 2); + e.Value = Util.NumberToBaseString(Project.Data.GetDataBank(row), Util.NumberBase.Hexadecimal, 2); break; case 9: - e.Value = Util.NumberToBaseString(Data.Inst.GetDirectPage(row), Util.NumberBase.Hexadecimal, 4); + e.Value = Util.NumberToBaseString(Project.Data.GetDirectPage(row), Util.NumberBase.Hexadecimal, 4); break; case 10: - e.Value = Util.BoolToSize(Data.Inst.GetMFlag(row)); + e.Value = Util.BoolToSize(Project.Data.GetMFlag(row)); break; case 11: - e.Value = Util.BoolToSize(Data.Inst.GetXFlag(row)); + e.Value = Util.BoolToSize(Project.Data.GetXFlag(row)); break; case 12: - e.Value = Data.Inst.GetComment(Util.ConvertPCtoSNES(row)); + e.Value = Project.Data.GetComment(Project.Data.ConvertPCtoSNES(row)); break; } } @@ -553,42 +580,136 @@ private void table_CellValuePushed(object sender, DataGridViewCellValueEventArgs string value = e.Value as string; int result; int row = e.RowIndex + viewOffset; - if (row >= Data.Inst.GetROMSize()) return; + if (row >= Project.Data.GetROMSize()) return; switch (e.ColumnIndex) { case 0: - Data.Inst.AddLabel(Util.ConvertPCtoSNES(row), new Data.AliasInfo() {name = value}, true); + Project.Data.AddLabel(Project.Data.ConvertPCtoSNES(row), new Label() {name = value}, true); break; // todo (validate for valid label characters) case 8: - if (int.TryParse(value, NumberStyles.HexNumber, null, out result)) Data.Inst.SetDataBank(row, result); + if (int.TryParse(value, NumberStyles.HexNumber, null, out result)) Project.Data.SetDataBank(row, result); break; case 9: - if (int.TryParse(value, NumberStyles.HexNumber, null, out result)) Data.Inst.SetDirectPage(row, result); + if (int.TryParse(value, NumberStyles.HexNumber, null, out result)) Project.Data.SetDirectPage(row, result); break; case 10: - Data.Inst.SetMFlag(row, (value == "8" || value == "M")); + Project.Data.SetMFlag(row, (value == "8" || value == "M")); break; case 11: - Data.Inst.SetXFlag(row, (value == "8" || value == "X")); + Project.Data.SetXFlag(row, (value == "8" || value == "X")); break; case 12: - Data.Inst.AddComment(Util.ConvertPCtoSNES(row), value, true); + Project.Data.AddComment(Project.Data.ConvertPCtoSNES(row), value, true); break; } table.InvalidateRow(e.RowIndex); } + public void PaintCell(int offset, DataGridViewCellStyle style, int column, int selOffset) + { + // editable cells show up green + if (column == 0 || column == 8 || column == 9 || column == 12) style.SelectionBackColor = Color.Chartreuse; + + switch (Project.Data.GetFlag(offset)) + { + case Data.FlagType.Unreached: + style.BackColor = Color.LightGray; + style.ForeColor = Color.DarkSlateGray; + break; + case Data.FlagType.Opcode: + int opcode = Project.Data.GetROMByte(offset); + switch (column) + { + case 4: // <*> + Data.InOutPoint point = Project.Data.GetInOutPoint(offset); + int r = 255, g = 255, b = 255; + if ((point & (Data.InOutPoint.EndPoint | Data.InOutPoint.OutPoint)) != 0) g -= 50; + if ((point & (Data.InOutPoint.InPoint)) != 0) r -= 50; + if ((point & (Data.InOutPoint.ReadPoint)) != 0) b -= 50; + style.BackColor = Color.FromArgb(r, g, b); + break; + case 5: // Instruction + if (opcode == 0x40 || opcode == 0xCB || opcode == 0xDB || opcode == 0xF8 // RTI WAI STP SED + || opcode == 0xFB || opcode == 0x00 || opcode == 0x02 || opcode == 0x42 // XCE BRK COP WDM + ) style.BackColor = Color.Yellow; + break; + case 8: // Data Bank + if (opcode == 0xAB || opcode == 0x44 || opcode == 0x54) // PLB MVP MVN + style.BackColor = Color.OrangeRed; + else if (opcode == 0x8B) // PHB + style.BackColor = Color.Yellow; + break; + case 9: // Direct Page + if (opcode == 0x2B || opcode == 0x5B) // PLD TCD + style.BackColor = Color.OrangeRed; + if (opcode == 0x0B || opcode == 0x7B) // PHD TDC + style.BackColor = Color.Yellow; + break; + case 10: // M Flag + case 11: // X Flag + int mask = column == 10 ? 0x20 : 0x10; + if (opcode == 0x28 || ((opcode == 0xC2 || opcode == 0xE2) // PLP SEP REP + && (Project.Data.GetROMByte(offset + 1) & mask) != 0)) // relevant bit set + style.BackColor = Color.OrangeRed; + if (opcode == 0x08) // PHP + style.BackColor = Color.Yellow; + break; + } + break; + case Data.FlagType.Operand: + style.ForeColor = Color.LightGray; + break; + case Data.FlagType.Graphics: + style.BackColor = Color.LightPink; + break; + case Data.FlagType.Music: + style.BackColor = Color.PowderBlue; + break; + case Data.FlagType.Data8Bit: + case Data.FlagType.Data16Bit: + case Data.FlagType.Data24Bit: + case Data.FlagType.Data32Bit: + style.BackColor = Color.NavajoWhite; + break; + case Data.FlagType.Pointer16Bit: + case Data.FlagType.Pointer24Bit: + case Data.FlagType.Pointer32Bit: + style.BackColor = Color.Orchid; + break; + case Data.FlagType.Text: + style.BackColor = Color.Aquamarine; + break; + case Data.FlagType.Empty: + style.BackColor = Color.DarkSlateGray; + style.ForeColor = Color.LightGray; + break; + } + + if (selOffset >= 0 && selOffset < Project.Data.GetROMSize()) + { + if (column == 1 + //&& (Project.Data.GetFlag(selOffset) == Data.FlagType.Opcode || Project.Data.GetFlag(selOffset) == Data.FlagType.Unreached) + && Project.Data.ConvertSNEStoPC(Project.Data.GetIntermediateAddressOrPointer(selOffset)) == offset + ) style.BackColor = Color.DeepPink; + + if (column == 6 + //&& (Project.Data.GetFlag(offset) == Data.FlagType.Opcode || Project.Data.GetFlag(offset) == Data.FlagType.Unreached) + && Project.Data.ConvertSNEStoPC(Project.Data.GetIntermediateAddressOrPointer(offset)) == selOffset + ) style.BackColor = Color.DeepPink; + } + } + private void table_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) { int row = e.RowIndex + viewOffset; - if (row < 0 || row >= Data.Inst.GetROMSize()) return; - Util.PaintCell(row, e.CellStyle, e.ColumnIndex, table.CurrentCell.RowIndex + viewOffset); + if (row < 0 || row >= Project.Data.GetROMSize()) return; + PaintCell(row, e.CellStyle, e.ColumnIndex, table.CurrentCell.RowIndex + viewOffset); } public void SelectOffset(int offset, int column = -1) { - int col = column == -1 ? table.CurrentCell.ColumnIndex : column; + var col = column == -1 ? table.CurrentCell.ColumnIndex : column; if (offset < viewOffset) { viewOffset = offset; @@ -609,33 +730,38 @@ public void SelectOffset(int offset, int column = -1) private void Step(int offset) { - SelectOffset(Manager.Step(offset, false, false, offset - 1)); + Project.UnsavedChanges = true; + SelectOffset(Project.Data.Step(offset, false, false, offset - 1)); UpdatePercent(); UpdateWindowTitle(); } private void StepIn(int offset) { - SelectOffset(Manager.Step(offset, true, false, offset - 1)); + Project.UnsavedChanges = true; + SelectOffset(Project.Data.Step(offset, true, false, offset - 1)); UpdatePercent(); UpdateWindowTitle(); } private void AutoStepSafe(int offset) { - int destination = Manager.AutoStep(offset, false, 0); - if (MoveWithStep) SelectOffset(destination); + Project.UnsavedChanges = true; + var destination = Project.Data.AutoStep(offset, false, 0); + if (MoveWithStep) + SelectOffset(destination); UpdatePercent(); UpdateWindowTitle(); } private void AutoStepHarsh(int offset) { - HarshAutoStep harsh = new HarshAutoStep(offset); + HarshAutoStep harsh = new HarshAutoStep(offset, Project.Data); DialogResult result = harsh.ShowDialog(); if (result == DialogResult.OK) { - int destination = Manager.AutoStep(harsh.GetOffset(), true, harsh.GetCount()); + Project.UnsavedChanges = true; + int destination = Project.Data.AutoStep(harsh.GetOffset(), true, harsh.GetCount()); if (MoveWithStep) SelectOffset(destination); UpdatePercent(); UpdateWindowTitle(); @@ -644,84 +770,89 @@ private void AutoStepHarsh(int offset) private void Mark(int offset) { - SelectOffset(Manager.Mark(offset, markFlag, Util.TypeStepSize(markFlag))); + Project.UnsavedChanges = true; + SelectOffset(Project.Data.Mark(offset, markFlag, Util.TypeStepSize(markFlag))); UpdatePercent(); UpdateWindowTitle(); } private void MarkMany(int offset, int column) { - MarkManyDialog mark = new MarkManyDialog(offset, column); - DialogResult result = mark.ShowDialog(); - if (result == DialogResult.OK) - { - int destination = 0; - int col = mark.GetProperty(); - switch (col) - { - case 0: - destination = Manager.Mark(mark.GetOffset(), (Data.FlagType) mark.GetValue(), mark.GetCount()); - break; - case 1: - destination = Manager.MarkDataBank(mark.GetOffset(), (int) mark.GetValue(), mark.GetCount()); - break; - case 2: - destination = Manager.MarkDirectPage(mark.GetOffset(), (int) mark.GetValue(), mark.GetCount()); - break; - case 3: - destination = Manager.MarkMFlag(mark.GetOffset(), (bool) mark.GetValue(), mark.GetCount()); - break; - case 4: - destination = Manager.MarkXFlag(mark.GetOffset(), (bool) mark.GetValue(), mark.GetCount()); - break; - case 5: - destination = Manager.MarkArchitechture(mark.GetOffset(), (Data.Architechture) mark.GetValue(), - mark.GetCount()); - break; - } + var mark = new MarkManyDialog(offset, column, Project.Data); + var result = mark.ShowDialog(); + if (result != DialogResult.OK) + return; - if (MoveWithStep) SelectOffset(destination); - UpdatePercent(); - UpdateWindowTitle(); - InvalidateTable(); + Project.UnsavedChanges = true; + + var destination = 0; + var col = mark.GetProperty(); + switch (col) + { + case 0: + destination = Project.Data.Mark(mark.GetOffset(), (Data.FlagType) mark.GetValue(), mark.GetCount()); + break; + case 1: + destination = Project.Data.MarkDataBank(mark.GetOffset(), (int) mark.GetValue(), mark.GetCount()); + break; + case 2: + destination = Project.Data.MarkDirectPage(mark.GetOffset(), (int) mark.GetValue(), mark.GetCount()); + break; + case 3: + destination = Project.Data.MarkMFlag(mark.GetOffset(), (bool) mark.GetValue(), mark.GetCount()); + break; + case 4: + destination = Project.Data.MarkXFlag(mark.GetOffset(), (bool) mark.GetValue(), mark.GetCount()); + break; + case 5: + destination = Project.Data.MarkArchitechture(mark.GetOffset(), (Data.Architechture) mark.GetValue(), + mark.GetCount()); + break; } + + if (MoveWithStep) + SelectOffset(destination); + + UpdatePercent(); + UpdateWindowTitle(); + InvalidateTable(); } private void GoToIntermediateAddress(int offset) { - int ia = Util.GetIntermediateAddressOrPointer(offset); - if (ia >= 0) - { - int pc = Util.ConvertSNEStoPC(ia); - if (pc >= 0) - { - SelectOffset(pc, 1); - } - } + var ia = Project.Data.GetIntermediateAddressOrPointer(offset); + if (ia < 0) + return; + + var pc = Project.Data.ConvertSNEStoPC(ia); + if (pc < 0) + return; + + SelectOffset(pc, 1); } private void GoToUnreached(bool end, bool direction) { int offset = table.CurrentCell.RowIndex + viewOffset; - int size = Data.Inst.GetROMSize(); + int size = Project.Data.GetROMSize(); int unreached = end ? (direction ? 0 : size - 1) : offset; if (direction) { if (!end) - while (unreached < size - 1 && Data.Inst.GetFlag(unreached) == Data.FlagType.Unreached) + while (unreached < size - 1 && Project.Data.GetFlag(unreached) == Data.FlagType.Unreached) unreached++; - while (unreached < size - 1 && Data.Inst.GetFlag(unreached) != Data.FlagType.Unreached) unreached++; + while (unreached < size - 1 && Project.Data.GetFlag(unreached) != Data.FlagType.Unreached) unreached++; } else { if (unreached > 0) unreached--; - while (unreached > 0 && Data.Inst.GetFlag(unreached) != Data.FlagType.Unreached) unreached--; + while (unreached > 0 && Project.Data.GetFlag(unreached) != Data.FlagType.Unreached) unreached--; } - while (unreached > 0 && Data.Inst.GetFlag(unreached - 1) == Data.FlagType.Unreached) unreached--; + while (unreached > 0 && Project.Data.GetFlag(unreached - 1) == Data.FlagType.Unreached) unreached--; - if (Data.Inst.GetFlag(unreached) == Data.FlagType.Unreached) SelectOffset(unreached, 1); + if (Project.Data.GetFlag(unreached) == Data.FlagType.Unreached) SelectOffset(unreached, 1); } private void visualMapToolStripMenuItem_Click(object sender, EventArgs e) @@ -738,46 +869,49 @@ private void graphicsWindowToolStripMenuItem_Click(object sender, EventArgs e) private void stepOverToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.Inst.GetROMSize() <= 0) return; + if (Project.Data.GetROMSize() <= 0) return; Step(table.CurrentCell.RowIndex + viewOffset); } private void stepInToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.Inst.GetROMSize() <= 0) return; + if (Project.Data.GetROMSize() <= 0) return; StepIn(table.CurrentCell.RowIndex + viewOffset); } private void autoStepSafeToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.Inst.GetROMSize() <= 0) return; + if (Project.Data.GetROMSize() <= 0) return; AutoStepSafe(table.CurrentCell.RowIndex + viewOffset); } private void autoStepHarshToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.Inst.GetROMSize() <= 0) return; + if (Project.Data.GetROMSize() <= 0) return; AutoStepHarsh(table.CurrentCell.RowIndex + viewOffset); } private void gotoToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.Inst.GetROMSize() <= 0) return; - GotoDialog go = new GotoDialog(viewOffset + table.CurrentCell.RowIndex); - DialogResult result = go.ShowDialog(); - if (result == DialogResult.OK) - { - int offset = go.GetPcOffset(); - if (offset >= 0 && offset < Data.Inst.GetROMSize()) SelectOffset(offset); - else - MessageBox.Show("That offset is out of range.", "Error", MessageBoxButtons.OK, - MessageBoxIcon.Error); - } + if (Project.Data.GetROMSize() <= 0) + return; + + var go = new GotoDialog(viewOffset + table.CurrentCell.RowIndex, Project.Data); + var result = go.ShowDialog(); + if (result != DialogResult.OK) + return; + + int offset = go.GetPcOffset(); + if (offset >= 0 && offset < Project.Data.GetROMSize()) + SelectOffset(offset); + else + MessageBox.Show("That offset is out of range.", "Error", MessageBoxButtons.OK, + MessageBoxIcon.Error); } private void gotoIntermediateAddressToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.Inst.GetROMSize() <= 0) return; + if (Project.Data.GetROMSize() <= 0) return; GoToIntermediateAddress(table.CurrentCell.RowIndex + viewOffset); } @@ -798,13 +932,13 @@ private void gotoNextUnreachedToolStripMenuItem_Click(object sender, EventArgs e private void markOneToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.Inst.GetROMSize() <= 0) return; + if (Project.Data.GetROMSize() <= 0) return; Mark(table.CurrentCell.RowIndex + viewOffset); } private void markManyToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.Inst.GetROMSize() <= 0) return; + if (Project.Data.GetROMSize() <= 0) return; MarkMany(table.CurrentCell.RowIndex + viewOffset, 7); } @@ -816,25 +950,25 @@ private void addLabelToolStripMenuItem_Click(object sender, EventArgs e) private void setDataBankToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.Inst.GetROMSize() <= 0) return; + if (Project.Data.GetROMSize() <= 0) return; MarkMany(table.CurrentCell.RowIndex + viewOffset, 8); } private void setDirectPageToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.Inst.GetROMSize() <= 0) return; + if (Project.Data.GetROMSize() <= 0) return; MarkMany(table.CurrentCell.RowIndex + viewOffset, 9); } private void toggleAccumulatorSizeMToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.Inst.GetROMSize() <= 0) return; + if (Project.Data.GetROMSize() <= 0) return; MarkMany(table.CurrentCell.RowIndex + viewOffset, 10); } private void toggleIndexSizeToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.Inst.GetROMSize() <= 0) return; + if (Project.Data.GetROMSize() <= 0) return; MarkMany(table.CurrentCell.RowIndex + viewOffset, 11); } @@ -846,29 +980,38 @@ private void addCommentToolStripMenuItem_Click(object sender, EventArgs e) private void fixMisalignedInstructionsToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.Inst.GetROMSize() <= 0) return; - MisalignmentChecker mis = new MisalignmentChecker(); - DialogResult result = mis.ShowDialog(); - if (result == DialogResult.OK) - { - int count = Manager.FixMisalignedFlags(); - InvalidateTable(); - MessageBox.Show(string.Format("Modified {0} flags!", count), "Done!", MessageBoxButtons.OK, - MessageBoxIcon.Information); - } + if (Project.Data.GetROMSize() <= 0) + return; + + var mis = new MisalignmentChecker(Project.Data); + var result = mis.ShowDialog(); + + if (result != DialogResult.OK) + return; + + int count = Project.Data.FixMisalignedFlags(); + + if (count > 0) + Project.UnsavedChanges = true; + + InvalidateTable(); + MessageBox.Show($"Modified {count} flags!", "Done!", + MessageBoxButtons.OK, MessageBoxIcon.Information); } private void rescanForInOutPointsToolStripMenuItem_Click(object sender, EventArgs e) { - if (Data.Inst.GetROMSize() <= 0) return; - InOutPointChecker point = new InOutPointChecker(); - DialogResult result = point.ShowDialog(); - if (result == DialogResult.OK) - { - Manager.RescanInOutPoints(); - InvalidateTable(); - MessageBox.Show("Scan complete!", "Done!", MessageBoxButtons.OK, MessageBoxIcon.Information); - } + if (Project.Data.GetROMSize() <= 0) + return; + + var point = new InOutPointChecker(); + if (point.ShowDialog() != DialogResult.OK) + return; + + Project.Data.RescanInOutPoints(); + Project.UnsavedChanges = true; + InvalidateTable(); + MessageBox.Show("Scan complete!", "Done!", MessageBoxButtons.OK, MessageBoxIcon.Information); } private void unreachedToolStripMenuItem_Click(object sender, EventArgs e) @@ -963,7 +1106,7 @@ private void moveWithStepToolStripMenuItem_Click(object sender, EventArgs e) public OpenFileDialog GetRomOpenFileDialog() { - return openROMFile; + return openFileDialog; } // sub windows @@ -981,13 +1124,16 @@ private void labelListToolStripMenuItem_Click(object sender, EventArgs e) private void ImportUsageMapToolStripMenuItem_Click(object sender, EventArgs e) { - if (openUsageMapFile.ShowDialog() == DialogResult.OK) - { - int total = Manager.ImportUsageMap(File.ReadAllBytes(openUsageMapFile.FileName)); + if (openUsageMapFile.ShowDialog() != DialogResult.OK) + return; - MessageBox.Show($"Modified total {total} flags!", "Done", - MessageBoxButtons.OK, MessageBoxIcon.Information); - } + var num_modified_flags = Project.Data.ImportUsageMap(File.ReadAllBytes(openUsageMapFile.FileName)); + + if (num_modified_flags > 0) + Project.UnsavedChanges = true; + + MessageBox.Show($"Modified total {num_modified_flags} flags!", "Done", + MessageBoxButtons.OK, MessageBoxIcon.Information); } private void ImportTraceLogToolStripMenuItem_Click(object sender, EventArgs e) @@ -1001,9 +1147,12 @@ private void ImportTraceLogToolStripMenuItem_Click(object sender, EventArgs e) // caution: trace logs can be gigantic, even a few seconds can be > 1GB LargeFilesReader.ReadFilesLines(openTraceLogDialog.FileNames, delegate (string line) { - totalLinesSoFar += Manager.ImportTraceLogLine(line); + totalLinesSoFar += Project.Data.ImportTraceLogLine(line); }); + if (totalLinesSoFar > 0) + Project.UnsavedChanges = true; + MessageBox.Show( $"Modified total {totalLinesSoFar} flags from {openTraceLogDialog.FileNames.Length} files!", "Done", diff --git a/DiztinGUIsh/window/MainWindow.resx b/DiztinGUIsh/window/MainWindow.resx index 8682862a..d6ef4ab3 100644 --- a/DiztinGUIsh/window/MainWindow.resx +++ b/DiztinGUIsh/window/MainWindow.resx @@ -162,7 +162,7 @@ 132, 17 - + 248, 17 diff --git a/DiztinGUIsh/window/dialog/ExportDisassembly.cs b/DiztinGUIsh/window/dialog/ExportDisassembly.cs index 63fae64c..61799d06 100644 --- a/DiztinGUIsh/window/dialog/ExportDisassembly.cs +++ b/DiztinGUIsh/window/dialog/ExportDisassembly.cs @@ -13,8 +13,12 @@ namespace DiztinGUIsh { public partial class ExportDisassembly : Form { - public ExportDisassembly() + private readonly LogCreator LogCreator; + private Data Data => LogCreator.Data; + public ExportDisassembly(LogCreator lc) { + LogCreator = lc; + InitializeComponent(); numData.Value = LogCreator.dataPerLine; textFormat.Text = LogCreator.format; @@ -92,24 +96,28 @@ private bool ValidateFormat() // https://stackoverflow.com/a/29679597 private void UpdateSample() { + // TODO: since we don't have to do this as a singleton now, we can + // replace all this save/restore stuff and just create a new Project() or Data() and populate it + // cheeky way of using the same methods for disassembling a different set of data :^) - while (sampleTable.RomBytes.Count < 0x8000) sampleTable.RomBytes.Add(new ROMByte()); + while (sampleTable.Count < 0x8000) + sampleTable.Add(new ROMByte()); using (MemoryStream mem = new MemoryStream()) using (StreamWriter sw = new StreamWriter(mem)) { - var tempTable = Data.Inst.GetTable(); - Data.ROMMapMode tempMode = Data.Inst.RomMapMode; - Data.ROMSpeed tempSpeed = Data.Inst.GetROMSpeed(); - var tempAlias = Data.Inst.GetAllLabels(); - var tempComment = Data.Inst.GetAllComments(); + var tempTable = Data.GetTable(); + Data.ROMMapMode tempMode = Data.RomMapMode; + Data.ROMSpeed tempSpeed = Data.GetROMSpeed(); + var tempAlias = Data.GetAllLabels(); + var tempComment = Data.GetAllComments(); LogCreator.FormatStructure tempStructure = LogCreator.structure; - Data.Inst.Restore(sampleTable, Data.ROMMapMode.LoROM, Data.ROMSpeed.FastROM, sampleAlias, sampleComment); + Data.Restore(sampleTable, Data.ROMMapMode.LoROM, Data.ROMSpeed.FastROM, sampleAlias, sampleComment); LogCreator.structure = LogCreator.FormatStructure.SingleFile; LogCreator.CreateLog(sw, StreamWriter.Null); - Data.Inst.Restore(tempTable, tempMode, tempSpeed, tempAlias, tempComment); + Data.Restore(tempTable, tempMode, tempSpeed, tempAlias, tempComment); LogCreator.structure = tempStructure; sw.Flush(); @@ -121,8 +129,8 @@ private void UpdateSample() // random sample code I made up; hopefully it shows a little bit of // everything so you can see how the settings will effect the output - public static TableData sampleTable = new TableData - { RomBytes = { + public static RomBytes sampleTable = new RomBytes + { new ROMByte {Rom = 0x78, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true, Point = Data.InOutPoint.InPoint}, new ROMByte {Rom = 0xA9, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true}, new ROMByte {Rom = 0x01, TypeFlag = Data.FlagType.Operand}, @@ -246,16 +254,16 @@ private void UpdateSample() new ROMByte {Rom = 0x83, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, new ROMByte {Rom = 0x34, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, new ROMByte {Rom = 0x6D, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - }}; + }; - public static Dictionary sampleAlias = new Dictionary + public static Dictionary sampleAlias = new Dictionary { - { 0x00, new Data.AliasInfo() {name="Emulation_RESET", comment="Sample emulation reset location"} }, - { 0x0A, new Data.AliasInfo() {name="FastRESET", comment="Sample label" } }, - { 0x32, new Data.AliasInfo() {name="Test_Indices"} }, - { 0x3A, new Data.AliasInfo() {name="Pointer_Table"} }, - { 0x44, new Data.AliasInfo() {name="First_Routine"} }, - { 0x5B, new Data.AliasInfo() {name="Test_Data", comment="Pretty cool huh?" } } + { 0x00, new Label() {name="Emulation_RESET", comment="Sample emulation reset location"} }, + { 0x0A, new Label() {name="FastRESET", comment="Sample label" } }, + { 0x32, new Label() {name="Test_Indices"} }, + { 0x3A, new Label() {name="Pointer_Table"} }, + { 0x44, new Label() {name="First_Routine"} }, + { 0x5B, new Label() {name="Test_Data", comment="Pretty cool huh?" } } }; public static Dictionary sampleComment = new Dictionary diff --git a/DiztinGUIsh/window/dialog/GotoDialog.cs b/DiztinGUIsh/window/dialog/GotoDialog.cs index 9f22e03b..16b565be 100644 --- a/DiztinGUIsh/window/dialog/GotoDialog.cs +++ b/DiztinGUIsh/window/dialog/GotoDialog.cs @@ -13,10 +13,12 @@ namespace DiztinGUIsh { public partial class GotoDialog : Form { - public GotoDialog(int offset) + public Data Data { get; set; } + public GotoDialog(int offset, Data data) { InitializeComponent(); - textROM.Text = Util.NumberToBaseString(Util.ConvertPCtoSNES(offset), Util.NumberBase.Hexadecimal, 6); + Data = data; + textROM.Text = Util.NumberToBaseString(Data.ConvertPCtoSNES(offset), Util.NumberBase.Hexadecimal, 6); textPC.Text = Util.NumberToBaseString(offset, Util.NumberBase.Hexadecimal, 0); } @@ -92,7 +94,7 @@ private void UpdateUI() private bool IsValidPCAddress(int pc) { - return pc >= 0 && pc < Data.Inst.GetROMSize(); + return pc >= 0 && pc < Data.GetROMSize(); } private bool IsPCOffsetValid() @@ -107,14 +109,14 @@ private bool IsRomAddressValid() if (address < 0) return false; - return IsValidPCAddress(Util.ConvertSNEStoPC(address)); + return IsValidPCAddress(Data.ConvertSNEStoPC(address)); } private void textROM_TextChanged(object sender, EventArgs e) { UpdateTextChanged(textROM.Text,(finaltext, address, noBase) => { - int pc = Util.ConvertSNEStoPC(address); + int pc = Data.ConvertSNEStoPC(address); textROM.Text = finaltext; textPC.Text = Util.NumberToBaseString(pc, noBase, 0); @@ -127,7 +129,7 @@ private void textPC_TextChanged(object sender, EventArgs e) { UpdateTextChanged(textPC.Text, (finaltext, offset, noBase) => { - int addr = Util.ConvertPCtoSNES(offset); + int addr = Data.ConvertPCtoSNES(offset); textPC.Text = finaltext; textROM.Text = Util.NumberToBaseString(addr, noBase, 6); diff --git a/DiztinGUIsh/window/dialog/HarshAutoStep.cs b/DiztinGUIsh/window/dialog/HarshAutoStep.cs index 6be4d58e..c02613c6 100644 --- a/DiztinGUIsh/window/dialog/HarshAutoStep.cs +++ b/DiztinGUIsh/window/dialog/HarshAutoStep.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Data; +using System.Diagnostics; using System.Drawing; using System.Globalization; using System.Linq; @@ -15,12 +16,17 @@ public partial class HarshAutoStep : Form { private int start, end, count; - public HarshAutoStep(int offset) + private readonly Data Data; + + public HarshAutoStep(int offset, Data data) { + Debug.Assert(Data!=null); + Data = data; + InitializeComponent(); start = offset; - int rest = Data.Inst.GetROMSize() - start; + var rest = data.GetROMSize() - start; count = rest < 0x100 ? rest : 0x100; end = start + count; @@ -43,16 +49,15 @@ private void UpdateText(TextBox selected) { Util.NumberBase noBase = radioDec.Checked ? Util.NumberBase.Decimal : Util.NumberBase.Hexadecimal; int digits = noBase == Util.NumberBase.Hexadecimal && radioROM.Checked ? 6 : 0; - int size = Data.Inst.GetROMSize(); if (start < 0) start = 0; - if (end >= size) end = size - 1; + if (end >= Data.GetROMSize()) end = Data.GetROMSize() - 1; count = end - start; if (count < 0) count = 0; updatingText = true; - if (selected != textStart) textStart.Text = Util.NumberToBaseString(radioROM.Checked ? Util.ConvertPCtoSNES(start) : start, noBase, digits); - if (selected != textEnd) textEnd.Text = Util.NumberToBaseString(radioROM.Checked ? Util.ConvertPCtoSNES(end) : end, noBase, digits); + if (selected != textStart) textStart.Text = Util.NumberToBaseString(radioROM.Checked ? Data.ConvertPCtoSNES(start) : start, noBase, digits); + if (selected != textEnd) textEnd.Text = Util.NumberToBaseString(radioROM.Checked ? Data.ConvertPCtoSNES(end) : end, noBase, digits); if (selected != textCount) textCount.Text = Util.NumberToBaseString(count, noBase, 0); updatingText = false; } @@ -72,10 +77,9 @@ private void textCount_TextChanged(object sender, EventArgs e) if (!updatingText) { updatingText = true; - NumberStyles style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; + var style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; - int result = 0; - if (int.TryParse(textCount.Text, style, null, out result)) + if (int.TryParse(textCount.Text, style, null, out var result)) { count = result; end = start + count; @@ -87,40 +91,41 @@ private void textCount_TextChanged(object sender, EventArgs e) private void textEnd_TextChanged(object sender, EventArgs e) { - if (!updatingText) - { - updatingText = true; - NumberStyles style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; + if (updatingText) + return; - int result = 0; - if (int.TryParse(textEnd.Text, style, null, out result)) - { - if (radioROM.Checked) result = Util.ConvertSNEStoPC(result); - end = result; - count = end - start; - } + updatingText = true; + var style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; + + if (int.TryParse(textEnd.Text, style, null, out var result)) + { + if (radioROM.Checked) + result = Data.ConvertSNEStoPC(result); - UpdateText(textEnd); + end = result; + count = end - start; } + + UpdateText(textEnd); } private void textStart_TextChanged(object sender, EventArgs e) { - if (!updatingText) - { - updatingText = true; - NumberStyles style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; + if (updatingText) + return; - int result = 0; - if (int.TryParse(textStart.Text, style, null, out result)) - { - if (radioROM.Checked) result = Util.ConvertSNEStoPC(result); - start = result; - count = end - start; - } + updatingText = true; + var style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; - UpdateText(textStart); + if (int.TryParse(textStart.Text, style, null, out var result)) + { + if (radioROM.Checked) + result = Data.ConvertSNEStoPC(result); + start = result; + count = end - start; } + + UpdateText(textStart); } private void go_Click(object sender, EventArgs e) diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.cs b/DiztinGUIsh/window/dialog/ImportROMDialog.cs index 47ad768b..f162e2c4 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.cs @@ -12,10 +12,10 @@ namespace DiztinGUIsh { public partial class ImportROMDialog : Form { - private Data.ROMMapMode mode; - private Data.ROMSpeed speed; + private Project.ImportRomSettings importSettings; + private bool couldnt_detect_rom_type; + private string title; - private byte[] data; private int offset; private string[,] vectorNames = new string[2, 6] { @@ -25,7 +25,28 @@ public partial class ImportROMDialog : Form private TextBox[,] vectors; private CheckBox[,] checkboxes; - public ImportROMDialog(byte [] rom) + public Project.ImportRomSettings PromptForImportSettings(string filename) + { + importSettings = new Project.ImportRomSettings + { + rom_filename = filename, + rom_bytes = Util.ReadAllRomBytesFromFile(filename), + ROMMapMode = Util.DetectROMMapMode(importSettings.rom_bytes, out couldnt_detect_rom_type) + }; + + UpdateUIFromRomMapDetection(); + UpdateOffsetAndSpeed(); + + if (ShowDialog() != DialogResult.OK) + importSettings = null; + + importSettings.InitialLabels = GetGeneratedLabels(); + importSettings.InitialHeaderFlags = GetHeaderFlags(); + + return importSettings; + } + + public ImportROMDialog() { InitializeComponent(); vectors = new TextBox[2, 6] @@ -38,36 +59,33 @@ public ImportROMDialog(byte [] rom) { checkboxNativeCOP, checkboxNativeBRK, checkboxNativeABORT, checkboxNativeNMI, checkboxNativeRESET, checkboxNativeIRQ }, { checkboxEmuCOP, checkboxEmuBRK, checkboxEmuABORT, checkboxEmuNMI, checkboxEmuRESET, checkboxEmuIRQ }, }; - data = rom; - mode = DetectROMMapMode(); - UpdateOffsetAndSpeed(); } - public Dictionary GetGeneratedLabels() + private Dictionary GetGeneratedLabels() { - var labels = new Dictionary(); + var labels = new Dictionary(); for (int i = 0; i < checkboxes.GetLength(0); i++) { for (int j = 0; j < checkboxes.GetLength(1); j++) { - if (checkboxes[i, j].Checked) - { - int index = offset + 15 + 0x10 * i + 2 * j; - int val = data[index] + (data[index + 1] << 8); - int pc = Util.ConvertSNEStoPC(val); - if (pc >= 0 && pc < data.Length && !labels.ContainsKey(val)) - labels.Add(val, new Data.AliasInfo() {name = vectorNames[i, j]}); - } + if (!checkboxes[i, j].Checked) + continue; + + int index = offset + 15 + 0x10 * i + 2 * j; + int val = importSettings.rom_bytes[index] + (importSettings.rom_bytes[index + 1] << 8); + int pc = Util.ConvertSNESToPC(val, importSettings.ROMMapMode, importSettings.rom_bytes.Length); + if (pc >= 0 && pc < importSettings.rom_bytes.Length && !labels.ContainsKey(val)) + labels.Add(val, new Label() {name = vectorNames[i, j]}); } } return labels; } - public Dictionary GetHeaderFlags() + private Dictionary GetHeaderFlags() { - Dictionary flags = new Dictionary(); + var flags = new Dictionary(); if (checkHeader.Checked) { @@ -76,13 +94,13 @@ public ImportROMDialog(byte [] rom) for (int i = 0; i < 4; i++) flags.Add(offset + 7 + i, Data.FlagType.Data16Bit); for (int i = 0; i < 0x20; i++) flags.Add(offset + 11 + i, Data.FlagType.Pointer16Bit); - if (data[offset - 1] == 0) + if (importSettings.rom_bytes[offset - 1] == 0) { flags.Remove(offset - 1); flags.Add(offset - 1, Data.FlagType.Data8Bit); for (int i = 0; i < 0x10; i++) flags.Add(offset - 0x25 + i, Data.FlagType.Data8Bit); } - else if (data[offset + 5] == 0x33) + else if (importSettings.rom_bytes[offset + 5] == 0x33) { for (int i = 0; i < 6; i++) flags.Add(offset - 0x25 + i, Data.FlagType.Text); for (int i = 0; i < 10; i++) flags.Add(offset - 0x1F + i, Data.FlagType.Data8Bit); @@ -92,106 +110,74 @@ public ImportROMDialog(byte [] rom) return flags; } - private Data.ROMMapMode DetectROMMapMode() + private void UpdateUIFromRomMapDetection() { - if ((data[Data.LOROM_SETTING_OFFSET] & 0xEF) == 0x23) + if (couldnt_detect_rom_type) + detectMessage.Text = "Couldn't auto detect ROM Map Mode!"; + else + detectMessage.Text = "ROM Map Mode Detected: " + Util.GetRomMapModeName(importSettings.ROMMapMode); + + // TODO: there's definitely a better way. probably have the control read from a data table, + // then have it update itself based on the value of importSettings.ROMMapMode. + switch (importSettings.ROMMapMode) { - if (data.Length > 0x400000) - { - detectMessage.Text = "ROM Map Mode Detected: SA-1 ROM (FuSoYa's 8MB mapper)"; - comboBox1.SelectedIndex = 4; - return Data.ROMMapMode.ExSA1ROM; - } - else - { - detectMessage.Text = "ROM Map Mode Detected: SA-1 ROM"; + case Data.ROMMapMode.LoROM: + comboBox1.SelectedIndex = 0; + break; + case Data.ROMMapMode.HiROM: + comboBox1.SelectedIndex = 1; + break; + case Data.ROMMapMode.ExHiROM: + comboBox1.SelectedIndex = 6; + break; + case Data.ROMMapMode.SA1ROM: comboBox1.SelectedIndex = 3; - return Data.ROMMapMode.SA1ROM; - } - } - else if ((data[Data.LOROM_SETTING_OFFSET] & 0xEC) == 0x20) - { - if ((data[Data.LOROM_SETTING_OFFSET + 1] & 0xF0) == 0x10) { - detectMessage.Text = "ROM Map Mode Detected: SuperFX"; + break; + case Data.ROMMapMode.ExSA1ROM: + comboBox1.SelectedIndex = 4; + break; + case Data.ROMMapMode.SuperFX: comboBox1.SelectedIndex = 5; - return Data.ROMMapMode.SuperFX; - } else { - detectMessage.Text = "ROM Map Mode Detected: LoROM"; - comboBox1.SelectedIndex = 0; - return Data.ROMMapMode.LoROM; - } - } - else if (data.Length >= 0x10000 && (data[Data.HIROM_SETTING_OFFSET] & 0xEF) == 0x21) - { - detectMessage.Text = "ROM Map Mode Detected: HiROM"; - comboBox1.SelectedIndex = 1; - return Data.ROMMapMode.HiROM; - } - else if (data.Length >= 0x10000 && (data[Data.HIROM_SETTING_OFFSET] & 0xE7) == 0x22) - { - detectMessage.Text = "ROM Map Mode Detected: Super MMC"; - comboBox1.SelectedIndex = 2; - return Data.ROMMapMode.SuperMMC; - } - else if (data.Length >= 0x410000 && (data[Data.EXHIROM_SETTING_OFFSET] & 0xEF) == 0x25) - { - detectMessage.Text = "ROM Map Mode Detected: ExHiROM"; - comboBox1.SelectedIndex = 6; - return Data.ROMMapMode.ExHiROM; - } - else - { - detectMessage.Text = "Couldn't auto detect ROM Map Mode!"; - if (data.Length > 0x40000) - { + break; + case Data.ROMMapMode.SuperMMC: + comboBox1.SelectedIndex = 2; + break; + case Data.ROMMapMode.ExLoROM: comboBox1.SelectedIndex = 7; - return Data.ROMMapMode.ExLoROM; - } else - { - comboBox1.SelectedIndex = 0; - return Data.ROMMapMode.LoROM; - } + break; + default: + break; } } - public Data.ROMMapMode GetROMMapMode() - { - return mode; - } - - public Data.ROMSpeed GetROMSpeed() - { - return speed; - } - private void UpdateOffsetAndSpeed() { - offset = Data.Inst.GetRomSettingOffset(mode); - if (offset >= data.Length) + offset = Data.GetRomSettingOffset(importSettings.ROMMapMode); + if (offset >= importSettings.rom_bytes.Length) { - speed = Data.ROMSpeed.Unknown; + importSettings.ROMSpeed = Data.ROMSpeed.Unknown; okay.Enabled = false; } else { okay.Enabled = true; - speed = (data[offset] & 0x10) != 0 ? Data.ROMSpeed.FastROM : Data.ROMSpeed.SlowROM; + importSettings.ROMSpeed = (importSettings.rom_bytes[offset] & 0x10) != 0 ? Data.ROMSpeed.FastROM : Data.ROMSpeed.SlowROM; } } private void UpdateTextboxes() { - if (speed == Data.ROMSpeed.Unknown) + if (importSettings.ROMSpeed == Data.ROMSpeed.Unknown) { romspeed.Text = "????"; romtitle.Text = "?????????????????????"; for (int i = 0; i < vectors.GetLength(0); i++) for (int j = 0; j < vectors.GetLength(1); j++) vectors[i, j].Text = "????"; } else { - if (speed == Data.ROMSpeed.SlowROM) romspeed.Text = "SlowROM"; + if (importSettings.ROMSpeed == Data.ROMSpeed.SlowROM) romspeed.Text = "SlowROM"; else romspeed.Text = "FastROM"; title = ""; - for (int i = 0; i < 0x15; i++) title += (char)data[offset - 0x15 + i]; + for (int i = 0; i < 0x15; i++) title += (char)importSettings.rom_bytes[offset - 0x15 + i]; romtitle.Text = title; for (int i = 0; i < vectors.GetLength(0); i++) @@ -199,7 +185,7 @@ private void UpdateTextboxes() for (int j = 0; j < vectors.GetLength(1); j++) { int index = offset + 15 + 0x10 * i + 2 * j; - int val = data[index] + (data[index + 1] << 8); + int val = importSettings.rom_bytes[index] + (importSettings.rom_bytes[index + 1] << 8); vectors[i, j].Text = Util.NumberToBaseString(val, Util.NumberBase.Hexadecimal, 4); if (val < 0x8000) @@ -232,16 +218,17 @@ private void cancel_Click(object sender, EventArgs e) private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) { + // TODO: there's definitely a better way, we'll get to it :) switch (comboBox1.SelectedIndex) { - case 0: mode = Data.ROMMapMode.LoROM; break; - case 1: mode = Data.ROMMapMode.HiROM; break; - case 2: mode = Data.ROMMapMode.SuperMMC; break; - case 3: mode = Data.ROMMapMode.SA1ROM; break; - case 4: mode = Data.ROMMapMode.ExSA1ROM; break; - case 5: mode = Data.ROMMapMode.SuperFX; break; - case 6: mode = Data.ROMMapMode.ExHiROM; break; - case 7: mode = Data.ROMMapMode.ExLoROM; break; + case 0: importSettings.ROMMapMode = Data.ROMMapMode.LoROM; break; + case 1: importSettings.ROMMapMode = Data.ROMMapMode.HiROM; break; + case 2: importSettings.ROMMapMode = Data.ROMMapMode.SuperMMC; break; + case 3: importSettings.ROMMapMode = Data.ROMMapMode.SA1ROM; break; + case 4: importSettings.ROMMapMode = Data.ROMMapMode.ExSA1ROM; break; + case 5: importSettings.ROMMapMode = Data.ROMMapMode.SuperFX; break; + case 6: importSettings.ROMMapMode = Data.ROMMapMode.ExHiROM; break; + case 7: importSettings.ROMMapMode = Data.ROMMapMode.ExLoROM; break; } UpdateOffsetAndSpeed(); UpdateTextboxes(); diff --git a/DiztinGUIsh/window/dialog/MarkManyDialog.cs b/DiztinGUIsh/window/dialog/MarkManyDialog.cs index d88878c2..bd985706 100644 --- a/DiztinGUIsh/window/dialog/MarkManyDialog.cs +++ b/DiztinGUIsh/window/dialog/MarkManyDialog.cs @@ -15,9 +15,13 @@ public partial class MarkManyDialog : Form { private int start, end, count, value; - public MarkManyDialog(int offset, int column) + private Data Data; + + public MarkManyDialog(int offset, int column, Data data) { InitializeComponent(); + Data = data; + switch (column) { case 8: property.SelectedIndex = 1; break; @@ -27,7 +31,7 @@ public MarkManyDialog(int offset, int column) default: property.SelectedIndex = 0; break; } start = offset; - int rest = Data.Inst.GetROMSize() - start; + int rest = Data.GetROMSize() - start; count = rest < 0x10 ? rest : 0x10; end = start + count; @@ -102,7 +106,7 @@ private void UpdateGroup() mxCombo.Visible = (property.SelectedIndex == 3 || property.SelectedIndex == 4); archCombo.Visible = (property.SelectedIndex == 5); regValue.MaxLength = (property.SelectedIndex == 1 ? 3 : 5); - value = property.SelectedIndex == 1 ? Data.Inst.GetDataBank(start) : Data.Inst.GetDirectPage(start); + value = property.SelectedIndex == 1 ? Data.GetDataBank(start) : Data.GetDirectPage(start); } private bool updatingText = false; @@ -111,7 +115,7 @@ private void UpdateText(TextBox selected) { Util.NumberBase noBase = radioDec.Checked ? Util.NumberBase.Decimal : Util.NumberBase.Hexadecimal; int digits = noBase == Util.NumberBase.Hexadecimal && radioROM.Checked ? 6 : 0; - int size = Data.Inst.GetROMSize(); + int size = Data.GetROMSize(); int maxValue = property.SelectedIndex == 1 ? 0x100 : 0x10000; if (start < 0) start = 0; @@ -122,8 +126,8 @@ private void UpdateText(TextBox selected) if (value >= maxValue) value = maxValue - 1; updatingText = true; - if (selected != textStart) textStart.Text = Util.NumberToBaseString(radioROM.Checked ? Util.ConvertPCtoSNES(start) : start, noBase, digits); - if (selected != textEnd) textEnd.Text = Util.NumberToBaseString(radioROM.Checked ? Util.ConvertPCtoSNES(end) : end, noBase, digits); + if (selected != textStart) textStart.Text = Util.NumberToBaseString(radioROM.Checked ? Data.ConvertPCtoSNES(start) : start, noBase, digits); + if (selected != textEnd) textEnd.Text = Util.NumberToBaseString(radioROM.Checked ? Data.ConvertPCtoSNES(end) : end, noBase, digits); if (selected != textCount) textCount.Text = Util.NumberToBaseString(count, noBase, 0); if (selected != regValue) regValue.Text = Util.NumberToBaseString(value, noBase, 0); updatingText = false; @@ -157,7 +161,7 @@ private void textEnd_TextChanged(object sender, EventArgs e) int result = 0; if (int.TryParse(textEnd.Text, style, null, out result)) { - if (radioROM.Checked) result = Util.ConvertSNEStoPC(result); + if (radioROM.Checked) result = Data.ConvertSNEStoPC(result); end = result; count = end - start; } @@ -202,7 +206,7 @@ private void textStart_TextChanged(object sender, EventArgs e) int result = 0; if (int.TryParse(textStart.Text, style, null, out result)) { - if (radioROM.Checked) result = Util.ConvertSNEStoPC(result); + if (radioROM.Checked) result = Data.ConvertSNEStoPC(result); start = result; count = end - start; } diff --git a/DiztinGUIsh/window/dialog/MisalignmentChecker.cs b/DiztinGUIsh/window/dialog/MisalignmentChecker.cs index fad4b02e..dcc1c43d 100644 --- a/DiztinGUIsh/window/dialog/MisalignmentChecker.cs +++ b/DiztinGUIsh/window/dialog/MisalignmentChecker.cs @@ -12,8 +12,10 @@ namespace DiztinGUIsh { public partial class MisalignmentChecker : Form { - public MisalignmentChecker() + private Data Data { get; set; } + public MisalignmentChecker(Data data) { + Data = data; InitializeComponent(); } @@ -27,28 +29,28 @@ private void buttonScan_Click(object sender, EventArgs e) textLog.Text = ""; int found = 0, offset = 0; - while (found < 500 && offset < Data.Inst.GetROMSize()) + while (found < 500 && offset < Data.GetROMSize()) { - Data.FlagType flag = Data.Inst.GetFlag(offset), check = flag == Data.FlagType.Opcode ? Data.FlagType.Operand : flag; - int step = flag == Data.FlagType.Opcode ? Manager.GetInstructionLength(offset) : Util.TypeStepSize(flag); + Data.FlagType flag = Data.GetFlag(offset), check = flag == Data.FlagType.Opcode ? Data.FlagType.Operand : flag; + int step = flag == Data.FlagType.Opcode ? Data.GetInstructionLength(offset) : Util.TypeStepSize(flag); if (flag == Data.FlagType.Operand) { found++; textLog.Text += string.Format("{0} (0x{1}): Operand without Opcode\r\n", - Util.NumberToBaseString(Util.ConvertPCtoSNES(offset), Util.NumberBase.Hexadecimal, 6, true), + Util.NumberToBaseString(Data.ConvertPCtoSNES(offset), Util.NumberBase.Hexadecimal, 6, true), Util.NumberToBaseString(offset, Util.NumberBase.Hexadecimal, 0)); } else if (step > 1) { for (int i = 1; i < step; i++) { - if (Data.Inst.GetFlag(offset + i) != check) + if (Data.GetFlag(offset + i) != check) { found++; textLog.Text += string.Format("{0} (0x{1}): {2} is not {3}\r\n", - Util.NumberToBaseString(Util.ConvertPCtoSNES(offset + i), Util.NumberBase.Hexadecimal, 6, true), + Util.NumberToBaseString(Data.ConvertPCtoSNES(offset + i), Util.NumberBase.Hexadecimal, 6, true), Util.NumberToBaseString(offset + i, Util.NumberBase.Hexadecimal, 0), - Util.TypeToString(Data.Inst.GetFlag(offset + i)), + Util.TypeToString(Data.GetFlag(offset + i)), Util.TypeToString(check)); } } From df27e401ef1e04ec4fed1fc59070393bc1809489 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 27 Sep 2020 18:43:19 -0400 Subject: [PATCH 040/136] almost finished major rewrite of exporter and other subsystems --- DiztinGUIsh/App.config | 14 +- DiztinGUIsh/DiztinGUIsh.csproj | 11 +- DiztinGUIsh/Program.cs | 2 +- DiztinGUIsh/Properties/Resources.Designer.cs | 44 +- .../binary_serializer_old/BinarySerializer.cs | 5 +- DiztinGUIsh/static/Data.cs | 9 +- DiztinGUIsh/static/IProjectView.cs | 17 + DiztinGUIsh/static/Label.cs | 19 +- DiztinGUIsh/static/LogCreator.cs | 556 +++++++++++------- DiztinGUIsh/static/Project.cs | 19 +- DiztinGUIsh/static/ProjectController.cs | 90 +++ DiztinGUIsh/static/SampleRomData.cs | 166 ++++++ DiztinGUIsh/static/Util.cs | 5 + DiztinGUIsh/static/diz/CPU65C816.cs | 10 +- DiztinGUIsh/window/AliasList.cs | 9 +- DiztinGUIsh/window/MainWindow.Designer.cs | 42 +- DiztinGUIsh/window/MainWindow.cs | 162 ++--- DiztinGUIsh/window/MainWindow.resx | 6 - .../dialog/ExportDisassembly.Designer.cs | 8 + .../window/dialog/ExportDisassembly.cs | 338 ++++------- .../window/dialog/ExportDisassembly.resx | 6 + 21 files changed, 935 insertions(+), 603 deletions(-) create mode 100644 DiztinGUIsh/static/IProjectView.cs create mode 100644 DiztinGUIsh/static/ProjectController.cs create mode 100644 DiztinGUIsh/static/SampleRomData.cs diff --git a/DiztinGUIsh/App.config b/DiztinGUIsh/App.config index d804381b..8947d701 100644 --- a/DiztinGUIsh/App.config +++ b/DiztinGUIsh/App.config @@ -1,17 +1,17 @@ - + -
+
- + - + True @@ -21,9 +21,9 @@ - - + + - \ No newline at end of file + diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 33b131d6..f3e3a12a 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -8,10 +8,12 @@ WinExe DiztinGUIsh DiztinGUIsh - v4.6.1 + v4.8 512 true true + false + publish\ true Disk @@ -24,7 +26,6 @@ true 0 1.0.0.%2a - false false true @@ -37,6 +38,7 @@ DEBUG;TRACE prompt 4 + 8.0 AnyCPU @@ -46,6 +48,7 @@ TRACE prompt 4 + 8.0 resource\diz.ico @@ -113,8 +116,11 @@ + + + Form @@ -232,6 +238,7 @@ True Resources.resx + True diff --git a/DiztinGUIsh/Program.cs b/DiztinGUIsh/Program.cs index 84bcd0e0..cc10b405 100644 --- a/DiztinGUIsh/Program.cs +++ b/DiztinGUIsh/Program.cs @@ -23,7 +23,7 @@ static void Main(string[] args) Application.SetCompatibleTextRenderingDefault(false); MainWindow window = new MainWindow(); - if (args.Length > 0) window.openProject(args[0]); + if (args.Length > 0) window.OpenProject(args[0]); Application.Run(window); } diff --git a/DiztinGUIsh/Properties/Resources.Designer.cs b/DiztinGUIsh/Properties/Resources.Designer.cs index ea9fee9a..a0c17d2d 100644 --- a/DiztinGUIsh/Properties/Resources.Designer.cs +++ b/DiztinGUIsh/Properties/Resources.Designer.cs @@ -8,10 +8,10 @@ // //------------------------------------------------------------------------------ -namespace DiztinGUIsh.Properties -{ - - +namespace DiztinGUIsh.Properties { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -19,51 +19,43 @@ namespace DiztinGUIsh.Properties // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources - { - + internal class Resources { + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { + internal Resources() { } - + /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if ((resourceMan == null)) - { + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DiztinGUIsh.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { + internal static global::System.Globalization.CultureInfo Culture { + get { return resourceCulture; } - set - { + set { resourceCulture = value; } } diff --git a/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs b/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs index 7ba9837f..e81c8cc9 100644 --- a/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs +++ b/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs @@ -87,12 +87,11 @@ public override Project Load(byte[] data) for (int i = 0; i < size; i++) project.Data.SetInOutPoint(i, (Data.InOutPoint)data[pointer + 7 * size + i]); pointer += 8 * size; - AliasList.me.ResetDataGrid(); + // AliasList.me.ResetDataGrid(); // need this outta here. + ReadLabels(project, data, ref pointer, converter, version >= 2); ReadComments(project, data, ref pointer, converter); - // redundant but, needed for forwards-compatibility - // project.InternalRomSize = project.Data.GetROMSize(); project.UnsavedChanges = false; return project; diff --git a/DiztinGUIsh/static/Data.cs b/DiztinGUIsh/static/Data.cs index ceb06187..15cdc596 100644 --- a/DiztinGUIsh/static/Data.cs +++ b/DiztinGUIsh/static/Data.cs @@ -284,13 +284,13 @@ public void AddLabel(int i, Label v, bool overwrite) if (alias.ContainsKey(i)) { alias.Remove(i); - AliasList.me.RemoveRow(i); + // TODO: notify observers AliasList.me.RemoveRow(i); } } else { if (alias.ContainsKey(i) && overwrite) { alias.Remove(i); - AliasList.me.RemoveRow(i); + // // TODO: notify observers AliasList.me.RemoveRow(i); } if (alias.ContainsKey(i)) @@ -299,7 +299,7 @@ public void AddLabel(int i, Label v, bool overwrite) v.CleanUp(); alias.Add(i, v); - AliasList.me.AddRow(i, v); + // // TODO: notify observers AliasList.me.AddRow(i, v); } } @@ -310,8 +310,7 @@ public Dictionary GetAllLabels() public string GetComment(int i) { - if (Comments.TryGetValue(i, out var val)) return val; - return ""; + return Comments.TryGetValue(i, out var val) ? val : ""; } public void AddComment(int i, string v, bool overwrite) diff --git a/DiztinGUIsh/static/IProjectView.cs b/DiztinGUIsh/static/IProjectView.cs new file mode 100644 index 00000000..786177f9 --- /dev/null +++ b/DiztinGUIsh/static/IProjectView.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DiztinGUIsh +{ + interface IProjectView + { + Project Project { get; set; } + void OnProjectOpened(string filename); + void OnProjectOpenFail(); + void OnProjectSaved(); + void OnExportFinished(LogCreator.OutputResult result); + } +} diff --git a/DiztinGUIsh/static/Label.cs b/DiztinGUIsh/static/Label.cs index 803b0e78..9772f560 100644 --- a/DiztinGUIsh/static/Label.cs +++ b/DiztinGUIsh/static/Label.cs @@ -8,6 +8,16 @@ namespace DiztinGUIsh { public class Label { + public string name = ""; // name of the label + public string comment = ""; // user-generated text, comment only + public void CleanUp() + { + if (comment == null) comment = ""; + if (name == null) name = ""; + } + + #region Equality + protected bool Equals(Label other) { return name == other.name && comment == other.comment; @@ -28,13 +38,6 @@ public override int GetHashCode() } } - public string name = ""; // name of the label - public string comment = ""; // user-generated text, comment only - - public void CleanUp() - { - if (comment == null) comment = ""; - if (name == null) name = ""; - } + #endregion } } diff --git a/DiztinGUIsh/static/LogCreator.cs b/DiztinGUIsh/static/LogCreator.cs index 78b45d14..8a02c941 100644 --- a/DiztinGUIsh/static/LogCreator.cs +++ b/DiztinGUIsh/static/LogCreator.cs @@ -1,46 +1,44 @@ -using DiztinGUIsh.window; -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Reflection; namespace DiztinGUIsh { - public class LogCreator + public struct LogWriterSettings { - public Data Data => Project.Data; - public Project Project { get; set; } + // struct because we want to make a bunch of copies of this struct. + // The plumbing could use a pass of something like 'ref readonly' because: + // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#reference-return-values + + public string format; + public int dataPerLine; + public LogCreator.FormatUnlabeled unlabeled; + public LogCreator.FormatStructure structure; + public bool includeUnusedLabels; + public bool printLabelSpecificComments; - public LogCreator(Project project) - { - Project = project; + // these are both paths to files or folders. TODO: rename for better description + public string file; + public string error; - parameters = new Dictionary, int>> - { - { "", Tuple.Create, int>(GetPercent, 1) }, - { "label", Tuple.Create, int>(GetLabel, -22) }, - { "code", Tuple.Create, int>(GetCode, 37) }, - { "ia", Tuple.Create, int>(GetIntermediateAddress, 6) }, - { "pc", Tuple.Create, int>(GetProgramCounter, 6) }, - { "offset", Tuple.Create, int>(GetOffset, -6) }, - { "bytes", Tuple.Create, int>(GetRawBytes, 8) }, - { "comment", Tuple.Create, int>(GetComment, 1) }, - { "b", Tuple.Create, int>(GetDataBank, 2) }, - { "d", Tuple.Create, int>(GetDirectPage, 4) }, - { "m", Tuple.Create, int>(GetMFlag, 1) }, - { "x", Tuple.Create, int>(GetXFlag, 1) }, - { "%org", Tuple.Create, int>(GetORG, 37) }, - { "%map", Tuple.Create, int>(GetMap, 37) }, - { "%empty", Tuple.Create, int>(GetEmpty, 1) }, - { "%incsrc", Tuple.Create, int>(GetIncSrc, 1) }, - { "%bankcross", Tuple.Create, int>(GetBankCross, 1) }, - { "%labelassign", Tuple.Create, int>(GetLabelAssign, 1) }, - }; + public void SetDefaults() + { + format = "%label:-22% %code:37%;%pc%|%bytes%|%ia%; %comment%"; + dataPerLine = 8; + unlabeled = LogCreator.FormatUnlabeled.ShowInPoints; + structure = LogCreator.FormatStructure.OneBankPerFile; + includeUnusedLabels = false; + printLabelSpecificComments = false; + file = ""; // path to file or folder, rename + error = ""; // path to file or folder, rename } + } + public class LogCreator + { public enum FormatUnlabeled { ShowAll = 0, @@ -54,119 +52,270 @@ public enum FormatStructure OneBankPerFile = 1 } - public Dictionary, int>> parameters; + public class OutputResult + { + public bool success; + public int error_count; + } - public string format = "%label:-22% %code:37%;%pc%|%bytes%|%ia%; %comment%"; - public int dataPerLine = 8; - public FormatUnlabeled unlabeled = FormatUnlabeled.ShowInPoints; - public FormatStructure structure = FormatStructure.OneBankPerFile; - public bool includeUnusedLabels; - public bool printLabelSpecificComments; + private class AssemblerHandler : Attribute + { + public string token; + public int weight; + } + + public StreamWriter StreamOutput { get; set; } + public StreamWriter StreamError { get; set; } + public LogWriterSettings Settings { get; set; } + public Data Data { get; set; } - private List> list; + + // dont use directly except to cache attributes + private static Dictionary> parameters; + + // safe to use directly. + private static Dictionary> Parameters + { + get + { + CacheAssemblerAttributeInfo(); + return parameters; + } + } + + private List> parseList; private List usedLabels; - private StreamWriter err; private int errorCount, bankSize; private string folder; - public int CreateLog(StreamWriter sw, StreamWriter er) + private static void CacheAssemblerAttributeInfo() { - // TODO: now that we aren't using one gloabl instance, we don't have to Restore()/etc. - // we can just create a new Data() here nd use that. + if (parameters != null) + return; - var tempAlias = Data.GetAllLabels(); - Data.Restore(a: new Dictionary(tempAlias)); - AliasList.me.locked = true; - bankSize = Data.RomMapMode == Data.ROMMapMode.LoROM ? 0x8000 : 0x10000; // todo + parameters = new Dictionary>(); - AddTemporaryLabels(); + var methodsWithAttributes = typeof(LogCreator) + .GetMethods() + .Where( + x => x.GetCustomAttributes(typeof(AssemblerHandler), false).FirstOrDefault() != null + ); - string[] split = format.Split('%'); - err = er; - errorCount = 0; - usedLabels = new List(); - - list = new List>(); - for (int i = 0; i < split.Length; i++) + foreach (var method in methodsWithAttributes) { - if (i % 2 == 0) list.Add(Tuple.Create(split[i], int.MaxValue)); - else - { - int colon = split[i].IndexOf(':'); - if (colon < 0) list.Add(Tuple.Create(split[i], parameters[split[i]].Item2)); - else list.Add(Tuple.Create(split[i].Substring(0, colon), int.Parse(split[i].Substring(colon + 1)))); - } - } + var assemblerHandler = method.GetCustomAttribute(); + var token = assemblerHandler.token; + var weight = assemblerHandler.weight; - int pointer = 0, size = (ReferenceEquals(Data.GetTable(), ExportDisassembly.sampleTable)) ? 0x7B : Data.GetROMSize(), bank = -1; + // check your method signature if you hit this stuff. + Debug.Assert(method.GetParameters().Length == 2); - if (structure == FormatStructure.OneBankPerFile) - { - folder = Path.GetDirectoryName(((FileStream)sw.BaseStream).Name); - sw.WriteLine(GetLine(pointer, "map")); - sw.WriteLine(GetLine(pointer, "empty")); - for (int i = 0; i < size; i += bankSize) sw.WriteLine(GetLine(i, "incsrc")); - sw.WriteLine(GetLine(-1, "incsrc")); - } else + Debug.Assert(method.GetParameters()[0].ParameterType == typeof(int)); + Debug.Assert(method.GetParameters()[0].Name == "offset"); + + Debug.Assert(method.GetParameters()[1].ParameterType == typeof(int)); + Debug.Assert(method.GetParameters()[1].Name == "length"); + + Debug.Assert(method.ReturnType == typeof(string)); + + parameters.Add(token, (new Tuple(method, weight))); + } + } + + public string GetParameter(int offset, string parameter, int length) + { + if (!Parameters.TryGetValue(parameter, out var methodAndWeight)) { - sw.WriteLine(GetLine(pointer, "map")); - sw.WriteLine(GetLine(pointer, "empty")); + throw new InvalidDataException($"Unknown parameter: {parameter}"); } + var methodInfo = methodAndWeight.Item1; + var callParams = new object[] { offset, length }; + + var returnValue = methodInfo.Invoke(this, callParams); + + Debug.Assert(returnValue is string); + return returnValue as string; + } + + public OutputResult CreateLog() + { + // var aliases = Data.GetAllLabels(); // junk + // Data.Restore(a: new Dictionary(aliases)); // junk + // AliasList.me.locked = true; // notify observers. do this outside this class. + + bankSize = Util.GetBankSize(Data.RomMapMode); + errorCount = 0; + + GenerateGenericLabels(); + + usedLabels = new List(); + + SetupParseList(); + + var size = Data.GetROMSize(); + var pointer = WriteMainIncludes(size); + + int bank = -1; + // show a progress bar while this happens ProgressBarJob.Loop(size, () => { if (pointer >= size) return -1; // stop looping - WriteAddress(ref sw, ref pointer, tempAlias, ref bank); + WriteAddress(ref pointer, ref bank); return (long) pointer; // report current address as the progress }); - WriteLabels(ref sw, pointer); + WriteLabels(pointer); + + if (Settings.structure == FormatStructure.OneBankPerFile) + StreamOutput.Close(); + + // // TODO: notify observers AliasList.me.locked = false; + return new OutputResult() + { + error_count = errorCount, + success = true, + }; + } + + private int WriteMainIncludes(int size) + { + var pointer = 0; + if (Settings.structure == FormatStructure.OneBankPerFile) + { + folder = Path.GetDirectoryName(((FileStream) StreamOutput.BaseStream).Name); + StreamOutput.WriteLine(GetLine(pointer, "map")); + StreamOutput.WriteLine(GetLine(pointer, "empty")); + for (var i = 0; i < size; i += bankSize) + StreamOutput.WriteLine(GetLine(i, "incsrc")); + + StreamOutput.WriteLine(GetLine(-1, "incsrc")); + } + else + { + StreamOutput.WriteLine(GetLine(pointer, "map")); + StreamOutput.WriteLine(GetLine(pointer, "empty")); + } + + return pointer; + } + + // TODO: These are labels like "CODE_856469" and "DATA_763525". + // ISSUE: the original code just modified Data, but, we can't do that anymore. + // Either we need to copy all of it, or, we need another list of labels and use that. + private void GenerateGenericLabels() + { + var addressList = new List(); + var pointer = 0; + + while (pointer < Data.GetROMSize()) + { + var addr = GetLabelTargetAddress(pointer, out var length); + pointer += length; + + if (addr != -1) + addressList.Add(addr); + } + + // TODO: +/- labels + foreach (var t in addressList) + { + var label = new Label() + { + name = Data.GetDefaultLabel(t) + }; + + throw new NotImplementedException("see note above, not implemented yet."); + // if we were just going to add them we could do this: + // Data.AddLabel(t, label, false); + } + } + + private int GetLabelTargetAddress(int pointer, out int length) + { + length = GetLineByteLength(pointer); + + var flag = Data.GetFlag(pointer); + + bool c1 = Settings.unlabeled == LogCreator.FormatUnlabeled.ShowAll; + bool c2 = Settings.unlabeled != LogCreator.FormatUnlabeled.ShowNone && + (flag == Data.FlagType.Opcode || flag == Data.FlagType.Pointer16Bit || + flag == Data.FlagType.Pointer24Bit || flag == Data.FlagType.Pointer32Bit); + + if (c1) + { + return Data.ConvertPCtoSNES(pointer); + } + else if (c2) + { + var ia = Data.GetIntermediateAddressOrPointer(pointer); + + if (ia >= 0 && Data.ConvertSNEStoPC(ia) >= 0) + return ia; + } - if (structure == FormatStructure.OneBankPerFile) sw.Close(); - Data.Restore(a: tempAlias); - AliasList.me.locked = false; - return errorCount; + return -1; + } + + private void SetupParseList() + { + // TODO: this is probably not correct now, check + + string[] split = Settings.format.Split('%'); + parseList = new List>(); + for (int i = 0; i < split.Length; i++) + { + if (i % 2 == 0) parseList.Add(Tuple.Create(split[i], int.MaxValue)); + else + { + var colon = split[i].IndexOf(':'); + parseList.Add(colon < 0 + ? Tuple.Create(split[i], Parameters[split[i]].Item2) + : Tuple.Create(split[i].Substring(0, colon), int.Parse(split[i].Substring(colon + 1)))); + } + } } - private void WriteAddress(ref StreamWriter sw, ref int pointer, Dictionary tempAlias, ref int bank) + private void WriteAddress(ref int pointer, ref int bank) { - int snes = Data.ConvertPCtoSNES(pointer); + var snes = Data.ConvertPCtoSNES(pointer); if ((snes >> 16) != bank) { - if (structure == FormatStructure.OneBankPerFile) + // TODO: combine w/ SwitchOutputFile? + if (Settings.structure == FormatStructure.OneBankPerFile) { - sw.Close(); - sw = new StreamWriter(string.Format("{0}/bank_{1}.asm", folder, - Util.NumberToBaseString((snes >> 16), Util.NumberBase.Hexadecimal, 2))); + StreamOutput.Close(); + StreamOutput = new StreamWriter( + $"{folder}/bank_{Util.NumberToBaseString((snes >> 16), Util.NumberBase.Hexadecimal, 2)}.asm"); } - sw.WriteLine(GetLine(pointer, "empty")); - sw.WriteLine(GetLine(pointer, "org")); - sw.WriteLine(GetLine(pointer, "empty")); + StreamOutput.WriteLine(GetLine(pointer, "empty")); + StreamOutput.WriteLine(GetLine(pointer, "org")); + StreamOutput.WriteLine(GetLine(pointer, "empty")); if ((snes % bankSize) != 0) - err.WriteLine("({0}) Offset 0x{1:X}: An instruction crossed a bank boundary.", ++errorCount, pointer); + StreamError.WriteLine("({0}) Offset 0x{1:X}: An instruction crossed a bank boundary.", ++errorCount, pointer); bank = snes >> 16; } var c1 = (Data.GetInOutPoint(pointer) & (Data.InOutPoint.ReadPoint)) != 0; - var c2 = (tempAlias.TryGetValue(pointer, out var Label) && Label.name.Length > 0); + var c2 = (Data.GetAllLabels().TryGetValue(pointer, out var label) && label.name.Length > 0); if (c1 || c2) - sw.WriteLine(GetLine(pointer, "empty")); + StreamOutput.WriteLine(GetLine(pointer, "empty")); - sw.WriteLine(GetLine(pointer, null)); - if ((Data.GetInOutPoint(pointer) & (Data.InOutPoint.EndPoint)) != 0) sw.WriteLine(GetLine(pointer, "empty")); + StreamOutput.WriteLine(GetLine(pointer, null)); + if ((Data.GetInOutPoint(pointer) & (Data.InOutPoint.EndPoint)) != 0) StreamOutput.WriteLine(GetLine(pointer, "empty")); pointer += GetLineByteLength(pointer); } - private void WriteLabels(ref StreamWriter sw, int pointer) + private void WriteLabels(int pointer) { - SwitchOutputFile(ref sw, pointer, $"{folder}/labels.asm"); + SwitchOutputFile(pointer, $"{folder}/labels.asm"); - Dictionary listToPrint = new Dictionary(); + var listToPrint = new Dictionary(); // part 1: important: include all labels we aren't defining somewhere else. needed for disassembly foreach (var pair in Data.GetAllLabels()) @@ -180,117 +329,87 @@ private void WriteLabels(ref StreamWriter sw, int pointer) foreach (var pair in listToPrint) { - sw.WriteLine(GetLine(pair.Key, "labelassign")); + StreamOutput.WriteLine(GetLine(pair.Key, "labelassign")); } // part 2: optional: if requested, print all labels regardless of use. // Useful for debugging, documentation, or reverse engineering workflow. // this file shouldn't need to be included in the build, it's just reference documentation - if (includeUnusedLabels) + if (Settings.includeUnusedLabels) { - SwitchOutputFile(ref sw, pointer, $"{folder}/all-labels.txt"); + SwitchOutputFile(pointer, $"{folder}/all-labels.txt"); foreach (var pair in Data.GetAllLabels()) { // not the best place to add formatting, TODO: cleanup var category = listToPrint.ContainsKey(pair.Key) ? "INLINE" : "EXTRA "; - sw.WriteLine($";!^!-{category}-! " + GetLine(pair.Key, "labelassign")); + StreamOutput.WriteLine($";!^!-{category}-! " + GetLine(pair.Key, "labelassign")); } } } - private void SwitchOutputFile(ref StreamWriter sw, int pointer, string path) + private void SwitchOutputFile(int pointer, string path) { - if (structure == FormatStructure.OneBankPerFile) + if (Settings.structure == FormatStructure.OneBankPerFile) { - sw.Close(); - sw = new StreamWriter(path); + StreamOutput.Close(); + StreamOutput = new StreamWriter(path); } else { - sw.WriteLine(GetLine(pointer, "empty")); + StreamOutput.WriteLine(GetLine(pointer, "empty")); } } - private void AddTemporaryLabels() - { - List addMe = new List(); - int pointer = 0; - - while (pointer < Data.GetROMSize()) - { - int length = GetLineByteLength(pointer); - Data.FlagType flag = Data.GetFlag(pointer); - - if (unlabeled == FormatUnlabeled.ShowAll) addMe.Add(Data.ConvertPCtoSNES(pointer)); - else if (unlabeled != FormatUnlabeled.ShowNone && - (flag == Data.FlagType.Opcode || flag == Data.FlagType.Pointer16Bit || flag == Data.FlagType.Pointer24Bit || flag == Data.FlagType.Pointer32Bit)) - { - int ia = Data.GetIntermediateAddressOrPointer(pointer); - if (ia >= 0 && Data.ConvertSNEStoPC(ia) >= 0) addMe.Add(ia); - } - - pointer += length; - } - - // TODO +/- labels - for (int i = 0; i < addMe.Count; i++) - { - Data.AddLabel(addMe[i], - new Label() - { - name = Data.GetDefaultLabel(addMe[i]) - }, - false); - } - } + // -------------------------- + #region WriteOperations private string GetLine(int offset, string special) { - string line = ""; - for (int i = 0; i < list.Count; i++) + var line = ""; + foreach (var t in parseList) { - if (list[i].Item2 == int.MaxValue) // string literal + if (t.Item2 == int.MaxValue) // string literal { - line += list[i].Item1; + line += t.Item1; } else if (special != null) // special parameter (replaces code & everything else = empty) { - line += GetParameter(offset, "%" + (list[i].Item1 == "code" ? special : "empty"), list[i].Item2); + line += GetParameter(offset, "%" + (t.Item1 == "code" ? special : "empty"), t.Item2); } else // normal parameter { - line += GetParameter(offset, list[i].Item1, list[i].Item2); + line += GetParameter(offset, t.Item1, t.Item2); } } - if (special == null) + if (special != null) + return line; + + // throw out some errors if stuff looks fishy + Data.FlagType flag = Data.GetFlag(offset), check = flag == Data.FlagType.Opcode ? Data.FlagType.Operand : flag; + int step = flag == Data.FlagType.Opcode ? GetLineByteLength(offset) : Util.TypeStepSize(flag), size = Data.GetROMSize(); + if (flag == Data.FlagType.Operand) StreamError.WriteLine("({0}) Offset 0x{1:X}: Bytes marked as operands formatted as Data.", ++errorCount, offset); + else if (step > 1) { - // throw out some errors if stuff looks fishy - Data.FlagType flag = Data.GetFlag(offset), check = flag == Data.FlagType.Opcode ? Data.FlagType.Operand : flag; - int step = flag == Data.FlagType.Opcode ? GetLineByteLength(offset) : Util.TypeStepSize(flag), size = Data.GetROMSize(); - if (flag == Data.FlagType.Operand) err.WriteLine("({0}) Offset 0x{1:X}: Bytes marked as operands formatted as Data.", ++errorCount, offset); - else if (step > 1) + for (var i = 1; i < step; i++) { - for (int i = 1; i < step; i++) + if (offset + i >= size) { - if (offset + i >= size) - { - err.WriteLine("({0}) Offset 0x{1:X}: {2} extends past the end of the ROM.", ++errorCount, offset, Util.TypeToString(check)); - break; - } - else if (Data.GetFlag(offset + i) != check) - { - err.WriteLine("({0}) Offset 0x{1:X}: Expected {2}, but got {3} instead.", ++errorCount, offset + i, Util.TypeToString(check), Util.TypeToString(Data.GetFlag(offset + i))); - break; - } + StreamError.WriteLine("({0}) Offset 0x{1:X}: {2} extends past the end of the ROM.", ++errorCount, offset, Util.TypeToString(check)); + break; + } + else if (Data.GetFlag(offset + i) != check) + { + StreamError.WriteLine("({0}) Offset 0x{1:X}: Expected {2}, but got {3} instead.", ++errorCount, offset + i, Util.TypeToString(check), Util.TypeToString(Data.GetFlag(offset + i))); + break; } - } - int ia = Data.GetIntermediateAddress(offset, true); - if (ia >= 0 && flag == Data.FlagType.Opcode && Data.GetInOutPoint(offset) == Data.InOutPoint.OutPoint && Data.GetFlag(Data.ConvertSNEStoPC(ia)) != Data.FlagType.Opcode) - { - err.WriteLine("({0}) Offset 0x{1:X}: Branch or jump instruction to a non-instruction.", ++errorCount, offset); } } + var ia = Data.GetIntermediateAddress(offset, true); + if (ia >= 0 && flag == Data.FlagType.Opcode && Data.GetInOutPoint(offset) == Data.InOutPoint.OutPoint && Data.GetFlag(Data.ConvertSNEStoPC(ia)) != Data.FlagType.Opcode) + { + StreamError.WriteLine("({0}) Offset 0x{1:X}: Branch or jump instruction to a non-instruction.", ++errorCount, offset); + } return line; } @@ -298,34 +417,35 @@ private string GetLine(int offset, string special) private int GetLineByteLength(int offset) { int max = 1, step = 1; - int size = Data.GetROMSize(); + var size = Data.GetROMSize(); + var data = Data; - switch (Data.GetFlag(offset)) + switch (data.GetFlag(offset)) { case Data.FlagType.Opcode: - return Project.Data.OpcodeByteLength(offset); + return data.OpcodeByteLength(offset); case Data.FlagType.Unreached: case Data.FlagType.Operand: case Data.FlagType.Data8Bit: case Data.FlagType.Graphics: case Data.FlagType.Music: case Data.FlagType.Empty: - max = dataPerLine; + max = Settings.dataPerLine; break; case Data.FlagType.Text: max = 21; break; case Data.FlagType.Data16Bit: step = 2; - max = dataPerLine; + max = Settings.dataPerLine; break; case Data.FlagType.Data24Bit: step = 3; - max = dataPerLine; + max = Settings.dataPerLine; break; case Data.FlagType.Data32Bit: step = 4; - max = dataPerLine; + max = Settings.dataPerLine; break; case Data.FlagType.Pointer16Bit: step = 2; @@ -345,28 +465,47 @@ private int GetLineByteLength(int offset) while ( min < max && offset + min < size && - Data.GetFlag(offset + min) == Data.GetFlag(offset) && - Data.GetLabelName(Data.ConvertPCtoSNES(offset + min)) == "" && + data.GetFlag(offset + min) == data.GetFlag(offset) && + data.GetLabelName(data.ConvertPCtoSNES(offset + min)) == "" && (offset + min) / bankSize == myBank ) min += step; return min; } - public string GetParameter(int offset, string parameter, int length) + public static bool ValidateFormat(string formatString) { - Tuple, int> tup; - if (parameters.TryGetValue(parameter, out tup)) - return tup.Item1.Invoke(offset, length); - return ""; + var tokens = formatString.ToLower().Split('%'); + + // not valid if format has an odd amount of %s + if (tokens.Length % 2 == 0) return false; + + for (int i = 1; i < tokens.Length; i += 2) + { + int indexOfColon = tokens[i].IndexOf(':'); + string kind = indexOfColon >= 0 ? tokens[i].Substring(0, indexOfColon) : tokens[i]; + + // not valid if base token isn't one we know of + if (!Parameters.ContainsKey(kind)) + return false; + + // not valid if parameter isn't an integer + int oof; + if (indexOfColon >= 0 && !int.TryParse(tokens[i].Substring(indexOfColon + 1), out oof)) + return false; + } + + return true; } // just a % + [AssemblerHandler(token = "", weight = 1)] private static string GetPercent(int offset, int length) { return "%"; } // all spaces + [AssemblerHandler(token = "%empty", weight = 1)] private static string GetEmpty(int offset, int length) { return string.Format("{0," + length + "}", ""); @@ -374,10 +513,11 @@ private static string GetEmpty(int offset, int length) // trim to length // negative length = right justified + [AssemblerHandler(token = "label", weight = -22)] private string GetLabel(int offset, int length) { - int snes = Data.ConvertPCtoSNES(offset); - string label = Data.GetLabelName(snes); + var snes = Data.ConvertPCtoSNES(offset); + var label = Data.GetLabelName(snes); if (label == null) return ""; @@ -387,15 +527,16 @@ private string GetLabel(int offset, int length) } // trim to length + [AssemblerHandler(token = "code", weight = 37)] private string GetCode(int offset, int length) { - int bytes = GetLineByteLength(offset); + var bytes = GetLineByteLength(offset); string code = ""; switch (Data.GetFlag(offset)) { case Data.FlagType.Opcode: - code = Project.Data.GetInstruction(offset); + code = Data.GetInstruction(offset); break; case Data.FlagType.Unreached: case Data.FlagType.Operand: @@ -403,40 +544,42 @@ private string GetCode(int offset, int length) case Data.FlagType.Graphics: case Data.FlagType.Music: case Data.FlagType.Empty: - code = Project.Data.GetFormattedBytes(offset, 1, bytes); + code = Data.GetFormattedBytes(offset, 1, bytes); break; case Data.FlagType.Data16Bit: - code = Project.Data.GetFormattedBytes(offset, 2, bytes); + code = Data.GetFormattedBytes(offset, 2, bytes); break; case Data.FlagType.Data24Bit: - code = Project.Data.GetFormattedBytes(offset, 3, bytes); + code = Data.GetFormattedBytes(offset, 3, bytes); break; case Data.FlagType.Data32Bit: - code = Project.Data.GetFormattedBytes(offset, 4, bytes); + code = Data.GetFormattedBytes(offset, 4, bytes); break; case Data.FlagType.Pointer16Bit: - code = Project.Data.GetPointer(offset, 2); + code = Data.GetPointer(offset, 2); break; case Data.FlagType.Pointer24Bit: - code = Project.Data.GetPointer(offset, 3); + code = Data.GetPointer(offset, 3); break; case Data.FlagType.Pointer32Bit: - code = Project.Data.GetPointer(offset, 4); + code = Data.GetPointer(offset, 4); break; case Data.FlagType.Text: - code = Project.Data.GetFormattedText(offset, bytes); + code = Data.GetFormattedText(offset, bytes); break; } return string.Format("{0," + (length * -1) + "}", code); } + [AssemblerHandler(token = "%org", weight = 37)] private string GetORG(int offset, int length) { string org = "ORG " + Util.NumberToBaseString(Data.ConvertPCtoSNES(offset), Util.NumberBase.Hexadecimal, 6, true); return string.Format("{0," + (length * -1) + "}", org); } + [AssemblerHandler(token = "%map", weight = 37)] private string GetMap(int offset, int length) { string s = ""; @@ -454,6 +597,7 @@ private string GetMap(int offset, int length) } // 0+ = bank_xx.asm, -1 = labels.asm + [AssemblerHandler(token = "%incsrc", weight = 1)] private string GetIncSrc(int offset, int length) { string s = "incsrc \"labels.asm\""; @@ -465,6 +609,7 @@ private string GetIncSrc(int offset, int length) return string.Format("{0," + (length * -1) + "}", s); } + [AssemblerHandler(token = "%bankcross", weight = 1)] private string GetBankCross(int offset, int length) { string s = "check bankcross off"; @@ -472,73 +617,83 @@ private string GetBankCross(int offset, int length) } // length forced to 6 + [AssemblerHandler(token = "ia", weight = 6)] private string GetIntermediateAddress(int offset, int length) { - int ia = Project.Data.GetIntermediateAddressOrPointer(offset); + int ia = Data.GetIntermediateAddressOrPointer(offset); return ia >= 0 ? Util.NumberToBaseString(ia, Util.NumberBase.Hexadecimal, 6) : " "; } // length forced to 6 + [AssemblerHandler(token = "pc", weight = 6)] private string GetProgramCounter(int offset, int length) { return Util.NumberToBaseString(Data.ConvertPCtoSNES(offset), Util.NumberBase.Hexadecimal, 6); } // trim to length + [AssemblerHandler(token = "offset", weight = -6)] private string GetOffset(int offset, int length) { return string.Format("{0," + (length * -1) + "}", Util.NumberToBaseString(offset, Util.NumberBase.Hexadecimal, 0)); } // length forced to 8 + [AssemblerHandler(token = "bytes", weight = 8)] private string GetRawBytes(int offset, int length) { string bytes = ""; if (Data.GetFlag(offset) == Data.FlagType.Opcode) { - for (int i = 0; i < Data.GetInstructionLength(offset); i++) + for (var i = 0; i < Data.GetInstructionLength(offset); i++) { bytes += Util.NumberToBaseString(Data.GetROMByte(offset + i), Util.NumberBase.Hexadecimal); } } - return string.Format("{0,-8}", bytes); + return $"{bytes,-8}"; } // trim to length + [AssemblerHandler(token = "comment", weight = 1)] private string GetComment(int offset, int length) { return string.Format("{0," + (length * -1) + "}", Data.GetComment(Data.ConvertPCtoSNES(offset))); } // length forced to 2 + [AssemblerHandler(token = "b", weight = 2)] private string GetDataBank(int offset, int length) { return Util.NumberToBaseString(Data.GetDataBank(offset), Util.NumberBase.Hexadecimal, 2); } // length forced to 4 + [AssemblerHandler(token = "d", weight = 4)] private string GetDirectPage(int offset, int length) { return Util.NumberToBaseString(Data.GetDirectPage(offset), Util.NumberBase.Hexadecimal, 4); } // if length == 1, M/m, else 08/16 + [AssemblerHandler(token = "m", weight = 1)] private string GetMFlag(int offset, int length) { - bool m = Data.GetMFlag(offset); + var m = Data.GetMFlag(offset); if (length == 1) return m ? "M" : "m"; else return m ? "08" : "16"; } // if length == 1, X/x, else 08/16 + [AssemblerHandler(token = "x", weight = 1)] private string GetXFlag(int offset, int length) { - bool x = Data.GetXFlag(offset); + var x = Data.GetXFlag(offset); if (length == 1) return x ? "X" : "x"; else return x ? "08" : "16"; } // output label at snes offset, and its value + [AssemblerHandler(token = "%labelassign", weight = 1)] private string GetLabelAssign(int offset, int length) { var labelName = Data.GetLabelName(offset); @@ -548,17 +703,18 @@ private string GetLabelAssign(int offset, int length) if (string.IsNullOrEmpty(labelName)) return ""; - if (labelComment == null) - labelComment = ""; + labelComment ??= ""; var finalCommentText = ""; // TODO: sorry, probably not the best way to stuff this in here, consider putting it in the %comment% section in the future. -Dom - if (printLabelSpecificComments && labelComment != "") + if (Settings.printLabelSpecificComments && labelComment != "") finalCommentText = $"; !^ {labelComment} ^!"; string s = $"{labelName} = {offsetStr}{finalCommentText}"; return string.Format("{0," + (length * -1) + "}", s); } } + + #endregion } diff --git a/DiztinGUIsh/static/Project.cs b/DiztinGUIsh/static/Project.cs index c46ba72b..8c555a1c 100644 --- a/DiztinGUIsh/static/Project.cs +++ b/DiztinGUIsh/static/Project.cs @@ -3,9 +3,11 @@ using System.Collections.Generic; using System.IO; using System.Windows.Forms; +using ExtendedXmlSerializer; namespace DiztinGUIsh { + // MODEL public class Project { // Any public properties will be automatically serialized to XML. @@ -23,6 +25,13 @@ public class Project // needs to come last for serialization public Data Data { get; set; } + public LogWriterSettings LogWriterSettings; + + public Project() + { + LogWriterSettings.SetDefaults(); + } + public class ImportRomSettings { public Data.ROMMapMode ROMMapMode; @@ -35,13 +44,7 @@ public class ImportRomSettings public string rom_filename; } - public Project ImportRomAndCreateNewProject(ImportRomSettings importSettings) - { - var project = new Project(); - project.DoImportRomAndCreateNewProject(importSettings); - return project; - } - private void DoImportRomAndCreateNewProject(ImportRomSettings importSettings) + public void ImportRomAndCreateNewProject(ImportRomSettings importSettings) { AttachedRomFilename = importSettings.rom_filename; UnsavedChanges = false; @@ -51,7 +54,7 @@ private void DoImportRomAndCreateNewProject(ImportRomSettings importSettings) Data.Initiate(importSettings.rom_bytes, importSettings.ROMMapMode, importSettings.ROMSpeed); // TODO: get this UI out of here. probably just use databinding instead - AliasList.me.ResetDataGrid(); + // AliasList.me.ResetDataGrid(); if (importSettings.InitialLabels.Count > 0) { diff --git a/DiztinGUIsh/static/ProjectController.cs b/DiztinGUIsh/static/ProjectController.cs new file mode 100644 index 00000000..6752abc0 --- /dev/null +++ b/DiztinGUIsh/static/ProjectController.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using DiztinGUIsh.loadsave; + +namespace DiztinGUIsh +{ + class ProjectController + { + public IProjectView ProjectView { get; set; } + public Project Project { get; private set; } + + public bool OpenProject(string filename) + { + var project = ProjectFileManager.Open(filename); + if (project == null) + { + ProjectView.OnProjectOpenFail(); + return false; + } + + OnProjectOpened(filename, project); + return true; + } + + private void OnProjectOpened(string filename, Project project) + { + ProjectView.Project = Project = project; + ProjectView.OnProjectOpened(filename); + } + + public void SaveProject(string projectProjectFileName) + { + ProjectFileManager.Save(Project, Project.ProjectFileName); + ProjectView.OnProjectSaved(); + } + + public void ImportRomAndCreateNewProject(Project.ImportRomSettings importSettings) + { + var project = new Project(); + project.ImportRomAndCreateNewProject(importSettings); + + // TODO: seems like we probably should pick a place for the Project reference to live. + // either here in this class, or out in the view. + // right now we're passing around our class's Project and ProjectView's project. + + OnProjectOpened(project.ProjectFileName, project); + } + + public void WriteAssemblyOutput() + { + WriteAssemblyOutput(ref Project.LogWriterSettings); + } + + private void WriteAssemblyOutput(ref LogWriterSettings settings) + { + int errors = 0; + + // kinda hate that we're passing in these... + using var sw = new StreamWriter(settings.file); + using var er = new StreamWriter(settings.error); + + var lc = new LogCreator() + { + Settings = settings, + Data = Project.Data, + StreamOutput = sw, + StreamError = er, + }; + + var result = lc.CreateLog(); + + if (result.error_count == 0) + File.Delete(settings.error); + + ProjectView.OnExportFinished(result); + } + + public void UpdateExportSettings(LogWriterSettings selectedSettings) + { + // TODO: ref readonly or similar here, to save us an extra copy of the struct. + + Project.LogWriterSettings = selectedSettings; + } + } +} diff --git a/DiztinGUIsh/static/SampleRomData.cs b/DiztinGUIsh/static/SampleRomData.cs new file mode 100644 index 00000000..12490378 --- /dev/null +++ b/DiztinGUIsh/static/SampleRomData.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DiztinGUIsh.Properties; + +namespace DiztinGUIsh +{ + class SampleRomData : Data + { + // TODO: this was originally how this thing was setup, we probably should inject this in somewhere. + // I don't remember how it interacts with our sample RomBytes data + //while (sampleTable.Count < 0x8000) + // sampleTable.Add(new ROMByte()); + + public static SampleRomData SampleData = new SampleRomData + { + // random sample code I made up; hopefully it shows a little bit of + // everything so you can see how the settings will effect the output + RomBytes = { + new ROMByte {Rom = 0x78, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true, Point = Data.InOutPoint.InPoint}, + new ROMByte {Rom = 0xA9, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true}, + new ROMByte {Rom = 0x01, TypeFlag = Data.FlagType.Operand}, + new ROMByte {Rom = 0x8D, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true}, + new ROMByte {Rom = 0x0D, TypeFlag = Data.FlagType.Operand}, + new ROMByte {Rom = 0x42, TypeFlag = Data.FlagType.Operand}, + new ROMByte {Rom = 0x5C, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true, Point = Data.InOutPoint.EndPoint}, + new ROMByte {Rom = 0x0A, TypeFlag = Data.FlagType.Operand}, + new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand}, + new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand}, + new ROMByte {Rom = 0xC2, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true, Point = Data.InOutPoint.InPoint}, + new ROMByte {Rom = 0x30, TypeFlag = Data.FlagType.Operand}, + new ROMByte {Rom = 0xA9, TypeFlag = Data.FlagType.Opcode}, + new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand}, + new ROMByte {Rom = 0x21, TypeFlag = Data.FlagType.Operand}, + new ROMByte {Rom = 0x5B, TypeFlag = Data.FlagType.Opcode}, + new ROMByte {Rom = 0x4B, TypeFlag = Data.FlagType.Opcode, DirectPage = 0x2100}, + new ROMByte {Rom = 0xAB, TypeFlag = Data.FlagType.Opcode, DirectPage = 0x2100}, + new ROMByte {Rom = 0xA2, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x07, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xBF, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x32, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x9F, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x7E, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xCA, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xCA, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x10, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xF4, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x64, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x40, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x64, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x41, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x64, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x42, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x64, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x43, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xAE, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xFC, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x3A, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x4C, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.EndPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xC0, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Data16Bit, Point = Data.InOutPoint.ReadPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x08, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x10, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x20, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x44, TypeFlag = Data.FlagType.Pointer16Bit, Point = Data.InOutPoint.ReadPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x7B, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x44, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x81, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xC4, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x81, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x0A, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x82, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x08, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x8B, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x4B, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xAB, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xE2, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x20, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xC2, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x10, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xA2, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x1F, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xBD, TypeFlag = Data.FlagType.Opcode, MFlag = true, Point = Data.InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x5B, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x9D, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x01, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xCA, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x10, TypeFlag = Data.FlagType.Opcode, MFlag = true, Point = Data.InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xF7, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xAB, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x28, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x60, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.EndPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x45, TypeFlag = Data.FlagType.Data8Bit, Point = Data.InOutPoint.ReadPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x8D, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x69, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x83, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xB2, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x99, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x23, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x01, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xA3, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xF8, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x52, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x08, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xBB, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x29, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x5C, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x32, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xE7, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x88, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x3C, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x30, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x18, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x9A, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xB0, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x34, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x8C, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xDD, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x05, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xB7, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x83, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x34, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x6D, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + }, + Comments = new Dictionary + { + {0x03, "this sets FastROM"}, + {0x0F, "direct page = $2100"}, + {0x21, "clear APU regs"}, + {0x44, "this routine copies Test_Data to $7E0100"} + }, + alias = new Dictionary + { + {0x00, new Label() {name = "Emulation_RESET", comment = "Sample emulation reset location"}}, + {0x0A, new Label() {name = "FastRESET", comment = "Sample label"}}, + {0x32, new Label() {name = "Test_Indices"}}, + {0x3A, new Label() {name = "Pointer_Table"}}, + {0x44, new Label() {name = "First_Routine"}}, + {0x5B, new Label() {name = "Test_Data", comment = "Pretty cool huh?"}} + }, + RomMapMode = Data.ROMMapMode.LoROM, + RomSpeed = Data.ROMSpeed.FastROM, + }; + } +} diff --git a/DiztinGUIsh/static/Util.cs b/DiztinGUIsh/static/Util.cs index 008b8ecf..77103ae6 100644 --- a/DiztinGUIsh/static/Util.cs +++ b/DiztinGUIsh/static/Util.cs @@ -15,6 +15,11 @@ public enum NumberBase { Decimal = 3, Hexadecimal = 2, Binary = 8 } + public static int GetBankSize(Data.ROMMapMode mode) + { + // todo + return mode == Data.ROMMapMode.LoROM ? 0x8000 : 0x10000; + } public static int ConvertSNESToPC(int address, Data.ROMMapMode mode, int size) { diff --git a/DiztinGUIsh/static/diz/CPU65C816.cs b/DiztinGUIsh/static/diz/CPU65C816.cs index c9f878d3..966e70b3 100644 --- a/DiztinGUIsh/static/diz/CPU65C816.cs +++ b/DiztinGUIsh/static/diz/CPU65C816.cs @@ -161,7 +161,12 @@ public string GetInstruction(int offset) public int GetInstructionLength(int offset) { - AddressMode mode = GetAddressMode(offset); + var mode = GetAddressMode(offset); + return InstructionLength(mode); + } + + public static int InstructionLength(AddressMode mode) + { switch (mode) { case AddressMode.IMPLIED: @@ -195,6 +200,7 @@ public int GetInstructionLength(int offset) case AddressMode.LONG_X_INDEX: return 4; } + return 1; } @@ -356,7 +362,7 @@ private AddressMode GetAddressMode(int offset) return mode; } - private enum AddressMode : byte + public enum AddressMode : byte { IMPLIED, ACCUMULATOR, CONSTANT_8, IMMEDIATE_8, IMMEDIATE_16, IMMEDIATE_X_FLAG_DEPENDENT, IMMEDIATE_M_FLAG_DEPENDENT, diff --git a/DiztinGUIsh/window/AliasList.cs b/DiztinGUIsh/window/AliasList.cs index 9037d754..ca0a69b6 100644 --- a/DiztinGUIsh/window/AliasList.cs +++ b/DiztinGUIsh/window/AliasList.cs @@ -16,7 +16,6 @@ namespace DiztinGUIsh.window public partial class AliasList : Form { // single instance - public static AliasList me; // TODO: get rid of static field and access via MainWindow private MainWindow mw; public bool locked = false; @@ -24,12 +23,8 @@ public partial class AliasList : Form public AliasList(MainWindow main) { - if (me == null) - { - me = this; - mw = main; - InitializeComponent(); - } + mw = main; + InitializeComponent(); } private void AliasList_Load(object sender, EventArgs e) diff --git a/DiztinGUIsh/window/MainWindow.Designer.cs b/DiztinGUIsh/window/MainWindow.Designer.cs index 64acb053..adb460e6 100644 --- a/DiztinGUIsh/window/MainWindow.Designer.cs +++ b/DiztinGUIsh/window/MainWindow.Designer.cs @@ -61,6 +61,7 @@ private void InitializeComponent() this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.newProjectToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.openProjectToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripOpenLast = new System.Windows.Forms.ToolStripMenuItem(); this.saveProjectToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.saveProjectAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); @@ -119,6 +120,7 @@ private void InitializeComponent() this.binaryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.optionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.moveWithStepToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.openLastProjectAutomaticallyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.labelListToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.viewHelpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -132,13 +134,9 @@ private void InitializeComponent() this.openProjectFile = new System.Windows.Forms.OpenFileDialog(); this.saveProjectFile = new System.Windows.Forms.SaveFileDialog(); this.vScrollBar1 = new System.Windows.Forms.VScrollBar(); - this.saveLogSingleFile = new System.Windows.Forms.SaveFileDialog(); - this.chooseLogFolder = new System.Windows.Forms.FolderBrowserDialog(); this.openUsageMapFile = new System.Windows.Forms.OpenFileDialog(); this.openTraceLogDialog = new System.Windows.Forms.OpenFileDialog(); this.openCDLDialog = new System.Windows.Forms.OpenFileDialog(); - this.toolStripOpenLast = new System.Windows.Forms.ToolStripMenuItem(); - this.openLastProjectAutomaticallyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); ((System.ComponentModel.ISupportInitialize)(this.table)).BeginInit(); this.menuStrip1.SuspendLayout(); this.statusStrip1.SuspendLayout(); @@ -401,6 +399,13 @@ private void InitializeComponent() this.openProjectToolStripMenuItem.Text = "Open Project..."; this.openProjectToolStripMenuItem.Click += new System.EventHandler(this.openProjectToolStripMenuItem_Click); // + // toolStripOpenLast + // + this.toolStripOpenLast.Name = "toolStripOpenLast"; + this.toolStripOpenLast.Size = new System.Drawing.Size(235, 22); + this.toolStripOpenLast.Text = "Open Last Project"; + this.toolStripOpenLast.Click += new System.EventHandler(this.toolStripOpenLast_Click); + // // saveProjectToolStripMenuItem // this.saveProjectToolStripMenuItem.Enabled = false; @@ -889,6 +894,13 @@ private void InitializeComponent() this.moveWithStepToolStripMenuItem.Text = "Move With Step"; this.moveWithStepToolStripMenuItem.Click += new System.EventHandler(this.moveWithStepToolStripMenuItem_Click); // + // openLastProjectAutomaticallyToolStripMenuItem + // + this.openLastProjectAutomaticallyToolStripMenuItem.Name = "openLastProjectAutomaticallyToolStripMenuItem"; + this.openLastProjectAutomaticallyToolStripMenuItem.Size = new System.Drawing.Size(244, 22); + this.openLastProjectAutomaticallyToolStripMenuItem.Text = "Open Last Project Automatically"; + this.openLastProjectAutomaticallyToolStripMenuItem.Click += new System.EventHandler(this.openLastProjectAutomaticallyToolStripMenuItem_Click); + // // labelListToolStripMenuItem // this.labelListToolStripMenuItem.Enabled = false; @@ -962,7 +974,7 @@ private void InitializeComponent() this.currentMarker.Size = new System.Drawing.Size(110, 17); this.currentMarker.Text = "Marker: Data (8-bit)"; // - // openROMFile + // openFileDialog // this.openFileDialog.Filter = "SNES ROM Images|*.smc;*.sfc|All files|*.*"; // @@ -985,10 +997,6 @@ private void InitializeComponent() this.vScrollBar1.TabIndex = 2; this.vScrollBar1.ValueChanged += new System.EventHandler(this.vScrollBar1_ValueChanged); // - // saveLogSingleFile - // - this.saveLogSingleFile.Filter = "Assembly Files|*.asm|All Files|*.*"; - // // openUsageMapFile // this.openUsageMapFile.Filter = "bsnes-plus usage map files|*.bin"; @@ -1001,20 +1009,6 @@ private void InitializeComponent() // this.openCDLDialog.Filter = "BizHawk Code Data Logger Files|*.cdl|All Files|*.*"; // - // toolStripOpenLast - // - this.toolStripOpenLast.Name = "toolStripOpenLast"; - this.toolStripOpenLast.Size = new System.Drawing.Size(235, 22); - this.toolStripOpenLast.Text = "Open Last Project"; - this.toolStripOpenLast.Click += new System.EventHandler(this.toolStripOpenLast_Click); - // - // openLastProjectAutomaticallyToolStripMenuItem - // - this.openLastProjectAutomaticallyToolStripMenuItem.Name = "openLastProjectAutomaticallyToolStripMenuItem"; - this.openLastProjectAutomaticallyToolStripMenuItem.Size = new System.Drawing.Size(244, 22); - this.openLastProjectAutomaticallyToolStripMenuItem.Text = "Open Last Project Automatically"; - this.openLastProjectAutomaticallyToolStripMenuItem.Click += new System.EventHandler(this.openLastProjectAutomaticallyToolStripMenuItem_Click); - // // MainWindow // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); @@ -1118,8 +1112,6 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem githubToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem importTraceLogToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem gotoNextUnreachedToolStripMenuItem; - private System.Windows.Forms.SaveFileDialog saveLogSingleFile; - private System.Windows.Forms.FolderBrowserDialog chooseLogFolder; private System.Windows.Forms.ToolStripMenuItem optionsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem moveWithStepToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem importUsageMapToolStripMenuItem; diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index c7eb55e0..250dd18a 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -6,10 +6,11 @@ using System.Windows.Forms; using DiztinGUIsh.loadsave; using DiztinGUIsh.Properties; +using ExtendedXmlSerializer.ExtensionModel.Types.Sources; namespace DiztinGUIsh { - public partial class MainWindow : Form + public partial class MainWindow : Form, IProjectView { public Project Project { get; set; } @@ -70,7 +71,7 @@ private void MainWindow_Load(object sender, EventArgs e) private void openLastProject() { if (Settings.Default.LastOpenedFile != "") - openProject(Settings.Default.LastOpenedFile); + OpenProject(Settings.Default.LastOpenedFile); } public void UpdateWindowTitle() @@ -92,7 +93,7 @@ private bool ContinueUnsavedChanges() } - public void TriggerSaveOptions(bool save, bool saveas) + public void UpdateSaveOptionStates(bool save, bool saveas) { saveProjectToolStripMenuItem.Enabled = save; saveProjectAsToolStripMenuItem.Enabled = saveas; @@ -124,7 +125,7 @@ private string PromptForOpenFilename() private void OnImportedProjectSuccess() { importCDLToolStripMenuItem.Enabled = true; - TriggerSaveOptions(false, true); + UpdateSaveOptionStates(false, true); UpdateWindowTitle(); UpdateDataGridView(); UpdatePercent(); @@ -140,7 +141,7 @@ private bool TryImportProject(string romFileToOpen) if (importSettings == null) return false; - Project.ImportRomAndCreateNewProject(importSettings); + ProjectController.ImportRomAndCreateNewProject(importSettings); return true; } catch (Exception ex) @@ -160,7 +161,7 @@ private void openProjectToolStripMenuItem_Click(object sender, EventArgs e) if (openProjectFile.ShowDialog() != DialogResult.OK) return; - openProject(openProjectFile.FileName); + OpenProject(openProjectFile.FileName); } public string LastProjectFilename @@ -186,42 +187,62 @@ private void UpdateUIFromSettings() openLastProjectAutomaticallyToolStripMenuItem.Checked = Settings.Default.OpenLastFileAutomatically; } - public void openProject(string filename) + public void OnProjectOpened(string filename) { - var project = ProjectFileManager.Open(filename); - if (project == null) - { - LastProjectFilename = ""; - return; - } + LastProjectFilename = filename; - Project = project; - importCDLToolStripMenuItem.Enabled = true; - TriggerSaveOptions(true, true); + UpdateSaveOptionStates(true, true); UpdateWindowTitle(); UpdateDataGridView(); UpdatePercent(); table.Invalidate(); EnableSubWindows(); - LastProjectFilename = filename; + } + + public void OnProjectOpenFail() + { + LastProjectFilename = ""; + } + + + public void OpenProject(string filename) + { + ProjectController.OpenProject(filename); } private void saveProjectToolStripMenuItem_Click(object sender, EventArgs e) { - ProjectFileManager.Save(Project, Project.ProjectFileName); + SaveProject(Project.ProjectFileName); + } + + public void SaveProject(string filename) + { + ProjectController.SaveProject(filename); + } + + public void OnProjectSaved() + { + UpdateSaveOptionStates(true, true); UpdateWindowTitle(); } + public void OnExportFinished(LogCreator.OutputResult result) + { + if (result.error_count > 0) + MessageBox.Show("Disassembly created with errors. See errors.txt for details.", "Warning", + MessageBoxButtons.OK, MessageBoxIcon.Warning); + else + MessageBox.Show("Disassembly created successfully!", "Complete", MessageBoxButtons.OK, + MessageBoxIcon.Asterisk); + } + private void saveProjectAsToolStripMenuItem_Click(object sender, EventArgs e) { saveProjectFile.InitialDirectory = Project.AttachedRomFilename; - DialogResult result = saveProjectFile.ShowDialog(); - if (result == DialogResult.OK && saveProjectFile.FileName != "") + if (saveProjectFile.ShowDialog() == DialogResult.OK && saveProjectFile.FileName != "") { - ProjectFileManager.Save(Project, saveProjectFile.FileName); - TriggerSaveOptions(true, true); - UpdateWindowTitle(); + SaveProject(saveProjectFile.FileName); } } @@ -254,54 +275,33 @@ private void importCDLToolStripMenuItem_Click(object sender, EventArgs e) } } + private readonly ProjectController ProjectController = new ProjectController(); + private void exportLogToolStripMenuItem_Click(object sender, EventArgs e) { - var lc = new LogCreator(Project); - - var export = new ExportDisassembly(lc); - if (export.ShowDialog() != DialogResult.OK) + var adjustedSettings = PromptForExportSettingsAndConfirmation(); + if (!adjustedSettings.HasValue) return; - string file = null, error = null; + ProjectController.UpdateExportSettings(adjustedSettings.Value); + ProjectController.WriteAssemblyOutput(); + } + + private LogWriterSettings? PromptForExportSettingsAndConfirmation() + { + // TODO: use the controller to update the project settings from a new one we build + // don't update directly. + // probably make our Project property be fully readonly/const/whatever [ReadOnly] attribute - // TODO: save this as a setting in the project file - if (lc.structure == LogCreator.FormatStructure.SingleFile) - { - saveLogSingleFile.InitialDirectory = Project.ProjectFileName; - if (saveLogSingleFile.ShowDialog() == DialogResult.OK && saveLogSingleFile.FileName != "") - { - file = saveLogSingleFile.FileName; - error = Path.GetDirectoryName(file) + "/error.txt"; - } - } - else - { - chooseLogFolder.SelectedPath = Path.GetDirectoryName(Project.ProjectFileName); - if (chooseLogFolder.ShowDialog() == DialogResult.OK && chooseLogFolder.SelectedPath != "") - { - file = chooseLogFolder.SelectedPath + "/main.asm"; - error = Path.GetDirectoryName(file) + "/error.txt"; - } - } + var selectedSettings = ExportDisassembly.ConfirmSettingsAndAskToStart(Project); + if (!selectedSettings.HasValue) + return null; - if (file == null) - return; + var settings = selectedSettings.Value; - int errors = 0; - using (StreamWriter sw = new StreamWriter(file)) - using (StreamWriter er = new StreamWriter(error)) - { - errors = lc.CreateLog(sw, er); - if (errors > 0) - MessageBox.Show("Disassembly created with errors. See errors.txt for details.", "Warning", - MessageBoxButtons.OK, MessageBoxIcon.Warning); - else - MessageBox.Show("Disassembly created successfully!", "Complete", MessageBoxButtons.OK, - MessageBoxIcon.Asterisk); - } + ProjectController.UpdateExportSettings(selectedSettings.Value); - if (errors == 0) - File.Delete(error); + return settings; } private void viewHelpToolStripMenuItem_Click(object sender, EventArgs e) @@ -387,24 +387,30 @@ public void InvalidateTable() private void UpdateDataGridView() { - if (Project.Data.GetROMSize() > 0) - { - rowsToShow = ((table.Height - table.ColumnHeadersHeight) / table.RowTemplate.Height); - if (viewOffset + rowsToShow > Project.Data.GetROMSize()) viewOffset = Project.Data.GetROMSize() - rowsToShow; - if (viewOffset < 0) viewOffset = 0; - vScrollBar1.Enabled = true; - vScrollBar1.Maximum = Project.Data.GetROMSize() - rowsToShow; - vScrollBar1.Value = viewOffset; - table.RowCount = rowsToShow; - - importTraceLogToolStripMenuItem.Enabled = true; - importUsageMapToolStripMenuItem.Enabled = true; - } + if (Project.Data.GetROMSize() <= 0) + return; + + rowsToShow = ((table.Height - table.ColumnHeadersHeight) / table.RowTemplate.Height); + + if (viewOffset + rowsToShow > Project.Data.GetROMSize()) + viewOffset = Project.Data.GetROMSize() - rowsToShow; + + if (viewOffset < 0) + viewOffset = 0; + + vScrollBar1.Enabled = true; + vScrollBar1.Maximum = Project.Data.GetROMSize() - rowsToShow; + vScrollBar1.Value = viewOffset; + table.RowCount = rowsToShow; + + importTraceLogToolStripMenuItem.Enabled = true; + importUsageMapToolStripMenuItem.Enabled = true; } private void table_MouseWheel(object sender, MouseEventArgs e) { - if (Project.Data.GetROMSize() <= 0) return; + if (Project.Data.GetROMSize() <= 0) + return; int selRow = table.CurrentCell.RowIndex + viewOffset, selCol = table.CurrentCell.ColumnIndex; int amount = e.Delta / 0x18; viewOffset -= amount; @@ -1110,7 +1116,7 @@ public OpenFileDialog GetRomOpenFileDialog() } // sub windows - AliasList aliasList; + public AliasList aliasList; private void EnableSubWindows() { diff --git a/DiztinGUIsh/window/MainWindow.resx b/DiztinGUIsh/window/MainWindow.resx index d6ef4ab3..884e0d97 100644 --- a/DiztinGUIsh/window/MainWindow.resx +++ b/DiztinGUIsh/window/MainWindow.resx @@ -171,12 +171,6 @@ 528, 17 - - 660, 17 - - - 808, 17 - 953, 17 diff --git a/DiztinGUIsh/window/dialog/ExportDisassembly.Designer.cs b/DiztinGUIsh/window/dialog/ExportDisassembly.Designer.cs index 25ac93bc..73297ae4 100644 --- a/DiztinGUIsh/window/dialog/ExportDisassembly.Designer.cs +++ b/DiztinGUIsh/window/dialog/ExportDisassembly.Designer.cs @@ -44,6 +44,8 @@ private void InitializeComponent() this.numData = new System.Windows.Forms.NumericUpDown(); this.chkPrintLabelSpecificComments = new System.Windows.Forms.CheckBox(); this.chkIncludeUnusedLabels = new System.Windows.Forms.CheckBox(); + this.saveLogSingleFile = new System.Windows.Forms.SaveFileDialog(); + this.chooseLogFolder = new System.Windows.Forms.FolderBrowserDialog(); ((System.ComponentModel.ISupportInitialize)(this.numData)).BeginInit(); this.SuspendLayout(); // @@ -216,6 +218,10 @@ private void InitializeComponent() this.chkIncludeUnusedLabels.UseVisualStyleBackColor = true; this.chkIncludeUnusedLabels.CheckedChanged += new System.EventHandler(this.chkIncludeUnusedLabels_CheckedChanged); // + // saveLogSingleFile + // + this.saveLogSingleFile.Filter = "Assembly Files|*.asm|All Files|*.*"; + // // ExportDisassembly // this.AcceptButton = this.button2; @@ -266,5 +272,7 @@ private void InitializeComponent() private System.Windows.Forms.NumericUpDown numData; private System.Windows.Forms.CheckBox chkPrintLabelSpecificComments; private System.Windows.Forms.CheckBox chkIncludeUnusedLabels; + private System.Windows.Forms.SaveFileDialog saveLogSingleFile; + private System.Windows.Forms.FolderBrowserDialog chooseLogFolder; } } \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/ExportDisassembly.cs b/DiztinGUIsh/window/dialog/ExportDisassembly.cs index 61799d06..bc0a2bd0 100644 --- a/DiztinGUIsh/window/dialog/ExportDisassembly.cs +++ b/DiztinGUIsh/window/dialog/ExportDisassembly.cs @@ -1,32 +1,51 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; using System.IO; -using System.Linq; using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; namespace DiztinGUIsh { + // consider renaming? this class is mostly about editing settings, with a 'save' button at the + // end. public partial class ExportDisassembly : Form { - private readonly LogCreator LogCreator; - private Data Data => LogCreator.Data; - public ExportDisassembly(LogCreator lc) + //private readonly LogCreator LogCreator; + private Data Data => Project.Data; + private readonly Project Project; + + // Our copy. At the end, if everything is correct, we'll return this. + private LogWriterSettings settings; + + // shows the UI and returns non-null settings if everything went OK in the + // setup process. + public static LogWriterSettings? ConfirmSettingsAndAskToStart(Project project) { - LogCreator = lc; + var export = new ExportDisassembly(project); + if (export.ShowDialog() != DialogResult.OK) + return null; + + return export.settings; + } + + public ExportDisassembly(Project project) + { + Project = project; + settings = project.LogWriterSettings; // copy InitializeComponent(); - numData.Value = LogCreator.dataPerLine; - textFormat.Text = LogCreator.format; - comboUnlabeled.SelectedIndex = (int)LogCreator.unlabeled; - comboStructure.SelectedIndex = (int)LogCreator.structure; - chkIncludeUnusedLabels.Checked = LogCreator.includeUnusedLabels; - chkPrintLabelSpecificComments.Checked = LogCreator.printLabelSpecificComments; - UpdateSample(); + UpdateUiFromProjectSettings(); + RegenerateSampleOutput(); + } + + public void UpdateUiFromProjectSettings() + { + // TODO: in the future, replace this with databinding so we don't have to do it manually + numData.Value = settings.dataPerLine; + textFormat.Text = settings.format; + comboUnlabeled.SelectedIndex = (int)settings.unlabeled; + comboStructure.SelectedIndex = (int)settings.structure; + chkIncludeUnusedLabels.Checked = settings.includeUnusedLabels; + chkPrintLabelSpecificComments.Checked = settings.printLabelSpecificComments; } private void cancel_Click(object sender, EventArgs e) @@ -36,18 +55,58 @@ private void cancel_Click(object sender, EventArgs e) private void button2_Click(object sender, EventArgs e) { + if (!PromptForPath()) + return; + this.DialogResult = DialogResult.OK; } + // Prompt user for either a filename to save, or a folder location + private string PromptForLogPathFromFileOrFolderDialog(bool askForFile) + { + if (askForFile) + { + saveLogSingleFile.InitialDirectory = Project.ProjectFileName; + if (saveLogSingleFile.ShowDialog() == DialogResult.OK && saveLogSingleFile.FileName != "") + return saveLogSingleFile.FileName; + } + else + { + chooseLogFolder.SelectedPath = Path.GetDirectoryName(Project.ProjectFileName); + if (chooseLogFolder.ShowDialog() == DialogResult.OK && chooseLogFolder.SelectedPath != "") + return saveLogSingleFile.FileName; + } + + return null; + } + + private bool PromptForPath() + { + var singleFile = settings.structure == LogCreator.FormatStructure.SingleFile; + var path = PromptForLogPathFromFileOrFolderDialog(singleFile); + + if (string.IsNullOrEmpty(path)) + return false; + + // kinda weird. we should probably just pass + // the containing folder name and let LogCreator handle these details + if (!singleFile) + path += "/main.asm"; + + settings.file = path; + settings.error = Path.GetDirectoryName(path) + "/error.txt"; + + return true; + } + private void textFormat_TextChanged(object sender, EventArgs e) { if (ValidateFormat()) { - LogCreator.format = textFormat.Text.ToLower(); - UpdateSample(); + settings.format = textFormat.Text.ToLower(); + RegenerateSampleOutput(); button2.Enabled = true; - } else - { + } else { textSample.Text = "Invalid format!"; button2.Enabled = false; } @@ -55,233 +114,62 @@ private void textFormat_TextChanged(object sender, EventArgs e) private void numData_ValueChanged(object sender, EventArgs e) { - LogCreator.dataPerLine = (int)numData.Value; - UpdateSample(); + settings.dataPerLine = (int)numData.Value; + RegenerateSampleOutput(); } private void comboUnlabeled_SelectedIndexChanged(object sender, EventArgs e) { - LogCreator.unlabeled = (LogCreator.FormatUnlabeled)comboUnlabeled.SelectedIndex; - UpdateSample(); + settings.unlabeled = (LogCreator.FormatUnlabeled)comboUnlabeled.SelectedIndex; + RegenerateSampleOutput(); } private void comboStructure_SelectedIndexChanged(object sender, EventArgs e) { - LogCreator.structure = (LogCreator.FormatStructure)comboStructure.SelectedIndex; + settings.structure = (LogCreator.FormatStructure)comboStructure.SelectedIndex; } private bool ValidateFormat() { - string[] tokens = textFormat.Text.ToLower().Split('%'); - - // not valid if format has an odd amount of %s - if (tokens.Length % 2 == 0) return false; - - for (int i = 1; i < tokens.Length; i += 2) - { - int indexOfColon = tokens[i].IndexOf(':'); - string kind = indexOfColon >= 0 ? tokens[i].Substring(0, indexOfColon) : tokens[i]; - - // not valid if base token isn't one we know of - if (!LogCreator.parameters.ContainsKey(kind)) return false; - - // not valid if parameter isn't an integer - int oof; - if (indexOfColon >= 0 && !int.TryParse(tokens[i].Substring(indexOfColon + 1), out oof)) return false; - } - - return true; + return LogCreator.ValidateFormat(textFormat.Text); } - // https://stackoverflow.com/a/29679597 - private void UpdateSample() + private void RegenerateSampleOutput() { - // TODO: since we don't have to do this as a singleton now, we can - // replace all this save/restore stuff and just create a new Project() or Data() and populate it - - // cheeky way of using the same methods for disassembling a different set of data :^) - while (sampleTable.Count < 0x8000) - sampleTable.Add(new ROMByte()); - - using (MemoryStream mem = new MemoryStream()) - using (StreamWriter sw = new StreamWriter(mem)) - { - var tempTable = Data.GetTable(); - Data.ROMMapMode tempMode = Data.RomMapMode; - Data.ROMSpeed tempSpeed = Data.GetROMSpeed(); - var tempAlias = Data.GetAllLabels(); - var tempComment = Data.GetAllComments(); - LogCreator.FormatStructure tempStructure = LogCreator.structure; - Data.Restore(sampleTable, Data.ROMMapMode.LoROM, Data.ROMSpeed.FastROM, sampleAlias, sampleComment); - LogCreator.structure = LogCreator.FormatStructure.SingleFile; - - LogCreator.CreateLog(sw, StreamWriter.Null); - - Data.Restore(tempTable, tempMode, tempSpeed, tempAlias, tempComment); - LogCreator.structure = tempStructure; - - sw.Flush(); - mem.Seek(0, SeekOrigin.Begin); - - textSample.Text = Encoding.UTF8.GetString(mem.ToArray(), 0, (int)mem.Length); - } + textSample.Text = CreateSampleOutput(); } - // random sample code I made up; hopefully it shows a little bit of - // everything so you can see how the settings will effect the output - public static RomBytes sampleTable = new RomBytes - { - new ROMByte {Rom = 0x78, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true, Point = Data.InOutPoint.InPoint}, - new ROMByte {Rom = 0xA9, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true}, - new ROMByte {Rom = 0x01, TypeFlag = Data.FlagType.Operand}, - new ROMByte {Rom = 0x8D, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true}, - new ROMByte {Rom = 0x0D, TypeFlag = Data.FlagType.Operand}, - new ROMByte {Rom = 0x42, TypeFlag = Data.FlagType.Operand}, - new ROMByte {Rom = 0x5C, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true, Point = Data.InOutPoint.EndPoint}, - new ROMByte {Rom = 0x0A, TypeFlag = Data.FlagType.Operand}, - new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand}, - new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand}, - new ROMByte {Rom = 0xC2, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true, Point = Data.InOutPoint.InPoint}, - new ROMByte {Rom = 0x30, TypeFlag = Data.FlagType.Operand}, - new ROMByte {Rom = 0xA9, TypeFlag = Data.FlagType.Opcode}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand}, - new ROMByte {Rom = 0x21, TypeFlag = Data.FlagType.Operand}, - new ROMByte {Rom = 0x5B, TypeFlag = Data.FlagType.Opcode}, - new ROMByte {Rom = 0x4B, TypeFlag = Data.FlagType.Opcode, DirectPage = 0x2100}, - new ROMByte {Rom = 0xAB, TypeFlag = Data.FlagType.Opcode, DirectPage = 0x2100}, - new ROMByte {Rom = 0xA2, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x07, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xBF, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x32, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x9F, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x7E, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xCA, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xCA, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x10, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xF4, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x64, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x40, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x64, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x41, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x64, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x42, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x64, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x43, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xAE, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xFC, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x3A, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x4C, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.EndPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xC0, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Data16Bit, Point = Data.InOutPoint.ReadPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x08, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x10, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x20, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x44, TypeFlag = Data.FlagType.Pointer16Bit, Point = Data.InOutPoint.ReadPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x7B, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x44, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x81, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xC4, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x81, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x0A, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x82, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x08, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x8B, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x4B, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xAB, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xE2, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x20, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xC2, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x10, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xA2, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x1F, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xBD, TypeFlag = Data.FlagType.Opcode, MFlag = true, Point = Data.InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x5B, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x9D, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x01, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xCA, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x10, TypeFlag = Data.FlagType.Opcode, MFlag = true, Point = Data.InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xF7, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xAB, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x28, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x60, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.EndPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x45, TypeFlag = Data.FlagType.Data8Bit, Point = Data.InOutPoint.ReadPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x8D, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x69, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x83, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xB2, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x99, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x23, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x01, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xA3, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xF8, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x52, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x08, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xBB, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x29, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x5C, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x32, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xE7, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x88, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x3C, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x30, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x18, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x9A, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xB0, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x34, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x8C, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xDD, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x05, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xB7, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x83, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x34, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x6D, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - }; - - public static Dictionary sampleAlias = new Dictionary - { - { 0x00, new Label() {name="Emulation_RESET", comment="Sample emulation reset location"} }, - { 0x0A, new Label() {name="FastRESET", comment="Sample label" } }, - { 0x32, new Label() {name="Test_Indices"} }, - { 0x3A, new Label() {name="Pointer_Table"} }, - { 0x44, new Label() {name="First_Routine"} }, - { 0x5B, new Label() {name="Test_Data", comment="Pretty cool huh?" } } - }; - - public static Dictionary sampleComment = new Dictionary - { - { 0x03, "this sets FastROM" }, - { 0x0F, "direct page = $2100" }, - { 0x21, "clear APU regs" }, - { 0x44, "this routine copies Test_Data to $7E0100" } - }; - private void chkPrintLabelSpecificComments_CheckedChanged(object sender, EventArgs e) { - LogCreator.printLabelSpecificComments = chkPrintLabelSpecificComments.Checked; + settings.printLabelSpecificComments = chkPrintLabelSpecificComments.Checked; } private void chkIncludeUnusedLabels_CheckedChanged(object sender, EventArgs e) { - LogCreator.includeUnusedLabels = chkIncludeUnusedLabels.Checked; + settings.includeUnusedLabels = chkIncludeUnusedLabels.Checked; + } + private string CreateSampleOutput() + { + using var mem = new MemoryStream(); + using var sw = new StreamWriter(mem); + + // make a copy, but override the FormatStructure so it's all in one file + var sampleSettings = settings; + sampleSettings.structure = LogCreator.FormatStructure.SingleFile; + + var lc = new LogCreator() + { + Settings = sampleSettings, + Data = SampleRomData.SampleData, + StreamOutput = sw, + StreamError = StreamWriter.Null, + }; + + lc.CreateLog(); + + sw.Flush(); + mem.Seek(0, SeekOrigin.Begin); + return Encoding.UTF8.GetString(mem.ToArray(), 0, (int)mem.Length); } } } diff --git a/DiztinGUIsh/window/dialog/ExportDisassembly.resx b/DiztinGUIsh/window/dialog/ExportDisassembly.resx index 5294a816..aa574a0f 100644 --- a/DiztinGUIsh/window/dialog/ExportDisassembly.resx +++ b/DiztinGUIsh/window/dialog/ExportDisassembly.resx @@ -124,4 +124,10 @@ the instruction misalignment checker and the in/out point scanner before exporting. See the help document for more details. + + 41, 29 + + + 201, 26 + \ No newline at end of file From cc956eae59aeebc95ff9d647f77e1e03cf00d5bb Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 27 Sep 2020 22:42:41 -0400 Subject: [PATCH 041/136] finished out features refactoring, now testing. - save as doesnt work - need to test hell out of exporter --- DiztinGUIsh/loadsave/ProjectSerializer.cs | 2 +- .../xml_serializer/ProjectXMLSerializer.cs | 2 +- DiztinGUIsh/static/Data.cs | 73 ++++------ DiztinGUIsh/static/Label.cs | 16 ++- DiztinGUIsh/static/LogCreator.cs | 133 +++++++++++------- DiztinGUIsh/static/Project.cs | 3 + DiztinGUIsh/static/SampleRomData.cs | 4 +- DiztinGUIsh/window/MainWindow.cs | 6 +- .../window/dialog/ExportDisassembly.cs | 2 + 9 files changed, 138 insertions(+), 103 deletions(-) diff --git a/DiztinGUIsh/loadsave/ProjectSerializer.cs b/DiztinGUIsh/loadsave/ProjectSerializer.cs index e09a6271..9861871a 100644 --- a/DiztinGUIsh/loadsave/ProjectSerializer.cs +++ b/DiztinGUIsh/loadsave/ProjectSerializer.cs @@ -25,7 +25,7 @@ public Project LoadFromFile(string filename) return Load(File.ReadAllBytes(filename)); } - private void DebugVerifyProjectEquality(Project project1, Project project2, bool deepcut = true) + protected static void DebugVerifyProjectEquality(Project project1, Project project2, bool deepcut = true) { if (deepcut) { diff --git a/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs b/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs index 12aa87fd..60151954 100644 --- a/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs +++ b/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs @@ -72,7 +72,7 @@ public override byte[] Save(Project project) var final_bytes = Encoding.UTF8.GetBytes(xml_str); // if you want some sanity checking, run this to verify everything saved correctly - // DebugVerifyProjectEquality(OpenProjectXml(file), project); + DebugVerifyProjectEquality(project, Load(final_bytes)); return final_bytes; } diff --git a/DiztinGUIsh/static/Data.cs b/DiztinGUIsh/static/Data.cs index 15cdc596..04b6b55f 100644 --- a/DiztinGUIsh/static/Data.cs +++ b/DiztinGUIsh/static/Data.cs @@ -13,6 +13,20 @@ namespace DiztinGUIsh { public class Data { + // Note: order of these properties matters for the load/save process. Keep 'RomBytes' LAST + public ROMMapMode RomMapMode { get; set; } + public ROMSpeed RomSpeed { get; set; } + public Dictionary Comments { get; set; } + public Dictionary Labels { get; set; } + public RomBytes RomBytes { get; set; } + + private CPU65C816 CPU65C816 { get; set; } + + public Data() + { + CPU65C816 = new CPU65C816(this); + } + public enum FlagType : byte { Unreached = 0x00, @@ -75,20 +89,13 @@ public const int EXHIROM_SETTING_OFFSET = 0x40FFD5, EXLOROM_SETTING_OFFSET = 0x407FD5; - // Note: order of these properties matters for the load/save process. Keep 'RomBytes' LAST - public ROMMapMode RomMapMode { get; set; } - public ROMSpeed RomSpeed { get; set; } - public Dictionary Comments { get; set; } - public RomBytes RomBytes { get; set; } - - public Dictionary alias; public void Initiate(byte[] data, ROMMapMode mode, ROMSpeed speed) { RomMapMode = mode; RomSpeed = speed; int size = data.Length; - alias = new Dictionary(); + Labels = new Dictionary(); Comments = new Dictionary(); RomBytes = new RomBytes(); for (int i = 0; i < size; i++) @@ -137,15 +144,6 @@ public void CopyRomDataIn(byte[] data) } } - public void Restore(RomBytes l = null, ROMMapMode m = ROMMapMode.LoROM, ROMSpeed s = ROMSpeed.Unknown, Dictionary a = null, Dictionary c = null) - { - RomBytes = l ?? RomBytes; - RomMapMode = s == ROMSpeed.Unknown ? RomMapMode : m; - RomSpeed = s == ROMSpeed.Unknown ? RomSpeed : s; - alias = a ?? alias; - Comments = c ?? Comments; - } - public ROMMapMode GetROMMapMode() { return RomMapMode; @@ -259,14 +257,14 @@ public void SetMXFlags(int i, int mx) public string GetLabelName(int i) { - if (alias.TryGetValue(i, out var val)) + if (Labels.TryGetValue(i, out var val)) return val?.name ?? ""; return ""; } public string GetLabelComment(int i) { - if (alias.TryGetValue(i, out var val)) + if (Labels.TryGetValue(i, out var val)) return val?.comment ?? ""; return ""; @@ -274,38 +272,38 @@ public string GetLabelComment(int i) public void DeleteAllLabels() { - alias.Clear(); + Labels.Clear(); } public void AddLabel(int i, Label v, bool overwrite) { if (v == null) { - if (alias.ContainsKey(i)) + if (Labels.ContainsKey(i)) { - alias.Remove(i); + Labels.Remove(i); // TODO: notify observers AliasList.me.RemoveRow(i); } } else { - if (alias.ContainsKey(i) && overwrite) + if (Labels.ContainsKey(i) && overwrite) { - alias.Remove(i); + Labels.Remove(i); // // TODO: notify observers AliasList.me.RemoveRow(i); } - if (alias.ContainsKey(i)) + if (Labels.ContainsKey(i)) return; v.CleanUp(); - alias.Add(i, v); + Labels.Add(i, v); // // TODO: notify observers AliasList.me.AddRow(i, v); } } public Dictionary GetAllLabels() { - return alias; + return Labels; } public string GetComment(int i) @@ -453,7 +451,8 @@ public string GetPointer(int offset, int bytes) break; case 4: ia = GetROMLong(offset); - format = "dl {0}" + string.Format(" : db {0}", Util.NumberToBaseString(GetROMByte(offset + 3), Util.NumberBase.Hexadecimal, 2, true)); + format = "dl {0}" + + $" : db {Util.NumberToBaseString(GetROMByte(offset + 3), Util.NumberBase.Hexadecimal, 2, true)}"; param = Util.NumberToBaseString(GetROMLong(offset), Util.NumberBase.Hexadecimal, 6, true); break; } @@ -477,18 +476,6 @@ public string GetDefaultLabel(int address) $"{Util.TypeToLabel(GetFlag(pc))}_{Util.NumberToBaseString(address, Util.NumberBase.Hexadecimal, 6)}"; } - - //private Project Project { get; set; } - - //private Data Data => Project.Data; - private CPU65C816 CPU65C816 { get; set; } - - public Data() - { - // Project = project; - CPU65C816 = new CPU65C816(this); - } - public int Step(int offset, bool branch, bool force, int prevOffset) { switch (GetArchitechture(offset)) @@ -799,6 +786,7 @@ public string GetInstruction(int offset) // we calculate it once from sample data and hang onto it private class CachedTraceLineIndex { + // NOTE: newer versions of BSNES use different text for flags. check for completeness. private string sample = "028cde rep #$30 A:0004 X:0000 Y:0004 S:1fdd D:0000 DB:02 nvmxdiZC V:133 H: 654 F:36"; @@ -925,10 +913,9 @@ public void ImportBizHawkCDL(BizHawkCdl cdl) } } #region Equality - protected bool Equals(Data other) { - return alias.SequenceEqual(other.alias) && RomMapMode == other.RomMapMode && RomSpeed == other.RomSpeed && Comments.SequenceEqual(other.Comments) && RomBytes.Equals(other.RomBytes); + return Labels.SequenceEqual(other.Labels) && RomMapMode == other.RomMapMode && RomSpeed == other.RomSpeed && Comments.SequenceEqual(other.Comments) && RomBytes.Equals(other.RomBytes); } public override bool Equals(object obj) @@ -943,7 +930,7 @@ public override int GetHashCode() { unchecked { - var hashCode = alias.GetHashCode(); + var hashCode = Labels.GetHashCode(); hashCode = (hashCode * 397) ^ (int)RomMapMode; hashCode = (hashCode * 397) ^ (int)RomSpeed; hashCode = (hashCode * 397) ^ Comments.GetHashCode(); diff --git a/DiztinGUIsh/static/Label.cs b/DiztinGUIsh/static/Label.cs index 9772f560..9099944b 100644 --- a/DiztinGUIsh/static/Label.cs +++ b/DiztinGUIsh/static/Label.cs @@ -6,14 +6,26 @@ namespace DiztinGUIsh { + // represent a label at a particular address + // NOTE: you can have labels at addresses in: + // 1) ROM (they will show up in the main table view) + // 2) anything else, like RAM (they will only show up in the label editor, not in the main table) + // + // Comments here are for the LABEL itself, and not so much about where they're used. + // i.e. a label for 0x7E0020 might store a character's HP in RAM. It would look like: + // - address: 0x7E0020 (0x7EXXXX means it's a RAM address) + // - label: "character_3_hp" + // - comment: "this address is only used in RAM during battle sequences" + // ^^^^---- will not show up in the main table, just the editor + public class Label { public string name = ""; // name of the label public string comment = ""; // user-generated text, comment only public void CleanUp() { - if (comment == null) comment = ""; - if (name == null) name = ""; + comment ??= ""; + name ??= ""; } #region Equality diff --git a/DiztinGUIsh/static/LogCreator.cs b/DiztinGUIsh/static/LogCreator.cs index 8a02c941..011a9e17 100644 --- a/DiztinGUIsh/static/LogCreator.cs +++ b/DiztinGUIsh/static/LogCreator.cs @@ -83,6 +83,7 @@ private static Dictionary> Parameters } } + private Dictionary ExtraLabels { get; set; } = new Dictionary(); private List> parseList; private List usedLabels; private int errorCount, bankSize; @@ -140,14 +141,12 @@ public string GetParameter(int offset, string parameter, int length) public OutputResult CreateLog() { - // var aliases = Data.GetAllLabels(); // junk - // Data.Restore(a: new Dictionary(aliases)); // junk - // AliasList.me.locked = true; // notify observers. do this outside this class. - bankSize = Util.GetBankSize(Data.RomMapMode); errorCount = 0; - GenerateGenericLabels(); + AddLabelSource(Data.Labels); + AddLabelSource(ExtraLabels); + GenerateAdditionalExtraLabels(); usedLabels = new List(); @@ -162,7 +161,7 @@ public OutputResult CreateLog() ProgressBarJob.Loop(size, () => { if (pointer >= size) - return -1; // stop looping + return -1; // means "stop looping" WriteAddress(ref pointer, ref bank); @@ -174,7 +173,6 @@ public OutputResult CreateLog() if (Settings.structure == FormatStructure.OneBankPerFile) StreamOutput.Close(); - // // TODO: notify observers AliasList.me.locked = false; return new OutputResult() { error_count = errorCount, @@ -204,67 +202,97 @@ private int WriteMainIncludes(int size) return pointer; } - // TODO: These are labels like "CODE_856469" and "DATA_763525". - // ISSUE: the original code just modified Data, but, we can't do that anymore. - // Either we need to copy all of it, or, we need another list of labels and use that. - private void GenerateGenericLabels() + private List> LabelSources { get; set; } = new List>(); + + public void AddLabelSource(Dictionary labelSource) { - var addressList = new List(); - var pointer = 0; + LabelSources.Add(labelSource); + } - while (pointer < Data.GetROMSize()) + public string GetLabelName(int i) + { + foreach (var labelDict in LabelSources) { - var addr = GetLabelTargetAddress(pointer, out var length); - pointer += length; - - if (addr != -1) - addressList.Add(addr); + if (labelDict.TryGetValue(i, out var val)) + return val?.name ?? ""; } - // TODO: +/- labels - foreach (var t in addressList) + return ""; + } + public string GetLabelComment(int i) + { + foreach (var labelDict in LabelSources) { - var label = new Label() - { - name = Data.GetDefaultLabel(t) - }; - - throw new NotImplementedException("see note above, not implemented yet."); - // if we were just going to add them we could do this: - // Data.AddLabel(t, label, false); + if (labelDict.TryGetValue(i, out var val)) + return val?.comment ?? ""; } + + return ""; } - private int GetLabelTargetAddress(int pointer, out int length) + // NOTE: we should refactor this and the stuff in Data to make a new class called + // LabelCollection or similar. + public void AddExtraLabel(int i, Label v) { - length = GetLineByteLength(pointer); + Debug.Assert(v != null); + if (ExtraLabels.ContainsKey(i)) + return; - var flag = Data.GetFlag(pointer); + v.CleanUp(); + + ExtraLabels.Add(i, v); + } - bool c1 = Settings.unlabeled == LogCreator.FormatUnlabeled.ShowAll; - bool c2 = Settings.unlabeled != LogCreator.FormatUnlabeled.ShowNone && - (flag == Data.FlagType.Opcode || flag == Data.FlagType.Pointer16Bit || - flag == Data.FlagType.Pointer24Bit || flag == Data.FlagType.Pointer32Bit); - if (c1) + // Generate labels like "CODE_856469" and "DATA_763525" + // These will be combined with the original labels to produce our final assembly + // These labels exist only for the duration of this export, and then are discarded. + // + // TODO: generate some nice looking "+"/"-" labels here. + private void GenerateAdditionalExtraLabels() + { + for (var pointer = 0; pointer < Data.GetROMSize();) { - return Data.ConvertPCtoSNES(pointer); + var offset = GetAddressOfAnyUsefulLabelsAt(pointer, out var length); + pointer += length; + + if (offset == -1) + continue; + + AddExtraLabel(offset, new Label() { + name = Data.GetDefaultLabel(offset) + }); } - else if (c2) - { - var ia = Data.GetIntermediateAddressOrPointer(pointer); + } - if (ia >= 0 && Data.ConvertSNEStoPC(ia) >= 0) - return ia; + private int GetAddressOfAnyUsefulLabelsAt(int pointer, out int length) + { + length = GetLineByteLength(pointer); + switch (Settings.unlabeled) + { + case FormatUnlabeled.ShowNone: + return -1; + case FormatUnlabeled.ShowAll: + return Data.ConvertPCtoSNES(pointer); } + var flag = Data.GetFlag(pointer); + var usefulToCreateLabelFrom = + flag == Data.FlagType.Opcode || flag == Data.FlagType.Pointer16Bit || + flag == Data.FlagType.Pointer24Bit || flag == Data.FlagType.Pointer32Bit; + + if (!usefulToCreateLabelFrom) + return -1; + + var ia = Data.GetIntermediateAddressOrPointer(pointer); + if (ia >= 0 && Data.ConvertSNEStoPC(ia) >= 0) + return ia; + return -1; } private void SetupParseList() { - // TODO: this is probably not correct now, check - string[] split = Settings.format.Split('%'); parseList = new List>(); for (int i = 0; i < split.Length; i++) @@ -418,12 +446,11 @@ private int GetLineByteLength(int offset) { int max = 1, step = 1; var size = Data.GetROMSize(); - var data = Data; - switch (data.GetFlag(offset)) + switch (Data.GetFlag(offset)) { case Data.FlagType.Opcode: - return data.OpcodeByteLength(offset); + return Data.OpcodeByteLength(offset); case Data.FlagType.Unreached: case Data.FlagType.Operand: case Data.FlagType.Data8Bit: @@ -465,8 +492,8 @@ private int GetLineByteLength(int offset) while ( min < max && offset + min < size && - data.GetFlag(offset + min) == data.GetFlag(offset) && - data.GetLabelName(data.ConvertPCtoSNES(offset + min)) == "" && + Data.GetFlag(offset + min) == Data.GetFlag(offset) && + GetLabelName(Data.ConvertPCtoSNES(offset + min)) == "" && (offset + min) / bankSize == myBank ) min += step; return min; @@ -517,7 +544,7 @@ private static string GetEmpty(int offset, int length) private string GetLabel(int offset, int length) { var snes = Data.ConvertPCtoSNES(offset); - var label = Data.GetLabelName(snes); + var label = GetLabelName(snes); if (label == null) return ""; @@ -696,9 +723,9 @@ private string GetXFlag(int offset, int length) [AssemblerHandler(token = "%labelassign", weight = 1)] private string GetLabelAssign(int offset, int length) { - var labelName = Data.GetLabelName(offset); + var labelName = GetLabelName(offset); var offsetStr = Util.NumberToBaseString(offset, Util.NumberBase.Hexadecimal, 6, true); - var labelComment = Data.GetLabelComment(offset); + var labelComment = GetLabelComment(offset); if (string.IsNullOrEmpty(labelName)) return ""; diff --git a/DiztinGUIsh/static/Project.cs b/DiztinGUIsh/static/Project.cs index 8c555a1c..98318b32 100644 --- a/DiztinGUIsh/static/Project.cs +++ b/DiztinGUIsh/static/Project.cs @@ -1,6 +1,7 @@ using DiztinGUIsh.window; using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Windows.Forms; using ExtendedXmlSerializer; @@ -167,6 +168,8 @@ public bool PostSerializationLoad() // So now, with all our metadata loaded successfully, we now open the .smc file on disk // and marry the original rom's bytes with all of our metadata loaded from the project file. + Debug.Assert(Data.RomBytes != null && Data.Labels != null && Data.Comments != null); + var rom = ReadFromOriginalRom(); if (rom == null) return false; diff --git a/DiztinGUIsh/static/SampleRomData.cs b/DiztinGUIsh/static/SampleRomData.cs index 12490378..edbbabc7 100644 --- a/DiztinGUIsh/static/SampleRomData.cs +++ b/DiztinGUIsh/static/SampleRomData.cs @@ -18,7 +18,7 @@ class SampleRomData : Data { // random sample code I made up; hopefully it shows a little bit of // everything so you can see how the settings will effect the output - RomBytes = { + RomBytes = new RomBytes { new ROMByte {Rom = 0x78, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true, Point = Data.InOutPoint.InPoint}, new ROMByte {Rom = 0xA9, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true}, new ROMByte {Rom = 0x01, TypeFlag = Data.FlagType.Operand}, @@ -150,7 +150,7 @@ class SampleRomData : Data {0x21, "clear APU regs"}, {0x44, "this routine copies Test_Data to $7E0100"} }, - alias = new Dictionary + Labels = new Dictionary { {0x00, new Label() {name = "Emulation_RESET", comment = "Sample emulation reset location"}}, {0x0A, new Label() {name = "FastRESET", comment = "Sample label"}}, diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 250dd18a..1f89d5d0 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -16,6 +16,10 @@ public partial class MainWindow : Form, IProjectView public MainWindow() { + ProjectController = new ProjectController + { + ProjectView = this + }; InitializeComponent(); } @@ -275,7 +279,7 @@ private void importCDLToolStripMenuItem_Click(object sender, EventArgs e) } } - private readonly ProjectController ProjectController = new ProjectController(); + private readonly ProjectController ProjectController; private void exportLogToolStripMenuItem_Click(object sender, EventArgs e) { diff --git a/DiztinGUIsh/window/dialog/ExportDisassembly.cs b/DiztinGUIsh/window/dialog/ExportDisassembly.cs index bc0a2bd0..88d87acc 100644 --- a/DiztinGUIsh/window/dialog/ExportDisassembly.cs +++ b/DiztinGUIsh/window/dialog/ExportDisassembly.cs @@ -157,6 +157,8 @@ private string CreateSampleOutput() var sampleSettings = settings; sampleSettings.structure = LogCreator.FormatStructure.SingleFile; + Data sampleData = SampleRomData.SampleData; + var lc = new LogCreator() { Settings = sampleSettings, From cbeb6a8263c805e08933a262f0af74da9cd80c41 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 27 Sep 2020 22:48:26 -0400 Subject: [PATCH 042/136] fix save as using wrong filename --- DiztinGUIsh/static/ProjectController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiztinGUIsh/static/ProjectController.cs b/DiztinGUIsh/static/ProjectController.cs index 6752abc0..382b4517 100644 --- a/DiztinGUIsh/static/ProjectController.cs +++ b/DiztinGUIsh/static/ProjectController.cs @@ -35,7 +35,7 @@ private void OnProjectOpened(string filename, Project project) public void SaveProject(string projectProjectFileName) { - ProjectFileManager.Save(Project, Project.ProjectFileName); + ProjectFileManager.Save(Project, projectProjectFileName); ProjectView.OnProjectSaved(); } From 300ac171102d0bc9d6298872147a99aa0fc9017b Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Mon, 28 Sep 2020 18:52:19 -0400 Subject: [PATCH 043/136] add GitInfo package for version info change icon to purple since it's a bigger release fix sample data by adding back in the 0x8000 bytes add longrunning task handler for easily showing progress bars from controller add progress bar dialogue "marquee mode" spinner upgrade to latet .NET framework 4.8 version --- DiztinGUIsh/App.config | 16 +- DiztinGUIsh/DiztinGUIsh.csproj | 46 +- DiztinGUIsh/ProgressBarWorker.cs | 20 +- DiztinGUIsh/Properties/AssemblyInfo.cs | 19 +- DiztinGUIsh/Resources/diz-4.ico | Bin 0 -> 4286 bytes DiztinGUIsh/Resources/diz-4.png | Bin 0 -> 51202 bytes DiztinGUIsh/diz-4.ico | Bin 0 -> 4286 bytes DiztinGUIsh/packages.config | 21 +- DiztinGUIsh/static/Data.cs | 9 +- DiztinGUIsh/static/IProjectView.cs | 3 + DiztinGUIsh/static/LogCreator.cs | 77 +- DiztinGUIsh/static/ProjectController.cs | 30 +- DiztinGUIsh/static/SampleRomData.cs | 24 +- DiztinGUIsh/window/MainWindow.cs | 3 + DiztinGUIsh/window/MainWindow.resx | 3770 +---------------- .../window/dialog/ExportDisassembly.cs | 1 - .../window/dialog/ProgressDialog.Designer.cs | 16 +- DiztinGUIsh/window/dialog/ProgressDialog.cs | 26 +- tmp.txt | 2566 +++++++++++ 19 files changed, 2874 insertions(+), 3773 deletions(-) create mode 100644 DiztinGUIsh/Resources/diz-4.ico create mode 100644 DiztinGUIsh/Resources/diz-4.png create mode 100644 DiztinGUIsh/diz-4.ico create mode 100644 tmp.txt diff --git a/DiztinGUIsh/App.config b/DiztinGUIsh/App.config index 8947d701..1b9f114e 100644 --- a/DiztinGUIsh/App.config +++ b/DiztinGUIsh/App.config @@ -1,17 +1,17 @@ - + -
+
- + - + True @@ -21,8 +21,12 @@ - - + + + + + + diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index f3e3a12a..bd556879 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -28,6 +28,8 @@ 1.0.0.%2a false true + + AnyCPU @@ -51,47 +53,47 @@ 8.0 - resource\diz.ico + diz-4.ico DiztinGUIsh.Program - - ..\packages\ExtendedXmlSerializer.3.2.7\lib\net452\ExtendedXmlSerializer.dll + + ..\packages\ExtendedXmlSerializer.3.3.0\lib\net452\ExtendedXmlSerializer.dll - - ..\packages\LightInject.6.2.0\lib\net46\LightInject.dll + + ..\packages\LightInject.6.3.5\lib\net46\LightInject.dll - ..\packages\NReco.LambdaParser.1.0.11\lib\net45\NReco.LambdaParser.dll + ..\packages\NReco.LambdaParser.1.0.12\lib\net45\NReco.LambdaParser.dll - - ..\packages\Sprache.2.2.0\lib\net45\Sprache.dll + + ..\packages\Sprache.2.3.1\lib\net45\Sprache.dll - - ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll + + ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll - ..\packages\System.Collections.Immutable.1.7.0\lib\netstandard2.0\System.Collections.Immutable.dll + ..\packages\System.Collections.Immutable.1.7.1\lib\net461\System.Collections.Immutable.dll - - ..\packages\System.Interactive.4.0.0\lib\net45\System.Interactive.dll + + ..\packages\System.Interactive.4.1.1\lib\net45\System.Interactive.dll - ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll + ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll - - ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll - ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\net461\System.Runtime.CompilerServices.Unsafe.dll @@ -256,6 +258,9 @@ + + + @@ -272,4 +277,11 @@ + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + \ No newline at end of file diff --git a/DiztinGUIsh/ProgressBarWorker.cs b/DiztinGUIsh/ProgressBarWorker.cs index 2a2854de..74cd2adc 100644 --- a/DiztinGUIsh/ProgressBarWorker.cs +++ b/DiztinGUIsh/ProgressBarWorker.cs @@ -9,6 +9,8 @@ public abstract class ProgressBarWorker private ProgressDialog Dialog = null; private bool IsRunning = false; private Thread backgroundThread = null; + public bool IsMarquee { get; set; } = false; + public string TextOverride { get; set; } = null; protected void UpdateProgress(int i) { @@ -39,7 +41,7 @@ protected virtual void Setup() IsRunning = true; - Dialog = new ProgressDialog(); + Dialog = new ProgressDialog(IsMarquee, TextOverride); // setup, but don't start, the new thread backgroundThread = new Thread(new ThreadStart(Thread_Main)); @@ -85,21 +87,35 @@ namespace DiztinGUIsh { public class ProgressBarJob : ProgressBarWorker { - public static void Loop(long maxProgress, NextAction callback) + // a version that keeps calling 'callback' until it returns -1 + public static void Loop(long maxProgress, NextAction callback, string overrideTxt = null) { var j = new ProgressBarJob() { MaxProgress = maxProgress, Callback = callback, + IsMarquee = maxProgress == -1, + TextOverride = overrideTxt, }; j.Run(); } + // a version that calls action once and exits + // shows a "marquee" i.e. spinner + public static void RunAndWaitForCompletion(Action action, string overrideTxt = null) + { + Loop(-1, () => { + action(); + return -1; + }, overrideTxt); + } + public NextAction Callback { get; set; } public long MaxProgress { get; set; } protected override void Thread_DoWork() { + UpdateProgress(0); var progress = -1L; do { progress = Callback(); diff --git a/DiztinGUIsh/Properties/AssemblyInfo.cs b/DiztinGUIsh/Properties/AssemblyInfo.cs index 31234e5f..f43946cd 100644 --- a/DiztinGUIsh/Properties/AssemblyInfo.cs +++ b/DiztinGUIsh/Properties/AssemblyInfo.cs @@ -1,6 +1,6 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Windows.Forms; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information @@ -10,10 +10,21 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Written by Alex \"Dotsarecool\" Losego")] [assembly: AssemblyProduct("DiztinGUIsh")] -[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyCopyright("Copyright © 2020")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] +[assembly: AssemblyVersion( + ThisAssembly.Git.SemVer.Major + "." + + ThisAssembly.Git.SemVer.Minor + "." + + ThisAssembly.Git.SemVer.Patch)] +[assembly: AssemblyInformationalVersion( + ThisAssembly.Git.SemVer.Major + "." + + ThisAssembly.Git.SemVer.Minor + "." + + ThisAssembly.Git.SemVer.Patch + "-" + + ThisAssembly.Git.Branch + "+" + + ThisAssembly.Git.Commit)] + // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. @@ -32,5 +43,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.1.6")] -[assembly: AssemblyFileVersion("1.0.1.6")] +// [assembly: AssemblyVersion("1.0.1.6")] +// [assembly: AssemblyFileVersion("1.0.1.6")] diff --git a/DiztinGUIsh/Resources/diz-4.ico b/DiztinGUIsh/Resources/diz-4.ico new file mode 100644 index 0000000000000000000000000000000000000000..e9c5163edb20fb449165db8f9d752129ccb986f8 GIT binary patch literal 4286 zcmd5g6p=$S*_Mu@3pnAZR}d6}AViYUSHfU2_C3Gow*a}r9A5|m{tqsD`_HJbw4kz}8CR@LD6?L} zB}*MjEjE;xt5IyO#QFR(oXfw6qP$`h=3PKR-g#Ja&yp3voLfj%fczW_@^Z|`&vjT{ zZay5Ahn$>ToH=ub?m0Ml@+4YYTYvSu%5n=c1S8}^Fr-2dTm^5q2r>wQh)i&5B9Y@ac9zGN zt?)M9RDX?yrej!O$i^FnLu6lIzTqHdX!l@Q=M$J6`UwUHzKMPTuc5o|cy#t229sw$ z=;b}2^@xT_7KT8n9zJd==#^p6DNN8R3{VAVpbXT&+tUXkkr)z*grAGW;qg_&@Ri?S ziRl|GGJJ)_#&59H_+Km!&A~gmT+toOW*koV0m;U*cwLu?7w8Pn`M!cKUN6EV?~f2!cc`UNP)Iw$%S8p1 zzX7*y-a=JXHHHovftSZmLUdGDj_c~`>IAVZsQ_uFi`dlDhP{&;ICjOi zcTnmvX=R_ltAj ziX{-ah#?k>pTe&#yo2Sz1xN`mBEL(prEd+gW;No}rWV-D_i(5A5!%U0vfJ=6eJ$&8N@RkLkq5c{!oc|soI*(K$erXs&pGoE#kwYFM}8#~?+1Ig3% z&+u1iE@DGe1=fX^<9+gf=g_NI+nJr|GQLP?Le|V{yccKb{)w^5H5eT5HhTL`1ykZrG1}?^+fCW7FJ$xqo9$yvq8)Z^*gSiVOqR^!DW@;zW7k9}|7 zX<+y){*UWl+kyYse``MJV!q`G|6QKp|9vC|pT$zsx0s{LBK+N$q~1(D_AbUN*HgW% zCErspij4Um=RX&HI`E^t9r|$4}Sn!BovIOjK{e z9Q{5_)9xbt)ff@DjN+fbd%uUzL>~VL(xIpEJ@_n;o0He!Kf`DFf4cta&)JcxyG;CV z#UkSgyb*Gk&afYILNYN^m5GgUmyzDniiwJ?6pM5W4Om3=H~Z=O>!^Q6{M}(S7yMd( zZmv>}@2vkC&fBpzv=ZqNrC34r&$M@m@mnMsbCGH)#^>{!NQ>&RSaTY)bbBcdslWB# z6Y*#LuVnq_VW9r^MM_c{Rwbp9|6;g_9r(`tzjncn^nB6DgZ zao;WE?YxN{&tJs~gO&2KllNdR-&cwM$58z_;_uKv6Wm39g!$VHBo?_5{!n;CN~?3isYdW3e4~Z$84^mPfd9 z;tmeXZbDi&D<*3;qZjdSl-F?5p1y?N60!tlc3gGW$aUe56}N?qqNdtLHR#PTv$L~NU0uzepQXR)`U-3tVB^^PreDLqlYhj)IgNx#a}dS+ zKP#J&9$t#qwfitqv6AOLhHAf)d;raVJrFGI0<}j3VR#_>&{0%Z)sXhNbIjw%zd~7A z8Gm**|1tetW30djakXSNs=Yd7PP@iGGfmz<<2rVYuEq?-UW`_ylJ9fS-REWUoy~r| zprzT5@xIcd6Jbbk=wLSY--UE43HP(W~k;gD1AQ5o^^LX5&yhe27y&L%+#pf;s^}RqoXYS47m~Cxs{9aH{0AC;0 zlLG1gGv*)NMXZaug!Ns@kRDk=I-JAzkm4rD*8ti*deZI@ z1GS7eM`}cXOb3~Z9|rXuhPks6FmLu7h<{-WWKs{VJ1q8(lmQ!qgG7J9f(LyTks!o(x^?xhrB5x{pZ13U!{)tLek;yV#(K8yd8 z-1Emh%$fe%+kZigr4`kMH&IdWBkiA!w0~aZyXW`ja@svFckG@e9lPf_zI$4J-91U? oa~-=U+ds{D7S8)jdzt>T-IMvtdY;|?xPS5_{Y7sSpTG3_AJC*|5C8xG literal 0 HcmV?d00001 diff --git a/DiztinGUIsh/Resources/diz-4.png b/DiztinGUIsh/Resources/diz-4.png new file mode 100644 index 0000000000000000000000000000000000000000..a904f4d586bef34715ad0489bc53115b14bbad2f GIT binary patch literal 51202 zcmbTd1ymf}(kME(O9)QTAi*7iySux)4#C}Bg1d*{?#>{=gL`lb?k>YTzVn~|tb5

pW(z%S(KWMXD#;Ywy| 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 literal 0 HcmV?d00001 diff --git a/DiztinGUIsh/packages.config b/DiztinGUIsh/packages.config index 08b1cc2f..c53ecd53 100644 --- a/DiztinGUIsh/packages.config +++ b/DiztinGUIsh/packages.config @@ -1,14 +1,15 @@  - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/DiztinGUIsh/static/Data.cs b/DiztinGUIsh/static/Data.cs index 04b6b55f..e585aa8b 100644 --- a/DiztinGUIsh/static/Data.cs +++ b/DiztinGUIsh/static/Data.cs @@ -469,11 +469,12 @@ public string GetFormattedText(int offset, int bytes) return text + "\""; } - public string GetDefaultLabel(int address) + public string GetDefaultLabel(int offset) { - var pc = ConvertSNEStoPC(address); - return - $"{Util.TypeToLabel(GetFlag(pc))}_{Util.NumberToBaseString(address, Util.NumberBase.Hexadecimal, 6)}"; + var snes = ConvertPCtoSNES(offset); + //return + // $"{Util.TypeToLabel(GetFlag(pc))}_{Util.NumberToBaseString(address, Util.NumberBase.Hexadecimal, 6)}"; + return string.Format("{0}_{1}", Util.TypeToLabel(GetFlag(offset)), Util.NumberToBaseString(snes, Util.NumberBase.Hexadecimal, 6)); } public int Step(int offset, bool branch, bool force, int prevOffset) diff --git a/DiztinGUIsh/static/IProjectView.cs b/DiztinGUIsh/static/IProjectView.cs index 786177f9..12431891 100644 --- a/DiztinGUIsh/static/IProjectView.cs +++ b/DiztinGUIsh/static/IProjectView.cs @@ -13,5 +13,8 @@ interface IProjectView void OnProjectOpenFail(); void OnProjectSaved(); void OnExportFinished(LogCreator.OutputResult result); + + public delegate void LongRunningTaskHandler(Action task, string description = null); + LongRunningTaskHandler TaskHandler { get; } } } diff --git a/DiztinGUIsh/static/LogCreator.cs b/DiztinGUIsh/static/LogCreator.cs index 011a9e17..66272a57 100644 --- a/DiztinGUIsh/static/LogCreator.cs +++ b/DiztinGUIsh/static/LogCreator.cs @@ -97,7 +97,7 @@ private static void CacheAssemblerAttributeInfo() parameters = new Dictionary>(); var methodsWithAttributes = typeof(LogCreator) - .GetMethods() + .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance) .Where( x => x.GetCustomAttributes(typeof(AssemblerHandler), false).FirstOrDefault() != null ); @@ -121,6 +121,8 @@ private static void CacheAssemblerAttributeInfo() parameters.Add(token, (new Tuple(method, weight))); } + + Debug.Assert(parameters.Count != 0); } public string GetParameter(int offset, string parameter, int length) @@ -146,7 +148,8 @@ public OutputResult CreateLog() AddLabelSource(Data.Labels); AddLabelSource(ExtraLabels); - GenerateAdditionalExtraLabels(); + AddTemporaryLabels(); + // GenerateAdditionalExtraLabels(); usedLabels = new List(); @@ -249,7 +252,7 @@ public void AddExtraLabel(int i, Label v) // These labels exist only for the duration of this export, and then are discarded. // // TODO: generate some nice looking "+"/"-" labels here. - private void GenerateAdditionalExtraLabels() + /*private void GenerateAdditionalExtraLabels() { for (var pointer = 0; pointer < Data.GetROMSize();) { @@ -289,6 +292,45 @@ private int GetAddressOfAnyUsefulLabelsAt(int pointer, out int length) return ia; return -1; + }*/ + + private void AddTemporaryLabels() + { + List addMe = new List(); + int pointer = 0; + + while (pointer < Data.GetROMSize()) + { + int length = GetLineByteLength(pointer); + Data.FlagType flag = Data.GetFlag(pointer); + + var flagsOK = (flag == Data.FlagType.Opcode || flag == Data.FlagType.Pointer16Bit || + flag == Data.FlagType.Pointer24Bit || flag == Data.FlagType.Pointer32Bit); + + if (Settings.unlabeled == FormatUnlabeled.ShowAll) + addMe.Add(pointer); + else if (Settings.unlabeled != FormatUnlabeled.ShowNone && flagsOK) + { + int ia = Data.GetIntermediateAddressOrPointer(pointer); + int pc = Data.ConvertSNEStoPC(ia); + if (pc >= 0) addMe.Add(pc); + } + + pointer += length; + } + + // TODO +/- labels + for (int i = 0; i < addMe.Count; i++) + { + var offset = addMe[i]; + var p1 = offset; + var p2 = Data.GetDefaultLabel(offset); + // Data.AddLabel(p1, p2, false); + AddExtraLabel(p1, new Label() + { + name = p2 + }); + } } private void SetupParseList() @@ -301,9 +343,28 @@ private void SetupParseList() else { var colon = split[i].IndexOf(':'); - parseList.Add(colon < 0 - ? Tuple.Create(split[i], Parameters[split[i]].Item2) - : Tuple.Create(split[i].Substring(0, colon), int.Parse(split[i].Substring(colon + 1)))); + + Tuple tuple; + + if (colon < 0) + { + /* + if (colon < 0) + list.Add(Tuple.Create(split[i], parameters[split[i]].Item2)); + else + list.Add(Tuple.Create(split[i].Substring(0, colon), int.Parse(split[i].Substring(colon + 1)))); + */ + + var s1 = split[i]; + var s2 = Parameters[s1].Item2; + tuple = Tuple.Create(s1, s2); + } + else + { + tuple = Tuple.Create(split[i].Substring(0, colon), int.Parse(split[i].Substring(colon + 1))); + } + + parseList.Add(tuple); } } } @@ -526,14 +587,14 @@ public static bool ValidateFormat(string formatString) // just a % [AssemblerHandler(token = "", weight = 1)] - private static string GetPercent(int offset, int length) + private string GetPercent(int offset, int length) { return "%"; } // all spaces [AssemblerHandler(token = "%empty", weight = 1)] - private static string GetEmpty(int offset, int length) + private string GetEmpty(int offset, int length) { return string.Format("{0," + length + "}", ""); } diff --git a/DiztinGUIsh/static/ProjectController.cs b/DiztinGUIsh/static/ProjectController.cs index 382b4517..054e52a8 100644 --- a/DiztinGUIsh/static/ProjectController.cs +++ b/DiztinGUIsh/static/ProjectController.cs @@ -14,9 +14,28 @@ class ProjectController public IProjectView ProjectView { get; set; } public Project Project { get; private set; } + // there's probably better ways to handle this. + // probably replace with a UI like "start task" and "stop task" + // so we can flip up a progress bar and remove it. + public void DoLongRunningTask(Action task, string description = null) + { + if (ProjectView.TaskHandler != null) + { + ProjectView.TaskHandler(task, description); + } + else + { + task(); + } + } + public bool OpenProject(string filename) { - var project = ProjectFileManager.Open(filename); + Project project = null; + DoLongRunningTask(delegate { + project = ProjectFileManager.Open(filename); + }, $"Opening {Path.GetFileName(filename)}..."); + if (project == null) { ProjectView.OnProjectOpenFail(); @@ -33,9 +52,12 @@ private void OnProjectOpened(string filename, Project project) ProjectView.OnProjectOpened(filename); } - public void SaveProject(string projectProjectFileName) + public void SaveProject(string filename) { - ProjectFileManager.Save(Project, projectProjectFileName); + DoLongRunningTask(delegate + { + ProjectFileManager.Save(Project, filename); + }, $"Saving {Path.GetFileName(filename)}..."); ProjectView.OnProjectSaved(); } @@ -58,8 +80,6 @@ public void WriteAssemblyOutput() private void WriteAssemblyOutput(ref LogWriterSettings settings) { - int errors = 0; - // kinda hate that we're passing in these... using var sw = new StreamWriter(settings.file); using var er = new StreamWriter(settings.error); diff --git a/DiztinGUIsh/static/SampleRomData.cs b/DiztinGUIsh/static/SampleRomData.cs index edbbabc7..ee755934 100644 --- a/DiztinGUIsh/static/SampleRomData.cs +++ b/DiztinGUIsh/static/SampleRomData.cs @@ -7,14 +7,26 @@ namespace DiztinGUIsh { - class SampleRomData : Data + internal class SampleRomData : Data { - // TODO: this was originally how this thing was setup, we probably should inject this in somewhere. - // I don't remember how it interacts with our sample RomBytes data - //while (sampleTable.Count < 0x8000) - // sampleTable.Add(new ROMByte()); + public static SampleRomData SampleData + { + get + { + if (finalSampleData != null) + return finalSampleData; + + while (baseSampleData.RomBytes.Count < 0x8000) + baseSampleData.RomBytes.Add(new ROMByte()); + + finalSampleData = baseSampleData; + return baseSampleData; + } + } + + private static SampleRomData finalSampleData = null; - public static SampleRomData SampleData = new SampleRomData + private static readonly SampleRomData baseSampleData = new SampleRomData { // random sample code I made up; hopefully it shows a little bit of // everything so you can see how the settings will effect the output diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 1f89d5d0..c8f78735 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -241,6 +241,9 @@ public void OnExportFinished(LogCreator.OutputResult result) MessageBoxIcon.Asterisk); } + IProjectView.LongRunningTaskHandler IProjectView.TaskHandler => + ProgressBarJob.RunAndWaitForCompletion; + private void saveProjectAsToolStripMenuItem_Click(object sender, EventArgs e) { saveProjectFile.InitialDirectory = Project.AttachedRomFilename; diff --git a/DiztinGUIsh/window/MainWindow.resx b/DiztinGUIsh/window/MainWindow.resx index 884e0d97..0b8cde8c 100644 --- a/DiztinGUIsh/window/MainWindow.resx +++ b/DiztinGUIsh/window/MainWindow.resx @@ -183,3704 +183,78 @@ - AAABAAQAEBAAAAEAGABoAwAARgAAACAgAAABABgAqAwAAK4DAABAQAAAAQAYACgyAABWEAAAAAAAAAEA - GAAoIAMAfkIAACgAAAAQAAAAIAAAAAEAGAAAAAAAQAMAAAAAAAAAAAAAAAAAAAAAAAD///////////// - //////////////////////////////////////////////////////+RMBqRMBqRMBq9PyIwEAkAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////+RMBqzOyCzOyDidVx8KRYAAAAAAAAAAAAAAAAAAAD/ - //////////8AAAD///////+RMBqzOyDidVzpk4DidVwwEAkAAAAAAAAAAAAAAAD///8AAAAAAAAAAAD/ - ///////aTi7idVzpk4D44Nrpk4DidVy9PyIwEAkAAAAAAAAAAAD///8AAAAAAAD///////+RMBqzOyDi - dVzpk4DidVwwEAkAAAAAAAAAAAAAAAD///////////8AAAD///////9eHxGzOyCzOyDidVx8KRYAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////9eHxGRMBqzOyC9PyIwEAkAAAAAAAAAAAAAAAAAAAAA - AAD///8AAAAAAAD///////9eHxGRMBqzOyC9PyIwEAkAAAAAAAAAAAAAAAAAAAAAAAD///8AAAAAAAD/ - //////9eHxGzOyCzOyDidVx8KRYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////+RMBqzOyDi - dVzpk4DidVwwEAkAAAAAAAAAAAAAAAD///////8AAAAAAAD////////aTi7idVzpk4D44Nrpk4DidVy9 - PyIwEAkAAAAAAAD///8AAAD///8AAAD///////+RMBqzOyDidVzpk4DidVwwEAkAAAAAAAAAAAAAAAD/ - //8AAAD///8AAAD///////+RMBqzOyCzOyDidVx8KRYAAAAAAAAAAAAAAAAAAAD///////8AAAAAAAD/ - //////+RMBqRMBqRMBq9PyIwEAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////// - //////////////////////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAACAAAABAAAAAAQAYAAAA - AACADAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////7g9Iaw5H6A1HZkyG5QxG4suGYMs - GIAqF2kjE1wfEVAbD0QWDDgSCjMRCS4QCScNByILBhsJBRYHBBMHBBEGAw4FAwwFAwkDAgMBAQIBAQIB - AQAAAP///////////////7k9IbE7IK05H6g3Hqo4Hqc3Hp40HJ40HLQ7IHUnFV8fEVMcD0YYDToUCzMR - CSwPCCUNBx8LBhoJBRQHBBEGAw8FAwwFAwoDAgcDAgIBAQIBAQAAAP///////////////70/Irg9IbQ7 - ILg9Ib0/IsA/IsJAI9lIJ+BrUJ40HH4qF2EhElMcD0YYDTgSCjEQCSkOCCILBh0KBm5qaf////////// - /////9XU1AMBAQIBAQAAAP///////////////8RBI70/Ir0/IsVBI89EJdpNLd1eQeWDbemTgNpLK686 - H4UsGF4fEU4aDj8VDDUSCi4QCSUNBx8LBhgJBcrJyevq6mxpaGpoaFhWVQMBAQIBAQAAAP////////// - /////8VBI8VBI8lCJM9EJdpPMOBsUueLdvC5rPPFuuaHctlJKaU3HnImFVcdEEcYDTgSCjAQCSkOCCAL - BhoJBUhDQv///4uJiAwFAwkDAgMBAQIBAQAAAP///////////////8xDJMxDJM5EJdpNLeFvVemTgPLA - tfvs6fvu6/bTy+R8ZcxDJIouGWEhElIbDz8VDDMRCSsOCCILBhsJBRQHBLKxsOvq6gwFAwkDAgMBAQIB - AQAAAP///////////////9NGJtFFJdVGJuN7Y+mXhe+wovbUzPvu6/vu6/vs6e6sneWCbNtSM3cnFVMc - D0QWDDgSCjAQCSQMBxsJBRYHBDAqKPX19YqJiAkDAgMBAQIBAQAAAP///////////////9hHJtVGJthH - JtpLK99lSuaFb++wovrn4/vu6/TLwuR9ZtVGJpEwGmQhElMcD0YYDTwUCzMRCSsOCDktKm5qaWxpaMrJ - yfX19SwoJwMBAQIBAQAAAP///////////////9ZGJtFFJdlJKdpLK9pPMOBqT+N3XuyklPG6ruWBatNG - JqI2HXkoFmQhElUcD0cYDToUCzMRCSsOCHNrav///////////////6WkpAIBAQIBAQAAAP////////// - /////9ZGJtlIJ9lIJ9lIJ+BrUNhHJtZGJuBsUueNec9EJac3HogtGHImFWEhElAbD0IWDDwUCzMRCSsO - CCILBhoJBRYHBBEGAwwFAwkDAgMBAQIBAQAAAP///////////////9NGJtVGJspDJMA/IslCJLg9Iac3 - HsJAI99kSJszHIUsGHUnFWgjE1gdEE4aDkIWDDgSCjMRCSkOCCILBh0KBjUsKmxpaAwFAwUCAQIBAQIB - AQAAAP///////////////9FFJcpDJMRBI7g9Ia05H540HJEwGpQxG605H4AqF3koFm8lFGQhElcdEEsZ - DkIWDDgSCjEQCSsOCCALBhoJBW5qaf///wwFAwUCAQIBAQAAAAAAAP///////////////8xDJL4/IrY8 - Iao4HpkyG4suGYUsGIYsGH4qF3koFnAlFGkjE18fEVUcD0sZDkIWDDgSCjAQCScNByALBhsJBW9qaf// - /woDAgUCAQIBAQAAAAAAAP///////////////85EJbs9Iao4HpkyG40uGYErF4ErF4gtGHooFnkoFm8l - FGgjE14fEVUcD00aDkIWDDgSCjAQCSkOCCALBh0KBm5qaf///woDAgMBAQIBAQAAAAAAAP////////// - /////9FFJb0/Iqg3HpkyG40uGYgtGIErF4ouGX4qF4AqF3QnFWQhElwfEVUcD00aDkIWDDoUCzAQCScN - ByILBhsJBW5qaf///wwFAwUCAQIBAQAAAAAAAP///////////////9NGJsA/IrM7IKU3Hpw0HJYyG5Ew - GpQxG540HIgtGHcnFW0kFGEhElgdEE0aDkQWDDoUCzMRCSkOCCQMBx0KBm1qaf///wwFAwkDAgIBAQAA - AAAAAP///////////////9pLK8xDJLs9Ia05H6c3HqU3HqU3Hr0/ItxYOpszHIYsGHQnFWYhElgdEE0a - DkIWDDoUCzMRCSsOCCQMBxoJBW1qaf///wwFAwkDAgIBAQIBAQAAAP///////////////9tRMtZGJsdC - JL0/Ir0/IsA/Is9EJeBoTeaFb8pDJKg3HogtGGsjE1oeEFAbD0QWDDoUCzMRCSsOCCALBhgJBVxYV9XU - 1A4FAwkDAgMBAQIBAQAAAP///////////////9tRMtpLK9ZGJtNGJtZGJttSM+BsUuugj++ypOJ1XM5E - JaU3HnUnFV4fEVMcD0QWDDoUCzEQCSUNBx8LBhYHBBEGAw8FAwwFAwkDAgMBAQIBAQAAAP////////// - /////9tUNdpOLtlIJ9pOLt9mS+WCbO6snfjg2vvs6fLBtuFuVMA/IoMsGGMhElUcD0IWDDYSCjAQCSUN - B3FqaaelpKelpJmXl0VCQQkDAgMBAQIBAQAAAP///////////////9tRMtpOLtpOLuR/aOqZh++zpfbU - zPvu6/vu6/vs6e2omOR8ZdlJKXUnFVIbDz8VDDMRCSwPCCQMB6ilpfX19dXU1Ovq6vX19VhWVQMBAQIB - AQAAAP///////////////9pOLtpPMNxVN+BqT+aHceymlvTLwvvu6/vu6/fZ0ueLdtpOLpcyG18fEU0a - Dj0UCzMRCSsOCCQMB6ilpdXV1BEGAw4FA8rJyeDf3wMBAQIBAQAAAP///////////////9pLK9pOLt1e - Qd9mS+J1XOiSfuyikfPFuvXPxumVgtpLK6U3HnAlFFgdEEcYDToUCzAQCSsOCCALBqilpdXV1BEGAw4F - A2poaP///wIBAQIBAQAAAP///////////////9lJKdtUNd9kSOBrUOmVguN3XuN5YeiRfeyjk9xVN686 - H4MsGGMhElMcD0EWDDYSCi4QCSUNBx8LBqilpdXV1BEGAw8FA2poaP///wMBAQIBAQAAAP////////// - /////9pLK9xXOd1bPt5gRON3Xt9kSNtSM91eQeN7Y6w5H4YsGGsjE1cdEEcYDToUCzEQCSkOCCILBh0K - BqelpNXV1BEGAwwFA8nJycnJyAMBAQIBAQAAAP///////////////9lIJ9pPMNxVN9tSM9tUNdNGJr4/ - IrE7IMlCJIAqF2gjE1cdEEkYDToUCzMRCSwPCCUNBx8LBhoJBaelpPX19dXU1Ovq6vX19VZVVQIBAQAA - AAAAAP///////////////9NGJs5EJdNGJsxDJL0/Iqg3HpQxG4MsGHQnFWMhElMcD0kYDTwUCzMRCS4Q - CScNByALBhsJBRYHBGxpaKalpKalpKWkpENBQAMBAQIBAQIBAQAAAP///////////////85EJb4/IrQ7 - IKU3HpkyG4UsGHcnFWYhElgdEFIbD0IWDDwUCzMRCSwPCCUNByILBhsJBRgJBRQHBBEGAw8FAwwFAwoD - AgMBAQMBAQIBAQAAAAAAAP////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAEAAAACAAAAAAQAYAAAA - AAAAMgAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////7g9IbQ7IK05H6c3HqA1HZkyG5IwGo8wGoouGYUsGIAqF3koFnUnFXImFWsjE3AlFF4fEVgd - EFMcD00aDkYYDUIWDD0UCzgSCjUSCjMRCTAQCS4QCSsOCCkOCCcNByQMByALBh0KBhsJBRgJBRYHBBMH - BBEGAxEGAxEGAw8FAw4FAwwFAwwFAwoDAgkDAgkDAgcDAgIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAA - AP///////////////////////7s9IbY8IbE7IKo4HqM2HZw0HJszHJYyG5IwGo0uGYouGYUsGIErF3oo - FnkoFnkoFmkjE2MhEloeEFcdEFAbD0kYDUYYDT8VDDwUCzUSCjMRCTEQCTAQCSwPCCkOCCUNByILBiAL - Bh0KBhoJBRgJBRQHBBMHBBEGAxEGAw8FAw8FAw4FAwwFAwoDAgoDAgkDAgcDAgMBAQIBAQIBAQIBAQAA - AAAAAAAAAAAAAAAAAP///////////////////////70/Irg9IbM7IK05H6g3HqM2HaA1HZszHJszHJky - G5YyG5QxG48wGoouGYUsGIUsGHcnFXAlFGgjE18fEVgdEFMcD0sZDkkYDUIWDDoUCzUSCjMRCTEQCS4Q - CSsOCCcNByUNByILBh8LBhsJBRoJBRYHBBMHBBMHBBEGAxEGAw8FAw4FAwwFAwwFAwoDAgkDAgkDAgUC - AQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAP///////////////////////70/Irk9IbQ7IK86H6w5H6g3 - Hqg3HqM2HaI2HaM2HZ40HJ40HJw0HJcyG5YyG5QxG7Y8IZYyG3QnFWsjE2MhEloeEFMcD1AbD0cYDUIW - DDoUCzgSCjMRCTEQCS4QCSsOCCcNByQMByALBh8LBhsJBRgJBRQHBBMHBBEGAxEGAw8FAw4FAw4FAwwF - AwoDAgkDAgkDAgcDAgIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAP///////////////////////70/Irg9 - Ibg9IbM7IK86H686H605H6w5H6o4Hq05H6o4Hqw5H6g3Hqc3HqA1Hag3Ht1eQc5EJYouGXwpFm8lFGMh - El4fEVUcD04aDkcYDUIWDDwUCzUSCjMRCTAQCSwPCCsOCCUNByQMBx8LBhsJBRoJBRYHBBQHBBEGAxEG - AxEGAw8FAw4FAwwFAwoDAgoDAgkDAgcDAgIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAP////////////// - /////////70/Irs9Ibg9IbY8IbQ7IK86H7E7ILQ7ILM7ILQ7ILQ7ILg9Ibs9Ibg9IbY8IcdCJOJyWd1b - Pqo4Ho0uGYAqF3QnFWgjE1oeEFUcD04aDkYYDUEWDDwUCzUSCjMRCTAQCSsOCCcNByQMByILBh8LBhsJ - BRgJBW5qaf///////////////////////////////////////wMBAQIBAQIBAQIBAQAAAAAAAAAAAAAA - AP///////////////////////70/Ir0/Irk9Ibk9Ibg9Ibg9Ibk9Ibk9Ib0/Ir4/IsJAI8VBI8dCJMxD - JM9EJdxXOeaHceN3XtNGJq05H5cyG4YsGHcnFWYhElwfEVUcD00aDkcYDT8VDDgSCjUSCjAQCSwPCCkO - CCUNByILBh8LBh0KBhoJBRYHBNXV1P///////////////////////////////////wUCAQMBAQIBAQIB - AQAAAAAAAAAAAAAAAP///////////////////////74/IsA/Irs9Ib0/Irs9Ibs9Ib0/IsA/IsJAI8lC - JM5EJdNGJtlJKdtSM91aPON3XumXheaHct5gQ8xDJLM7IKI2HYsuGXkoFmYhElcdEFIbD0sZDkQWDDwU - CzUSCjMRCTAQCSsOCCcNByQMByILBh0KBhoJBRYHBFxYV////////////769vaalpKalpKWkpKWkpKWk - pAUCAQIBAQIBAQAAAAAAAAAAAAAAAAAAAP///////////////////////8VBI8RBI8A/Ir0/Ir0/IsA/ - IsJAI8VBI8xDJNVGJtlJKdtUNd1eQd9lSuJ1XOeNee2omOuejON5YdxVN8pDJLY8IaA1HYsuGXImFV8f - EVcdEE4aDkYYDUEWDDoUCzUSCjAQCS4QCSkOCCUNByILBh8LBhsJBRgJBRQHBL69vf///////769vQ4F - AwwFAwoDAgoDAgkDAgcDAgMBAQIBAQIBAQAAAAAAAAAAAAAAAP///////////////////////8RBI8JA - I8RBI8RBI8RBI8RBI8dCJMxDJNZGJtpLK9tUNd9kSOBsUuR8ZeiRfe2omfG9sfC2qeqciuJ1XNxXOc9E - JcJAI540HIYsGGkjE1wfEVIbD0sZDkIWDDwUCzYSCjMRCS4QCSsOCCcNByILBh8LBh0KBhoJBRYHBEhD - Qv///////////0ZCQQwFAwwFAwoDAgkDAgcDAgMBAQMBAQIBAQAAAAAAAAAAAAAAAP////////////// - /////////8dCJMVBI8RBI8RBI8VBI8lCJM5EJdFFJdlIJ9tSM95gROJ0W+aFb+qZh+6un/PFu/bTy/XR - yfG8sOqZh+JyWdpPMMVBI6o4HpYyG3cnFWQhElcdEFIbD0kYDT8VDDgSCjMRCTAQCSwPCCkOCCUNByAL - BhsJBRoJBRYHBBMHBL69vf///////9XU1AwFAwwFAwoDAgkDAgcDAgMBAQIBAQIBAQAAAAAAAAAAAAAA - AP///////////////////////8xDJMpDJMlCJMlCJMxDJM5EJc9EJdZGJttSM99kSOJyWeaHcemXhe+z - pfXNxPnh3Pvs6fvs6fjg2vLAteiRfeBrUNlJKbs9IaI2HX4qF2sjE1wfEVMcD04aDkQWDD0UCzUSCjEQ - CS4QCSkOCCUNByILBh0KBhoJBRYHBBQHBEdDQfX19f///////2tpaAwFAwoDAgkDAgcDAgMBAQIBAQIB - AQAAAAAAAAAAAAAAAP///////////////////////85EJcxDJMpDJMpDJMxDJM5EJdhHJttSM99kSON7 - Y+aJdOufju+zpfTKwfni3fvu6/vu6/vu6/vu6/jg2u+zpeeLduBoTdpLK7s9IZIwGnkoFmQhEloeEFUc - D0kYDT8VDDoUCzMRCTAQCSsOCCUNByILBh8LBhsJBRgJBRQHBBEGA6alpP///////9XU1AoDAgoDAgkD - AgcDAgMBAQMBAQIBAQAAAAAAAAAAAAAAAP///////////////////////9FFJc9EJc5EJcxDJNFFJdNG - Jt5gROWCbOiPe+qciuyklO+ypPLBtvbUzPvs6Pvu6/vu6/vu6/vu6/vs6fTKwe6snemTgOWBauBrUNpO - LrM7IHQnFV4fEVMcD0cYDUIWDD0UCzUSCjMRCS4QCScNByILBh8LBhsJBRgJBRYHBBEGAzAqKPX19f// - /////2tpaAoDAgkDAgkDAgMBAQIBAQIBAQAAAAAAAAAAAAAAAP///////////////////////9VGJtNG - JtNGJtFFJdNGJtZGJttUNeFwV+WDbeiSfuufju6snfG8sPXRyfro5Pvu6/vu6/vu6/vu6/vs6PPHve2q - m+mVguWCbOFvVdxXOcVBI3koFlcdEFIbD0kYDUIWDD0UCzgSCjMRCTAQCSsOCCUNBx8LBhsJBRoJBRYH - BBMHBBEGA6alpP///////9XU1AoDAgkDAgcDAgMBAQIBAQIBAQAAAAAAAAAAAAAAAP////////////// - /////////9ZGJtZGJtZGJtVGJtFFJdVGJthHJtpLK9xVN+BrUON5YeiRfeyklPK/s/jb1fvu6/vu6/vu - 6/vu6/jb1e+ypOiRfeFvVdxVN8dCJJszHHkoFmMhElcdEFIbD0kYDUQWDD8VDDgSCjMRCTEQCS4QCSsO - CCQMBx0KBhgJBRQHBBMHBBEGAzAqKPX19f///////2poaAkDAgcDAgMBAQIBAQIBAQAAAAAAAAAAAAAA - AP///////////////////////9lIJ9hHJtZGJtNGJtNGJtlIJ9hHJthHJtpNLd1aPN9mS+J0W+aHcuuf - jvLBtvfZ0vni3frm4ffX0PC2qeeMd+BoTdlIJ70/Ip40HIMsGHAlFGMhEloeEFIbD00aDkYYDT0UCzoU - CzUSCjEQCSwPCCkOCCQMByALBtbV1NbV1NXV1NXU1NXU1PX19f///////+rq6gkDAgcDAgMBAQIBAQIB - AQAAAAAAAAAAAAAAAP///////////////////////9lIJ9VGJtVGJtNGJtFFJdVGJtlIJ9lJKdpNLdpP - MN5gQ+BsUuFwV+WCbOmXhe+0p/PFu/PFuu+wouiPe+BoTdpNLb4/Iqc3Ho8wGnkoFm8lFGYhEloeEFMc - D0sZDkYYDT8VDDwUCzUSCjMRCTAQCSsOCCUNByALBv///////////////////////////////////4qI - iAUCAQIBAQIBAQIBAQAAAAAAAAAAAAAAAP///////////////////////9lIJ9ZGJtVGJs9EJdhHJtpN - LdlJKdpLK9pOLtpOLttSM95iRuBoTd9mS+N3XumTgO2qm+6sneeNeeBrUNpLK8RBI605H5szHIouGXUn - FWkjE2EhElcdEFMcD00aDkcYDT8VDDgSCjUSCjEQCS4QCSsOCCcNByQMB9bV1NbV1NXV1NXU1NXU1NXU - 1NXU1NXU1NXU1L29vQMBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAP///////////////////////9lIJ9ZG - JtNGJtZGJtlJKdlIJ9hHJtlJKdlIJ91eQd1bPtpNLdtSM9pOLt1aPON5YemWg+mVguFwV9pNLcRBI686 - H5szHI0uGYAqF3QnFWkjE18fEVcdEFAbD0sZDkIWDD8VDD0UCzYSCjEQCS4QCSkOCCUNByILBh8LBhoJ - BRgJBRQHBBEGAxEGAw8FAwwFAwoDAgkDAgMBAQMBAQIBAQIBAQAAAAAAAAAAAAAAAP////////////// - /////////9hHJtVGJtFFJdlJKdlIJ9hHJtNGJtVGJtxXOeN5YdxYOsxDJMlCJMlCJM9EJd1eQeaFb+WD - bdxVN74/Iqw5H540HI0uGYErF3cnFW0kFGYhEl8fEVUcD04aDkcYDUEWDD0UCzgSCjUSCjMRCTAQCSsO - CCcNByALBh8LBhoJBRgJBRYHBBEGAw8FAw4FAwwFAwwFAwkDAgUCAQMBAQIBAQIBAQAAAAAAAAAAAAAA - AP///////////////////////9VGJtVGJs9EJdhHJtVGJs5EJclCJMVBI89EJdVGJsA/Ir0/Iq86H686 - H7E7INFFJeJyWeFuVMxDJKM2HZQxG4ouGYAqF3koFnAlFGgjE18fEVoeEFMcD04aDkcYDUEWDDwUCzYS - CjMRCTEQCSwPCCkOCCUNByILBh8LBhsJBRgJBRQHBBMHBA8FAwwFAwoDAgkDAgUCAQMBAQIBAQIBAQIB - AQAAAAAAAAAAAAAAAP///////////////////////9FFJdFFJcpDJM9EJc9EJcVBI74/Irs9Ib0/Ir0/ - IrY8Ia86H6A1HZw0HJ40HLM7IN9kSNxXOa05H40uGYUsGHwpFnkoFnImFWkjE2YhEl8fEVcdEFAbD0kY - DUcYDUEWDDwUCzYSCjMRCTEQCSsOCCcNByQMByALBh8LBhsJBRoJBW9qaaelpKalpEVCQQwFAwkDAgMB - AQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAP///////////////////////9NGJtFFJcdCJM5EJc5EJcRB - I70/Irk9IbY8IbM7IKo4HqI2HZYyG5QxG5QxG5szHNlJKcdCJJszHIMsGHwpFnkoFncnFW8lFGkjE2Mh - El8fEVcdEFIbD0sZDkYYDUIWDD0UCzYSCjMRCTEQCSwPCCkOCCUNByALBh0KBhoJBRYHBKelpP////// - /2xpaAoDAgkDAgMBAQMBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAP///////////////////////9VGJsxD - JMlCJMVBI8dCJMA/Irs9IbQ7ILM7IKc3HqU3HpcyG48wGosuGYouGYsuGZkyG5EwGpEwGnooFnkoFnUn - FXAlFG8lFGgjE2MhElgdEFUcD04aDkkYDUYYDUEWDD0UCzYSCjMRCTAQCSsOCCkOCCQMByALBh0KBhoJ - BRgJBaelpP///////2xpaAoDAgUCAQUCAQMBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAP////////////// - /////////9NGJspDJMdCJL4/Ir0/Ir0/IrY8Ia86H6c3HqA1HZcyG40uGYgtGIYsGIMsGIYsGHooFn4q - F4ouGXkoFnUnFXImFW8lFGsjE2YhEl8fEVoeEFMcD1AbD0sZDkYYDUEWDDwUCzYSCjMRCTEQCSsOCCUN - ByQMByALBh0KBhoJBRgJBaelpP///////2xpaAoDAgUCAQUCAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAA - AP///////////////////////9NGJsxDJMA/Ir0/IrM7IKo4Hqc3HqA1HZszHI0uGYgtGIUsGH4qF4Aq - F3wpFoUsGHkoFnkoFoMsGHkoFnQnFW0kFGkjE2YhEmQhElwfEVcdEFMcD04aDksZDkYYDUEWDD0UCzYS - CjMRCS4QCSsOCCcNByQMByALBh0KBhsJBRoJBaelpP///////2xpaAoDAgUCAQMBAQIBAQIBAQAAAAAA - AAAAAAAAAAAAAAAAAP///////////////////////9NGJsxDJMJAI7k9IbM7IKw5H6A1HZkyG5QxG40u - GYYsGIAqF34qF4AqF3ooFoYsGHkoFnkoFnwpFnkoFnQnFW0kFGkjE2gjE2EhElwfEVcdEFUcD1AbD00a - DkcYDUEWDD0UCzgSCjMRCS4QCSsOCCcNByUNByALBh0KBhsJBRgJBaelpP///////2xpaAoDAgcDAgMB - AQMBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////////////////9ZGJs5EJcVBI70/Iq86H6c3 - HqA1HZcyG48wGogtGIUsGIAqF34qF34qF3ooFogtGHkoFnooFncnFXkoFnAlFG8lFGgjE2QhEl8fEV4f - EVcdEFMcD1AbD0sZDkcYDUEWDDwUCzgSCjMRCTAQCSsOCCcNByILBiALBh0KBh0KBhgJBaelpP////// - /2xpaAoDAgkDAgMBAQMBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAP///////////////////////9VGJs9E - JcRBI70/Iq86H6g3Hp40HJYyG5IwGoouGYYsGIMsGIErF4AqF34qF4gtGHkoFnooFncnFXwpFnQnFXAl - FGsjE2MhEl8fEVwfEVcdEFUcD1AbD00aDkYYDUEWDDwUCzgSCjMRCTEQCSsOCCkOCCQMByALBh0KBhoJ - BRgJBaelpP///////2tpaAwFAwoDAgUCAQMBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////// - /////////9VGJs5EJcRBI70/IrM7IKc3Hp40HJszHJQxG40uGYsuGYouGYYsGIErF4MsGIouGYAqF34q - F3koFn4qF3UnFXImFWkjE2QhEmEhEloeEFgdEFMcD1AbD0sZDkcYDUEWDDwUCzgSCjMRCS4QCSsOCCUN - ByQMByALBh0KBhsJBRgJBaelpP///////2tpaAoDAgoDAgUCAQMBAQIBAQIBAQAAAAAAAAAAAAAAAAAA - AP///////////////////////9lJKdFFJclCJL4/IrY8Ia05H6U3HqM2HZw0HJkyG5QxG5IwGpEwGo0u - GYsuGY8wGpYyG4YsGH4qF4UsGHkoFnUnFW0kFGsjE2QhEmEhElgdEFcdEFAbD0sZDkcYDUIWDD0UCzgS - CjUSCjEQCS4QCSkOCCQMByILBh0KBhsJBRoJBaelpP///////2xpaAwFAwoDAgkDAgIBAQIBAQIBAQAA - AAAAAAAAAAAAAAAAAP///////////////////////9lJKdVGJsxDJL4/Irk9IbQ7IK05H6U3HqM2HZ40 - HJszHJkyG5YyG5QxG5IwGpYyG9hHJrQ7IIouGYgtGHooFncnFXQnFWsjE2YhEmEhEl4fEVcdEFAbD00a - DkYYDUIWDD0UCzgSCjUSCjEQCSwPCCkOCCUNByILBh0KBhsJBRgJBaalpP///////2xpaAwFAwoDAgcD - AgIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAP///////////////////////9pNLdlJKc9EJclCJL4/Irg9 - Ia86H6g3Hqc3HqM2HZw0HKA1HZ40HJw0HJw0HKg3Ht9mS9pLK5szHJYyG4YsGH4qF3koFnImFWkjE2Qh - El4fEVcdEFIbD00aDkcYDUIWDD0UCzgSCjMRCTEQCSwPCCkOCCUNByQMBx0KBhsJBRQHBKelpP////// - /2tpaAwFAwoDAgcDAgMBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAP///////////////////////9pPMNlJ - KdVGJsxDJMVBI70/Irg9IbE7IKo4Hqc3Hqc3HqU3Hqg3Hqg3Hq86H8pDJON3Xt9kSLg9IaA1HZQxG4su - GYAqF3QnFWsjE2QhElwfEVgdEFMcD0sZDkcYDUEWDD0UCzgSCjUSCjEQCS4QCSsOCCUNByILBh0KBhYH - BBQHBKalpP///////2xpaAwFAwoDAgkDAgUCAQIBAQIBAQIBAQAAAAAAAAAAAAAAAP////////////// - /////////9tRMtpOLthHJtNGJspDJMRBI70/IrY8IbY8IbY8IbQ7ILY8Ibk9IcA/IsdCJNxXOeaHcuN7 - Y9pNLb0/Iqw5H5w0HIsuGX4qF3QnFWkjE2EhEloeEFUcD00aDkkYDUIWDD0UCzoUCzUSCjEQCS4QCSkO - CCUNByALBhsJBRgJBRQHBKelpP///////2xpaAwFAwkDAgkDAgUCAQIBAQIBAQIBAQAAAAAAAAAAAAAA - AP///////////////////////9xVN9tRMtlJKdZGJs9EJcdCJMRBI8JAI8A/Ir4/IsJAI8lCJM5EJdlI - J9tUNeJ1XOqZh+eMd99mS9ZGJsA/IrE7IKA1HY0uGXooFmsjE2EhEloeEFUcD1AbD0YYDUIWDD8VDDgS - CjUSCjEQCS4QCSsOCCILBh8LBhoJBRYHBBQHBEhDQmxpaGxpaC8qKAwFAwoDAgkDAgcDAgMBAQIBAQIB - AQAAAAAAAAAAAAAAAP///////////////////////9tUNdpPMNpOLtpLK9hHJtFFJcxDJMpDJMxDJM5E - JdNGJtlIJ9tSM91eQeFwV+iPe+2qm+yklOaFb99kSNhHJsJAI7M7IJ40HIUsGHImFWYhElwfEVMcD1Ab - D0kYDUIWDD0UCzgSCjMRCTEQCSwPCCUNByILBh0KBhsJBRYHBBQHBBEGAxEGAw8FAw4FAwoDAgoDAgkD - AgcDAgMBAQIBAQIBAQAAAAAAAAAAAAAAAP///////////////////////9xVN9tRMtpNLdlIJ9hHJtlI - J9hHJtZGJtVGJtlIJ9tRMt1eQeBqT+N7Y+iRfe6un/LDuPK/s+ymluaFb95gRNhHJsVBI6c3HpEwGnko - FmgjE1wfEVcdEFMcD0kYDUIWDD0UCzoUCzMRCTAQCSkOCCUNByALBh8LBhoJBRYHBBQHBBEGAxEGAw8F - AwwFAwwFAwoDAgkDAgcDAgMBAQMBAQIBAQAAAAAAAAAAAAAAAP///////////////////////9xXOdtU - NdpPMNpOLtpLK9hHJthHJtpLK9tRMt1cP99kSOJyWeaFb+qaiPC2qfXPx/jg2vje2PTLwu2qm+WBat1c - P85EJbQ7IJw0HHwpFm0kFF8fEVcdEFIbD0sZDkQWDD0UCzYSCjEQCS4QCSkOCCUNByALBh0KBhoJBRYH - BBMHBBEGAxEGAw4FAwwFAwwFAwoDAgkDAgcDAgMBAQIBAQIBAQAAAAAAAAAAAAAAAP////////////// - /////////9xVN9tSM9pOLtpNLdpLK9lJKdpNLdpPMN1bPuBrUON7Y+eMd+yklPG6rvbVzvvs6Pvu6/vu - 6/vu6/bTy+yklOR8ZdxYOspDJKw5H4MsGHImFWQhElwfEVcdEEsZDj8VDDgSCjMRCTEQCS4QCSkOCCQM - ByALBnFqaf////////////////////X19crJyWtpaAoDAgkDAgcDAgMBAQMBAQIBAQAAAAAAAAAAAAAA - AP///////////////////////9xVN9tRMtpPMNpLK9pOLtpNLdxVN+BrUON7Y+eLduqaiO2qm/G9sfXP - x/ro5Pvu6/vu6/vu6/vu6/vs6PLDuOyikeWDbeBsUtxVN70/IpEwGmsjE1gdEFUcD0cYDT8VDDgSCjMR - CTEQCSwPCCkOCCQMByALBnFqaf///////////////////////////////7GwsAkDAgcDAgMBAQIBAQIB - AQAAAAAAAAAAAAAAAP///////////////////////9tSM9tRMtpOLtpOLtpOLttSM+R9ZumTgOqciuyk - lO6un/C5rPPFuvfZ0vvq5vvu6/vu6/vu6/vu6/vs6fTKwe6uoOmXheaHcuN3Xt5gRNZGJnwpFlcdEE0a - DkQWDD0UCzYSCjMRCS4QCSsOCCcNByILBh8LBnBqaf///////9XU1KalpKalpMrJyf///////////3t5 - eAcDAgMBAQIBAQIBAQAAAAAAAAAAAAAAAP///////////////////////9tRMtpOLtpOLtpOLtpOLttS - M91bPuFuVOWBauiPe+ugj++wovLAtfbTy/rn4/vu6/vu6/vu6/vu6/nk3/G9seuejOR/aN9mS9pLK7E7 - IIAqF18fEVIbD00aDkIWDD0UCzUSCjMRCS4QCSsOCCUNByQMBx8LBnBqaf///////6alpBEGAw8FAw4F - A4qJiP///////+rq6gcDAgMBAQIBAQIBAQAAAAAAAAAAAAAAAP///////////////////////9pOLtpO - LtpOLtpOLtpOLtxVN91aPN5gQ+BqT+N5YeaJdOqaiO2qm/LAtfjb1fvs6Pvu6/vu6/ro5PPHveuejOJ1 - XNtSM8VBI6M2HXooFmkjE1wfEVMcD0kYDUIWDDoUCzUSCjAQCS4QCSkOCCUNByILBh0KBm9qaf////// - /6alpBEGAw8FAw4FAwwFA8rJyf///////2poaAMBAQIBAQIBAQAAAAAAAAAAAAAAAP////////////// - /////////9pOLtpLK9pNLdpOLttRMtxXOd1bPt5gQ+BqT+JyWeaHceiPe+qZh+2omfLAtfbTy/jb1ffa - 0/PFu+yklON4YNxVN8dCJKo4Ho0uGXQnFWgjE1oeEE4aDkYYDT8VDDoUCzYSCjEQCS4QCSsOCCQMByAL - Bh0KBm9qaf///////6alpBEGAw8FAw4FAwwFA4qIiP///////5eWlgIBAQIBAQIBAQAAAAAAAAAAAAAA - AP///////////////////////9pNLdpLK9pLK9pNLdtUNd9kSN9mS+BsUuJyWeN4YOWBauiPe+qaiOmX - heyklPC2qfLDuPLDuOymluWDbd1bPs9EJbQ7IJszHIErF20kFF8fEVcdEEsZDkcYDT8VDDgSCjMRCS4Q - CSsOCCcNByQMByALBh0KBm9qaf///////6alpBEGAw8FAw4FAwwFA2poaP///////6SkpAIBAQIBAQIB - AQAAAAAAAAAAAAAAAP///////////////////////9lJKdlJKdpNLdpPMN1cP95iRuBoTeBrUOFvVeR9 - ZuWDbeR/aOaHcuWCbOaHcuqciu6un+2qm+aJdN5iRtFFJbg9IZ40HIsuGXcnFWYhElgdEFMcD0cYDUEW - DDoUCzgSCjMRCTAQCSsOCCQMByILBh0KBhsJBW9qaf///////6alpBEGAxEGAw8FAwwFA2poaP////// - /6SkpAMBAQIBAQIBAQAAAAAAAAAAAAAAAP///////////////////////9lJKdlJKdpOLtxXOd1aPN9k - SN9mS+BrUOR9Zu2omeeNeeFuVOFwV+FvVeFwV+aFb+uejOmXheBsUtlIJ7s9IaM2HY0uGXkoFm0kFF4f - EVcdEE4aDkIWDD0UCzYSCjMRCS4QCSsOCCcNBycNByQMBx8LBhsJBW5qaf///////6alpBEGAw8FAw4F - Aw4FA5iXlv///////4mIhwMBAQIBAQIBAQAAAAAAAAAAAAAAAP///////////////////////9lIJ9pL - K9pNLdxXOd1eQd1eQd1cP99kSON4YOWCbOFuVOBqT91cP91bPtxVN+BrUOeMd+aHcdxXObs9IaA1HY8w - GnooFnAlFGMhElcdEFAbD0kYDUIWDDoUCzUSCjEQCSwPCCkOCCUNByILBh8LBh0KBhsJBW9qaf////// - /6alpA8FAw8FAwwFAwwFA9XU1P///////0FAQAMBAQMBAQMBAQAAAAAAAAAAAAAAAP////////////// - /////////9lIJ9pLK9pLK9xVN91bPt1aPN1aPN1bPt5iRuBoTd5gQ91cP9pOLtlIJ9NGJtpOLuR8ZeFu - VMlCJJszHIouGXwpFnAlFGQhElgdEFMcD00aDkIWDDwUCzgSCjMRCS4QCSsOCCcNByQMByILBh8LBhsJ - BRgJBW1qaf///////6alpBEGAw4FAwwFA769vf///////9TU1AMBAQIBAQIBAQAAAAAAAAAAAAAAAAAA - AP///////////////////////9lIJ9lIJ9lIJ9tUNd1aPNxVN9xVN9xVN91aPN1bPttRMtpNLc5EJcdC - JL0/IsA/It9mS9tSM6o4HoouGXkoFm0kFGMhEloeEFIbD00aDkYYDTwUCzgSCjMRCTEQCS4QCSkOCCUN - ByILBiALBhsJBRoJBRYHBG1qaf///////+vq6tXU1NXU1PX19f////////X19VZVVQMBAQIBAQIBAQAA - AAAAAAAAAAAAAAAAAP///////////////////////9hHJthHJthHJtpNLdtRMttSM9pPMNpOLtpPMNpL - K9ZGJsdCJLs9IbM7IKc3Hp40HMJAI6g3HpIwGnUnFWsjE2EhElgdEFIbD0sZDkQWDD0UCzgSCjMRCTEQ - CSwPCCkOCCcNByQMByALBh0KBhoJBRgJBRYHBG1qaf////////////////////////////X19VZVVQMB - AQMBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAP///////////////////////9hHJtNGJtZGJtFFJdhHJtlJ - KdlIJ9ZGJs9EJcpDJL0/IrE7IKo4HpszHJYyG4ouGYErF3koFoAqF2gjE14fEVcdEFAbD00aDkcYDT8V - DDgSCjUSCjAQCTAQCSsOCCcNByQMByILBh8LBh0KBhgJBRYHBBQHBFtXVtXU1NXU1NXU1NXU1NXU1MnJ - yZiXlisoJwMBAQMBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAP///////////////////////9ZGJtFF - Jc5EJcpDJMdCJMVBI8VBI8JAI7s9Ia05H6c3Hpw0HJIwGoouGYErF3ooFnImFW0kFHAlFF4fEVcdEE4a - DkcYDUQWDD8VDDoUCzMRCTAQCS4QCSsOCCcNByUNByILBh8LBhsJBRoJBRgJBRQHBBMHBBEGAxEGAw8F - Aw4FAwwFAwwFAwoDAgkDAgUCAQMBAQMBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAP////////////// - /////////9NGJs5EJcdCJMA/IsA/Irs9IbM7IKw5H6c3HqI2HZcyG4suGYErF3wpFnImFWsjE2QhElwf - EV4fEVUcD00aDkYYDUEWDD0UCzoUCzMRCTAQCS4QCSsOCCcNByUNByILBiALBh0KBhsJBRgJBRYHBBQH - BBMHBBEGAxEGAw8FAw4FAwwFAwoDAgoDAgcDAgMBAQMBAQMBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAA - AP///////////////////////85EJcxDJMRBI70/IrQ7IKw5H6U3Hpw0HJcyG48wGoMsGHwpFnUnFW0k - FGQhEl4fEVgdEFMcD1AbD04aDkQWDD8VDDoUCzYSCjEQCTEQCSwPCCsOCCcNByQMByILBiALBh0KBhoJ - BRgJBRYHBBQHBBMHBBEGAxEGAw8FAw8FAw4FAwwFAwoDAgoDAgUCAQMBAQMBAQIBAQIBAQIBAQAAAAAA - AAAAAAAAAAAAAAAAAP///////////////////////8dCJMJAI70/IrQ7IKw5H6I2HZkyG5EwGoYsGH4q - F3cnFW8lFGgjE18fEVgdEFIbD04aDkkYDUQWDEYYDToUCzgSCjMRCTEQCSwPCCsOCCcNByUNByQMByIL - Bh8LBh0KBhsJBRgJBRgJBRQHBBMHBBEGAxEGAw8FAw4FAwwFAwwFAwoDAgoDAgUCAQMBAQMBAQIBAQIB - AQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAABAAAAAgAAAQAYAAAA - AAAAIAMAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////7Y8Ibg9Ibg9IbE7ILY8Iao4Hq05H7E7IK05H6o4Hqg3Hqg3Hqg3HqA1HaM2 - HaI2HZ40HKM2HZszHJkyG5kyG5EwGpYyG5YyG5EwGpQxG40uGZEwGpEwGo8wGosuGYouGYsuGYYsGIYs - GIgtGIouGYMsGIAqF4ErF4AqF4AqF3koFnkoFnkoFncnFXooFncnFXUnFXImFXUnFXQnFXAlFG8lFG8l - FGsjE2sjE2kjE2gjE20kFHkoFnImFWEhEl4fEVoeEFwfEVoeEFoeEFgdEFcdEFMcD1UcD1McD04aDk4a - DksZDkkYDUkYDUkYDUsZDkcYDUcYDUIWDEIWDD8VDD8VDEEWDD0UCzwUCz8VDDwUCzgSCjYSCjgSCjYS - CjYSCjgSCjUSCjMRCTMRCTMRCTMRCTEQCTAQCS4QCTAQCS4QCTAQCSwPCCsOCCwPCCwPCCwPCCsOCCkO - CCkOCCcNBykOCCcNBykOCCcNByUNByQMByQMByUNByQMByILBiALBh8LBiALBh8LBh8LBh0KBh0KBh0K - Bh0KBh0KBhsJBRsJBRoJBRoJBRgJBRYHBBYHBBQHBBQHBBQHBBQHBBMHBBMHBBMHBBEGAxEGAxEGAxEG - AxEGAxEGAxEGAxEGAw8FAw8FAw8FAw8FAw8FAw4FAw8FAw4FAw8FAw4FAw4FAwwFAwwFAwwFAwwFAwwF - AwwFAwoDAgoDAgoDAgoDAgoDAgoDAgoDAgkDAgkDAgcDAgkDAgkDAgkDAgkDAgcDAgkDAgcDAgMBAQMB - AQIBAQIBAQIBAQMBAQMBAQIBAQAAAAIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAIBAQAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////7s9IbY8IbM7ILY8IbE7ILQ7ILM7IK86H605H6w5H6c3Hqo4HqU3HqI2HaI2HZ40HJszHJszHJw0 - HKA1HZszHJszHJkyG5QxG5EwGpQxG5cyG5YyG5EwGo0uGYouGY8wGo8wGoouGYYsGIMsGIUsGIgtGIEr - F4YsGIMsGIAqF3wpFoAqF3koFnooFnooFnkoFnkoFnImFXcnFXcnFXcnFXQnFW8lFG8lFGsjE2sjE2kj - E3ImFXooFnUnFWgjE2MhEl8fEWEhEl8fEV4fEV8fEVcdEFcdEFcdEFUcD1cdEFIbD1IbD04aDkkYDU0a - DkcYDUkYDUkYDUkYDUcYDUYYDUIWDEEWDD0UCz0UCz8VDDwUCzoUCzgSCjoUCzgSCjMRCTYSCjYSCjMR - CTMRCTEQCTAQCTAQCTAQCS4QCTAQCS4QCS4QCS4QCSwPCCsOCCsOCCkOCCkOCCsOCCsOCCkOCCkOCCwP - CCkOCCcNByUNByQMByILBiQMByQMByALBiALBh8LBiALBh8LBiALBh8LBh0KBh0KBh0KBh0KBhsJBRoJ - BRsJBRoJBRYHBBgJBRYHBBQHBBYHBBQHBBMHBBMHBBQHBBMHBBEGAxEGAxEGAxEGAxEGAxEGAxEGAxEG - AxEGAxEGAxEGAw8FAw8FAw4FAw8FAw4FAw8FAw4FAw4FAw4FAwwFAwwFAwwFAwwFAwwFAwoDAgoDAgoD - AgoDAgwFAwoDAgkDAgkDAgkDAgcDAgkDAgkDAgkDAgkDAgcDAgcDAgUCAQUCAQMBAQMBAQMBAQIBAQIB - AQIBAQIBAQIBAQAAAAIBAQIBAQAAAAIBAQAAAAIBAQAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////7Q7ILY8IbQ7 - IK86H7g9Ia05H7Y8IbM7IK86H605H6w5H6c3Hqg3Hqc3HqA1HZ40HJw0HJ40HJw0HJkyG5kyG5szHJsz - HJcyG5kyG5IwGpEwGpQxG5IwGo0uGZIwGpEwGpEwGo0uGY0uGYsuGYouGYMsGIMsGIYsGIgtGIAqF4Aq - F4AqF34qF3ooFn4qF3wpFnkoFncnFXUnFXcnFXcnFXQnFXUnFXImFXAlFG8lFG0kFHImFXooFncnFWkj - E2MhEmEhEl4fEV8fEWMhEmEhEl4fEVgdEFcdEFMcD1cdEFMcD1IbD1UcD1AbD00aDkkYDUsZDksZDkYY - DUYYDUcYDUEWDEEWDEEWDEEWDD8VDDwUCzgSCjoUCzgSCjwUCzoUCzoUCzUSCjMRCTMRCTMRCTMRCTMR - CTEQCTMRCTAQCTEQCTAQCS4QCS4QCSwPCC4QCSsOCCwPCCwPCCsOCCwPCCsOCCsOCCcNByUNByQMByUN - ByILBiQMByILBiALBiILBiILBiILBiALBiALBh8LBh8LBh0KBh0KBhsJBRoJBRoJBRsJBRoJBRYHBBgJ - BRQHBBQHBBYHBBYHBBQHBBQHBBQHBBMHBBMHBBEGAxMHBBEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FAw4F - Aw8FAw8FAw8FAw4FAw8FAw4FAw4FAw4FAwwFAwwFAw4FAwwFAwwFAwwFAwwFAwoDAgoDAgoDAgoDAgkD - AgkDAgkDAgcDAgcDAgkDAgkDAgkDAgcDAgcDAgcDAgcDAgMBAQMBAQIBAQIBAQIBAQIBAQAAAAIBAQAA - AAAAAAIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////7Y8Ibg9Ibg9Ibg9Ia86H7Y8Ia86 - H605H7M7IK86H686H6M2Hag3Hqw5H6U3HqA1HaA1HaI2HZ40HKA1HZ40HJszHJszHJszHJw0HJQxG5Iw - GpcyG5YyG48wGo0uGY0uGZIwGo8wGpEwGosuGYsuGY0uGYsuGYouGYgtGIMsGIErF4MsGIUsGIErF4Er - F3wpFnkoFn4qF34qF3koFnkoFnQnFXkoFnQnFXImFW8lFHImFXQnFXwpFoAqF3AlFGQhEmQhEmQhEmQh - EmQhEl8fEVwfEVcdEFwfEVcdEFcdEFcdEFcdEFMcD1McD1IbD04aDlIbD1AbD0sZDkcYDUsZDkYYDUQW - DEQWDD8VDEQWDD8VDD0UCzwUCzoUCzwUCzoUCzYSCjoUCzYSCjMRCTMRCTMRCTMRCTMRCTEQCTAQCTEQ - CTEQCTEQCS4QCTAQCS4QCSwPCCwPCCsOCCsOCCwPCCsOCCkOCCcNByUNByUNBycNByQMByQMByQMByQM - ByILBiILBiQMByILBiALBh8LBh8LBh8LBh8LBhsJBRsJBRoJBRoJBRoJBRgJBRgJBRYHBBMHBBQHBBQH - BBQHBBQHBBMHBBMHBBMHBBEGAxMHBBMHBBEGAxEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FAxEGAw8FAw8F - Aw8FAw8FAw4FAw4FAwwFAw4FAw4FAwwFAwwFAwwFAwwFAwoDAgoDAgoDAgoDAgkDAgkDAgkDAgkDAgkD - AgcDAgkDAgcDAgcDAgcDAgUCAQUCAQUCAQMBAQIBAQIBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAIB - AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////7s9Ibk9Ibg9IbQ7ILE7ILg9IbM7IK86H605H686H6w5 - H6w5H6o4Hqg3HqU3Hqc3HqI2HaI2HZ40HJw0HKA1HZw0HJszHJkyG5cyG5kyG5kyG5cyG5IwGpcyG5Ew - GpIwGo8wGpEwGpEwGo8wGo0uGYsuGYouGYsuGY8wGoMsGIYsGIYsGIErF4ErF4gtGIAqF4MsGH4qF34q - F3ooFnooFnooFn4qF3koFncnFXcnFXQnFXUnFYAqF4ErF3AlFGgjE2sjE2YhEmkjE2YhEmYhEl8fEV8f - EV4fEVoeEFcdEFcdEFcdEFUcD1cdEFUcD1McD04aDk4aDksZDksZDksZDkYYDUkYDUcYDUYYDUIWDEIW - DD8VDDwUCz0UCz0UCz0UCzwUCzgSCjgSCjYSCjMRCTUSCjUSCjUSCjMRCTMRCTAQCTAQCTEQCTAQCS4Q - CS4QCSwPCCwPCCwPCDAQCS4QCSsOCCsOCCkOCCcNByUNByUNByUNByUNByUNByQMByILBiILBiQMByIL - BiALBh8LBh8LBh0KBh0KBhsJBR0KBhoJBRoJBRoJBRoJBRgJBRgJBRQHBBYHBBQHBBQHBBQHBBMHBBMH - BBMHBBMHBBMHBBEGAxEGAxEGAxEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FAw8FAw8FAw8FAw4FAw4FAw4F - Aw4FAw4FAwwFAwwFAwwFAwoDAgoDAgoDAgoDAgwFAwoDAgoDAgoDAgoDAgkDAgkDAgcDAgkDAgcDAgcD - AgcDAgcDAgcDAgUCAQMBAQIBAQIBAQMBAQIBAQMBAQIBAQAAAAAAAAAAAAAAAAIBAQAAAAAAAAIBAQAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////70/Irk9Ibk9Ibs9Ibk9IbQ7ILM7IK86H6w5H686H686H6o4Hq05H6c3Hqc3 - Hqg3HqM2HaM2HaA1HaI2HaA1HZw0HJw0HJkyG5szHJw0HJcyG5cyG5cyG5szHJcyG5kyG5YyG48wGo0u - GY0uGY0uGZIwGo0uGZEwGo8wGo0uGYsuGYgtGIouGYMsGIUsGIMsGIUsGIUsGIAqF34qF4MsGHwpFn4q - F3wpFnooFnUnFXcnFXUnFYMsGIYsGHUnFWsjE2kjE2kjE2YhEmYhEmYhEmQhEmEhElwfEV8fEVoeEFoe - EFcdEFcdEFcdEFMcD1AbD1UcD1AbD1AbD00aDksZDk0aDksZDkYYDUcYDUcYDUQWDEEWDEEWDD0UC0IW - DEEWDD0UCzoUCzgSCjYSCjYSCjYSCjYSCjUSCjMRCTMRCTMRCTEQCTMRCTEQCTAQCSwPCCwPCC4QCS4Q - CS4QCSwPCCsOCCsOCCkOCCcNBycNBycNByUNByUNByUNByQMByILBiQMByQMByILBiALBiALBiALBh8L - Bh0KBhsJBRsJBRsJBRsJBRsJBRoJBRoJBRoJBRgJBRYHBBQHBBYHBBQHBBMHBBMHBBMHBBQHBBMHBBEG - AxEGAxEGAxEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FAw8FAw8FAw8FAw4FAw4FAw8FAw4FAwwFAwwFAw4F - Aw4FAwwFAwoDAgoDAgoDAgoDAgwFAwoDAgoDAgoDAgkDAgkDAgkDAgkDAgcDAgkDAgcDAgcDAgcDAgcD - AgMBAQMBAQMBAQIBAQIBAQMBAQIBAQAAAAIBAQAAAAAAAAIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////7g9Ib0/Irs9Ibs9Ibg9Ibg9IbM7ILM7IK86H7E7ILQ7IK86H6o4Hqg3HqM2Hac3Hqg3Hqc3HqI2 - HaM2HaA1HaA1HZ40HJw0HJw0HJszHJszHJszHJkyG5szHJkyG5YyG5cyG5YyG48wGpcyG4suGY0uGZEw - GpQxG48wGpcyG5IwGo8wGoouGYouGYsuGYsuGYYsGIMsGIMsGIErF4ErF4AqF3ooFnwpFnwpFnkoFnUn - FXQnFYMsGIouGXwpFm8lFGsjE2sjE2sjE20kFG0kFGkjE2MhEmMhEl4fEV4fEVoeEFwfEVgdEFgdEFcd - EFMcD1McD1IbD1McD1AbD1AbD00aDkkYDUYYDUcYDUkYDUcYDUQWDEYYDUQWDEIWDEEWDDwUCzgSCj0U - CzwUCzYSCjgSCjUSCjUSCjUSCjMRCTMRCTMRCTEQCTEQCTAQCS4QCTEQCTAQCTAQCSwPCCwPCCsOCCwP - CCsOCCkOCCkOCCkOCCcNByUNByUNByUNByQMByQMByQMByILBiILBiALBiALBiALBh0KBhsJBR0KBh0K - BhsJBRsJBRoJBRgJBRoJBRoJBRgJBRYHBBQHBBYHBBQHBBMHBBMHBBMHBBMHBBEGAxEGAxEGAxEGAxEG - AxEGAxEGAxEGAxEGAw8FAw8FAw4FAw4FAw8FAw4FAw4FAw8FAw4FAwwFAwwFAwwFAwwFAw4FAwwFAwwF - AwoDAgwFAwwFAwoDAgoDAgkDAgkDAgkDAgkDAgkDAgcDAgkDAgcDAgUCAQcDAgcDAgUCAQMBAQMBAQMB - AQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////70/Irg9Ibg9 - Ibs9IbY8IbM7ILQ7IK86H686H7E7IKw5H605H6o4Hqg3HqU3Hqg3HqU3Hqc3Hqc3HqU3HqA1HaA1HZ40 - HJw0HKA1HZszHJw0HJszHJszHJkyG5kyG5kyG5cyG5cyG5YyG5YyG5EwGpIwGpQxG5YyG5QxG5IwGpQx - G5EwGpQxG40uGY8wGpQxG4ouGY8wGogtGIYsGIYsGIgtGIAqF4ErF4AqF34qF3koFnkoFogtGJEwGn4q - F3cnFXAlFG0kFG0kFG8lFG8lFGsjE2gjE2kjE2QhEmEhEmMhEl8fEVwfEVgdEFoeEFcdEFUcD1cdEFUc - D04aDk4aDk0aDksZDksZDkkYDUsZDkkYDUkYDUcYDUcYDUQWDD8VDEEWDDwUCz0UCzoUCzgSCjYSCjYS - CjYSCjUSCjMRCTUSCjMRCTMRCTMRCTEQCTMRCTEQCTAQCTAQCS4QCSwPCC4QCS4QCSsOCCsOCCkOCCkO - CCcNBycNBycNByUNByQMByQMByQMByILBiQMByQMByILBiALBh8LBh8LBh0KBh0KBh0KBhsJBRoJBRoJ - BRgJBRgJBRgJBRYHBBQHBBYHBBQHBBQHBBMHBBMHBBMHBBMHBBMHBBEGAxEGAxEGAxEGAxEGAxEGAxEG - Aw8FAw8FAw8FAw4FAw8FAw8FAw8FAw8FAw8FAw8FAw4FAw4FAw4FAwwFAwwFAwwFAwwFAwoDAgoDAgoD - AgoDAgoDAgoDAgkDAgoDAgkDAgcDAgkDAgkDAgcDAgUCAQcDAgUCAQMBAQMBAQIBAQIBAQIBAQMBAQMB - AQIBAQIBAQIBAQIBAQAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////74/Irs9Ibs9Ibk9Ibk9IbM7ILQ7 - ILQ7ILQ7IK86H605H6w5H6w5H6w5H686H6c3HqM2Hac3HqI2HaU3HqA1HaI2HaI2HZw0HJszHKU3Hpsz - HJ40HJw0HJw0HJkyG5cyG5szHJszHJw0HJszHJcyG5w0HJkyG5cyG5cyG5YyG5cyG5QxG5YyG5IwGpEw - GpQxG40uGZEwGo8wGo0uGYsuGYgtGIUsGIsuGYgtGIMsGH4qF4AqF4ouGZYyG4UsGHkoFnAlFHImFXQn - FXQnFXQnFW0kFGkjE2kjE2QhEmMhEmEhEl8fEV8fEVoeEFgdEFgdEFcdEFcdEFcdEFcdEFcdEFAbD00a - DksZDksZDkcYDUkYDUcYDUYYDUQWDEEWDEEWDD0UCz0UCzoUCzoUCzgSCjYSCjgSCjgSCjYSCjUSCjYS - CjMRCTMRCTMRCTMRCTMRCTAQCS4QCS4QCS4QCSwPCCwPCCwPCCsOCCsOCCkOCCkOCCUNBycNByUNByUN - ByQMByQMByQMByQMByILBiILBiILBiALBiALBh0KBh0KBh0KBhsJBRsJBRsJBRsJBRoJBRgJBRgJBRYH - BBQHBBYHBBQHBBQHBBMHBBMHBBQHBBQHBBMHBBMHBBEGAxEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FAw8F - Aw8FAw8FAw8FAw8FAw4FAw4FAw4FAw4FAw4FAwwFAwwFAwwFAwwFAwoDAgoDAgoDAgkDAgoDAgoDAgkD - AgkDAgoDAgkDAgkDAgkDAgkDAgcDAgcDAgcDAgIBAQMBAQIBAQIBAQIBAQIBAQIBAQMBAQIBAQIBAQIB - AQAAAAAAAAIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////70/Irs9IbM7ILY8IbY8Ibk9IbY8IbQ7ILE7ILE7ILE7 - IKw5H605H6g3Hqw5H6g3Hqo4Hqo4HqI2HaU3HqU3HqM2HaM2HaI2HaM2HZw0HJw0HJszHKI2HZszHJ40 - HKA1HZszHJw0HJw0HJszHJ40HJkyG540HJszHJcyG5cyG5w0HJszHJYyG5QxG5kyG5YyG5QxG5EwGpIw - Go8wGoouGYouGYYsGJEwGo0uGYgtGIgtGIUsGIgtGJkyG5EwGnwpFnwpFnkoFnkoFncnFXImFW8lFGsj - E2sjE2kjE2YhEmEhEmYhEmMhEl4fEV4fEV4fEVoeEFgdEFcdEFcdEFMcD1IbD1AbD1AbD04aDkkYDUkY - DUcYDUcYDUYYDUQWDEIWDEIWDD8VDD0UCz8VDD0UCz0UCzgSCjgSCjUSCjMRCTMRCTMRCTMRCTUSCjMR - CTMRCTAQCTAQCTAQCS4QCS4QCS4QCSwPCCwPCCsOCCkOCCkOCCkOCCcNByUNByUNByUNByUNByQMByQM - ByALBiILBiILBiALBiALBh8LBh0KBh8LBh8LBh0KBhoJBRsJBRgJBRgJBRgJBRgJBRYHBBYHBBYHBBQH - BBMHBBMHBBQHBBMHBBMHBBEGAxEGAxEGAxEGAxEGAxEGAxEGAw8FAxEGAxEGAw8FAxEGAw8FAw8FAw4F - Aw4FAw8FAw4FAw4FAwwFAwwFAwwFAwwFAwwFAwwFAwoDAgkDAgkDAgoDAgoDAgoDAgkDAgoDAgkDAgkD - AgcDAgcDAgkDAgkDAgcDAgMBAQMBAQIBAQMBAQIBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIB - AQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////70/Irk9Ibs9Ibg9IbY8IbY8Ibs9IbY8IbY8IbE7ILE7IKg3Hq05H7E7IKg3 - Hqo4Hqw5H6U3Hqc3HqM2HaM2HaM2HaI2HaM2HZ40HKM2HZ40HKI2HaA1HZ40HKM2HZw0HKA1HZw0HJ40 - HKA1HaA1HZszHJ40HJszHJszHJszHJszHJszHJszHJw0HJszHJkyG5cyG5QxG5QxG5EwGo0uGZEwGo8w - Go0uGZEwGo8wGoouGYouGYsuGZkyG5YyG4YsGI8wGpszHIYsGHkoFncnFXAlFG8lFG0kFGsjE2sjE2gj - E2QhEmMhEmMhEmEhEl4fEVwfEVoeEFcdEFcdEFcdEFUcD1IbD1IbD04aDk4aDk0aDksZDk0aDkkYDUcY - DUIWDEIWDD8VDEEWDD8VDEEWDD8VDDoUCz0UCzgSCjUSCjgSCjYSCjUSCjUSCjYSCjEQCTEQCTAQCTEQ - CTMRCS4QCS4QCTAQCS4QCSwPCCsOCCkOCCkOCCkOCCcNBycNByUNByUNByQMByUNByILBiALBiILBiIL - BiILBiALBh8LBh8LBh8LBh0KBhsJBR0KBhoJBRoJBRgJBRgJBRYHBBYHBBYHBBYHBBMHBBMHBBMHBBMH - BBMHBBEGAxEGAxMHBBEGAxEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FAw8FAw4FAw4FAw4FAw4FAw4FAw4F - Aw4FAwwFAwwFAwwFAwoDAgoDAgoDAgoDAgoDAgoDAgoDAgoDAgoDAgkDAgkDAgkDAgkDAgcDAgcDAgcD - AgkDAgUCAQMBAQIBAQIBAQMBAQIBAQIBAQIBAQAAAAIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////70/Irs9Ibs9Ibs9Ibs9Ibg9IbQ7ILY8Ibg9IbM7ILE7ILQ7IK05H605H605H6c3Hqo4Hqg3HqM2 - HaU3Hqo4HqA1HaM2Hac3Hqc3Hqc3HqI2HaM2HaI2Hac3HqI2HaM2HaI2HaI2HaM2HaI2HaU3Hpw0HKA1 - HZ40HJw0HKA1HZcyG540HKI2HZszHJkyG5kyG5w0HJcyG5QxG5YyG5cyG5IwGo8wGpEwGpIwGpIwGo8w - GoouGYouGZ40HKc3HpIwGq86H8A/Iqo4HoouGXooFnkoFnQnFXImFXAlFGsjE2sjE2gjE2QhEmQhEmgj - E2MhEmEhEl8fEVoeEFcdEFwfEVUcD1McD1UcD1AbD1AbD04aDk0aDk0aDkkYDUcYDUcYDUcYDUYYDUIW - DEIWDD8VDEEWDD8VDDwUCzoUCzoUCzYSCjYSCjoUCzUSCjMRCTMRCTMRCTEQCTAQCTAQCSwPCDAQCS4Q - CS4QCSwPCCsOCCwPCCsOCCkOCCkOCCkOCCcNBycNByUNByUNByUNByILBiILBiILBiALBiALBiALBh8L - Bh8LBh0KBhsJBR0KBhoJBRoJBRoJBRgJBRYHBBYHBBYHBBYHBBQHBBQHBBQHBBMHBBMHBBEGAxMHBBMH - BBEGAxEGAxEGAxEGAw8FAw8FAw8FAw8FAxEGAw8FAw8FAw4FAw8FAw8FAw4FAw8FAw4FAwwFAwoDAgoD - AgwFAwoDAgoDAgoDAgoDAgoDAgoDAgoDAgoDAgkDAgcDAgcDAgkDAgkDAgcDAgcDAgkDAgUCAQIBAQMB - AQIBAQIBAQIBAQIBAQIBAQAAAAIBAQIBAQIBAQIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////7s9Ibs9Ib0/ - Ir4/Irk9IbQ7ILY8IbM7ILs9Ia86H7M7ILM7IKg3Hqo4Hqc3Hq86H6o4Hqw5H6g3Hqw5H6o4Hqo4HqU3 - Hqc3Hqc3Hqg3Hqc3HqU3HqM2HaU3HqU3HqA1HaM2HaA1Hag3HqI2HaA1Hac3HqA1HaA1HZw0HJszHJw0 - HKI2HaM2HaA1HaI2HZszHJ40HJszHJszHJkyG5kyG5szHJYyG5YyG5QxG5QxG48wGpEwGo0uGZw0HKw5 - H686H8xDJNpPMMpDJKM2HYouGX4qF3koFnQnFXImFXAlFHImFWsjE2kjE2gjE2YhEmYhEmMhEl8fEVoe - EF8fEVwfEVoeEFUcD1cdEFMcD1AbD1cdEFIbD0kYDUsZDkcYDUcYDUcYDUcYDUQWDEIWDEEWDD8VDD8V - DDwUCzgSCjgSCjYSCjoUCzoUCzMRCTMRCTYSCjYSCjMRCTMRCTAQCTAQCS4QCS4QCS4QCTAQCSsOCCwP - CCwPCCkOCCkOCCkOCCkOCCcNBycNBycNByUNByQMByILBiILBiALBiALBiALBh0KBh0KBh0KBh0KBh0K - BhsJBRoJBRoJBRgJBRYHBBgJBRgJBRYHBBQHBBQHBBQHBBQHBBMHBBEGAxMHBBMHBBEGAxEGAxEGAxEG - AxEGAxEGAw8FAxEGAxEGAw8FAw8FAw4FAw8FAw4FAw4FAw4FAwwFAwwFAwwFAwwFAwwFAwoDAgoDAgoD - AgwFAwoDAgoDAgoDAgoDAgkDAgcDAgcDAgkDAgkDAgcDAgcDAgkDAgcDAgMBAQMBAQIBAQIBAQIBAQIB - AQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////70/Irk9Ibk9Ib0/IrY8Ibk9Ibg9 - IbQ7ILk9Ia05H7E7IK05H7M7IKw5H6w5H6o4Hqw5H6o4Hqo4Hqg3Hq05H6g3Hqo4Hqo4Hqc3Hqw5H6I2 - HaU3HqI2HaI2HaU3HqU3HqI2HaI2Hac3HqU3Hqo4HqU3HqU3HqM2HaM2HaM2HaA1HaI2HaM2HaU3HqU3 - HqA1HaM2HZw0HJszHJszHJkyG5kyG5kyG5kyG5kyG5kyG5YyG5IwGpcyG6c3Hr0/IsRBI9tSM95gQ9pP - MLk9IZszHIgtGH4qF3ooFnooFncnFXImFXQnFXAlFGsjE2kjE2YhEmMhEl8fEWEhEl8fEV4fEVcdEFcd - EFcdEFMcD1McD1IbD1IbD04aDk4aDksZDkYYDUkYDUcYDUQWDEQWDEQWDD8VDD8VDDwUCzoUCz8VDDoU - CzoUCzgSCjoUCzUSCjUSCjUSCjMRCTMRCTEQCTEQCTAQCTAQCS4QCS4QCTAQCSsOCCsOCCkOCCsOCCkO - CCcNByUNByUNByUNByUNByQMByILBiILBiALBh8LBiALBiALBiALBh8LBh0KBh0KBhoJBRoJBRoJBRoJ - BRgJBRgJBRgJBRYHBBQHBBQHBBQHBBQHBBMHBBMHBBQHBBEGAxEGAxEGAxEGAxEGAxEGAxEGAw8FAw8F - Aw8FAw8FAw8FAw4FAw4FAw4FAw4FAw4FAwwFAw4FAw4FAw4FAwwFAwoDAgoDAgoDAgoDAgoDAgoDAgoD - AgkDAgkDAgkDAgkDAgkDAgkDAgcDAgcDAgkDAgcDAgUCAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIB - AQIBAQIBAQIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////74/Irs9Ib0/Irk9Ibk9Ibk9Ibk9Ibg9IbM7ILQ7ILQ7 - ILM7ILM7ILE7IKo4Hqo4Hqo4Hqw5H6w5H6w5H605H6w5H686H605H605H6w5H6o4Hqw5H6c3HqM2HaM2 - Hag3Hqc3HqU3Hq05H6w5H6o4Hqc3Hqc3Hqg3HqU3Hqc3Hqw5H6M2Hac3Hqo4Hqc3HqM2HaA1HaI2HaA1 - HZ40HJ40HJw0HJszHJszHJkyG5szHJkyG5kyG5w0HK86H8lCJNpLK91cP+BrUN1cP8pDJKc3Ho0uGYAq - F4ErF34qF3koFnooFncnFXQnFW8lFG0kFGgjE2kjE2QhEmEhEl8fEV8fEVwfEVoeEFcdEFwfEVcdEFMc - D1IbD1AbD1AbD0sZDkkYDU0aDkYYDUcYDUQWDEEWDEEWDEIWDEEWDD8VDD8VDDoUCzgSCjwUCzYSCjYS - CjMRCTMRCTMRCTMRCTEQCTEQCTAQCTAQCS4QCSwPCC4QCS4QCSsOCCsOCCsOCCkOCCkOCCkOCCcNByUN - ByUNByUNByILBiILBiALBiALBiILBiALBh8LBh0KBh0KBh0KBhoJBRoJBRgJBRoJBRoJBRgJBRYHBBYH - BBQHBBQHBBQHBBYHBBMHBBMHBBQHBBMHBBMHBBEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FAw8FAw8FAw4F - Aw4FAw4FAwwFAwwFAwwFAw4FAw4FAwwFAwwFAwwFAwoDAgoDAgoDAgoDAgoDAgoDAgoDAgkDAgkDAgkD - AgkDAgkDAgkDAgcDAgcDAgcDAgUCAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////74/Ir0/Irg9Ibg9Ibg9IbQ7ILY8Ibg9Ibk9IbY8Ia86H7Q7ILQ7IK05H6o4 - Hqw5H605H605H7E7IKw5H605H686H686H6w5H6w5H6o4Hqo4Hqw5H6g3Hq05H605H6g3Hqg3Hqc3Hqg3 - Hqo4Hq86H6w5H6g3Hqo4Hqo4Hqc3Hqc3HqM2HaI2Hao4Hqw5H6o4HqM2HaA1HaM2HaM2HaI2HaI2HZ40 - HJ40HJw0HJ40HJw0HJszHKA1HbY8IdlJKdxXOeBqT+FuVN5iRtlIJ7Q7IJszHI8wGoErF4ErF4AqF34q - F3ooFncnFXUnFW8lFGsjE2gjE2gjE2MhEmMhEmEhEmEhEloeEFgdEFgdEFoeEFUcD1IbD1IbD1IbD1Ab - D04aDk4aDkcYDUYYDUQWDEQWDEIWDEIWDEQWDEQWDD8VDDwUCzoUCzoUCzwUCzgSCjUSCjYSCjMRCTEQ - CTEQCTEQCTEQCTAQCSwPCC4QCSwPCCwPCCwPCCsOCCsOCCsOCCsOCCkOCCkOCCcNByUNByUNByQMByQM - ByILBiALBiALBh8LBh8LBh8LBh8LBh8LBh0KBhsJBRoJBRoJBRoJBRgJBRgJBRgJBRgJBRYHBBQHBBYH - BBQHBBMHBBQHBBMHBBMHBBEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FAw8FAw8FAw8FAw4FAw8FAw4FAwwF - Aw4FAw4FAw4FAwwFAwwFAwwFAwwFAwwFAwoDAgoDAgoDAgoDAgoDAgkDAgkDAgkDAgkDAgkDAgkDAgcD - AgcDAgcDAgcDAgMBAQIBAQIBAQIBAQMBAQMBAQIBAQIBAQIBAQAAAAAAAAIBAQAAAAIBAQIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////70/Ir0/IrY8IbY8Ibk9IbY8IbY8IbY8Ibs9IbY8IbQ7ILE7ILM7IKo4Hqw5H686H6o4Hq05H686 - H605H7E7ILM7ILE7IK86H605H6g3Hqw5H6o4Hqw5H605H7E7IKg3Hqg3Hqg3Hq05H6o4Hqw5H6w5H6o4 - Hq05H605H686H6o4Hqo4Hqg3Hqo4Hqw5H6g3Hqo4Hqw5H6g3Hqg3Hqc3Hqg3HqM2HaM2HaA1HaA1HaA1 - HaA1Hac3Hr0/IttRMt1eQeBoTeFvVd9lStpOLsJAI6g3HpcyG4suGYMsGIErF4ErF4AqF3wpFnooFnoo - FncnFW8lFGkjE2YhEmYhEmEhEl4fEV8fEV4fEV8fEV4fEVcdEFUcD1cdEFIbD04aDlAbD00aDk0aDkYY - DUcYDUYYDUQWDEYYDUcYDUEWDDwUCz0UCzoUCzwUCzwUCzgSCjYSCjUSCjMRCTMRCTMRCTAQCTEQCTAQ - CS4QCS4QCSwPCDAQCS4QCSwPCCsOCCsOCCsOCCsOCCkOCCkOCCQMByUNByUNByUNByQMByILBiILBiAL - BiALBh8LBh0KBh0KBh0KBhsJBRoJBRoJBRoJBRgJBRYHBBYHBBgJBRgJBRYHBBYHBBQHBBMHBBMHBBEG - AxMHBBEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FAw8FAw8FAw8FAw4FAw4FAw4FAw4FAw4FAw4FAw4FAwwF - AwwFAwwFAwwFAwwFAwwFAwkDAgkDAgoDAgkDAgoDAgkDAgkDAgkDAgcDAgkDAgkDAgcDAgcDAgcDAgMB - AQIBAQIBAQIBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////8A/Ir4/Ir0/ - Irs9IbQ7ILk9IbY8Ib0/IrQ7ILk9Ibk9IbQ7ILQ7IK05H686H7M7IK86H7E7ILE7ILE7ILE7ILE7IK86 - H605H6w5H6w5H6w5H605H686H7E7IK86H7E7ILE7IK86H7E7IK86H686H7E7ILE7IK05H6w5H6w5H686 - H605H6o4Hq86H686H7E7IK05H6o4Hq86H605H6c3Hqw5H605H6o4Hqc3HqU3Hqw5H6o4HrE7IMVBI9xY - OuBoTeFuVOJ0W+BoTdxXOdFFJbE7IJw0HJIwGogtGIUsGIYsGIMsGIErF3ooFnooFncnFXUnFXAlFG0k - FGsjE2EhEmYhEmMhEl8fEVwfEVoeEFgdEFcdEFcdEFcdEFUcD1AbD00aDk4aDksZDkkYDUcYDUYYDUQW - DEQWDEIWDD8VDEEWDD0UCzgSCjwUCzgSCjgSCjYSCjYSCjYSCjUSCjMRCTMRCTMRCTAQCTAQCTAQCS4Q - CS4QCS4QCS4QCSsOCCsOCCkOCCkOCCcNByUNByUNByQMByQMByUNByQMByILBiALBiALBh8LBh8LBh0K - Bh0KBhsJBRoJBRoJBRoJBRoJBRgJBRYHBBgJBRYHBBYHBBgJBRQHBBMHBBMHBBMHBBMHBBEGAxEGAxEG - AxEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FAw4FAw4FAw8FAw4FAw4FAw4FAw4FAwwFAwwFAwwFAwwFAwwF - AwoDAgkDAgkDAgoDAgkDAgkDAgoDAgkDAgoDAgkDAgkDAgcDAgcDAgkDAgcDAgMBAQIBAQIBAQMBAQIB - AQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////70/Irg9Ibs9Ibs9Ibk9Ibs9Ibg9 - Ibg9Ibg9IbQ7ILk9Ibk9Ibs9IbQ7ILQ7ILE7ILE7ILM7IK86H7Y8Ia05H605H605H6w5H7Q7ILE7IK86 - H7M7ILY8IbM7IK05H7M7IK05H7M7ILM7IK86H7M7ILQ7ILE7IK86H686H7M7ILE7ILY8Ia86H7E7ILE7 - ILg9IbQ7ILE7IK05H605H6w5H7Q7ILM7IKw5H6w5H605H7E7ILE7ILY8Ic5EJd1eQeFuVOFuVOJyWeBs - Ut5gQ9hHJr0/IqM2HZszHI0uGYouGYYsGIUsGIgtGIAqF4AqF3koFnkoFncnFXImFWsjE2gjE2YhEmQh - EmgjE2EhEloeEFcdEFcdEFgdEFUcD1UcD1McD1AbD0sZDksZDk0aDksZDksZDkcYDUQWDEIWDEEWDD0U - Cz0UCzgSCjoUCzoUCzgSCjYSCjYSCjYSCjUSCjUSCjMRCTMRCTEQCTEQCTAQCTEQCS4QCSwPCCwPCCkO - CCkOCCkOCCkOCCcNBycNByUNByQMByQMByQMByQMByILBiALBiILBh8LBiALBh8LBh8LBh0KBhsJBRsJ - BRgJBRgJBRgJBRoJBRgJBRgJBRYHBBgJBRYHBNXV1P////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////6WkpAMBAQIBAQIBAQMBAQMBAQIBAQAAAAIB - AQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////7k9Ibs9Ib0/Ir0/Irg9Ibk9IbQ7ILQ7ILE7ILQ7ILs9 - IbQ7ILg9Ibg9Ibg9IbM7ILM7ILM7ILE7ILM7IK05H6o4Hq86H6w5H686H7E7ILE7IK86H7Q7ILY8IbY8 - IbE7ILQ7ILQ7ILE7ILM7IK05H7M7ILE7ILM7ILQ7ILM7ILY8Ibg9IbM7ILQ7IK86H7s9Ib0/IrY8IbQ7 - IL0/IrY8IbY8Ibk9IbQ7ILM7ILM7ILY8Ib0/IsJAI9ZGJt9kSOJyWeJyWeN3XuFwV99lStpNLcRBI7E7 - IKI2HZkyG48wGo0uGYouGYgtGIMsGIErF4AqF3wpFnkoFnkoFncnFXAlFG8lFGkjE2kjE2kjE1wfEV8f - EVoeEFgdEFgdEFMcD1IbD1AbD1AbD1AbD04aDk0aDk0aDkQWDEYYDUQWDEQWDEEWDEQWDD8VDDwUCzwU - CzwUCzoUCzgSCjUSCjUSCjUSCjMRCTEQCTEQCTAQCS4QCS4QCS4QCS4QCS4QCSsOCCkOCCkOCCkOCCkO - CCkOCCUNByUNByQMByQMByUNByQMByILBiALBh8LBiALBh8LBh8LBh0KBh0KBh0KBhsJBRsJBRoJBRoJ - BRoJBRgJBRYHBBgJBRYHBF1YV/////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////////////6WkpAMBAQIBAQIBAQMBAQMBAQIBAQAAAAIBAQIBAQIBAQIBAQIB - AQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////74/Ir4/Irg9Ibk9IbY8Ibk9IbY8Ibg9Ibs9Ibg9IbY8IbY8Ibg9IbY8Ibk9 - IbM7ILg9IbE7IK86H7E7ILM7IK86H7E7IK05H7Q7ILM7ILE7ILM7ILY8Ibg9IbM7ILE7ILQ7ILM7ILQ7 - ILM7ILg9Ibk9Ibg9Ibg9Ibs9IbM7ILY8Ibk9IbY8Ibg9IbY8Ibg9Ib4/Ir0/Irk9Ibg9IbQ7ILY8Ibs9 - IbY8IbQ7ILM7ILY8IcJAI8xDJNpNLeBrUON3XuN4YON7Y+N3XuBrUNxXOdNGJrk9Iag3Hp40HJkyG5cy - G40uGY0uGYgtGIgtGIMsGHwpFnooFnkoFnkoFnQnFXAlFG0kFGkjE2kjE2QhEloeEF4fEVwfEVoeEFcd - EFIbD1IbD1McD1McD1IbD0sZDk0aDkYYDUQWDEcYDUYYDUQWDEEWDEEWDEEWDD0UCz0UCzoUCzYSCjUS - CjYSCjMRCTMRCTMRCTMRCTEQCTAQCTAQCTAQCS4QCSwPCCsOCCsOCCkOCCkOCCkOCCkOCCkOCCUNByUN - ByQMByQMByILBiILBiALBiALBiALBh8LBh8LBh8LBh0KBhsJBRsJBRsJBRoJBRgJBRoJBRgJBRYHBBYH - BBQHBBQHBL+9vf////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////6WkpAMBAQIBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////7Y8Ibs9Ibg9Ibk9Ibk9IbY8Ibk9Ibk9Ib0/Ir0/IrY8IbQ7ILQ7ILY8IbY8IbY8IbM7ILY8Ia86 - H7M7ILM7ILM7ILM7ILQ7ILY8IbQ7ILQ7ILg9IbY8Ibg9IbQ7ILg9IbQ7ILY8IbM7ILQ7ILg9Ibs9Ibg9 - Ib0/Irg9Ib0/Ir0/Ir0/Irs9Ibs9Ib4/Irk9IcA/IsVBI8JAI70/Ir0/IrY8Ibs9IcA/Irk9Ibk9IcdC - JM9EJdhHJtxXOeBrUOR8ZeR8ZeN7Y+N7Y+JyWd1eQdlIJ8A/IrQ7IKg3Hp40HJszHJQxG5IwGo0uGYYs - GIUsGIUsGIErF3wpFn4qF3koFnkoFnAlFG8lFG0kFGMhEl4fEV4fEV8fEVoeEFwfEVcdEFMcD1McD1Uc - D1McD0sZDk0aDksZDkcYDUYYDUYYDUYYDUEWDEIWDD0UCzwUCz0UCzwUCzgSCjYSCjMRCTMRCTUSCjMR - CTMRCTMRCTAQCTAQCTEQCS4QCSwPCCwPCCwPCCwPCCsOCCsOCCkOCCUNBycNBycNByUNByQMByILBiIL - BiILBiILBiILBiALBiALBiALBh0KBhsJBRoJBRsJBRoJBRgJBRgJBRgJBRYHBBYHBBQHBBQHBEhDQv// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////6Wk - pAMBAQMBAQIBAQIBAQIBAQIBAQMBAQMBAQIBAQIBAQIBAQAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////70/Ir0/Ir0/ - Ir0/Irk9Ibs9Ibg9Ibk9IbY8Ibg9Ibs9Ibk9Ibg9IbY8IbQ7ILY8Ibk9IbY8IbE7ILQ7ILY8Ia05H7Y8 - IbY8IbY8Ibk9IbY8Ibk9IbY8IbY8Ibg9IbY8Ibg9Ibg9Ibk9IbY8Ib0/Ir0/Irs9IcA/Irs9Ib4/Ir0/ - Ir4/IsA/Ir4/Ir4/Ir4/IsVBI8dCJMVBI8JAI74/IsRBI74/IsdCJMJAI8dCJMxDJNpNLdpPMN1aPOFw - V+WDbeWCbOWDbeR/aOJ1XN9lSttSM8pDJMA/IrM7IKM2HaI2HZw0HJYyG5IwGo0uGYouGYUsGIYsGIEr - F34qF4AqF3koFnUnFXUnFWsjE2gjE2EhEmQhEmEhEloeEFcdEFcdEFcdEFcdEFMcD1IbD1McD00aDk0a - DkkYDUcYDUYYDUYYDUYYDUIWDEEWDD0UCz0UCzwUCzgSCjYSCjYSCjYSCjMRCTMRCTMRCTEQCTAQCS4Q - CS4QCTAQCSwPCCwPCCsOCCsOCCsOCCkOCCkOCCkOCCkOCCkOCCUNByQMByQMByILBiILBiILBiILBiAL - Bh8LBh8LBh8LBh0KBhsJBR0KBhsJBRoJBRoJBRoJBRYHBBgJBRYHBBQHBBQHBLOxsf////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////6WkpAUCAQMBAQIBAQIB - AQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////70/Irs9Ibk9Ib4/Ir0/Irk9Ibg9 - Ibk9Ibg9Ibk9Ib0/IrQ7ILk9Ibs9Ibk9IbM7ILY8IbM7ILk9Ibg9Ibs9Ibk9Ibg9IbY8IbQ7ILs9Ibk9 - Ib0/IrY8Ibk9Ibs9IbY8Ib0/Ir4/Irs9Ib0/Ir0/Ir0/IsA/IsA/IsJAI8A/Ir4/IsRBI8JAI8JAI8VB - I70/IsRBI8dCJMlCJMdCJMRBI8lCJMlCJMxDJM5EJc9EJdFFJdtRMtxYOt5iRuJ0W+aJdOaHcuaFb+WC - bOR8ZeFvVd1bPtlJKcpDJL0/Iq86H605H6g3HqA1HZszHJkyG5EwGo8wGo0uGYYsGIMsGIErF3wpFncn - FXcnFXImFW8lFGQhEmQhEl4fEV8fEVwfEVwfEVoeEFoeEFcdEFAbD1IbD04aDk0aDksZDkcYDUcYDUcY - DUQWDEQWDEIWDD0UCzoUCzwUCzoUCzgSCjoUCzUSCjUSCjUSCjMRCTMRCTEQCTAQCS4QCS4QCS4QCS4Q - CS4QCSwPCCwPCCkOCCkOCCcNBycNByUNByQMByUNByQMByQMByILBiILBiILBiILBiALBh8LBh0KBh0K - BhsJBRsJBRsJBRoJBRoJBRoJBRgJBRgJBRYHBBYHBBQHBDIrKfX19f////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////6WkpAUCAQMBAQIBAQMBAQMBAQMBAQIBAQIB - AQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////7g9Ibs9Ib0/Irs9Ib0/Ir0/Irk9Ibs9Ibs9Ibk9Ib0/ - IrY8Ibk9IbY8IbQ7ILg9IbM7ILQ7ILM7ILY8IbQ7IL0/Irk9Ib0/Irk9Ibs9IbQ7ILs9Ibk9Ibk9Ib0/ - Irk9Ib4/Ir0/Ir4/IsJAI74/Ir0/Ir0/IsJAI8JAI8RBI8dCJMdCJMdCJMpDJMpDJMdCJMdCJMdCJMlC - JMpDJMxDJM9EJc9EJcxDJNZGJtlIJ9pNLdxVN95gQ+BrUOR8ZeeNeeeNeeaHcuaHcuWBauJ0W95gRNtU - NdNGJsdCJL0/IrQ7ILM7IKo4Hqc3HqU3Hp40HJszHJQxG48wGosuGYYsGH4qF3koFnkoFnQnFXImFW8l - FGkjE2YhEmQhEloeEFwfEVwfEVgdEFgdEFUcD1IbD1IbD1IbD00aDk0aDkkYDUkYDUcYDUQWDEIWDEEW - DEEWDD0UCzwUCzgSCjoUCzoUCzgSCjYSCjMRCTUSCjMRCTAQCTAQCTEQCS4QCS4QCTAQCSwPCCwPCCsO - CCkOCCcNByUNByUNByUNByUNByQMByQMByQMByILBiILBiALBiALBh0KBh0KBh8LBh0KBhsJBRoJBRsJ - BRoJBRYHBBgJBRgJBRYHBBYHBBQHBBQHBKelpP////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////////////6WkpAUCAQMBAQIBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAIB - AQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////70/Irk9Ib0/Ir0/Ir0/Ir0/Irs9Ib0/Ir0/Irk9Ibs9Ibs9IbY8IbQ7ILk9 - Ibs9Ibg9IbY8Ibs9Ibk9Ibg9Ibg9Ibg9Ibs9Ib0/Irk9IcA/Irk9Ib0/Ir0/Ir0/Ir4/IsA/Ir4/Irs9 - IclCJMJAI74/IsJAI8RBI8RBI8lCJMdCJMlCJMpDJMxDJM5EJclCJMpDJMpDJNFFJdhHJthHJtlIJ9lI - J9lIJ9pNLdpOLtpPMNxYOuBqT+FwV+R/aOeNeeiRfeeNeeeMd+aHceN5YeBqT91bPtpOLtNGJsRBI70/ - Irg9IbE7IKw5H6o4HqU3HqI2HZszHJkyG5IwGo0uGYYsGIAqF3wpFnkoFnUnFXImFXAlFGYhEmgjE2Mh - EmMhEloeEFcdEFcdEFcdEFIbD1McD1AbD00aDk0aDkkYDUkYDUQWDEQWDEIWDEEWDEQWDD8VDDoUCzgS - CjgSCjgSCjwUCzYSCjUSCjMRCTMRCTEQCTEQCTMRCTAQCTEQCTAQCS4QCSwPCCsOCCkOCCkOCCkOCCcN - BykOCCUNByUNByQMByQMByILBiALBiALBh8LBh0KBh0KBh8LBh0KBhsJBRoJBRsJBRgJBRYHBBgJBRoJ - BRgJBRYHBBQHBBYHBDIrKfX19f////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////6WkpAcDAgMBAQIBAQIBAQMBAQMBAQMBAQIBAQMBAQIBAQAAAAIBAQIBAQIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////8A/Ir4/Ir0/Ir4/Ir0/Ir4/Irs9Ibs9Ib0/Irk9Ibk9Ibk9Ibg9Ibk9Ibk9Ibk9Ib0/IrY8Ibs9 - IbY8Ibg9IbY8Ibs9Ib0/Ir0/Irs9Ib0/Irg9Ib0/Ir4/IsJAI70/IsA/IsJAI8JAI8VBI74/IsVBI8VB - I8dCJMxDJMlCJMlCJMdCJM9EJc5EJc9EJdFFJdZGJthHJtlIJ9hHJtpOLtpLK9pOLtpLK9tUNdxXOd1b - Pt5iRuJyWeN5YeaFb+mXhemXheiSfueNeeeLduR9ZuFwV95gRNtUNdlJKdVGJslCJMA/IrQ7ILM7IK05 - H6U3Hqc3HqM2HaM2HZw0HJcyG5EwGogtGIAqF3wpFnUnFXUnFXQnFW8lFGsjE2kjE2QhEl8fEVwfEVcd - EFcdEFUcD1McD04aDk0aDk0aDkkYDUsZDkcYDUkYDUQWDEYYDUYYDUQWDD8VDDoUCzoUCzUSCjYSCjUS - CjYSCjYSCjUSCjAQCTEQCTEQCTAQCSwPCCwPCCwPCCwPCCsOCCkOCCkOCCkOCCkOCCcNByUNByQMByQM - ByQMByQMByILBiALBiALBh8LBh8LBh0KBh8LBhsJBRoJBRoJBRoJBRYHBBgJBRoJBRgJBRYHBBQHBBYH - BBYHBIyJif////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////6Wk - pAcDAgMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////8JAI70/Ir0/ - Ir4/Ir0/Ir4/Ir0/Irs9Ib0/Irk9Ib0/Irg9Ibs9Ibg9Ibk9Ib0/Irk9IbQ7ILk9Ibs9Ib4/Irk9IbY8 - Ibk9Ib4/Irs9Ib4/Ir0/Ir4/IsJAI8JAI74/Ir0/IsA/IsA/IsVBI8dCJMdCJMlCJMxDJMxDJMpDJNFF - JcxDJNFFJdFFJdZGJthHJtlJKdpNLdpLK9pOLttRMttRMtpPMNtUNdxVN91aPN5gROBqT+N4YOWCbOaH - cumXheqaiOmWg+iSfueNeeaFb+N3XuBrUN1cP9pOLtlIJ9NGJsRBI74/Ir0/IrQ7ILQ7IKw5H6o4Hqc3 - HqM2HZszHJszHJEwGogtGIErF3wpFnkoFncnFXImFW8lFGQhEmMhEmEhEl4fEVgdEFgdEFcdEFUcD1Mc - D00aDk4aDkkYDUkYDUsZDkkYDUcYDUYYDUQWDEEWDEIWDD0UCz0UCzoUCzoUCzUSCjYSCjUSCjMRCTMR - CTAQCTAQCTEQCTAQCS4QCS4QCS4QCSwPCCwPCCsOCCkOCCcNByUNByQMByQMByQMByQMByILBiILBiIL - BiALBiALBh8LBh0KBh0KBhsJBR0KBhsJBRoJBRoJBRgJBRgJBRgJBRYHBBQHBBQHBBYHBBQHBOvq6v// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////6WkpAcDAgMBAQMBAQMB - AQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////74/Ir0/Ir0/IsRBI7s9Ib4/Ir0/ - Ir0/Irs9Ibk9Ib0/Irk9Ibk9Ibg9Ib0/Ir0/Irk9IbQ7ILk9Ibk9Ibs9Ibk9Ib0/Ir4/Ir0/Irk9IcVB - I8A/IsJAI8JAI8JAI8JAI8RBI8A/IsJAI8lCJMlCJM5EJc5EJc5EJc5EJcxDJM9EJdZGJtVGJtZGJtlI - J9pLK9pNLdtRMttRMttRMttUNdxXOdtSM9xYOt1eQd9mS+BrUOFwV+R9ZuaHcuiRfeqciuufjuqZh+mW - g+iSfuaHceR8ZeFvVd1eQdxVN9pLK9NGJs9EJcRBI8VBI7g9Ia86H7Q7ILM7IK05H6c3HqM2HZw0HJcy - G40uGYouGYErF4AqF3koFnkoFnAlFGsjE2kjE2MhEmEhEl4fEVoeEFcdEFcdEFUcD1McD1IbD00aDksZ - DkkYDUkYDUQWDEYYDUEWDD8VDEIWDEEWDD8VDDoUCzoUCzYSCjMRCTUSCjMRCTMRCTEQCTMRCTAQCS4Q - CTAQCS4QCS4QCSsOCCsOCCsOCCkOCCkOCCcNByUNByUNByUNByUNByILBiILBiILBiILBiILBiALBh8L - Bh8LBh0KBh0KBhsJBRoJBRsJBRoJBRgJBRYHBBYHBBYHBBQHBBgJBRYHBH16ef////////////////// - /////////////////////////////8rJyQ4FAw4FAw8FAw4FAwwFAwwFAwwFAw4FAwoDAgoDAgoDAgoD - AgwFAwoDAgoDAgoDAgkDAgkDAgcDAgkDAgkDAgcDAgkDAgkDAgcDAgUCAQMBAQMBAQIBAQIBAQIBAQIB - AQIBAQIBAQAAAAIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////70/IsJAI8A/IsJAI8A/Ir0/Irk9Ib0/Irk9Ibs9Ib0/ - Irs9Ib0/Ir0/Ir0/Irs9Ib0/IrY8Ibk9Ibg9Ib0/Irs9Ib0/Ir4/Irs9Ib0/Ir0/IsJAI8JAI8A/IsVB - I8dCJMxDJMdCJMlCJM5EJcxDJMxDJMpDJM5EJdNGJtFFJdNGJtZGJtpLK9pLK9pOLtpPMNpOLttSM9xY - Ot1aPN1eQd1cP91cP91eQd5iRuBrUOFwV+N4YOWDbeeNeemTgOufjuyklOufjumXhemVgueLduWCbOJ0 - W+BoTd1cP9tSM9lIJ9VGJsxDJMlCJMA/Irs9Ibg9IbQ7ILE7IKw5H6M2HaM2HZ40HJkyG5cyG40uGYUs - GH4qF3UnFXcnFW8lFGYhEmgjE2EhEl8fEVwfEVoeEFcdEFUcD1McD1IbD1IbD00aDksZDksZDkkYDUYY - DUIWDEIWDD8VDD0UCz0UCz0UCzoUCzgSCjYSCjYSCjUSCjMRCTMRCTMRCTEQCTEQCTAQCTAQCTAQCSwP - CCsOCCkOCCcNBysOCCsOCCUNByUNByUNByUNByQMByILBiILBiILBiALBiALBh8LBh8LBh8LBh8LBhoJ - BRoJBRoJBRgJBRoJBRgJBRYHBBQHBBQHBBYHBBQHBBMHBNXV1P////////////////////////////// - /////////////////2xpaA4FAw4FAw4FAw4FAwwFAwwFAw4FAwwFAwwFAwwFAwwFAwwFAwoDAgoDAgkD - AgkDAgkDAgkDAgoDAgkDAgkDAgcDAgkDAgcDAgUCAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQAAAAAAAAAA - AAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////74/IsRBI74/Ir0/IsRBI70/Irk9Ib0/Ir0/Ir0/Ir0/Ir0/Ir0/Irk9Ibs9 - Ibk9Ib0/Irs9Ibs9Ib0/Ir4/Ir4/IsA/Ir0/Ir4/Ir4/Ir0/IsRBI8RBI8VBI8dCJMxDJMlCJMdCJMRB - I8xDJM5EJdFFJc5EJdZGJtZGJtlIJ9VGJtpLK9pPMNpNLdtUNdxVN9xYOtxYOt1bPt1bPt1cP95iRuBo - Td9lSuBqT+FuVOR8ZeR/aOeLduiRfemWg+yike2omeyikeuejOqaiOmTgOaHcuR8ZeFuVN9mS91bPttR - MtlIJ9NGJs9EJclCJL0/IsRBI7s9IbQ7ILQ7IKw5H6M2HZ40HJszHJszHJIwGosuGYMsGHkoFnkoFnIm - FW0kFGgjE2gjE18fEVwfEVoeEFcdEFgdEFUcD1McD00aDk4aDksZDk0aDk0aDkcYDUQWDEQWDEEWDD0U - Cz8VDD0UCzoUCzoUCzgSCjUSCjYSCjUSCjMRCTMRCTMRCTEQCTEQCTAQCS4QCS4QCSwPCCwPCCsOCCsO - CCcNBysOCCcNByUNByUNByQMByQMByILBiILBiALBh8LBh8LBh8LBh0KBh0KBhsJBRoJBRoJBRgJBRoJ - BRgJBRYHBBYHBBYHBBYHBBMHBBMHBG1qaf////////////////////////////////////////////// - /9XU1A4FAw4FAw4FAw4FAwwFAw4FAw4FAwwFAwwFAwoDAgoDAgwFAwoDAgoDAgoDAgoDAgkDAgkDAgoD - AgkDAgkDAgcDAgkDAgcDAgUCAQMBAQIBAQIBAQMBAQIBAQMBAQIBAQIBAQIBAQIBAQAAAAIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////8lCJMVBI8RBI70/Ir4/IsRBI74/Ir0/Ir0/Ir0/Ir0/Irk9Ibk9Ib0/Ir4/Ir0/Ir0/Ir0/Ir0/ - Ir4/Ir4/Ir0/IsVBI8JAI8A/IsRBI70/IsdCJMdCJMVBI8VBI8dCJMxDJM5EJc5EJdNGJtZGJtlIJ9lI - J9lJKdlIJ9hHJtlJKdpOLttSM9xYOt1cP9xYOtxXOd1eQd1cP95gQ99kSN9lSuBsUuBsUuFvVeN3XuR9 - ZuaHceeMd+mWg+uejOyklO6sneymluyklOufjumXheaJdOWDbeN4YOBsUt5gRNxVN9pOLtpNLdlIJ89E - JcpDJMJAI70/Ir0/Irk9Ia86H6g3HqA1HaA1HZw0HJszHJEwGoYsGIAqF3koFnQnFW0kFG0kFGsjE18f - EV4fEVgdEFwfEVcdEFUcD1IbD1IbD04aDk0aDksZDkcYDUYYDUQWDEQWDEIWDD8VDEEWDDoUCzwUCzwU - CzUSCjYSCjYSCjUSCjUSCjMRCTUSCjMRCTAQCTAQCS4QCS4QCSwPCCwPCCkOCCsOCCkOCCkOCCkOCCcN - BycNByQMByQMByILBiQMByALBh8LBh8LBh8LBh8LBh8LBhsJBRoJBRsJBRoJBRgJBRgJBRYHBBgJBRYH - BBQHBBMHBBMHBBQHBNXV1P///////////////////////////////////////////////2xpaA4FAw4F - Aw4FAwwFAwwFAw4FAwwFAwwFAwoDAgoDAgoDAgwFAwwFAwoDAgoDAgoDAgkDAgkDAgkDAgkDAgkDAgkD - AgkDAgcDAgMBAQMBAQMBAQIBAQIBAQMBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////8JAI8dCJMlC - JMdCJMpDJMRBI74/Ir4/Irs9Ib0/Ir0/Irk9IbY8Ib0/Irs9Ib4/Ir0/Ir0/Ir4/IsJAI70/Ir0/IsJA - I70/IsJAI74/IsVBI8JAI8dCJMlCJMpDJM5EJcxDJNFFJdFFJdVGJtFFJdZGJtZGJthHJtlJKdpOLtpO - LttUNd1aPNxYOt1bPt1cP95gQ95gRN9kSOBoTeBqT+BrUOJyWeN7Y+N4YON5YeaHcueMd+mWg+qciuyi - ke2omO+ypO6uoOymluyklOufjuiSfuaHcuN7Y+JyWeBqT99kSNxVN9pPMNpOLtlIJ85EJcpDJMRBI8JA - I70/IrE7IK05H6c3HqU3Hpw0HJszHJcyG40uGYYsGH4qF3wpFnImFWsjE20kFGQhEmQhEl4fEVgdEFcd - EFgdEFIbD1McD1IbD04aDk0aDksZDkkYDUYYDUIWDEQWDEIWDEQWDEEWDD8VDDwUCzgSCjYSCjUSCjUS - CjUSCjMRCTMRCTEQCTAQCTAQCS4QCSwPCCsOCCwPCCwPCCsOCCsOCCcNBykOCCcNByUNByUNByQMByIL - BiILBiALBiALBh8LBh0KBh8LBh8LBhsJBRsJBRsJBRoJBRgJBRgJBRYHBBYHBBYHBBQHBBQHBBQHBBQH - BEhDQv///////////////////////////////////////////////+vq6g4FAw4FAw4FAw4FAwwFAwwF - AwwFAwwFAwwFAwwFAwoDAgoDAgoDAgoDAgoDAgoDAgkDAgkDAgkDAgkDAgkDAgcDAgkDAgcDAgMBAQIB - AQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////8RBI70/IsJAI8dCJMJAI8dCJMRB - I8VBI70/Ir4/Ir4/Ir0/Irk9Ib4/Irk9Ib0/Ir4/Ir0/Ir0/Ir4/Ir4/IsJAI8JAI8RBI8JAI8RBI8VB - I8VBI8RBI8JAI8lCJMxDJMpDJNFFJdVGJtVGJtlJKdVGJtlIJ9pOLtpOLtpNLdtSM9xVN91aPN1eQd5g - RN9mS99mS99mS+BrUOBrUOBrUOFwV+J1XON7Y+WBauaFb+aHcumTgOqaiOyike2omO2qm++zpe+ypO6u - n+2qm+yklOqZh+iPe+WDbeR8ZeFvVeBoTd1eQdxVN9tUNdlIJ9ZGJs9EJcpDJMRBI74/Ir0/IrY8Ia86 - H6w5H6I2HZkyG5kyG5YyG48wGoUsGH4qF3ImFXAlFGsjE2gjE2MhEl4fEVwfEVoeEFcdEFMcD1UcD1Ab - D1IbD00aDkkYDUsZDkYYDUQWDEYYDUQWDEEWDD8VDEEWDD8VDDoUCzYSCjYSCjUSCjYSCjUSCjMRCTMR - CS4QCTAQCSwPCDAQCS4QCS4QCSsOCCkOCCkOCCcNBykOCCkOCCQMByQMByQMByQMByILBiALBiALBh8L - Bh8LBh0KBhsJBR0KBhsJBRsJBRoJBRoJBRoJBRYHBBYHBBQHBBYHBBYHBBQHBBQHBBMHBL69vf////// - /////////////////////////////////////////4uJiA4FAw4FAw4FAw4FAwwFAwwFAwwFAwoDAgoD - AgoDAgoDAgoDAgoDAgoDAgkDAgkDAgoDAgkDAgkDAgkDAgcDAgcDAgcDAgMBAQMBAQMBAQIBAQMBAQIB - AQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////8JAI74/IsJAI8RBI8lCJMRBI70/IsJAI8dCJMdCJMA/ - Ir4/IsJAI8JAI8A/IsA/Ir0/Irs9IcJAI74/Ir4/IsA/IsRBI8RBI8RBI8dCJMlCJMxDJMlCJMVBI85E - JdNGJtNGJtlJKdlIJ9ZGJtpLK9pLK9pOLtpOLtpOLtxXOdxVN91eQd5gRN9lSt9kSN9lSuBqT+BsUuBs - UuFvVeJyWeN5YeR8ZeWBauaJdOeLduiSfuqaiOugj+2omO6un++wovC5rPC3qu+zpe+wou2omOyjk+mW - g+eMd+WDbeJ0W+FuVN9mS95iRt1aPNtUNdpOLtlJKc9EJcVBI8RBI8JAI70/IrQ7ILE7IKc3HqA1HZw0 - HJQxG5QxG48wGoMsGHkoFnQnFXImFW8lFGkjE18fEVwfEVwfEVgdEFgdEFUcD1AbD1IbD1AbD00aDkkY - DUcYDUYYDUYYDUQWDEEWDD8VDDwUCzwUCzwUCzgSCjoUCzYSCjUSCjYSCjUSCjMRCTMRCTAQCS4QCS4Q - CTAQCS4QCSwPCCwPCCkOCCcNBysOCCcNByUNByUNByUNByQMByILBiALBh8LBh0KBh0KBh0KBhsJBR0K - BhoJBRoJBRoJBRoJBRgJBRYHBBgJBRYHBBYHBBYHBBQHBBQHBBQHBEdDQf////////////////////// - /////////////////////////+vq6i8qKA8FAw4FAwwFAwwFAwoDAgwFAwoDAgoDAgwFAwwFAwwFAwoD - AgkDAgkDAgkDAgoDAgkDAgcDAgcDAgcDAgcDAgcDAgMBAQMBAQIBAQIBAQMBAQMBAQIBAQIBAQIBAQIB - AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////8RBI8A/IsJAI74/Ir0/IsA/Irs9Ib4/IsA/IsA/IsdCJMVBI8RBI8A/IsRB - I70/IsA/Ir4/Ir4/IsA/IsA/IsJAI8JAI8RBI8RBI8lCJMdCJMpDJMlCJM5EJdFFJdFFJdNGJthHJtZG - JthHJtpLK9pOLttSM9pPMNtRMt1aPN1bPt1eQd5gQ99lSt9mS+BsUuFuVOFwV+FvVeJ1XON3XuR8ZeWD - beaHcuiPe+mTgOmXheugj+ymlu6un++zpfC2qfG9sfG8sPC5rPC5rO+wou2omeugj+mWg+eMd+WDbeN5 - YeFwV+BqT99kSN1cP9xXOdpOLtlJKdNGJsxDJMlCJMRBI74/Ir4/Irg9IaI2HaA1HZw0HJYyG40uGYgt - GH4qF3QnFXUnFW8lFGgjE2EhEl8fEV4fEVwfEVcdEFMcD1McD1IbD1AbD04aDk0aDksZDkYYDUQWDEQW - DEIWDEIWDEEWDEIWDDoUCzwUCzoUCzgSCjYSCjMRCTUSCjMRCTMRCS4QCTAQCTAQCTEQCTAQCSsOCC4Q - CSkOCCkOCCkOCCkOCCUNByQMByUNByQMByQMByQMByALBh8LBh0KBh0KBhsJBR0KBhsJBRsJBRsJBRoJ - BRgJBRYHBBgJBRYHBBYHBBYHBBQHBBQHBBMHBBEGA6elpP////////////////////////////////// - /////////////6alpA8FAw8FAw4FAwwFAwoDAgoDAgwFAwoDAgoDAgoDAgoDAgoDAgoDAgkDAgkDAgkD - AgcDAgcDAgcDAgkDAgkDAgcDAgMBAQMBAQIBAQIBAQIBAQIBAQMBAQIBAQIBAQIBAQAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////74/IsJAI8JAI70/Ir4/IsJAI8JAI8JAI74/Ir0/Ir4/IsJAI8JAI8VBI8lCJMxDJMVBI8VBI8dC - JMA/IsdCJMRBI8A/IsRBI89EJc5EJcdCJMVBI8lCJM9EJdFFJc9EJdVGJtVGJtlIJ9pNLdpOLtpOLtpN - LdpPMN1aPN5gRN5gQ91eQd9kSOBrUOBrUOFvVeFvVeJyWeJ0W+N5YeR/aOaHcuaHcuiPe+mVguuejOyj - k+2omO+wovC2qfG6rvK/s/LBtvLDuPLAtfLBtvC3qu+wouyklOufjumVguaJdOWBauN4YOJyWeBrUN9m - S95iRtxXOdpOLtlIJ89EJcpDJMlCJNVGJtpOLs5EJa05H6M2HZ40HJkyG5szHJEwGosuGX4qF3koFnQn - FWsjE2gjE2MhEmEhEl4fEVgdEFcdEFMcD04aDk4aDk0aDk0aDksZDkkYDUkYDUQWDEIWDEEWDD8VDD8V - DD0UCzwUCzwUCzgSCjgSCjUSCjMRCTMRCTAQCTAQCTMRCTAQCTAQCTAQCSsOCCsOCCkOCCcNBykOCCsO - CCcNByUNByUNByILBiILBiILBiILBiILBh8LBh0KBh0KBh8LBh0KBhsJBRsJBRoJBRgJBRoJBRgJBRYH - BBYHBBYHBBYHBBYHBBMHBBEGAzIrKfX19f////////////////////////////////////////////X1 - 9S8qKA4FAw4FAw4FAwwFAwwFAwwFAwwFAwoDAgkDAgkDAgkDAgoDAgkDAgkDAgkDAgkDAgkDAgcDAgkD - AgkDAgcDAgMBAQIBAQMBAQIBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////8dCJMRBI8dC - JMJAI8RBI74/IsA/IsA/IsRBI8RBI70/Ir4/IsJAI8JAI8JAI8VBI8JAI8RBI8xDJMpDJMVBI8RBI8pD - JMdCJMJAI8lCJMlCJMxDJMxDJM9EJdNGJs9EJdhHJtpLK9hHJtpNLdpLK9pPMNpPMNtRMtxXOd5gRN1e - Qd9lSuBqT+FvVeJyWeFwV+J1XON5YeR8ZeWBauaFb+eLdumWg+mXheufjuyklO6sne+wovC5rPG9sfLB - tvLDuPPFuvPHvfPFuvLDuPG9sfC3qu+wou2omOqciumWg+eMd+WCbON5YeFuVOBsUt9lSt1bPttSM9pO - LtlIJ9FFJdZGJtpOLtxVN9lJKbg9Iac3HqI2HZszHJszHJYyG5EwGoErF3wpFncnFXQnFXAlFGsjE2gj - E18fEVwfEVoeEFcdEFUcD1IbD1AbD04aDk0aDksZDkkYDUQWDEYYDUIWDD8VDD8VDD8VDDoUCzgSCjYS - CjgSCjYSCjUSCjMRCTMRCTUSCjEQCTAQCTAQCS4QCSwPCC4QCSsOCCsOCCcNBysOCCcNByUNByQMByIL - BiQMByILBiILBiALBh8LBiALBiALBh8LBh8LBh0KBhsJBRsJBRoJBRoJBRgJBRgJBRYHBBQHBBMHBBQH - BBMHBBMHBBMHBKalpP///////////////////////////////////////////////6alpA4FAw4FAw4F - AwwFAw4FAw4FAwwFAwwFAwoDAgoDAgoDAgoDAgoDAgkDAgkDAgkDAgkDAgkDAgkDAgcDAgcDAgMBAQMB - AQIBAQMBAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////8dCJMVBI8dCJMRBI74/IsRBI74/ - IsJAI8A/IsA/IsRBI8RBI8A/IsJAI74/IsVBI8RBI8pDJMpDJMlCJMlCJM9EJclCJMpDJMlCJM5EJcxD - JM5EJcxDJM5EJc9EJdNGJthHJtpLK9lJKdpOLttRMttUNdtUNdtUNd1bPt9kSN9lSuBqT+FuVOFuVOJ1 - XON4YOR8ZeR/aOWDbeaHcuiPe+mVguqZh+ufjuyklO6sne+zpfG9sfG9sfLDuPPFuvPHvfTKwfXNxPTJ - v/TKwfLDuPG9sfC3qu6un+yklOufjumVgueLduaFb+N7Y+JyWeBrUN5gRN1bPtxVN9lJKdlIJ9ZGJtlJ - KdpNLcxDJLQ7IKo4Hqo4HqI2HZw0HJYyG5EwGoYsGH4qF3cnFXUnFXAlFG8lFGgjE2QhEl8fEV4fEVcd - EFcdEFAbD1AbD00aDk4aDksZDk0aDkcYDUcYDUIWDEEWDEEWDD0UCzoUCzgSCjgSCjgSCjYSCjUSCjUS - CjMRCTMRCTMRCTAQCTAQCS4QCTAQCS4QCSwPCCsOCCkOCCkOCCcNByUNByUNByILBiILBiQMByILBiAL - BiALBh8LBh0KBhsJBRsJBRsJBRoJBRsJBRoJBRgJBRYHBBYHBBQHBBQHBBQHBBQHBBEGAxMHBBMHBBEG - A+vq6v///////////////////////////////////////////////0ZCQQ4FAwwFAwwFAwwFAwwFAwwF - AwwFAwoDAgoDAgoDAgoDAgkDAgkDAgkDAgkDAgkDAgcDAgcDAgkDAgcDAgMBAQMBAQIBAQMBAQMBAQIB - AQMBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////8RBI8RBI8VBI8JAI8JAI8JAI8A/IsRBI8dCJMRBI8RB - I8VBI8JAI8VBI8RBI8JAI8RBI8JAI8VBI8RBI8VBI8VBI85EJdNGJtFFJc9EJcpDJMxDJNVGJtZGJtVG - JtVGJtZGJtlIJ9pNLdtSM9xVN9xVN9xXOd1bPt5gQ99kSOBoTeFuVOJyWeN5YeR9ZuWBauR/aOWCbOeL - duiSfumWg+qciuqaiOyklO2qm++zpfG8sPLAtfPFuvTJv/TKwfXPxvXPx/bUzPXRyfbTy/PHvfTJv/K/ - s/C2qe6un+yklOuejOmTgOeMd+aFb+R8ZeFvVeBoTd5gRNxYOtpPMNlJKdNGJtNGJspDJL0/IrM7IKc3 - Hqg3HqI2HZ40HJszHJQxG40uGYAqF34qF3QnFXUnFXImFWgjE2EhEmQhEl4fEVwfEVcdEFUcD1McD1Ib - D1AbD04aDkkYDU0aDkcYDUYYDUIWDEEWDDoUCzwUCzwUCzoUCzoUCzYSCjMRCTMRCTMRCTAQCTEQCTAQ - CTEQCTAQCSwPCCwPCCsOCCkOCCkOCCcNBykOCCUNByQMByQMByUNByQMByILBiILBiILBh0KBhsJBRsJ - BRoJBRsJBRoJBRsJBRgJBRgJBRgJBRgJBRQHBBQHBBQHBBQHBBMHBBMHBBMHBBEGA4uJiP////////// - /////////////////////////////////////769vQ4FAw4FAwwFAwwFAwoDAgoDAgwFAwoDAgoDAgkD - AgkDAgkDAgkDAgcDAgcDAgkDAgkDAgcDAgkDAgcDAgMBAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIB - AQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////8dCJMlCJMpDJMpDJL4/IsRBI8RBI70/Ir4/IsRBI74/IsVBI8RBI8VBI8JA - I8VBI8VBI8VBI8dCJMlCJMVBI8dCJMdCJMVBI8xDJNFFJdNGJtNGJtZGJtNGJtFFJdZGJthHJtpLK9pO - LtpPMNxVN9tSM91bPt9lSuBoTeBsUuFuVON3XuJ1XOR8ZeR/aOWBauaHcueNeeiPe+mWg+qciuyklO2o - me6sne+0p/G8sPLBtvPFu/TKwfXRyfbTy/bUzPfX0Pfa0/fZ0vfZ0vbTy/XPx/PFuvK/s/C2qe6uoOym - luqaiOiSfuaHcuWBauN5YeBsUuBqT91eQd1aPNpOLtZGJs5EJcVBI70/Irk9Ia86H6w5H6M2HaI2HaA1 - HZkyG5EwGoUsGH4qF3ooFncnFXQnFWsjE2gjE2QhEl8fEV4fEVcdEFcdEFUcD1IbD1AbD04aDksZDk0a - DkkYDUkYDUQWDEIWDD8VDD0UCz8VDDgSCjgSCjYSCjUSCjYSCjMRCTMRCTEQCTAQCTEQCS4QCS4QCS4Q - CSwPCCsOCCkOCCsOCCkOCCUNBycNByUNByUNByQMByILBiALBh8LBh0KBh0KBh8LBh0KBhoJBRoJBRsJ - BRoJBRgJBRgJBRYHBBYHBBQHBBQHBBYHBBQHBBMHBBMHBBEGAxEGA+vq6v////////////////////// - /////////////////////////0ZCQQ4FAwwFAwwFAwwFAwoDAgoDAgoDAgkDAgkDAgoDAgkDAgkDAgkD - AgkDAgkDAgkDAgkDAgkDAgkDAgMBAQMBAQIBAQMBAQMBAQMBAQIBAQMBAQIBAQIBAQIBAQIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////8lCJMpDJMdCJMdCJMlCJMdCJMdCJMdCJMJAI8VBI8dCJMlCJMpDJMRBI8JAI8JAI8VBI8dCJMlC - JMVBI8VBI8pDJMlCJMpDJMxDJMxDJM5EJc5EJdhHJtpOLtlJKdpLK9pOLtpOLttUNdtSM91aPN1cP95g - Q+BoTeBqT+FvVeJ0W+N5YeR9ZuR9ZuWDbeaHcueMd+iRfeqZh+ufjuyklO2qm+6uoO+0p/C5rPLDuPTJ - v/XPx/bUzPfX0Pfa0/jb1fje2Pni3fjg2vjg2vjb1ffX0PXRyfTJv/K/s/C5rO+wou2omOqciumTgOaJ - dOWCbON4YOFuVN9mS95gQ9tSM9pLK9NGJspDJMVBI7s9IbQ7IK86H6o4Hqc3HqI2HZszHJIwGoouGX4q - F3ooFnkoFnAlFG8lFGgjE2MhEl4fEV8fEV4fEVgdEFUcD1UcD1UcD1IbD1AbD04aDksZDkYYDUcYDUYY - DUEWDEEWDDwUCz0UCzoUCzgSCjUSCjYSCjUSCjMRCTMRCTEQCTAQCS4QCTAQCS4QCS4QCSsOCCsOCCsO - CCkOCCkOCCUNByUNByUNByUNByQMByILBiALBh8LBiALBh8LBhsJBRsJBRsJBRsJBRsJBRgJBRgJBRYH - BBYHBBYHBBQHBBYHBBMHBBMHBBMHBBMHBBEGA2xpaP////////////////////////////////////// - /////////9XU1A4FAw4FAwwFAwwFAwwFAwwFAwwFAwoDAgoDAgoDAgkDAgkDAgkDAgkDAgkDAgkDAgkD - AgkDAgkDAgMBAQMBAQMBAQMBAQIBAQIBAQMBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////8dCJMdCJMRB - I8pDJMpDJMRBI8VBI8dCJMxDJM5EJcpDJM5EJclCJMJAI8dCJMVBI8pDJMVBI8pDJMVBI8lCJMlCJMVB - I85EJdFFJcxDJMpDJNNGJtVGJtFFJdlJKdpLK9pPMNxXOd1eQd1eQd1eQd5gRN9lSt9kSOBsUuFvVeR8 - ZeN7Y+R8ZeWDbeaHceaJdOiSfuqaiOqciuyklO2qm++ypPC5rPG8sPLBtvTLwvXPx/bUzPfa0/jd1/jg - 2vnh3Pni3frn4/nk3/rm4fjg2vjg2vfX0PXRyfTKwfLBtvC5rO6un+yklOufjumTgOaHcuWBauJ1XOBs - Ut9lSt1cP9tRMtpLK9NGJspDJMA/Ir0/Irg9Iaw5H6c3HqA1HZ40HJYyG4suGYUsGH4qF3koFnUnFXAl - FGkjE2gjE2MhElwfEVwfEVcdEFUcD1IbD1McD04aDlIbD04aDksZDksZDkkYDUYYDUQWDEQWDEIWDD0U - CzYSCjgSCjgSCjYSCjYSCjEQCTEQCTEQCTEQCTEQCTAQCS4QCSwPCCsOCCsOCCwPCCcNBykOCCcNByQM - ByQMByALBiALBiALBiALBiALBiALBh0KBh0KBhsJBRoJBRoJBR0KBh0KBhgJBRYHBBYHBBYHBBYHBBQH - BBMHBBMHBBEGAxEGAxMHBBEGA9XU1P///////////////////////////////////////////////2tp - aAwFAwwFAwwFAwwFAwoDAgoDAgoDAgoDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgcDAgcDAgcDAgUCAQMB - AQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////8lCJMlCJMdCJMlCJMxDJMpDJMVB - I8VBI8VBI8pDJMdCJMlCJMlCJMpDJMdCJMlCJMlCJM5EJcxDJMlCJM9EJcxDJM5EJcpDJNNGJs5EJcxD - JNFFJdhHJtlIJ9pNLdpOLtpPMNxYOt1cP99kSOBoTeBrUOBrUOBrUOFvVeJyWeN3XuR9ZuaHceaHcueM - d+iRfemVguqciuymlu2qm+6uoPG6rvG8sPPFuvTLwvbTy/fX0Pjd1/jg2vrm4frm4fvq5vro5Pvs6Pvs - 6Pvs6Prn4/rn4/ni3fjb1fbVzvTLwvLDuPG6ru6un+yklOqaiOiSfuaHcuR9ZuJyWeBoTd5gQ9xXOdpP - MNhHJs5EJcVBI70/Irk9Ia86H6g3HqI2HaA1HZkyG5QxG4YsGIAqF3wpFnkoFnQnFWkjE2YhEmYhEl8f - EVoeEFgdEFcdEFIbD1McD1McD1AbD1IbD1AbD0sZDkkYDUYYDUQWDEIWDEEWDEEWDD0UCzoUCzgSCjYS - CjYSCjUSCjEQCTEQCTAQCTAQCTEQCSwPCCwPCCsOCCsOCCsOCCkOCCkOCCcNByUNByQMByILBiALBiIL - BiALBiALBh0KBh8LBhsJBRsJBRsJBRsJBRoJBRoJBRYHBBYHBBYHBBQHBBYHBBQHBBMHBBEGAxMHBBMH - BBMHBBEGA2xpaP///////////////////////////////////////////////9XU1AwFAwwFAwwFAwwF - AwoDAgoDAgoDAgoDAgoDAgkDAgkDAgkDAgoDAgkDAgkDAgkDAgkDAgkDAgUCAQMBAQMBAQMBAQMBAQIB - AQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////8lCJMpDJMxDJMpDJMlCJMdCJMVBI8VBI8dCJMVBI8VB - I8lCJMVBI8lCJMxDJMdCJMxDJMxDJM9EJdZGJs5EJc5EJdFFJdVGJs5EJc5EJdFFJdNGJthHJtlIJ9pL - K9pPMNtSM91aPN1eQd5gRN9lSuFvVeJ0W+N3XuJ0W+R8ZeR/aOWDbeeMd+eMd+iSfumXheuejOyklO2o - me+ypPC5rPLAtfPFuvXPxvXPx/fa0/je2Pnh3Prm4fvs6Pvs6fvs6fvu6/vu6/vu6/vu6/vs6fvs6fvq - 5vnk3/je2PfX0PXNxPLDuPC3qu6un+yikeqciuiPe+WDbeN5YeFvVd9lSt5gRNxVN9pOLthHJsxDJMA/ - Irk9IbQ7IKw5H6c3HqI2HZ40HJcyG40uGXwpFnkoFnUnFXImFW8lFGsjE2YhEl8fEWEhElcdEFgdEFcd - EFMcD1IbD04aDk0aDksZDkkYDUcYDUcYDUYYDUIWDD8VDD8VDEEWDDwUCzwUCzYSCjYSCjYSCjMRCTMR - CTEQCS4QCTAQCS4QCTAQCS4QCS4QCSkOCCkOCCcNBycNByUNByUNByQMByALBiQMByALBiILBiILBh8L - Bh0KBhsJBR0KBhsJBRsJBRgJBRYHBBYHBBYHBBQHBBYHBBYHBBQHBBEGAxEGAxMHBBMHBBEGAxEGA8rJ - yf///////////////////////////////////////////////4qJiA4FAwwFAwwFAwwFAwwFAwoDAgkD - AgkDAgoDAgkDAgkDAgkDAgkDAgkDAgkDAgcDAgcDAgUCAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIB - AQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////8pDJMlCJMxDJMlCJMlCJMlCJMRBI8VBI8dCJMdCJMlCJMJAI8VBI8dCJMVB - I8JAI8pDJMxDJM9EJcdCJMpDJM9EJc9EJdFFJdVGJtVGJthHJtpNLdpOLtpOLttSM9pPMNxVN91aPN5g - RN5gRN9kSOBsUuFuVOJyWeN7Y+WDbeaJdOeLduiPe+mTgOmWg+qciuyklO2omO+wovC3qvK/s/PFuvXP - xvbTy/fa0/jg2vnk3/ro5Pvs6Pvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vs6Prn4/jg2vfZ - 0vTKwfLBtvC2qe6sneyikemWg+eMd+WBauN3XuBsUt9mS95gQ9tUNdpNLdVGJslCJMRBI7s9IbM7IK86 - H6g3HqA1HZYyG4gtGH4qF3ooFnUnFW8lFG8lFG0kFGQhEl8fEVwfEVwfEVgdEFcdEFMcD1IbD1IbD1Ib - D00aDksZDk4aDksZDkYYDUQWDEQWDEEWDD8VDD0UCzoUCzYSCjgSCjUSCjMRCTMRCTMRCTMRCS4QCTAQ - CTAQCSwPCCsOCCsOCCkOCCcNBysOCCcNBycNByQMByILBiQMByALBiALBiALBiALBh0KBhsJBR0KBhoJ - BRsJBRgJBRgJBRgJBRYHBBYHBBQHBBYHBBQHBBMHBBMHBBMHBBMHBBEGAxEGA0dDQf////////////// - /////////////////////////////////+vq6g4FAwwFAwwFAwwFAwwFAwwFAwoDAgoDAgkDAgkDAgkD - AgkDAgkDAgkDAgkDAgcDAgkDAgUCAQMBAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////8pDJMpDJMlCJMlCJMlCJMlCJMdCJMpDJMpDJMRBI8JAI8dCJMlCJMpDJMlCJMdCJMlCJMRBI8pD - JM5EJcxDJMlCJM9EJdFFJdFFJdVGJtlIJ9pOLtpOLttSM9tUNdtUNd5gQ91eQd5gQ+BqT+BsUuFvVeFv - VeN3XuWBauaHceiPe+mTgOqZh+uejOuejOyklO2qm++wovC5rPK/s/LDuPTKwfbUzPfa0/jg2vnk3/rn - 4/vs6fvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vs6frn4/jg2vbTy/TJv/LAte+z - pe2qm+uejOmWg+eLduaFb+N3XuBrUN9lSt1aPNtRMtlJKc9EJcpDJL4/Irk9Ia86H6g3Hpw0HJcyG48w - GoUsGHwpFnooFncnFXQnFXAlFGkjE2EhEl4fEV8fEVgdEFcdEFcdEFUcD1McD1IbD1IbD0sZDk0aDksZ - DkcYDUYYDUQWDEEWDEIWDDwUCzwUCzwUCzoUCzgSCjYSCjUSCjEQCTEQCS4QCS4QCSwPCCwPCCwPCCkO - CCcNBykOCCkOCCUNByUNByQMByQMByQMByALBh8LBiALBh8LBh8LBh0KBh0KBhsJBRoJBRgJBRgJBRYH - BBYHBBQHBBQHBBQHBBQHBBMHBBMHBBMHBBMHBBEGAxEGAxEGA769vf////////////////////////// - /////////////////////4qJiAwFAwoDAgoDAgwFAwoDAgoDAgoDAgkDAgoDAgkDAgkDAgkDAgkDAgkD - AgkDAgkDAgUCAQUCAQMBAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////8xDJMpDJM5E - JcpDJNFFJcdCJMlCJMdCJMpDJMRBI8lCJMlCJMdCJMdCJMlCJMVBI8lCJM9EJcdCJM5EJc9EJc5EJdFF - JdVGJtZGJtlIJ9lJKdpOLtpOLttSM9xVN91eQd9kSOBoTeBrUOFwV+R8ZeR8ZeN5YeWBauaHcueMd+iS - fumVguqciuyikeymlu+wovC2qfC5rPLAtfLDuPTLwvXPx/fZ0vje2Pnh3Pro5Pvs6fvu6/vu6/vu6/vu - 6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vs6frm4fje2PXRyfPHvfG9se+0p+2qm+ugj+mT - gOaJdOR9ZuJ1XOFvVd9mS91bPttRMtpLK9FFJclCJL0/Irk9IbM7IKg3HqM2HZszHIYsGHwpFn4qF3cn - FXImFXAlFGkjE2kjE2EhEmEhEl4fEVoeEFwfEVoeEFgdEFcdEFUcD1IbD04aDksZDkYYDUQWDEYYDUIW - DD8VDD8VDDoUCzwUCzwUCzgSCjoUCzUSCjMRCTMRCTAQCS4QCTAQCS4QCSwPCC4QCSsOCCsOCCkOCCUN - ByUNByILBiQMByQMByALBiALBiILBiALBh0KBh8LBh8LBh0KBhoJBRsJBRoJBRgJBRYHBBYHBBQHBBYH - BBMHBBMHBBQHBBMHBBEGAxEGAxEGAxEGAzAqKPX19f////////////////////////////////////// - //////X19S4qKAwFAwoDAgwFAwwFAwoDAgoDAgoDAgoDAgoDAgoDAgkDAgcDAgcDAgcDAgkDAgUCAQMB - AQMBAQMBAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9NGJslCJM5EJcxDJMlCJMxDJM5E - JclCJMdCJMpDJMVBI8JAI8dCJMpDJMpDJMpDJM5EJcxDJMlCJM5EJcxDJM9EJdFFJdFFJdZGJtlIJ9pN - LdpNLdtSM9xYOtxYOt9kSOBrUOBrUON3XuN3XuWCbOaHceaHcuaJdOmVguqZh+qaiOufjuyklOyklO6u - n++ypPC5rPK/s/LDuPTLwvXRyfbVzvje2Pjg2vrn4/vs6Pvs6fvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu - 6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vs6Pni3ffa0/XPxvLDuPG6ru6uoO2omOuejOmVgueLduWCbON7 - Y+FwV+BoTd5gQ9xYOtpOLtlIJ89EJcdCJL0/IrM7IK05H6A1HZYyG4suGYUsGHwpFnooFncnFXImFWsj - E2gjE2YhEmQhEmMhEl8fEVwfEVgdEFgdEFcdEFUcD1McD00aDkcYDUQWDEIWDEIWDEEWDD8VDDwUCzoU - CzwUCzoUCzYSCjYSCjMRCTUSCjMRCTEQCTAQCTAQCS4QCSwPCCsOCCwPCCwPCCcNByUNByQMByQMByQM - ByQMByALBiALBh8LBh8LBh0KBh0KBh0KBhsJBRgJBRgJBRgJBRYHBBYHBBYHBBQHBBMHBBQHBBQHBBMH - BBMHBBMHBBEGAxEGAxEGA6alpP///////////////////////////////////////////////6alpAwF - AwoDAgoDAgoDAgoDAgoDAgoDAgkDAgoDAgoDAgkDAgcDAgkDAgcDAgcDAgUCAQMBAQMBAQMBAQIBAQMB - AQMBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////8xDJM9EJcxDJM9EJclCJMpDJMlCJMxDJMxDJMpDJMpD - JMdCJMdCJM5EJclCJMxDJM5EJdFFJcxDJM5EJc5EJdVGJtFFJdlIJ9lJKdpNLdpPMNtSM95gRN5iRt9l - SuBrUOFwV+N7Y+WCbOaFb+eNeeiPe+iRfeiSfuqciuuejOyjk+2omO6sne6un++ypPC3qvG8sPLDuPPF - u/XNxPbTy/fa0/jg2vni3fvs6Pvs6fvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu - 6/vu6/vu6/vu6/vs6frn4/jg2vbVzvTJv/LAtfC3qu6uoOymluqciumVgueLduWCbON7Y+JyWeBrUN9l - St1aPNxXOdpOLtlIJ85EJcRBI8JAI7k9Iaw5H6M2HZYyG5EwGogtGHwpFnooFnImFWsjE2YhEmMhEl4f - EVoeEFoeEFgdEFcdEFUcD1UcD1IbD0sZDkkYDUcYDUYYDUIWDD8VDDwUCzwUCzwUCzwUCzgSCjgSCjUS - CjMRCTUSCjUSCjMRCTMRCTEQCTAQCSwPCCsOCCkOCCkOCCkOCCkOCCcNByUNByQMByILBiILBiILBh8L - Bh0KBh0KBh0KBh8LBh0KBhsJBRsJBRsJBRgJBRgJBRYHBBMHBBQHBBQHBBQHBBEGAxMHBBMHBBEGAxEG - AxEGAzAqKPX19f////////////////////////////////////////////X19S4qKAoDAgwFAwoDAgoD - AgoDAgoDAgkDAgoDAgkDAgkDAgcDAgcDAgcDAgcDAgUCAQUCAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIB - AQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////8xDJM5EJcpDJMlCJMpDJMxDJNFFJcpDJMxDJM5EJc9EJc5EJclCJMpDJMpD - JMxDJNFFJcpDJNFFJdVGJtFFJdVGJs9EJdlJKdpOLtxXOd1cP99mS+BrUOFwV+N5YeR/aOR/aOaFb+eL - duiRfemXheqaiOmWg+qaiOugj+ymluymlu2qm+6uoO+zpfC2qfG9sfLBtvPFu/TJv/bTy/bUzPjb1fjg - 2vrn4/vs6Pvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu - 6/vs6Pni3fjb1fXPx/PFu/K/s++0p+6sneyklOufjumVgueMd+aHcuWCbOR9ZuJyWeJyWeBqT99mS95g - RNxXOdpPMNpNLdNGJsA/IrQ7IKc3HpszHJEwGoMsGHcnFXQnFWsjE2QhEmEhEmEhEloeEFgdEFcdEFUc - D1McD1McD04aDk0aDkkYDUkYDUQWDEQWDEIWDD0UCz8VDDoUCzwUCzoUCzoUCzUSCjUSCjUSCjMRCTMR - CTMRCTEQCTEQCTAQCSsOCCsOCCcNBycNBycNBycNBycNByQMByILBiILBiALBiALBh8LBh0KBh0KBh8L - BhsJBRsJBRgJBRoJBRYHBBgJBRYHBBQHBBMHBBQHBBEGAxEGAxMHBBMHBBEGAxEGAxEGAxEGA5mXl/// - /////////////////////////////////////////////769vQoDAgwFAwoDAgoDAgoDAgoDAgkDAgkD - AgkDAgkDAgkDAgkDAgcDAgcDAgMBAQUCAQMBAQIBAQIBAQMBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////89EJdFFJc9EJc9EJc5EJc5EJc5EJcxDJMxDJM5EJc5EJclCJMlCJMpDJMpDJMlCJM9EJc5EJcxD - JNFFJc9EJdZGJtlIJ9pOLtxYOuBoTeFwV+N7Y+WBauWCbOaHcuaJdOeMd+iRfemWg+qZh+uejOugj+uf - juyikeymlu2omO6sne6uoO+zpfC2qfG6rvK/s/LDuPPHvfTLwvXPx/bVzvjd1/nh3Prn4/vs6Pvu6/vu - 6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vs6fnk3/je2PbU - zPTKwfLDuPG8sO+0p+2qm+ymluugj+qZh+mVguiSfueLduaFb+R9ZuN5YeJ0W+FuVN9lSt5gQ9xXOdpP - MNZGJslCJL4/IrQ7IKI2HZQxG34qF3QnFWgjE2MhEl8fEV8fEVoeEFcdEFcdEFcdEFcdEFAbD04aDksZ - DksZDkYYDUQWDEIWDEYYDUEWDD0UCz8VDD0UCzoUCzwUCzYSCjMRCTMRCTMRCTMRCTMRCTEQCTMRCTAQ - CS4QCS4QCSsOCCcNBycNBycNBycNByILBiALBiILBiILBiALBh8LBh8LBh8LBh0KBhsJBRsJBRoJBRoJ - BRgJBRQHBBQHBBMHBBQHBBQHBBMHBBMHBBEGAxEGAxEGAxEGAxEGAxEGAxEGA+vq6v////////////// - /////////////////////////////////0VBQAwFAwwFAwoDAgoDAgkDAgkDAgkDAgkDAgkDAgkDAgkD - AgkDAgkDAgMBAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQAAAAIBAQIBAQAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////89EJc9EJc5E - JdNGJs5EJdFFJdFFJdNGJsxDJM5EJclCJMRBI8xDJMpDJNVGJs9EJdZGJs9EJcxDJM9EJdVGJtlJKdpO - Lt5gQ+J1XOWCbOaFb+aJdOeNeeeNeeiSfumTgOqZh+qZh+qciuuejOyikeugj+ymlu2qm+2qm+6un++w - ou+ypO+0p/C3qvG8sPLAtfLDuPPFu/XNxPbTy/fX0Pjb1fnh3Prm4fvs6Pvu6/vu6/vu6/vu6/vu6/vu - 6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/ro5Pjg2vfa0/XRyfTJv/LDuPG8 - sO+zpe6sneymluufjuqZh+mTgOeNeeaHcuaFb+R/aON7Y+N3XuJyWeBrUOBoTd9kSN1aPNpPMNpLK9VG - JsVBI7g9IZ40HIouGXUnFWgjE2EhEmEhEl8fEVwfEVoeEFcdEFgdEFMcD04aDksZDkcYDUYYDUYYDUQW - DEYYDT8VDD0UCz8VDDwUCzoUCzoUCzgSCjUSCjUSCjMRCTMRCTMRCTEQCTMRCTAQCTAQCS4QCS4QCSsO - CCcNByUNByUNByILBiALBiILBiILBiALBh8LBh0KBh0KBh0KBhsJBRsJBRoJBRoJBRYHBBQHBBYHBBQH - BBQHBBYHBBQHBBMHBBEGAxEGAxEGAxEGAxEGAxEGAxEGA4uJiP////////////////////////////// - /////////////////769vQwFAwoDAgoDAgoDAgoDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgcDAgUCAQMB - AQMBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////89EJc9EJdVGJs5EJc5EJc9EJcxD - JMpDJM9EJclCJMpDJMlCJM5EJdVGJs9EJc9EJdNGJs5EJdFFJdFFJdVGJtNGJtxYOuFuVOWBauaHcuiP - e+iRfeiSfumVgumWg+mWg+mXheufjuqaiOufjuyjk+yjk+yklO2ome2qm+6un+6uoO+zpe+0p/C5rPG9 - sfLAtfLDuPTJv/TLwvXRyfbVzvjd1/nh3Pro5Pvs6Pvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu - 6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/ro5Pnh3Pjb1fXRyfTLwvLDuPG9se+0p+6uoO2omeyk - lOufjuqZh+mTgOiRfeeMd+aHcuaHceWDbeR9ZuN7Y+J1XOJyWeBrUN9mS99kSN5gQ9xYOtpOLs5EJbg9 - IYouGXAlFGYhEmEhEl8fEVoeEFcdEFcdEFMcD1IbD04aDksZDkcYDUYYDUQWDEQWDEEWDEEWDD0UCzwU - Cz0UCzoUCzgSCjgSCjgSCjUSCjMRCTMRCTMRCTAQCTMRCTAQCTAQCTAQCS4QCSwPCCsOCCcNByUNByQM - ByILBiQMByQMByILBh8LBiALBh0KBh0KBhsJBRsJBRoJBRoJBRQHBBYHBBQHBBYHBBQHBBMHBBMHBBEG - AxMHBBEGAxEGAxEGAxEGAxEGAxEGAxEGA9XU1P////////////////////////////////////////// - /////2poaAoDAgoDAgoDAgkDAgoDAgkDAgkDAgoDAgkDAgkDAgkDAgkDAgMBAQMBAQMBAQIBAQIBAQIB - AQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9NGJtNGJtFFJc5EJdFFJcxDJNVGJtVGJsxDJM9EJcxD - JNNGJtNGJs9EJc5EJdNGJs5EJdZGJspDJNVGJtVGJtVGJttRMt1cP+FwV+WBauaHcuaJdOaJdOeNeemT - gOmTgOmVgumXheqciuqciuufjuyikeyklOyklO2ome2qm+6sne+wou+0p/C3qvG8sPLAtfLDuPPFuvTK - wfXPx/fZ0vjd1/jg2vrm4fvs6Pvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu - 6/vu6/vu6/vu6/vu6/vs6fro5Pjg2vfX0PXPxvPFu/LAtfG6ru+ypO6un+2omOyklOuejOqZh+mTgOiR - feeLduaHcuaHceWCbOR9ZuN7Y+N4YOJ0W+FuVOBrUOBqT99lSt5gRN1bPtpOLsVBI5w0HHImFWEhElwf - EVgdEFgdEFcdEFUcD1IbD04aDk4aDksZDksZDkcYDUcYDUYYDUQWDEEWDDwUCz8VDDwUCzwUCzoUCzgS - CjUSCjgSCjYSCjMRCTMRCTEQCTEQCTEQCS4QCS4QCSwPCCwPCCwPCCsOCCcNByUNByILBiQMBx8LBh8L - Bh8LBh8LBh0KBhsJBRsJBRoJBRoJBRsJBRoJBRYHBBQHBBYHBBYHBBQHBBQHBBEGAxMHBBMHBBEGAxEG - AxEGAxEGAxEGAw8FA2xpaP///////////////////////////////////////////////9XU1AoDAgoD - AgoDAgkDAgoDAgoDAgkDAgoDAgkDAgkDAgcDAgcDAgMBAQMBAQMBAQMBAQIBAQMBAQIBAQMBAQMBAQIB - AQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9FFJdNGJtVGJs5EJdNGJs9EJdNGJsxDJM9EJdVGJs5EJc5EJdVGJs5EJdFF - JcxDJNFFJdFFJc5EJdVGJthHJtlIJ9ZGJtpPMN1bPuBoTeFuVON5YeR8ZeR9ZuaHceeLdueMd+iRfemX - hemXheuejOqaiOugj+ufjuyklOymlu2omO6sne+ypO+zpfC2qfG9sfLAtfPFuvTJv/XPxvbVzvjb1fnh - 3Prn4/vs6Pvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu - 6/vs6frm4fje2PbVzvTKwfLDuPK/s++0p+6uoOymluyjk+qciuqaiOiSfueMd+aJdOaFb+WDbeR/aON7 - Y+N5YeJyWeFuVOBrUN9kSN1eQd1cP9xXOdtRMthHJsdCJKw5H4ErF2gjE14fEVoeEFgdEFcdEFUcD1Ib - D1AbD04aDk4aDk4aDkkYDUcYDUcYDUQWDEQWDEEWDD8VDD8VDD8VDDwUCzoUCzoUCzYSCjYSCjYSCjUS - CjMRCTMRCTMRCTEQCTAQCTAQCSwPCC4QCSsOCCsOCCkOCCkOCCUNByQMBx8LBh8LBh0KBh8LBh0KBhsJ - BRsJBRsJBRoJBRoJBRgJBRYHBBYHBBYHBBYHBBQHBBQHBBMHBBQHBBMHBBEGAxEGAxEGAxEGAxEGAw8F - Aw4FA9XU1P///////////////////////////////////////////////2poaAoDAgoDAgoDAgoDAgkD - AgkDAgkDAgkDAgcDAgcDAgcDAgMBAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQAAAAAAAAIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9ZGJtVGJtVGJtNGJtFFJc9EJdZGJs9EJdVGJs9EJdVGJtFFJdNGJslCJNFFJcxDJNZGJthHJtFF - JdVGJthHJtlIJ9VGJtpLK9pNLdxVN91bPt5iRuBrUOJyWeN5YeN5YeWCbOWCbOaJdOeMd+iRfeiRfemW - g+qZh+ufjuugj+yklO2ome2qm++wovC2qfC3qvG8sPLDuPPFu/XPxvbUzPfa0/je2Pnk3/vq5vvs6fvu - 6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vs6Prm4fjd1/bU - zPTLwvLDuPG9se+0p+6un+yklOugj+qZh+iRfeeNeeaHcuWCbOWBauN7Y+J1XOFwV+FuVN9mS95iRt1c - P9xXOdpPMNhHJspDJL4/Iq86H5kyG4AqF2kjE2MhEl4fEVoeEFcdEFcdEFMcD1McD1McD00aDk0aDk0a - DksZDkcYDUEWDEIWDD8VDD0UCz8VDD0UCzoUCz0UCzgSCjoUCzgSCjgSCjMRCTMRCTMRCTMRCTEQCTEQ - CTMRCTAQCSwPCCwPCCsOCCwPCCkOCCcNByUNByUNByQMByILBh8LBh0KBh8LBh0KBhsJBRsJBRsJBRoJ - BRgJBRYHBBYHBBQHBBYHBBQHBBMHBBMHBBQHBBEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FA1pXVv////// - /////////////////////////////////////////+rq6goDAgoDAgoDAgkDAgoDAgoDAgkDAgkDAgkD - AgcDAgcDAgMBAQMBAQMBAQIBAQIBAQMBAQIBAQIBAQIBAQAAAAIBAQIBAQAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9VGJtZGJtVG - JtNGJtFFJdFFJdFFJdFFJdFFJdZGJtNGJs9EJdFFJc9EJc9EJdNGJtZGJtFFJdZGJtVGJthHJthHJtFF - JdZGJtZGJtlIJ9pNLdtRMt1bPt1bPt9lSuBrUON3XuN4YON4YOaFb+aFb+eLdueLduiSfumVguqaiOue - jOyjk+yklO6un+6un++0p/C5rPG8sPLDuPPHvfXPx/bVzvjb1fnh3Pvq5vvs6Pvu6/vu6/vu6/vu6/vu - 6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vs6fro5Pjg2vfZ0vXPx/PFu/G9sfC3qu6u - oO2omeyjk+qZh+mTgOeNeeaHceR/aON7Y+N3XuFwV+BrUN9kSN5gQ9xXOdpOLtlJKc5EJcVBI7s9Iaw5 - H5cyG4suGXwpFnAlFGQhEmEhElwfEVcdEFcdEFUcD1UcD1McD1AbD1AbD04aDk4aDk0aDkcYDUIWDEIW - DEEWDEEWDD8VDDoUCzoUCz0UCzoUCzoUCzYSCjUSCjMRCTUSCjEQCTMRCTMRCTEQCTEQCTAQCS4QCTEQ - CSwPCCsOCCkOCCcNBycNBykOCCUNByILBiALBh8LBh8LBhsJBRoJBRsJBRsJBRgJBRoJBRoJBRgJBRYH - BBQHBBQHBBMHBBMHBBMHBBMHBBEGAxEGAxEGAxEGAxEGAxEGAxEGAw8FA769vf////////////////// - /////////////////////////////4qJiAoDAgoDAgkDAgkDAgkDAgkDAgcDAgcDAgcDAgcDAgMBAQMB - AQMBAQIBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////89EJc5EJdVGJtFFJdNGJtVGJthH - JtVGJtZGJtZGJtNGJtVGJtZGJtFFJcxDJMxDJM9EJdZGJtVGJtVGJthHJtVGJtZGJtFFJdVGJtlIJ9lJ - KdpOLtpOLttSM9xXOd1eQd9mS+BrUOBsUuJ1XON7Y+N7Y+R/aOaHcuaJdOeNeeiSfumWg+uejOugj+ym - lu2qm++ypPG6rvG8sPLDuPTKwfbUzPfZ0vjg2vnk3/vq5vvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu - 6/vu6/vu6/vu6/vu6/vu6/vu6/vs6fvs6Pnk3/jd1/bVzvTKwfLBtvG6ru+zpe2qm+ugj+qZh+iRfeaJ - dOaFb+R/aON5YeFvVeBqT95iRt1cP9xVN9pPMNZGJslCJMA/IrY8Iaw5H6A1HZIwGogtGHkoFnAlFGsj - E2YhEmEhEloeEFoeEFcdEFcdEFUcD1IbD1McD1AbD1IbD00aDk0aDkcYDUcYDUYYDUQWDEEWDD8VDD0U - CzwUCzoUCzgSCjwUCzYSCjYSCjUSCjYSCjMRCTEQCTEQCTEQCTEQCTEQCTAQCSwPCCwPCCwPCCwPCCsO - CCkOCCcNByUNByQMByQMByALBh8LBh0KBhoJBRoJBRsJBRoJBRoJBRoJBRgJBRYHBBQHBBQHBBQHBBQH - BBMHBBMHBBEGAxMHBBMHBBEGAxEGAxEGAxEGAw8FA0dCQf////////////////////////////////// - /////////////+vq6goDAgkDAgoDAgkDAgoDAgkDAgcDAgcDAgcDAgcDAgMBAQIBAQMBAQIBAQMBAQIB - AQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9ZGJtVGJtVGJtFFJdZGJtNGJthHJtZGJthHJtZGJtVG - Js9EJdVGJs9EJc5EJc9EJc5EJc5EJdNGJtZGJtFFJdNGJtNGJtVGJtlJKdhHJtNGJtlJKdlJKdpOLttU - NdtSM91aPN1eQd9mS+BoTeFvVeJ0W+J1XOR9ZuWBauaHceeNeeiPe+mVgumWg+ugj+ymlu2omO+wovG6 - rvK/s/PFu/TKwfXRyffa0/jg2vrn4/vs6Pvs6fvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu - 6/vu6/vu6/vs6Prm4fjg2vbVzvTKwfLDuPC5rO6uoO2omOyikeqZh+iSfuaHcuWCbON5YeFuVOBoTd5g - Q91aPNxVN9pOLtlJKc9EJcRBI7Y8Ia05H5w0HJYyG4suGYAqF3wpFm8lFGsjE2YhEmMhEmMhElwfEVgd - EFcdEFcdEFUcD1IbD1McD04aDlAbD0kYDUsZDkcYDUcYDUIWDEIWDEIWDEEWDD8VDDwUCzwUCzoUCzoU - CzYSCjYSCjYSCjYSCjUSCjMRCTMRCTMRCTEQCTAQCSwPCC4QCS4QCSsOCCkOCCkOCCkOCCUNByUNByUN - ByUNByQMBx8LBh8LBh8LBh0KBhsJBRsJBRoJBRgJBRYHBBQHBBQHBBYHBBMHBBEGAxMHBBEGAxEGAxMH - BBEGAxEGAxEGAw8FAw8FAw8FAw8FA7KxsP////////////////////////////////////////////// - /6WkpAkDAgoDAgkDAgoDAgkDAgkDAgkDAgkDAgUCAQIBAQIBAQIBAQIBAQMBAQIBAQIBAQMBAQIBAQIB - AQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9NGJtZGJtlIJ9ZGJthHJthHJthHJthHJtZGJtVGJs5EJdFFJdVGJtNGJtFF - JcxDJNFFJdNGJtNGJs9EJc9EJdVGJs9EJc9EJdZGJtZGJtVGJtVGJtpOLtpOLtlIJ9tSM9tUNdxVN91e - Qd9kSOBqT+BqT+BsUuFwV+J0W+R8ZeaFb+aHcueLdumVgumWg+ufjuyklO2omO6uoO+0p/G9sfPFuvTL - wvbTy/jb1frm4fvq5vvs6fvs6fvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vs6Prn4/jg - 2vfZ0vXNxPLDuPG6ru+ypO2omOuejOmWg+iPe+aHcuR9ZuJ1XOFvVd9lSt1eQdtRMtpLK9VGJs5EJcRB - I7s9Ia05H6M2HaM2HZcyG48wGoYsGHooFnUnFXAlFGkjE2YhEmMhEmEhEloeEFgdEFcdEFcdEFMcD1Mc - D1AbD1IbD1AbD0sZDksZDkkYDUcYDUYYDUYYDUEWDD0UCz8VDD0UCzoUCzoUCzgSCjgSCjYSCjgSCjUS - CjUSCjMRCTMRCTMRCTEQCTEQCTAQCTAQCSsOCCkOCCkOCCsOCCkOCCkOCCcNBycNByUNByQMByALBh8L - Bh0KBhsJBRoJBRgJBRYHBBgJBRgJBRYHBBQHBBYHBBQHBBQHBBQHBBMHBBEGAxMHBBEGAxEGAxEGAw8F - Aw8FAxEGAxEGAy8qKPX19f////////////////////////////////////////////X19SwoJwkDAgkD - AgkDAgcDAgkDAgcDAgcDAgUCAQMBAQMBAQMBAQMBAQIBAQMBAQIBAQMBAQIBAQIBAQIBAQIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9ZGJtVGJtZGJtZGJtlIJ9lIJ9VGJtVGJtVGJtVGJs9EJc9EJdVGJtNGJs9EJcpDJM5EJdNGJs9E - JdZGJtlIJ9ZGJtVGJtlJKdlJKdlIJ9lIJ9VGJtpLK9pLK9pNLdpPMNtRMtxVN9xYOt1bPt5gRN9lSuBo - TeBsUuFwV+J0W+R/aOWDbeaHcuaJdOiPe+mVguqciuugj+yklO6un++0p/G8sPLDuPTLwvfX0Pnh3Pro - 5Pvq5vvs6Pvs6fvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vs6Pnk3/jg2vfa0/XPxvPFu/G9se+z - peymluufjumVgueMd+WCbON5YeJyWeBoTd5iRtxYOttRMtlJKdNGJspDJMJAI7g9Ia05H6U3Hp40HJYy - G4UsGIUsGH4qF3koFnkoFnQnFW0kFGkjE2gjE2MhEl8fEVwfEVcdEFUcD1UcD1McD1IbD00aDk4aDksZ - DkkYDUkYDUQWDEQWDEYYDUEWDD0UCz8VDEEWDDwUCzgSCjgSCjgSCjYSCjYSCjUSCjUSCjMRCTEQCTEQ - CTAQCTEQCTAQCS4QCSwPCCwPCCsOCCkOCCkOCCcNBykOCCcNByUNByQMByILBiALBh8LBhsJBRoJBRoJ - BRoJBRgJBRYHBBYHBBQHBBMHBBMHBBQHBBQHBBEGAxEGAxEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FAw8F - A6alpP///////////////////////////////////////////////6WkpAkDAgkDAgkDAgcDAgkDAgkD - AgcDAgUCAQMBAQMBAQMBAQIBAQIBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9hHJthHJtlJ - KdVGJtlIJ9ZGJtVGJtZGJtVGJtNGJtNGJs5EJdNGJtNGJs5EJc9EJc9EJdFFJdVGJthHJtlIJ9ZGJtlJ - KdhHJtZGJtlJKdlIJ9hHJthHJtlJKdpOLtpOLtpOLttUNdxVN9xXOdxYOt5iRt5iRuBoTeFwV+FwV+N3 - XuN4YOR/aOaFb+aHcueLdumVguuejOyikeyklO6sne+wovG8sPPFuvXPxvfa0/nh3Pni3frm4fro5Pvs - 6Pvs6fvs6fvs6fvu6/vu6/vs6fvs6Pro5Pnk3/jg2vfZ0vXNxPPFuvG6ru+ypO2omeuejOmTgOeLduWB - auN4YOFuVOBoTd1cP9xVN9pPMNhHJs5EJclCJMJAI70/Iq86H6c3HpkyG5kyG4suGYMsGIAqF34qF3Qn - FXQnFXAlFGYhEmkjE2QhEmgjE2QhEl4fEVwfEVcdEFMcD1UcD1AbD04aDlAbD00aDksZDkcYDUYYDUYY - DUYYDUIWDD8VDDwUCzwUCzoUCzgSCjgSCjoUCzgSCjgSCjYSCjUSCjMRCTMRCTEQCTEQCTAQCTAQCTAQ - CSwPCCsOCCkOCCkOCCcNBycNBykOCCcNByQMByALBiILBiQMByALBh0KBk1FQ6ilpailpailpaelpKel - pKelpKelpKelpKelpKelpKelpKalpKalpKalpKalpKalpKalpKalpKalpKalpKalpLKxsP////////// - /////////////////////////////////////////0VBQAkDAgkDAgkDAgkDAgkDAgcDAgMBAQMBAQIB - AQIBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9ZGJthHJtpLK9VGJtVGJtVGJthH - JtVGJtVGJs5EJc9EJdFFJdNGJs9EJc5EJc9EJcxDJNZGJthHJthHJthHJthHJtVGJtNGJtZGJthHJtVG - JtNGJtlIJ9hHJtpNLdpLK9pOLtpPMNtUNd1aPNxYOt9kSN5gRN5iRt9mS+BrUOFvVeFvVeN5YeN5YeR9 - ZuaJdOeLduiRfemXheqZh+yklO6un/C5rPLBtvPFu/XPxvbVzvfZ0vje2Pnh3Pni3frm4fro5Pro5Pvq - 5vro5Pvq5vrm4fjg2vjd1/bVzvTLwvLDuPG6ru+wou2omOuejOiSfueLduWCbON5YeFuVN9mS91cP9tU - NdpOLtZGJs5EJcVBI74/Irk9Ia86H6M2HZ40HJszHJIwGosuGX4qF3wpFnkoFnUnFXImFWkjE2kjE2gj - E2QhEmMhEmEhElwfEVoeEFoeEFcdEFcdEFUcD1IbD1IbD04aDk0aDkcYDUYYDUQWDEIWDEQWDD8VDD8V - DD0UCzwUCzoUCzoUCzwUCzYSCjUSCjUSCjMRCTMRCTMRCTMRCTMRCTMRCTEQCSwPCCsOCCkOCCsOCCsO - CCkOCCcNByUNByUNByQMByILBiALBiILBiILBh0KBnFqaf////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////////729vQkDAgkDAgkDAgkDAgkDAgkDAgMBAQMBAQIBAQMBAQIBAQIBAQIB - AQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9hHJthHJtlJKdZGJtZGJtNGJtlIJ9ZGJtZGJtFFJdVG - JtFFJdFFJc5EJdVGJs5EJdFFJdhHJtlIJ9hHJthHJtFFJdVGJtNGJtVGJtVGJtNGJtlIJ9lIJ9lJKdlJ - KdlIJ9pLK9pLK9tSM9xVN9xYOt5gQ99kSN1eQd5iRt9mS+BoTeFuVOJyWeN4YOR9ZuWBauWCbOaJdOiR - femTgOqciu2omfC3qvK/s/K/s/PFuvTJv/XPx/bVzvjb1fjd1/jg2vni3fnh3Pjg2vni3fnh3Pjb1ffZ - 0vXRyfTJv/LDuPG6ru+wouyklOuejOmTgOaJdOWDbeN5YeBsUt9kSN1eQdtSM9pLK9hHJsxDJMdCJL0/ - IrY8IbE7IKU3Hp40HJkyG5szHJEwGoouGYErF3ooFnkoFncnFW8lFGkjE20kFGgjE2EhEl8fEV8fEVgd - EFoeEFcdEFcdEFIbD1AbD1AbD1IbD1IbD04aDksZDksZDkkYDUQWDEIWDEIWDD8VDD0UCzwUCzwUCzoU - CzwUCzYSCjUSCjUSCjMRCTMRCTMRCTMRCTMRCTAQCS4QCSwPCCwPCCsOCCkOCCkOCCkOCCcNBycNByUN - ByQMByILBiILBiALBiILBiALBnFqaf////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////0RBQAcDAgcDAgcDAgcDAgcDAgMBAQMBAQIBAQIBAQMBAQMBAQIBAQIBAQIBAQIBAQIB - AQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9lIJ9lIJ9ZGJtlIJ9hHJtNGJthHJtVGJtNGJtVGJtVGJtNGJtFFJdVGJtVG - JtZGJtNGJtNGJtVGJtVGJtZGJtZGJtNGJtVGJtZGJthHJtNGJtNGJthHJtpLK9pLK9pNLdlJKdpOLtpO - LtxVN9pPMNxXOd1bPt1cP99kSOBoTd9mS+BsUuFuVOFvVeN3XuR8ZeR8ZeaFb+aJdOiPe+mTgOugj+2o - mO6uoO+zpfG6rvLBtvPHvfTKwfXPx/bVzvfX0Pfa0/fa0/jb1fjb1ffZ0vbTy/XNxPPFu/LBtvG6ru+w - ouymluqciumTgOaHcuWBauN7Y+FwV99lSt1cP9tUNdpPMNlIJ8xDJMlCJMJAI7g9IbM7IKo4Hp40HJsz - HJszHJIwGogtGIUsGIMsGIAqF4AqF3koFnUnFW0kFGgjE2YhEl8fEV8fEVwfEVgdEFgdEFcdEFcdEFAb - D1AbD04aDlAbD00aDk0aDkcYDUYYDUcYDUYYDUcYDUcYDUIWDEEWDD0UCz0UCz0UCzwUCzgSCjUSCjUS - CjUSCjUSCjMRCTMRCTMRCTAQCS4QCSwPCCwPCCwPCCsOCCsOCCkOCCcNBykOCCkOCCUNByILBiQMByIL - BiILBiALBnJraf////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////9XU - 1AcDAgkDAgkDAgcDAgUCAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9lJKdVGJthHJtZGJtNGJtlJKdlIJ9NGJtVGJs9EJc9EJc5EJdFFJdhHJtNGJtVGJtFFJdVGJtZG - JtNGJtVGJtVGJtVGJtFFJdFFJdVGJtVGJtNGJtFFJdZGJtZGJtZGJtZGJtpLK9lJKdpOLttRMttUNd1c - P91cP95gQ+BsUuFuVOBrUOBoTeFuVOJyWeJ0W+N3XuR8ZeWBauaJdOeNeeiSfuqaiOyklO2ome6uoPC2 - qfG9sfLDuPTJv/XNxPXPx/bTy/XRyfXRyfbVzvXPx/TJv/LDuPG9sfC2qe6un+yklOqaiOiSfueLduWB - auJ1XOBsUt9mS95gRNxYOtpPMNlIJ9NGJslCJMA/Ir4/IrQ7IKo4HqU3HpszHJkyG5kyG5EwGoUsGIMs - GHwpFnooFnkoFncnFXcnFXAlFG8lFGgjE2QhEmMhEl8fEVoeEFgdEFcdEFMcD1IbD1McD1IbD00aDk0a - DksZDkkYDUYYDUIWDEYYDUIWDEQWDD8VDEEWDEEWDEEWDD0UCz8VDDwUCzoUCzUSCjUSCjMRCTMRCTMR - CTMRCTEQCTAQCS4QCS4QCS4QCSsOCCsOCCkOCCsOCCkOCCUNByQMByILBiQMByILBiALBiALBnJraf// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////2poaAkDAgkDAgcD - AgUCAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9ZGJtlJKdZG - JtZGJtZGJthHJtVGJs9EJdNGJtFFJdFFJdVGJtNGJtZGJtFFJdFFJdNGJtNGJtFFJdNGJtVGJtVGJthH - JtNGJtFFJdVGJtZGJtVGJtZGJthHJtlJKdlIJ9hHJthHJtpNLdpNLdtRMtxVN91aPN5gRN9kSOFuVOBr - UOBrUOBrUOBsUuFuVOJ0W+J0W+J0W+N7Y+WBauaHceaHcumVguqZh+yjk+yklO6uoPC2qfG9sfLDuPLD - uPPHvfTKwfTKwfTLwvTLwvTLwvLAtfG8sO+0p+6uoOyklOqciuiSfuaJdOaFb+N4YOBsUt9kSN1cP91a - PNtSM9lJKdFFJcxDJMRBI70/IrY8IbM7IKo4HqI2HZszHJcyG5kyG5EwGoYsGIAqF3ooFncnFXQnFXQn - FXQnFW0kFGkjE20kFGsjE2YhEmEhElgdEFcdEFcdEFMcD1IbD1AbD04aDk0aDkkYDUsZDksZDkYYDUYY - DUYYDUIWDD8VDDwUCz8VDDwUCzwUCzoUCzwUCzwUCzwUCzoUCzoUCzYSCjMRCTMRCTMRCTMRCTEQCS4Q - CSwPCCwPCCsOCCsOCCkOCCcNBycNBycNByUNByILBiQMByQMByILBiALBnJraf////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////9XU1AkDAgkDAgcDAgUCAQMBAQMBAQIB - AQMBAQIBAQIBAQMBAQMBAQIBAQAAAAIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9ZGJtZGJtVGJtVGJthHJtVGJtFF - JdVGJtVGJtVGJtNGJtNGJspDJNNGJs5EJc5EJdNGJtFFJdNGJs9EJdFFJc5EJdpLK9hHJtlJKdlJKdpN - LdlJKdpOLtpOLtpOLtpPMNpNLdpNLdpOLtpNLdpOLttSM9tUNd1aPN1bPuBrUOBrUOBrUOFvVeFvVeFv - VeJ0W+FwV+J1XOJ0W+R/aOR/aOaHceaHcueNeemWg+ufjuyjk+6un/C3qvC5rPK/s/LDuPLDuPLDuPLD - uPLDuPLDuPG9sfC2qe2qm+yklOqciuiSfuaJdOWBauJ1XOFuVN5iRt1eQd1bPtpOLtpLK9ZGJs9EJcdC - JL0/Ir0/IrM7ILE7IKg3Hpw0HJcyG5QxG5EwGoYsGIMsGHwpFnooFnUnFXUnFXImFW0kFGkjE2gjE2Qh - EmQhEmQhEmYhEl8fEV8fEVoeEFMcD1McD1IbD04aDk4aDksZDksZDkcYDUYYDUcYDUQWDEEWDEIWDEIW - DD8VDDwUCzwUCzoUCzgSCjgSCjgSCjYSCjUSCjMRCTUSCjYSCjYSCjMRCTMRCTEQCTAQCS4QCSsOCCkO - CCkOCCkOCCkOCCUNByQMByILBiQMByQMByILBiALBnJraf////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////4qIiAkDAgkDAgUCAQMBAQMBAQMBAQMBAQIBAQIBAQIB - AQIBAQIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9hHJthHJtVGJtNGJtVGJtNGJthHJtNGJtNGJtZGJs9E - JdFFJdVGJtVGJtNGJs9EJdVGJtFFJdVGJtZGJtlJKdlJKdpOLtlJKdlJKdpOLtpLK9pNLdlJKdpOLttR - MttSM9pPMNpOLtpPMNpOLtpOLtpLK9xVN9tSM91cP91eQd5iRt9lSuBrUOBsUuFwV+JyWeBqT+BrUOFw - V+J1XON4YON5YeN7Y+WBauaJdOmVguqciuyjk+2qm++wovC3qvG8sPG8sPG8sPK/s/K/s/G6ru+zpe6s - neyklOqaiOiSfuaHcuWBauN3XuFuVN9mS91cP91aPNpOLtpLK9ZGJs9EJcdCJMJAI7g9IbQ7IK05H6w5 - H540HJkyG5QxG5QxG4suGYAqF4AqF3wpFnooFnkoFncnFXImFWsjE2kjE2gjE2YhEmEhEmMhEmEhEloe - EF4fEVwfEVoeEFcdEFUcD1IbD04aDksZDk4aDkkYDUQWDEQWDEQWDEIWDEQWDEEWDD8VDDwUCzwUCzoU - CzgSCjYSCjgSCjUSCjUSCjMRCTMRCTMRCTMRCTEQCTEQCTEQCTMRCTEQCS4QCSwPCCwPCCsOCCsOCCUN - ByUNByQMByQMByILBiALBiALBnFraf////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////+rq6gkDAgcDAgMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIB - AQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9ZGJtVGJtVGJtZGJtZGJtNGJtNGJtZGJtNGJtZGJs5EJdFFJdVGJtNGJs9E - Jc9EJdVGJthHJtpNLdpOLtpOLtpNLdlJKdlJKdpNLdpOLtlJKdpNLdpOLttSM9tSM9pPMNxVN9pPMNpP - MNtRMttRMttRMtpPMNpOLttUNd1bPt5gQ99kSOBrUOBsUuFvVeBrUOBrUOBrUOBrUOBsUuFvVeFwV+J1 - XOR9ZuaHcueMd+mVguqZh+yklO6sne+ypO+ypO+0p/C2qfC5rPC3qu+0p+6un+yjk+qciuiSfuaJdOR/ - aOJ1XOFvVeBoTd1cP91bPttUNdpLK9ZGJs5EJclCJMA/Irs9IbM7ILM7IKw5H6U3Hpw0HJkyG5cyG5Ew - GoouGYUsGIErF3wpFnooFnUnFXQnFXAlFGsjE2gjE2gjE2gjE2MhEmEhElwfEVgdEFcdEFcdEFcdEFMc - D1cdEFcdEFUcD00aDksZDkcYDUYYDUIWDEEWDEIWDEIWDEQWDEEWDDwUCzoUCzwUCzgSCjgSCjYSCjUS - CjYSCjUSCjMRCTMRCTAQCTEQCTEQCS4QCTAQCS4QCSwPCCwPCCsOCCsOCDAQCS4QCSsOCCcNByUNByQM - ByALBiALBnJraf////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////4qIiAcDAgMBAQMBAQMBAQIBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9hHJtZGJtVGJtFFJdNGJtZGJtNGJtVGJtVGJtFFJdNGJsxDJM5EJcxDJMxDJMxDJNVGJtlJKdpL - K9pLK9hHJtlJKdpLK9pNLdpNLdpLK9lJKdlIJ9pOLtpPMNpOLtpNLdtRMtlJKdpOLtpPMNtRMttRMtpO - LtpOLttRMtxVN91eQd5gRN9kSOBqT+FvVd9lSt9lSuBqT+BoTeBoTeBoTeBrUOFuVOJ0W+R8ZeWDbeaJ - dOiRfemXheyike2omO6sne6uoO+ypO+ypO+ypO6uoO2omeqciuiSfuaHceR/aOJ0W+BrUOBoTd1cP9xX - OdtSM9pNLdVGJsxDJMlCJL4/Ir0/Irg9Ia86H605H6U3Hp40HJszHJcyG5QxG48wGoouGYMsGHooFnoo - FnkoFnUnFXImFXAlFGsjE2YhEmYhEmEhEmQhEmMhElwfEVgdEFcdEFUcD1McD1McD1IbD1AbD1AbD04a - DlIbD1AbD0sZDkcYDUcYDUIWDEEWDD8VDD0UCzwUCzwUCzwUCzgSCjoUCzYSCjUSCjYSCjUSCjMRCTEQ - CTAQCTAQCTEQCS4QCSwPCCwPCCsOCCwPCCsOCCcNBysOCCsOCCkOCCkOCCsOCCkOCCcNByUNB3Rrav// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////X19Sso - JwMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9lIJ9hHJtlI - J9NGJtVGJs9EJc9EJdVGJs9EJdNGJtNGJs5EJc9EJcxDJM9EJdlIJ9lIJ9lJKdpOLtpNLdpOLtlJKdlJ - KdlIJ9pNLdlJKdZGJtlIJ9pNLdpLK9pOLthHJtpNLdpNLdpPMNtRMtpOLtpPMNtSM9tUNdpOLttUNd1b - Pt1cP95gRN9mS99mS95gRN9lSt9lSt5gQ95iRt5iRt9mS+BrUOBsUuN3XuN5YeWDbeeLdumTgOqciuug - j+ymlu2ome2qm+2qm+6sne2omeyklOmWg+aJdOWBauN4YOBrUN9lSt1cP91cP9pOLtlJKdNGJs5EJcRB - I8RBI70/Irg9IbM7ILE7IKo4Hqc3HqA1HZszHJcyG5QxG48wGogtGIErF3koFncnFXUnFXUnFW0kFG8l - FGkjE2kjE2YhEmEhEl4fEV4fEVgdEFoeEFcdEFMcD1IbD1UcD1AbD1IbD00aDksZDkcYDUsZDk4aDlAb - D0sZDkQWDEIWDD8VDDwUCzoUCzoUCzgSCjgSCjgSCjYSCjUSCjUSCjUSCjMRCTEQCTMRCTEQCTEQCS4Q - CS4QCS4QCSwPCCsOCCkOCCUNBykOCCcNByUNByQMByQMByILBiALBiALBlBFQ6mlpaqmpamlpamlpaml - pamlpailpailpailpaelpKelpKalpKelpKalpKalpKalpKalpKalpKalpKalpKalpKalpKalpKalpKal - pKalpKalpKalpKalpKWkpKWkpKWkpKWkpKWkpKWkpKWkpKWkpKWkpKWkpKWkpFdVVQMBAQMBAQIBAQMB - AQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9hHJtZGJtZGJtVGJtNGJtZGJtFF - JdZGJtNGJs5EJcpDJM5EJc9EJdFFJdNGJtpOLttRMtpNLdpLK9pLK9hHJtZGJtZGJthHJthHJtlIJ9hH - JtlIJ9lJKdlIJ9lIJ9lIJ9pOLtpOLtpLK9pOLtlJKdpOLttRMttSM9tSM9tRMtpOLt1cP91aPN5gQ95g - Q91eQd5iRt5gRNxVN95gQ91cP91eQd5gQ+BrUOBsUuJ0W+R8ZeWCbOiPe+mXheqciuugj+yklOymluym - luyklOugj+ugj+eNeeWBauN3XuBrUN9mS91cP9xVN9tRMtpLK89EJclCJMRBI8JAI70/Irs9Ibg9Ia05 - H6g3HqA1HZ40HJw0HJszHJIwGo0uGYouGYMsGIAqF3wpFnUnFXUnFXQnFW0kFGkjE2kjE2YhEmYhEl8f - EWEhEl8fEVoeEFgdEFUcD1UcD1UcD1IbD1AbD04aDk0aDksZDksZDksZDkYYDUkYDUsZDkcYDUcYDUQW - DEEWDD0UCz0UCzwUCzgSCjUSCjYSCjYSCjUSCjMRCTMRCTEQCTEQCTAQCTEQCS4QCSwPCCwPCC4QCSwP - CCsOCCcNBycNBycNBycNByQMByILBiALBiILBiILBiALBiALBiALBh0KBh0KBh8LBh0KBh8LBh8LBh0K - BhgJBRYHBBEGAxEGAxEGAxEGAxMHBBEGAw8FAw8FAxEGAxEGAw8FAw8FAw4FAwwFAw4FAwwFAwwFAwwF - Aw4FAwwFAwoDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgcDAgMBAQUCAQUCAQMBAQMBAQIBAQIBAQIBAQIB - AQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9hHJthHJtZGJthHJtVGJthHJtlIJ9VGJs5EJdFFJdFF - JcxDJMxDJNVGJtlIJ9pLK9pOLtpOLtpNLdpLK9ZGJtFFJdlIJ9lIJ9lIJ9VGJtZGJthHJtlIJ9VGJthH - JthHJthHJtlIJ9lJKdlJKdpOLttSM9tSM9tUNdtRMtpNLdpNLdtUNdxYOtxXOd1bPt1aPN5gRNxYOtxX - Od1aPN1aPNtUNdxXOd5gQ99lSuBsUuFvVeN7Y+aHcueNeemVguqZh+uejOyikeyikeufjuqaiOmXheaH - ceN5YeFwV99kSN1eQdtUNdpPMNlIJ9NGJspDJMRBI74/Ir0/Irs9IbM7IK05H6o4Hqc3HqI2HZszHJsz - HJQxG40uGY0uGYUsGIErF3koFnkoFnooFnUnFXImFW8lFGsjE2kjE2gjE2QhEmMhEl8fEVwfEVoeEFcd - EFUcD1McD1UcD1AbD1AbD04aDkkYDUsZDkkYDUkYDUQWDEIWDEQWDEQWDEQWDEQWDEYYDUQWDEEWDD8V - DDoUCzgSCjYSCjUSCjYSCjUSCjMRCTMRCTEQCTAQCS4QCS4QCS4QCS4QCSsOCCkOCCkOCCcNByUNByUN - ByUNByQMByQMByQMByILBiALBh8LBh0KBh0KBh0KBhsJBRsJBRsJBRsJBRoJBRgJBRoJBRsJBRgJBRYH - BBMHBBMHBBMHBBEGAxEGAxEGAxEGAw8FAw8FAw8FAw8FAwwFAw4FAwwFAwoDAgoDAg4FAwoDAgoDAgoD - AgoDAgkDAgkDAgkDAgkDAgkDAgcDAgMBAQMBAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIB - AQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9ZGJthHJthHJthHJthHJthHJtVGJtZGJtVGJsxDJM5EJc5EJdVGJtpOLtpO - LtZGJtlJKdlIJ9lJKdhHJtlJKdhHJtNGJs5EJdNGJtVGJtlJKdlJKdpLK9lJKdlIJ9pLK9ZGJtVGJtVG - JttUNeBoTd9kSN9lSt5gRN1bPtpOLttRMtpLK9pPMNtSM9tSM9xXOd1aPNxVN9tUNdpPMNpOLtpOLttS - M91bPt5gRN9lSuBrUON3XuR/aOeMd+iRfemXheqciuqciuqaiOmXhemVgumVguWBauJ0W+BoTd1cP9tU - NdpOLthHJs9EJclCJMVBI7s9Ibs9Ibk9IbE7ILE7IKg3HqI2HaA1HZszHJcyG5cyG40uGYouGYYsGIAq - F3wpFnooFnkoFnImFXImFXUnFW0kFGkjE2kjE2YhEmYhEmQhEmEhElwfEVwfEVcdEFUcD1UcD1cdEFIb - D04aDksZDk0aDk0aDksZDkkYDUIWDEIWDEYYDUQWDEIWDEIWDEEWDD0UCz0UC0QWDEQWDD8VDDgSCjYS - CjUSCjMRCTEQCTEQCTAQCTAQCS4QCTAQCS4QCS4QCSsOCCsOCCcNBycNByUNByUNBycNByQMByILBiQM - ByILBiALBiILBiALBh0KBh8LBhsJBRsJBRoJBRoJBRoJBRgJBRYHBBgJBRYHBBQHBBMHBBEGAxMHBBYH - BBYHBBMHBBEGAw8FAxEGAxEGAw4FAw4FAwwFAwwFAwwFAwwFAwwFAwwFAwoDAgoDAgoDAgoDAgoDAgkD - AgkDAgkDAgcDAgUCAQMBAQIBAQIBAQIBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9ZGJthHJtZGJtNGJtZGJtlJKdNGJtVGJtFFJdNGJs5EJdVGJtlIJ9pLK9lJKdVGJthHJthHJtpL - K9lJKdlIJ9lIJ9hHJtlJKdhHJtpLK9lJKdlJKdpLK9lJKdhHJtlJKdlIJ9hHJttSM95gROBqT+BrUN5i - Rt9lSt5gRNtSM9lJKdhHJtlIJ9lJKdpLK9tRMtpOLtpOLtpOLtlJKdlIJ9hHJtpNLdtSM91aPN1eQd9m - S+BsUuR8ZeWCbOeMd+mTgOmVguqZh+qZh+mVgueNeeeLduR8ZeBrUN5iRttUNdlIJ9hHJs5EJcpDJMJA - I8A/Irk9Ibg9IbE7IK86H6w5H6g3HqI2HZszHJcyG5YyG5EwGogtGIYsGIMsGIErF4AqF3koFncnFXUn - FXImFW8lFG8lFGsjE2gjE2YhEmYhEl8fEVwfEV4fEVgdEFcdEFUcD1UcD1IbD1IbD00aDk0aDk4aDk0a - DksZDkcYDUYYDUQWDEIWDEIWDEEWDD8VDD8VDDwUCzwUCzwUCzoUCzwUCzwUCz0UCzoUCzUSCjMRCTMR - CTEQCTAQCS4QCTAQCS4QCS4QCSwPCCsOCCcNBycNByUNBycNByUNByQMByQMByQMByILBiALBiILBiAL - Bh0KBhsJBRsJBRsJBRoJBRsJBRoJBRgJBRYHBBYHBBYHBBQHBBMHBBMHBBEGAxEGAxEGAxEGAxMHBBMH - BBEGAxEGAxEGAxEGAw8FAw4FAw4FAwwFAwwFAwwFAwoDAgkDAgkDAgoDAgkDAgcDAgkDAgkDAgcDAgUC - AQIBAQMBAQIBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9ZGJtVGJtZG - Js5EJdNGJtZGJtFFJc9EJc9EJc5EJdNGJtZGJtpLK9lJKdlJKdZGJtpNLdZGJtVGJtZGJtpLK9lIJ9lJ - KdpLK9ZGJthHJtlIJ9lIJ9lIJ9VGJtpLK9pNLdlJKdpOLtxYOuFuVON5YeN4YOBrUN9kSN5gRNxXOdlI - J9lJKdVGJtNGJtlIJ9lIJ9hHJtlIJ9hHJtZGJtVGJtlJKdlJKdpLK9pPMNxYOt5gQ99mS+J1XOR9ZuaH - cueMd+iPe+mVgumWg+iRfeaJdOaHceN3Xt9lSt1aPNpOLthHJs9EJcpDJMJAI74/Ir0/Irs9IbQ7IK86 - H686H6c3HqA1HZw0HJw0HJYyG5EwGosuGYgtGIMsGIMsGIAqF3ooFncnFXcnFXQnFXImFW8lFG0kFGkj - E2gjE2gjE2MhEmEhEl4fEVwfEVgdEFcdEFUcD1UcD1IbD1McD04aDk4aDk4aDksZDkkYDUcYDUcYDUYY - DUIWDEEWDD8VDD8VDD0UCz0UCzoUCzoUCzgSCjgSCjgSCjYSCjgSCjoUCzoUCzYSCjUSCjMRCTMRCTEQ - CTAQCSwPCCsOCCsOCCkOCCcNByUNByUNByQMByQMByQMByQMByALBiILBiILBiALBh8LBh0KBh0KBh0K - BhsJBRoJBRsJBRoJBRoJBRgJBRYHBBgJBRQHBBMHBBEGAxEGAw8FAxEGAxEGAxEGAw8FAxEGAw8FAxEG - AxEGAxMHBBEGAw8FAwwFAwwFAwoDAgoDAgoDAgoDAgkDAgkDAgkDAgkDAgUCAQUCAQMBAQMBAQIBAQMB - AQMBAQIBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9lIJ9ZGJtZGJtNGJtVGJtVGJs9E - JcxDJMxDJM5EJdVGJthHJtpLK9lJKdlJKdZGJtpLK9lIJ9lIJ9pNLdlJKdpLK9hHJthHJtNGJtVGJtZG - JtlJKdlIJ9lJKdhHJtpOLttUNd1cP+BrUON7Y+aJdOaHceFwV95gRN5gQ9tSM9ZGJs5EJdFFJcxDJM5E - Jc5EJdlIJ9FFJc5EJc5EJdFFJcxDJNNGJtlJKdpNLdpOLt1aPN1eQeFwV+N4YOWCbOaHcueMd+iRfeiR - feeNeeaFb+R/aOJyWd1cP9pPMNpNLc5EJcpDJMJAI70/Irg9IbQ7ILQ7IK05H6o4Hqo4HqI2HZ40HJsz - HJkyG5EwGosuGYUsGIYsGIMsGH4qF3koFnkoFncnFXcnFXAlFHAlFG8lFGsjE2gjE2QhEmYhEmQhEmEh - El8fEVwfEVwfEVcdEFUcD1McD1IbD1AbD1AbD04aDkkYDUkYDUkYDUQWDEQWDEQWDEQWDEIWDD8VDD0U - Cz0UCz0UCzwUCzwUCzgSCjYSCjgSCjYSCjUSCjMRCTMRCTUSCjUSCjYSCjYSCjMRCTEQCTAQCSwPCC4Q - CSsOCCcNBycNByUNByUNByUNByQMByQMByALBiILBh8LBh8LBh8LBh0KBh0KBhsJBRoJBRoJBRoJBRgJ - BRYHBBgJBRgJBRYHBBQHBBMHBBEGAxEGAxEGAxEGAxEGAw8FAw4FAw4FAwwFAw4FAw4FAw4FAwwFAwwF - AwwFAwwFAw4FAw8FAw8FAwwFAwkDAgkDAgkDAgcDAgUCAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQAA - AAIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9NGJtZGJtNGJtZGJtNGJtVGJtFFJc5EJc5EJc5EJdZG - JtlIJ9lIJ9ZGJtZGJtVGJthHJtlJKdpNLdpLK9hHJs9EJdNGJtNGJs9EJdFFJdlIJ9VGJtZGJtlIJ9pL - K9pOLt1eQd9mS+FuVOWBauaHceWBauBsUt5iRt1cP9pNLc9EJdNGJs5EJcRBI8pDJMVBI9NGJslCJM9E - Jc5EJcpDJMRBI8RBI8lCJNFFJdpLK9tRMt1cP+BoTeJ0W+R9ZuaHcuaJdOeNeeiPe+aJdOR/aON4YOBr - UNtUNdlIJ89EJcdCJL4/Irs9IbY8IbE7IK05H686H6g3HqM2HZw0HKI2HZszHJQxG5EwGo0uGYUsGIUs - GIErF34qF3wpFnkoFnkoFncnFXUnFW8lFGsjE2kjE2QhEmgjE2YhEmEhEmYhEmQhEmEhElwfEVoeEFcd - EFcdEFMcD1IbD1IbD04aDk4aDk4aDkkYDUkYDUYYDUQWDEIWDEIWDEEWDD8VDDwUCz0UCz0UCzoUCzoU - CzgSCjYSCjYSCjUSCjUSCjMRCTMRCTMRCTEQCTMRCTMRCTMRCTMRCTAQCS4QCS4QCSwPCCcNByUNByUN - ByUNByUNByQMByILBiALBiALBh8LBh8LBh0KBhsJBR0KBhsJBRgJBRoJBRoJBRoJBRgJBRgJBRgJBRgJ - BRQHBBQHBBEGAxMHBBEGAw8FAw8FAw8FAw8FAw4FAwwFAwwFAw4FAw4FAwoDAgoDAgoDAgoDAgwFAwwF - AwwFAwwFAwwFAwwFAwoDAgkDAgcDAgUCAQUCAQUCAQMBAQIBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIB - AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9lJKdZGJtVGJtZGJtZGJs9EJdNGJtFFJc9EJdZGJtZGJtpLK9lJKdhHJthH - JthHJtlJKdlIJ9hHJthHJtZGJs9EJc9EJcxDJM9EJdNGJtFFJc5EJdNGJs9EJdZGJtpPMN1bPt5gROFu - VON5YeN7Y+FwV95iRt5gQ9tUNc5EJcpDJMxDJM5EJcdCJMJAI8RBI8VBI8VBI8dCJMxDJMlCJL0/IsJA - I8RBI85EJdZGJtlJKdpPMN5gQ+BsUuN4YOWBauaHcuaJdOeLduaHceN7Y+J0W99lStpNLcxDJMdCJMA/ - Irs9Ibg9IbM7IKo4Hqo4Hqw5H6g3HqM2HZszHJcyG5EwGoouGYsuGYgtGIUsGIMsGIErF4AqF3ooFnwp - FncnFXkoFnAlFHQnFW8lFGgjE2YhEmgjE2kjE2QhEmMhEmMhEl4fEVwfEVwfEVUcD1UcD1IbD1McD1Ib - D1AbD04aDk0aDkkYDUkYDUcYDUQWDEIWDEIWDEEWDD8VDD0UCz0UCzwUCzgSCjoUCzgSCjgSCjUSCjUS - CjUSCjMRCTMRCTMRCTEQCTAQCTEQCTAQCS4QCSwPCDEQCTEQCSwPCCcNBycNBykOCCcNBycNByILBiAL - Bh8LBh8LBh8LBiALBiALBh0KBh0KBhsJBRgJBRgJBRgJBRgJBRgJBRgJBRoJBRYHBBQHBBMHBBMHBBMH - BBEGAxEGAxEGAxEGAw8FAw8FAw4FAw4FAw4FAw4FAwwFAwwFAwoDAgoDAgoDAgkDAgoDAgwFAwoDAgkD - AgkDAgcDAgUCAQUCAQoDAgoDAgcDAgMBAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9ZGJtZGJtNGJtlJKc9EJdVGJspDJNFFJc9EJdlIJ9pNLdlIJ9hHJtVGJtZGJtVGJtZGJtlJKdlI - J9VGJtZGJtNGJs9EJcxDJMpDJM5EJcpDJNFFJc5EJdFFJdlIJ9tRMt1bPt5gQ99kSOBsUuBoTd1bPttS - M9lIJ9FFJcdCJMdCJMxDJM5EJcJAI70/Ir4/Ir0/Ir4/Ir0/IsA/IsdCJMJAI8JAI8A/IsVBI8pDJNFF - JdpLK9tUNd9lSuJ0W+R8ZeaFb+aHceaHcuWDbeN4YOBsUt5iRtlJKclCJMA/Irk9Ia05H7M7IKw5H6g3 - HqI2HaU3HqM2HaM2HZYyG5QxG5IwGosuGYYsGIgtGIErF4AqF4ErF3koFnkoFncnFXcnFXImFW8lFHIm - FW0kFGsjE2sjE2gjE2MhEmEhEmMhEl8fEV4fEV4fEVgdEFcdEFcdEFMcD1IbD04aDk0aDk0aDksZDkYY - DUYYDUYYDUYYDUIWDEQWDEEWDD8VDD8VDD0UCz8VDDwUCzgSCjgSCjYSCjYSCjYSCjUSCjUSCjMRCTMR - CTAQCS4QCS4QCSwPCC4QCSwPCCwPCC4QCS4QCSwPCCwPCCsOCCsOCCcNByQMByILBiALBh8LBiALBiAL - Bh8LBh0KBh0KBhsJBRoJBRoJBRoJBRgJBRgJBRgJBRgJBRgJBRYHBBQHBBQHBBMHBBEGAw8FAxEGAxEG - Aw8FAw8FAw4FAw4FAw4FAw4FAwwFAwwFAwwFAwoDAgkDAgkDAgoDAgkDAgkDAgoDAgkDAgUCAQMBAQUC - AQUCAQUCAQMBAQUCAQUCAQMBAQcDAgcDAgUCAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9FFJdVGJthH - JtZGJtNGJtNGJtFFJc9EJdFFJdNGJtpNLdpNLdpLK9lIJ9FFJdZGJthHJtZGJtZGJtlIJ9FFJc5EJc9E - Jc5EJclCJMlCJMxDJNFFJc5EJc5EJdZGJtpLK9xXOd5gQ91eQd1cP9tSM9VGJtFFJcdCJMRBI8JAI8RB - I8RBI8RBI8JAI7s9IbQ7ILg9IbY8Ibk9Ib0/Irk9Ibk9Ib0/Ir0/IsRBI8VBI89EJdlIJ9tRMt5gQ+Fu - VON3XuWCbOWCbOaFb+WBauJyWd5gRN1aPNZGJsVBI7g9IbY8Iag3Hqg3HqU3HqU3HqA1HaA1HZw0HJcy - G5IwGo0uGYouGYgtGIYsGIUsGIAqF34qF3ooFnkoFnkoFnkoFncnFW8lFG8lFGsjE2kjE2kjE2gjE2Yh - EmMhEl8fEV8fEV4fEV4fEVoeEFgdEFcdEFcdEFMcD1McD1McD1AbD0sZDkkYDUkYDUcYDUcYDUcYDUQW - DEQWDEEWDD8VDD8VDD0UCzwUCzoUCzoUCzoUCzgSCjgSCjYSCjUSCjMRCTMRCTMRCTEQCTAQCTAQCSwP - CC4QCSwPCCwPCCsOCCkOCCkOCCkOCCsOCCwPCCkOCCUNByQMByQMByALBh8LBh8LBh0KBh0KBh8LBhsJ - BRsJBRsJBRoJBRoJBRoJBRgJBRYHBBQHBBYHBBQHBBQHBBQHBBEGAw8FAw8FAxEGAw4FAw8FAw4FAw4F - AwwFAwwFAwoDAgoDAgkDAgoDAgkDAgkDAgoDAgkDAgkDAgkDAgkDAgcDAgUCAQMBAQMBAQMBAQIBAQMB - AQMBAQMBAQMBAQMBAQMBAQUCAQUCAQUCAQMBAQMBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9hHJtVGJtVGJthHJtVGJtVGJs5E - Jc5EJdFFJdVGJtlJKdlIJ9pLK9ZGJtNGJtlJKdhHJtNGJtNGJtNGJspDJNFFJdFFJc9EJclCJMJAI8VB - I8pDJMpDJMdCJM9EJdVGJtpLK9tRMtpOLtpNLdlJKc5EJcpDJMRBI8JAI70/IsA/IsVBI8A/Ir0/Irg9 - Ibk9IbY8Ibg9Ibs9Ibk9Ibk9IbQ7ILE7ILM7ILk9Ib4/IspDJNNGJtpNLd1cP+BqT+J1XOR8ZeWBauWC - bOR9ZuBsUt1eQd1bPsxDJLs9IbY8IbQ7IKw5H6g3HqM2HZ40HJkyG5IwGpYyG5IwGpEwGosuGYYsGIUs - GIYsGIErF4ErF34qF34qF3cnFXUnFXImFXImFXAlFG0kFG0kFGkjE2gjE2YhEmMhEmEhEmEhEmEhEl4f - EWEhEl8fEVcdEFcdEFUcD1IbD1UcD1McD04aDkkYDUkYDUkYDUkYDUkYDUcYDUQWDEQWDEIWDEEWDD0U - Cz0UCz0UCzwUCzoUCzwUCzgSCjYSCjYSCjMRCTMRCTMRCTEQCTEQCTEQCTEQCS4QCS4QCSsOCC4QCSsO - CCkOCCcNBycNByUNByUNByQMBycNByUNBykOCCUNByQMBx8LBh0KBh0KBh0KBhsJBRoJBRgJBRoJBRoJ - BRsJBRgJBRgJBRgJBRYHBBQHBBQHBBQHBBMHBBEGAxEGAxEGAxEGAw4FAw4FAw4FAwwFAwwFAwoDAgoD - AgoDAgkDAgoDAgcDAgoDAgkDAgcDAgoDAgcDAgMBAQMBAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIB - AQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9NGJtVGJs9EJdFFJdVGJtFFJc5EJdFFJc9EJdhHJtlJ - KdlJKdVGJtVGJthHJtZGJtNGJtNGJtNGJtFFJcpDJM9EJcpDJMdCJMRBI8dCJMRBI8xDJMlCJMlCJMdC - JM5EJc9EJdVGJtNGJtFFJcpDJNNGJsRBI8RBI74/Irs9Ib0/Ir0/IsJAI7g9IbE7ILE7IK05H7M7ILE7 - ILE7IK86H7E7IKw5H605H605H7M7ILs9IcVBI9lJKdxXOeBqT+J0W+N7Y+WBauWCbOR9ZuBqT9xYOtxV - N8xDJLk9Iaw5H605H6U3Hpw0HJszHJcyG5IwGpEwGo8wGo0uGZEwGoYsGIMsGIMsGIErF4AqF4AqF3wp - FnkoFncnFXImFXImFXAlFG0kFGkjE2gjE20kFGgjE2MhEmMhEmQhEl8fEV4fEV8fEVoeEFgdEFcdEFUc - D1cdEFMcD1IbD1IbD1AbD0kYDU4aDksZDkcYDUcYDUcYDUQWDEEWDEIWDD8VDD0UCz8VDD0UCzwUCzoU - CzgSCjgSCjYSCjUSCjMRCTMRCTMRCTMRCTEQCTAQCS4QCS4QCSwPCCwPCCsOCCsOCCkOCCcNBycNByUN - BycNByUNByQMByILBiQMByQMBycNByQMByILBh8LBh8LBh0KBhoJBRoJBRoJBRoJBRoJBRYHBBYHBBYH - BBYHBBQHBBMHBBMHBBMHBBMHBBEGAw8FAw8FAw8FAw4FAw4FAwwFAwwFAw4FAwoDAgwFAwoDAgwFAwoD - AgkDAgkDAgkDAgkDAgUCAQMBAQMBAQMBAQUCAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAIB - AQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////89EJdFFJdhHJtFFJdVGJtFFJdFFJcxDJM5EJdNGJtZGJtlIJ9hHJtVGJtNG - JtlIJ9VGJtNGJs5EJcxDJMdCJMpDJMlCJMpDJMVBI8lCJMlCJMdCJMA/IsJAI70/IsVBI8RBI8dCJMdC - JNNGJs5EJcVBI8JAI70/Ir0/Ir4/Irk9Ibk9Ib4/Irg9IbM7IKo4Hqc3Hqw5H6o4Hqg3HqU3Hqg3Hqc3 - Hqo4Hq86H6w5H7Q7IMA/Is5EJdpOLt1eQeFvVeN3XuR8ZeN7Y+N3Xt9kSNpPMNpOLsA/Iqo4HqI2HaA1 - HZ40HJcyG5cyG5IwGpIwGpEwGoouGYUsGIUsGIUsGIErF4UsGHwpFnwpFncnFXkoFnkoFncnFXUnFXAl - FGsjE2kjE2sjE2kjE2gjE2MhEmQhEmEhEmEhEl8fEV8fEV4fEV4fEVcdEFUcD1UcD1McD1McD1IbD1Mc - D04aDk4aDksZDkkYDUkYDUcYDUYYDUQWDEEWDEIWDD8VDEEWDD8VDD0UCz0UCzgSCjgSCjgSCjUSCjMR - CTUSCjMRCTMRCTEQCTEQCTAQCS4QCS4QCSsOCCwPCCsOCCkOCCsOCCcNBysOCCcNBycNByILBiQMByQM - ByILBiALBiALBiALBiILBiILBiILBiALBh0KBh0KBhsJBRsJBRoJBRYHBBYHBBQHBBgJBRQHBBMHBBQH - BBMHBBMHBBEGAxEGAw8FAw4FAw8FAw4FAw4FAwwFAwwFAwoDAgoDAgkDAgoDAgoDAgkDAgkDAgoDAgcD - AgUCAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQMBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAIBAQAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9NGJtVGJtVGJtZGJtVGJtZGJsxDJMxDJM5EJdhHJtlIJ9VGJtFFJc9EJdZGJtZGJtNGJs9EJc9E - JcpDJMRBI8lCJMRBI8lCJL4/IsVBI8JAI70/IsA/Ir0/Ir4/Ir4/Ir4/IsA/IsJAI8RBI74/Ir4/IsA/ - Irk9Ibs9Ibs9Ibk9Ibs9Ibk9IbM7IKo4Hqg3HqU3HqU3HqA1HaM2HaM2HaM2HaA1Hac3Hqg3Hqg3Hq05 - H7Q7IMdCJNhHJt1aPOBqT+J1XON4YON4YOFwV91bPtlIJ9ZGJr0/Iqo4HqI2HZ40HJszHJIwGpEwGpEw - GpYyG4ouGYouGYUsGIUsGIMsGIAqF4ErF3ooFnooFncnFXkoFnkoFnUnFXImFXImFWkjE2kjE2kjE2kj - E2gjE2MhEmQhEmMhEmEhEmQhEl8fEV8fEVwfEVgdEFcdEFcdEFUcD1McD04aDk4aDk4aDk0aDlAbD0sZ - DkcYDUQWDEYYDUIWDEEWDD8VDEEWDD8VDD0UCz0UCzoUCzoUCzoUCzgSCjUSCjMRCTYSCjMRCTEQCTAQ - CTMRCTEQCTAQCTAQCSwPCCsOCCsOCCkOCCkOCCsOCCkOCCkOCCkOCCILBiALBiALBiILBiALBiALBiAL - Bh8LBh0KBh0KBiALBiALBiILBh8LBh0KBhoJBRgJBRgJBRQHBBYHBBQHBBQHBBMHBBMHBBMHBBMHBBMH - BA8FAw4FAw8FAw4FAwwFAwwFAwwFAwoDAgwFAwkDAgwFAwoDAgkDAgkDAgkDAgcDAgUCAQUCAQMBAQMB - AQMBAQMBAQIBAQMBAQIBAQIBAQIBAQIBAQAAAAIBAQIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9FFJdFFJdlI - J9VGJtFFJc9EJc5EJcVBI8pDJNFFJdVGJtVGJtNGJs5EJdNGJtZGJs9EJc9EJdNGJslCJMJAI8RBI8RB - I70/IsA/Ir0/Ir4/Ir0/Irs9Ibs9Ib4/IsA/Ir0/Ir4/IsRBI74/Irs9Ib0/Irk9Ibg9Ibk9Ibg9IbQ7 - ILY8IbY8Ia05H6g3HqM2HaA1HaA1HaI2HaU3Hqc3HqM2HZw0HKA1HaI2Hao4Hq86H7E7IL0/Is9EJdtU - Nd9kSOFvVeN3XuJ1XOBsUtxVN9FFJclCJLk9IaA1HZkyG5cyG5YyG5QxG48wGoouGY8wGoUsGIgtGIUs - GIAqF34qF4AqF34qF3ooFnooFnkoFncnFXQnFXQnFXAlFHAlFHAlFGkjE2kjE2gjE2kjE2QhEmMhEmMh - EmMhEmMhEl8fEV4fEVoeEFUcD1McD1IbD1McD1IbD00aDk0aDksZDk0aDk0aDkkYDUkYDUkYDUcYDUIW - DEEWDEEWDD8VDD0UCz0UCz0UCzwUCzwUCzoUCzgSCjYSCjYSCjMRCTMRCTMRCTMRCTMRCTEQCTAQCTAQ - CSwPCCsOCCsOCCsOCCkOCCkOCCcNByUNBycNByILBiILBiALBiALBiILBh8LBh8LBh8LBh8LBh0KBh0K - Bh0KBh0KBh0KBiALBh0KBhsJBRoJBRoJBRYHBBYHBBQHBBQHBBMHBBMHBBEGAxEGAxEGAw8FAw8FAw4F - AwwFAwwFAwwFAwwFAwoDAgoDAgwFAwoDAgoDAgkDAgkDAgUCAQMBAQMBAQMBAQMBAQMBAQMBAQIBAQIB - AQMBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9NGJs9EJdNGJtNGJtVGJtNGJsxD - JMpDJMxDJNNGJtNGJtZGJtNGJtNGJtZGJthHJs5EJcxDJM9EJcVBI8RBI8JAI8RBI8JAI8JAI7s9IcA/ - Irs9Ibg9Ib0/Ir0/Ir0/Ir0/Ir4/IsJAI74/Irk9Ib0/Irk9Ibk9Ibg9IbQ7ILE7ILY8Ia86H605H6A1 - Hag3HqU3Hp40HJ40HKA1HZszHKM2HZszHJ40HKM2Hag3Hqo4Hqw5H7Y8IcRBI9pOLt9kSOBsUuN5YeFv - Vd9mS9pOLsVBI8RBI7Q7IJIwGpIwGpIwGpEwGo0uGYYsGIouGYouGYErF4ErF4ErF4AqF4AqF34qF4Er - F3ooFncnFXcnFXUnFXQnFXImFXAlFG0kFGsjE2sjE2YhEmYhEmYhEmQhEmYhEmMhEmEhEmEhElwfEVwf - EVoeEFMcD1AbD1cdEFMcD04aDk0aDk0aDksZDksZDkkYDUkYDUkYDUcYDUYYDUcYDUQWDEEWDD8VDD8V - DD8VDD0UCzoUCzoUCzgSCjgSCjgSCjUSCjMRCTMRCTMRCTMRCTMRCTEQCTEQCS4QCSsOCCsOCCwPCCsO - CCsOCCcNByQMByUNByUNByILBiILBiILBiQMByILBh8LBh8LBh0KBh8LBh8LBh0KBhsJBRsJBRsJBRoJ - BRgJBRoJBRoJBR0KBhgJBaelpP///////////////////////////////////////6alpAwFAw4FAwwF - AwwFAwwFAwoDAgoDAgkDAgkDAgkDAgUCAQMBAQMBAQIBAQIBAQIBAQIBAQMBAQMBAQIBAQIBAQIBAQIB - AQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9NGJtVGJtNGJtZGJs9EJcpDJM5EJc5EJcdCJNFFJdFF - JdNGJtNGJtFFJdZGJtNGJs5EJcpDJMVBI8dCJMA/IsA/IsA/IsJAI70/IsJAI74/Ir0/Irg9Ibk9Ibs9 - Ibk9Ibs9Ibs9Ib0/IsA/Irk9Ibk9IbY8Ibg9IbM7ILY8IbE7IK86H6o4HqU3Hp40HKM2HZ40HJszHJsz - HJkyG5szHJszHJcyG5YyG6I2HaI2Hag3HqI2Haw5H74/ItlIJ91bPuBrUOJyWeFuVN9lSthHJr4/Irg9 - Ia86H5IwGoouGY0uGYsuGYouGYUsGIUsGIUsGIUsGHooFnkoFn4qF3ooFnooFoAqF3ooFnUnFXImFXQn - FW8lFHAlFG8lFGsjE2sjE2sjE2kjE2YhEmYhEmkjE2YhEmQhEmEhEl8fEV4fEV4fEVgdEFUcD1McD1cd - EFcdEE4aDk0aDksZDk0aDksZDksZDkkYDUcYDUQWDEYYDUQWDEIWDD8VDD8VDD8VDD0UCzwUCzoUCzoU - CzYSCjYSCjYSCjYSCjMRCTMRCTMRCTEQCTEQCTEQCTEQCTAQCSwPCCsOCCsOCCsOCCkOCCkOCCcNByUN - ByUNByILBiALBiILBiQMByILBiALBh8LBh0KBh0KBh0KBhsJBRsJBRsJBRoJBRoJBRYHBBgJBRgJBRgJ - BRgJBailpf///////////////////////////////////////6alpA4FAw4FAwwFAw4FAwwFAwoDAgoD - AgkDAgkDAgUCAQUCAQUCAQUCAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAIB - AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9ZGJtFFJdFFJdFFJdZGJtFFJcpDJMpDJMVBI8xDJM9EJc9EJdFFJdNGJtNG - JtFFJdFFJc9EJcxDJMpDJMdCJL4/Ir4/Ir0/Ir4/IsdCJMA/IrQ7ILk9Ibg9Ibg9Ibg9Ibk9Ibg9Ibk9 - Ibs9IbM7ILQ7ILQ7ILM7IK86H6w5H6o4Hqo4Hqw5H6M2HaA1HZ40HJkyG5QxG5szHJw0HJszHJYyG5Iw - GpcyG5w0HKA1HaA1HZw0HKM2HbQ7IMpDJNxYOuBoTeFwV+BrUN1cP85EJbM7ILE7IKw5H40uGYgtGIYs - GIYsGIouGYYsGIMsGIMsGIAqF4AqF3koFnooFnkoFnwpFnooFnooFnUnFXAlFG8lFHAlFG8lFG0kFGsj - E2sjE2gjE2gjE2QhEmQhEmYhEmEhEmEhEl8fEV8fEWEhElwfEVgdEFcdEFIbD1cdEFMcD1IbD1AbD00a - Dk0aDk0aDkkYDUkYDUkYDUYYDUYYDUQWDEQWDEcYDUEWDD8VDD0UCz0UCzwUCzgSCjUSCjYSCjUSCjMR - CTMRCTMRCTEQCTMRCTEQCTAQCSwPCC4QCSwPCCwPCCsOCCsOCCsOCCkOCCUNByQMByUNByQMByQMByIL - Bh8LBh8LBiALBiALBh8LBh0KBhsJBRoJBRoJBRoJBRoJBRoJBRgJBRgJBRoJBRYHBBgJBaelpP////// - /////////////////////////////////6alpAwFAwwFAwwFAwwFAwoDAgoDAgkDAgcDAgkDAgcDAgUC - AQUCAQMBAQUCAQIBAQMBAQMBAQIBAQIBAQIBAQIBAQAAAAIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9NGJtFFJdVGJs9EJdVGJsxDJMlCJMxDJMdCJMxDJNFFJdFFJcxDJMlCJM5EJdNGJs5EJc5EJcpD - JMdCJMVBI74/Ir0/Irs9Ib0/IsRBI7k9Ib0/Irg9IbY8IbY8Ibk9IbY8Ibs9IbQ7ILY8Ibg9Iaw5H6w5 - H6w5H6o4Hqo4Hq86H6g3HqI2HZw0HJ40HJkyG5kyG5w0HJQxG5cyG5QxG5QxG5IwGpcyG5kyG5kyG5sz - HJQxG5szHKo4Hr0/ItpLK95gROBrUOBoTdtUNcJAI6M2Hac3Hqg3HpIwGoouGYYsGIUsGIYsGIMsGHwp - FnooFnwpFnwpFnooFnkoFnkoFncnFXkoFnkoFncnFXAlFHImFXAlFHAlFG8lFGsjE2kjE2gjE2YhEmQh - EmMhEmMhEmEhEmEhEl8fEV8fEV8fEVwfEVgdEFUcD1UcD1McD1IbD1IbD04aDk0aDk0aDk0aDkkYDUcY - DUkYDUYYDUYYDUQWDEIWDEIWDEIWDD8VDD0UCzwUCzoUCzoUCzUSCjUSCjMRCTUSCjMRCTEQCTMRCTMR - CTMRCTEQCS4QCTAQCS4QCSwPCCsOCCsOCCkOCCcNBycNBycNByUNByQMByUNByQMByALBh8LBh8LBh8L - Bh8LBh0KBhsJBRsJBR0KBhsJBRgJBRYHBBYHBBYHBBYHBBQHBBYHBKelpP////////////////////// - /////////////////6alpAwFAw4FAwwFAwwFAwwFAwwFAwoDAgcDAgkDAgcDAgMBAQMBAQUCAQIBAQIB - AQMBAQMBAQMBAQMBAQIBAQIBAQAAAAIBAQAAAAAAAAIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9ZGJtFFJdNG - Js9EJdFFJdVGJs9EJclCJMpDJMVBI9FFJdZGJs5EJdFFJc5EJdFFJdFFJdNGJslCJMVBI8A/Ir0/Ir0/ - Irg9Ibs9Ib0/IsJAI7s9Ibk9Ibg9IbY8IbQ7ILY8IbY8Ibg9Ibg9IbE7ILM7IKw5H7M7IKg3Hqw5H6U3 - Hqw5H6M2HaA1HZQxG5cyG5YyG5EwGpQxG5cyG5IwGo0uGZQxG5EwGpQxG5YyG5QxG5YyG5kyG540HLY8 - IdFFJd1bPuBrUN9kSNpLK7M7IJkyG5kyG6A1HY8wGoYsGIUsGIMsGIUsGIAqF3wpFnwpFnwpFnooFnko - FnkoFnooFnkoFnUnFXkoFnkoFnQnFXQnFXAlFG8lFG8lFGsjE2kjE2kjE2gjE2YhEmMhEmQhEmMhEl8f - EV4fEV8fEV4fEVgdEFcdEFcdEFMcD1IbD04aDlIbD04aDk0aDk0aDksZDkkYDUcYDUQWDEQWDEQWDEIW - DEIWDEEWDEEWDEEWDD0UCz0UCzoUCzoUCzYSCjYSCjUSCjUSCjMRCTMRCTEQCTMRCTMRCTAQCTAQCSwP - CCwPCCwPCCwPCCsOCCkOCCkOCCkOCCUNByUNByQMByILBiALBiILBiALBh8LBh8LBh8LBh8LBhsJBRsJ - BRsJBRoJBRoJBRgJBRoJBRgJBRgJBRYHBBYHBKelpP////////////////////////////////////// - /6alpA4FAw4FAwoDAgoDAgoDAgoDAgoDAgkDAgcDAgUCAQMBAQMBAQUCAQMBAQMBAQIBAQUCAQMBAQUC - AQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9FFJc5EJcxDJM5EJdFFJc9EJclC - JMlCJMdCJMVBI85EJdZGJs9EJdVGJs9EJcpDJM9EJcpDJMlCJMRBI8JAI8A/IsA/IrY8Ibg9Ibk9Ibk9 - Ib4/IrY8IbQ7ILY8IbY8IbQ7ILE7ILQ7ILk9IbQ7IKw5H6w5H6w5H6g3Hqc3Hqw5H6c3HqI2HZQxG5Iw - GpQxG5YyG5QxG5cyG5YyG5IwGo0uGY8wGo8wGo8wGpYyG5szHJcyG5EwGpIwGqA1HcRBI9xVN99kSN1b - Ps5EJaM2HZIwGpcyG6I2HZIwGoErF4ErF4ErF4AqF4ErF3ooFnkoFnooFnkoFnkoFnkoFnkoFncnFXUn - FXQnFXUnFXQnFW8lFG8lFG0kFGsjE2kjE2gjE2kjE2gjE2gjE2QhEmEhEmMhEl8fEVwfEV4fEVwfEVcd - EFcdEFcdEFcdEFAbD1AbD04aDk4aDk0aDk4aDk4aDksZDkcYDUYYDUYYDUYYDUYYDUQWDEIWDD8VDEIW - DD8VDD8VDDoUCzgSCjYSCjYSCjUSCjMRCTMRCTMRCTMRCTEQCTEQCTEQCTAQCSwPCCwPCC4QCSsOCCkO - CCkOCCcNBycNByUNByUNByUNByQMByALBiILBiALBiALBh8LBh8LBh0KBh0KBh8LBhsJBRgJBRoJBRoJ - BRgJBRgJBRgJBRoJBRoJBaelpP///////////////////////////////////////6alpA4FAw8FAw4F - Aw4FAwoDAgwFAwoDAgkDAgcDAgUCAQUCAQMBAQMBAQMBAQMBAQIBAQUCAQMBAQMBAQIBAQIBAQIBAQIB - AQIBAQIBAQAAAAIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9VGJtZGJsxDJM9EJdNGJtNGJsxDJMlCJMdCJMVBI8JA - I8pDJNNGJspDJMlCJMRBI8lCJM5EJcxDJMRBI8JAI70/IsA/Irs9IbQ7ILg9Ibg9Ibs9Ibg9IbY8IbY8 - Ibk9IbY8IbY8IbQ7ILE7ILE7IKg3Hqg3Hqo4HqU3HqU3HqA1HaA1HZkyG5QxG48wGo8wGpQxG5YyG5Yy - G40uGY0uGYouGY8wGpEwGpEwGpEwGpYyG5IwGo0uGYYsGJszHLE7INlIJ91cP9pOLrY8IZkyG4ouGZEw - GpszHI0uGYErF4ErF4AqF4AqF4AqF3wpFnooFnkoFnkoFnooFncnFXcnFXUnFXcnFXUnFXQnFXQnFXAl - FG8lFG0kFG8lFGsjE2sjE2YhEmYhEmYhEmQhEmEhEmEhEl8fEV8fEV4fEVgdEFcdEFUcD1cdEFcdEFIb - D1IbD1AbD1AbD00aDk4aDksZDkkYDUcYDUYYDUcYDUQWDEIWDEIWDEEWDD0UCz8VDD0UCz0UCz0UCzwU - CzgSCjYSCjUSCjUSCjMRCTMRCTEQCTEQCTAQCTAQCTAQCSwPCCwPCCwPCCkOCCkOCCkOCCUNBycNByUN - ByUNByQMByUNByQMByALBiALBiALBiILBh8LBh0KBhsJBRsJBRsJBRoJBRgJBRgJBRgJBRYHBBYHBBgJ - BRYHBKelpP///////////////////////////////////////6alpA4FAwwFAwwFAwwFAwoDAgwFAwoD - AgcDAgUCAQUCAQMBAQMBAQUCAQIBAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9VGJtFFJc5EJcpDJNNGJsxDJMxDJMVBI8lCJMRBI8JAI8lCJM9EJc5EJc5E - JclCJMdCJM9EJc9EJcVBI7s9Ibk9Ib0/Irs9Ib0/Irk9Ibg9IbQ7ILg9IbE7ILY8IbM7ILM7IL0/IrQ7 - IK86H6g3HqA1Hao4HqU3HqU3HqI2HaM2HZ40HJcyG5YyG48wGpIwGpQxG5QxG5cyG5IwGpEwGoYsGI8w - Go8wGosuGZEwGpkyG5YyG4YsGIgtGIouGZszHMA/IthHJsVBI6I2HY0uGYUsGIsuGZ40HJIwGoErF4Ms - GIAqF3wpFnooFnkoFnkoFnooFnkoFnooFnUnFXUnFXUnFXQnFXImFXImFXImFXQnFW0kFG0kFG0kFGkj - E2kjE2sjE2YhEmYhEmYhEmQhEmMhEl8fEWEhElwfEVgdEFcdEFcdEFcdEFcdEFAbD1IbD1AbD04aDk0a - DksZDksZDkcYDUcYDUcYDUYYDUQWDEQWDEIWDD8VDD0UCz8VDD0UCzoUCzwUCzoUCzgSCjoUCzYSCjUS - CjYSCjUSCjMRCTEQCTAQCTAQCS4QCSwPCC4QCSsOCCsOCCsOCCcNBycNBycNByUNByUNByQMByQMByQM - ByILBiALBiALBiALBh0KBh0KBhsJBRsJBRsJBRoJBRgJBRoJBRoJBRgJBRgJBRYHBBYHBKelpP////// - /////////////////////////////////6alpA8FAwwFAwwFAwoDAgwFAwoDAgkDAgUCAQMBAQUCAQUC - AQUCAQUCAQIBAQIBAQMBAQIBAQMBAQIBAQIBAQIBAQIBAQAAAAIBAQIBAQAAAAIBAQAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9ZGJtNGJtFFJc9EJcxDJMxDJM5EJcpDJMdCJMJAI8A/IsdCJMVBI8lCJMVBI8pDJMJAI8dCJMdC - JMdCJMdCJL0/Ir0/Ir4/Irg9IbY8Ibg9IbQ7ILg9Ibs9Ibs9IbQ7ILM7ILg9Ia05H6g3HqM2HaM2Hag3 - Hqg3Hqc3Hqc3HqA1HZkyG48wGpQxG4suGZIwGpEwGpYyG5EwGo8wGo0uGYouGYouGYgtGIYsGJIwGpIw - GpIwGosuGYYsGIYsGIouGZ40HLQ7IKo4HpIwGoYsGIMsGIMsGJszHJYyG4AqF3ooFnkoFnooFnooFnko - FnkoFnkoFncnFXUnFXcnFXcnFXImFXAlFHAlFHImFW8lFHImFW0kFG8lFGsjE2sjE2YhEmYhEmYhEmgj - E2QhEmMhEl8fEV4fEV4fEVoeEFcdEFgdEFgdEFcdEFcdEFMcD1IbD04aDk0aDksZDkkYDUsZDkkYDUcY - DUcYDUYYDUQWDEIWDEIWDEEWDD8VDEIWDD8VDDwUCz0UCzoUCzwUCzoUCzgSCjUSCjMRCTMRCTMRCTEQ - CTEQCS4QCS4QCSwPCCsOCCsOCCkOCCsOCCkOCCcNByUNByQMByUNByUNByUNByILBiILBiILBh0KBh8L - Bh0KBh0KBhsJBRoJBRoJBRoJBRgJBRoJBRsJBRoJBRYHBBgJBRYHBKelpP////////////////////// - /////////////////6alpA8FAwwFAwwFAwoDAgwFAwoDAgcDAgUCAQMBAQUCAQUCAQUCAQUCAQMBAQUC - AQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9ZGJs9EJcxD - JNFFJdNGJs5EJc5EJcxDJMlCJMVBI8RBI8A/IsJAI8lCJMlCJMdCJMdCJMdCJMA/Ir0/IsVBI8VBI74/ - Ir0/Ir0/Irk9IbQ7ILs9IbQ7IL0/Irg9IbM7IKw5H6w5H6w5H605H6I2HaU3HqU3HqU3HqI2HaU3Hpcy - G5QxG5cyG48wGo0uGY8wGpEwGpIwGo0uGYouGYgtGIUsGIgtGIYsGIYsGIsuGZEwGo0uGYouGYErF4Er - F4ErF4UsGJIwGo0uGYouGYErF4ErF4AqF5YyG5QxG4ErF3ooFnooFnooFnooFnooFnooFnkoFnkoFncn - FXkoFnkoFnQnFXImFXAlFHAlFHAlFHImFXQnFWsjE2kjE2kjE2kjE2gjE2YhEmMhEmMhEmMhEl4fEV4f - EV4fEVcdEFcdEFgdEFcdEFIbD1McD04aDlAbD1AbD1AbD00aDk4aDkkYDUsZDkkYDUcYDUYYDUQWDEQW - DEIWDEIWDEEWDD0UCzwUCzwUCzwUCzoUCzgSCjgSCjYSCjYSCjMRCTMRCTEQCTEQCTMRCTAQCTAQCS4Q - CSwPCCkOCCkOCCcNBycNBycNByUNByQMByQMByQMByQMByILBiALBiALBh8LBiALBh8LBh8LBh0KBhsJ - BRsJBRsJBRoJBRoJBRoJBRoJBRgJBRgJBRYHBKelpP////////////////////////////////////// - /6alpBEGAw8FAwwFAwwFAwoDAgkDAgkDAgcDAgcDAgUCAQMBAQMBAQUCAQMBAQMBAQMBAQMBAQMBAQIB - AQIBAQIBAQIBAQIBAQAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9FFJdVGJs9EJc5EJcxDJMlCJMxD - JMRBI8VBI8VBI8JAI70/Ir0/IsRBI8dCJMlCJMVBI8RBI8RBI8A/IsRBI8RBI8VBI74/Ir0/Irk9IbQ7 - ILQ7ILM7ILk9Ibg9Ia86H6o4Hqg3Hqc3HqU3HqI2HaA1HaU3Hqc3Hqc3HpszHJYyG5IwGo8wGosuGYou - GY0uGY0uGZIwGoouGYYsGIouGYUsGIgtGIYsGIUsGI8wGpEwGo0uGYYsGIAqF4AqF3wpFoAqF4MsGIYs - GIUsGIAqF3wpFoAqF5YyG5IwGoAqF3ooFnwpFnkoFnooFnwpFnkoFnkoFnkoFnUnFXUnFXUnFXImFXIm - FW0kFG0kFHAlFHAlFHAlFG0kFGkjE2gjE2YhEmgjE2QhEmQhEl8fEV4fEV8fEV4fEV4fEVcdEFgdEFcd - EFUcD1IbD1McD1IbD1AbD1AbD1AbD04aDk4aDksZDk0aDksZDkcYDUcYDUYYDUIWDEIWDEIWDEEWDDwU - CzwUCzwUCzwUCzgSCjYSCjYSCjYSCjMRCTMRCTYSCjMRCTMRCTEQCTMRCTAQCS4QCSwPCCkOCCsOCCcN - BycNByQMByUNByQMByILBiILBiILBiILBiALBh8LBiALBh8LBh8LBh0KBh0KBhsJBRsJBRsJBRsJBRgJ - BRoJBRgJBRgJBRgJBRgJBaelpP///////////////////////////////////////6alpBEGAw8FAw4F - AwwFAwoDAgkDAgcDAgcDAgcDAgUCAQMBAQMBAQMBAQMBAQIBAQIBAQMBAQIBAQMBAQMBAQIBAQIBAQIB - AQIBAQIBAQAAAAIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9VGJspDJM5EJc9EJcxDJM5EJclCJMdCJMVBI8RBI8JA - I8JAI74/Irs9IcA/IsVBI8dCJMRBI8JAI74/Ir0/Ir4/Irg9Ibk9IbQ7ILE7ILE7ILM7ILE7ILE7IK86 - H6M2Hac3HqU3HqU3Hqc3Hqc3HqM2HaA1HZ40HJw0HJszHJIwGpEwGpQxG4suGY8wGoouGY0uGYYsGI8w - GoYsGIgtGIgtGIUsGIYsGIErF40uGY0uGZEwGoMsGHwpFn4qF34qF3koFn4qF4UsGH4qF3wpFnUnFXoo - FpEwGpQxG4ErF3ooFnooFnkoFnkoFnkoFnkoFnQnFXUnFXcnFXImFXImFXAlFHQnFXAlFG8lFG0kFGsj - E28lFHAlFGkjE2gjE2YhEmQhEmQhEmMhEmQhEmEhEl4fEV4fEVwfEVgdEFoeEFcdEFcdEFcdEFUcD1Mc - D1IbD1AbD00aDk0aDk0aDk4aDksZDkcYDUYYDUQWDEYYDUIWDEQWDEEWDEEWDD0UCzwUCzoUCzoUCzoU - CzoUCzgSCjYSCjUSCjMRCTUSCjMRCTMRCTEQCTEQCTAQCS4QCSwPCCsOCCsOCCcNBycNBycNBycNByUN - ByUNByQMByQMByILBiILBiALBiILBh8LBh8LBh8LBh0KBhoJBRsJBRsJBRoJBRgJBRgJBRgJBRgJBRYH - BBYHBKelpP///////////////////////////////////////6alpBEGAxEGAw8FAwwFAwoDAgcDAgUC - AQUCAQUCAQUCAQUCAQMBAQUCAQIBAQIBAQUCAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQAAAAIBAQAAAAIB - AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9FFJcxDJMxDJMlCJMlCJM5EJcdCJMxDJMA/IsJAI8RBI74/Irk9Ibs9Ibs9 - Ib0/IsRBI70/Ir4/Ir0/Ir0/Ir0/IrY8IbM7IK05H686H605H7E7IK05H6c3Hqw5H6w5H6g3Hqg3HqM2 - Hac3Hpw0HKI2HZszHJkyG5IwGpEwGpEwGo8wGpEwGo0uGYouGYsuGY8wGoUsGIsuGYErF4UsGIErF4Us - GIErF4ErF4MsGIgtGI0uGYYsGH4qF3wpFnooFnkoFnooFoAqF34qF3ooFnkoFnkoFosuGZYyG4ErF3ko - FnkoFnkoFnUnFXkoFnUnFXImFXQnFXImFXQnFW8lFHAlFHImFW0kFG0kFGsjE20kFGsjE20kFGsjE2Qh - EmYhEmQhEmMhEmMhEmEhEmMhEmEhEl4fEVoeEFwfEVgdEFcdEFcdEFMcD1McD1IbD1IbD1IbD04aDk4a - Dk0aDk0aDksZDkkYDUcYDUQWDEYYDUIWDEIWDD8VDEEWDD8VDD8VDD0UCzoUCzoUCzoUCzYSCjYSCjYS - CjMRCTMRCTMRCTMRCTEQCTEQCS4QCSwPCC4QCSsOCCkOCCkOCCcNBycNBykOCCUNBycNByUNByILBiIL - BiALBiALBh8LBh8LBh8LBh0KBhsJBRsJBR0KBhoJBRoJBRoJBRYHBBgJBRYHBBYHBBgJBaelpP////// - /////////////////////////////////6alpBEGAxEGAw8FAwwFAwkDAgcDAgcDAgcDAgUCAQUCAQUC - AQUCAQMBAQUCAQIBAQMBAQUCAQMBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9hHJthHJtVGJspDJMdCJMdCJMVBI8VBI8RBI8lCJMJAI74/Ir0/IsRBI7g9IbQ7ILg9IbY8IcA/ - Ir0/Ir0/IrY8IbM7ILg9IbY8IbE7ILE7IK05H686H6w5H6o4Hq05H540HKc3Hqc3HqU3Hpw0HJw0HJQx - G5EwGo0uGY8wGo8wGo0uGYouGY8wGogtGI0uGYouGYMsGIouGYYsGIErF4ErF34qF3wpFoErF34qF4su - GYYsGIAqF3wpFn4qF3wpFnooFnooFoErF4ErF34qF3koFnooFoouGZQxG4ErF3koFnkoFnUnFXcnFXko - FnkoFncnFXQnFXAlFHQnFXAlFGsjE3AlFG8lFHAlFGsjE2sjE2kjE2sjE20kFGYhEmYhEmYhEmEhEl8f - EWEhEl4fEV8fEV4fEVgdEFgdEFcdEFIbD1UcD1McD1McD1IbD1IbD1AbD00aDk0aDk4aDk0aDkkYDUkY - DUQWDEQWDEcYDUQWDEIWDD8VDEEWDD0UCz0UCz0UCzoUCzgSCjYSCjUSCjYSCjUSCjMRCTEQCTEQCTEQ - CTEQCTEQCTAQCS4QCS4QCSkOCCwPCCsOCCsOCCkOCCcNByQMByUNByQMByILBiALBh8LBh8LBh0KBh8L - Bh8LBh0KBhsJBRsJBRsJBRgJBRoJBRgJBRYHBBgJBRYHBBgJBRgJBaelpP////////////////////// - /////////////////6alpBEGAxEGAxEGAw4FAwcDAgcDAgUCAQUCAQUCAQMBAQMBAQMBAQMBAQMBAQIB - AQIBAQMBAQMBAQAAAAAAAAIBAQAAAAIBAQAAAAAAAAAAAAAAAAIBAQIBAQAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9VGJtFFJc5E - JcpDJM5EJclCJMVBI8RBI8JAI8VBI8JAI70/Ir4/Ir0/Irk9IbQ7ILM7ILQ7ILQ7ILg9Ibs9IbQ7ILg9 - Ib0/Irg9Iaw5H686H6w5H6w5H6w5H6U3HqM2HaM2HaM2HaM2HZw0HJYyG40uGY0uGY0uGYouGY0uGY0u - GYYsGIYsGIouGYYsGIYsGIAqF4UsGIMsGIErF4gtGH4qF4AqF34qF3koFoErF48wGogtGIUsGHooFnwp - FnkoFnwpFnooFoErF4AqF3ooFnwpFnooFoUsGJQxG4UsGHkoFnkoFnkoFnUnFXcnFXcnFXQnFXQnFXIm - FXAlFG8lFGsjE3AlFG8lFG0kFGkjE2kjE2gjE2sjE2sjE2gjE2QhEmEhEmEhEl8fEWMhEl4fEV4fEVwf - EVgdEFcdEFUcD1McD1McD1McD1McD1McD1IbD04aDk4aDk0aDk0aDkkYDUkYDUkYDUcYDUQWDEYYDUQW - DEIWDEEWDEEWDD0UCz0UCz0UCz0UCzoUCzgSCjYSCjUSCjUSCjUSCjMRCTMRCTEQCTEQCTAQCTAQCS4Q - CS4QCSsOCCsOCCkOCCkOCCUNByQMByUNByILBiILBiILBiILBiALBiILBh8LBh0KBhsJBRsJBR0KBhsJ - BR0KBhoJBRoJBRgJBRoJBRgJBRYHBBgJBRQHBKelpP////////////////////////////////////// - /6alpBEGAxEGAw8FAwwFAwkDAgcDAgUCAQUCAQUCAQUCAQcDAgUCAQUCAQMBAQIBAQMBAQIBAQMBAQIB - AQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9NGJs5EJcxDJNFFJcxDJMdCJMA/ - IsJAI8JAI8RBI8A/Ir4/IsJAI7k9IbY8IbM7ILY8Ia86H7Q7IKw5H686H7Q7ILE7ILM7IK05H6w5H6w5 - H6g3Hqo4HqM2Hag3HqI2Hac3HqM2HZYyG5IwGo0uGZQxG4gtGIouGY0uGYsuGYouGYouGYYsGIUsGIAq - F4ErF4MsGHwpFnwpFoAqF4AqF4UsGIErF4ErF3ooFoMsGIYsGI0uGYgtGHwpFn4qF3koFn4qF3ooFoAq - F3koFnwpFnkoFnooFoMsGJIwGogtGHkoFnkoFnkoFnImFXQnFXUnFXAlFHImFW0kFG8lFG8lFG0kFG8l - FG8lFG0kFG0kFG8lFGgjE2gjE2kjE20kFGgjE2MhEmMhEl8fEV8fEV4fEVoeEFoeEFoeEFcdEFcdEFcd - EFMcD1IbD1McD1IbD1IbD04aDk4aDk4aDksZDkkYDUsZDksZDkkYDUIWDEYYDUIWDEEWDEEWDD0UCzwU - Cz8VDD0UCz0UCzoUCzgSCjYSCjYSCjUSCjUSCjUSCjMRCTMRCS4QCTAQCTAQCS4QCS4QCSkOCCkOCCkO - CCsOCCcNByUNByUNByQMByILBiILBiILBiALBiILBh8LBh0KBh0KBhsJBR0KBhsJBR0KBh0KBhoJBRoJ - BRoJBRsJBRoJBRgJBRYHBKelpP///////////////////////////////////////6alpBEGAxEGAw8F - AwwFAwkDAgcDAgkDAgUCAQUCAQUCAQMBAQMBAQUCAQMBAQMBAQUCAQIBAQAAAAAAAAIBAQIBAQAAAAAA - AAAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9VGJtNGJs9EJc9EJclCJMlCJMVBI8A/IsRBI8RBI8RB - I8JAI70/Irg9IbY8IbY8Ia05H7E7IKc3Hqg3Hq05H605H6U3HqU3Hq86H6g3Hp40HKI2HaI2HaA1HZw0 - HJszHJYyG5kyG4suGY8wGo0uGYsuGY0uGYsuGY0uGYYsGIgtGIgtGIouGYErF4MsGIErF3koFn4qF4Aq - F4ErF4AqF4AqF34qF4AqF4AqF4AqF4YsGIYsGIouGYAqF3wpFnkoFnwpFnwpFoMsGHooFn4qF3ooFnoo - FoUsGJEwGoUsGHkoFncnFXQnFXQnFXQnFXkoFnAlFHAlFHAlFHImFXAlFG0kFG0kFGsjE2kjE2YhEmYh - EmYhEmgjE2gjE2YhEmYhEmQhEmEhEmEhEmEhEloeEFoeEFoeEFwfEVcdEFgdEFcdEFMcD1McD1IbD04a - DlAbD1AbD04aDk4aDk0aDkkYDUcYDUkYDUcYDUcYDUcYDUQWDEIWDEEWDD8VDD8VDD0UCzwUCzwUCzoU - CzgSCjgSCjYSCjUSCjMRCTMRCTMRCTMRCTEQCTEQCTAQCTAQCTAQCS4QCSwPCCkOCCsOCCcNByUNBycN - ByUNByQMByQMByQMByILBiALBh8LBh8LBh0KBh0KBhsJBR0KBhsJBR0KBhsJBRoJBRoJBRgJBRgJBRgJ - BRgJBaelpP///////////////////////////////////////6alpBEGAxEGAw4FAwoDAgkDAgoDAgcD - AgUCAQUCAQUCAQMBAQUCAQUCAQUCAQMBAQMBAQMBAQIBAQMBAQIBAQIBAQIBAQAAAAAAAAIBAQIBAQAA - AAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9ZGJtVGJspDJM5EJcxDJMlCJMRBI8A/IsA/IsA/Irs9Ib0/Ir0/Irs9Ibg9 - IbY8Ia86H7E7ILE7IKg3Hqo4Hqc3HqU3HqU3HqA1HaA1HaA1HZw0HJszHJszHJQxG5IwGpQxG540HI8w - GosuGYsuGY0uGYouGYouGYYsGIsuGYgtGIgtGIAqF4AqF4ErF3ooFn4qF3wpFnwpFoMsGIMsGHooFnko - FnkoFnkoFn4qF4MsGIouGY0uGXooFnkoFnUnFXkoFnkoFn4qF3koFncnFXkoFncnFYMsGI8wGoouGXko - FnQnFXUnFXQnFXUnFXcnFXQnFXQnFW8lFHAlFHAlFGsjE20kFGgjE2kjE2YhEmYhEmYhEmYhEmQhEmYh - EmkjE2QhEmEhEmEhEl4fEVwfEV4fEVoeEFgdEFcdEFcdEFgdEFMcD1McD1IbD1AbD1McD1IbD04aDlAb - D00aDkcYDUcYDUcYDUcYDUYYDUYYDUQWDEEWDEEWDD8VDD8VDD0UCzwUCzgSCjoUCzoUCzYSCjUSCjMR - CTUSCjMRCTMRCTEQCTAQCTAQCS4QCS4QCS4QCSwPCCwPCCkOCCsOCCcNByUNByUNByQMByQMByQMByIL - BiILBiALBiALBh8LBh0KBh0KBh0KBh0KBhsJBRsJBRgJBRoJBRoJBRoJBRgJBRYHBBYHBKelpP////// - /////////////////////////////////6alpBEGAw8FAwwFAwoDAgoDAgkDAgcDAgcDAgUCAQUCAQMB - AQMBAQUCAQMBAQMBAQIBAQIBAQIBAQAAAAMBAQAAAAIBAQAAAAMBAQAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9ZGJs9EJc5EJdVGJs9EJcRBI8RBI8JAI74/Ir4/Irs9Ibs9Ibk9Ib0/Irk9IbQ7ILE7ILQ7IK05 - H605H6o4Hqo4HqU3HqA1HZw0HKM2HZszHJszHJkyG5YyG5kyG5YyG5IwGpcyG5EwGpEwGo8wGpIwGo0u - GYUsGIYsGIYsGI8wGoouGYErF3koFoAqF4ErF4AqF3ooFn4qF4AqF4MsGIMsGHooFnkoFoErF34qF4Us - GIgtGIsuGXcnFXkoFnkoFnkoFnkoFnkoFnkoFnwpFnkoFnkoFnwpFo8wGosuGXooFncnFXImFXUnFXcn - FXQnFXUnFXQnFXAlFGsjE3AlFGsjE20kFG8lFGkjE2sjE2sjE2YhEmYhEmQhEmYhEmQhEmQhEmEhEl8f - EVoeEFwfEV8fEVwfEVgdEFcdEFUcD1cdEFUcD1IbD1IbD1McD1McD1IbD04aDk0aDksZDkkYDUkYDUsZ - DkkYDUcYDUcYDUQWDD8VDEEWDD8VDD0UCz8VDD0UCzoUCzwUCzwUCzYSCjUSCjMRCTMRCTMRCTMRCTEQ - CTAQCS4QCSsOCC4QCS4QCSwPCCcNBysOCCkOCCkOCCcNBycNByUNByUNByQMByILBiALBiALBh8LBh8L - BiILBh8LBh0KBhsJBR0KBhsJBRoJBRoJBRgJBRgJBRoJBRgJBRYHBKilpf////////////////////// - /////////////////6elpA8FAw4FAwwFAwoDAgoDAgoDAgcDAgkDAgcDAgUCAQUCAQMBAQMBAQUCAQMB - AQMBAQIBAQMBAQAAAAMBAQIBAQAAAAAAAAAAAAIBAQAAAAIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9FFJc9EJdFF - Jc5EJc9EJcRBI8lCJMA/Ir0/Ir4/Irs9IbY8Ibg9IbQ7IL0/Irg9IbQ7ILE7IK05H686H605H6g3HqA1 - HZ40HJszHJ40HJszHJszHJszHJYyG5QxG5YyG40uGZcyG5IwGpIwGpEwGo8wGpEwGo0uGYsuGYMsGIYs - GIErF3wpFoAqF3ooFnwpFn4qF34qF4AqF34qF4ErF4AqF3cnFXooFnooFnwpFoYsGIsuGYgtGH4qF3cn - FXkoFnkoFnkoFnkoFncnFXooFnkoFnkoFnkoFoouGYYsGHUnFXcnFXQnFXImFXAlFG8lFHQnFXAlFG8l - FHAlFG8lFGsjE20kFGkjE2YhEmYhEmgjE2gjE2gjE2QhEmQhEmMhEmYhEmQhEl8fEVoeEFoeEFoeEFgd - EFoeEFgdEFcdEFcdEFUcD1McD1McD1IbD04aDk4aDlAbD04aDk4aDksZDkkYDUsZDksZDkcYDUYYDUQW - DEEWDEIWDEEWDD8VDD8VDD8VDDwUCzgSCjYSCjUSCjYSCjMRCTUSCjUSCjMRCTAQCTEQCTAQCSwPCCwP - CCwPCCsOCCkOCCsOCCcNBycNBykOCCkOCCUNByQMByQMByILBiALBiALBiALBh8LBh8LBh8LBh0KBhsJ - BRsJBRsJBRoJBRoJBRgJBRgJBRgJBRgJBRQHBKilpf////////////////////////////////////// - /6alpA8FAwwFAwwFAwoDAgoDAgwFAwkDAgcDAgUCAQUCAQUCAQMBAQMBAQMBAQMBAQMBAQMBAQIBAQAA - AAIBAQAAAAAAAAAAAAAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9VGJtZGJs5EJdVGJslCJMlCJMxD - JMVBI8VBI70/Irk9Ibs9Ibk9IbY8Ibg9IbM7ILM7ILQ7IKw5H6w5H686H6g3HqU3Hqc3HqA1HZw0HJsz - HJszHJkyG5kyG5IwGpYyG5IwGpcyG48wGo8wGosuGYouGYsuGYouGYYsGIMsGIErF4AqF3wpFn4qF34q - F34qF3wpFoAqF34qF3koFoAqF4AqF34qF3ooFnooFnooFnwpFo8wGo0uGXooFnUnFXcnFXkoFnkoFncn - FXQnFXcnFXooFnUnFXkoFosuGYouGXooFncnFW8lFHImFXQnFXImFXImFXcnFXAlFGsjE2sjE20kFG8l - FGkjE2YhEmgjE2gjE2gjE2gjE2kjE2MhEmMhEmQhEmMhEmEhEl4fEV8fEVoeEFoeEFgdEFcdEFcdEFcd - EFUcD1UcD1UcD1McD04aDlIbD1AbD00aDk0aDk0aDkkYDUkYDUYYDUkYDUYYDUIWDEEWDEYYDUIWDEIW - DD8VDD8VDDwUCzgSCjYSCjYSCjUSCjMRCTMRCTMRCTMRCTMRCTAQCTAQCTEQCSsOCC4QCSwPCCkOCCsO - CCcNBycNBykOCCcNBycNByILBiILBiILBh8LBiALBiALBh8LBh0KBh0KBh8LBh0KBhsJBRsJBRsJBRoJ - BRgJBRYHBBgJBRgJBRYHBKelpP///////////////////////////////////////6alpA4FAwwFAwwF - AwoDAgwFAwwFAwoDAgcDAgUCAQMBAQMBAQcDAgMBAQUCAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIB - AQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////89EJdVGJtFFJc9EJcpDJMpDJMRBI8dCJL4/IsJAI70/ - Ir0/Irk9IbY8Ibg9IbM7IK86H7M7IKo4Hqo4Hqo4Hqg3Hqg3HqI2HaA1HaA1HZ40HJw0HJQxG5YyG5Qx - G5cyG5IwGpkyG48wGo8wGoouGY8wGo0uGYUsGIMsGIMsGIAqF4ErF4AqF4AqF4AqF4AqF4AqF34qF3wp - FoMsGIAqF4AqF3cnFXkoFnUnFXkoFoAqF4suGY8wGoErF3koFnQnFXkoFnkoFnwpFnkoFnkoFnkoFnko - FncnFYUsGIouGXooFnUnFXImFW8lFHAlFHQnFXQnFXUnFW0kFG0kFG0kFGsjE2sjE2kjE2gjE2gjE2gj - E2sjE2QhEmYhEmQhEmMhEl8fEWEhEmMhEl4fEVoeEFcdEFcdEFoeEFcdEFUcD1cdEFMcD1McD1McD1Mc - D1AbD1AbD1AbD1AbD04aDk0aDkkYDUcYDUYYDUcYDUcYDUQWDEIWDEIWDEEWDEEWDD0UCz8VDDwUCzoU - CzgSCjgSCjYSCjYSCjUSCjUSCjMRCTEQCTAQCS4QCTEQCS4QCSwPCCsOCCkOCCkOCCcNByUNByUNByQM - ByUNByUNByUNByILBiALBiALBh8LBh8LBh0KBh0KBh0KBhsJBRsJBRsJBRsJBRoJBRoJBRoJBRgJBRYH - BBYHBKelpP///////////////////////////////////////6alpAwFAwwFAw4FAw4FAwwFAwoDAgwF - AwkDAgcDAgMBAQMBAQcDAgMBAQMBAQMBAQMBAQMBAQMBAQAAAAIBAQIBAQIBAQAAAAIBAQAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9ZGJtFFJdNGJtNGJsxDJMlCJMJAI8JAI8A/IsA/Irs9Ib4/Irg9Ibs9IbE7 - ILE7ILE7IK86H605H6o4Hqg3Hqo4HqU3Hqg3Hp40HJ40HJ40HJ40HJw0HJIwGpYyG5cyG5EwGpIwGpQx - G48wGogtGIsuGYYsGIUsGIYsGIMsGIMsGIErF34qF34qF4AqF4ErF4ErF34qF3ooFoAqF4AqF3wpFnoo - FnkoFnwpFnkoFnwpFogtGI0uGYMsGHooFnooFncnFXkoFnooFnkoFnwpFnUnFXcnFXkoFoMsGIUsGHwp - FnUnFXQnFXUnFXAlFG8lFHcnFXQnFXImFW0kFG0kFGsjE2sjE20kFGsjE2kjE2YhEmkjE2gjE2QhEmQh - EmQhEl8fEV4fEWEhEmEhElwfEVoeEFcdEFoeEFcdEFcdEFcdEFUcD1McD1McD1IbD1AbD1IbD1IbD1Ab - D00aDk0aDkkYDUcYDUcYDUcYDUcYDUYYDUIWDEEWDD8VDD0UCz8VDDwUCzgSCjgSCjgSCjgSCjYSCjUS - CjUSCjMRCTEQCTAQCTEQCS4QCTAQCS4QCSsOCCkOCCsOCCkOCCkOCCUNBycNByUNByQMByUNByQMByQM - ByILBiILBiALBh8LBh0KBh0KBhsJBRsJBR0KBhsJBRsJBRoJBRgJBRgJBRgJBRYHBBYHBKelpP////// - /////////////////////////////////6alpA4FAw4FAwwFAwoDAgoDAgwFAwoDAgkDAgUCAQUCAQUC - AQUCAQUCAQUCAQMBAQMBAQMBAQMBAQIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9NGJtVGJsxDJNNGJs9EJclCJMpDJMRBI8lCJMA/Ir4/Irs9Ib0/Irk9IbE7IK86H605H686H7E7 - IKc3Hqc3Hqo4HqU3Hqc3HqU3HqI2HZszHJszHJkyG5IwGpEwGo8wGpIwGpEwGo8wGosuGYYsGIYsGIYs - GIYsGIgtGIgtGIErF4MsGIMsGIUsGH4qF3ooFoErF4ErF3ooFnwpFoMsGIMsGIErF4AqF3wpFnooFnoo - FoouGY8wGoouGX4qF3wpFnkoFnooFn4qF3ooFnkoFncnFXUnFXkoFoMsGIUsGH4qF3UnFXUnFXImFXQn - FXAlFHQnFXQnFXImFXAlFHQnFW0kFGkjE2sjE2gjE2gjE2YhEmMhEmQhEmQhEmMhEmMhEmEhEl8fEWEh - El4fEVwfEVoeEFcdEFgdEFcdEFcdEFcdEFUcD1McD1McD1McD1McD1IbD1IbD04aDksZDk0aDkkYDUcY - DUcYDUkYDUYYDUQWDEEWDEEWDEIWDD8VDD8VDDwUCzwUCzoUCzYSCjYSCjYSCjUSCjMRCTEQCTAQCTEQ - CTMRCS4QCSwPCDAQCS4QCSsOCCkOCCcNBysOCCcNBycNByUNByUNByQMByILBiILBiILBiILBiALBh8L - Bh0KBh0KBhsJBR8LBh0KBh0KBhsJBRoJBRgJBRoJBRgJBRYHBBYHBKelpP////////////////////// - /////////////////6alpA4FAwoDAgoDAgwFAwwFAwwFAwoDAgoDAgcDAgUCAQMBAQMBAQMBAQMBAQMB - AQMBAQIBAQIBAQIBAQMBAQAAAAIBAQAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9hHJtZGJtVG - JtFFJc9EJcdCJMpDJMlCJMlCJMJAI8JAI70/Irk9IbQ7ILQ7ILE7ILM7ILM7IK86H6o4HqM2HaA1HaI2 - Hao4HpszHJYyG5cyG5kyG5cyG5YyG5cyG48wGpQxG48wGosuGYsuGYgtGIouGYsuGYUsGIMsGIMsGIUs - GIMsGIgtGIAqF3wpFoErF4MsGIErF3koFnooFnooFoUsGHwpFoAqF3ooFnkoFnkoFogtGJEwGogtGHko - FnwpFnooFnooFn4qF3wpFnkoFnkoFnkoFnUnFYMsGIYsGH4qF3QnFXImFXUnFXQnFXUnFW8lFHImFXcn - FXAlFG0kFG0kFGkjE2gjE2YhEmYhEmgjE2QhEmQhEmMhEl8fEV8fEV4fEV8fEWEhEl4fEVwfEVoeEFcd - EFgdEFgdEFcdEFcdEFUcD1IbD1McD1McD1IbD1AbD04aDk4aDk0aDkkYDUcYDUcYDUcYDUkYDUQWDEQW - DEEWDEIWDEIWDD8VDD0UCz0UCzwUCzgSCjoUCzYSCjUSCjMRCTMRCTMRCTMRCTMRCTEQCS4QCSwPCC4Q - CS4QCSwPCCkOCCsOCCsOCCkOCCUNByUNByQMByILBiILBiILBiILBiALBiILBiALBh0KBh0KBhsJBR8L - Bh0KBh0KBhoJBRoJBRgJBRgJBRgJBRYHBBYHBKelpP////////////////////////////////////// - /6alpA4FAw4FAwwFAw4FAw4FAwwFAwoDAgoDAgkDAgUCAQUCAQUCAQMBAQMBAQMBAQIBAQMBAQMBAQMB - AQIBAQIBAQAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9VGJtVGJtVGJs9EJcpDJMpDJMlC - JMdCJMdCJL4/IsA/Ir0/Irk9IbY8IbQ7IK86H686H605H605H6w5H6w5H6I2HaI2HZszHKI2HZw0HJYy - G5kyG5cyG5QxG5EwGo0uGZIwGo8wGoYsGIsuGYsuGYouGYouGYgtGIMsGH4qF4AqF34qF3wpFn4qF34q - F3ooFnwpFoMsGIAqF34qF3wpFoUsGHwpFnooFnwpFnkoFnwpFoouGY8wGogtGHcnFXkoFnUnFXwpFoAq - F3koFnkoFnooFncnFXkoFnwpFoYsGIUsGHUnFXQnFXImFXImFXAlFHQnFXImFXcnFXAlFG0kFG0kFG0k - FGgjE2sjE2kjE2gjE2QhEmQhEmQhEl8fEV8fEV8fEV8fEV8fEV8fEV4fEVoeEFcdEFcdEFcdEFUcD1cd - EFcdEFMcD1UcD1IbD1IbD1IbD00aDk4aDk0aDkkYDUkYDUsZDksZDkkYDUYYDUQWDEIWDEIWDEEWDD8V - DD0UCzwUCzwUCzgSCjwUCzgSCjYSCjMRCTUSCjYSCjUSCjMRCTEQCTAQCTAQCS4QCSwPCCsOCCsOCCkO - CCkOCCcNBycNByUNByILBiILBiILBiILBiALBiALBiALBiALBh0KBhsJBRsJBR0KBh0KBhoJBRsJBRoJ - BRoJBRgJBRgJBRYHBBYHBKelpP///////////////////////////////////////6alpA4FAwwFAw4F - AwwFAwwFAwwFAwoDAgwFAwkDAgUCAQUCAQUCAQMBAQMBAQUCAQUCAQMBAQIBAQIBAQIBAQAAAAAAAAIB - AQAAAAAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9NGJthHJthHJs5EJc5EJcpDJMdCJMJAI8dCJMJAI74/ - Ir0/Ir0/IrY8Ibg9Iao4Hq05H605H686H6c3Hqo4Hqg3HqA1HZw0HJszHJszHJw0HJYyG5YyG5EwGpEw - Go0uGZEwGpEwGosuGYYsGIouGZEwGoYsGIYsGIErF4AqF3wpFoAqF4MsGHwpFnkoFoAqF4AqF34qF34q - F3wpFoMsGIErF3wpFnwpFn4qF3koFnwpFoouGY8wGosuGXkoFnkoFncnFXkoFnwpFnkoFnooFnkoFncn - FXkoFnkoFogtGIYsGHooFncnFXcnFXImFXImFXUnFXQnFXUnFXAlFG8lFG8lFGsjE2kjE2gjE2kjE2Yh - EmQhEmYhEmgjE2MhEl8fEV8fEV4fEV4fEV8fEV8fEVgdEFcdEFgdEFgdEFcdEFUcD1UcD1UcD1McD1Ab - D1AbD04aDk0aDk4aDk4aDksZDksZDk0aDksZDkcYDUQWDEIWDEIWDEIWDD8VDD0UCzwUCzoUCzoUCzgS - CjwUCzgSCjYSCjUSCjUSCjYSCjMRCTEQCTMRCTEQCS4QCTAQCSwPCCsOCCwPCCkOCCcNBycNBycNByUN - ByQMByQMByILBiILBiILBiALBiILBiALBh8LBh0KBh0KBh0KBhsJBRoJBRoJBRgJBRoJBRoJBRgJBRgJ - BRYHBKelpP///////////////////////////////////////6alpA4FAwwFAw4FAwwFAwwFAwoDAgkD - AgkDAgcDAgcDAgUCAQUCAQUCAQMBAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQAAAAIBAQIBAQIBAQAAAAAA - AAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9ZGJtZGJtVGJs9EJc9EJcxDJMlCJMVBI8RBI8RBI8JAI70/Ir0/IrY8Ibg9 - IbE7IK05H6w5H6o4Hqg3Hqg3HqU3HqA1HZ40HKI2HZw0HJQxG5kyG5szHJIwGpQxG5QxG5EwGpEwGo0u - GYsuGYouGYYsGIgtGIgtGIgtGIgtGIMsGIMsGIMsGIErF4YsGIAqF3wpFoAqF3wpFnkoFnwpFoErF34q - F4ErF3ooFoAqF3koFogtGI8wGosuGXooFnooFncnFXooFnooFnwpFnwpFnwpFnUnFXkoFnooFogtGIYs - GHcnFXcnFXQnFXImFXcnFXQnFXQnFXQnFXQnFXAlFGsjE2sjE2gjE2kjE2YhEmQhEmMhEmEhEl8fEWEh - EmEhEmMhEl4fEV4fEVwfEVwfEV4fEVgdEFgdEFcdEFcdEFcdEFMcD1McD1McD1AbD1IbD04aDk4aDk4a - Dk4aDk4aDk0aDkkYDUcYDUYYDUIWDEQWDEEWDEIWDEEWDDwUCz0UCz0UCzwUCzoUCzoUCzYSCjYSCjUS - CjUSCjUSCjMRCTEQCTMRCTMRCS4QCS4QCSsOCCkOCCsOCCsOCCkOCCsOCCkOCCUNByQMByQMByQMByIL - BiALBiALBiALBh0KBh0KBh0KBh0KBhoJBRsJBRsJBRoJBRoJBRoJBRgJBRgJBRYHBBQHBKelpP////// - /////////////////////////////////6alpA4FAwwFAwoDAgwFAwwFAwwFAwoDAgoDAgoDAgkDAgUC - AQUCAQMBAQUCAQMBAQIBAQIBAQMBAQIBAQAAAAIBAQMBAQIBAQMBAQAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9lIJ9ZGJs9EJcxDJM5EJdFFJc5EJcVBI8lCJMA/Irs9IcA/Irs9IbY8IbE7ILE7IKw5H6w5H605 - H6w5H6U3HqM2HaI2HZw0HJw0HJszHJQxG5szHJYyG5IwGpQxG5cyG5IwGogtGI0uGY8wGosuGYYsGIYs - GI0uGYgtGIUsGIUsGIErF4UsGIUsGIErF4YsGIAqF4MsGIAqF3wpFoMsGIUsGH4qF4AqF4ErF4AqF4Er - F34qF5IwGpEwGnwpFoErF3UnFXooFnwpFnwpFnooFncnFXUnFXkoFnwpFoYsGIgtGHkoFnUnFXcnFXUn - FXAlFHUnFXkoFnUnFXAlFHImFW0kFHAlFGsjE2sjE2gjE2MhEmgjE2EhEl8fEWMhEl8fEV8fEVwfEV8f - EVwfEVwfEV4fEVoeEFoeEFgdEFgdEFcdEFUcD1cdEFIbD1IbD1IbD1IbD1AbD0sZDk0aDk4aDksZDkkY - DUYYDUQWDEIWDEYYDUEWDEIWDEEWDEEWDD8VDD0UCz0UCzoUCzgSCjUSCjgSCjYSCjYSCjUSCjMRCTMR - CTEQCTEQCS4QCS4QCSsOCCkOCCsOCCkOCCkOCCkOCCcNByUNByQMByILBiUNByUNByALBiALBiALBh8L - Bh8LBh0KBhsJBRoJBRoJBRsJBRoJBRsJBRoJBRoJBRoJBRYHBBQHBKelpP////////////////////// - /////////////////6alpAwFAwwFAwwFAwoDAgwFAwkDAgoDAgkDAgcDAgkDAgcDAgUCAQMBAQMBAQMB - AQIBAQMBAQMBAQIBAQMBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9ZGJtFFJdVG - JthHJsxDJM5EJcpDJMlCJMJAI74/IsJAI8A/Ir4/Irk9IbQ7IK86H7E7IKw5H7E7IKw5H6I2HaA1HaI2 - HaI2HZszHJ40HJkyG5cyG5cyG5cyG5szHJYyG48wGo0uGYsuGY8wGogtGIsuGYgtGIouGYsuGYsuGYMs - GIYsGIMsGIAqF4YsGIUsGH4qF4ErF4ErF4AqF4ErF4MsGIMsGIMsGHwpFnkoFnwpFoAqF5EwGpIwGoAq - F4AqF3koFnwpFnwpFnooFnwpFnooFnkoFnooFnkoFoUsGIsuGXooFnkoFnQnFXUnFXQnFXUnFXUnFXIm - FXUnFXAlFG0kFHAlFG8lFGsjE2gjE2gjE2QhEmQhEmQhEmQhEmMhEl8fEV8fEV8fEV8fEVwfEVwfEV4f - EVgdEFcdEFcdEFUcD1McD1UcD1IbD1IbD1AbD1AbD1AbD04aDk4aDk0aDksZDksZDkcYDUYYDUIWDEIW - DEEWDEIWDEIWDD8VDDwUCzwUCzwUCzwUCzgSCjgSCjgSCjYSCjMRCTMRCTMRCTEQCTAQCS4QCS4QCSwP - CCsOCCkOCCsOCCcNBycNBycNByUNByUNByQMByQMByQMByILBiALBiALBiALBh8LBh0KBh0KBh0KBh0K - BhoJBRoJBRoJBRoJBRoJBRgJBRgJBRYHBBQHBKelpP////////////////////////////////////// - /6alpA4FAwwFAwwFAwoDAgwFAwkDAgkDAgoDAgoDAgkDAgcDAgUCAQMBAQMBAQUCAQIBAQUCAQIBAQAA - AAAAAAAAAAAAAAIBAQAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9VGJtVGJtNGJtFFJcxDJMdCJNFF - JcdCJMJAI8JAI74/IsA/Ir4/Irg9IbQ7ILY8Iaw5H7E7IK86H6U3Hqc3HqM2HZszHJw0HJw0HKA1HaM2 - HZkyG5QxG5cyG540HJYyG5QxG5YyG48wGpIwGosuGYgtGIsuGYgtGIouGYsuGYouGYouGYgtGIUsGIAq - F4YsGIAqF4suGX4qF34qF4MsGHwpFoUsGIMsGIAqF3ooFn4qF3wpFosuGZYyG4AqF3ooFoAqF4AqF34q - F3wpFnwpFnwpFnkoFnooFn4qF4MsGIYsGHwpFncnFXcnFXQnFXImFXUnFXUnFXcnFXcnFXImFXImFW8l - FGsjE2kjE2sjE2gjE2kjE2kjE2MhEmYhEmQhEmMhEl8fEV8fEVwfEVwfEVoeEFoeEFcdEFcdEFcdEFUc - D1McD1UcD1McD1IbD04aDk4aDlAbD04aDk0aDksZDkkYDUsZDkcYDUQWDEQWDEQWDEIWDEEWDEEWDD8V - DDwUCz0UCzwUCzwUCzYSCjgSCjgSCjYSCjMRCTMRCTMRCTEQCTEQCTAQCTAQCTAQCSwPCCsOCCsOCCcN - BykOCCcNByUNByQMByUNByUNByQMByALBiALBiILBiALBh8LBiALBh0KBh0KBh0KBhsJBRsJBRoJBRoJ - BRoJBRgJBRgJBRoJBRYHBKelpP///////////////////////////////////////6alpA4FAwoDAgoD - AgoDAgwFAwoDAgoDAgoDAgkDAgoDAgkDAgUCAQUCAQUCAQMBAQIBAQUCAQIBAQAAAAIBAQAAAAAAAAIB - AQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9ZGJtNGJtVGJtNGJs5EJcpDJMRBI8RBI8VBI8dCJMJA - I8RBI7s9Ib0/Irs9IbQ7ILE7ILY8IaU3HrE7IKc3Hqc3HqM2HZw0HKI2HZw0HJszHJcyG5cyG5szHJsz - HJYyG5IwGpIwGpYyG5IwGogtGIYsGIgtGIsuGYsuGZEwGo0uGYsuGYYsGIYsGIouGYYsGIErF4UsGIUs - GIMsGIAqF4AqF4AqF4UsGIMsGHwpFn4qF34qF48wGpkyG4ouGXkoFnwpFoAqF3wpFoAqF4AqF3wpFnko - FnooFnkoFoMsGIUsGIAqF3UnFXkoFnUnFXQnFXImFXQnFXUnFXQnFXQnFXImFW0kFGkjE2sjE2sjE2Yh - EmkjE2kjE2YhEmYhEmQhEl8fEV8fEV8fEV8fEVoeEFoeEFoeEFwfEVgdEFcdEFcdEFMcD1McD1IbD1Ib - D00aDlIbD1IbD00aDksZDksZDksZDksZDkkYDUYYDUYYDUYYDUIWDD8VDEEWDEEWDDwUCz0UCz0UCzoU - CzgSCjoUCzgSCjYSCjMRCTEQCTEQCTEQCTAQCTEQCS4QCSwPCC4QCSwPCCsOCCkOCCcNBykOCCcNByQM - ByQMByQMByILBiALBiILBiILBiALBh8LBh8LBh0KBh0KBhsJBR0KBhsJBRgJBRgJBRoJBRgJBRoJBRoJ - BRYHBKelpP///////////////////////////////////////6alpA4FAwwFAwwFAwwFAwwFAwoDAgwF - AwkDAgkDAgkDAgkDAgcDAgUCAQUCAQUCAQMBAQMBAQMBAQIBAQMBAQIBAQIBAQIBAQIBAQIBAQAAAAIB - AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9VGJtZGJtFFJcxDJMpDJMlCJMVBI8VBI8dCJMVBI74/IsJAI8JAI7Y8Ibg9 - IbQ7ILM7IK86H6o4Hqo4HqU3HqU3HqM2HaA1HZszHJszHJ40HJszHJszHJszHJkyG5EwGpcyG5QxG5Ew - GpEwGogtGIUsGIUsGIsuGY0uGY0uGYsuGY0uGYgtGIgtGIouGYouGYYsGIgtGIMsGIMsGIAqF4MsGIEr - F4gtGIUsGIAqF4ErF4AqF5IwGpkyG4suGX4qF3wpFoAqF4ErF34qF34qF3ooFnooFnooFnkoFoMsGIou - GYUsGHkoFnkoFnkoFnkoFnkoFnUnFXkoFnQnFXImFXImFWsjE20kFGkjE2sjE2kjE2YhEmYhEmkjE2Qh - EmMhEmMhEl8fEV4fEVwfEVoeEFwfEVoeEFwfEVoeEFcdEFcdEFUcD1McD1IbD1IbD1IbD1IbD1AbD00a - DksZDk0aDksZDkkYDUYYDUcYDUYYDUQWDEIWDEEWDEEWDD8VDD0UCzoUCzoUCzgSCjgSCjgSCjgSCjUS - CjMRCTMRCTEQCTEQCTEQCTAQCS4QCSwPCCwPCCsOCCkOCCkOCCcNBycNByUNByUNByQMByILBiILBiIL - BiILBiALBiALBiALBh8LBh0KBh0KBh0KBhsJBRoJBRgJBRgJBRgJBRoJBRoJBRgJBRgJBailpf////// - /////////////////////////////////6alpA8FAw4FAwoDAgwFAwwFAwoDAgwFAwoDAgoDAgcDAgkD - AgcDAgUCAQUCAQMBAQMBAQMBAQUCAQMBAQIBAQIBAQIBAQIBAQAAAAAAAAIBAQAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9hHJthHJtZGJtFFJc9EJcxDJMdCJMVBI8VBI8RBI8RBI70/Ir4/Ir4/Irg9IbM7ILE7ILM7IK86 - H686H6g3Hqg3HqU3Hp40HJ40HJszHJszHJw0HKA1HZszHJszHJYyG5cyG5QxG5IwGosuGY0uGY8wGo8w - Go0uGYsuGY8wGpIwGpQxG4ouGYsuGYsuGY0uGYsuGYsuGYgtGIYsGIgtGIMsGIouGYouGYYsGIErF4Er - F4UsGI8wGpkyG48wGoAqF4AqF4UsGIAqF34qF4ErF34qF34qF3ooFnkoFoMsGIYsGIUsGHcnFXcnFXcn - FXkoFnUnFXUnFXkoFnkoFnQnFXAlFG0kFGsjE2sjE2gjE2kjE2gjE2gjE2gjE2MhEmQhEmEhEl4fEVwf - EV4fEVoeEFgdEFgdEFgdEFwfEVcdEFcdEFUcD1McD1IbD1AbD1IbD04aDk4aDk4aDksZDksZDksZDksZ - DkcYDUYYDUQWDEQWDD8VDEEWDEEWDD8VDDwUCzoUCzgSCjoUCzYSCjYSCjYSCjUSCjUSCjMRCTMRCTEQ - CTEQCS4QCS4QCS4QCSwPCCwPCCkOCCcNByUNBycNByUNByUNByQMByILBiUNByQMByALBiALBiALBh8L - Bh8LBh0KBh0KBh8LBhsJBRoJBRgJBRgJBRoJBRgJBRoJBRgJBRYHBKelpP////////////////////// - /////////////////6alpA4FAw4FAwwFAwoDAg4FAwwFAwoDAgoDAgwFAwoDAgkDAgcDAgIBAQUCAQMB - AQIBAQIBAQMBAQIBAQMBAQIBAQIBAQIBAQAAAAAAAAIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9lIJ9ZGJtFF - Jc5EJc5EJc5EJcdCJMdCJMRBI8RBI70/Irs9Ib0/Ir0/Ir0/IrQ7ILM7ILE7IK05H6g3Hqo4Hqc3HqI2 - HaU3HqA1HaA1HZ40HKM2HZw0HJw0HJkyG5szHJYyG5szHJEwGpcyG5IwGpcyG5cyG5EwGpEwGo0uGZEw - GpIwGogtGIsuGY0uGY8wGoouGY0uGY0uGYouGYsuGYgtGIgtGIYsGI8wGogtGIMsGIYsGI8wGpw0HJYy - G4MsGH4qF4ErF3wpFoAqF4AqF3ooFnooFnooFn4qF4ErF4gtGIMsGHkoFnkoFnUnFXkoFnooFnkoFnko - FncnFXkoFm8lFG8lFGsjE2sjE2kjE2sjE2kjE2gjE2YhEmMhEmQhEmMhEl4fEV8fEWEhEl8fEVoeEFgd - EFoeEFoeEFcdEFcdEFUcD1McD1IbD1McD1IbD00aDk0aDk0aDksZDk0aDkkYDUsZDkcYDUQWDEIWDEQW - DEEWDD8VDEEWDEEWDD0UCzwUCzwUCzoUCzgSCjgSCjYSCjMRCTUSCjMRCTMRCTMRCTEQCTAQCS4QCS4Q - CSsOCCsOCCsOCCsOCCcNBykOCCcNByUNByQMByILBiUNByILBiALBiALBh8LBh0KBh0KBhsJBRsJBR0K - BhsJBRsJBRsJBRoJBRoJBRgJBRYHBBYHBBYHBKilpf////////////////////////////////////// - /6alpA4FAw4FAw4FAwwFAwwFAwoDAgoDAgoDAgkDAgoDAgoDAgcDAgUCAQUCAQMBAQMBAQIBAQMBAQIB - AQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9lIJ9VGJtVGJs5EJc5EJcpDJMlC - JMdCJMdCJMVBI8A/Irs9Ib0/Irk9Ibg9IbY8IbY8Ia86H7E7IKw5H605H6c3HqM2HaI2HaA1HaI2HaM2 - HaU3HqA1HZ40HJ40HJcyG540HJszHJQxG5IwGpcyG5kyG5YyG5IwGo8wGpEwGpYyG5IwGpIwGo8wGpEw - Go0uGYsuGYgtGIouGYouGZEwGoouGYgtGIUsGIouGYUsGIouGYouGY8wGp40HJkyG4gtGIUsGIouGYgt - GH4qF4AqF34qF3ooFnwpFnooFoUsGIgtGIYsGIAqF3koFncnFXkoFncnFXkoFnQnFXUnFXImFXImFW8l - FGsjE2kjE2kjE20kFGsjE2gjE2gjE2gjE2MhEmEhEmEhEmMhEl4fEV8fEVwfEVwfEVwfEVwfEVgdEFcd - EFcdEFUcD1UcD1McD1IbD00aDk0aDk0aDksZDkkYDUsZDksZDkYYDUQWDEYYDUQWDEIWDEIWDD8VDEEW - DD0UCzwUCzoUCzgSCjgSCjYSCjYSCjUSCjUSCjMRCTMRCTEQCTMRCTAQCS4QCTAQCSsOCCsOCCsOCCkO - CCcNBycNBycNBycNByQMByILBiILBiILBiILBh8LBiALBh8LBh0KBh8LBhsJBR0KBhsJBRsJBRoJBRoJ - BRgJBRgJBRYHBBYHBBYHBKelpP///////////////////////////////////////6alpAwFAw4FAw4F - Aw4FAwwFAwoDAgoDAgoDAgkDAgkDAgkDAgkDAgUCAQUCAQMBAQIBAQMBAQMBAQIBAQIBAQIBAQIBAQIB - AQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9lJKdhHJtVGJs9EJdFFJc5EJclCJMpDJMpDJMdCJMlC - JL0/Ir0/Ir0/IrY8Ibk9Ibg9IbE7ILE7IKc3Hq05H6o4HqM2Hag3Hqo4HqM2Hac3HqM2HaI2HaI2HaA1 - HaI2HZw0HJw0HJ40HJkyG5cyG5YyG5cyG5cyG5EwGpEwGo8wGpYyG5kyG48wGpQxG5QxG40uGYouGYou - GYouGYouGY0uGYouGYgtGIsuGYsuGYsuGYYsGI0uGaA1HaI2HYsuGY0uGZcyG48wGoYsGIUsGIErF4Ms - GH4qF3wpFoYsGIouGYUsGHwpFnooFnkoFnooFnkoFnImFXUnFXcnFXUnFXQnFW8lFG0kFG0kFGkjE2sj - E2sjE2sjE2gjE2gjE2MhEmMhEmQhEmEhEl8fEVwfEV8fEVoeEFoeEFgdEFgdEFcdEFcdEFoeEFMcD1Ab - D1AbD04aDk0aDk4aDksZDkcYDUcYDUsZDkcYDUQWDEIWDEQWDEIWDEEWDEEWDEEWDD0UCz0UCzwUCzwU - CzoUCzUSCjUSCjYSCjMRCTUSCjMRCTMRCTMRCS4QCSwPCDAQCSwPCCwPCCwPCCkOCCcNByUNByUNBycN - ByUNByILBiILBiILBiILBh8LBiALBiALBh0KBhsJBRsJBR8LBhsJBRoJBRoJBRoJBRsJBRgJBRgJBRYH - BBgJBaelpP///////////////////////////////////////6alpA4FAw4FAwwFAwwFAwoDAgkDAgkD - AgoDAgoDAgkDAgcDAgoDAgcDAgMBAQMBAQIBAQMBAQIBAQIBAQIBAQAAAAIBAQIBAQIBAQIBAQAAAAIB - AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9lIJ9VGJtlIJ9hHJtFFJcxDJMlCJMRBI8pDJMJAI8RBI8A/Ir0/Irg9Ibg9 - Ibg9IbQ7ILg9IbE7ILE7ILM7IK05H6c3Hqc3Hqc3HqU3Hqg3HqU3Hqc3Hp40HKI2HaI2HZszHJ40HJsz - HJYyG5cyG5szHJQxG5cyG5IwGo0uGZIwGo8wGpcyG5QxG5EwGo8wGo8wGpQxG40uGY0uGYsuGZIwGoYs - GIgtGI0uGYsuGY0uGYgtGIsuGZszHKU3HpEwGp40HLs9IaI2HY0uGYgtGIUsGIUsGH4qF4MsGIYsGIgt - GIgtGIUsGH4qF3ooFnkoFnkoFncnFXUnFXQnFXQnFXQnFXImFXImFW0kFG0kFGsjE2sjE2gjE2sjE2Yh - EmQhEmYhEmMhEmQhEl8fEV8fEV4fEVoeEFoeEFcdEFcdEFgdEFcdEFcdEFMcD1IbD1IbD1AbD04aDk4a - Dk0aDksZDkkYDUsZDkcYDUcYDUQWDEIWDEIWDEEWDD8VDD8VDD0UCz0UCzwUCzwUCzwUCzoUCzYSCjYS - CjMRCTMRCTMRCTAQCTEQCS4QCS4QCTAQCSwPCCsOCCwPCCkOCCUNBycNBycNByUNByQMByILBiILBiQM - ByALBh0KBiALBiALBh8LBh8LBh0KBh0KBhoJBRsJBRoJBRoJBRoJBRoJBRYHBBQHBBYHBKelpP////// - /////////////////////////////////6alpAwFAw4FAwwFAwwFAwwFAwkDAgkDAgoDAgoDAgkDAgcD - AgoDAgkDAgUCAQUCAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAIBAQAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9lJKdlIJ9ZGJtZGJtNGJs9EJcpDJMRBI8lCJMA/Ir0/Ir0/Irs9Ibg9Ibs9Ib0/IrM7ILQ7ILY8 - IbE7ILM7IK05H6w5H6o4Hq05H6g3Hp40HKM2HaI2HaA1HZ40HKM2HZkyG5w0HJw0HJszHJszHJkyG5sz - HJIwGpQxG5kyG5cyG5kyG5szHJkyG48wGpYyG5IwGpIwGo0uGZEwGpEwGo0uGY0uGZIwGpEwGpYyG4gt - GIsuGYYsGJszHKo4Hqc3HsRBI9pLK8RBI6I2HY8wGogtGIUsGIUsGIgtGI0uGYsuGYouGYMsGIAqF3ko - FnkoFnooFncnFXUnFXImFXUnFXAlFHAlFHQnFW8lFGsjE28lFGkjE2sjE2kjE2gjE2MhEmQhEmMhEmMh - EmEhEl8fEVoeEFwfEVcdEFoeEFwfEVwfEVoeEFcdEFMcD1AbD1AbD04aDk0aDksZDksZDk0aDkkYDUsZ - DkcYDUkYDUYYDUIWDEQWDEEWDEIWDD8VDD0UCzwUCzoUCzoUCzoUCzgSCjgSCjUSCjMRCTMRCTMRCTEQ - CTEQCTAQCS4QCS4QCSsOCCkOCCsOCCsOCCkOCCkOCCkOCCUNByQMByILBiILBiILBiALBiALBiILBh8L - Bh0KBhsJBRsJBRsJBRsJBRoJBRoJBRgJBRgJBRgJBRYHBBQHBBMHBKalpP////////////////////// - /////////////////6alpAwFAw4FAw4FAwwFAwwFAwoDAgoDAgoDAgoDAgkDAgkDAgkDAgcDAgUCAQMB - AQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9VGJtZGJthH - JtVGJs9EJc9EJcxDJM5EJcRBI8JAI8JAI74/IsA/Ir0/IrY8IbM7ILg9IbY8Ibg9IbY8IbE7ILY8Ia86 - H6o4Hqw5H6g3HqM2HaU3HqA1Hac3HqA1HaA1HaM2HZszHJw0HJszHJszHJw0HJkyG5kyG5cyG5cyG5cy - G5IwGpIwGpcyG5kyG5IwGpYyG5QxG5QxG5cyG40uGZIwGo8wGo0uGYgtGJQxG5EwGo0uGZYyG6M2HbY8 - Ib0/ItpOLt1eQdpOLrQ7IJszHIouGYYsGIYsGIgtGIgtGJEwGpEwGoAqF34qF3koFnUnFXwpFnUnFXUn - FXcnFXUnFXQnFXQnFWsjE3AlFHImFWsjE2gjE2sjE2gjE2YhEmYhEmYhEmMhEl8fEV8fEV8fEVwfEVwf - EVoeEFoeEFwfEVgdEFgdEFUcD1McD1UcD1AbD04aDk0aDk0aDksZDk0aDksZDksZDkcYDUYYDUYYDUQW - DEIWDEIWDD8VDD8VDDwUCz0UCz0UCzwUCzgSCjgSCjYSCjUSCjMRCTMRCTMRCTMRCTAQCS4QCTAQCS4Q - CSsOCCkOCCkOCCkOCCkOCCcNBycNByUNByQMByQMByILBiQMByALBiALBiALBh8LBh0KBh0KBhsJBR0K - BhsJBRsJBRgJBRgJBRgJBRgJBRYHBBMHBBEGA6alpP////////////////////////////////////// - /6alpA4FAwwFAwwFAw4FAwwFAwoDAgoDAgoDAgoDAgoDAgkDAgcDAgcDAgcDAgMBAQMBAQIBAQIBAQMB - AQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9pNLdhHJthHJtZGJthHJspDJM5E - JdFFJcxDJMxDJMRBI8RBI8JAI70/Irk9IbE7ILY8IbQ7ILY8IbE7IK86H7Q7IK05H686H6c3Hqw5H6g3 - Hqc3HqU3HqI2Hac3HqI2Hag3HqI2Hac3HpszHJszHJ40HKA1HZw0HJYyG5YyG5YyG5cyG5YyG5szHJQx - G5cyG5cyG5EwGpYyG5YyG5EwGpYyG48wGpIwGpIwGpIwGo8wGpQxG5YyG6U3HsRBI9ZGJt1bPuBrUN1a - PMdCJKU3Ho8wGoouGYouGYgtGIYsGI8wGpEwGoYsGHwpFoAqF3koFnkoFnkoFnkoFnkoFncnFXQnFXQn - FXAlFHUnFXAlFGsjE2kjE2kjE2gjE2gjE2YhEmQhEmMhEmEhEmEhEl8fEV4fEVwfEV4fEV4fEVwfEVcd - EFgdEFcdEFMcD1AbD04aDlAbD04aDk0aDk4aDksZDkkYDUcYDUQWDEQWDEQWDEQWDEEWDEIWDD8VDD8V - DD0UCz0UCzwUCzoUCzYSCjgSCjUSCjYSCjMRCTMRCTMRCTEQCTEQCTAQCTAQCTAQCS4QCSwPCCsOCCkO - CCkOCCcNBykOCCcNByUNByUNByQMByUNByILBiALBiILBh8LBh0KBh0KBhsJBRsJBRsJBRsJBRgJBRoJ - BRoJBRgJBRQHBBMHBBEGA6elpP///////////////////////////////////////6alpA4FAwwFAw4F - AwwFAwoDAgoDAgoDAgoDAgoDAgkDAgcDAgcDAgkDAgkDAgMBAQIBAQIBAQIBAQMBAQMBAQIBAQIBAQIB - AQAAAAAAAAIBAQAAAAIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9lIJ9ZGJthHJtVGJthHJtFFJdFFJdFFJcxDJMdCJMRB - I70/Ir0/Irs9Ib0/Irs9Ibg9IbQ7ILM7ILE7ILE7ILg9Iaw5H7E7IKw5H6o4Hqg3Hqg3Hqc3Hqg3HqU3 - HqU3HqM2HaI2HZszHKA1HZszHJw0HJszHJszHJw0HJkyG5QxG5YyG5szHJw0HJkyG5QxG5QxG5cyG5Qx - G5cyG5IwGpYyG5cyG40uGZYyG5kyG5cyG5EwGpszHKw5H9NGJttRMt5gROFuVN5iRtVGJrQ7IJkyG5Iw - Go8wGoouGYouGZEwGpIwGogtGIUsGIErF4YsGHwpFnooFnUnFXkoFncnFXkoFncnFXQnFXcnFXImFW8l - FGsjE20kFGkjE2kjE2MhEmYhEmQhEmQhEmMhEmMhEl4fEV4fEV8fEVwfEVgdEFcdEFUcD1cdEFUcD1Ib - D1AbD1AbD04aDk0aDksZDkkYDUkYDUcYDUYYDUQWDEEWDEIWDEEWDEEWDEEWDD0UCz0UCz8VDDwUCzgS - CjUSCjYSCjYSCjgSCjYSCjUSCjMRCTEQCTMRCTAQCS4QCS4QCSwPCCwPCCsOCCsOCCsOCCcNBycNBycN - ByUNByUNByQMByQMByILBiALBh0KBh0KBh8LBhsJBRsJBRsJBRsJBRoJBRoJBRgJBRgJBRMHBBMHBBMH - BBEGA6alpP///////////////////////////////////////6alpAoDAgoDAgwFAwoDAgoDAgoDAgkD - AgkDAgcDAgkDAgkDAgkDAgcDAgkDAgUCAQIBAQIBAQIBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9pNLdlJKdlIJ9ZGJtNGJtNGJs5EJc5EJcpDJMxDJMxDJMVBI8dCJL4/IsA/ - IsA/Ir0/Irk9Ibs9Ibk9IbM7IK86H605H7E7IKo4Hq05H6A1Ha05H6I2HaU3HqU3Hqc3HqM2HaA1Hac3 - Hp40HJszHJ40HJ40HJw0HJw0HJszHJszHJszHJszHJszHJszHJ40HJszHJ40HJszHJcyG5szHJw0HJ40 - HJQxG5szHJYyG5szHJszHJ40HLM7INlIJ91bPuBoTeFwV99kSNpNLcA/Iqg3HpcyG5EwGoouGYsuGZcy - G5YyG5EwGosuGYMsGIMsGIUsGIAqF3koFnkoFncnFXUnFXcnFXcnFXQnFXQnFW8lFG8lFG8lFG0kFGkj - E2YhEmgjE2YhEmQhEmMhEmQhEl8fEV4fEVoeEFgdEFcdEFcdEFUcD1McD1UcD1IbD1IbD1AbD1AbD00a - Dk0aDksZDksZDkkYDUcYDUkYDUQWDEIWDEIWDD8VDEEWDD0UCz0UCzwUCzwUCzgSCjYSCjYSCjYSCjUS - CjUSCjUSCjMRCTEQCTEQCTAQCTAQCS4QCSwPCCsOCCkOCCkOCCkOCCcNByUNByUNByUNByQMByQMByUN - ByILBh8LBh8LBh8LBh8LBh0KBh0KBh0KBhsJBRsJBRoJBRgJBRQHBBQHBBMHBBMHBBEGA6alpP////// - /////////////////////////////////6alpAoDAgwFAwwFAwoDAgoDAgwFAwoDAgwFAwoDAgoDAgcD - AgcDAgkDAgcDAgMBAQIBAQIBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9tSM9pLK9pOLtlJKdlIJ9NGJs9EJcxDJMpDJMdCJMdCJMpDJMVBI74/IsJAI70/Ir0/Irk9Ibk9 - Ibs9Ibg9Ia05H686H686H605H6w5H6o4Hq05H6U3Hqg3HqU3Hqc3HqI2HaM2Hag3HqA1HaI2HaM2HZky - G5kyG5w0HJszHKA1HZw0HJw0HJw0HKI2HaU3Hpw0HJszHJkyG5szHJszHKI2HZ40HJw0HJszHJw0HKM2 - HZw0HKU3Hrg9IdpOLt9kSOBrUOJyWeBoTdxXOcpDJK86H5w0HJYyG40uGY8wGpszHJszHJYyG48wGoYs - GIMsGIUsGIErF4AqF34qF3koFnkoFnkoFnooFnQnFXAlFHImFW8lFHAlFG0kFG0kFGsjE2gjE2YhEmMh - EmMhEmQhEmQhEl8fEV4fEVwfEVoeEFcdEFcdEFMcD1UcD1UcD1McD04aDlAbD04aDk0aDk0aDkkYDUsZ - DkkYDUYYDUQWDEQWDEYYDT8VDD8VDD0UCzwUCzoUCzoUCzoUCzgSCjYSCjUSCjUSCjMRCTMRCTMRCTAQ - CTEQCTAQCTAQCS4QCS4QCSsOCCsOCCkOCCUNBycNByUNBykOCCUNByUNByQMByUNByQMByILBiILBh8L - Bh8LBh0KBh8LBhsJBRsJBRsJBRsJBRYHBBMHBBMHBBMHBBMHBBMHBKalpP////////////////////// - /////////////////6alpAwFAwwFAw4FAwwFAwwFAwwFAwoDAgwFAwwFAwkDAgkDAgcDAgkDAgcDAgUC - AQMBAQIBAQIBAQMBAQMBAQIBAQAAAAIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9lJKdlIJ9lJ - KdlJKdZGJtFFJc9EJdNGJspDJM5EJcxDJMlCJMdCJMVBI8dCJL0/Ir4/Ir0/Irg9Ibk9Ibs9Ia86H7Q7 - IKw5H6w5H6w5H6A1HaM2HaU3HqM2HaU3HqU3HqM2HaU3HqU3HqU3HqI2HZ40HJ40HJw0HJszHJw0HKA1 - HZ40HJ40HJ40HJw0HJw0HKU3HqA1HZ40HJw0HJszHKI2HaM2HZ40HJw0HKA1HaA1HaI2Hao4Hr4/IttU - NeBoTeBrUOJyWeBrUN1cP9NGJrs9Iac3Hpw0HJIwGpIwGpkyG5w0HJYyG4suGYouGYYsGIYsGIMsGIEr - F4ErF3wpFnkoFnkoFnwpFnkoFnQnFXUnFXAlFHAlFG0kFGsjE2QhEmYhEmYhEmQhEmgjE2MhEmQhEl8f - EWEhEl4fEVgdEFoeEFcdEFcdEFUcD1UcD1UcD04aDk4aDk0aDk0aDk0aDkkYDUsZDkYYDUYYDUIWDEIW - DEIWDD8VDEEWDD0UCzwUCz0UCzoUCzwUCzoUCzYSCjUSCjUSCjMRCTUSCjMRCTMRCTEQCTAQCTAQCS4Q - CS4QCSsOCCwPCCsOCCkOCCsOCCkOCCkOCCcNByUNByQMByUNByQMByILBiILBh8LBh8LBh8LBh0KBhsJ - BRsJBRsJBRgJBRQHBBMHBBMHBBMHBBMHBBMHBKalpP////////////////////////////////////// - /6alpAwFAw4FAw4FAwwFAwwFAwwFAwoDAgkDAgkDAgkDAgcDAgkDAgcDAgcDAgcDAgMBAQIBAQIBAQMB - AQMBAQIBAQAAAAIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9lJKdpLK9pLK9pNLdlJKdlJKdhH - JtZGJtNGJsxDJMxDJMpDJMdCJMlCJMlCJMdCJL4/IrY8Ibg9Ibk9Ibg9Ibk9IbY8Ia05H7E7ILM7IKc3 - HrE7IKg3Hq05H6c3HqM2HaI2HaU3Hqc3HqA1HaM2HZw0HKM2HaA1HZszHJw0HKM2HaI2HZw0HKM2HZsz - HKA1HaI2HaM2HZw0HKI2HZw0HJw0HKU3Hpw0HJw0HJ40HKA1Hao4HrE7IMlCJN1aPOBrUOFvVeN3XuFu - VN5gQ9lJKcRBI605H6A1HZszHJszHJkyG540HJcyG40uGYsuGY0uGYsuGYgtGIUsGIMsGIAqF34qF3oo - FnkoFnooFnQnFXAlFG8lFHQnFW0kFGsjE2gjE2gjE2gjE2QhEmYhEmQhEmEhElwfEVoeEF4fEVgdEFwf - EVgdEFUcD1UcD1McD1McD04aDlAbD04aDksZDkkYDUkYDUkYDUYYDUYYDUQWDEQWDEcYDUQWDD8VDDwU - Cz0UCzwUCzoUCzoUCzgSCjgSCjYSCjUSCjMRCTMRCTMRCTMRCTEQCTAQCTAQCS4QCS4QCSwPCCsOCCkO - CCsOCCkOCCcNByUNBycNByUNByILBiALBiALBiALBiALBiALBh0KBh0KBhsJBR0KBhoJBRgJBRYHBBQH - BBQHBBQHBBMHBBMHBBEGA6alpP///////////////////////////////////////6alpAwFAwwFAwwF - AwwFAwwFAwwFAwoDAgkDAgkDAgkDAgkDAgcDAgkDAgcDAgcDAgMBAQIBAQMBAQIBAQIBAQIBAQIBAQIB - AQIBAQIBAQIBAQAAAAIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9pOLtlJKdlJKdlJKdlIJ9lIJ9VGJthHJsxDJM9EJclC - JMVBI8lCJMRBI8RBI8VBI8VBI70/Irk9IbQ7ILk9IbY8Ibk9IbM7ILg9IbM7IKw5H6o4Hq05H7E7IKg3 - Hqo4HqU3Hqg3Hp40HKI2HaA1HZ40HKA1HZ40HKA1HaI2HaA1HaA1HaA1HaA1HaM2HaA1HaA1Hao4Hqc3 - Hp40HKI2HaM2HZ40HKU3Hqc3Hqc3Hqw5H7Y8IcJAI9NGJt1eQeFwV+FwV+N4YOFwV99mS9pPMMxDJLg9 - Iac3HqM2HZszHJcyG5cyG5QxG5EwGo0uGY0uGY8wGoouGYgtGIYsGIMsGIMsGH4qF3wpFnooFnUnFWsj - E3cnFXQnFW0kFGsjE2kjE2gjE2YhEmgjE2YhEl8fEVwfEV8fEVoeEFoeEFoeEFwfEVoeEFcdEFMcD1Mc - D1cdEE4aDksZDksZDksZDkcYDUkYDUkYDUcYDUcYDUYYDUIWDEIWDEIWDD8VDD0UCzwUCz0UCzwUCzwU - CzgSCjYSCjUSCjYSCjMRCTMRCTMRCTEQCTMRCTEQCTEQCS4QCS4QCS4QCSsOCCcNBycNBykOCCcNBycN - BycNByUNByQMByILBiALBiALBh8LBiALBh0KBh0KBh0KBhsJBRgJBRYHBBQHBBQHBBYHBBQHBBMHBBQH - BBMHBKalpP///////////////////////////////////////6alpAwFAwwFAwoDAgwFAwoDAgoDAgkD - AgkDAgoDAgkDAgkDAgkDAgcDAgcDAgcDAgMBAQMBAQIBAQIBAQIBAQIBAQMBAQMBAQIBAQIBAQIBAQAA - AAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9pOLtpNLdpLK9lIJ9hHJtlIJ9VGJtVGJtZGJsxDJM9EJcpDJMpDJMJAI8VB - I8RBI8JAI70/IsRBI70/Ir0/Irg9IbQ7ILQ7ILM7ILQ7IKw5H6w5H605H686H6o4Hqc3Hqo4HqI2Hao4 - Hqg3HqI2HaI2Hac3Hqc3HqM2HaM2HaA1HaU3Hqc3HqI2HaM2HaI2Hag3Hqo4Hqc3HqM2HaU3HqM2Hao4 - HqU3Hqc3Hq05H7M7IMA/IsdCJNlJKd5gRON4YON7Y+R8ZeN3XuBrUN1aPNlJKcA/IrQ7IKg3HqA1HZsz - HJszHJszHJYyG5QxG48wGosuGY0uGY0uGYsuGYsuGYouGYErF4MsGH4qF3koFm8lFHAlFHAlFHImFWkj - E2gjE2kjE2kjE2kjE2QhEmQhEmEhEl4fEVwfEVgdEFoeEF4fEVoeEFgdEFUcD1McD1IbD1IbD04aDksZ - Dk0aDksZDksZDkcYDUcYDUQWDEYYDUIWDD8VDD8VDD0UCz8VDDwUCzwUCzoUCzoUCzoUCzoUCzYSCjgS - CjUSCjMRCTMRCTMRCTEQCTEQCTEQCTAQCSwPCC4QCSwPCCsOCCkOCCsOCCcNByUNBycNByUNByILBiQM - ByILBiALBiALBh8LBh0KBh0KBh0KBhoJBRYHBBYHBBQHBBQHBBQHBBQHBBEGAxEGAxEGA6alpP////// - /////////////////////////////////6alpA4FAwwFAwoDAgwFAwoDAgwFAwoDAgoDAgwFAwoDAgkD - AgcDAgkDAgcDAgcDAgUCAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9pPMNpPMNpNLdhHJtpNLdZGJthHJthHJtFFJdNGJs9EJdFFJclCJMVBI8lCJMdCJL0/Ir4/Irs9 - IcA/Ir0/Irs9Ibs9IbY8Ibs9Ia05H605H7E7IKw5H7E7IKw5H6w5H605H6g3Hqo4Hqw5H6U3Hqo4HqU3 - HqM2HaM2Hag3HqU3HqM2HaU3HqM2HaM2Hac3Hqg3Hqc3Hqo4Hqo4Hqo4Hqw5H6w5H7E7IK86H7Q7ILs9 - IcpDJNZGJttRMuBrUOR9ZuR9ZuR/aON7Y+JyWd5gRNpOLslCJLs9Ia86H6o4HqU3Hqc3Hpw0HJw0HJky - G5EwGpIwGpEwGo8wGosuGYouGYErF4AqF4ErF34qF3wpFnQnFXImFXImFW8lFHAlFG0kFG8lFG0kFGkj - E2QhEmEhEmMhEl8fEV4fEVoeEFcdEFoeEFcdEFcdEFcdEFIbD1AbD04aDk4aDksZDk4aDkkYDUkYDUkY - DUkYDUYYDUQWDEEWDEEWDEEWDD8VDD8VDDwUCzwUCzoUCzgSCjoUCzgSCjUSCjMRCTMRCTUSCjMRCTMR - CTEQCTEQCTEQCTAQCS4QCSwPCCwPCCwPCCkOCCkOCCkOCCcNBycNByUNByUNByQMByILBiILBiALBh8L - Bh8LBhsJBRoJBRgJBRYHBBYHBBYHBBQHBBQHBBMHBBQHBBEGAxEGA6alpP////////////////////// - /////////////////6alpAwFAwwFAwwFAwwFAwwFAwoDAgoDAgoDAgoDAgkDAgoDAgkDAgcDAgcDAgUC - AQUCAQMBAQIBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9pOLtpNLdpO - LtlIJ9lJKdhHJtpNLdVGJtVGJtFFJdZGJtVGJs5EJcxDJMlCJMdCJMJAI70/IsA/Ir0/IsJAI8A/Ir4/ - Irs9Ibs9Ia86H7Q7ILg9IbE7IK86H605H7E7IK86H605H686H6w5H6w5H6g3Hqw5H6I2Hao4Hq05H6U3 - Hqo4Hqg3Hqo4Hq86H605H6o4Hqw5H686H7Q7IK05H7Q7ILM7ILY8Ib0/Ir0/IsA/Is5EJdpLK9xYOuBq - T+R9ZuWBauWCbOR9ZuJ1XOBqT9xVN9VGJsRBI7s9IbM7IKo4Hqo4Hqc3Hqc3HqI2HZ40HJszHJYyG5Yy - G5QxG4suGYgtGIUsGIYsGIErF34qF3koFnUnFXQnFXAlFHAlFG8lFG8lFGgjE2gjE2YhEl8fEWEhEmEh - ElwfEV8fEVoeEF4fEVgdEFUcD1cdEFUcD1McD1McD00aDk4aDlAbD00aDksZDksZDkcYDUcYDUYYDUIW - DEIWDEEWDD0UCz0UC0EWDD0UCz0UCzwUCzoUCzgSCjUSCjMRCTMRCTMRCTMRCTMRCTEQCTEQCTAQCTAQ - CS4QCSwPCCsOCC4QCSsOCCkOCCcNBycNBycNByILBiQMByQMByILBiILBh8LBh8LBh0KBhoJBRgJBRYH - BBYHBBYHBBYHBBQHBBQHBBMHBBMHBBEGAxEGA6alpP////////////////////////////////////// - /6alpA4FAwwFAwkDAgoDAgwFAwwFAwoDAgoDAgoDAgkDAgkDAgkDAgcDAgcDAgUCAQUCAQMBAQIBAQMB - AQIBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9pOLttRMtpNLdpOLtpLK9pLK9lJ - KdpLK9ZGJtNGJtNGJtFFJcxDJM5EJcRBI85EJcVBI8RBI8RBI8RBI70/Ir0/Irs9Ibk9Ib4/Irg9IbQ7 - ILg9IbE7IKw5H7M7ILM7ILY8Ia05H605H605H6g3HrE7IKo4Hqo4Hqw5H605H6g3Hqw5H6o4Hq86H686 - H605H6w5H686H7g9Ib0/Irs9Ib0/Irg9Ibk9IcJAI74/IsRBI9VGJttUNd5gQ+FuVOaFb+aHcuaHcuWB - auR8ZeFuVN1cP9pNLdFFJcA/Irk9IbM7IKw5H605H6w5H6w5H6U3Hp40HJszHJszHJcyG48wGosuGYgt - GIUsGIMsGIUsGHooFnwpFnkoFncnFXImFXQnFXAlFGkjE2sjE2YhEmYhEmYhEmMhEl8fEV4fEV4fEV8f - EVwfEVcdEFoeEFcdEFUcD1UcD1McD04aDk0aDksZDksZDkkYDUcYDUYYDUcYDUIWDEYYDUQWDD8VDD0U - Cz0UCz0UCzwUCzwUCzgSCjgSCjYSCjYSCjYSCjUSCjMRCTMRCTEQCTEQCTAQCS4QCSwPCCsOCCsOCCwP - CCkOCCcNBycNBycNByQMByILBiQMByQMByILBiALBh8LBiALBh0KBhgJBRoJBRgJBRYHBBYHBBYHBBQH - BBYHBBQHBBMHBBMHBBMHBKelpP///////////////////////////////////////6alpA4FAwwFAwoD - AgoDAgoDAgoDAgwFAwkDAgoDAgkDAgoDAgcDAgcDAgcDAgcDAgcDAgMBAQIBAQIBAQMBAQMBAQMBAQIB - AQMBAQIBAQAAAAIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9pPMNtSM9pLK9pLK9pOLtpLK9VGJtNGJtZGJtZGJtVG - JtNGJtNGJspDJMpDJMlCJMlCJMdCJMlCJMRBI70/Ir4/IsA/Ir4/IsA/Irk9IbY8IbM7ILE7ILM7IK86 - H7Q7ILM7ILQ7IK05H7M7ILQ7IK05H6o4HrE7ILM7IK86H7E7IK86H7Q7ILM7ILQ7ILM7ILk9Ibs9Ibs9 - Ib4/IsJAI70/Ir0/Ir0/IsVBI8lCJM9EJdpNLd1aPN9kSOJ0W+aHcuiPe+eLduaHceR/aOJ0W99mS9tU - NdhHJsdCJMJAI70/Irk9IbQ7IKw5H6w5H6g3Hqg3HqA1HaI2HZkyG5szHJcyG5EwGosuGYYsGIUsGIAq - F34qF3ooFnkoFnImFXImFXAlFG0kFGsjE2gjE2YhEmMhEmQhEmMhEl8fEVwfEVgdEFwfEVoeEFcdEFcd - EFcdEFcdEFIbD00aDk4aDkkYDUsZDk0aDksZDkcYDUQWDEIWDEEWDEIWDD0UCzwUCzwUCzwUCzwUCzoU - CzgSCjYSCjYSCjYSCjUSCjMRCTMRCTMRCTEQCTEQCTAQCTAQCSwPCCsOCCwPCCsOCCsOCCcNByUNByUN - ByQMByQMByQMByQMByQMByALBh0KBh0KBh0KBhgJBRoJBRgJBRgJBRYHBBYHBBQHBBQHBBQHBBQHBBMH - BBEGA6alpP///////////////////////////////////////6alpA4FAw4FAwoDAgoDAgwFAwoDAgoD - AgoDAgwFAwkDAgkDAgoDAgcDAgkDAgkDAgcDAgMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIB - AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9pOLtpPMNpOLttSM9pNLdlJKdlJKdZGJtZGJtZGJtVGJs9EJdNGJs5EJcpD - JMVBI8lCJMVBI8lCJMA/IsJAI74/Ir0/Ir0/Irg9Ib0/IsA/Irk9Ibk9IbM7ILQ7ILg9IbY8Ia86H7Y8 - Ibs9IbQ7ILg9IbQ7ILM7ILg9Ibk9IbE7ILM7ILk9Ibg9Ibg9Ibk9Ib0/Ir4/IsJAI8RBI74/IsA/IsVB - I8dCJMlCJNFFJdhHJtpPMN5gROFuVON5YeeLdumTgOeNeeaHcuWCbON7Y+BrUN1cP9pOLthHJsxDJMA/ - Irs9Ibk9IbQ7ILM7IKo4Hqg3Hqg3Hqc3HqA1HZszHJszHJcyG4suGYsuGYYsGIUsGIErF3wpFnkoFnko - Fm8lFG0kFG0kFGkjE2kjE2YhEmMhEmEhEmEhEl4fEVoeEFoeEFoeEFoeEFcdEFcdEFMcD1IbD1McD1Ab - D04aDksZDksZDkkYDUcYDUcYDUQWDEQWDEEWDD8VDEEWDD0UCzwUCz0UCzoUCzoUCzoUCzgSCjYSCjUS - CjMRCTMRCTMRCTEQCTEQCTEQCTAQCTAQCSwPCCwPCCwPCCsOCCsOCCcNBykOCCcNByUNByUNByQMByIL - BiILBh8LBhsJBRoJBRsJBRoJBRoJBRgJBRYHBBYHBBgJBRMHBBMHBBMHBBMHBBMHBBMHBKalpP////// - /////////////////////////////////6alpAwFAwwFAwoDAgoDAgoDAgwFAwkDAgkDAgoDAgkDAgkD - AgkDAgcDAgcDAgcDAgcDAgMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAIBAQAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9pPMNpOLttSM9pPMNpOLtpOLtlJKdZGJtZGJthHJtlIJ9VGJs9EJdFFJc5EJdFFJcxDJMpDJMVB - I74/IsA/IsJAI70/Ir4/Ir0/IsA/Irs9Ibk9Ibs9Ibk9Ibs9Ibg9Ibg9Ibs9Ibk9IbQ7ILY8IbQ7ILg9 - Ibk9IbQ7ILs9Ib0/Irk9Ibs9Ib0/Irs9IcA/IsRBI8RBI8JAI8lCJMxDJM5EJclCJMpDJNNGJtlIJ9pP - MNxYOuBrUOJ1XOWBauiPe+mWg+iSfueMd+aHcuR9ZuFvVd5iRttUNdlJKdFFJclCJL4/Ir0/Ir4/Irk9 - Ia86H7M7IK05H6o4Hqc3HqU3Hp40HJszHJQxG5EwGo8wGoYsGIMsGIMsGHooFnUnFXImFXImFW8lFGsj - E2sjE2gjE2QhEmMhEmEhEmMhElwfEVoeEFgdEFgdEFcdEFUcD1McD1IbD1AbD1McD00aDk0aDksZDksZ - DkcYDUYYDUIWDEQWDEEWDEEWDD8VDD0UCz0UCzwUCzwUCzgSCjgSCjgSCjYSCjUSCjUSCjMRCTMRCTMR - CTMRCTAQCTAQCTAQCS4QCS4QCS4QCSsOCCsOCCkOCCsOCCcNByUNBycNByUNByILBh0KBhsJBR0KBhoJ - BR0KBhsJBRgJBRgJBRYHBBYHBBQHBBMHBBMHBBMHBBQHBBMHBBMHBKalpP////////////////////// - /////////////////6WkpAoDAgoDAgwFAw4FAwoDAgoDAgoDAgkDAgkDAgcDAgkDAgkDAgcDAgkDAgkD - AgcDAgUCAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9pOLtpOLttR - MttSM9pOLtpOLtpNLdZGJtlIJ9lIJ9hHJtNGJtFFJdNGJtNGJsdCJM9EJcxDJMVBI74/Ir4/IsVBI8RB - I70/IsA/Ir0/Ir4/Ir0/IsA/Ir0/Ir4/Irk9Ib0/Irg9Ibk9Ib0/IrQ7ILg9Ibk9Ibg9IbY8Ibk9Ibs9 - Ib0/IsRBI8A/IsRBI8lCJMdCJMlCJM9EJc5EJdFFJdVGJtVGJtFFJdpLK9tSM91aPN5gQ+FuVON5YeWD - beiPe+qciumWg+iPe+eLduR/aOJ1XOBoTd1aPNtRMtZGJs9EJclCJMlCJMJAI7k9Ibk9Ibg9IbM7IKo4 - Hqw5H6c3Hqg3HqM2HZszHJcyG5YyG48wGogtGIErF3wpFnkoFnQnFXUnFXImFW0kFG0kFGYhEmQhEmEh - El8fEWEhEl4fEVgdEFcdEFoeEFcdEFcdEFgdEFMcD1AbD1AbD1IbD00aDkkYDUcYDUkYDUQWDEIWDEEW - DEEWDEIWDD8VDD8VDD0UCz0UCzoUCzgSCjgSCjYSCjUSCjUSCjUSCjMRCTMRCTMRCTMRCTAQCTAQCS4Q - CTAQCS4QCSwPCCsOCCsOCCsOCCsOCCQMByQMByUNByILBiILBh8LBh0KBhoJBRgJBRsJBRoJBRgJBRYH - BBYHBBYHBBMHBBQHBBQHBBMHBBQHBBEGAxMHBG1qaaelpKalpKalpKalpKalpKalpKalpKalpKalpKal - pGxpaA4FAwwFAwwFAwwFAwwFAwwFAwoDAgkDAgkDAgkDAgoDAgkDAgkDAgcDAgkDAgcDAgUCAQMBAQMB - AQMBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9tRMtpOLtpOLtpLK9pOLtpLK9hH - JtpNLdVGJtZGJtNGJtZGJtlJKdNGJtNGJs5EJc9EJclCJMpDJMVBI8VBI8VBI8JAI8dCJMA/IsJAI8A/ - Ir0/Ir0/Ir4/IsA/IsA/IsVBI7s9Ib0/Ir0/IsRBI70/Ir0/IsJAI70/Ir0/IsA/IsA/IsVBI8lCJMxD - JM5EJc5EJc9EJc9EJdZGJtNGJthHJtpLK9pNLdpPMN1aPN5iRuBrUON3XuR/aOaJdOiRfeufjuqZh+mT - gOeMd+aHceN7Y+BsUt5iRttUNdpNLdVGJsxDJMVBI8dCJMVBI70/Ir0/Irs9IbQ7ILE7IKg3HqM2HaA1 - HZw0HJszHJYyG48wGogtGIMsGIAqF34qF3koFnUnFXQnFWsjE2kjE2kjE2kjE2kjE2EhEl8fEV4fEVoe - EFcdEFoeEFcdEFUcD1UcD1AbD1IbD04aDk4aDlAbD0kYDUkYDUYYDUQWDEYYDUIWDEIWDEQWDD8VDD8V - DD8VDD0UCzwUCzoUCzgSCjgSCjYSCjYSCjMRCTMRCTMRCTMRCTEQCTAQCTEQCS4QCTAQCS4QCSwPCCwP - CCsOCCkOCCkOCCUNByQMByQMByALBh8LBh8LBhsJBRsJBRoJBRoJBRgJBRgJBRYHBBYHBBYHBBQHBBQH - BBMHBBMHBBMHBBEGAxMHBBMHBBEGAxEGAxEGAxEGAw8FAw8FAw8FAw4FAw8FAw4FAwwFAw4FAwwFAwoD - AgwFAwoDAgoDAgoDAgoDAgkDAgkDAgoDAgkDAgkDAgcDAgkDAgcDAgUCAQMBAQIBAQIBAQMBAQIBAQMB - AQIBAQIBAQIBAQIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////91bPt1bPttSM9pNLdpOLtpNLdpPMNpOLtlIJ9lJKdlI - J9FFJdZGJs5EJdFFJdNGJs9EJcpDJMpDJMdCJMlCJMdCJMRBI8RBI8RBI8dCJMA/IsdCJMA/Ir4/IsRB - I7s9IcdCJL4/Ir0/Ir4/IsRBI8A/IsdCJMRBI8lCJMdCJMRBI8pDJMpDJM5EJc9EJdlIJ89EJdVGJtZG - JtlJKdlIJ9lJKdtSM9xVN9xXOd1aPOBoTeFuVON7Y+aFb+eNeemXheyikeufjumXhemTgOaJdOWBauJ0 - W99mS91aPNtRMtpNLdZGJthHJtFFJcRBI8RBI8RBI7s9Ib0/IrY8IbE7IKw5H6I2HZ40HJw0HJw0HJsz - HI8wGoYsGIErF34qF3koFnooFnQnFW0kFGsjE2YhEmYhEmMhEmMhEl8fEVoeEFwfEVcdEFgdEFcdEFcd - EFIbD1UcD1McD04aDk0aDk0aDkkYDUcYDUYYDUQWDEQWDEYYDUIWDEEWDEEWDEEWDD8VDD0UCz0UCzoU - CzYSCjYSCjUSCjYSCjYSCjUSCjMRCTMRCTMRCTEQCTAQCS4QCTAQCSwPCCwPCCsOCCsOCCkOCCkOCCcN - ByQMByILBiALBh8LBh8LBh0KBh0KBhsJBRoJBRgJBRgJBRoJBRYHBBQHBBQHBBQHBBMHBBMHBBEGAxEG - AxMHBBMHBBMHBBEGAxEGAw8FAw8FAw8FAw8FAw4FAw4FAw8FAwwFAwwFAwwFAwwFAwoDAgwFAwwFAwoD - AgoDAgwFAwkDAgkDAgkDAgkDAgkDAgkDAgkDAgcDAgMBAQMBAQMBAQIBAQIBAQMBAQIBAQIBAQIBAQAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9xXOdtUNdpPMNtUNdxVN9tRMtpLK9pNLdVGJtlIJ9lJKdlJKdZGJtNGJtNG - JspDJMxDJMpDJMpDJMlCJM9EJcdCJMdCJMdCJMRBI8JAI8RBI8JAI74/IsJAI74/IsVBI8VBI8RBI8lC - JMRBI8VBI8RBI85EJcdCJMlCJMpDJM5EJc5EJdZGJtFFJdFFJdhHJthHJthHJtlIJ9pNLdpOLttSM9xV - N91eQd5gRN9lSuFwV+N3XuWDbeeMd+mVguufjuyklOyklOufjuqaiOmTgOaHcuR8ZeJyWd9lSt1eQdtR - MtpNLdVGJtFFJcpDJMlCJMVBI8JAI8RBI7s9IbE7IK05H6g3Hqg3HqA1HaA1HZszHJQxG40uGYYsGIEr - F3wpFnooFnUnFW8lFG0kFGsjE2gjE2QhEmkjE18fEV4fEVwfEVwfEVwfEVgdEFcdEFMcD1McD1UcD1Ib - D1IbD00aDksZDksZDkYYDUYYDUQWDEIWDEIWDEQWDEIWDEEWDD0UCzwUCzwUCzgSCjYSCjYSCjYSCjYS - CjYSCjMRCTMRCTMRCTEQCTEQCTAQCS4QCSwPCCsOCCwPCCsOCCkOCCkOCCcNByQMByILBiILBiALBh0K - Bh0KBhsJBRsJBR0KBhoJBRgJBRgJBRoJBRgJBRYHBBgJBRYHBBMHBBQHBBEGAxEGAxEGAxMHBBEGAxEG - AxEGAxEGAw8FAxEGAw8FAw4FAwwFAwwFAwwFAwwFAw4FAwwFAwoDAgoDAgoDAgoDAgoDAgoDAgkDAgkD - AgkDAgkDAgkDAgcDAgkDAgcDAgMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9tUNdtRMttRMtxVN9pOLttRMttUNdpPMNpNLdpOLtlJKdhHJtZGJtVGJtVGJtFFJdVGJtNGJspD - JMpDJNFFJclCJMVBI8lCJMdCJMdCJMlCJMVBI8VBI8VBI8RBI8VBI8JAI8dCJMpDJMJAI8VBI8VBI8dC - JM9EJclCJM5EJcpDJNhHJtZGJtVGJthHJtpOLtpLK9pNLdtRMttRMtxXOd1aPN1cP99kSOBoTeBsUuN3 - XuR/aOaHcuiSfuqaiOugj+2qm+2omeyjk+ugj+mWg+iPe+WCbON3XuBrUN9kSN1bPttUNdpOLtlJKdVG - JtFFJc5EJcdCJMA/Irk9IbM7ILM7ILE7IKw5H6M2HZ40HJw0HJkyG5EwGo0uGYMsGIAqF3koFnQnFXIm - FXAlFG0kFG0kFGgjE2YhEl8fEWMhEl4fEV4fEVgdEFcdEFcdEFUcD1McD1McD1IbD1McD00aDksZDksZ - DkcYDUQWDEQWDEIWDEQWDEQWDEEWDD8VDDwUCzoUCzoUCzoUCzgSCjgSCjUSCjMRCTMRCTMRCTMRCTMR - CTEQCTEQCTAQCS4QCS4QCSsOCCwPCCkOCCcNBycNByILBiQMByALBiALBiALBiALBh8LBhsJBRsJBRoJ - BRoJBRoJBRoJBRgJBRYHBBQHBBQHBBYHBBQHBBMHBBMHBBMHBBEGAxEGAxEGAxEGAw8FAw8FAw8FAw8F - Aw8FAw8FAw4FAw4FAwwFAwwFAwoDAgwFAwoDAgoDAgoDAgoDAgoDAgkDAgkDAgoDAgkDAgkDAgkDAgcD - AgcDAgcDAgMBAQMBAQMBAQIBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9tRMttRMtpO - LtpPMNpOLtpNLdpLK9pNLdtSM9tSM9lJKdlJKdlIJ9hHJthHJtVGJtVGJs5EJdFFJdFFJcxDJM9EJcxD - JMlCJMdCJMlCJMdCJMlCJMlCJMlCJMpDJMVBI8xDJMpDJMxDJM5EJcxDJMlCJM5EJcxDJMxDJNFFJdZG - JtlIJ9lIJ9pOLtpNLdtRMtxVN9xXOd1aPNtUNdxXOd5gQ95iRt9mS+FvVeJ0W+R9ZuaHcuiRfemXheuf - juyklO6un+6sneymlu2omOqciumVguaJdOR9ZuFwV+BrUN9lStxYOtxVN9tRMtpNLdZGJs9EJc5EJcdC - JMJAI70/Ir0/IrM7IKw5H6g3HqA1HaU3Hpw0HJkyG5YyG4suGX4qF3ooFnkoFnkoFnQnFWgjE2YhEmYh - EmQhEmMhEmMhEl4fEV4fEVoeEFoeEFcdEFUcD1IbD1IbD1IbD1AbD00aDksZDkcYDUYYDUQWDEYYDUQW - DEEWDEIWDEEWDEIWDD0UCzwUCzgSCjgSCjgSCjoUCzYSCjYSCjMRCTMRCTMRCTMRCTEQCTAQCTEQCTAQ - CS4QCSsOCCkOCCcNByUNByQMByILBiILBh8LBh8LBiALBiALBh0KBhsJBRsJBRoJBRsJBRoJBRgJBRoJ - BRgJBRQHBBYHBBQHBBQHBBEGAxEGAxMHBBEGAxEGAxEGAxEGAxEGAw8FAw8FAw8FAxEGAw8FAw4FAw4F - AwwFAw4FAwoDAgoDAgwFAwwFAwwFAwoDAgkDAgkDAgkDAgoDAgkDAgcDAgcDAgcDAgcDAgcDAgMBAQMB - AQIBAQIBAQMBAQMBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9pOLtxVN9tSM9pOLtpPMNpOLtpN - LdNGJtZGJtlJKdpOLttRMtpOLtpLK9hHJtZGJtZGJtZGJtFFJdVGJsxDJMxDJNNGJs5EJc5EJcxDJMxD - JMlCJMVBI8lCJM5EJclCJM5EJc9EJc5EJcpDJM9EJdVGJtVGJtVGJs9EJdlIJ9pNLdlJKdpLK9tRMttR - MttUNdxVN9xVN91aPN1cP99lSt9kSOBsUuFuVON4YOR9ZuaHcueNeeqZh+ufjuymlu2qm++wou+0p++w - ou6sneyklOqciuiPe+aHcuR/aOJ0W+BrUN5gQ91aPNxXOdpPMNpNLdlIJ9FFJcpDJMVBI8A/Ir4/Ir0/ - Irs9Ia86H6M2HaA1HaA1HZkyG5IwGogtGIYsGIAqF3ooFnkoFnQnFWsjE2kjE2YhEmYhEmQhEmQhEl4f - EVoeEFoeEFgdEFcdEFUcD1IbD1IbD1IbD1IbD1AbD00aDksZDkkYDUcYDUcYDUYYDUEWDD8VDD8VDD0U - Cz0UCz0UCzwUCzoUCzoUCzgSCjYSCjYSCjUSCjMRCTMRCTMRCTEQCTAQCTEQCTAQCS4QCSsOCCkOCCcN - ByQMByILBiILBiILBiALBh8LBh8LBh0KBhsJBRoJBR0KBhsJBRsJBRsJBRoJBRoJBRYHBBQHBBYHBBMH - BBMHBBMHBBEGAxMHBBEGAxEGAxEGAxEGAw8FAw8FAw8FAw8FAxEGAxEGAw4FAw4FAwwFAwwFAwwFAwoD - AgwFAwoDAgoDAgoDAgoDAgkDAgkDAgkDAgcDAgcDAgcDAgkDAgkDAgcDAgMBAQMBAQIBAQIBAQIBAQIB - AQMBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9tSM9tRMttUNdtRMtpNLdpNLdpNLdlIJ9lIJ9hHJtlI - J9VGJthHJtpNLdpOLtpOLtlIJ9hHJtlJKdhHJtNGJs9EJcxDJM5EJdNGJs9EJcpDJM9EJcxDJNFFJcpD - JMpDJM9EJc9EJclCJNlJKc5EJdFFJdVGJtVGJtlJKdtRMtlJKdlJKdpOLttUNdxXOd1bPt1aPN1eQd1c - P95gRN9lSuBrUOFwV+N7Y+R8ZeaFb+eMd+mTgOqaiOyklO6sne+wou+zpfC5rO+zpe+ypO2qm+yjk+qZ - h+iRfeaHcuR8ZeJ1XOBrUN9lSt5gQ9xXOdtRMtpNLdhHJs9EJclCJMRBI8VBI9FFJdlIJ8lCJLM7IKc3 - Hpw0HJkyG5YyG48wGo0uGYMsGH4qF3koFnUnFXAlFGsjE2kjE2YhEmYhEmEhEl4fEVoeEFgdEFgdEFcd - EFgdEFcdEFIbD04aDk4aDk0aDksZDk4aDkcYDUkYDUkYDUQWDEIWDEIWDD8VDDwUCzwUCz0UCzoUCzwU - CzwUCzwUCzYSCjYSCjUSCjMRCTMRCTMRCTMRCTEQCTEQCS4QCSsOCCUNBycNByUNByILBiQMByUNByQM - ByILBiILBh8LBh0KBh0KBh8LBhsJBRoJBRoJBRoJBRoJBRoJBRYHBBQHBBQHBBQHBBQHBBMHBBQHBBEG - AxEGAxEGAxEGAxEGAxEGAw8FAw8FAw8FAw4FAw4FAw4FAw4FAw4FAwwFAwwFAwwFAwoDAgkDAgkDAgkD - AgoDAgkDAgkDAgkDAgkDAgkDAgcDAgkDAgkDAgcDAgMBAQIBAQMBAQIBAQMBAQMBAQMBAQIBAQIBAQIB - AQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9tUNdtSM9tUNdtUNdpOLtpOLtpLK9pNLdlIJ9lJKdpNLdlIJ9ZGJtNGJthH - JtpNLdpLK9pNLdpPMNpLK9VGJs9EJc9EJc9EJcxDJNFFJcpDJNNGJtNGJs5EJcxDJM9EJdFFJc9EJdNG - JtVGJtZGJtNGJtVGJthHJtpOLttSM9pOLttRMtxVN9xXOd1aPN5iRt9kSN9kSN9lSuBsUuBqT+J1XON5 - YeWBauaHceaJdOmXheqciuyjk+2qm++wovC3qvG6rvK/s/C5rPC3qu+wou2omeyklOqZh+eMd+aHceR9 - ZuJ1XOBrUN9mS95gQ9xYOtpPMNpNLdlIJ9FFJclCJMlCJNhHJtpPMNVGJrg9Iao4HqU3Hpw0HJkyG5Yy - G5IwGoUsGH4qF3ooFnkoFncnFXImFW8lFGkjE2QhEmMhEl8fEV4fEVoeEFgdEFgdEFcdEFUcD1McD1cd - EFIbD1AbD0sZDk0aDkcYDUcYDUcYDUQWDEEWDEEWDEIWDD8VDD0UCz0UCzwUCzoUCzoUCzgSCjYSCjYS - CjUSCjMRCTMRCTMRCTEQCTEQCTAQCSsOCCkOCCcNBycNByQMByQMByUNByUNByQMByQMByILBiALBh8L - Bh8LBh8LBh0KBhsJBRoJBRgJBRYHBBgJBRYHBBQHBBQHBBMHBBYHBBMHBBMHBBEGAxMHBBMHBBEGAw8F - Aw8FAxEGAw4FAw8FAw8FAw4FAw4FAw4FAw4FAw4FAw4FAwwFAwwFAwoDAgoDAgoDAgoDAgoDAgkDAgkD - AgkDAgkDAgkDAgkDAgcDAgcDAgMBAQMBAQIBAQMBAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9tUNdxYOttSM9pOLtpPMNpOLtpOLtpPMNpOLtlIJ9pLK9lIJ9VGJtFFJdFFJdZGJtZGJtVGJtZG - JthHJtZGJtZGJtVGJtNGJtNGJsxDJM9EJdFFJdNGJtNGJs5EJdNGJs9EJdhHJtZGJtlIJ9ZGJtZGJtpL - K9pNLdpPMNpOLtxVN91cP91cP95gQ+BoTeBoTd9lSuBqT+FuVOJyWeJ1XON7Y+R8ZeaHcueNeemTgOue - jO2omO6sne+ypPC2qfG8sPK/s/LDuPK/s/K/s/C3qu6uoO6sneyjk+mWg+eMd+aHcuR8ZeN3XuBrUN9l - St5gQ9tUNdxVN9pOLtFFJcxDJMpDJNFFJdVGJsxDJLQ7IKo4Hqo4HqU3HpszHJkyG5QxG4YsGIAqF3oo - FnUnFXUnFXQnFW0kFGkjE2YhEmMhEl4fEV4fEVwfEVgdEFoeEFgdEFcdEFMcD1UcD1McD1AbD00aDk0a - DkkYDUQWDEYYDUYYDUIWDEEWDEEWDD0UCzwUCzwUCzwUCzoUCzoUCzgSCjYSCjYSCjYSCjMRCTMRCTMR - CTEQCS4QCSwPCCkOCCkOCCcNBycNByUNBycNByQMByILBiALBh8LBh8LBh8LBh8LBh0KBh0KBhsJBRoJ - BRgJBRgJBRoJBRgJBRQHBBQHBBYHBBMHBBMHBBQHBBEGAxEGAxEGAxEGAxEGAw8FAxEGAxEGAw8FAw8F - Aw8FAw4FAw8FAw4FAwwFAwwFAwwFAw4FAwwFAwoDAgoDAgoDAgoDAgkDAgkDAgkDAgkDAgkDAgcDAgcD - AgkDAgcDAgMBAQMBAQIBAQMBAQMBAQIBAQMBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9xXOdtRMttU - NdtSM9pPMNpLK9pOLtpNLdpLK9pPMNlJKdlIJ9ZGJtFFJdZGJthHJtNGJtVGJtlIJ9lIJ9ZGJthHJtlJ - KdpLK9lIJ9pLK9ZGJtNGJtZGJtZGJtVGJthHJtlJKdVGJtVGJtlIJ9lJKdpOLtpOLttRMtxXOdxXOdxX - Od1cP95gROBoTeBqT+BsUuBqT+FuVOJ1XOR8ZeWCbOWBauaHcemVgumWg+yikeyklO6un++zpfC5rPK/ - s/LDuPPFuvTKwfPFuvPFuvK/s/C5rO+wou2omeyikemXheiRfeaHceR/aON7Y+FuVN9lSt1cP9xYOtpP - MNlJKdVGJs5EJcVBI8RBI70/IrQ7IKc3Hqc3Hqc3Hp40HJszHJIwGo0uGYErF3wpFncnFXUnFXUnFW0k - FGgjE2sjE2MhEl4fEVoeEFoeEFgdEFgdEFcdEFcdEFUcD1McD1IbD1IbD00aDk0aDkcYDUcYDUcYDUYY - DUIWDEEWDD8VDD0UCzoUCzwUCzoUCzoUCzoUCzgSCjYSCjYSCjMRCTMRCTMRCTEQCTAQCSwPCCkOCCkO - CCsOCCkOCCcNBycNBycNByILBiILBiALBh0KBh8LBh8LBiALBhsJBRsJBR0KBhsJBRgJBRgJBRgJBRgJ - BRQHBBQHBBQHBBMHBBMHBBMHBBQHBBQHBBEGAxEGAw8FAw8FAxEGAxEGAw4FAw4FAw8FAw4FAw4FAw4F - AwwFAw4FAwwFAwoDAgwFAwoDAgoDAgkDAgkDAgkDAgkDAgcDAgcDAgkDAgkDAgcDAgkDAgcDAgMBAQMB - AQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9xXOdxYOttSM9tRMttRMtpPMNpO - LtpLK9pOLtlIJ9lJKdlJKdlIJ9hHJtFFJdNGJtVGJtNGJtVGJthHJtlIJ9VGJtpLK9lIJ9lIJ9lJKdlJ - KdhHJtpNLdpLK9NGJtlIJ9lJKdlIJ9hHJtpLK9pOLtpPMNtUNd1bPt1cP95iRt5gQ99lSt9kSOBqT+Br - UOJyWeN3XuN4YOR8ZeaFb+eMd+iPe+iRfeqZh+yike2ome6snfC3qvG8sPLBtvPHvfTJv/TLwvXRyfXN - xPXPxvPFu/LBtvG8sO+0p+2qm+yklOqZh+mTgOaHcuR9ZuJ1XOBrUN9mS91cP9xVN9tRMtlJKc9EJclC - JMJAI74/Irk9Ia86H6o4Hqc3Hpw0HJw0HJszHJIwGoUsGIAqF3koFnUnFXUnFW8lFGkjE2sjE2YhEmMh - El4fEV8fEVgdEFgdEFcdEFcdEFMcD1McD1IbD1AbD1AbD0sZDksZDkcYDUQWDEYYDUIWDD8VDEEWDD0U - Cz0UCzwUCzoUCzgSCjoUCzgSCjYSCjYSCjMRCTMRCTEQCTEQCS4QCSwPCCsOCCkOCCkOCCcNBycNBycN - ByQMByQMByQMByILBh8LBh0KBh0KBh8LBh8LBhsJBR0KBhsJBRoJBRgJBRYHBBgJBRgJBRYHBBQHBBMH - BBMHBBMHBBEGAxEGAxEGAxEGAxEGAw8FAxEGAxEGAw8FAw8FAw4FAw8FAw8FAw4FAwwFAwwFAwwFAwoD - AgoDAgoDAgkDAgkDAgoDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgMBAQMBAQIBAQMBAQMBAQMB - AQIBAQMBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9xXOdxYOtxXOdtRMttUNdtUNdtRMttSM9pLK9pLK9pO - LtlIJ9lJKdlJKdZGJtNGJtNGJthHJtZGJtFFJdNGJthHJtVGJtlJKdZGJtZGJtNGJtlIJ9pLK9pOLtpP - MNpNLdpOLtpOLtpOLttUNdxYOtxVN91bPt1aPN5iRt5gROBoTeBoTeBsUuFvVeJyWeJ1XOR8ZeR9ZuWD - beaJdOiPe+mVguqaiOyike2omfC2qfG8sPK/s/LDuPPHvfXPxvXPx/bTy/fa0/bUzPbVzvXPxvPHvfPF - uvK/s++zpe6un+yklOqciuiSfuaHceR9ZuN3XuBsUt9mS95gRNxYOtpOLtZGJtFFJcRBI74/Ir0/IrY8 - Ia05H6c3Hqg3Hp40HJszHJIwGosuGYErF3ooFnkoFnUnFXImFWkjE2gjE2QhEl8fEWEhElwfEVoeEFgd - EFoeEFcdEFUcD1IbD04aDk4aDk4aDk0aDkkYDUcYDUYYDUYYDUQWDEEWDD8VDD8VDD8VDDwUCzwUCzgS - CjoUCzYSCjYSCjUSCjMRCTEQCTAQCTAQCS4QCSwPCCkOCCkOCCkOCCkOCCcNByUNByQMByQMByQMByIL - Bh8LBh8LBiALBh8LBh0KBhsJBR0KBhoJBRoJBRoJBRgJBRgJBRYHBBQHBBYHBBQHBBQHBBQHBBEGAxEG - AxEGAxEGAxEGAxEGAw8FAxEGAw8FAxEGAw4FAw4FAw4FAw4FAw4FAwwFAwwFAwwFAwwFAwwFAwoDAgoD - AgoDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgMBAQMBAQMBAQMBAQIBAQIBAQMBAQIBAQIBAQIB - AQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9xVN9xVN9tUNdpOLttUNdpPMNtRMttUNdtRMtpPMNpPMNpOLtpLK9pOLtlJ - KdZGJthHJtlIJ9lJKdNGJthHJtZGJthHJtZGJthHJtFFJdVGJtpLK9pNLdpOLtpLK9pOLttUNd1cP91a - PNxXOdxVN91cP95gQ9xYOt9kSN9kSOBrUOBrUOFwV+FvVeN3XuN4YOWCbOaJdOeMd+iRfeqZh+ufjuyi - ke2qm++zpfG8sPLDuPTJv/XPxvXRyfbVzvfZ0vfa0/jg2vjd1/jb1fbVzvbVzvXNxPPFuvLAtfC3qu+w - ouyklOqZh+iRfeaHcuR8ZeJyWeBsUt9kSN5gQ9tUNdpOLthHJsxDJMlCJL4/Irk9IbM7IKg3Hqg3HqA1 - HaI2HZcyG48wGoMsGHwpFnkoFnkoFnQnFW0kFGkjE2QhEmYhEmEhEl4fEVwfEVcdEFcdEFcdEFUcD1Uc - D1McD04aDk4aDksZDkcYDUkYDUcYDUQWDEIWDEEWDEEWDEEWDD8VDDoUCzwUCzoUCzYSCjYSCjUSCjMR - CTEQCTAQCTAQCTAQCSsOCCwPCCsOCCkOCCcNByUNByUNByUNByUNByQMByQMByILBiILBh8LBh8LBh0K - Bh8LBh8LBhsJBRoJBRoJBRgJBRgJBRYHBBYHBBQHBBMHBBMHBBQHBBMHBBEGAxEGAxEGAxEGAxEGAxEG - AxEGAw8FAw8FAw8FAw4FAw4FAw4FAwwFAwwFAwwFAwwFAwwFAwoDAgoDAgoDAgoDAgkDAgkDAgkDAgkD - AgkDAgkDAgkDAgcDAgcDAgcDAgUCAQMBAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////91aPNtRMttSM9pPMNtRMtpPMNtSM9pOLttRMtpNLdtRMtpOLtlJKdpOLtpNLdpLK9pNLdpOLtpL - K9lJKdVGJtlJKdlIJ9hHJtlJKdhHJthHJtlJKdlJKdpLK9pLK9pPMNtSM9xXOd1eQd1cP91eQeBoTd9l - St9mS99kSOBsUuBsUuFwV+J0W+N3XuWBauR/aOaHcueLdumWg+qaiOufjuymlu6uoO+zpfK/s/LDuPTL - wvXRyfbVzvjb1fjd1/jg2vni3fnk3/rm4fnk3/je2Pjb1ffZ0vXRyfTKwfLDuPC5rO6sneyikeufjuiP - e+aHcuR9ZuJyWeBrUN9lSt1aPNtSM9lIJ9FFJclCJMVBI70/IrM7IK05H6o4HqA1HZkyG5cyG5EwGogt - GIMsGHooFnooFnImFW0kFGgjE2gjE2MhEmMhEl4fEVoeEFcdEFcdEFcdEFMcD1McD1IbD04aDk0aDk0a - DkcYDUcYDUYYDUcYDUIWDEIWDD8VDD8VDDwUCzwUCzgSCjYSCjMRCTUSCjMRCTEQCTEQCS4QCS4QCTAQ - CSwPCC4QCSsOCCsOCCcNByUNByQMByUNByQMByQMByALBiALBh8LBiALBiALBh8LBh8LBh0KBhgJBRoJ - BRoJBRYHBBoJBRYHBBQHBBMHBBQHBBMHBBQHBBMHBBEGAxEGAxEGAw8FAxEGAxEGAxEGAxEGAw8FAw4F - Aw4FAw4FAwwFAwwFAwwFAwwFAwwFAwwFAwoDAgoDAgoDAgoDAgoDAgkDAgkDAgkDAgoDAgkDAgkDAgkD - AgkDAgkDAgUCAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9tSM9tSM9xV - N9tSM9tSM9tRMtpPMNpLK9pOLtpPMNpOLtpLK9pLK9lIJ9lJKdpLK9lIJ9pNLdtRMtpNLdpLK9lIJ9lI - J9lIJ9pNLdpLK9ZGJtpOLtpOLtpOLtpOLttRMttUNdxVN91bPt1aPN1eQeBqT+FwV+FvVeFwV+J1XOJy - WeN4YOR/aOWCbOWCbOeMd+iPe+mVguqZh+yklO2ome6uoO+0p/G8sPPFu/XPxvXRyfjb1fjd1/ni3frm - 4fvq5vvs6Pvs6Pvs6fvs6Prn4/rm4fnh3Pjb1fbVzvTLwvLDuPC3qu6uoOyklOqaiOiPe+aHceR/aOFv - VeBqT95gQ9xYOtpOLtpNLdFFJcRBI8A/IrY8Ia05H6o4HqM2HZ40HJszHJQxG4ouGX4qF3koFnkoFnUn - FXImFW0kFGgjE2QhEmEhEl4fEVoeEFoeEFcdEFUcD1UcD1McD1McD1AbD00aDk0aDkcYDUYYDUQWDEcY - DUIWDEIWDEEWDD0UCz0UCzoUCzYSCjUSCjMRCTMRCTMRCTEQCTEQCTAQCTEQCSwPCCwPCCwPCCwPCCsO - CCkOCCcNByUNBycNByQMByUNByQMByALBiALBh8LBh8LBh8LBh0KBhsJBRgJBRgJBRgJBRYHBBoJBRoJ - BRYHBBQHBBQHBBQHBBQHBBMHBBMHBBMHBBEGAxEGAxEGAxEGAw8FAxEGAxEGAxEGAw4FAw4FAwwFAwwF - AwwFAw4FAwwFAwwFAwwFAwwFAwoDAgkDAgkDAgoDAgkDAgkDAgkDAgkDAgkDAgkDAgcDAgcDAgUCAQMB - AQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9tSM9tSM9xXOdxXOdpOLttRMttS - M9pOLtpOLtpOLtpLK9pOLtpLK9lJKdpLK9pLK9lJKdpNLdlIJ9pLK9ZGJtpNLdlJKdlJKdZGJtpOLtpO - LtpOLtpOLttRMtpOLttSM9xXOdxXOd1aPN5gRN5gROBrUOBrUOFuVOJyWeR8ZeWCbOR/aOaFb+aHcueL - dumTgOmVguuejOyjk+2ome6un/C3qvLAtfLDuPXPxvbUzPfa0/jg2vrn4/ro5Pvs6Pvu6/vu6/vu6/vu - 6/vu6/vu6/vs6fvq5vrn4/nh3PbVzvXPxvLBtvG6ru6uoOyklOqaiOeNeeaFb+R9ZuJyWd9mS95iRtxY - OtpOLtZGJsxDJMdCJL0/IrM7IK05H605H6M2HZ40HJEwGogtGIErF3koFnUnFXImFXImFW8lFGgjE2Mh - EmMhEmEhEloeEFwfEVoeEFUcD1McD1McD1McD04aDlAbD00aDk0aDkQWDEcYDUIWDEEWDEEWDDwUCzwU - CzwUCzYSCjMRCTYSCjUSCjMRCTMRCTEQCTEQCTAQCS4QCSwPCCwPCCwPCCwPCCkOCCkOCCcNByUNBycN - ByQMByQMByQMByILBiILBh8LBh8LBh0KBh8LBhsJBdbV1P////////////////////////////////// - /////////////////////////////////////////////+Dg39XU1L69vaalpGtpaAwFAw4FAwwFAwwF - AwwFAwwFAwwFAwoDAgoDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgcDAgkDAgUCAQMBAQMBAQMBAQMBAQMB - AQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9tSM9xXOdtSM9tSM9tRMttRMtpOLtpNLdtSM9pPMNpO - LtpOLtpLK9pLK9pNLdVGJtlJKdlJKdhHJtVGJtpNLdlJKdhHJtlIJ9lIJ9lJKdpOLtpPMNpOLtpOLttS - M9xVN91bPt1aPN1eQd5iRuBqT+FwV+BrUOJyWeN3XuR/aOWCbOaHcueLduiPe+mVguqZh+yikeymlu2o - mO+wovC3qvK/s/PFu/XNxPfX0Pjd1/nh3Pro5Pvs6fvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu - 6/vs6fro5Pje2PfZ0vXPxvLDuPC2qe2qm+yikeqZh+eNeeaFb+N4YOFwV99mS91eQdxXOdpOLtVGJs9E - JcdCJLs9IbM7IK86H6M2HZszHJkyG40uGYYsGHkoFnkoFnUnFXcnFW8lFGkjE2MhEmMhEl4fEV4fEVoe - EFwfEVcdEFcdEFUcD1McD1AbD04aDk4aDksZDkcYDUYYDUQWDEQWDD8VDDoUCzoUCzoUCzgSCjYSCjUS - CjUSCjUSCjMRCTEQCTAQCTEQCS4QCS4QCSsOCCwPCCwPCCkOCCkOCCkOCCcNByUNByQMByILBiILBiAL - BiALBh8LBh8LBh0KBh0KBhsJBdbV1P////////////////////////////////////////////////// - /////////////////////////////////////////////////////8rJyYqJiCwoJwoDAgwFAwoDAgoD - AgoDAgkDAgoDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgUCAQUCAQMBAQMBAQMBAQMBAQMBAQIBAQIBAQIB - AQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9tUNdtRMttRMttSM9pPMNpOLttSM9pOLtpNLdlJKdpLK9pLK9lJKdpNLdpN - LdlJKdpLK9lJKdpNLdlIJ9lIJ9VGJtpLK9lIJ9pOLtpOLtpOLtpPMNtSM9tUNdxVN91bPt1bPt5iRt9l - SuBrUOFwV+J1XOJ0W+JyWeR8ZeaHceaHcueLdumTgOmWg+uejOymlu6sne+ypO+zpfG8sPK/s/TJv/XP - xvfX0Pjd1/ni3frn4/vs6Pvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vs6fvq5vnh - 3PfX0PTKwfLAte+0p+6sneyklOqciueNeeWCbON4YOFvVeBqT95gRNtUNdlIJ9NGJspDJMJAI7g9IbY8 - Iaw5H6I2HZszHJIwGoMsGH4qF3koFnQnFXImFXAlFG8lFGkjE2MhEmMhEmEhElwfEV8fEVwfEV8fEVgd - EFcdEFUcD1AbD00aDkkYDUYYDUQWDEIWDD8VDD0UCzoUCzgSCjgSCjgSCjYSCjUSCjMRCTMRCTMRCTAQ - CTAQCTAQCS4QCTAQCS4QCS4QCSwPCCkOCCcNByUNByUNBycNByILBiILBiQMByILBiALBiALBiALBh0K - Bh0KBh0KBtbV1P////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////X19aWkpC4qKAwFAwoDAgoDAgoDAgoDAgoD - AgoDAgkDAgcDAgcDAgcDAgkDAgUCAQMBAQMBAQMBAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9tUNdtSM9tUNdtRMttRMtpOLtpPMNtRMtpOLtlIJ9pOLtpNLdlJKdpLK9pNLdpNLdpNLdpOLtlJ - KdlJKdpLK9NGJtpLK9pNLdpLK9pPMNpOLttSM9xVN9tSM91bPt1bPt9lSt9mS+BrUOBrUOJ1XON7Y+R/ - aOaFb+aJdOiSfuiSfuiSfuqaiOuejOyklO2qm++wovC3qvG9sfLDuPTKwfXPxvbVzvjd1/ni3frn4/vs - 6fvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vs6frm4fjg2vbTy/TKwfLA - tfC2qe2qm+yjk+mXheeMd+aFb+N7Y+FvVeBqT95gQ9xXOdpOLtZGJs9EJcpDJL0/IrQ7IKw5H6U3Hpsz - HIsuGYYsGIMsGH4qF3cnFXcnFXQnFXImFWkjE2kjE2gjE2MhEmEhElwfEVoeEFgdEFgdEFgdEFUcD0sZ - DkcYDUQWDEQWDD8VDEEWDDwUCzwUCzgSCjgSCjYSCjUSCjMRCTMRCTMRCTMRCTEQCTEQCTAQCTAQCTAQ - CSwPCCsOCCwPCCsOCCcNByUNByUNByUNByUNByILBiILBiALBiALBiALBh8LBh8LBhsJBRsJBdbV1P// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////X19aWkpAoDAgoDAgoDAgkDAgoDAgoDAgkDAgcDAgkD - AgcDAgcDAgUCAQMBAQMBAQMBAQIBAQMBAQMBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9xXOdxXOdpP - MNpPMNpOLttSM9tRMttSM9pOLtpOLtpLK9lJKdhHJttRMtpNLdlJKdpLK9pLK9pOLtlJKdpOLtlJKdlJ - KdpNLdpPMNpPMNpPMNtUNd1aPN9lSt5gQ99kSOBoTeBrUOJ1XON4YOWDbeWBauaHceaJdOiRfemXheuf - juyikeyklO2ome6sne+wou+0p/G6rvLDuPTJv/XPx/bVzvjb1fjg2vrm4fvs6Pvu6/vu6/vu6/vu6/vu - 6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vs6Pnk3/jb1fXRyfPHvfG8sO+ypO2omeyi - kemVgueMd+aHceR8ZeFwV+BrUN9lSt1bPttUNdpOLtlJKc5EJcdCJL0/Irs9IbE7IKA1HZkyG5EwGo0u - GYErF34qF3koFnQnFW0kFGsjE2YhEmEhEloeEFwfEVgdEFgdEFUcD1McD1AbD0cYDUYYDUIWDEIWDEEW - DDwUCzwUCzwUCzYSCjYSCjYSCjUSCjMRCTMRCTMRCTMRCTEQCTEQCTEQCTAQCS4QCSkOCCkOCCwPCCwP - CCsOCCcNByUNByQMByILBiQMByQMByALBh8LBh8LBh8LBh8LBh0KBh8LBtbV1P////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////////////+Df30VBQAoDAgkDAgoDAgkDAgkDAgcDAgcDAgcDAgcDAgUCAQUC - AQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9pPMNtSM9tUNdtRMtpPMNpOLttS - M9tRMtpOLttRMtpOLtpNLdpLK9tRMtpOLtpLK9pOLtpNLdpNLdlJKdlJKdlJKdpOLtpNLdtRMttSM9xX - Od5gQ95gROBrUOBrUOFvVeJ1XON7Y+WBauWCbOaHcueLdueNeeiPe+qZh+uejOyjk+ymlu2ome6uoPC2 - qfC3qvLBtvLDuPPHvfXNxPbTy/fX0Pje2Pnk3/vs6Pvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu - 6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vs6fvq5vnh3PfX0PTLwvLDuPC5rO+wou2omOugj+qZh+iPe+aH - cuWCbON7Y+J1XOFwV+BrUN9lSt1eQdxXOdtRMtlIJ85EJcdCJLk9Iaw5H5cyG5IwGoUsGIAqF3koFnAl - FGgjE2YhEmEhEl8fEVwfEVcdEFUcD1UcD1IbD1AbD0sZDkcYDUYYDUcYDUIWDEEWDD0UCzwUCzgSCjgS - CjgSCjYSCjUSCjMRCTMRCTMRCTMRCTMRCTAQCS4QCTAQCS4QCSwPCCwPCCkOCCkOCCkOCCkOCCcNByUN - ByILBiQMByILBiALBh8LBiALBh0KBiALBhsJBR0KBtbV1P////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////X19VlWVQkDAgkDAgkDAgkDAgkDAgkDAgcDAgcDAgMBAQUCAQMBAQIBAQIBAQMB - AQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9tSM9tSM9pPMNxVN9pPMNpNLdpOLttRMtpNLdpPMNpN - LdpNLdpNLdhHJtpNLdpLK9lIJ9pOLtpOLtlJKdpOLtlJKdtUNdpOLtxYOt1eQd9lSt9lSuFwV+N3XuN5 - YeR9ZuWBauaHcuaHcueMd+iSfumVguqaiOuejOyjk+ymluymlu6sne6un++zpfC3qvG8sPLAtfPHvfTL - wvXRyffX0Pfa0/jg2vrm4fvs6Pvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu - 6/vu6/vu6/vu6/vu6/vs6Prm4fjb1fXRyfTJv/LAtfG6ru+wou2omeyklOuejOmWg+iRfeeLduaHcuR/ - aON3XuJyWeBrUN9mS95gRNxYOtpOLthHJslCJL0/IrE7IKA1HZQxG4YsGHkoFmsjE2QhEmQhEl4fEVwf - EVcdEFMcD1McD1McD1IbD04aDk4aDkcYDUYYDUIWDEIWDD8VDEEWDD0UCz0UCzgSCjgSCjYSCjYSCjMR - CTMRCTEQCTEQCTAQCTEQCS4QCS4QCS4QCSwPCC4QCSsOCCkOCCcNBycNBycNByQMByALBiILBiQMByIL - BiALBh8LBh8LBh8LBhsJBRsJBdbV1P////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////X19VhWVQkDAgkDAgkDAgkDAgkDAgkDAgkDAgMBAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQAA - AAIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9tSM9tRMttRMttSM9pPMNpPMNpOLttSM9pLK9pLK9pOLtpLK9pNLdpOLtpO - LtpNLdpLK9pOLtpNLdpNLdpOLtpPMNtRMt1bPuBoTeBsUuJyWeN7Y+WDbeaFb+aHceeMd+iPe+iSfumT - gOmXheqciuuejOyikeymluymlu6sne6uoO+wovC2qfC5rPG8sPLBtvPFuvPHvfTLwvXRyffX0Pjb1frm - 4frn4/vs6Pvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu - 6/vs6fro5Pjg2vjb1fXPxvPFu/LBtvG6ru+ypO2omeyklOqciumWg+iRfeeLduaHceR9ZuN4YOJ0W+Fw - V+BrUN9kSN5gQ9xYOtpOLtlIJ85EJcA/IrQ7IJ40HIouGXkoFm0kFGYhEl8fEVwfEVoeEFgdEFcdEFcd - EFMcD1AbD0sZDkkYDUQWDEIWDD8VDEIWDEEWDD8VDDgSCjgSCjgSCjgSCjYSCjUSCjMRCTMRCTAQCTAQ - CS4QCSwPCCwPCCwPCCwPCCwPCCsOCCkOCCUNByUNByUNByQMByILBiALBiILBiILBh8LBh0KBh0KBh0K - Bh0KBhsJBdbV1P////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////X19VhW - VQkDAgkDAgkDAgkDAgkDAgcDAgUCAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAIBAQAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9tSM9tSM9tSM9tRMttUNdtRMtpPMNpOLtpOLtpNLdpOLtpNLdpPMNpOLtpPMNpLK9pNLdpOLtlJ - KdpOLtpOLttSM91cP+BsUuR8ZeWCbOaHcueLdueNeemTgOmVgumXhemWg+qciuufjuufjuyjk+yjk+yk - lO6un+6sne6uoO+wou+0p/C2qfG8sPK/s/LDuPPFuvTKwfXPxvbUzPfZ0vjd1/nh3Pro5Pvs6fvu6/vu - 6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vq5vnh3Pfa - 0/XRyfTKwfLBtvG6ru+zpe6un+2omOyklOuejOmXhemVguiPe+aJdOaHceWCbON7Y+N5YeN3XuFvVeBr - UN5iRt1cP9xYOtpPMNlJKcpDJLM7IJszHHcnFWgjE2MhEl8fEVoeEFgdEFUcD1AbD00aDksZDkcYDUcY - DUQWDEIWDD8VDEEWDD0UCzwUCzgSCjgSCjYSCjYSCjUSCjMRCTMRCTMRCTEQCTAQCTAQCSwPCC4QCSsO - CCsOCCsOCCkOCCkOCCcNByUNByQMByUNByILBiILBiQMByALBiALBh8LBh0KBh0KBhsJBR0KBtbV1P// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////X19SwoJwoDAgkDAgkD - AgkDAgkDAgMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9tRMttSM9tS - M9tSM9pOLtpPMNpPMNpPMNpLK9pLK9pOLtpNLdpOLtpOLtpNLdpOLtpNLdpOLtpOLttRMtpLK95iRuJy - WeaFb+eMd+iRfemTgOmWg+mXheqaiOqaiOuejOqciuugj+yikeyike2omOyklO6un+6un+6uoO+ypO+0 - p/C2qfC5rPG9sfLBtvLDuPPFu/TLwvXPx/bUzPfa0/jg2vni3fvq5vvs6Pvu6/vu6/vu6/vu6/vu6/vu - 6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vq5vjg2vbVzvXNxPPHvfLAtfC5 - rO+zpe6sneyklOyikeuejOqZh+mTgOiPe+eLduaHcuWCbOR9ZuN5YeJ1XOJyWeFuVOBoTd5iRt5gRN1b - PtxXOdpPMNhHJr0/IpEwGmgjE1oeEFgdEFcdEFcdEFIbD04aDksZDkcYDUkYDUQWDEYYDUIWDD8VDEIW - DEEWDDoUCzoUCzgSCjYSCjoUCzUSCjUSCjMRCTMRCTEQCTAQCTAQCSwPCCwPCCwPCCcNBykOCCkOCCkO - CCkOCCUNByUNByUNByILBiILBh8LBh8LBh8LBiALBh0KBhsJBRsJBRoJBdbV1P////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////9XU1AoDAgkDAgkDAgcDAgcDAgMBAQMB - AQMBAQMBAQIBAQMBAQIBAQMBAQMBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9tRMttRMttRMttRMtpPMNtRMtpN - LdpOLtpOLtpOLtpOLtlJKdpNLdpNLdpOLtpLK9pNLdpOLttRMtpOLttSM91eQeN4YOaHcuiPe+iSfumV - gumWg+mXheqZh+qaiOugj+ufjuyikeyklOyklO2ome2ome6sne6uoO+wou+ypO+zpfC2qfG9sfG9sfLD - uPLDuPPHvfTLwvXPxvbVzvfa0/jg2vni3fvq5vvs6Pvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu - 6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vs6fro5Pjd1/bUzPTKwfLDuPLAtfC2qe6uoO2omeyjk+ue - jOqaiOmTgOeNeeaJdOaFb+WCbON7Y+N5YeN5YeJyWeFuVOBrUN5iRt1eQd1eQdxYOttUNdpOLtFFJb0/ - IpYyG2sjE1gdEFUcD1UcD1McD04aDk0aDk0aDksZDksZDkcYDUYYDUQWDEEWDD8VDD0UCzoUCzoUCzgS - CjYSCjgSCjMRCTMRCTEQCTMRCTMRCTAQCTAQCS4QCSwPCCwPCCsOCCsOCCkOCCkOCCUNBycNByUNByQM - ByQMByQMBx8LBh0KBh8LBh0KBh0KBhsJBRoJBRoJBdbV1P////////////////////////////////// - /////21qaREGAxEGAxEGAxEGAxEGAw8FAw4FAw8FA1pXVnx6ebKxsOvq6v////////////////////// - /////////////////////////////////////5iXlgkDAgcDAgcDAgcDAgMBAQMBAQMBAQMBAQMBAQIB - AQIBAQIBAQIBAQAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9tRMtpPMNpOLttSM9pOLtpPMNtRMtpOLttRMtpLK9pP - MNpLK9pOLtpLK9tRMtlIJ9pOLttRMtpPMNpPMNpPMNtUNd5gROFuVOR8ZeaHcuaHcueLduiPe+mWg+mW - g+qZh+qaiOufjuugj+yjk+2omO2omO2ome2qm++wou+wou+ypO+zpfG6rvLAtfLAtfPFuvPFu/TLwvXR - yfbUzPfZ0vje2Pnh3Prn4/vs6Pvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu - 6/vu6/vu6/vu6/vu6/vs6fni3fjb1fbTy/TJv/LDuPG9se+0p+6un+ymluyikeqaiOmVguiPe+aJdOWD - beWCbON7Y+N3XuJyWeFwV+BrUN9mS95iRt1bPtxVN9pOLtlIJ8xDJL4/Iqo4Ho8wGnAlFFwfEVcdEFcd - EFIbD1AbD04aDk4aDk4aDkkYDUQWDEcYDUQWDEEWDDwUCzwUCz0UCzgSCjoUCzYSCjYSCjUSCjMRCTYS - CjMRCTMRCTEQCTAQCTAQCS4QCSwPCCwPCCwPCCsOCCcNBycNByUNBycNByQMByILBiQMByQMByILBiAL - Bh8LBh0KBh8LBhsJBRoJBRoJBdbV1P///////////////////////////////////////2xpaBEGAxEG - AxEGAxEGAxEGAw8FAw8FAw4FAw4FAw4FAw4FAw4FA3x6eevq6v////////////////////////////// - //////////////////////X19SwoJwkDAgcDAgcDAgMBAQMBAQMBAQIBAQIBAQMBAQIBAQIBAQIBAQAA - AAIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9pPMNtRMttUNdtSM9pPMNtSM9pOLtpNLdpLK9pOLtlJKdpOLtpLK9pOLtpN - LdpOLttRMtpOLttSM9tSM9pPMNtSM9xVN91eQd9mS+FwV+J0W+R9ZuaHcuaHceaJdOiRfeiRfemTgOmX - heuejOyjk+ugj+yklOymlu2ome+wou+wovC2qfC5rPG9sfG9sfLDuPPFuvTJv/XNxPbTy/fZ0vje2Pnh - 3Prn4/vs6Pvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu - 6/vq5vnh3PfZ0vXRyfPHvfK/s/C3qu+wou2qm+yjk+qaiOmVguiRfeaJdOWDbeR/aON7Y+J1XOBsUuBq - T99kSN1bPtxYOtpOLthHJs5EJcJAI7Y8IaM2HZcyG4MsGG8lFGEhElwfEVcdEFIbD1IbD00aDk0aDksZ - Dk0aDk0aDkkYDUYYDUIWDEQWDD8VDD8VDDwUCzwUCzoUCzYSCjUSCjYSCjMRCTMRCTEQCTEQCTAQCS4Q - CS4QCSwPCCwPCCwPCCwPCCkOCCcNBycNBycNByQMByQMByILBiILBiILBiILBiALBh8LBh8LBh0KBhoJ - BRgJBRsJBdbV1P///////////////////////////////////////2xpaBEGAxEGAxEGAxEGAxEGAxEG - AxEGAw8FAw4FAw4FAw4FAw8FAw4FAw4FA7KxsP////////////////////////////////////////// - /////////6WkpAcDAgcDAgcDAgMBAQMBAQMBAQIBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9tSM9pOLtpNLdtRMtpOLtpOLtpOLtpNLdpOLtpNLdpOLtpLK9pPMNpNLdpLK9pOLtpPMNpOLttR - MttRMttSM9tRMtxXOd1bPt5gQ99lSt9mS+FwV+J0W+N3XuWBauaFb+aHcuaJdOiPe+mTgOmXheqaiOqc - iuyikeyjk+2qm+6sne+ypO+zpfC5rPG6rvK/s/LDuPPFu/TKwfbTy/fX0Pje2Pjg2vrm4fvq5vvs6fvu - 6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vs6Prm4fjd1/bUzPTK - wfPFuvG6ru+0p+6un+yklOqciumVgueNeeaHcuWCbOR8ZeJ0W+BsUuBrUN9kSN1bPttRMtpOLs9EJclC - JL0/IrE7IKA1HZYyG4gtGHkoFm0kFGQhEmMhElwfEVcdEFUcD1McD1McD00aDksZDk0aDk0aDkcYDUQW - DEQWDD8VDD8VDD0UCz0UCzoUCzgSCjgSCjUSCjUSCjMRCTMRCTMRCTAQCTAQCTEQCTAQCSwPCCwPCCwP - CCsOCCsOCCcNBycNByUNByUNByUNByQMByQMByALBh8LBiALBiALBh8LBh8LBhsJBRoJBRgJBdbV1P// - /////////////////////////////////////2xpaBEGAxEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FAw4F - Aw4FAw4FAw4FAw4FAwwFA4qJiP////////////////////////////////////////////////X19Sso - JwcDAgcDAgMBAQIBAQMBAQIBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9pPMNtRMtpO - LtpPMNpOLtpOLtpOLtpPMNpOLtpPMNpOLtpPMNtRMtpPMNpNLdpLK9pOLtpOLttRMttRMttUNdxXOdxX - Od1aPNxYOt1aPN1bPt9kSN9mS+BrUOFvVeN4YOR8ZeWBauWDbeaFb+eNeeiRfemWg+qciuufjuyklO2o - mO2omO6uoO+wovC3qvK/s/K/s/LDuPTKwfXPxvXRyffa0/je2Pni3fro5Pvs6Pvu6/vu6/vu6/vu6/vu - 6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vq5vjg2vfa0/XPxvPFuvG9se+0p+2qm+yk - lOufjumWg+eLduWCbOR9ZuN3XuBrUN9mS91eQd1aPNtRMtpNLdVGJslCJL0/IrE7IKU3HpkyG4ouGX4q - F3cnFXAlFGQhEmEhEl4fEVwfEVcdEFMcD1AbD1McD04aDksZDkkYDUcYDUkYDUIWDEQWDEQWDD8VDD0U - CzoUCzoUCzgSCjYSCjMRCTMRCTMRCTMRCTEQCTEQCTAQCS4QCSwPCCwPCCwPCC4QCSwPCCkOCCUNBykO - CCUNByQMByQMByQMByQMByALBiALBh8LBiALBh8LBhsJBR0KBh0KBhsJBdbV1P////////////////// - /////////////////////2xpaBEGAxEGAxEGAxEGAxEGAw8FAw8FAw8FAw8FAw4FAw4FAw4FAw4FAw4F - AwwFAwwFA7GwsP///////////////////////////////////////////////4qIiAkDAgUCAQIBAQIB - AQIBAQIBAQMBAQIBAQIBAQMBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9tRMtpNLdpOLtpOLtpLK9pOLtpP - MNpNLdpNLdpOLtlJKdpOLtpOLtpNLdpOLtpLK9pOLttRMttUNdpPMNtSM9tUNdxVN9tRMttRMt1bPt1a - PN5gQ99kSN5gRN9mS+FuVOJ0W+N4YON5YeR9ZuaHcuaHcueMd+eNeeiSfuugj+yjk+yklO2omO+wou+y - pPC2qfG8sPG9sfPFuvPHvfXPxvfX0Pje2Pjg2vrn4/vs6Pvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu - 6/vu6/vu6/vu6/vu6/vu6/vu6/vs6Pni3fje2PbTy/TJv/LAte+0p+2qm+yjk+qciuiRfeaJdOWCbON5 - YeJyWeBqT95gRNtUNdpOLtlJKdFFJcpDJL4/IrE7IKo4HqA1HZcyG40uGYErF3koFnAlFGkjE2MhEl4f - EVwfEVoeEFcdEFAbD04aDlAbD04aDksZDkkYDUYYDUYYDUEWDEIWDEEWDEEWDD0UCzwUCzgSCjoUCzUS - CjMRCTMRCTMRCTMRCTMRCTMRCTEQCTEQCS4QCSsOCCwPCCsOCCsOCCkOCCkOCCcNByUNByQMByQMByQM - ByQMByALBiILBiALBiALBh0KBhsJBRoJBRsJBRgJBdbV1P////////////////////////////////// - /////2xpaBEGAxEGAxEGAxEGAxEGAw8FAw8FAw8FAxEGAw4FAw4FAw4FAw4FAwwFAwwFAwwFAwwFA+Dg - 3////////////////////////////////////////////8nJyQcDAgUCAQMBAQMBAQMBAQMBAQIBAQMB - AQIBAQMBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9tRMtpNLdpOLtpLK9pOLtpPMNpOLtpOLtpLK9pOLtpO - LtpOLtpOLthHJtlIJ9pLK9pOLttRMtpPMNtUNdtRMttUNdtUNdpPMNxVN91cP95gRN5gRN5iRt5gQ99m - S+BrUOBrUOJyWeN3XuN4YON5YeWBauaHceeMd+eNeemWg+uejOyjk+2omO2ome2qm+6uoPC2qfG6rvLD - uPLDuPTKwfXPxvbUzPjd1/nk3/vs6Pvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vu - 6/vu6/vq5vni3fje2PbVzvTLwvLAtfG6ru6un+yjk+qaiOiRfeaHcuWBauJ1XOFuVN5iRt1cP9tUNdpN - LdhHJs5EJb4/Irg9Iac3Hp40HJszHIsuGYMsGH4qF3UnFXQnFW0kFGgjE2QhEmEhEl4fEVoeEFgdEFMc - D1IbD04aDk0aDkkYDUkYDUQWDEYYDUEWDEEWDD0UC0IWDD0UCzwUCzoUCzwUCzgSCjUSCjUSCjEQCTEQ - CTEQCTEQCTEQCTAQCS4QCSsOCCwPCCkOCCcNBykOCCcNBykOCCUNByQMByQMByILBiILBiALBiALBiAL - BiALBh8LBhsJBRsJBRsJBRoJBdbV1P///////////////////////////////////////2xpaBEGAxEG - AxEGAw8FAxEGAxEGAw8FAw8FAw8FAw8FAw4FAw4FAw4FAwwFAw4FAwwFAwoDAmtpaP////////////// - /////////////////////////////////ysoJwUCAQMBAQMBAQMBAQIBAQIBAQMBAQIBAQIBAQIBAQIB - AQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9tRMtpNLdpLK9pOLttRMtpOLtpOLttSM9pNLdpOLtpNLdlJKdpOLtpOLtpN - LdpNLdpLK9pPMNtRMtxVN9xXOdtUNdxXOdxVN91eQd1bPt1aPN1cP95gQ95gQ95iRuBoTeBoTeFuVOJy - WeN3XuN5YeWBauWBauaHcuiPe+mXhemWg+mWg+ufjuyjk+ymluymlu6uoPC3qvG9sfK/s/LDuPTJv/XR - yffX0Pjg2vrn4/vs6Pvs6Pvs6Pvs6fvu6/vu6/vu6/vu6/vu6/vu6/vu6/vu6/vs6fvq5vrm4fjd1/bU - zPTLwvLDuPC5rO6uoOyklOuejOiPe+aHcuR8ZeJ1XOBrUN9lStxYOttRMtlIJ89EJcxDJMRBI7s9IbM7 - IKM2HZcyG5EwGoYsGHwpFnkoFnUnFWkjE20kFGYhEl8fEV8fEV8fEV4fEVwfEVcdEFcdEFIbD04aDk0a - DkkYDUcYDUYYDUEWDEIWDD0UCzwUCzoUCzoUCzoUCzgSCjMRCTUSCjMRCTMRCTEQCTMRCTAQCS4QCTAQ - CTAQCSsOCCkOCCsOCCcNBycNBycNBycNByQMByILBiILBiILBiALBiALBh8LBh8LBh0KBhsJBRsJBR0K - BhoJBRgJBdbV1P///////////////////////////////////////2xpaBEGAxEGAxEGAw8FAw8FAw8F - Aw8FAw8FAw8FAw8FAw4FAw8FAw4FAw4FAwwFAwwFAwoDAgwFA769vf////////////////////////// - /////////////////4mIiAMBAQMBAQIBAQIBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9lJKdpNLdpOLtpOLtpOLtpPMNpPMNpPMNpOLtlJKdlIJ9pLK9pOLtpPMNlIJ9pLK9pOLtpPMNtS - M9xYOttUNdxXOd1bPt1aPNxXOd1aPN1aPN5iRt1cP95gQ91eQd9lSt9mS+BrUOFuVON3XuN7Y+WDbeWD - beaHceaHcueMd+mTgOiRfemVguqaiOugj+yjk+ymlu6un++zpfC3qvK/s/PHvfXRyffX0Pfa0/jd1/rm - 4fro5Pro5Pvq5vvs6Pvs6fvs6fvu6/vs6fvu6/vu6/vs6Pro5Pnk3/jg2vfX0PTLwvLDuPG6ru+ypOyk - lOqaiOiSfuaHcuR8ZeJyWeBqT95iRtxYOtpPMNZGJspDJMdCJL0/Irg9Ia86H6M2HZszHJYyG48wGoUs - GHkoFnImFXAlFG0kFGYhEmMhEmQhEl4fEVoeEFoeEFgdEFMcD1UcD1IbD1IbD04aDk0aDkkYDUcYDUYY - DUIWDD0UCz0UCzoUCzgSCjgSCjgSCjMRCTYSCjMRCTMRCTAQCTEQCTEQCS4QCSwPCCwPCCwPCCsOCCsO - CCsOCCkOCCcNByUNByUNByILBiILBiQMByALBh8LBh8LBh0KBh0KBhsJBRsJBRoJBRoJBRgJBdbV1P// - /////////////////////////////////////2xpaBEGAxEGAxEGAxEGAxEGAw8FAw8FAw8FAw8FAw8F - Aw4FAw4FAw4FAwwFAw4FAw4FAwwFAwwFA2tpaP////////////////////////////////////////// - /729vQMBAQMBAQIBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9pOLtpNLdpL - K9pOLtpLK9pOLtpLK9pOLtpLK9pNLdpNLdpOLtpOLtpNLdpNLdpOLttRMttSM9tUNdtSM9tUNdxXOdxX - Od1bPt1aPNxYOt1bPt1aPN5gQ99kSN5gRN5gRN9mS+BqT+BsUuN3XuN5YeR9ZuWBauWCbOWBauaHceiP - e+mVgumTgOmWg+qaiOqciuyike6sne6sne+ypO+0p/PFu/bTy/XRyfbUzPfZ0vjd1/jg2vnk3/rm4fro - 5Pro5Pvq5vvs6Pvq5vro5Pvq5vrm4fjg2vjb1fbVzvXPxvPFu/G6ru+wouymluqaiOiRfeaHcuR/aOJy - WeBqT99kSN1aPNpOLtZGJs9EJcVBI70/IrY8Ia05H6I2HZszHJYyG5IwGoouGYgtGHkoFnUnFXImFWsj - E2YhEmMhEmEhEl8fEVoeEFcdEFUcD1IbD1McD1AbD04aDk0aDkcYDUcYDUkYDUYYDUQWDD8VDD8VDD0U - CzwUCzwUCzYSCjMRCTYSCjMRCTEQCTAQCTEQCTAQCS4QCS4QCSwPCCsOCCwPCCwPCCsOCCkOCCcNByUN - ByQMByILBiALBiILBiILBiALBiALBh8LBh8LBhsJBRoJBRoJBRoJBRgJBdbV1P////////////////// - /////////////////////2xpaBEGAxEGAxEGAxEGAw8FAxEGAw8FAw8FAw4FAw8FAw4FAw4FAwwFAwwF - AwwFAwwFAwwFAwwFAwwFA+vq6v///////////////////////////////////////+Df3wMBAQMBAQIB - AQIBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9pNLdpLK9pOLtlJKdpOLtpNLdpO - LtlJKdpOLtpLK9pNLdpNLdtRMttRMtpOLttRMtpPMNxYOtpOLtpPMNxVN9xYOtxXOd1aPN1bPt1aPN1b - Pt5gRN1cP95iRt9kSOBoTeBqT+BqT+BrUOFuVOFwV+N7Y+R/aOWDbeR/aOWDbeeNeeiRfemVguiPe+mV - guqciuufjuyklO2omO2ome+ypPG9sfLDuPTLwvXNxPXRyffX0Pjb1fje2Pjg2vnh3Pnk3/ni3fnk3/nk - 3/nk3/jg2vje2PfX0PbTy/XPxvPFu/G6ru+wouymluqciuiSfuaHcuWCbON3XuBrUN5gQ91bPttUNdlJ - KdNGJsdCJL4/IrQ7IK86H6o4Hpw0HJcyG5cyG4ouGYUsGH4qF3cnFXkoFnQnFW8lFGYhEmQhEl8fEVoe - EFgdEFgdEFUcD1McD1AbD04aDksZDkkYDUYYDUYYDUYYDT8VDEIWDEEWDDoUCzoUCzwUCz0UCzoUCzoU - CzYSCjUSCjMRCTMRCTMRCTEQCS4QCSwPCC4QCSwPCCsOCCsOCCsOCCcNByUNByUNByQMByQMByILBiIL - BiILBiALBiALBh8LBh0KBhsJBR0KBhsJBRoJBRgJBdbV1P////////////////////////////////// - /////2xpaBEGAxEGAxEGAxEGAw8FAxEGAw8FAw8FAw8FAw4FAw4FAw4FAw4FAwwFAwwFAwwFAwoDAgoD - AgoDArGwsP///////////////////////////////////////////wMBAQMBAQMBAQIBAQIBAQIBAQIB - AQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9pLK9pNLdpOLtpLK9lJKdpNLdpNLdpLK9lJKdpLK9lJ - KdpOLttUNdlIJ9pOLttRMttSM9pOLtxYOtxVN9xXOdxXOdxYOtxYOt1aPNxYOt1cP9xXOd1cP91cP99k - SN9kSN9lSuBrUOBrUOFwV+J0W+N5YeN7Y+WBauR/aOeLduiPe+iPe+iSfuiRfemTgOqZh+qaiOuejOyk - lO2ome6sne+zpfG6rvLAtfLDuPTKwfTLwvbUzPfX0Pfa0/je2Pje2Pjg2vje2Pjg2vjg2vjd1/bVzvXP - xvTJv/PFuvC5rO6uoO2omOqciumVguaHcuR9ZuN3XuFuVN9lStxXOdxXOdpLK9ZGJslCJMJAI70/IrM7 - IKo4HqI2HZszHJYyG5IwGoouGYAqF3wpFnUnFXUnFXAlFG0kFG0kFGgjE2YhEl4fEVgdEFgdEFUcD1Ib - D04aDksZDkcYDUYYDUcYDUYYDUIWDEEWDD0UCzwUCzgSCjwUCzoUCzwUCzgSCjYSCjUSCjYSCjgSCjMR - CTMRCTMRCTEQCS4QCSwPCCkOCCsOCCsOCCsOCCkOCCUNByUNByQMByILBiQMByQMByALBiALBh8LBh0K - BhsJBRoJBRsJBRsJBRgJBRgJBdbV1P///////////////////////////////////////2xpaBEGAxEG - AxEGAxEGAw8FAw8FAw8FAw8FAw8FAw4FAw4FAw4FAw4FAw4FAw4FAwwFAwoDAgoDAgwFA3t5eP////// - /////////////////////////////////////0FAQAMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIB - AQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9pOLtpOLtpOLtpNLdlJKdpOLtlJKdpOLtpLK9pOLtpNLdpNLdpOLttSM9pO - LtpOLttSM9tRMttUNdxYOtxXOdxVN9xXOd1aPN1aPN1aPN1cP91bPt5gQ91cP99lSt5iRuBoTeBqT+Fv - VeJ0W+J1XON7Y+WBauaHceaHceeMd+aJdOeMd+mTgOmTgOmTgOmWg+qaiOqciuuejOyikeymlu2qm++w - ovC3qvG9sfLDuPPFu/XNxPXRyfbUzPbVzvfZ0vfZ0vfZ0vfa0/fa0/bVzvXPx/TJv/LBtvG8sO+ypO2o - meufjumWg+aJdOWBauJ1XOBsUuBqT91eQdtSM9pNLdFFJc9EJcVBI70/IrY8IbE7IKg3Hpw0HJQxG5Qx - G40uGYYsGH4qF3cnFXImFW0kFGgjE2YhEmQhEl8fEWEhEmEhEmEhElwfEVcdEFIbD1IbD04aDkcYDUcY - DUcYDUcYDUQWDD0UCz8VDD0UCzoUCzwUCzgSCjUSCjMRCTYSCjMRCTEQCTMRCTEQCTEQCTMRCTMRCTMR - CTMRCSwPCCsOCCkOCCsOCCsOCCUNByUNByUNByQMByQMByILBiALBh8LBh0KBh8LBh0KBhoJBR0KBh0K - BhoJBRgJBdbV1P///////////////////////////////////////2xpaBEGAxEGAxEGAxEGAxEGAw8F - AxEGAxEGAw8FAw4FAw8FAw8FAw4FAw4FAw4FAwwFAwwFAwwFAwwFA0VCQf////////////////////// - /////////////////////2hnZwMBAQIBAQMBAQIBAQIBAQMBAQMBAQIBAQAAAAIBAQIBAQAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9pOLtpLK9pLK9lJKdlJKdlIJ9lJKdlJKdpLK9pOLtpOLtpPMNpOLtpPMNpOLttUNdpOLtxVN9xX - OdtUNdxYOtxYOt1eQd5gRN5iRt1eQd9mS99mS+BoTeBrUOBrUOBqT+FvVeFuVOFvVeFvVeJyWeN3XuN7 - Y+WBauaHcuiPe+aHcuiSfumTgOmTgOmVgumXhemXhemXheqaiOufjuyklOyklO6sne6uoPC2qfG6rvK/ - s/LDuPPHvfXNxPXRyfbTy/bTy/bUzPbUzPbUzPXPxvPHvfLDuPG6ru+0p+2omOufjumWg+eMd+WDbeN3 - XuFuVN9mS91eQdxVN9tRMtlIJ9FFJcpDJMJAI70/IrM7ILE7IKI2HZszHJYyG4ouGYYsGIAqF3ooFnQn - FXImFXAlFGkjE2kjE2YhEmEhEl4fEV4fEVgdEFoeEFgdEFcdEFUcD04aDkkYDUkYDUQWDEEWDEIWDD8V - DD0UCz0UCzoUCzoUCzoUCzgSCjYSCjUSCjMRCTAQCTAQCTAQCS4QCTEQCS4QCS4QCSwPCCwPCC4QCS4Q - CS4QCSsOCCwPCCcNBycNByQMByALBiALBh8LBiALBiALBh0KBh0KBhoJBRoJBRoJBRoJBRoJBdbV1P// - /////////////////////////////////////2xpaBEGAxEGAxEGAxEGAxEGAxEGAw8FAw4FAw4FAw8F - Aw8FAw4FAwwFAwwFAwwFAwwFAwwFAwoDAgoDAgoDAv////////////////////////////////////// - /////3l4eAMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9lJKdpOLtlJ - KdpOLtpLK9pNLdlIJ9hHJthHJtpNLdpOLtpNLdpPMNpPMNpPMNpOLtpPMNpPMNxXOdxXOd5gQ99kSN9l - St9mS+BqT+BrUN9kSN9mS+BrUOFuVOFwV+JyWeJ0W+JyWeN5YeJyWeJ1XOJ1XON5YeR/aOWBaueLduaH - cumTgOmWg+qZh+qaiOqaiOmVgumXhemXheqciuuejOugj+yjk+ymlu6uoO+0p/C3qvG8sPLBtvPFu/TL - wvTLwvXPxvXNxPXNxPXNxPTKwfLDuPG6ru+0p+yjk+yjk+mWg+eMd+WDbeN7Y+FuVN9mS95iRt1bPtpO - LthHJtZGJslCJMVBI7s9IbM7IK86H6c3HqM2HZYyG5EwGosuGYYsGHkoFnUnFXImFW8lFHAlFGsjE2Yh - EmEhEl8fEV4fEVoeEFcdEFcdEFUcD1AbD1IbD1AbD04aDksZDkkYDUQWDEEWDDwUC0QWDD0UCzgSCjYS - CjYSCjUSCjYSCjYSCjUSCjEQCTEQCTAQCS4QCS4QCSwPCCsOCCsOCCkOCCkOCCkOCCsOCCcNBycNBycN - BycNBykOCCQMByILBiILBiILBiALBh8LBhsJBRoJBRoJBRgJBRgJBRgJBdbV1P////////////////// - /////////////////////2xpaBEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FAw8FAw8FAw8FAw4FAw4FAwwF - AwwFAwwFAwwFAwwFAwoDAgoDAurq6v///////////////////////////////////////6SkpAMBAQIB - AQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9pLK9lIJ9lJKdlIJ9VGJthHJtZG - JtpLK9pPMNpOLtpOLtpLK9pNLdpPMNpOLtpNLdtUNdxVN95gRN9kSN9lSt9mS+BoTd9lSuBrUOBoTd9m - S+BrUOFvVeBsUuFwV+N3XuJyWeJ0W+J1XOR/aOJ1XOJ1XOJ0W+R9ZuR9ZuaJdOaJdOeMd+iSfumTgOqZ - h+qZh+mWg+mTgOmVguqciumXheqZh+ugj+yjk+2omO6uoO+ypPC2qfG8sPK/s/PFuvPFuvPFu/PHvfPH - vfPFuvLDuPK/s++zpe6sneugj+iSfueLduWBauN5YeFwV+BqT95iRt1bPttUNdlJKdNGJsxDJMJAI74/ - IrQ7ILM7IKw5H6I2HZkyG5YyG48wGoouGYgtGHkoFncnFXAlFG0kFHAlFGsjE2YhEl8fEVwfEVwfEVoe - EFUcD1cdEFIbD0sZDk0aDkkYDUkYDUQWDEkYDUsZDkkYDT8VDD0UCz0UCzgSCjgSCjYSCjYSCjUSCjYS - CjUSCjEQCTAQCTEQCTAQCS4QCS4QCSsOCCwPCCsOCCsOCCcNByQMBycNBycNByQMByQMByILBiILBiIL - BiALBiILBiUNByUNByALBh0KBhsJBRoJBRgJBRgJBdbV1P////////////////////////////////// - /////2xpaBEGAxEGAxEGAxEGAxEGAxEGAw8FAxEGAxEGAw4FAw4FAw4FAw4FAwwFAwwFAwwFAwwFAwwF - AwwFAwwFA9XU1P///////////////////////////////////////6SkpAMBAQIBAQMBAQIBAQIBAQIB - AQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9pLK9pLK9pOLtlJKdhHJtlIJ9pLK9pOLtpOLtpNLdpN - LdpOLtpNLdpNLdpOLtpPMN1aPN1eQd5iRt5iRt9mS99mS95iRt5iRt9mS+BrUOBqT+BqT+BsUuFvVeFu - VOFwV+JyWeJ0W+J1XON4YOR9ZuN7Y+N4YON5YeR/aOWDbeaHcueLduiRfemWg+uejOqZh+mXhemTgOiP - e+mVgumVgumWg+mXheqaiOyjk+yklO2ome+wou+zpfC5rPK/s/K/s/LAtfLDuPLBtvLDuPG8sPG6ru6u - n+yjk+mWg+iPe+aHceR9ZuJ0W+BsUt5iRtxYOtxXOdpOLtZGJsxDJMVBI74/Irg9IbE7IK05H6U3Hp40 - HJszHJIwGosuGYsuGYAqF3cnFXImFW8lFGsjE2sjE2gjE2QhEmEhEloeEFoeEFoeEFcdEFUcD1AbD1Ab - D00aDkcYDUkYDUYYDUYYDUQWDEIWDEIWDEQWDEEWDDwUCzoUCzgSCjUSCjMRCTMRCTMRCTAQCTAQCTAQ - CS4QCS4QCSwPCCwPCCwPCCsOCCkOCCkOCCQMByUNBycNByQMByQMByQMByALBiILBh8LBh0KBiALBh8L - Bh8LBh8LBiALBh8LBh0KBh0KBtbV1P///////////////////////////////////////2xpaBEGAxEG - AxEGAxEGAw8FAxEGAw8FAw8FAw8FAw4FAw4FAw4FAw4FAwwFAwwFAwwFAwwFAwoDAgoDAgoDAtXU1P// - /////////////////////////////////////6SkpAIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIB - AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9pOLtlJKdlIJ9lJKdlIJ9ZGJtpNLdpLK9pLK9pLK9pLK9pOLtpLK9lJKdpO - Lt1aPN1eQd5gRN9lSt9kSN5gRN5iRt5iRt9kSOBqT99kSOBoTd9lSuFuVOBrUOFvVeFuVOJyWeJ0W+J0 - W+J1XON3XuN4YOR9ZuN5YeR9ZuaFb+aHcuaHceaHcuiPe+iSfumVguiSfueNeeeNeeeNeeeMd+iRfemT - gOmWg+uejOufjuyjk+ymlu6un++zpfC3qvG8sPG6rvG8sPG9sfG6rvC3qu+0p+yjk+qciueNeeaHcuR/ - aOJyWeBrUOBrUN1bPtpPMNpLK9ZGJs5EJcVBI8A/Ir0/Irg9IbE7IKg3HqM2HaI2HZcyG5EwGosuGYMs - GHkoFncnFXImFWsjE2kjE2gjE2EhEl4fEVwfEVcdEFcdEFcdEFMcD1IbD1IbD00aDkkYDUYYDUYYDUYY - DUIWDEQWDEEWDD8VDD0UCz0UC0EWDEEWDEEWDDgSCjMRCTEQCTEQCTEQCTAQCSwPCCwPCC4QCSwPCCkO - CCkOCCsOCCcNBycNByUNByUNBycNByQMByILBiQMByILBiALBh8LBh0KBh8LBhsJBRsJBRsJBRsJBRgJ - BRgJBRgJBdbV1P///////////////////////////////////////2xpaBEGAxEGAxEGAw8FAw8FAxEG - Aw8FAw4FAw8FAw4FAw4FAw4FAwwFAwwFAwwFAwwFAwwFAwwFAwoDAgoDAtXU1P////////////////// - /////////////////////6SkpAIBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9pLK9pNLdlJKdlIJ9lJKdlJKdpOLtpOLtpLK9lJKdlJKdpOLtpOLtpPMNtSM9xYOt5gQ95gRN5g - RN5iRt9kSN5gRN5gRN5iRuBqT99mS+BoTeBrUOBrUOBrUOBsUuJ0W+FuVOFwV+JyWeJ0W+FvVeN4YON5 - YeR8ZeN5YeR/aOR8ZeWCbOaHcuaHcueNeeeNeeeNeeaJdOaHcueLduaJdOeMd+eMd+iRfemVgumWg+qa - iOyklOymlu6uoO+ypO+zpe+0p/C3qvC2qe+0p++wou6uoOuejOmVguaHceR8ZeJ1XOBqT95iRt1bPtpP - MNlJKdFFJc9EJcdCJMJAI7s9Ibg9IbM7IKg3HqI2HZw0HJw0HJQxG40uGYouGX4qF3ooFncnFW8lFGsj - E2gjE2YhEmEhEl8fEV4fEVgdEFcdEFUcD1UcD1UcD04aDkkYDUYYDUcYDUcYDUYYDUEWDEEWDD8VDD0U - CzwUCzgSCjgSCjgSCjwUCzoUCzoUCzgSCjMRCTEQCTEQCTEQCSwPCCsOCCsOCCwPCCkOCCkOCCUNByQM - ByQMByQMByUNByQMByILBiILBiILBiALBiALBh0KBh0KBhsJBRsJBRoJBRgJBRYHBBgJBRgJBdbV1P// - /////////////////////////////////////2xpaBEGAxEGAxEGAxEGAxEGAw8FAw8FAw8FAw8FAw8F - Aw4FAw4FAw4FAwwFAwwFAwwFAwwFAwwFAwwFAwwFA9XU1P////////////////////////////////// - /////6WkpAMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9hHJtpNLdhH - JthHJtpLK9lJKdpLK9pNLdlJKdpOLtpLK9lJKdpPMNxVN91bPt5gQ95gRN5gRN9kSN9kSN5gQ95iRt9k - SN9mS99kSOBoTeFuVOBrUOBqT+BrUOFuVOFvVeFuVOFvVeFuVOJyWeN4YOR9ZuWBauR/aON7Y+N5YeN5 - YeR8ZeaHcuaHceaHcueLduaHcuaHceWDbeaHcuWDbeWDbeaFb+eLduiPe+iPe+mVguqaiOyike2omO6s - ne6un++ypO+ypO+ypO+wou2ome2omeqaiOeLduaFb+N5YeBrUN9kSN1bPttRMtpNLdhHJs5EJclCJMJA - I70/Irk9IbQ7IKg3Hqg3Hpw0HJkyG5IwGosuGYgtGIAqF3wpFncnFXAlFHImFWsjE2sjE2QhEmEhEl4f - EV4fEVgdEFMcD1UcD1UcD04aDlAbD0kYDUkYDUQWDEQWDEEWDEEWDD8VDDwUCz0UCzgSCjgSCjYSCjUS - CjgSCjYSCjUSCjYSCjYSCjYSCjMRCTMRCTEQCTAQCS4QCSsOCCsOCCkOCCkOCCUNByQMByQMByILBiIL - BiILBiILBh8LBh8LBh8LBh0KBhsJBRsJBRsJBRoJBRoJBRoJBRgJBRgJBdbV1P////////////////// - /////////////////////21qaRQHBBMHBBEGAxEGAxEGAxEGAxEGAw8FAw8FAw4FAw4FAw4FAw4FAwwF - AwwFAwwFAwoDAgoDAgwFAwoDAtXU1P///////////////////////////////////////6SkpAMBAQMB - AQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9lIJ9lIJ9pOLtlIJ9hHJtlIJ9pO - LtpNLdpOLtpLK9pLK9pNLdtSM91bPt1aPN1eQd5gRN1eQd1bPt5gQ99lSt9kSN5gQ95iRt9kSOBrUN9m - S+BsUuBrUOBrUOFuVOBsUuBsUuBrUOFwV+N3XueLdueNeeeMd+aJdOWDbeN4YON4YON5YeWBauaFb+WC - bOaHceaFb+WDbeWBauWBauR9ZuR/aOR/aOaFb+aHcuaHcueMd+mTgOqZh+yike2omO2ome6uoO6sne2q - m+2qm+yklOyklOmVguaFb+N7Y+FuVN5gQ91eQdxVN9pPMNhHJtNGJsxDJMJAI7s9IbQ7IK86H686H6c3 - HqA1HZszHJEwGo8wGoouGX4qF3koFnkoFnUnFW8lFGsjE2YhEmYhEmMhEl8fEV4fEVcdEFcdEFMcD1cd - EFIbD04aDk4aDkkYDUYYDUYYDUcYDUQWDEEWDDoUCz8VDDwUCzgSCjgSCjUSCjUSCjUSCjUSCjMRCTMR - CTMRCTEQCTMRCTYSCjUSCjEQCSwPCCsOCCsOCCcNByUNByQMByQMByQMByILBiILBiALBiILBiALBh8L - Bh0KBhsJBRoJBRoJBRsJBRoJBRoJBRoJBRgJBRYHBNbV1P////////////////////////////////// - /////2xpaBEGAxEGAxEGAxEGAxEGAxQHBBQHBBEGAw8FAw4FAw8FAw8FAw4FAwwFAwwFAwwFAwwFAwwF - AwoDAgoDAv///////////////////////////////////////////4iHhwIBAQIBAQMBAQMBAQMBAQIB - AQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9lIJ9VGJthHJtVGJtZGJtlJKdpNLdpOLtlIJ9pNLdpL - K9pOLttUNdxYOtxYOtxYOt1aPN1bPt1eQd9kSN9kSN5gROBrUOBrUOBoTeBrUOBoTeFuVOBsUt9mS+Bq - T+BrUOBsUuJyWeN7Y+eMd+mVguqaiOiSfuiRfeeMd+R9ZuR8ZeJ0W+N5YeN4YOR/aOR/aOR9ZuN5YeR8 - ZeN5YeN3XuN3XuN7Y+R/aOWBauWDbeaJdOeMd+mWg+qciuyjk+ymlu2omO2qm+ymluyjk+ufjuuejOiP - e+R9ZuJyWd9mS91aPNxYOttRMtZGJtFFJcxDJMdCJL0/Irg9IbE7IK86H6g3Hp40HJszHJIwGpIwGogt - GIAqF34qF3koFnkoFnQnFW8lFGkjE2YhEmMhEmEhEmMhElwfEVcdEFcdEFMcD1IbD04aDksZDk0aDkcY - DUIWDEQWDEEWDEIWDDwUCz8VDDwUCzoUCzgSCjYSCjMRCTgSCjMRCTMRCTMRCTMRCTEQCS4QCS4QCS4Q - CTAQCS4QCTAQCTAQCS4QCSsOCCcNByUNByUNByQMByILBiILBiALBiILBiALBiALBh0KBhsJBRoJBRsJ - BRoJBRoJBRsJBRsJBRgJBRgJBdbV1P///////////////////////////////////////2xpaBEGAxEG - AxEGAxEGAw8FAxEGAxEGAw8FAxEGAxEGAxEGAxEGAxEGAw8FAw4FAwwFAwwFAwwFAwoDAgoDAv////// - /////////////////////////////////////2hnZwIBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIB - AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9lJKdhHJtZGJtZGJtpLK9lIJ9pOLtpOLtpOLtlJKdpNLdtUNdxYOtxVN91a - PNxXOd1aPNxYOt5gQ95iRt9kSOBrUOBqT99lSuBrUOBrUOFuVOBsUuBrUOBqT+FuVOFwV+J0W+N5YeaH - cuqZh+2omO2omOqaiOiSfueLduR/aOJ0W+J1XOFwV+JyWeN3XuN4YON7Y+N5YeN5YeJ1XOJ1XOJ0W+N3 - XuN7Y+R8ZeR8ZeWDbeaHcuiRfeqZh+ugj+yikeyklOyklOyklOugj+mXhemXheaHceJ0W+BqT95gQ9tS - M9pOLtpNLc9EJcxDJMpDJMJAI7k9IbQ7IK86H6g3Hp40HJszHJYyG5EwGpIwGoUsGIAqF3koFnkoFnIm - FW8lFG8lFGsjE2QhEl8fEV4fEV8fEVoeEFoeEFgdEFMcD1IbD04aDksZDk0aDkYYDUYYDUQWDD8VDD8V - DEEWDDwUCzwUCzgSCjYSCjUSCjUSCjUSCjMRCTMRCTEQCTAQCTAQCS4QCSsOCCwPCCsOCCsOCCsOCCkO - CCsOCDAQCS4QCSsOCCkOCCcNByUNByILBiILBiALBh8LBh8LBh0KBhsJBRoJBRoJBRoJBRsJBRsJBRoJ - BRYHBBgJBdbV1P///////////////////////////////////////2xpaBEGAxEGAxEGAxEGAw8FAw8F - Aw4FAw8FAw8FAw8FAw4FAw8FAw4FAw8FAxEGAxEGAxEGAw8FAwwFA2tpaP////////////////////// - /////////////////////1ZVVQIBAQMBAQMBAQIBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9lIJ9lIJ9ZGJthHJtpLK9lJKdpNLdlIJ9hHJtpLK9pOLtxXOdxXOdxYOt1aPN1cP9xXOd1cP95g - Q95gQ+BrUOBoTd9kSN9kSN9lSuBqT+BrUOBqT+BrUOFuVOFvVeJ0W+R9ZuaHcumWg+2omPG6rvC3quue - jOiRfeiPe+WCbON3XuN3XuBrUOBrUOFvVeFwV+J0W+N7Y+JyWeFwV+BsUuFuVOFvVeJ0W+JyWeN3XuN5 - YeaFb+eNeeiSfuqaiOufjuugj+yjk+yjk+qaiOmTgOiPe+WDbeBsUt5iRt1bPtpPMNZGJtNGJsxDJMVB - I74/Irg9Ibg9Ia05H6g3HqM2HZ40HJszHJEwGoouGYYsGIAqF3koFncnFXQnFW0kFG0kFG8lFGgjE2Mh - El8fEV8fEVwfEVgdEFgdEFMcD1McD1McD1AbD00aDkkYDUQWDEIWDEEWDEEWDD0UCz8VDDwUCzoUCzgS - CjUSCjYSCjMRCTUSCjYSCjMRCTEQCTAQCS4QCS4QCS4QCS4QCSwPCCwPCCsOCCkOCCkOCCcNBycNBykO - CCkOCCsOCCsOCCUNByQMByILBiALBiALBh8LBh0KBhsJBRsJBRoJBRsJBRoJBRoJBRYHBBgJBdbV1P// - /////////////////////////////////////2xpaBEGAxEGAxEGAw8FAw8FAxEGAw8FAw8FAw4FAw4F - AwwFAwwFAwwFAwwFAwwFAwwFAwwFAwwFAwwFA5iXl/////////////////////////////////////// - /////wIBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9lIJ9VGJthH - JtpLK9pLK9pOLtpLK9pNLdpOLtpLK9tUNd1bPtxXOdxXOd1bPtxXOdxYOt1bPt5iRt5gRN9lSt9kSN9m - S95iRt5gQ95iRuBrUOBrUOBoTeBrUOFwV+N5YeaHcuiRfeqciu+wovC2qe6uoOufjuiSfuaHcuR8ZeJ1 - XOFuVOBrUOBrUOBrUOFuVOFuVOFwV+FwV+BsUuBrUN9mS99mS+BrUOBrUOFwV+N3XuR8ZeaFb+eMd+mW - g+qciuufjuufjuufjumXheeMd+eMd+R/aOBoTd1aPNxVN9lIJ9NGJsxDJMVBI70/Ir0/IrM7ILM7IKI2 - HZszHJw0HJszHJEwGo8wGogtGIAqF3ooFnkoFncnFXImFW8lFG0kFGsjE2YhEmMhElwfEVgdEFoeEFcd - EFcdEFUcD1IbD1McD04aDk0aDkcYDUQWDEIWDEQWDEEWDEEWDDwUCzwUCzgSCjgSCjoUCzUSCjUSCjMR - CTMRCTMRCTEQCS4QCTAQCTAQCSwPCCwPCCkOCCkOCCkOCCUNBycNByUNByQMByUNByQMByUNBycNBycN - BycNByQMByILBiILBiALBhsJBRoJBRsJBRoJBRoJBRgJBRYHBBYHBBYHBNXV1P////////////////// - /////////////////////2xpaBEGAxEGAxEGAxEGAw8FAxEGAw8FAw4FAw4FAw4FAw4FAwwFAwwFAwwF - AwwFAwwFAwoDAgoDAgoDAsnJyf///////////////////////////////////////+Df3wUCAQMBAQIB - AQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9pLK9hHJtZGJtlJKdlJKdpLK9lJ - KdhHJtlJKdpOLtxVN9xVN9xVN9xVN9tUNdxXOd1bPt5gQ95gRN5gRN1eQd1eQd5gQ95gQ95gQ95iRt9l - St9mS+BqT+BrUOFuVOWBaueLduiSfuufjuymlu2omeyikemWg+eNeeaHceFwV+FvVeFuVOFvVd9lSt9l - SuBoTd9mS+BqT+BqT+BqT+BrUN9kSN5iRuBqT+BoTeBrUOFuVOJ0W+R/aOaHcumTgOmTgOqciuqZh+qZ - h+mVguaJdOWDbeN5Yd5gRNtRMtpNLdVGJs9EJcdCJL0/Irs9IbQ7ILE7IKo4HqU3HqA1HZszHI8wGoou - GYMsGIErF3koFnooFncnFXImFW8lFG0kFGkjE2gjE2YhEl8fEV8fEVoeEFUcD1cdEFcdEFIbD1AbD1Ab - D1AbD04aDkcYDUcYDUYYDT8VDEEWDD0UCzgSCjgSCjgSCjwUCzYSCjUSCjMRCTEQCTMRCTMRCS4QCTAQ - CSwPCCwPCCsOCCsOCCkOCCkOCCcNBykOCCcNByUNByUNByUNByQMByILBiILBiILBiALBiALBiUNByUN - ByALBhsJBRsJBRsJBRsJBRsJBRgJBRYHBBQHBBQHBNXV1P////////////////////////////////// - /////2xpaBEGAxEGAw8FAw8FAw4FAw8FAw8FAw4FAw8FAw4FAw4FAwwFAwwFAwwFAwwFAwwFAwoDAgoD - AiwoJ////////////////////////////////////////////769vQoDAgcDAgMBAQMBAQMBAQMBAQMB - AQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9lJKdpNLdlIJ9pOLtpLK9lJKdpLK9hHJtpOLttRMtxV - N9tRMtxYOtxXOdxYOt1aPN1aPN1eQd5iRt5iRt1bPt5gQ95gQ91eQd1cP91eQd9kSN9kSN9mS+BoTeFu - VOR8ZeeLduiSfumWg+qaiOmXheiPe+aFb+WBauN3XuBrUOFvVeFuVOJ1XOBqT95iRt5gRN5iRt9lSt5i - Rt9mS99lSt5gQ95iRt1eQd5gRN5iRt9mS+FvVeN4YOR/aOeLduiRfemXhemXheqZh+iSfuaHceR8ZeN3 - Xt1eQdpLK9VGJs9EJcJAI70/Irk9IbM7IK05H6o4HqI2HaM2HZcyG5YyG48wGoMsGIUsGIAqF3cnFXko - FnAlFG8lFG0kFGsjE2YhEmMhEl8fEV8fEV8fEVgdEFUcD1UcD1McD1McD1AbD00aDkkYDUsZDkcYDUQW - DEEWDEEWDD0UCz0UCzoUCzYSCjUSCjYSCjMRCTMRCTMRCTMRCTMRCS4QCS4QCS4QCSwPCC4QCSwPCCsO - CCkOCCkOCCcNBykOCCcNBycNByUNByUNByILBiALBiALBiALBiALBh8LBh8LBiALBiALBiALBiALBh8L - Bh0KBhsJBRoJBRgJBRYHBBQHBNXV1P///////////////////////////////////////2xpaBEGAxEG - Aw8FAw8FAw8FAw8FAw8FAw4FAw8FAw8FAw4FAwwFAwwFAwwFAwwFAwwFAwoDAgoDAoqIiP////////// - /////////////////////////////////4mIhwUCAQMBAQUCAQUCAQMBAQcDAgcDAgUCAQIBAQIBAQIB - AQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9VGJtZGJtpLK9pOLtpOLtpNLdpNLdhHJtlIJ9pOLtxYOtxVN9tUNdxVN91b - Pt1bPt1eQd1cP91bPt5gQ91bPt5gQ95gRN1bPt1cP91eQd5gRN9kSOBoTd9kSN9mS+N3XuWCbOaJdOiP - e+eMd+aFb+N4YOFvVeBsUuBrUN9lSuBrUOBrUOBrUN9lSt1eQd1eQd1eQd1bPt1eQd5gRN1cP9xYOt1a - PN1bPt1bPt1eQd9lSuBqT+JyWeR/aOaHcueLduiSfumTgOmVgumTgOWBauJ1XOFwV9xXOdlIJ8xDJMVB - I7k9Ibg9Ia05H6o4Hqc3HqM2HZ40HJszHJEwGosuGYMsGIAqF4AqF3koFnooFncnFXImFW0kFG0kFGQh - EmEhEl8fEVwfEV4fEVcdEFcdEFMcD1AbD04aDk4aDk4aDksZDksZDkkYDUQWDEYYDUIWDEEWDEEWDD8V - DDgSCjYSCjYSCjUSCjUSCjMRCTMRCTMRCTMRCTAQCTAQCS4QCSwPCCwPCCsOCCsOCCsOCCkOCCcNBycN - ByUNByUNByQMByILBiILBiILBiILBiALBiALBh0KBh8LBh0KBh0KBhsJBR0KBh8LBh8LBhsJBRsJBRoJ - BRgJBRQHBNXV1P///////////////////////////////////////2xpaA8FAw8FAxEGAw8FAw8FAw8F - Aw4FAwwFAw4FAw4FAwwFAwwFAwwFAwwFAwoDAgoDAgoDAgkDAurq6v////////////////////////// - /////////////////ygmJgMBAQIBAQMBAQMBAQMBAQMBAQMBAQMBAQUCAQUCAQUCAQMBAQMBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9hHJtlIJ9lJKdpLK9lJKdpLK9lIJ9pNLdpLK9pPMNxVN9xXOdxXOdxYOtxYOt5gQ91eQd5gQ95g - Q91eQd5gQ91eQd1eQd1eQd1cP91aPN1cP95gRN9kSN9lSuBqT+BsUuJ1XOR9ZuN7Y+R8ZeN4YOBsUuFv - VeBrUOBqT+BqT+BrUN9mS99mS99kSN1aPN1aPN1bPtxYOt1eQd1bPtxVN9xVN9tSM9tRMttUNdtUNd1e - Qd9lSuBsUuN3XuWDbeaHcuiPe+iRfeiSfueMd+R8ZeFvVeBrUNpNLdFFJcRBI8A/Irk9Ia86H6o4HqA1 - HZ40HJkyG5IwGo8wGo8wGoUsGHooFn4qF3ooFnQnFXcnFXUnFW0kFGkjE2gjE2MhEmEhEl8fEVoeEFgd - EFgdEFUcD1AbD04aDlIbD04aDk0aDk0aDkkYDUcYDUEWDEIWDD8VDD0UC0EWDD0UCzYSCjYSCjMRCTYS - CjMRCTMRCTMRCTEQCTEQCTMRCTAQCSwPCCwPCCwPCCwPCCsOCCsOCCkOCCcNBycNByUNByQMByQMByIL - BiILBiQMByILBiALBiALBh0KBh8LBh0KBh0KBhsJBRsJBRoJBRoJBRgJBRsJBRoJBR8LBhoJBdbV1P// - /////////////////////////////////////2xpaBEGAxEGAxEGAw8FAw8FAw8FAw4FAw4FAw4FAw4F - Aw4FAwwFAwwFAwwFAwoDAgoDAgoDApiXlv///////////////////////////////////////////9TU - 1AMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9ZGJtZGJtpN - LdpNLdpNLdlIJ9lJKdhHJtpNLdtRMtxXOdtRMtxXOdxXOdxVN95gQ91bPt1eQd1bPt1cP91cP91bPt1b - Pt1cP95gRN1bPt1bPt5gQ95gRN9kSN9mS99mS+BrUOFuVOFwV+FwV+JyWeFvVeBrUN9kSN9kSOBoTd5i - Rt5iRt9kSN5gRNxYOt1aPNxXOdxVN9tRMttSM9tSM9pOLtpOLtlIJ9pNLdpOLtxVN91cP99mS+JyWeR8 - ZeaHceeLdueNeeiPe+eLduN3Xt9mS95iRtpNLcVBI70/Irg9Ia05H6g3HqI2HZw0HJcyG5IwGpEwGoou - GYouGYMsGHooFnooFnkoFnooFnQnFXImFWsjE2YhEmYhEl8fEVwfEVwfEVcdEFcdEFUcD1UcD1AbD1Ib - D1IbD04aDkcYDUcYDUYYDUYYDUEWDEEWDEEWDD8VDD0UCz0UCzwUCzYSCjYSCjUSCjUSCjMRCTEQCTEQ - CTEQCTAQCS4QCSwPCCwPCCwPCCsOCCkOCCcNBycNBycNByUNByUNByQMByQMByQMByILBiILBiALBiAL - Bh8LBh8LBh0KBhsJBRsJBRoJBRoJBRgJBRoJBRgJBRgJBRYHBBgJBRgJBdbV1P////////////////// - /////////////////////2xpaBEGAw8FAw8FAw8FAw8FAw4FAw4FAw4FAwwFAwwFAwwFAwwFAwwFAwwF - AwoDAgoDAllXVvX19f///////////////////////////////////////////4iHhwUCAQMBAQIBAQIB - AQIBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9ZGJtlIJ9pOLtpNLdlJKdhHJtlI - J9lJKdlIJ9tRMtxXOdxVN9xYOttUNd1eQd1aPN1eQd1cP91bPt1bPt1bPt1aPN1cP9xYOt1bPt1bPt1b - Pt1cP91bPt5gQ91eQd5gROBoTeBrUOBrUOFuVOFvVeBrUOBqT99mS95gQ95gRN5gRN5iRt9kSN5gQ9tS - M9tUNdtRMtpOLtpOLttSM9pNLdlIJ9lIJ9hHJthHJtZGJttRMttRMt1aPN9mS+JyWeWBauaJdOaJdOaH - cuaHceBsUt5gRN1eQdZGJrs9Iaw5H6o4Hqg3HqA1HZszHJcyG5IwGo8wGogtGIAqF4ErF4AqF3koFnko - FnQnFXQnFW0kFGkjE2sjE2kjE2MhElwfEVwfEVwfEVcdEFcdEFcdEFAbD1IbD04aDk4aDkkYDU0aDkYY - DUQWDD8VDEEWDD8VDD8VDDoUCzoUCzYSCjwUCzgSCjUSCjYSCjYSCjMRCTEQCTEQCS4QCS4QCSwPCCwP - CCsOCCwPCCsOCCsOCCcNByUNByUNByQMBycNByQMByQMByILBiILBiALBh8LBiALBh0KBh8LBhsJBRsJ - BRsJBRsJBRsJBRoJBRoJBRYHBBgJBRgJBRYHBBQHBNXV1P////////////////////////////////// - /////2xpaA8FAw4FAxEGAw8FAw8FAw4FAw4FAw4FAwwFAw4FAwwFAwwFAwwFAwwFAwwFAywoJ+Df3/// - //////////////////////////////////////////X19SgmJgMBAQIBAQIBAQIBAQMBAQIBAQIBAQIB - AQIBAQAAAAAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9lIJ9VGJtlIJ9lJKdZGJtpOLtVGJthHJtlJKdtRMttS - M9xYOtxVN9xXOdxXOd1bPtxYOtxYOtxXOdxYOtxXOdtUNdxVN9xVN91cP91bPt1cP91eQd1aPN5gQ95i - Rt1cP95gRN9mS+BqT+BoTeBqT99lSt5iRt5gQ95iRt5iRt1eQd1eQd1eQd1cP9pPMNpOLtpOLtpLK9pL - K9pNLdlIJ9ZGJtNGJtVGJtNGJtVGJtNGJtpNLdtUNd5gROFuVON7Y+aFb+aHcuaHceR/aN9mS9tUNdpP - MMlCJLM7IKg3HqI2HaA1HZcyG5YyG5EwGpIwGoouGYUsGIUsGH4qF3ooFnkoFnImFXQnFW0kFGsjE2Yh - EmMhEmMhEl8fEVgdEFoeEFgdEFgdEFcdEFUcD1IbD1IbD0sZDk0aDksZDkkYDUcYDUQWDEQWDD8VDD0U - Cz8VDDgSCjgSCjoUCzYSCjgSCjYSCjYSCjMRCTAQCTEQCS4QCS4QCSwPCCwPCCwPCCsOCCsOCCkOCCkO - CCcNByUNByQMByQMBycNByQMByILBiALBiILBiILBiALBiALBh8LBh0KBh0KBhsJBR0KBhsJBRsJBRoJ - BRoJBRYHBBQHBBQHBBYHBBQHBNXV1P///////////////////////////////////////2xpaA8FAw8F - Aw8FAw8FAw8FAw4FAw4FAw4FAwwFAw4FAwwFAwwFAwwFAwwFA0VBQODf3/////////////////////// - /////////////////////////6SkpAMBAQMBAQMBAQIBAQMBAQIBAQIBAQIBAQIBAQAAAAIBAQIBAQAA - AAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9lJKdhHJtZGJtpOLtlIJ9pLK9pLK9pLK9hHJttUNdtRMtxXOdtUNdtSM91c - P91aPNxYOtxVN91aPN1aPNtSM91aPNxVN91aPN1aPNxYOt1aPN1aPNxXOd1bPt1eQd5gQ95iRt5gRN9m - S95iRt9lSt5gQ91eQd1eQd1bPt1cP91eQd1cP91cP9tSM9lJKdpPMNlIJ9pLK89EJdVGJthHJtVGJs9E - JdNGJsxDJMpDJM9EJdVGJtpNLdxYOuBrUON3XuWCbOaHceWCbON5Yd5gRNpNLdlJKcRBI6w5H6M2HaA1 - HZszHJYyG40uGYsuGYsuGYMsGIErF4ErF3ooFncnFXQnFXAlFGsjE2sjE2sjE2EhEmMhEl8fEV4fEV8f - EVoeEFgdEFcdEFcdEFIbD1McD04aDk0aDksZDkcYDUYYDUQWDEYYDT8VDDwUCzoUCzwUCzgSCjoUCzoU - CzYSCjUSCjMRCTMRCTMRCTMRCTAQCS4QCS4QCS4QCSsOCCsOCCsOCCsOCCwPCCkOCCcNByUNByUNByUN - ByQMByQMByILBiILBiILBiALBiALBiALBh8LBh0KBh0KBh0KBhsJBRoJBRgJBRgJBRgJBRQHBBQHBBQH - BBQHBBQHBNXV1P///////////////////////////////////////21qaREGAxEGAw8FAw4FAw8FAw4F - Aw4FAw4FAwwFAwwFAwwFAwwFAwwFA4qIiPX19f////////////////////////////////////////// - //////X19SgmJgMBAQMBAQMBAQIBAQIBAQMBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAIBAQAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9ZGJtlIJ9lIJ9lJKdlJKdpNLdlJKdlJKdhHJttRMttUNdtSM9tUNdtUNd1aPN1aPNxXOdxVN9xY - OttRMtxVN91bPtxXOd1aPNxYOtxXOdxYOtxXOdxVN9xYOt1eQd1eQd5gQ95iRt9kSN5gQ95iRt1cP91a - PN1bPt1cP91aPNxXOdxYOtxVN9pOLtlIJ9lIJ9NGJtZGJtVGJtZGJtFFJcxDJMVBI8xDJMVBI8pDJM5E - Jc5EJdlIJ9pOLt5iRuFwV+R8ZeWBauR/aOJyWdxYOtlJKdNGJr0/IqI2HZw0HJcyG5QxG48wGosuGYgt - GIYsGIAqF3wpFnooFnUnFXcnFXImFXQnFXAlFGgjE2QhEl4fEWEhEmEhElwfEVcdEFUcD1UcD1McD1Mc - D1AbD04aDk0aDkkYDU4aDkkYDUIWDEIWDEQWDDwUCzwUCzoUCzwUCzgSCjYSCjgSCjMRCTMRCTMRCTUS - CjUSCjMRCTEQCTEQCS4QCS4QCSwPCC4QCSsOCCsOCCkOCCcNByUNBycNBycNByUNByQMByQMByILBiAL - BiILBiALBiALBh8LBh0KBh0KBh0KBh0KBhsJBRoJBRgJBRgJBRYHBBQHBBYHBBYHBBYHBBQHBNXV1P// - /////////////////////////////////////2xpaBEGAxQHBBEGAw8FAw8FAw8FAw4FAw4FAw4FAw4F - Ay4qKIqJiODg3////////////////////////////////////////////////////////5eWlgIBAQIB - AQIBAQIBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9lIJ9NGJtpN - LdpNLdlJKdlJKdhHJthHJtlIJ9tSM9tSM9xVN9xVN9tRMtxVN91eQd1aPNxVN9xVN9xVN9tSM9xVN91b - PttUNdxXOdxVN9xXOdxVN9xVN9xXOdxYOt1aPN1bPt1aPN1bPt1bPt1cP91eQd1bPtxXOdxYOttUNdpO - LttRMttRMtpLK9NGJtFFJdFFJc9EJcxDJMpDJNNGJspDJMJAI8A/Ir0/IsRBI8VBI8VBI85EJdpNLd1a - POFuVON3XuR9ZuN5YeBsUtpPMMxDJMdCJLs9IZszHJYyG5EwGo8wGosuGYgtGIErF34qF4AqF3koFncn - FXcnFXImFW0kFG8lFGsjE2EhEmEhElwfEV4fEVoeEFoeEFcdEFMcD1UcD1McD1AbD00aDk0aDk4aDkkY - DUkYDUcYDUIWDEQWDD8VDDoUCzoUCzoUCzoUCzYSCjYSCjMRCTMRCTEQCTMRCTMRCTMRCTAQCTEQCTEQ - CS4QCSwPCCsOCCwPCCkOCCkOCCkOCCcNByUNByUNByUNByQMByQMByILBiILBiALBiALBiALBiALBh8L - BhsJBRsJBRsJBRsJBRsJBRoJBRgJBRgJBRgJBRYHBBQHBBQHBBYHBBYHBNXV1P////////////////// - /////////////////////769vaalpKalpKalpKalpKalpKalpKalpKalpMrJyeDg3/////////////// - /////////////////////////////////////////////////+Df3wMBAQMBAQIBAQIBAQIBAQIBAQIB - AQIBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9lJKdVGJthHJtpOLtpOLtpLK9NG - JtpLK9ZGJtpOLttSM9tUNdtUNdtUNd1aPN1aPN1bPt1bPtxXOdxVN9tSM9tRMttUNdtUNdxVN9xVN9tS - M9tUNdtUNdxXOd1aPNxYOtxXOd1aPN1bPt1bPt1aPN1aPNxXOdxVN9tUNdtSM9tUNdtSM9pNLdlIJ9NG - JtNGJsxDJNFFJcxDJMlCJMpDJMdCJL0/Ir0/Irs9Ib0/Ir4/Irg9IcRBI85EJdtUNeBoTeJyWeN4YOJ0 - W99mS9lJKb4/Ir0/IrM7IJszHI8wGoouGYsuGYgtGIMsGIAqF3wpFnUnFXcnFXImFW8lFG0kFGgjE2gj - E2gjE2MhElwfEVwfEVgdEF8fEVgdEFUcD1IbD1IbD1AbD04aDksZDkkYDUcYDUsZDkYYDUYYDUIWDD8V - DD8VDD8VDDgSCjoUCzgSCjYSCjUSCjMRCTMRCTMRCTUSCjEQCTAQCS4QCTAQCS4QCTAQCS4QCTAQCSsO - CCkOCCkOCCcNByUNByQMByUNByQMByILBiILBiALBiALBiILBiILBiALBh0KBh0KBhsJBR0KBhsJBRsJ - BRsJBRoJBRgJBRYHBBgJBRYHBBYHBBQHBBMHBBMHBNXV1P////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////X19VZVVQMBAQMBAQIBAQMBAQMBAQIBAQIBAQIBAQIBAQAAAAIB - AQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9VGJtlIJ9VGJtlJKdlIJ9lIJ9pLK9lJKdlIJ9pLK9tR - MtxXOdxVN9pOLttSM91aPN1bPtxXOdxYOtxXOdxXOdtUNdtSM9tSM9xVN9tUNdtUNdtSM9tSM9xVN9xY - OtxYOt1bPtxVN91bPt1aPNxYOttSM9tRMtpNLdpOLtpOLtpPMNlJKdlIJ9ZGJsxDJM5EJclCJMpDJMdC - JMVBI8RBI7s9Ibs9Ib0/Ir0/Irg9Ibg9IbY8Ibk9IcdCJNlJKd5gQ+BsUuJ1XOJyWd5gQ85EJbE7IK86 - H7M7IJcyG48wGogtGIMsGIYsGIErF3koFnkoFnQnFXcnFXImFW8lFGgjE20kFGYhEmYhEmEhEl4fEV8f - EVoeEFcdEFcdEFMcD1AbD1AbD04aDksZDk0aDk0aDkcYDUkYDUQWDEYYDUQWDEEWDD8VDDgSCjgSCjgS - CjoUCzYSCjYSCjMRCTMRCTMRCTEQCTAQCTAQCTAQCTAQCSwPCC4QCSwPCC4QCSsOCCkOCCkOCCcNBycN - ByQMByILBiILBiQMByILBh8LBiALBiALBiALBh8LBh0KBh0KBhsJBR0KBhoJBRoJBRoJBRgJBRgJBRgJ - BRYHBBQHBBYHBBQHBBMHBBMHBNXV1P////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////4iHhwMBAQMBAQIBAQIBAQMBAQMBAQMBAQMBAQIBAQIBAQAAAAIBAQAAAAAAAAIBAQIB - AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9hHJtlJKdNGJtpLK9pLK9lIJ9lJKdlJKdhHJtZGJtpOLttUNdtSM9pPMNtU - Nd1aPNxYOttUNdxVN9tRMttRMtpOLttUNdxVN9tUNdtRMttSM9tUNdtSM9xVN9tUNdxVN9tRMttUNdxX - OdxXOdxXOdpOLtpNLdpOLtpOLtpNLdlJKdpNLdhHJs9EJcdCJMJAI8dCJMJAI74/IsA/Ir0/Irk9Ibk9 - IbY8IbE7ILM7ILE7IK86H7E7ILs9Ic5EJdxXOeBrUOJ0W+FvVdxVN8A/IqU3HqA1Ha05H5YyG4YsGH4q - F4AqF4ErF3wpFnkoFnUnFXQnFW8lFGkjE2kjE2sjE2QhEmQhEmMhEmEhElwfEVwfEVcdEFMcD1UcD1Ib - D04aDk4aDksZDksZDkkYDUkYDUYYDUYYDUEWDEYYDUEWDDwUCzoUCzgSCjYSCjYSCjUSCjUSCjUSCjMR - CTEQCTAQCTAQCTAQCTAQCS4QCSwPCCwPCCwPCCsOCCsOCCwPCCkOCCkOCCcNBycNByQMByILBiILBiQM - ByILBh8LBh8LBh8LBiALBh8LBh0KBhsJBR0KBh0KBhsJBRoJBRoJBRoJBRoJBRYHBBYHBBQHBBQHBBMH - BBQHBBQHBNXV1P////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////5eWlgMB - AQMBAQMBAQMBAQIBAQIBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9ZGJs5EJdZGJtlIJ9pNLdpLK9ZGJthHJthHJthHJtpOLtpPMNtSM9tUNdtUNdxXOdxYOttUNdtU - NdtRMttRMttSM9xVN9pPMNpOLttRMtpPMNxVN9tSM9tSM9xVN9xVN9pOLtxXOdxXOdtUNdtUNdpLK9lJ - KdpNLdhHJtlJKdlJKdlIJ9FFJcRBI8JAI8JAI8A/Ir0/Ir0/Ir0/Irs9IbY8IbY8IbM7IK86H6o4HqU3 - Hq05H6o4Hq05H74/ItpNLd9lSuJ0W+BqT9pNLbY8IZw0HJ40HKw5H5YyG4AqF34qF3wpFncnFXkoFnIm - FXAlFG0kFG0kFGsjE2YhEmgjE2EhEmEhEl8fEV4fEVgdEFgdEFcdEFIbD1AbD1McD00aDksZDk0aDk0a - DkcYDUkYDUcYDUIWDEEWDEIWDD0UCzoUCzwUCzgSCjgSCjUSCjUSCjMRCTMRCTUSCjMRCTMRCTAQCSwP - CCwPCCwPCCwPCC4QCSsOCCkOCCkOCCsOCCkOCCsOCCcNByUNByQMByQMByILBiILBiALBh8LBh8LBh8L - Bh8LBh8LBh0KBhsJBRsJBR0KBhsJBRoJBRoJBRgJBRgJBRYHBBYHBBYHBBYHBBMHBBMHBBMHBNXV1P// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////7GwsAMBAQMBAQMBAQMBAQMBAQMB - AQIBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9lJKdZGJtlI - J9ZGJthHJtlJKdlJKdhHJtZGJthHJtlIJ9tRMttSM9tSM9tRMttRMtxVN9xYOttUNdtUNdtUNdpPMNtS - M9tRMtpOLtpOLtpPMNtRMttSM9tSM9tRMttRMttUNdtSM9tUNdtRMtlIJ9pLK9pLK9lJKdVGJthHJtZG - JtNGJspDJMA/Ir4/Ir0/Ir4/Irs9Ib0/IrY8IbQ7ILE7ILE7IKw5H6w5H6U3Hqg3HqM2HaI2HaM2HbE7 - IMdCJNxXOeBoTd1bPslCJJ40HI0uGZEwGp40HJEwGn4qF3koFnkoFncnFXUnFXAlFHAlFGkjE2sjE2kj - E2YhEmYhEl4fEV4fEVwfEVwfEVwfEVcdEFcdEFAbD1AbD1AbD00aDk0aDkcYDUcYDUkYDUYYDUIWDEQW - DD0UC0EWDDoUCzgSCjoUCzgSCjgSCjYSCjYSCjMRCTUSCjEQCTMRCTMRCTAQCSwPCDAQCS4QCSsOCCsO - CCsOCCkOCCsOCCkOCCUNBycNBycNBycNByQMByQMByILBiILBiILBiALBh8LBh8LBh0KBh0KBh0KBhsJ - BRsJBRoJBRgJBRgJBRgJBRYHBBYHBBYHBBYHBBYHBBYHBBYHBBMHBBMHBNXV1P////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////4mIhwMBAQMBAQIBAQIBAQMBAQIBAQMBAQMBAQIBAQMBAQIB - AQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9lJKdlIJ9VGJtlIJ9hHJthHJtVG - JtpNLdNGJthHJtlIJ9pLK9pPMNtRMttUNdpPMNtRMttUNdxYOtxVN9tUNdtRMtpOLtpOLtpPMNtRMtpO - LtpOLtpNLdpPMNpOLttRMttRMttUNdtSM9lJKdpNLdpLK9lIJ9pLK9ZGJtZGJtFFJcxDJMVBI8A/Ir0/ - Ir0/Irs9Ibs9Ibk9IbQ7ILE7IKw5H6w5H6g3HqM2Hac3HqM2HaA1HZszHJkyG6A1HbQ7INZGJtxVN9lJ - KbE7IJQxG4gtGIouGZw0HI8wGnooFnwpFnQnFXUnFXQnFXImFW0kFGkjE2YhEmQhEmEhEl8fEVgdEFoe - EFgdEFcdEFcdEFcdEFAbD04aDk4aDk0aDlAbD0kYDUkYDUsZDkQWDEYYDUEWDEEWDEEWDD0UCzoUCzgS - CjoUCzgSCjgSCjMRCTMRCTMRCTEQCTMRCTEQCTEQCSwPCC4QCTEQCSsOCCsOCCsOCCwPCCcNBycNBykO - CCUNByQMByUNByUNByUNByUNByQMByALBiALBiALBiALBh0KBh8LBh0KBhsJBRsJBRsJBRoJBRgJBRoJ - BRgJBRgJBRgJBRYHBBYHBBQHBBQHBBYHBBMHBBMHBNXV1P////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////+rq6lhWVQMBAQMBAQMBAQMBAQMBAQMBAQIBAQIBAQMBAQIBAQMBAQIBAQIBAQIBAQIBAQAA - AAIBAQIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9hHJtlIJ9NGJtZGJtVGJtlIJ9lIJ9lJKdNGJtlIJ9VG - JtVGJtpOLtpPMNpOLttRMtpOLtpOLttRMtpOLttUNdtSM9tSM9pOLtpOLtpPMNpOLtpLK9pOLtpPMNpN - LdpOLtpOLtpNLdpOLtZGJtNGJs9EJdNGJtNGJtNGJtNGJs9EJcVBI74/IsA/Irg9IbY8IbQ7ILg9IbM7 - ILM7IKw5H6g3HqU3HqM2HaU3HqA1HaA1HZkyG5cyG5kyG5cyG5szHLs9IcxDJL4/IpszHIUsGH4qF4Er - F5YyG40uGXkoFnQnFXImFXImFXImFWsjE2YhEmgjE2YhEmQhElwfEVoeEFoeEFoeEFcdEFUcD1cdEFcd - EFIbD1IbD00aDk0aDkcYDUYYDUkYDUYYDUQWDEQWDEEWDEIWDD8VDDoUCzwUCzgSCjgSCjMRCTUSCjEQ - CTUSCjMRCS4QCS4QCTAQCS4QCSwPCC4QCS4QCSwPCC4QCSsOCCkOCCcNBycNBykOCCcNByUNByUNByQM - ByQMByUNByUNByALBiALBh8LBiALBh8LBh8LBhsJBRsJBRsJBRoJBRoJBRgJBRoJBRgJBRYHBBYHBBYH - BBgJBRYHBBQHBBQHBBMHBBMHBNXU1P////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////6WkpCwoJwUC - AQMBAQMBAQMBAQMBAQMBAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9hHJtFFJdVGJtFFJdhHJtlIJ9hHJtVGJtFFJdhHJtlJKdhHJtlJKdpPMNpO - LtpOLtpNLdpOLtpOLtpPMNpPMNtRMtpPMNpOLttSM9pOLtpOLtpLK9lJKdpLK9pOLtpNLdpNLdlJKdpL - K9VGJthHJtFFJdFFJdFFJc5EJclCJMRBI7k9Ibg9Ibg9IbQ7ILQ7ILE7ILE7ILE7IKo4Hqo4HqU3HqA1 - HaA1HZw0HJkyG5szHJYyG5QxG40uGY0uGYouGZcyG6c3HpszHI0uGX4qF3ooFnooFpEwGo0uGXQnFW0k - FHAlFGsjE2sjE2kjE2YhEmMhEmMhElwfEVoeEFgdEFcdEFcdEFMcD1McD1McD1IbD1UcD00aDk0aDkkY - DUkYDUcYDUQWDEQWDEIWDEIWDEEWDD0UCz0UCzYSCjYSCjUSCjYSCjMRCTMRCTAQCTMRCTMRCTAQCS4Q - CTAQCTAQCS4QCSwPCCwPCCsOCCsOCCsOCCkOCCkOCCcNBycNBykOCCcNByUNByILBiILBiILBiQMByIL - BiALBh8LBh0KBh0KBh8LBhsJBRsJBRsJBRoJBRgJBRgJBRYHBBYHBBYHBBYHBBQHBBQHBBQHBBMHBBMH - BBMHBBMHBNXU1P////////////////////////////////////////////////////////////////// - //////////////////////////////////////////X19bGwsERBQAkDAgcDAgUCAQMBAQUCAQMBAQIB - AQIBAQMBAQMBAQMBAQIBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAIBAQAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9hHJtlIJ9FFJdNGJtNGJtFFJdhHJtZGJthHJtZGJtNGJtFFJc5EJdVGJtpOLtpNLdpNLdpLK9pN - LdpNLdpOLtpOLtpPMNxVN9tRMtpPMNlJKdpOLtpLK9pLK9lJKdlJKdNGJtVGJtNGJtNGJsxDJNNGJspD - JMpDJMdCJMJAI7s9Ibg9IbM7ILM7IK86H605H6w5H605H6o4HqA1HaA1HZszHJ40HJszHJkyG5QxG5cy - G5EwGo8wGosuGYouGYMsGIgtGIUsGIouGYMsGHwpFnkoFnooFosuGYouGXUnFW8lFG8lFGgjE2YhEmYh - EmQhEl8fEVwfEVwfEVgdEFgdEFcdEFUcD1IbD1McD1AbD04aDlIbD00aDkkYDUkYDUkYDUcYDUQWDD0U - C0EWDD8VDD8VDD8VDDoUCzYSCjYSCjMRCTUSCjMRCTUSCjEQCTEQCTAQCTAQCTEQCTEQCTAQCS4QCTAQ - CSsOCCwPCCkOCCkOCCcNBycNByUNByUNByUNByUNByQMByILBiALBiILBiILBh8LBh8LBiALBh8LBh8L - Bh0KBh0KBh0KBhsJBRoJBRYHBBgJBRYHBBgJBRQHBBQHBBQHBBMHBBMHBBMHBBMHBBMHBBEGA9XU1P// - //////////////////////////////////////////////////////////////////////////////// - /////////////+rq6r69vXt5eAkDAgkDAgkDAgkDAgcDAgMBAQUCAQUCAQMBAQIBAQMBAQMBAQMBAQIB - AQIBAQIBAQIBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9lIJ9FFJdNG - JtNGJtZGJtNGJtZGJtZGJtZGJthHJtFFJdNGJs9EJdhHJtlIJ9pNLdlJKdpNLdpLK9hHJtpLK9lJKdlI - J9pNLdlJKdlIJ9pNLdZGJtZGJtVGJtZGJtVGJs5EJcxDJM5EJcVBI8pDJMxDJMlCJMRBI8JAI70/IrY8 - IbE7IK05H7Q7IKo4Hqw5H6o4Hq05H6I2HaA1HZszHJw0HJszHJkyG48wGpQxG40uGYsuGYgtGIMsGIUs - GIUsGIAqF4ErF4UsGH4qF3koFnUnFXQnFYMsGIgtGHQnFW0kFGkjE2QhEmYhEmQhEl4fEV4fEVcdEFcd - EFcdEFUcD1cdEFcdEFUcD1AbD04aDkkYDU0aDk0aDkcYDUcYDUkYDUQWDEQWDEIWDD8VDDwUCz0UCz0U - CzoUCzUSCjUSCjYSCjYSCjUSCjMRCTEQCTEQCTAQCS4QCS4QCSwPCDAQCSwPCCwPCCsOCCkOCCkOCCcN - BykOCCcNByUNByQMByQMByQMByQMByQMByILBiILBiALBh8LBh0KBh8LBiALBiALBh0KBhsJBRsJBRoJ - BRoJBRgJBRgJBRYHBBYHBBYHBBYHBBYHBBQHBBMHBBMHBBMHBBMHBBEGA4yJiaalpKalpKalpKalpKal - pKalpKalpKalpKalpKalpKalpKalpKalpKalpKalpKalpKalpKalpKalpKWkpKalpHt5eGpoaCwoJwoD - AgoDAgoDAgoDAgkDAgkDAgcDAgUCAQMBAQMBAQMBAQMBAQMBAQMBAQMBAQIBAQIBAQMBAQIBAQIBAQIB - AQIBAQIBAQIBAQIBAQAAAAIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9VGJtZGJtVGJtNGJtFFJdFFJdVG - JtZGJtVGJtZGJs9EJc9EJcxDJM5EJc5EJdFFJdNGJthHJtpNLdlIJ9pLK9lIJ9lIJ9ZGJtVGJs9EJc9E - JdNGJtVGJtFFJcxDJMdCJM5EJclCJMdCJMdCJMdCJMRBI8JAI7s9IbY8IbM7IK05H6o4Hqw5H605H6w5 - H6o4Hqc3HqA1HZszHJszHJszHJkyG5kyG5QxG5EwGo0uGYYsGIYsGIUsGIErF4ErF3wpFnkoFn4qF3oo - FnkoFnQnFXAlFHAlFIAqF4gtGHQnFWQhEmQhEmMhEmEhEmMhEl8fEVwfEVcdEFoeEFUcD1IbD1McD1Ab - D04aDlAbD0sZDkkYDUkYDU4aDk0aDkYYDUQWDEIWDD8VDEEWDDwUCz8VDEEWDDoUCzUSCjUSCjYSCjMR - CTMRCTMRCTAQCTEQCTAQCTAQCTAQCS4QCSwPCCwPCCwPCCsOCCsOCCwPCCkOCCcNBycNByUNBycNByUN - ByQMByQMByILBiILBiILBiALBiALBiALBh8LBh8LBh8LBh8LBhsJBRsJBRsJBRoJBRoJBRgJBRgJBRgJ - BRYHBBYHBBYHBBYHBBYHBBQHBBMHBBMHBBEGAxEGAxEGAxEGAxEGAxEGAxEGAxEGAxEGAw8FAw4FAw8F - Aw4FAw4FAw4FAw4FAw4FAwwFAw4FAwwFAwwFAwwFAwoDAgoDAgoDAgwFAwoDAgoDAgoDAgoDAgoDAgkD - AgkDAgUCAQUCAQMBAQMBAQMBAQMBAQMBAQMBAQIBAQMBAQIBAQMBAQMBAQIBAQIBAQIBAQAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9hHJtZGJtNGJtFFJdFFJc9EJdFFJdNGJtNGJtVGJs9E - Jc9EJc9EJc5EJcxDJMdCJNFFJdNGJthHJtlIJ9lJKdFFJdVGJtNGJtFFJdFFJc5EJc9EJdFFJdFFJclC - JMlCJMdCJMdCJMxDJMVBI74/Ir4/IrM7IK86H7Q7IK05H686H6g3Hqg3Hqg3Hqc3Hqg3HqA1HZszHJky - G5kyG5IwGpIwGpEwGo0uGYgtGIYsGIYsGIUsGIAqF4MsGIErF4AqF3koFnkoFnkoFncnFW8lFG0kFG0k - FHooFoUsGHAlFGEhEmMhElwfEVwfEV4fEVoeEFoeEFUcD1McD1UcD1McD1AbD1AbD04aDksZDkkYDUcY - DUYYDUYYDU0aDkQWDEEWDEQWDD8VDDoUCz8VDDwUCzwUCzYSCjUSCjUSCjMRCTMRCTUSCjMRCTMRCTEQ - CTAQCS4QCSwPCCwPCC4QCS4QCSwPCCwPCCcNBycNBykOCCcNBycNByUNByUNByILBiQMByQMByILBiAL - BiILBh8LBh8LBh8LBh0KBhsJBR0KBhsJBRsJBRsJBRoJBRoJBRoJBRYHBBgJBRgJBRgJBRYHBBQHBBMH - BBMHBBMHBBEGAxEGAxEGAxEGAxEGAxEGAxEGAxEGAxEGAxEGAw8FAw4FAw8FAw8FAw4FAw4FAw4FAw4F - Aw4FAwwFAw4FAwwFAw4FAw4FAwwFAwoDAgoDAgoDAgoDAgoDAgkDAgoDAgkDAgkDAgkDAgUCAQMBAQMB - AQMBAQUCAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAIBAQAAAAIBAQAAAAAAAAAAAAAA - AAIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////9lIJ9NGJtNGJs9EJc9EJdFFJcpDJM9EJc5EJc9EJc5EJcxDJM9EJcVBI8lC - JMpDJMVBI8pDJNVGJtFFJdVGJtFFJc5EJcxDJM5EJcxDJM5EJcpDJMxDJMdCJMdCJMJAI8VBI8lCJL0/ - Ir0/IrY8IbQ7IK86H686H6w5H6g3HqM2Hag3HqI2HaM2HaA1HaA1HZkyG5szHJQxG5QxG5EwGo0uGY0u - GYgtGIUsGIUsGIUsGIAqF4AqF3ooFnooFncnFXcnFXcnFXcnFXQnFW0kFGsjE2sjE3QnFYMsGHImFWEh - El8fEVwfEVwfEVoeEFoeEFcdEFcdEFUcD1IbD04aDlAbD00aDksZDkkYDUcYDUcYDUcYDUYYDUIWDEIW - DEEWDDwUCz0UCzwUCz0UCzwUCzgSCjYSCjMRCTMRCTMRCTEQCTEQCTEQCTAQCTAQCS4QCTAQCS4QCS4Q - CSsOCCwPCCkOCCsOCCsOCCcNBykOCCcNBycNByUNByUNByILBiILBiILBiILBiALBiILBh8LBh8LBh8L - Bh0KBhsJBRsJBRsJBRsJBRsJBRoJBRsJBRsJBRgJBRgJBRYHBBYHBBMHBBMHBBMHBBEGAxEGAxEGAxMH - BBEGAxEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FAw4FAw4FAw4FAw4FAw4FAw4FAw4FAwwFAwwFAw4FAw4F - Aw4FAwwFAwwFAwwFAwwFAwwFAwoDAgoDAgkDAgkDAgkDAgkDAgcDAgMBAQMBAQMBAQMBAQMBAQMBAQMB - AQMBAQMBAQMBAQIBAQMBAQIBAQIBAQAAAAIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9VGJtFFJdVGJtFFJdZGJtFFJc5EJcpDJM5EJcpDJM5EJcpDJMpDJMRBI8dCJMVBI8RBI8RBI8dC - JMlCJMxDJMlCJMpDJMxDJNFFJcpDJMxDJMlCJMVBI8VBI8dCJL0/IsJAI74/IrY8Ia05H605H6I2Ha05 - H6c3HqU3HqU3Hp40HJ40HKA1HaA1HZszHJQxG5YyG4ouGY8wGo0uGZEwGo0uGYYsGIMsGIAqF34qF4Aq - F3wpFnooFncnFXcnFXQnFXImFXAlFHQnFW8lFGsjE2sjE2kjE3ImFX4qF2sjE2QhElwfEVgdEFcdEFgd - EFcdEFMcD1IbD1AbD1IbD00aDk0aDk0aDkYYDUcYDUYYDUYYDUYYDUIWDEIWDEYYDUEWDD8VDDwUCz0U - CzwUCzoUCzYSCjYSCjUSCjMRCTMRCTMRCTAQCS4QCTAQCTAQCS4QCSwPCCwPCCsOCCkOCCkOCCsOCCsO - CCsOCCUNBykOCCcNByUNByQMByQMByILBiQMByILBiILBiALBh8LBh0KBh8LBh8LBh0KBhsJBRsJBRsJ - BRoJBRoJBRoJBRoJBRoJBRYHBBQHBBQHBBYHBBQHBBMHBBQHBBMHBBEGAxEGAxMHBBEGAxEGAxEGAxEG - AxEGAw8FAxEGAw8FAw8FAxEGAw8FAw4FAw8FAw8FAw4FAwwFAw4FAwwFAwwFAw4FAw4FAwwFAwwFAwoD - AgoDAgoDAgoDAgkDAgkDAgoDAgoDAgcDAgUCAQMBAQMBAQUCAQMBAQMBAQMBAQIBAQIBAQMBAQMBAQIB - AQMBAQIBAQAAAAAAAAIBAQIBAQAAAAAAAAAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////9VGJtZGJtNG - Js9EJc9EJcxDJM9EJc9EJc9EJcxDJMpDJMpDJMpDJMVBI8dCJMdCJMA/IsRBI8A/IsA/Ir0/Ir0/Ir4/ - IsRBI8JAI74/Ir0/Ir0/Ir0/Ir0/Irs9Ibs9IbY8Ia86H6w5H6g3Hqg3Hqc3Hqc3Hqc3Hp40HKA1HZ40 - HJkyG5kyG5QxG5YyG5EwGo0uGYsuGYYsGIErF4UsGIYsGIUsGIErF4AqF3wpFnooFnooFnkoFncnFXAl - FG8lFHQnFW8lFHAlFG8lFGQhEmgjE2QhEmgjE3UnFW0kFF4fEVgdEFoeEFUcD1cdEFgdEFUcD1McD04a - Dk0aDk0aDkYYDUsZDksZDkkYDUIWDEEWDEIWDEEWDEEWDEEWDEEWDDwUCz0UCzwUCzoUCzUSCjMRCTUS - CjMRCTMRCTEQCTAQCS4QCTAQCS4QCS4QCSwPCCwPCCsOCCwPCCsOCCkOCCcNBycNBycNBycNBykOCCcN - ByUNByQMByQMByILBiILBiILBiILBiALBh8LBh0KBh8LBh0KBhsJBRsJBRsJBRsJBRoJBRoJBRgJBRgJ - BRoJBRgJBRgJBRQHBBYHBBQHBBQHBBQHBBMHBBMHBBMHBBEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FAw8F - Aw8FAxEGAw8FAw4FAw4FAw4FAw4FAwwFAw4FAwwFAwwFAwwFAwwFAwwFAwoDAgoDAgoDAgkDAgoDAgkD - AgkDAgkDAgoDAgcDAgMBAQMBAQUCAQMBAQMBAQMBAQMBAQIBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIB - AQIBAQIBAQAAAAAAAAAAAAIBAQIBAQAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9NGJtZGJtNGJsxDJNNGJslCJMxD - JMpDJMpDJMlCJMlCJMdCJMJAI8dCJMVBI8VBI8JAI8RBI8RBI70/IsA/Irk9Ib0/Irk9Ibg9IbY8IbQ7 - ILM7ILY8IbE7IK86H686H6w5H6w5H6U3Hqc3HqU3HqA1HaA1HaI2HZw0HKA1HZcyG5szHJEwGo0uGY8w - GosuGYsuGYYsGIErF4UsGIMsGIAqF3ooFnooFnooFnkoFnUnFXImFXAlFHUnFXAlFGkjE28lFGYhEmsj - E2QhEmEhEmMhEmEhEmYhEnQnFW0kFFgdEFgdEFUcD1McD1McD1UcD1McD00aDk0aDlAbD0kYDUIWDEcY - DUIWDEIWDD8VDD8VDD0UCz0UCz0UCz0UCz0UCz8VDD0UCzgSCjgSCjUSCjUSCjYSCjMRCTEQCTEQCTAQ - CS4QCSwPCC4QCSwPCDAQCS4QCSsOCCsOCCsOCCcNBycNBycNBycNByUNByUNByUNByQMByQMByILBiIL - BiALBiALBh8LBh8LBh8LBh0KBh0KBhsJBRsJBRoJBRoJBRoJBRoJBRgJBRgJBRYHBBgJBRYHBBYHBBQH - BBYHBBQHBBMHBBMHBBMHBBMHBBMHBBEGAxEGAxEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FAw8FAw4FAw4F - Aw4FAw4FAw4FAwwFAwwFAwwFAwwFAwwFAwwFAwwFAwwFAwoDAgoDAgoDAgoDAgoDAgoDAgkDAgcDAgUC - AQMBAQMBAQMBAQMBAQMBAQMBAQMBAQIBAQIBAQMBAQMBAQIBAQIBAQIBAQAAAAAAAAIBAQAAAAIBAQAA - AAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9FFJc9EJdFFJcxDJM9EJcpDJMpDJMpDJMlCJMJAI8JA - I74/IsdCJMJAI8JAI8VBI8A/Ir4/Ir0/IsJAI70/Irg9Ibs9IbY8IbM7ILE7IK86H686H686H6o4Hqw5 - H605H6g3Hqg3Hq05H6U3HqI2HaI2HZ40HKA1HZkyG5kyG5cyG5IwGo8wGosuGYgtGIgtGIouGYUsGIMs - GIMsGIMsGH4qF3koFnkoFnkoFncnFXUnFXUnFW8lFGkjE2sjE20kFGsjE2YhEmkjE2MhEl4fEV8fEV8f - EWMhEm0kFGsjE1wfEVMcD1McD1IbD1IbD1AbD1AbD1IbD0kYDUQWDEcYDUYYDUIWDEQWDEQWDD8VDEEW - DDoUCzwUCz0UCzwUCzwUCz8VDDgSCjgSCjMRCTMRCTMRCTMRCTEQCTEQCTAQCTAQCS4QCS4QCSwPCCwP - CC4QCSsOCCkOCCsOCCcNBykOCCcNBysOCCcNByUNByUNByQMByILBiQMByILBiALBiILBiALBh8LBh8L - BiALBh0KBhsJBRoJBRoJBRoJBRsJBRsJBRgJBRYHBBQHBBYHBBgJBRYHBBMHBBQHBBQHBBQHBBQHBBMH - BBMHBBMHBBMHBBEGAxEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FAxEGAw8FAw4FAw4FAwwFAw4FAw4FAw4F - Aw4FAw4FAw4FAwwFAwoDAgoDAgwFAwoDAgoDAgoDAgoDAgoDAgoDAgcDAgUCAQUCAQUCAQMBAQMBAQMB - AQMBAQMBAQMBAQMBAQIBAQIBAQMBAQIBAQIBAQIBAQIBAQAAAAIBAQAAAAAAAAAAAAAAAAIBAQAAAAIB - AQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////89EJdNGJtFFJcxDJNFFJclCJMpDJMpDJMdCJMRBI8A/IsA/IsJAI8JAI8RB - I8VBI8A/IsJAI7k9Ibs9Ibk9Ibk9IbQ7ILg9IbM7ILE7ILE7ILE7IK86H6o4HqU3Hqw5H6o4Hqc3HqA1 - HZ40HKM2HaA1HaI2HZszHJkyG5szHI8wGosuGYgtGIgtGIMsGIgtGIErF4ErF34qF4AqF4AqF3koFncn - FXQnFXUnFXQnFXAlFG0kFGkjE2sjE2gjE2sjE2EhEmMhEmQhEmMhElwfEVgdEFgdEFwfEWsjE2gjE1Uc - D1McD1AbD00aDk0aDk0aDk0aDksZDksZDkcYDUQWDEcYDUYYDUEWDD8VDDwUCzwUCzwUCzoUCzoUCzwU - CzoUCzoUCzgSCjYSCjMRCTEQCTEQCTEQCTEQCTEQCS4QCTAQCS4QCSwPCCsOCCsOCCkOCCkOCCsOCCcN - BycNBycNBycNBycNBycNByUNByUNByQMByILBiILBiALBiALBiALBiALBh8LBh0KBh0KBhsJBR0KBhsJ - BRsJBRsJBRoJBRoJBRoJBRYHBBQHBBYHBBYHBBYHBBQHBBQHBBMHBBMHBBQHBBQHBBMHBBMHBBMHBBEG - AxEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FAw8FAw4FAw4FAw4FAwwFAw4FAw4FAwwFAwwFAw4FAwwFAwwF - AwoDAgoDAgoDAgoDAgoDAgoDAgkDAgkDAgkDAgcDAgUCAQMBAQMBAQIBAQMBAQMBAQMBAQMBAQMBAQIB - AQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAIBAQAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////9FFJcxDJM5EJcdCJMxDJMpDJMlCJMpDJMdCJMA/IsA/Ir0/Ir0/IsA/Ir0/Ir4/Ir4/Irs9Ibg9 - IbQ7IL0/IrQ7ILQ7ILM7IK86H6w5H6w5H605H6w5H6c3Hqc3Hqc3HqU3Hqc3HqM2HZszHJw0HJszHJcy - G5IwGpYyG48wGosuGYsuGYUsGIMsGIErF3wpFn4qF34qF3ooFnwpFncnFXQnFXQnFXQnFW0kFGkjE2Yh - EmgjE2kjE2YhEmEhEmEhEl8fEWMhEmEhEl4fEVcdEFcdEFcdEFoeEGgjE2YhElcdEFIbD0sZDkkYDUkY - DUsZDkkYDUkYDUYYDUYYDUQWDEQWDD8VDEEWDD8VDD8VDD0UCz0UCz8VDDoUCzUSCjoUCzUSCjgSCjUS - CjMRCTEQCTAQCS4QCTAQCS4QCTAQCS4QCS4QCSwPCCwPCCsOCCcNBycNBykOCCkOCCcNBykOCCUNByUN - ByQMByUNByQMByILBiALBiILBiILBiILBiALBiALBh8LBh0KBhsJBRsJBRsJBRsJBRsJBRsJBRoJBRgJ - BRgJBRgJBRgJBRQHBBYHBBYHBBQHBBYHBBMHBBEGAxMHBBMHBBQHBBEGAxEGAxEGAxEGAxEGAxEGAxEG - Aw8FAw8FAw8FAw8FAw8FAw4FAw4FAw4FAwwFAwwFAw4FAw4FAwwFAwwFAwwFAwoDAgwFAwoDAgoDAgoD - AgoDAgkDAgkDAgkDAgkDAgUCAQMBAQUCAQMBAQMBAQUCAQMBAQMBAQMBAQIBAQIBAQMBAQIBAQMBAQIB - AQIBAQIBAQIBAQAAAAAAAAAAAAIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////8xDJMxDJM5E - JcdCJMpDJMlCJMlCJMJAI8JAI74/IsJAI70/Ir0/Ir4/Irs9Ibk9Ibk9Ibg9Ib0/IrY8IbY8IbQ7ILQ7 - ILM7ILE7IK86H6o4HqU3Hqg3HqU3HqI2HaI2HaI2HZw0HJw0HJ40HJszHJQxG5EwGo0uGYYsGIouGYou - GYMsGIYsGIErF3koFnwpFnwpFnkoFnQnFXcnFXkoFnUnFW8lFHAlFGsjE2kjE2gjE2MhEmEhEmEhEl4f - EV8fEVwfEV4fEV4fEVcdEFUcD1UcD1UcD1UcD2EhEl8fEVcdEFAbD0kYDUsZDk0aDkcYDU0aDkkYDUEW - DD8VDEEWDD8VDEEWDD0UCzoUCz0UCzwUCzoUCzoUCzYSCjUSCjgSCjUSCjYSCjUSCjMRCTEQCS4QCS4Q - CTAQCS4QCSwPCCwPCCwPCCwPCCsOCCkOCCcNBykOCCkOCCkOCCcNBycNByQMByQMByQMByQMByQMByIL - BiALBiALBiALBiALBh8LBiALBh8LBh0KBhsJBRsJBRoJBRoJBRoJBRsJBRgJBRgJBRYHBBgJBRgJBRYH - BBQHBBQHBBQHBBQHBBQHBBEGAxEGAxEGAxEGAxMHBBMHBBEGAxEGAxEGAxEGAxEGAw8FAw8FAw8FAw8F - Aw4FAw4FAw8FAw4FAw4FAw4FAw4FAwwFAwwFAwwFAwoDAgoDAgwFAwoDAgkDAgkDAgkDAgkDAgoDAgkD - AgcDAgMBAQMBAQMBAQMBAQMBAQMBAQUCAQMBAQMBAQIBAQIBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQAA - AAAAAAIBAQIBAQAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////9NGJs9EJc5EJcxDJMlCJMxDJMlC - JMdCJMVBI74/Ir4/Ir0/Ir0/Ir0/IrY8IbY8IbY8Ia05H7M7ILQ7ILQ7ILM7IKw5H686H6w5H6U3Hqg3 - Hqg3HqM2HZw0HKI2HZ40HKA1HZw0HJszHJ40HJQxG48wGosuGYgtGIgtGIErF34qF4UsGHwpFn4qF3cn - FXooFnkoFnQnFXImFXcnFXQnFXAlFG8lFGkjE2kjE2sjE2gjE2MhEmMhEl4fEV4fEV4fEV4fEVwfEVoe - EFoeEFMcD1UcD1AbD1AbD14fEV8fEVcdEE4aDkcYDUkYDUkYDUkYDUcYDUkYDUQWDEIWDEEWDD8VDD8V - DDgSCjgSCjwUCzoUCzwUCzYSCjUSCjUSCjMRCTEQCTMRCTYSCjMRCTAQCS4QCTAQCTEQCSwPCCwPCCwP - CCsOCCsOCC4QCSsOCCkOCCkOCCkOCCcNByUNBycNByQMByQMByQMByQMByILBiILBiILBiALBh8LBh8L - Bh8LBh0KBh0KBhsJBRsJBRsJBRsJBRsJBRsJBRgJBRgJBRYHBBYHBBQHBBYHBBQHBBQHBBMHBBMHBBMH - BBQHBBEGAxEGAxEGAxEGAxEGAxEGAxEGAxEGAxEGAxEGAxEGAw4FAw8FAw4FAw8FAw8FAw4FAw4FAw4F - AwwFAw4FAw4FAwwFAwwFAwwFAwoDAgoDAgwFAwoDAgoDAgoDAgoDAgkDAgkDAgcDAgUCAQMBAQMBAQUC - AQMBAQMBAQMBAQMBAQMBAQMBAQMBAQIBAQMBAQIBAQMBAQIBAQIBAQIBAQIBAQIBAQAAAAIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAP////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////9NGJsxDJMxDJM9EJcpDJMxDJMJAI8dCJMJAI8A/IsA/ - Ir0/Irg9IbY8IbY8IbE7IK86H7M7IK86H686H6g3Hqc3Hqg3Hqc3Hqc3HqI2HaI2HZ40HJ40HJ40HJsz - HJszHJYyG5YyG5QxG4suGY0uGYsuGY0uGYMsGIAqF4MsGH4qF3wpFn4qF3ooFncnFXImFXkoFnUnFXUn - FXImFW0kFG0kFGgjE2YhEmQhEmQhEmEhEl8fEVwfEVwfEVwfEV4fEVoeEFgdEFcdEFMcD1AbD1IbD04a - Dk0aDlwfEV4fEVUcD0kYDUYYDUQWDEQWDEYYDUYYDUEWDEEWDD0UCz8VDDwUCzoUCzoUCzoUCzoUCzgS - CjgSCjYSCjUSCjMRCTUSCjEQCS4QCTMRCS4QCTEQCS4QCSsOCCwPCCwPCCwPCCwPCCkOCCsOCCkOCCsO - CCkOCCcNBykOCCQMByQMByUNByQMByILBiILBiQMBx8LBiALBiALBiALBiALBh8LBh8LBh0KBh0KBhoJ - BRoJBRoJBRsJBRoJBRoJBRYHBBYHBBgJBRgJBRQHBBQHBBYHBBYHBBQHBBMHBBMHBBMHBBMHBBMHBBEG - AxEGAxEGAxEGAxEGAxEGAxEGAxEGAw8FAw4FAw8FAw4FAw8FAw8FAw8FAw8FAw4FAwwFAw4FAwwFAwwF - AwwFAwwFAwoDAgkDAgkDAgkDAgkDAgoDAgkDAgoDAgcDAgUCAQMBAQUCAQMBAQMBAQUCAQUCAQMBAQMB - AQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQAAAAAAAAAAAAAAAAIBAQAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////////////8xDJMlCJM5EJcpDJMpDJMRBI8VBI8RBI8dCJMRBI70/Ir4/Irg9IbY8Ibg9 - IbY8IbY8IbM7IKc3Hqo4Hqg3HqI2HaU3HqM2HaM2HaI2HZw0HJszHJszHJcyG5YyG5kyG5QxG5EwGosu - GY0uGYsuGYUsGIUsGIErF3wpFnooFnooFnooFnwpFnUnFXUnFXQnFXQnFW0kFGsjE2sjE2kjE2gjE2Qh - EmMhEmMhEl8fEV4fEV4fEVwfEVoeEFgdEFUcD1cdEFUcD1cdEFAbD00aDk4aDksZDk4aDlcdEF4fEVMc - D0cYDUIWDEYYDUEWDEEWDEEWDEEWDEEWDD0UCz0UCzoUCzwUCzgSCjoUCzUSCjYSCjMRCTMRCTMRCTEQ - CTEQCTMRCTAQCTMRCTEQCSwPCC4QCSwPCCsOCCsOCCsOCCkOCCkOCCkOCCkOCCsOCCcNByUNByUNByUN - ByQMByILBiILBiQMByILBiILBiALBiALBh8LBh8LBh8LBh0KBh0KBh0KBhsJBRoJBRsJBRoJBRgJBRYH - BBgJBRgJBRgJBRYHBBYHBBQHBBMHBBQHBBQHBBMHBBEGAxMHBBMHBBMHBBEGAxEGAxEGAxEGAxEGAxEG - AxEGAxEGAxEGAxEGAw8FAw4FAw4FAw8FAw8FAw8FAw4FAwwFAwwFAwwFAwwFAwwFAwwFAwwFAwoDAgoD - AgoDAgwFAwoDAgoDAgkDAgkDAgcDAgUCAQUCAQUCAQUCAQMBAQUCAQUCAQMBAQMBAQMBAQMBAQIBAQIB - AQMBAQIBAQIBAQIBAQAAAAIBAQIBAQIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////8lCJM5EJcxDJMpDJMdCJMRBI8dCJL0/Irs9Ib4/Ir0/Irs9Ibg9IbQ7ILY8IbM7ILE7ILM7IKo4 - Hq05H6c3HqM2HZw0HJszHJ40HJ40HJszHJYyG5cyG5cyG5IwGo8wGo8wGosuGY0uGYouGYUsGIUsGIEr - F4AqF3wpFnkoFnkoFnUnFXcnFXcnFW8lFG8lFHAlFG8lFGkjE2gjE2QhEmMhEmMhEl8fEV4fEVwfEVwf - EVoeEFoeEFgdEFMcD1cdEE4aDk0aDlUcD04aDksZDksZDksZDksZDlIbD1UcD1McD0IWDEEWDEIWDEEW - DD8VDD0UC0EWDD8VDD0UCzwUCz0UCzYSCjYSCjMRCTUSCjgSCjMRCTMRCTAQCTMRCS4QCTEQCTAQCS4Q - CTAQCTEQCSwPCC4QCSsOCCkOCCcNBykOCCsOCCkOCCkOCCUNByUNByUNByQMByQMByQMByILBiILBiQM - ByILBiILBiALBiALBh8LBh0KBh0KBh0KBh0KBhsJBRsJBRoJBRsJBRoJBRgJBRYHBBgJBRoJBRoJBRYH - BBQHBBQHBBQHBBQHBBMHBBMHBBMHBBMHBBMHBBEGAxMHBBEGAxEGAxEGAxEGAxEGAxEGAxEGAxEGAw8F - Aw8FAw4FAw4FAw8FAw4FAw4FAw4FAwwFAwwFAwwFAwwFAwoDAgwFAwwFAwoDAgkDAgoDAgwFAwoDAgkD - AgkDAgkDAgUCAQUCAQUCAQUCAQUCAQMBAQMBAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQMBAQIBAQIBAQIB - AQIBAQIBAQIBAQAAAAAAAAAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////8pDJMpDJMpD - JMVBI8RBI8RBI70/Ir0/Ir0/Irs9Ibs9IbY8IbY8IbE7ILE7ILM7IK86H6w5H6o4HqU3HqM2HaI2HZsz - HJszHJw0HJkyG5kyG5YyG5QxG48wGo0uGYsuGYouGYMsGIgtGIYsGIMsGIAqF4AqF34qF3koFnQnFXQn - FXUnFXAlFHAlFG0kFHAlFGsjE2kjE2QhEmEhEmMhEl4fEV4fEVgdEFwfEVcdEFgdEFcdEFUcD1McD1cd - EFMcD04aDk0aDlAbD1AbD00aDkcYDUkYDUkYDUkYDVUcD1IbD0QWDD8VDD0UCz0UCzwUCzoUCz8VDD0U - CzoUCzoUCzUSCjYSCjYSCjMRCTMRCTMRCTMRCTMRCTEQCTMRCS4QCS4QCSwPCC4QCTAQCS4QCSsOCCsO - CCsOCCkOCCcNBysOCCkOCCcNBycNByUNByUNByUNByQMByQMByQMByILBiALBiILBiILBiALBh8LBh8L - Bh8LBh8LBhsJBRsJBRsJBRoJBRoJBRoJBRsJBRoJBRgJBRgJBRgJBRoJBRgJBRQHBBQHBBQHBBQHBBQH - BBQHBBMHBBMHBBMHBBEGAxEGAxEGAxEGAxEGAxEGAxEGAxEGAxEGAxEGAxEGAw8FAw8FAw4FAw4FAw8F - Aw4FAwwFAwwFAwwFAwwFAw4FAwwFAwwFAwoDAgoDAgoDAgkDAgkDAgoDAgoDAgkDAgcDAgUCAQMBAQMB - AQMBAQUCAQMBAQMBAQMBAQMBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIBAQIB - AQAAAAAAAAAAAAAAAAIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAABMLAAATCwAAAAAAAAAA + AAD///////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////28fr/18Tq/9jG6P/VxeT/1MXi/9LE3//QxNz/z8Pa/87D2P/LwtT/ysLR/8jB + zv/Hwcz/xsHL/8XAyf/FwMj/w8DH/8PAxv/Cv8T/wb/D/8LAw//CwMP/wcDC/8HAwv/BwMH/v7/A/76+ + vv+/v7//u7u7/+/v7////////////9nE7f9eC63/Xxak/1cSmf9SEJH/Tg+K/0kNgv9EDHj/Pglv/zEG + Wv8qBE3/IwJB/xwANv8WACz/EgAm/w8AIf8LABr/CAAV/wQADv8BAAn/AAAC/wAAAP8AAAD/AAAA/wAA + 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 + Bv8AAAD/vr6+////////////4Mn2/34g2P+JMtv/kUHd/5ZI3/+iXuP/tX7o/8OY7f/dxPT/1rny/6Rg + 5f94Icn/VBaO/zsSY/8yD1L/KAxC/yAKNv8cCS7/Gwsq/wAADP+rp67/29rc/wgADv8AAAD/q6ur/9ra + 2v8AAAD/AwME/wAAAP++vr7////////////fyPX/fh/X/4473P+WSN//oVvi/7F45/+lYuP/pGDj/7yL + 6v+yd+j/fibQ/2Ecof9IFnf/OBFd/y0OSv8kCzv/Hgky/xoIK/8ZCif/AAAK/6uorv/a2dv/AQAH/wAA + AP+zs7T/1NTU/wAAAP8EBAT/AAAA/76+vv///////////9/I9f9/Idf/jzzd/4883P+YTN//oFri/488 + 3f+DKtf/olzl/5RL2v9cFp3/Sxh7/zsSYv8xD1H/KAxB/yAKNf8cCC3/Fwcm/xcKJP8AAAj/qKWr/9va + 3P8BAAb/PTpA//////+IiIj/AAAA/wYGBv8AAAD/vr6+////////////38j1/30e1v+MNdz/izXc/4oz + 3P+IL9z/fCbN/2sdtP97LsT/biiw/0UTdP88E2T/Mg9S/yoNRf8iCjj/HQkw/xoIKv8VByP/Fgog/wAA + B/+gnaP///////Dw8P//////xsbG/xAPEf8AAAD/AwME/wAAAP++vr7////////////fyPX/eh3R/4Eq + 0v+CK9T/fijP/3Qjv/9mIKj/Wx2U/08Yg/9JF3j/PBRj/zIRUv8tD0j/JQ07/x8LM/8cCi3/GQkn/xUI + If8TCR3/CQER/z44Q/9jX2f/ZGBm/0lGTP8JCAr/AgIC/wQEBP8EBAT/AAAA/7+/v////////////93F + 8/9sD8P/bBm5/2MUrf9bEp//URCN/0UMev87CWr/Mgda/y0FUv8lA0X/HAA2/xcALv8TACb/DwAg/wwA + G/8IABb/BQAQ/wIAC/8AAAj/AAAC/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wICAv8AAAD/vr6+//// + ////////9vH8/9vE7//ax+z/18bn/9TF4//SxN7/z8Pa/83D1v/LwtP/ysLR/8jBz//Hwcz/xsHK/8XA + yf/EwMj/w8DH/8PAxf/CwMT/wb/D/8G/w//DwcT/xMPF/8PCxP/CwcP/v7/A/7+/v/++vr7/v7+//7u7 + u//v7+////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/ExportDisassembly.cs b/DiztinGUIsh/window/dialog/ExportDisassembly.cs index 88d87acc..f63d4cf1 100644 --- a/DiztinGUIsh/window/dialog/ExportDisassembly.cs +++ b/DiztinGUIsh/window/dialog/ExportDisassembly.cs @@ -9,7 +9,6 @@ namespace DiztinGUIsh // end. public partial class ExportDisassembly : Form { - //private readonly LogCreator LogCreator; private Data Data => Project.Data; private readonly Project Project; diff --git a/DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs b/DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs index 209cf50f..05031285 100644 --- a/DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs +++ b/DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs @@ -38,14 +38,14 @@ private void InitializeComponent() this.label1.Location = new System.Drawing.Point(11, 9); this.label1.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(54, 13); + this.label1.Size = new System.Drawing.Size(40, 13); this.label1.TabIndex = 0; - this.label1.Text = "Progress: "; + this.label1.Text = "Status:"; // // label2 // this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(68, 9); + this.label2.Location = new System.Drawing.Point(69, 9); this.label2.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(73, 13); @@ -55,16 +55,16 @@ private void InitializeComponent() // progressBar1 // this.progressBar1.Location = new System.Drawing.Point(8, 34); - this.progressBar1.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.progressBar1.Margin = new System.Windows.Forms.Padding(2); this.progressBar1.Name = "progressBar1"; - this.progressBar1.Size = new System.Drawing.Size(219, 19); + this.progressBar1.Size = new System.Drawing.Size(319, 19); this.progressBar1.TabIndex = 2; // // ProgressDialog // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(236, 63); + this.ClientSize = new System.Drawing.Size(338, 63); this.ControlBox = false; this.Controls.Add(this.progressBar1); this.Controls.Add(this.label2); @@ -73,10 +73,10 @@ private void InitializeComponent() this.MaximizeBox = false; this.MinimizeBox = false; this.Name = "ProgressDialog"; - this.Padding = new System.Windows.Forms.Padding(9, 9, 9, 9); + this.Padding = new System.Windows.Forms.Padding(9); this.ShowIcon = false; this.ShowInTaskbar = false; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "Working..."; this.TopMost = true; this.ResumeLayout(false); diff --git a/DiztinGUIsh/window/dialog/ProgressDialog.cs b/DiztinGUIsh/window/dialog/ProgressDialog.cs index 3b3318af..4883a172 100644 --- a/DiztinGUIsh/window/dialog/ProgressDialog.cs +++ b/DiztinGUIsh/window/dialog/ProgressDialog.cs @@ -12,11 +12,31 @@ namespace DiztinGUIsh.window.dialog { public partial class ProgressDialog : Form { - public ProgressDialog() + private readonly string overrideText = null; + + public ProgressDialog(bool marquee = false, string textOverride = null) { InitializeComponent(); progressBar1.Value = 0; progressBar1.Maximum = 100; + + overrideText = textOverride; + UpdateProgressText(); + + if (marquee) + progressBar1.Style = ProgressBarStyle.Marquee; + } + + private void UpdateProgressText() + { + if (overrideText != null) + { + label2.Text = overrideText; + return; + } + + var percentDone = (int)(100 * ((float)progressBar1.Value / (float)progressBar1.Maximum)); + label2.Text = $@"{percentDone}%"; } public void UpdateProgress(int i) @@ -24,9 +44,7 @@ public void UpdateProgress(int i) this.InvokeIfRequired(() => { progressBar1.Value = i; - var percentDone = (int)(100*((float)progressBar1.Value / (float)progressBar1.Maximum)); - - label2.Text = $@"{percentDone}%"; + UpdateProgressText(); }); } } diff --git a/tmp.txt b/tmp.txt new file mode 100644 index 00000000..4720d4b0 --- /dev/null +++ b/tmp.txt @@ -0,0 +1,2566 @@ +Microsoft (R) Build Engine version 16.7.0+b89cb5fde for .NET Framework +Copyright (C) Microsoft Corporation. All rights reserved. + +C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe -v:diag .\DiztinGUIsh.sln +Building the projects in this solution one at a time. To enable parallel build, please add the "-m" switch. +Build started 9/28/2020 4:45:56 PM. +Environment at start of build: +ALLUSERSPROFILE = C:\ProgramData +APPDATA = C:\Users\Dominic Cerquetti\AppData\Roaming +CommonProgramFiles = C:\Program Files (x86)\Common Files +CommonProgramFiles(x86) = C:\Program Files (x86)\Common Files +CommonProgramW6432 = C:\Program Files\Common Files +COMPUTERNAME = LAPTOP-DOM-CERQ +ComSpec = C:\Windows\system32\cmd.exe +DriverData = C:\Windows\System32\Drivers\DriverData +FPS_BROWSER_APP_PROFILE_STRING = Internet Explorer +FPS_BROWSER_USER_PROFILE_STRING = Default +HOMEDRIVE = C: +HOMEPATH = \Users\Dominic Cerquetti +LOCALAPPDATA = C:\Users\Dominic Cerquetti\AppData\Local +LOGONSERVER = \\LAPTOP-DOM-CERQ +MSBuildLoadMicrosoftTargetsReadOnly = true +NDI_RUNTIME_DIR_V2 = C:\Program Files\NewTek\NDI 4 Runtime\v4 +NDI_RUNTIME_DIR_V3 = C:\Program Files\NewTek\NDI 4 Runtime\v4 +NDI_RUNTIME_DIR_V4 = C:\Program Files\NewTek\NDI 4 Runtime\v4 +NUMBER_OF_PROCESSORS = 8 +OneDrive = C:\Users\Dominic Cerquetti\OneDrive - AA Recycle II LLC +OneDriveCommercial = C:\Users\Dominic Cerquetti\OneDrive - AA Recycle II LLC +OS = Windows_NT +Path = D:\installs\msys64\mingw64\bin;D:\installs\msys64\usr\bin\;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\Microsoft SQL Server\130\Tools\Binn\;C:\Program Files\Perforce\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR;C:\Program Files\PuTTY\;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\;C:\Program Files\Git\cmd;C:\Program Files\nodejs\;C:\Program Files\dotnet\;C:\Users\Dominic Cerquetti\AppData\Local\Microsoft\WindowsApps;C:\Users\Dominic Cerquetti\.dotnet\tools;C:\Users\Dominic Cerquetti\.platformio\penv\Scripts\;C:\Users\Dominic Cerquetti\AppData\Local\Programs\Python\Python38-32\python.exe;C:\Users\Dominic Cerquetti\AppData\Local\Programs\Microsoft VS Code\bin;C:\Program Files (x86)\Nmap;C:\Users\Dominic Cerquetti\AppData\Roaming\npm;C:\Users\Dominic Cerquetti\.dotnet\tools;D:\installs\msys64\mingw64\bin; +PATHEXT = .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC +PROCESSOR_ARCHITECTURE = x86 +PROCESSOR_ARCHITEW6432 = AMD64 +PROCESSOR_IDENTIFIER = Intel64 Family 6 Model 158 Stepping 9, GenuineIntel +PROCESSOR_LEVEL = 6 +PROCESSOR_REVISION = 9e09 +ProgramData = C:\ProgramData +ProgramFiles = C:\Program Files (x86) +ProgramFiles(x86) = C:\Program Files (x86) +ProgramW6432 = C:\Program Files +PROMPT = $P$G +PSModulePath = C:\Program Files (x86)\WindowsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules;C:\Program Files (x86)\AutoIt3\AutoItX +PUBLIC = C:\Users\Public +SESSIONNAME = Console +SystemDrive = C: +SystemRoot = C:\Windows +TEMP = C:\Users\DOMINI~1\AppData\Local\Temp +TMP = C:\Users\DOMINI~1\AppData\Local\Temp +USERDOMAIN = LAPTOP-DOM-CERQ +USERDOMAIN_ROAMINGPROFILE = LAPTOP-DOM-CERQ +USERNAME = Dominic Cerquetti +USERPROFILE = C:\Users\Dominic Cerquetti +VBOX_MSI_INSTALL_PATH = C:\Program Files\Oracle\VirtualBox\ +windir = C:\Windows +WWISEROOT = C:\Program Files (x86)\Audiokinetic\Wwise 2019.2.4.7329 +WWISESDK = C:\Program Files (x86)\Audiokinetic\Wwise 2019.2.4.7329\SDK + +Process = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe" +MSBuild executable path = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe" +Command line arguments = ""C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe" -v:diag " +Current directory = "d:\projects\cthack\src\diztinguish" +MSBuild version = "16.7.0+b89cb5fde" +Project "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln" on node 1 (default targets). +Initial Properties: +_DirectorySolutionPropsBasePath = +_DirectorySolutionPropsFile = Directory.Solution.props +_DirectorySolutionTargetsBasePath = +_DirectorySolutionTargetsFile = Directory.Solution.targets +_GenerateRestoreGraphProjectEntryInputProperties = + ExcludeRestorePackageImports=true; + _RestoreSolutionFileUsed=true; + SolutionDir=d:\projects\cthack\src\diztinguish\; + SolutionName=DiztinGUIsh; + SolutionFileName=DiztinGUIsh.sln; + SolutionPath=d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln; + SolutionExt=.sln; + +_RestoreSolutionFileUsed = true +ALLUSERSPROFILE = C:\ProgramData +AndroidTargetsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\MDD\Android\V150\ +APPDATA = C:\Users\Dominic Cerquetti\AppData\Roaming +AspNetConfiguration = Debug +CommonProgramFiles = C:\Program Files (x86)\Common Files +CommonProgramW6432 = C:\Program Files\Common Files +COMPUTERNAME = LAPTOP-DOM-CERQ +ComSpec = C:\Windows\system32\cmd.exe +Configuration = Debug +CurrentSolutionConfigurationContents = + Debug|AnyCPU + +DriverData = C:\Windows\System32\Drivers\DriverData +FPS_BROWSER_APP_PROFILE_STRING = Internet Explorer +FPS_BROWSER_USER_PROFILE_STRING = Default +FrameworkSDKRoot = C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\ +HideWarningsAndErrors = false +HOMEDRIVE = C: +HOMEPATH = \Users\Dominic Cerquetti +iOSTargetsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\MDD\iOS\V150\ +IsRestoreTargetsFileLoaded = true +LOCALAPPDATA = C:\Users\Dominic Cerquetti\AppData\Local +LOGONSERVER = \\LAPTOP-DOM-CERQ +MSBuildAllProjects = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\SolutionFile\ImportAfter\Microsoft.NuGet.Solution.ImportAfter.targets;;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.targets +MSBuildAssemblyVersion = 16.0 +MSBuildBinPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin +MSBuildExtensionsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild +MSBuildExtensionsPath32 = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild +MSBuildExtensionsPath64 = C:\Program Files\MSBuild +MSBuildFrameworkToolsPath = C:\Windows\Microsoft.NET\Framework\v4.0.30319\ +MSBuildFrameworkToolsPath32 = C:\Windows\Microsoft.NET\Framework\v4.0.30319\ +MSBuildFrameworkToolsPath64 = C:\Windows\Microsoft.NET\Framework64\v4.0.30319\ +MSBuildFrameworkToolsRoot = C:\Windows\Microsoft.NET\Framework\ +MSBuildLoadMicrosoftTargetsReadOnly = true +MSBuildNodeCount = 1 +MSBuildProgramFiles32 = C:\Program Files (x86) +MSBuildProjectDefaultTargets = Build +MSBuildProjectDirectory = d:\projects\cthack\src\diztinguish +MSBuildProjectDirectoryNoRoot = projects\cthack\src\diztinguish +MSBuildProjectExtension = .metaproj +MSBuildProjectFile = DiztinGUIsh.sln.metaproj +MSBuildProjectFullPath = d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln.metaproj +MSBuildProjectName = DiztinGUIsh.sln +MSBuildRuntimeType = Full +MSBuildRuntimeVersion = 4.0.30319 +MSBuildSDKsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Sdks +MSBuildStartupDirectory = d:\projects\cthack\src\diztinguish +MSBuildToolsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin +MSBuildToolsPath32 = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin +MSBuildToolsPath64 = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\amd64 +MSBuildToolsRoot = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild +MSBuildToolsVersion = Current +MSBuildUserExtensionsPath = C:\Users\Dominic Cerquetti\AppData\Local\Microsoft\MSBuild +MSBuildVersion = 16.7.0 +NDI_RUNTIME_DIR_V2 = C:\Program Files\NewTek\NDI 4 Runtime\v4 +NDI_RUNTIME_DIR_V3 = C:\Program Files\NewTek\NDI 4 Runtime\v4 +NDI_RUNTIME_DIR_V4 = C:\Program Files\NewTek\NDI 4 Runtime\v4 +NuGetInteractive = +NuGetRestoreTargets = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\..\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.targets +NUMBER_OF_PROCESSORS = 8 +OneDrive = C:\Users\Dominic Cerquetti\OneDrive - AA Recycle II LLC +OneDriveCommercial = C:\Users\Dominic Cerquetti\OneDrive - AA Recycle II LLC +OS = Windows_NT +PackageDownloadSupported = true +Path = D:\installs\msys64\mingw64\bin;D:\installs\msys64\usr\bin\;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\Microsoft SQL Server\130\Tools\Binn\;C:\Program Files\Perforce\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR;C:\Program Files\PuTTY\;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\;C:\Program Files\Git\cmd;C:\Program Files\nodejs\;C:\Program Files\dotnet\;C:\Users\Dominic Cerquetti\AppData\Local\Microsoft\WindowsApps;C:\Users\Dominic Cerquetti\.dotnet\tools;C:\Users\Dominic Cerquetti\.platformio\penv\Scripts\;C:\Users\Dominic Cerquetti\AppData\Local\Programs\Python\Python38-32\python.exe;C:\Users\Dominic Cerquetti\AppData\Local\Programs\Microsoft VS Code\bin;C:\Program Files (x86)\Nmap;C:\Users\Dominic Cerquetti\AppData\Roaming\npm;C:\Users\Dominic Cerquetti\.dotnet\tools;D:\installs\msys64\mingw64\bin; +PATHEXT = .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC +Platform = Any CPU +PROCESSOR_ARCHITECTURE = x86 +PROCESSOR_ARCHITEW6432 = AMD64 +PROCESSOR_IDENTIFIER = Intel64 Family 6 Model 158 Stepping 9, GenuineIntel +PROCESSOR_LEVEL = 6 +PROCESSOR_REVISION = 9e09 +ProgramData = C:\ProgramData +ProgramFiles = C:\Program Files (x86) +ProgramW6432 = C:\Program Files +PROMPT = $P$G +PSModulePath = C:\Program Files (x86)\WindowsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules;C:\Program Files (x86)\AutoIt3\AutoItX +PUBLIC = C:\Users\Public +RestoreBuildInParallel = true +RestoreContinueOnError = WarnAndContinue +RestoreRecursive = true +RestoreTaskAssemblyFile = NuGet.Build.Tasks.dll +RestoreUseSkipNonexistentTargets = true +RoslynTargetsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Roslyn +SDK35ToolsPath = C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\ +SDK40ToolsPath = C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\ +SESSIONNAME = Console +SolutionDir = d:\projects\cthack\src\diztinguish\ +SolutionExt = .sln +SolutionFileName = DiztinGUIsh.sln +SolutionName = DiztinGUIsh +SolutionPath = d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln +SystemDrive = C: +SystemRoot = C:\Windows +TargetFrameworkVersion = v4.0 +TEMP = C:\Users\DOMINI~1\AppData\Local\Temp +TMP = C:\Users\DOMINI~1\AppData\Local\Temp +USERDOMAIN = LAPTOP-DOM-CERQ +USERDOMAIN_ROAMINGPROFILE = LAPTOP-DOM-CERQ +USERNAME = Dominic Cerquetti +USERPROFILE = C:\Users\Dominic Cerquetti +ValidateRuntimeIdentifierCompatibility = false +VBOX_MSI_INSTALL_PATH = C:\Program Files\Oracle\VirtualBox\ +VCTargetsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VC\v160\ +VCTargetsPath10 = C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\ +VCTargetsPath11 = C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V110\ +VCTargetsPath12 = C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\ +VCTargetsPath14 = C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\ +VisualStudioVersion = 16.0 +VsInstallRoot = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community +windir = C:\Windows +WindowsSDK80Path = +WWISEROOT = C:\Program Files (x86)\Audiokinetic\Wwise 2019.2.4.7329 +WWISESDK = C:\Program Files (x86)\Audiokinetic\Wwise 2019.2.4.7329\SDK + +Initial Items: +ProjectReference + d:\projects\cthack\src\diztinguish\DiztinGUIsh\DiztinGUIsh.csproj + ToolsVersion = + SkipNonexistentProjects = False + AdditionalProperties = Configuration=Debug; Platform=AnyCPU + Configuration = Debug + Platform = AnyCPU +SolutionConfiguration + Debug|Any CPU + Configuration = Debug + Platform = Any CPU + Content = + Debug|AnyCPU + + Release|Any CPU + Configuration = Release + Platform = Any CPU + Content = + Release|AnyCPU + + +Building with tools version "Current". +Target "ValidateSolutionConfiguration: (TargetId:2)" in file "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln.metaproj" from project "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln" (entry point): +Task "Error" skipped, due to false condition; (('$(CurrentSolutionConfigurationContents)' == '') and ('$(SkipInvalidConfigurations)' != 'true')) was evaluated as ((' + Debug|AnyCPU +' == '') and ('' != 'true')). +Task "Warning" skipped, due to false condition; (('$(CurrentSolutionConfigurationContents)' == '') and ('$(SkipInvalidConfigurations)' == 'true')) was evaluated as ((' + Debug|AnyCPU +' == '') and ('' == 'true')). +Using "Message" task from assembly "Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a". +Task "Message" (TaskId:2) + Task Parameter:Text=Building solution configuration "Debug|Any CPU". (TaskId:2) + Building solution configuration "Debug|Any CPU". (TaskId:2) +Done executing task "Message". (TaskId:2) +Done building target "ValidateSolutionConfiguration" in project "DiztinGUIsh.sln".: (TargetId:2) +Target "ValidateToolsVersions: (TargetId:3)" in file "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln.metaproj" from project "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln" (entry point): +Task "Error" skipped, due to false condition; ('$(MSBuildToolsVersion)' == '2.0' and ('$(ProjectToolsVersion)' != '2.0' and '$(ProjectToolsVersion)' != '')) was evaluated as ('Current' == '2.0' and ('' != '2.0' and '' != '')). +Done building target "ValidateToolsVersions" in project "DiztinGUIsh.sln".: (TargetId:3) +Target "ValidateProjects: (TargetId:4)" in file "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln.metaproj" from project "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln" (entry point): +Done building target "ValidateProjects" in project "DiztinGUIsh.sln".: (TargetId:4) +Target "Build: (TargetId:5)" in file "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln.metaproj" from project "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln" (entry point): +Using "MSBuild" task from assembly "Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a". +Task "MSBuild" (TaskId:3) + Task Parameter: + Projects= + d:\projects\cthack\src\diztinguish\DiztinGUIsh\DiztinGUIsh.csproj + AdditionalProperties=Configuration=Debug; Platform=AnyCPU + Configuration=Debug + Platform=AnyCPU + SkipNonexistentProjects=False + ToolsVersion= (TaskId:3) + Task Parameter:BuildInParallel=True (TaskId:3) + Task Parameter: + Properties= + BuildingSolutionFile=true + CurrentSolutionConfigurationContents= + Debug|AnyCPU + + SolutionDir=d:\projects\cthack\src\diztinguish\ + SolutionExt=.sln + SolutionFileName=DiztinGUIsh.sln + SolutionName=DiztinGUIsh + SolutionPath=d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln (TaskId:3) + Task Parameter:SkipNonexistentProjects=False (TaskId:3) + Global Properties: (TaskId:3) + BuildingSolutionFile=true (TaskId:3) + CurrentSolutionConfigurationContents= + Debug|AnyCPU + (TaskId:3) + SolutionDir=d:\projects\cthack\src\diztinguish\ (TaskId:3) + SolutionExt=.sln (TaskId:3) + SolutionFileName=DiztinGUIsh.sln (TaskId:3) + SolutionName=DiztinGUIsh (TaskId:3) + SolutionPath=d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln (TaskId:3) + Additional Properties for project "d:\projects\cthack\src\diztinguish\DiztinGUIsh\DiztinGUIsh.csproj": (TaskId:3) + Configuration=Debug (TaskId:3) + Platform=AnyCPU (TaskId:3) +Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild +Trying to import C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\$(MSBuildToolsVersion)\Microsoft.Common.props using extensions path C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild +Property reassignment: $(MSBuildProjectExtensionsPath)="d:\projects\cthack\src\diztinguish\DiztinGUIsh\obj\" (previous value: "obj\") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Microsoft.Common.props (56,5) +Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild +Trying to import C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\$(MSBuildToolsVersion)\Imports\Microsoft.Common.props\ImportBefore\* using extensions path C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild +Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild +The "Configuration" property is a global property, and cannot be modified. +The "Platform" property is a global property, and cannot be modified. +Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild +Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild +The "Configuration" property is a global property, and cannot be modified. +The "Platform" property is a global property, and cannot be modified. +Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild +Property reassignment: $(DefineCommonItemSchemas)="false" (previous value: "true") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\Managed\Microsoft.Managed.DesignTime.targets (12,5) +Property reassignment: $(DefineCommonCapabilities)="false" (previous value: "true") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\Managed\Microsoft.Managed.DesignTime.targets (13,5) +Property reassignment: $(DefineCommonReferenceSchemas)="false" (previous value: "true") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\Managed\Microsoft.Managed.DesignTime.targets (14,5) +Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild +Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild +Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild +Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild +The "Configuration" property is a global property, and cannot be modified. +The "Platform" property is a global property, and cannot be modified. +Property reassignment: $(_DebugSymbolsProduced)="true" (previous value: "false") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets (149,5) +Property reassignment: $(_DocumentationFileProduced)="false" (previous value: "true") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets (158,5) +The "SolutionName" property is a global property, and cannot be modified. +The "SolutionFileName" property is a global property, and cannot be modified. +The "SolutionPath" property is a global property, and cannot be modified. +The "SolutionDir" property is a global property, and cannot be modified. +The "SolutionExt" property is a global property, and cannot be modified. +Property reassignment: $(_DeploymentUrl)="publish\" (previous value: "") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets (432,5) +Property reassignment: $(_DeploymentUrl)="publish\DiztinGUIsh.application" (previous value: "publish\") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets (434,5) +Property reassignment: $(_DeploymentUrl)="" (previous value: "publish\DiztinGUIsh.application") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets (441,5) +Property reassignment: $(ProcessorArchitecture)="msil" (previous value: "AnyCPU") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets (473,5) +Property reassignment: $(DelaySign)="" (previous value: "false") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets (527,5) +Property reassignment: $(_SGenGenerateSerializationAssembliesConfig)="Auto" (previous value: "") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets (3491,5) +Property reassignment: $(_SGenGenerateSerializationAssembliesConfig)="Off" (previous value: "Auto") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets (3492,5) +Property reassignment: $(PrepareForRunDependsOn)=" + CopyFilesToOutputDirectory + ;RunCodeAnalysis" (previous value: " + CopyFilesToOutputDirectory + ") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\v16.0\CodeAnalysis\Microsoft.CodeAnalysis.targets (199,9) +Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild +Property reassignment: $(ResolveReferencesDependsOn)=" + + BeforeResolveReferences; + AssignProjectConfiguration; + ResolveProjectReferences; + FindInvalidProjectReferences; + ResolveNativeReferences; + ResolveAssemblyReferences; + GenerateBindingRedirects; + ResolveComReferences; + AfterResolveReferences + ; + ImplicitlyExpandDesignTimeFacades + " (previous value: " + BeforeResolveReferences; + AssignProjectConfiguration; + ResolveProjectReferences; + FindInvalidProjectReferences; + ResolveNativeReferences; + ResolveAssemblyReferences; + GenerateBindingRedirects; + ResolveComReferences; + AfterResolveReferences + ") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.NETFramework.CurrentVersion.targets (75,5) +Property reassignment: $(PrepareResourceNamesDependsOn)=" + AssignWinFXEmbeddedResource; + + AssignTargetPaths; + SplitResourcesByCulture; + CreateManifestResourceNames; + CreateCustomManifestResourceNames + + " (previous value: " + AssignTargetPaths; + SplitResourcesByCulture; + CreateManifestResourceNames; + CreateCustomManifestResourceNames + ") at C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.WinFx.targets (97,7) +Property reassignment: $(PrepareResourcesDependsOn)=" + MarkupCompilePass1; + AfterMarkupCompilePass1; + MarkupCompilePass2ForMainAssembly; + FileClassification; + MainResourcesGeneration; + + ; + PrepareResourceNames; + ResGen; + CompileLicxFiles + + " (previous value: " + ; + PrepareResourceNames; + ResGen; + CompileLicxFiles + ") at C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.WinFx.targets (108,7) +Property reassignment: $(CompileDependsOn)=" + + ResolveReferences; + ResolveKeySource; + SetWin32ManifestProperties; + FindReferenceAssembliesForReferences; + _GenerateCompileInputs; + BeforeCompile; + _TimeStampBeforeCompile; + _GenerateCompileDependencyCache; + CoreCompile; + _TimeStampAfterCompile; + AfterCompile; + ; + _AfterCompileWinFXInternal + " (previous value: " + ResolveReferences; + ResolveKeySource; + SetWin32ManifestProperties; + FindReferenceAssembliesForReferences; + _GenerateCompileInputs; + BeforeCompile; + _TimeStampBeforeCompile; + _GenerateCompileDependencyCache; + CoreCompile; + _TimeStampAfterCompile; + AfterCompile; + ") at C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.WinFx.targets (184,5) +Property reassignment: $(PublishBuildDependsOn)=" + BuildOnlySettings; + PrepareForBuild; + ResolveReferences; + PrepareResources; + ResolveKeySource; + PrepareResourcesForSatelliteAssemblies; + GenerateSerializationAssemblies; + CreateSatelliteAssemblies; + " (previous value: " + BuildOnlySettings; + PrepareForBuild; + ResolveReferences; + PrepareResources; + ResolveKeySource; + GenerateSerializationAssemblies; + CreateSatelliteAssemblies; + ") at C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.WinFx.targets (813,9) +Property reassignment: $(BuildDependsOn)=" + EntityDeploy; + + BeforeBuild; + CoreBuild; + AfterBuild + + " (previous value: " + BeforeBuild; + CoreBuild; + AfterBuild + ") at C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Data.Entity.targets (35,5) +Property reassignment: $(CleanDependsOn)=" + + BeforeClean; + UnmanagedUnregistration; + CoreClean; + CleanReferencedProjects; + CleanPublishFolder; + AfterClean + ; + EntityClean; + " (previous value: " + BeforeClean; + UnmanagedUnregistration; + CoreClean; + CleanReferencedProjects; + CleanPublishFolder; + AfterClean + ") at C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Data.Entity.targets (42,5) +Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild +Property reassignment: $(PrepareResourcesDependsOn)=" + XamlMarkupCompilePass1; + XamlMarkupCompilePass2; + + MarkupCompilePass1; + AfterMarkupCompilePass1; + MarkupCompilePass2ForMainAssembly; + FileClassification; + MainResourcesGeneration; + + ; + PrepareResourceNames; + ResGen; + CompileLicxFiles + + + " (previous value: " + MarkupCompilePass1; + AfterMarkupCompilePass1; + MarkupCompilePass2ForMainAssembly; + FileClassification; + MainResourcesGeneration; + + ; + PrepareResourceNames; + ResGen; + CompileLicxFiles + + ") at C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Xaml.targets (35,5) +Property reassignment: $(PrepareResourcesDependsOn)=" + ValidationExtension; + ExpressionBuildExtension; + + XamlMarkupCompilePass1; + XamlMarkupCompilePass2; + + MarkupCompilePass1; + AfterMarkupCompilePass1; + MarkupCompilePass2ForMainAssembly; + FileClassification; + MainResourcesGeneration; + + ; + PrepareResourceNames; + ResGen; + CompileLicxFiles + + + + " (previous value: " + XamlMarkupCompilePass1; + XamlMarkupCompilePass2; + + MarkupCompilePass1; + AfterMarkupCompilePass1; + MarkupCompilePass2ForMainAssembly; + FileClassification; + MainResourcesGeneration; + + ; + PrepareResourceNames; + ResGen; + CompileLicxFiles + + + ") at C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.WorkflowBuildExtensions.targets (16,5) +Property reassignment: $(ResolveReferencesDependsOn)=" + + + BeforeResolveReferences; + AssignProjectConfiguration; + ResolveProjectReferences; + FindInvalidProjectReferences; + ResolveNativeReferences; + ResolveAssemblyReferences; + GenerateBindingRedirects; + ResolveComReferences; + AfterResolveReferences + ; + ImplicitlyExpandDesignTimeFacades + ; + ResolveTestReferences + " (previous value: " + + BeforeResolveReferences; + AssignProjectConfiguration; + ResolveProjectReferences; + FindInvalidProjectReferences; + ResolveNativeReferences; + ResolveAssemblyReferences; + GenerateBindingRedirects; + ResolveComReferences; + AfterResolveReferences + ; + ImplicitlyExpandDesignTimeFacades + ") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\v16.0\TeamTest\Microsoft.TeamTest.targets (4,5) +Property reassignment: $(MSBuildAllProjects)=";C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Xaml.targets;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.targets" (previous value: ";C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Xaml.targets") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.targets (45,5) +Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild +Trying to import C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\$(MSBuildToolsVersion)\Microsoft.Common.targets\ImportAfter\* using extensions path C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild +Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild +Trying to import C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Sdks\Microsoft.Docker.Sdk\build\Microsoft.Docker.targets using extensions path C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild +Property reassignment: $(MSBuildAllProjects)=";C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Xaml.targets;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.targets;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\NuGet\16.0\Microsoft.NuGet.targets" (previous value: ";C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Xaml.targets;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.targets") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\NuGet\16.0\Microsoft.NuGet.targets (67,5) +Property reassignment: $(ResolveAssemblyReferencesDependsOn)=" + ResolveProjectReferences; + FindInvalidProjectReferences; + GetFrameworkPaths; + GetReferenceAssemblyPaths; + PrepareForBuild; + ResolveSDKReferences; + ExpandSDKReferences; + ;ResolveNuGetPackageAssets" (previous value: " + ResolveProjectReferences; + FindInvalidProjectReferences; + GetFrameworkPaths; + GetReferenceAssemblyPaths; + PrepareForBuild; + ResolveSDKReferences; + ExpandSDKReferences; + ") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\NuGet\16.0\Microsoft.NuGet.targets (173,5) +Property reassignment: $(PrepareResourcesDependsOn)="ResolveNuGetPackageAssets; + ValidationExtension; + ExpressionBuildExtension; + + XamlMarkupCompilePass1; + XamlMarkupCompilePass2; + + MarkupCompilePass1; + AfterMarkupCompilePass1; + MarkupCompilePass2ForMainAssembly; + FileClassification; + MainResourcesGeneration; + + ; + PrepareResourceNames; + ResGen; + CompileLicxFiles + + + + " (previous value: " + ValidationExtension; + ExpressionBuildExtension; + + XamlMarkupCompilePass1; + XamlMarkupCompilePass2; + + MarkupCompilePass1; + AfterMarkupCompilePass1; + MarkupCompilePass2ForMainAssembly; + FileClassification; + MainResourcesGeneration; + + ; + PrepareResourceNames; + ResGen; + CompileLicxFiles + + + + ") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\NuGet\16.0\Microsoft.NuGet.targets (174,5) +Property reassignment: $(_HandlePackageFileConflictsAfter)="ResolveNuGetPackageAssets;ResolveNuGetPackageAssetsNonAOT" (previous value: "ResolveNuGetPackageAssets") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\NuGet\16.0\Microsoft.NuGet.targets (255,5) +Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild +Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild +Property reassignment: $(CoreCompileDependsOn)=" + GitInfo; + GitVersion; + GitThisAssembly; + GitInfoReport; + ;_ComputeNonExistentFileProperty;ResolveCodeAnalysisRuleSet + " (previous value: ";_ComputeNonExistentFileProperty;ResolveCodeAnalysisRuleSet") at d:\projects\cthack\src\diztinguish\packages\GitInfo.2.1.1\build\GitInfo.targets (125,3) +Overriding target "ResolveFrameworkReferences" in project "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\Managed\Microsoft.Managed.DesignTime.targets" with target "ResolveFrameworkReferences" from project "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets". +Overriding target "GetFrameworkPaths" in project "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets" with target "GetFrameworkPaths" from project "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.NETFramework.CurrentVersion.targets". +Overriding target "SatelliteDllsProjectOutputGroup" in project "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets" with target "SatelliteDllsProjectOutputGroup" from project "C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.WinFx.targets". +Overriding target "GenerateCompiledExpressionsTempFile" in project "C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.WorkflowBuildExtensions.targets" with target "GenerateCompiledExpressionsTempFile" from project "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.WorkflowBuildExtensions.targets". +Overriding target "CollectPackageReferences" in project "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\Managed\Microsoft.Managed.DesignTime.targets" with target "CollectPackageReferences" from project "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.targets". +The target "ClCompile" listed in an AfterTargets attribute at "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\v16.0\CodeAnalysis\Microsoft.CodeAnalysis.targets (478,11)" does not exist in the project, and will be ignored. +Project "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln" (1) is building "d:\projects\cthack\src\diztinguish\DiztinGUIsh\DiztinGUIsh.csproj" (2) on node 1 (default targets). +Initial Properties: +_AfterCompileWinFXInternalDependsOn = + PrepareResourcesForSatelliteAssemblies; + MergeLocalizationDirectives; + AfterCompileWinFX + +_CommitDateFormat = %%cI +_CompileTargetNameForLocalType = _CompileTemporaryAssembly +_DebugSymbolsProduced = true +_DeploymentApplicationManifestIdentity = DiztinGUIsh.exe +_DeploymentBuiltUpdateInterval = 0 +_DeploymentBuiltUpdateIntervalUnits = Days +_DeploymentDeployManifestIdentity = DiztinGUIsh.application +_DeploymentFileMappingExtension = .deploy +_DeploymentPublishableProjectDefault = true +_DeploymentTargetApplicationManifestFileName = DiztinGUIsh.exe.manifest +_DeploymentUrl = +_DirectoryBuildPropsBasePath = +_DirectoryBuildPropsFile = Directory.Build.props +_DirectoryBuildTargetsBasePath = +_DirectoryBuildTargetsFile = Directory.Build.targets +_DirectoryPackagesPropsBasePath = +_DirectoryPackagesPropsFile = Directory.Packages.props +_DocumentationFileProduced = false +_GenerateBindingRedirectsIntermediateAppConfig = obj\Debug\DiztinGUIsh.exe.config +_GenerateRestoreGraphProjectEntryInputProperties = ExcludeRestorePackageImports=true +_GetChildProjectCopyToOutputDirectoryItems = true +_GitInfoFile = obj\Debug\GitInfo.cache +_HandlePackageFileConflictsAfter = ResolveNuGetPackageAssets;ResolveNuGetPackageAssetsNonAOT +_HandlePackageFileConflictsBefore = ResolveAssemblyReferences +_InitialBaseIntermediateOutputPath = obj\ +_InitialMSBuildProjectExtensionsPath = d:\projects\cthack\src\diztinguish\DiztinGUIsh\obj\ +_LongShaFormat = %%H +_MaxSupportedLangVersion = 7.3 +_NuGetRuntimeIdentifierWithoutAot = win +_OriginalConfiguration = Debug +_OriginalPlatform = AnyCPU +_ProjectDefaultTargets = Build +_RecursiveTargetForContentCopying = GetCopyToOutputDirectoryItems +_RequireMCPass2ForMainAssembly = false +_RequireMCPass2ForSatelliteAssemblyOnly = false +_ResolveReferenceDependencies = false +_ResourceNameInMainAssembly = DiztinGUIsh.g.resources +_SGenDllCreated = false +_SGenDllName = DiztinGUIsh.XmlSerializers.dll +_SGenGenerateSerializationAssembliesConfig = Off +_ShortShaFormat = %%h +_TargetFrameworkVersionWithoutV = 4.8 +_TargetsThatPrepareProjectReferences = _SplitProjectReferencesByFileExistence +AddAdditionalExplicitAssemblyReferences = true +AddAppConfigToBuildOutputs = true +AddItemTemplatesGuid = {FAE04EC0-301F-11d3-BF4B-00C04F79EFBC} +AdditionalExplicitAssemblyReferences = System.Core; +AllowedReferenceAssemblyFileExtensions = + .winmd; + .dll; + .exe + +AllowedReferenceRelatedFileExtensions = + .pdb; + .xml; + .pri; + .dll.config; + .exe.config + +ALLUSERSPROFILE = C:\ProgramData +AlwaysCompileMarkupFilesInSeparateDomain = true +AlwaysUseNumericalSuffixInItemNames = true +AndroidTargetsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\MDD\Android\V150\ +APPDATA = C:\Users\Dominic Cerquetti\AppData\Roaming +AppDesignerFolder = Properties +AppDesignerFolderContentsVisibleOnlyInShowAllFiles = false +ApplicationIcon = diz-4.ico +ApplicationRevision = 0 +ApplicationVersion = 1.0.0.* +AssemblyFoldersConfigFile = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\AssemblyFolders.config +AssemblyFoldersConfigFileSearchPath = {AssemblyFoldersFromConfig:C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\AssemblyFolders.config,v4.8}; +AssemblyFoldersSuffix = AssemblyFoldersEx +AssemblyName = DiztinGUIsh +AssemblySearchPaths = + {CandidateAssemblyFiles}; + ; + {HintPathFromItem}; + {TargetFrameworkDirectory}; + {AssemblyFoldersFromConfig:C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\AssemblyFolders.config,v4.8}; + {Registry:Software\Microsoft\.NETFramework,v4.8,AssemblyFoldersEx}; + {AssemblyFolders}; + {GAC}; + {RawFileName}; + bin\Debug\ + +AssignTargetPathsDependsOn = +AutoGenerateBindingRedirects = true +AutoUnifyAssemblyReferences = true +AvailablePlatforms = Any CPU,x86,x64 +BaseIntermediateOutputPath = obj\ +BaseNuGetRuntimeIdentifier = win +BootstrapperEnabled = true +BootstrapperUrlHistory = +BuildCompileAction = Build +BuildDependsOn = + EntityDeploy; + + BeforeBuild; + CoreBuild; + AfterBuild + + +BuildGenerateSourcesAction = Build +BuildingProject = false +BuildingSolutionFile = true +BuildInParallel = true +BuildLinkAction = Build +BuildProjectReferences = true +BuildSystem = MSBuild +BuildTaskAssembly = PresentationBuildTasks, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 +BuiltProjectOutputGroupDependenciesDependsOn = + ; + + ; + BuildOnlySettings; + PrepareForBuild; + AssignTargetPaths; + ResolveReferences + + +BuiltProjectOutputGroupDependsOn = PrepareForBuild +CleanDependsOn = + + BeforeClean; + UnmanagedUnregistration; + CoreClean; + CleanReferencedProjects; + CleanPublishFolder; + AfterClean + ; + EntityClean; + +CleanFile = DiztinGUIsh.csproj.FileListAbsolute.txt +CmdUIContextGuid = {FAE04EC1-301F-11d3-BF4B-00C04F79EFBC} +CodeAnalysisApplyLogFileXsl = false +CodeAnalysisFailOnMissingRules = false +CodeAnalysisForceOutput = true +CodeAnalysisGenerateSuccessFile = true +CodeAnalysisIgnoreGeneratedCode = true +CodeAnalysisIgnoreInvalidTargets = true +CodeAnalysisIgnoreMissingIndirectReferences = false +CodeAnalysisInputAssembly = bin\Debug\DiztinGUIsh.exe +CodeAnalysisLogFile = bin\Debug\DiztinGUIsh.exe.CodeAnalysisLog.xml +CodeAnalysisModuleSuppressionsFile = GlobalSuppressions.cs +CodeAnalysisOutputToConsole = false +CodeAnalysisOverrideRuleVisibilities = false +CodeAnalysisPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Team Tools\Static Analysis Tools\FxCop\ +CodeAnalysisQuiet = false +CodeAnalysisRuleDirectories = ;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Team Tools\Static Analysis Tools\FxCop\\Rules +CodeAnalysisRuleSet = MinimumRecommendedRules.ruleset +CodeAnalysisRuleSetDirectories = ;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Team Tools\Static Analysis Tools\\Rule Sets +CodeAnalysisSaveMessagesToReport = Active +CodeAnalysisSearchGlobalAssemblyCache = true +CodeAnalysisStaticAnalysisDirectory = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Team Tools\Static Analysis Tools\ +CodeAnalysisSucceededFile = bin\Debug\DiztinGUIsh.exe.lastcodeanalysissucceeded +CodeAnalysisSummary = false +CodeAnalysisTargets = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\v16.0\CodeAnalysis\Microsoft.CodeAnalysis.targets +CodeAnalysisTimeout = 120 +CodeAnalysisTreatWarningsAsErrors = false +CodeAnalysisUpdateProject = false +CodeAnalysisUseTypeNameInSuppression = true +CodeAnalysisVerbose = false +CommonOutputGroupsDependsOn = + ; + BuildOnlySettings; + PrepareForBuild; + AssignTargetPaths; + ResolveReferences + +CommonProgramFiles = C:\Program Files (x86)\Common Files +CommonProgramW6432 = C:\Program Files\Common Files +CommonTargetsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets +CommonXamlResourcesDirectory = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\\ +CompileDependsOn = + + ResolveReferences; + ResolveKeySource; + SetWin32ManifestProperties; + FindReferenceAssembliesForReferences; + _GenerateCompileInputs; + BeforeCompile; + _TimeStampBeforeCompile; + _GenerateCompileDependencyCache; + CoreCompile; + _TimeStampAfterCompile; + AfterCompile; + ; + _AfterCompileWinFXInternal + +CompileLicxFilesDependsOn = +CompileTargetNameForTemporaryAssembly = CompileTemporaryAssembly +ComputeIntermediateSatelliteAssembliesDependsOn = + CreateManifestResourceNames + +COMPUTERNAME = LAPTOP-DOM-CERQ +ComReferenceExecuteAsTool = false +ComReferenceNoClassMembers = false +ComSpec = C:\Windows\system32\cmd.exe +Configuration = Debug +ConfigurationName = Debug +ConsiderPlatformAsProcessorArchitecture = true +ContentFilesProjectOutputGroupDependsOn = PrepareForBuild;AssignTargetPaths +ContinueOnError = false +CopyNuGetImplementations = true +CoreBuildDependsOn = + BuildOnlySettings; + PrepareForBuild; + PreBuildEvent; + ResolveReferences; + PrepareResources; + ResolveKeySource; + Compile; + ExportWindowsMDFile; + UnmanagedUnregistration; + GenerateSerializationAssemblies; + CreateSatelliteAssemblies; + GenerateManifests; + GetTargetPath; + PrepareForRun; + UnmanagedRegistration; + IncrementalClean; + PostBuildEvent + +CoreCleanDependsOn = +CoreCompileDependsOn = + GitInfo; + GitVersion; + GitThisAssembly; + GitInfoReport; + ;_ComputeNonExistentFileProperty;ResolveCodeAnalysisRuleSet + +CoreResGenDependsOn = FindReferenceAssembliesForReferences +CreateCustomManifestResourceNamesDependsOn = +CreateHardLinksForCopyAdditionalFilesIfPossible = false +CreateManifestResourceNamesDependsOn = +CreateSatelliteAssembliesDependsOn = + _GenerateSatelliteAssemblyInputs; + ComputeIntermediateSatelliteAssemblies; + GenerateSatelliteAssemblies + +CreateSymbolicLinksForCopyAdditionalFilesIfPossible = false +CSharpCoreTargetsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Roslyn\Microsoft.CSharp.Core.targets +CSharpDesignTimeTargetsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\Managed\Microsoft.CSharp.DesignTime.targets +CSharpTargetsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.CSharp.CurrentVersion.targets +CurrentSolutionConfigurationContents = + Debug|AnyCPU + +CustomAfterMicrosoftCommonProps = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\vCurrent\Custom.After.Microsoft.Common.props +CustomAfterMicrosoftCommonTargets = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\vCurrent\Custom.After.Microsoft.Common.targets +CustomAfterMicrosoftCSharpTargets = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\vCurrent\Custom.After.Microsoft.CSharp.targets +CustomBeforeMicrosoftCommonProps = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\vCurrent\Custom.Before.Microsoft.Common.props +CustomBeforeMicrosoftCommonTargets = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\vCurrent\Custom.Before.Microsoft.Common.targets +CustomBeforeMicrosoftCSharpTargets = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\vCurrent\Custom.Before.Microsoft.CSharp.targets +DebuggerFlavor = ProjectDebugger +DebugSymbols = true +DebugSymbolsProjectOutputGroupDependenciesDependsOn = + ; + + ; + BuildOnlySettings; + PrepareForBuild; + AssignTargetPaths; + ResolveReferences + + +DebugSymbolsProjectOutputGroupDependsOn = +DebugType = full +DefaultLanguageSourceExtension = .cs +DefaultProjectTypeGuid = {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} +DeferredValidationErrorsFileName = obj\Debug\\AC2C1ABA-CCF6-44D4-8127-588FD4D0A860-DeferredValidationErrors.xml +DefineCommonCapabilities = false +DefineCommonItemSchemas = false +DefineCommonManagedCapabilities = true +DefineCommonManagedItemSchemas = true +DefineCommonManagedReferenceSchemas = true +DefineCommonReferenceSchemas = false +DefineConstants = DEBUG;TRACE +DefineCSharpItemSchemas = false +DelaySign = +DeploymentType = Installed +DesignerFunctionVisibility = Private +DesignerHiddenCodeGeneration = Declarations +DesignerRuntimeImplementationProjectOutputGroupDependsOn = + ; + + ; + BuildOnlySettings; + PrepareForBuild; + AssignTargetPaths; + ResolveReferences + + +DesignerVariableNaming = Camel +DesignTimeIntermediateOutputPath = obj\Debug\InProcessTempFiles\ +DesignTimeResolveAssemblyReferencesDependsOn = + GetFrameworkPaths; + GetReferenceAssemblyPaths; + ResolveReferences + +Deterministic = true +DevEnvDir = *Undefined* +DisableLogTaskParameter_ConvertToAbsolutePath_Path = true +DisableLogTaskParameter_FindUnderPath_OutOfPath = true +DisableLogTaskParameter_RemoveDuplicates_Inputs = true +DisableLogTaskParameterItemMetadata_ConvertToAbsolutePath_AbsolutePaths = true +DisableLogTaskParameterItemMetadata_Copy_CopiedFiles = true +DisableLogTaskParameterItemMetadata_Copy_DestinationFiles = true +DisableLogTaskParameterItemMetadata_Copy_SourceFiles = true +DisableLogTaskParameterItemMetadata_FindUnderPath_Files = true +DisableLogTaskParameterItemMetadata_FindUnderPath_InPath = true +DisableLogTaskParameterItemMetadata_GenerateResource_FilesWritten = true +DisableLogTaskParameterItemMetadata_Hash_ItemsToHash = true +DisableLogTaskParameterItemMetadata_RemoveDuplicates_Filtered = true +DisableLogTaskParameterItemMetadata_WriteLinesToFile_Lines = true +DockerBuildTasksAssembly = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Sdks\Microsoft.Docker.Sdk\build\..\tools\Microsoft.Docker.BuildTasks.dll +DockerIntermediateOutputPath = obj\Docker +DockerPublishDirectory = obj\Docker\publish +DocumentationProjectOutputGroupDependenciesDependsOn = + ; + + ; + BuildOnlySettings; + PrepareForBuild; + AssignTargetPaths; + ResolveReferences + + +DocumentationProjectOutputGroupDependsOn = +DriverData = C:\Windows\System32\Drivers\DriverData +EmbeddedWin32Manifest = +EntityDeployDependsOn = +EntityDeployIntermediateResourcePath = obj\Debug\edmxResourcesToEmbed\ +ErrorReport = prompt +ErrorReportUrlHistory = +ExpandSDKAllowedReferenceExtensions = + .winmd; + .dll + +ExpandSDKReferencesDependsOn = + ResolveSDKReferences + +FallbackCulture = en-US +FileAlignment = 512 +FindInvalidProjectReferencesDependsOn = + GetReferenceTargetPlatformMonikers + +FPS_BROWSER_APP_PROFILE_STRING = Internet Explorer +FPS_BROWSER_USER_PROFILE_STRING = Default +Framework20Dir = @(_TargetFramework20DirectoryItem) +Framework30Dir = @(_TargetFramework30DirectoryItem) +Framework35Dir = @(_TargetFramework35DirectoryItem) +Framework40Dir = @(_TargetFramework40DirectoryItem) +FrameworkDir = @(_TargetFramework40DirectoryItem) +FrameworkPathOverride = C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8 +FrameworkRegistryBase = Software\Microsoft\.NETFramework +FrameworkSDKDir = @(_TargetFrameworkSDKDirectoryItem) +FrameworkSDKRoot = C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\ +FullReferenceAssemblyNames = Full +GenerateBindingRedirectsOutputType = true +GenerateClickOnceManifests = +GenerateCompiledExpressionsTempFilePathForEditing = obj\Debug\\TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs +GenerateCompiledExpressionsTempFilePathForTypeInfer = obj\Debug\\TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs +GenerateCompiledExpressionsTempFilePathForValidation = obj\Debug\\TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs +GeneratedFileExtension = .g.cs +GeneratedMSBuildEditorConfigFile = DiztinGUIsh.GeneratedMSBuildEditorConfig.editorconfig +GenerateManifestsDependsOn = + SetWin32ManifestProperties; + GenerateApplicationManifest; + GenerateDeploymentManifest + +GenerateMSBuildEditorConfigFile = true +GenerateTargetFrameworkAttribute = true +GeneratorsTypeGuid = {FAE04EC1-301F-11d3-BF4B-00C04F79EFBC} +GetCopyToOutputDirectoryItemsDependsOn = + AssignTargetPaths; + _SplitProjectReferencesByFileExistence; + _GetProjectReferenceTargetFrameworkProperties; + _PopulateCommonStateForGetCopyToOutputDirectoryItems + +GetFrameworkPathsDependsOn = +GetReferenceAssemblyPathsDependsOn = + ; + GetWinFXPath + +GetTargetPathDependsOn = +GetTargetPathWithTargetPlatformMonikerDependsOn = +GitBaseVersionRegex = v?(?\d+)\.(?\d+)(?:\-(?

+ /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + internal static System.Drawing.Icon diz { + get { + object obj = ResourceManager.GetObject("diz", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap diz_4 { + get { + object obj = ResourceManager.GetObject("diz_4", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + internal static System.Drawing.Icon diz_41 { + get { + object obj = ResourceManager.GetObject("diz_41", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } } } diff --git a/DiztinGUIsh/Properties/Resources.resx b/DiztinGUIsh/Properties/Resources.resx index af7dbebb..24b377e2 100644 --- a/DiztinGUIsh/Properties/Resources.resx +++ b/DiztinGUIsh/Properties/Resources.resx @@ -46,7 +46,7 @@ mimetype: application/x-microsoft.net.object.binary.base64 value : The object must be serialized with - : System.Serialization.Formatters.Binary.BinaryFormatter + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter : and then encoded with base64 encoding. mimetype: application/x-microsoft.net.object.soap.base64 @@ -60,6 +60,7 @@ : and then encoded with base64 encoding. --> + @@ -68,9 +69,10 @@ - + + @@ -85,9 +87,10 @@ - + + @@ -109,9 +112,19 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\resource\diz.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\resource\diz-4.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\resource\diz-4.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs b/DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs index 05031285..5553d7fc 100644 --- a/DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs +++ b/DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs @@ -30,12 +30,14 @@ private void InitializeComponent() this.label1 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label(); this.progressBar1 = new System.Windows.Forms.ProgressBar(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); this.SuspendLayout(); // // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(11, 9); + this.label1.Location = new System.Drawing.Point(11, 264); this.label1.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(40, 13); @@ -45,7 +47,7 @@ private void InitializeComponent() // label2 // this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(69, 9); + this.label2.Location = new System.Drawing.Point(55, 264); this.label2.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(73, 13); @@ -54,18 +56,28 @@ private void InitializeComponent() // // progressBar1 // - this.progressBar1.Location = new System.Drawing.Point(8, 34); + this.progressBar1.Location = new System.Drawing.Point(11, 286); this.progressBar1.Margin = new System.Windows.Forms.Padding(2); this.progressBar1.Name = "progressBar1"; - this.progressBar1.Size = new System.Drawing.Size(319, 19); + this.progressBar1.Size = new System.Drawing.Size(255, 19); this.progressBar1.TabIndex = 2; // + // pictureBox1 + // + this.pictureBox1.Image = global::DiztinGUIsh.Properties.Resources.diz_4; + this.pictureBox1.Location = new System.Drawing.Point(7, 2); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(259, 259); + this.pictureBox1.TabIndex = 3; + this.pictureBox1.TabStop = false; + // // ProgressDialog // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(338, 63); + this.ClientSize = new System.Drawing.Size(272, 316); this.ControlBox = false; + this.Controls.Add(this.pictureBox1); this.Controls.Add(this.progressBar1); this.Controls.Add(this.label2); this.Controls.Add(this.label1); @@ -79,6 +91,7 @@ private void InitializeComponent() this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "Working..."; this.TopMost = true; + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -89,5 +102,6 @@ private void InitializeComponent() private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label2; private System.Windows.Forms.ProgressBar progressBar1; + private System.Windows.Forms.PictureBox pictureBox1; } } From e5220f44b4711a15628c9ec13e47c3386b5eab83 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 29 Sep 2020 16:13:28 -0400 Subject: [PATCH 047/136] WIP further refactoring - refactor bizhawk stuff into new improts section - more general cleanup - add observabledictionary for labels/comments - refactor/simplify aliaslist to take advantage of property change notifications - refactor ROM import code into better locations - separating more GUI stuff from business logic functions labels in asm export still not fixed, getting there though. --- DiztinGUIsh.sln.DotSettings | 2 + DiztinGUIsh/DiztinGUIsh.csproj | 4 + DiztinGUIsh/DiztinGUIsh.csproj.DotSettings | 2 + DiztinGUIsh/Model.cs | 30 + DiztinGUIsh/Properties/Annotations.cs | 1239 +++++++++++++++++ DiztinGUIsh/core/Data.cs | 470 +++---- DiztinGUIsh/core/LogCreator.cs | 66 +- DiztinGUIsh/core/Project.cs | 161 +-- DiztinGUIsh/core/ROMByte.cs | 2 +- DiztinGUIsh/core/import/BizHawkCdl.cs | 81 +- DiztinGUIsh/core/import/SampleRomData.cs | 288 ++-- DiztinGUIsh/core/util/ObservableDictionary.cs | 228 +++ DiztinGUIsh/core/util/RomUtil.cs | 13 + DiztinGUIsh/core/util/Util.cs | 72 +- .../binary_serializer_old/BinarySerializer.cs | 16 +- .../xml_serializer/ProjectXMLSerializer.cs | 9 +- .../xml_serializer/RomBytesXMLSerializer.cs | 2 +- DiztinGUIsh/window/AliasList.Designer.cs | 1 - DiztinGUIsh/window/AliasList.cs | 217 +-- DiztinGUIsh/window/IProjectView.cs | 4 +- DiztinGUIsh/window/MainWindow.cs | 251 ++-- DiztinGUIsh/window/MainWindow.resx | 3 - DiztinGUIsh/window/ProjectController.cs | 98 +- DiztinGUIsh/window/dialog/ImportROMDialog.cs | 6 +- DiztinGUIsh/window/dialog/MarkManyDialog.cs | 6 +- 25 files changed, 2431 insertions(+), 840 deletions(-) create mode 100644 DiztinGUIsh.sln.DotSettings create mode 100644 DiztinGUIsh/DiztinGUIsh.csproj.DotSettings create mode 100644 DiztinGUIsh/Model.cs create mode 100644 DiztinGUIsh/Properties/Annotations.cs create mode 100644 DiztinGUIsh/core/util/ObservableDictionary.cs create mode 100644 DiztinGUIsh/core/util/RomUtil.cs diff --git a/DiztinGUIsh.sln.DotSettings b/DiztinGUIsh.sln.DotSettings new file mode 100644 index 00000000..2c5807cc --- /dev/null +++ b/DiztinGUIsh.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 75439798..84c90a6a 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -113,12 +113,16 @@ + + + + diff --git a/DiztinGUIsh/DiztinGUIsh.csproj.DotSettings b/DiztinGUIsh/DiztinGUIsh.csproj.DotSettings new file mode 100644 index 00000000..6e7fff86 --- /dev/null +++ b/DiztinGUIsh/DiztinGUIsh.csproj.DotSettings @@ -0,0 +1,2 @@ + + No \ No newline at end of file diff --git a/DiztinGUIsh/Model.cs b/DiztinGUIsh/Model.cs new file mode 100644 index 00000000..18c9e1c8 --- /dev/null +++ b/DiztinGUIsh/Model.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using DiztinGUIsh.Annotations; + +namespace DiztinGUIsh +{ + public class DizModel : INotifyPropertyChanged + { + // this stuff lets other parts of code subscribe to events that get fired anytime + // properties of our class change. + // + // Just hook up SetField() to the 'set' param of any property you would like to + // expose to outside classes. + public event PropertyChangedEventHandler PropertyChanged; + protected bool SetField(ref T field, T value, [CallerMemberName] string propertyName = null) + { + if (EqualityComparer.Default.Equals(field, value)) return false; + field = value; + OnPropertyChanged(propertyName); + return true; + } + + [NotifyPropertyChangedInvocator] + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} diff --git a/DiztinGUIsh/Properties/Annotations.cs b/DiztinGUIsh/Properties/Annotations.cs new file mode 100644 index 00000000..71e20aff --- /dev/null +++ b/DiztinGUIsh/Properties/Annotations.cs @@ -0,0 +1,1239 @@ +// Note from Dom/Diztinguish: Jetbrains added this. Not sure we really need it, +// remove if you feel like it. probably won't hurt anything, just editor functionality. + +/* MIT License + +Copyright (c) 2016 JetBrains http://www.jetbrains.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. */ + +using System; +// ReSharper disable InheritdocConsiderUsage + +#pragma warning disable 1591 +// ReSharper disable UnusedMember.Global +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable IntroduceOptionalParameters.Global +// ReSharper disable MemberCanBeProtected.Global +// ReSharper disable InconsistentNaming + +namespace DiztinGUIsh.Annotations +{ + /// + /// Indicates that the value of the marked element could be null sometimes, + /// so checking for null is required before its usage. + /// + /// + /// [CanBeNull] object Test() => null; + /// + /// void UseTest() { + /// var p = Test(); + /// var s = p.ToString(); // Warning: Possible 'System.NullReferenceException' + /// } + /// + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | + AttributeTargets.Delegate | AttributeTargets.Field | AttributeTargets.Event | + AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.GenericParameter)] + public sealed class CanBeNullAttribute : Attribute { } + + /// + /// Indicates that the value of the marked element can never be null. + /// + /// + /// [NotNull] object Foo() { + /// return null; // Warning: Possible 'null' assignment + /// } + /// + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | + AttributeTargets.Delegate | AttributeTargets.Field | AttributeTargets.Event | + AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.GenericParameter)] + public sealed class NotNullAttribute : Attribute { } + + /// + /// Can be applied to symbols of types derived from IEnumerable as well as to symbols of Task + /// and Lazy classes to indicate that the value of a collection item, of the Task.Result property + /// or of the Lazy.Value property can never be null. + /// + /// + /// public void Foo([ItemNotNull]List<string> books) + /// { + /// foreach (var book in books) { + /// if (book != null) // Warning: Expression is always true + /// Console.WriteLine(book.ToUpper()); + /// } + /// } + /// + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | + AttributeTargets.Delegate | AttributeTargets.Field)] + public sealed class ItemNotNullAttribute : Attribute { } + + /// + /// Can be applied to symbols of types derived from IEnumerable as well as to symbols of Task + /// and Lazy classes to indicate that the value of a collection item, of the Task.Result property + /// or of the Lazy.Value property can be null. + /// + /// + /// public void Foo([ItemCanBeNull]List<string> books) + /// { + /// foreach (var book in books) + /// { + /// // Warning: Possible 'System.NullReferenceException' + /// Console.WriteLine(book.ToUpper()); + /// } + /// } + /// + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | + AttributeTargets.Delegate | AttributeTargets.Field)] + public sealed class ItemCanBeNullAttribute : Attribute { } + + /// + /// Indicates that the marked method builds string by the format pattern and (optional) arguments. + /// The parameter, which contains the format string, should be given in constructor. The format string + /// should be in -like form. + /// + /// + /// [StringFormatMethod("message")] + /// void ShowError(string message, params object[] args) { /* do something */ } + /// + /// void Foo() { + /// ShowError("Failed: {0}"); // Warning: Non-existing argument in format string + /// } + /// + [AttributeUsage( + AttributeTargets.Constructor | AttributeTargets.Method | + AttributeTargets.Property | AttributeTargets.Delegate)] + public sealed class StringFormatMethodAttribute : Attribute + { + /// + /// Specifies which parameter of an annotated method should be treated as the format string + /// + public StringFormatMethodAttribute([NotNull] string formatParameterName) + { + FormatParameterName = formatParameterName; + } + + [NotNull] public string FormatParameterName { get; } + } + + /// + /// Use this annotation to specify a type that contains static or const fields + /// with values for the annotated property/field/parameter. + /// The specified type will be used to improve completion suggestions. + /// + /// + /// namespace TestNamespace + /// { + /// public class Constants + /// { + /// public static int INT_CONST = 1; + /// public const string STRING_CONST = "1"; + /// } + /// + /// public class Class1 + /// { + /// [ValueProvider("TestNamespace.Constants")] public int myField; + /// public void Foo([ValueProvider("TestNamespace.Constants")] string str) { } + /// + /// public void Test() + /// { + /// Foo(/*try completion here*/);// + /// myField = /*try completion here*/ + /// } + /// } + /// } + /// + [AttributeUsage( + AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Field, + AllowMultiple = true)] + public sealed class ValueProviderAttribute : Attribute + { + public ValueProviderAttribute([NotNull] string name) + { + Name = name; + } + + [NotNull] public string Name { get; } + } + + /// + /// Indicates that the integral value falls into the specified interval. + /// It's allowed to specify multiple non-intersecting intervals. + /// Values of interval boundaries are inclusive. + /// + /// + /// void Foo([ValueRange(0, 100)] int value) { + /// if (value == -1) { // Warning: Expression is always 'false' + /// ... + /// } + /// } + /// + [AttributeUsage( + AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property | + AttributeTargets.Method | AttributeTargets.Delegate, + AllowMultiple = true)] + public sealed class ValueRangeAttribute : Attribute + { + public object From { get; } + public object To { get; } + + public ValueRangeAttribute(long from, long to) + { + From = from; + To = to; + } + + public ValueRangeAttribute(ulong from, ulong to) + { + From = from; + To = to; + } + + public ValueRangeAttribute(long value) + { + From = To = value; + } + + public ValueRangeAttribute(ulong value) + { + From = To = value; + } + } + + /// + /// Indicates that the integral value never falls below zero. + /// + /// + /// void Foo([NonNegativeValue] int value) { + /// if (value == -1) { // Warning: Expression is always 'false' + /// ... + /// } + /// } + /// + [AttributeUsage( + AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property | + AttributeTargets.Method | AttributeTargets.Delegate)] + public sealed class NonNegativeValueAttribute : Attribute { } + + /// + /// Indicates that the function argument should be a string literal and match one + /// of the parameters of the caller function. For example, ReSharper annotates + /// the parameter of . + /// + /// + /// void Foo(string param) { + /// if (param == null) + /// throw new ArgumentNullException("par"); // Warning: Cannot resolve symbol + /// } + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class InvokerParameterNameAttribute : Attribute { } + + /// + /// Indicates that the method is contained in a type that implements + /// System.ComponentModel.INotifyPropertyChanged interface and this method + /// is used to notify that some property value changed. + /// + /// + /// The method should be non-static and conform to one of the supported signatures: + /// + /// NotifyChanged(string) + /// NotifyChanged(params string[]) + /// NotifyChanged{T}(Expression{Func{T}}) + /// NotifyChanged{T,U}(Expression{Func{T,U}}) + /// SetProperty{T}(ref T, T, string) + /// + /// + /// + /// public class Foo : INotifyPropertyChanged { + /// public event PropertyChangedEventHandler PropertyChanged; + /// + /// [NotifyPropertyChangedInvocator] + /// protected virtual void NotifyChanged(string propertyName) { ... } + /// + /// string _name; + /// + /// public string Name { + /// get { return _name; } + /// set { _name = value; NotifyChanged("LastName"); /* Warning */ } + /// } + /// } + /// + /// Examples of generated notifications: + /// + /// NotifyChanged("Property") + /// NotifyChanged(() => Property) + /// NotifyChanged((VM x) => x.Property) + /// SetProperty(ref myField, value, "Property") + /// + /// + [AttributeUsage(AttributeTargets.Method)] + public sealed class NotifyPropertyChangedInvocatorAttribute : Attribute + { + public NotifyPropertyChangedInvocatorAttribute() { } + public NotifyPropertyChangedInvocatorAttribute([NotNull] string parameterName) + { + ParameterName = parameterName; + } + + [CanBeNull] public string ParameterName { get; } + } + + /// + /// Describes dependency between method input and output. + /// + /// + ///

Function Definition Table syntax:

+ /// + /// FDT ::= FDTRow [;FDTRow]* + /// FDTRow ::= Input => Output | Output <= Input + /// Input ::= ParameterName: Value [, Input]* + /// Output ::= [ParameterName: Value]* {halt|stop|void|nothing|Value} + /// Value ::= true | false | null | notnull | canbenull + /// + /// If the method has a single input parameter, its name could be omitted.
+ /// Using halt (or void/nothing, which is the same) for the method output + /// means that the method doesn't return normally (throws or terminates the process).
+ /// Value canbenull is only applicable for output parameters.
+ /// You can use multiple [ContractAnnotation] for each FDT row, or use single attribute + /// with rows separated by semicolon. There is no notion of order rows, all rows are checked + /// for applicability and applied per each program state tracked by the analysis engine.
+ ///
+ /// + /// + /// [ContractAnnotation("=> halt")] + /// public void TerminationMethod() + /// + /// + /// [ContractAnnotation("null <= param:null")] // reverse condition syntax + /// public string GetName(string surname) + /// + /// + /// [ContractAnnotation("s:null => true")] + /// public bool IsNullOrEmpty(string s) // string.IsNullOrEmpty() + /// + /// + /// // A method that returns null if the parameter is null, + /// // and not null if the parameter is not null + /// [ContractAnnotation("null => null; notnull => notnull")] + /// public object Transform(object data) + /// + /// + /// [ContractAnnotation("=> true, result: notnull; => false, result: null")] + /// public bool TryParse(string s, out Person result) + /// + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + public sealed class ContractAnnotationAttribute : Attribute + { + public ContractAnnotationAttribute([NotNull] string contract) + : this(contract, false) { } + + public ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates) + { + Contract = contract; + ForceFullStates = forceFullStates; + } + + [NotNull] public string Contract { get; } + + public bool ForceFullStates { get; } + } + + /// + /// Indicates whether the marked element should be localized. + /// + /// + /// [LocalizationRequiredAttribute(true)] + /// class Foo { + /// string str = "my string"; // Warning: Localizable string + /// } + /// + [AttributeUsage(AttributeTargets.All)] + public sealed class LocalizationRequiredAttribute : Attribute + { + public LocalizationRequiredAttribute() : this(true) { } + + public LocalizationRequiredAttribute(bool required) + { + Required = required; + } + + public bool Required { get; } + } + + /// + /// Indicates that the value of the marked type (or its derivatives) + /// cannot be compared using '==' or '!=' operators and Equals() + /// should be used instead. However, using '==' or '!=' for comparison + /// with null is always permitted. + /// + /// + /// [CannotApplyEqualityOperator] + /// class NoEquality { } + /// + /// class UsesNoEquality { + /// void Test() { + /// var ca1 = new NoEquality(); + /// var ca2 = new NoEquality(); + /// if (ca1 != null) { // OK + /// bool condition = ca1 == ca2; // Warning + /// } + /// } + /// } + /// + [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Struct)] + public sealed class CannotApplyEqualityOperatorAttribute : Attribute { } + + /// + /// When applied to a target attribute, specifies a requirement for any type marked + /// with the target attribute to implement or inherit specific type or types. + /// + /// + /// [BaseTypeRequired(typeof(IComponent)] // Specify requirement + /// class ComponentAttribute : Attribute { } + /// + /// [Component] // ComponentAttribute requires implementing IComponent interface + /// class MyComponent : IComponent { } + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + [BaseTypeRequired(typeof(Attribute))] + public sealed class BaseTypeRequiredAttribute : Attribute + { + public BaseTypeRequiredAttribute([NotNull] Type baseType) + { + BaseType = baseType; + } + + [NotNull] public Type BaseType { get; } + } + + /// + /// Indicates that the marked symbol is used implicitly (e.g. via reflection, in external library), + /// so this symbol will not be reported as unused (as well as by other usage inspections). + /// + [AttributeUsage(AttributeTargets.All)] + public sealed class UsedImplicitlyAttribute : Attribute + { + public UsedImplicitlyAttribute() + : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } + + public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags) + : this(useKindFlags, ImplicitUseTargetFlags.Default) { } + + public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags) + : this(ImplicitUseKindFlags.Default, targetFlags) { } + + public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) + { + UseKindFlags = useKindFlags; + TargetFlags = targetFlags; + } + + public ImplicitUseKindFlags UseKindFlags { get; } + + public ImplicitUseTargetFlags TargetFlags { get; } + } + + /// + /// Can be applied to attributes, type parameters, and parameters of a type assignable from . + /// When applied to an attribute, the decorated attribute behaves the same as . + /// When applied to a type parameter or to a parameter of type , indicates that the corresponding type + /// is used implicitly. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.GenericParameter | AttributeTargets.Parameter)] + public sealed class MeansImplicitUseAttribute : Attribute + { + public MeansImplicitUseAttribute() + : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } + + public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags) + : this(useKindFlags, ImplicitUseTargetFlags.Default) { } + + public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags) + : this(ImplicitUseKindFlags.Default, targetFlags) { } + + public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) + { + UseKindFlags = useKindFlags; + TargetFlags = targetFlags; + } + + [UsedImplicitly] public ImplicitUseKindFlags UseKindFlags { get; } + + [UsedImplicitly] public ImplicitUseTargetFlags TargetFlags { get; } + } + + /// + /// Specify the details of implicitly used symbol when it is marked + /// with or . + /// + [Flags] + public enum ImplicitUseKindFlags + { + Default = Access | Assign | InstantiatedWithFixedConstructorSignature, + /// Only entity marked with attribute considered used. + Access = 1, + /// Indicates implicit assignment to a member. + Assign = 2, + /// + /// Indicates implicit instantiation of a type with fixed constructor signature. + /// That means any unused constructor parameters won't be reported as such. + /// + InstantiatedWithFixedConstructorSignature = 4, + /// Indicates implicit instantiation of a type. + InstantiatedNoFixedConstructorSignature = 8, + } + + /// + /// Specify what is considered to be used implicitly when marked + /// with or . + /// + [Flags] + public enum ImplicitUseTargetFlags + { + Default = Itself, + Itself = 1, + /// Members of entity marked with attribute are considered used. + Members = 2, + /// Inherited entities are considered used. + WithInheritors = 4, + /// Entity marked with attribute and all its members considered used. + WithMembers = Itself | Members + } + + /// + /// This attribute is intended to mark publicly available API + /// which should not be removed and so is treated as used. + /// + [MeansImplicitUse(ImplicitUseTargetFlags.WithMembers)] + [AttributeUsage(AttributeTargets.All, Inherited = false)] + public sealed class PublicAPIAttribute : Attribute + { + public PublicAPIAttribute() { } + + public PublicAPIAttribute([NotNull] string comment) + { + Comment = comment; + } + + [CanBeNull] public string Comment { get; } + } + + /// + /// Tells code analysis engine if the parameter is completely handled when the invoked method is on stack. + /// If the parameter is a delegate, indicates that delegate is executed while the method is executed. + /// If the parameter is an enumerable, indicates that it is enumerated while the method is executed. + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class InstantHandleAttribute : Attribute { } + + /// + /// Indicates that a method does not make any observable state changes. + /// The same as System.Diagnostics.Contracts.PureAttribute. + /// + /// + /// [Pure] int Multiply(int x, int y) => x * y; + /// + /// void M() { + /// Multiply(123, 42); // Warning: Return value of pure method is not used + /// } + /// + [AttributeUsage(AttributeTargets.Method)] + public sealed class PureAttribute : Attribute { } + + /// + /// Indicates that the return value of the method invocation must be used. + /// + /// + /// Methods decorated with this attribute (in contrast to pure methods) might change state, + /// but make no sense without using their return value.
+ /// Similarly to , this attribute + /// will help detecting usages of the method when the return value in not used. + /// Additionally, you can optionally specify a custom message, which will be used when showing warnings, e.g. + /// [MustUseReturnValue("Use the return value to...")]. + ///
+ [AttributeUsage(AttributeTargets.Method)] + public sealed class MustUseReturnValueAttribute : Attribute + { + public MustUseReturnValueAttribute() { } + + public MustUseReturnValueAttribute([NotNull] string justification) + { + Justification = justification; + } + + [CanBeNull] public string Justification { get; } + } + + /// + /// Indicates the type member or parameter of some type, that should be used instead of all other ways + /// to get the value of that type. This annotation is useful when you have some "context" value evaluated + /// and stored somewhere, meaning that all other ways to get this value must be consolidated with existing one. + /// + /// + /// class Foo { + /// [ProvidesContext] IBarService _barService = ...; + /// + /// void ProcessNode(INode node) { + /// DoSomething(node, node.GetGlobalServices().Bar); + /// // ^ Warning: use value of '_barService' field + /// } + /// } + /// + [AttributeUsage( + AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.Method | + AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.GenericParameter)] + public sealed class ProvidesContextAttribute : Attribute { } + + /// + /// Indicates that a parameter is a path to a file or a folder within a web project. + /// Path can be relative or absolute, starting from web root (~). + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class PathReferenceAttribute : Attribute + { + public PathReferenceAttribute() { } + + public PathReferenceAttribute([NotNull, PathReference] string basePath) + { + BasePath = basePath; + } + + [CanBeNull] public string BasePath { get; } + } + + /// + /// An extension method marked with this attribute is processed by code completion + /// as a 'Source Template'. When the extension method is completed over some expression, its source code + /// is automatically expanded like a template at call site. + /// + /// + /// Template method body can contain valid source code and/or special comments starting with '$'. + /// Text inside these comments is added as source code when the template is applied. Template parameters + /// can be used either as additional method parameters or as identifiers wrapped in two '$' signs. + /// Use the attribute to specify macros for parameters. + /// + /// + /// In this example, the 'forEach' method is a source template available over all values + /// of enumerable types, producing ordinary C# 'foreach' statement and placing caret inside block: + /// + /// [SourceTemplate] + /// public static void forEach<T>(this IEnumerable<T> xs) { + /// foreach (var x in xs) { + /// //$ $END$ + /// } + /// } + /// + /// + [AttributeUsage(AttributeTargets.Method)] + public sealed class SourceTemplateAttribute : Attribute { } + + /// + /// Allows specifying a macro for a parameter of a source template. + /// + /// + /// You can apply the attribute on the whole method or on any of its additional parameters. The macro expression + /// is defined in the property. When applied on a method, the target + /// template parameter is defined in the property. To apply the macro silently + /// for the parameter, set the property value = -1. + /// + /// + /// Applying the attribute on a source template method: + /// + /// [SourceTemplate, Macro(Target = "item", Expression = "suggestVariableName()")] + /// public static void forEach<T>(this IEnumerable<T> collection) { + /// foreach (var item in collection) { + /// //$ $END$ + /// } + /// } + /// + /// Applying the attribute on a template method parameter: + /// + /// [SourceTemplate] + /// public static void something(this Entity x, [Macro(Expression = "guid()", Editable = -1)] string newguid) { + /// /*$ var $x$Id = "$newguid$" + x.ToString(); + /// x.DoSomething($x$Id); */ + /// } + /// + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method, AllowMultiple = true)] + public sealed class MacroAttribute : Attribute + { + /// + /// Allows specifying a macro that will be executed for a source template + /// parameter when the template is expanded. + /// + [CanBeNull] public string Expression { get; set; } + + /// + /// Allows specifying which occurrence of the target parameter becomes editable when the template is deployed. + /// + /// + /// If the target parameter is used several times in the template, only one occurrence becomes editable; + /// other occurrences are changed synchronously. To specify the zero-based index of the editable occurrence, + /// use values >= 0. To make the parameter non-editable when the template is expanded, use -1. + /// + public int Editable { get; set; } + + /// + /// Identifies the target parameter of a source template if the + /// is applied on a template method. + /// + [CanBeNull] public string Target { get; set; } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] + public sealed class AspMvcAreaMasterLocationFormatAttribute : Attribute + { + public AspMvcAreaMasterLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] public string Format { get; } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] + public sealed class AspMvcAreaPartialViewLocationFormatAttribute : Attribute + { + public AspMvcAreaPartialViewLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] public string Format { get; } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] + public sealed class AspMvcAreaViewLocationFormatAttribute : Attribute + { + public AspMvcAreaViewLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] public string Format { get; } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] + public sealed class AspMvcMasterLocationFormatAttribute : Attribute + { + public AspMvcMasterLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] public string Format { get; } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] + public sealed class AspMvcPartialViewLocationFormatAttribute : Attribute + { + public AspMvcPartialViewLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] public string Format { get; } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] + public sealed class AspMvcViewLocationFormatAttribute : Attribute + { + public AspMvcViewLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] public string Format { get; } + } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter + /// is an MVC action. If applied to a method, the MVC action name is calculated + /// implicitly from the context. Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] + public sealed class AspMvcActionAttribute : Attribute + { + public AspMvcActionAttribute() { } + + public AspMvcActionAttribute([NotNull] string anonymousProperty) + { + AnonymousProperty = anonymousProperty; + } + + [CanBeNull] public string AnonymousProperty { get; } + } + + /// + /// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC area. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] + public sealed class AspMvcAreaAttribute : Attribute + { + public AspMvcAreaAttribute() { } + + public AspMvcAreaAttribute([NotNull] string anonymousProperty) + { + AnonymousProperty = anonymousProperty; + } + + [CanBeNull] public string AnonymousProperty { get; } + } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter is + /// an MVC controller. If applied to a method, the MVC controller name is calculated + /// implicitly from the context. Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String, String). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] + public sealed class AspMvcControllerAttribute : Attribute + { + public AspMvcControllerAttribute() { } + + public AspMvcControllerAttribute([NotNull] string anonymousProperty) + { + AnonymousProperty = anonymousProperty; + } + + [CanBeNull] public string AnonymousProperty { get; } + } + + /// + /// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC Master. Use this attribute + /// for custom wrappers similar to System.Web.Mvc.Controller.View(String, String). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] + public sealed class AspMvcMasterAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC model type. Use this attribute + /// for custom wrappers similar to System.Web.Mvc.Controller.View(String, Object). + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcModelTypeAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter is an MVC + /// partial view. If applied to a method, the MVC partial view name is calculated implicitly + /// from the context. Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial(HtmlHelper, String). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] + public sealed class AspMvcPartialViewAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Allows disabling inspections for MVC views within a class or a method. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] + public sealed class AspMvcSuppressViewErrorAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC display template. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.DisplayExtensions.DisplayForModel(HtmlHelper, String). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] + public sealed class AspMvcDisplayTemplateAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC editor template. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.EditorExtensions.EditorForModel(HtmlHelper, String). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] + public sealed class AspMvcEditorTemplateAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC template. + /// Use this attribute for custom wrappers similar to + /// System.ComponentModel.DataAnnotations.UIHintAttribute(System.String). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] + public sealed class AspMvcTemplateAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter + /// is an MVC view component. If applied to a method, the MVC view name is calculated implicitly + /// from the context. Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Controller.View(Object). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] + public sealed class AspMvcViewAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter + /// is an MVC view component name. + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] + public sealed class AspMvcViewComponentAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter + /// is an MVC view component view. If applied to a method, the MVC view component view name is default. + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] + public sealed class AspMvcViewComponentViewAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. When applied to a parameter of an attribute, + /// indicates that this parameter is an MVC action name. + /// + /// + /// [ActionName("Foo")] + /// public ActionResult Login(string returnUrl) { + /// ViewBag.ReturnUrl = Url.Action("Foo"); // OK + /// return RedirectToAction("Bar"); // Error: Cannot resolve action + /// } + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)] + public sealed class AspMvcActionSelectorAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Field)] + public sealed class HtmlElementAttributesAttribute : Attribute + { + public HtmlElementAttributesAttribute() { } + + public HtmlElementAttributesAttribute([NotNull] string name) + { + Name = name; + } + + [CanBeNull] public string Name { get; } + } + + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] + public sealed class HtmlAttributeValueAttribute : Attribute + { + public HtmlAttributeValueAttribute([NotNull] string name) + { + Name = name; + } + + [NotNull] public string Name { get; } + } + + /// + /// Razor attribute. Indicates that the marked parameter or method is a Razor section. + /// Use this attribute for custom wrappers similar to + /// System.Web.WebPages.WebPageBase.RenderSection(String). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + public sealed class RazorSectionAttribute : Attribute { } + + /// + /// Indicates how method, constructor invocation, or property access + /// over collection type affects the contents of the collection. + /// Use to specify the access type. + /// + /// + /// Using this attribute only makes sense if all collection methods are marked with this attribute. + /// + /// + /// public class MyStringCollection : List<string> + /// { + /// [CollectionAccess(CollectionAccessType.Read)] + /// public string GetFirstString() + /// { + /// return this.ElementAt(0); + /// } + /// } + /// class Test + /// { + /// public void Foo() + /// { + /// // Warning: Contents of the collection is never updated + /// var col = new MyStringCollection(); + /// string x = col.GetFirstString(); + /// } + /// } + /// + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property)] + public sealed class CollectionAccessAttribute : Attribute + { + public CollectionAccessAttribute(CollectionAccessType collectionAccessType) + { + CollectionAccessType = collectionAccessType; + } + + public CollectionAccessType CollectionAccessType { get; } + } + + /// + /// Provides a value for the to define + /// how the collection method invocation affects the contents of the collection. + /// + [Flags] + public enum CollectionAccessType + { + /// Method does not use or modify content of the collection. + None = 0, + /// Method only reads content of the collection but does not modify it. + Read = 1, + /// Method can change content of the collection but does not add new elements. + ModifyExistingContent = 2, + /// Method can add new elements to the collection. + UpdatedContent = ModifyExistingContent | 4 + } + + /// + /// Indicates that the marked method is assertion method, i.e. it halts the control flow if + /// one of the conditions is satisfied. To set the condition, mark one of the parameters with + /// attribute. + /// + [AttributeUsage(AttributeTargets.Method)] + public sealed class AssertionMethodAttribute : Attribute { } + + /// + /// Indicates the condition parameter of the assertion method. The method itself should be + /// marked by attribute. The mandatory argument of + /// the attribute is the assertion type. + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AssertionConditionAttribute : Attribute + { + public AssertionConditionAttribute(AssertionConditionType conditionType) + { + ConditionType = conditionType; + } + + public AssertionConditionType ConditionType { get; } + } + + /// + /// Specifies assertion type. If the assertion method argument satisfies the condition, + /// then the execution continues. Otherwise, execution is assumed to be halted. + /// + public enum AssertionConditionType + { + /// Marked parameter should be evaluated to true. + IS_TRUE = 0, + /// Marked parameter should be evaluated to false. + IS_FALSE = 1, + /// Marked parameter should be evaluated to null value. + IS_NULL = 2, + /// Marked parameter should be evaluated to not null value. + IS_NOT_NULL = 3, + } + + /// + /// Indicates that the marked method unconditionally terminates control flow execution. + /// For example, it could unconditionally throw exception. + /// + [Obsolete("Use [ContractAnnotation('=> halt')] instead")] + [AttributeUsage(AttributeTargets.Method)] + public sealed class TerminatesProgramAttribute : Attribute { } + + /// + /// Indicates that method is pure LINQ method, with postponed enumeration (like Enumerable.Select, + /// .Where). This annotation allows inference of [InstantHandle] annotation for parameters + /// of delegate type by analyzing LINQ method chains. + /// + [AttributeUsage(AttributeTargets.Method)] + public sealed class LinqTunnelAttribute : Attribute { } + + /// + /// Indicates that IEnumerable passed as a parameter is not enumerated. + /// Use this annotation to suppress the 'Possible multiple enumeration of IEnumerable' inspection. + /// + /// + /// static void ThrowIfNull<T>([NoEnumeration] T v, string n) where T : class + /// { + /// // custom check for null but no enumeration + /// } + /// + /// void Foo(IEnumerable<string> values) + /// { + /// ThrowIfNull(values, nameof(values)); + /// var x = values.ToList(); // No warnings about multiple enumeration + /// } + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class NoEnumerationAttribute : Attribute { } + + /// + /// Indicates that the marked parameter is a regular expression pattern. + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] + public sealed class RegexPatternAttribute : Attribute { } + + /// + /// Prevents the Member Reordering feature from tossing members of the marked class. + /// + /// + /// The attribute must be mentioned in your member reordering patterns. + /// + [AttributeUsage( + AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.Enum)] + public sealed class NoReorderAttribute : Attribute { } + + /// + /// XAML attribute. Indicates the type that has ItemsSource property and should be treated + /// as ItemsControl-derived type, to enable inner items DataContext type resolve. + /// + [AttributeUsage(AttributeTargets.Class)] + public sealed class XamlItemsControlAttribute : Attribute { } + + /// + /// XAML attribute. Indicates the property of some BindingBase-derived type, that + /// is used to bind some item of ItemsControl-derived type. This annotation will + /// enable the DataContext type resolve for XAML bindings for such properties. + /// + /// + /// Property should have the tree ancestor of the ItemsControl type or + /// marked with the attribute. + /// + [AttributeUsage(AttributeTargets.Property)] + public sealed class XamlItemBindingOfItemsControlAttribute : Attribute { } + + /// + /// XAML attribute. Indicates the property of some Style-derived type, that + /// is used to style items of ItemsControl-derived type. This annotation will + /// enable the DataContext type resolve for XAML bindings for such properties. + /// + /// + /// Property should have the tree ancestor of the ItemsControl type or + /// marked with the attribute. + /// + [AttributeUsage(AttributeTargets.Property)] + public sealed class XamlItemStyleOfItemsControlAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + public sealed class AspChildControlTypeAttribute : Attribute + { + public AspChildControlTypeAttribute([NotNull] string tagName, [NotNull] Type controlType) + { + TagName = tagName; + ControlType = controlType; + } + + [NotNull] public string TagName { get; } + + [NotNull] public Type ControlType { get; } + } + + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)] + public sealed class AspDataFieldAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)] + public sealed class AspDataFieldsAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Property)] + public sealed class AspMethodPropertyAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + public sealed class AspRequiredAttributeAttribute : Attribute + { + public AspRequiredAttributeAttribute([NotNull] string attribute) + { + Attribute = attribute; + } + + [NotNull] public string Attribute { get; } + } + + [AttributeUsage(AttributeTargets.Property)] + public sealed class AspTypePropertyAttribute : Attribute + { + public bool CreateConstructorReferences { get; } + + public AspTypePropertyAttribute(bool createConstructorReferences) + { + CreateConstructorReferences = createConstructorReferences; + } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class RazorImportNamespaceAttribute : Attribute + { + public RazorImportNamespaceAttribute([NotNull] string name) + { + Name = name; + } + + [NotNull] public string Name { get; } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class RazorInjectionAttribute : Attribute + { + public RazorInjectionAttribute([NotNull] string type, [NotNull] string fieldName) + { + Type = type; + FieldName = fieldName; + } + + [NotNull] public string Type { get; } + + [NotNull] public string FieldName { get; } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class RazorDirectiveAttribute : Attribute + { + public RazorDirectiveAttribute([NotNull] string directive) + { + Directive = directive; + } + + [NotNull] public string Directive { get; } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class RazorPageBaseTypeAttribute : Attribute + { + public RazorPageBaseTypeAttribute([NotNull] string baseType) + { + BaseType = baseType; + } + public RazorPageBaseTypeAttribute([NotNull] string baseType, string pageName) + { + BaseType = baseType; + PageName = pageName; + } + + [NotNull] public string BaseType { get; } + [CanBeNull] public string PageName { get; } + } + + [AttributeUsage(AttributeTargets.Method)] + public sealed class RazorHelperCommonAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Property)] + public sealed class RazorLayoutAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Method)] + public sealed class RazorWriteLiteralMethodAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Method)] + public sealed class RazorWriteMethodAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class RazorWriteMethodParameterAttribute : Attribute { } +} \ No newline at end of file diff --git a/DiztinGUIsh/core/Data.cs b/DiztinGUIsh/core/Data.cs index ebc0f185..3ccea068 100644 --- a/DiztinGUIsh/core/Data.cs +++ b/DiztinGUIsh/core/Data.cs @@ -1,34 +1,15 @@ -using DiztinGUIsh.window; -using System; +using System; using System.Collections.Generic; -using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; -using System.Runtime.CompilerServices; using System.Text; -using System.Threading.Tasks; +using DiztinGUIsh.core.util; namespace DiztinGUIsh { public class Data { - // Note: order of these properties matters for the load/save process. Keep 'RomBytes' LAST - // TODO: should be a way in the XML serializer to control the order, remove this comment - // when we figure it out. - public ROMMapMode RomMapMode { get; set; } - public ROMSpeed RomSpeed { get; set; } - public Dictionary Comments { get; set; } - public Dictionary Labels { get; set; } - public RomBytes RomBytes { get; set; } - - private CPU65C816 CPU65C816 { get; set; } - - public Data() - { - CPU65C816 = new CPU65C816(this); - } - public enum FlagType : byte { Unreached = 0x00, @@ -47,7 +28,7 @@ public enum FlagType : byte Text = 0x60 } - public enum Architechture : byte + public enum Architecture : byte { CPU65C816 = 0x00, APUSPC700 = 0x01, @@ -91,29 +72,45 @@ public const int EXHIROM_SETTING_OFFSET = 0x40FFD5, EXLOROM_SETTING_OFFSET = 0x407FD5; + // Note: order of these properties matters for the load/save process. Keep 'RomBytes' LAST + // TODO: should be a way in the XML serializer to control the order, remove this comment + // when we figure it out. + public ROMMapMode RomMapMode { get; set; } + public ROMSpeed RomSpeed { get; set; } + public ObservableDictionary Comments { get; set; } = new ObservableDictionary< int, string>(); + public ObservableDictionary Labels { get; set; } = new ObservableDictionary< int, Label>(); + public RomBytes RomBytes { get; set; } = new RomBytes(); + + private CPU65C816 CPU65C816 { get; set; } + + public Data() + { + CPU65C816 = new CPU65C816(this); + romMemoryOp = new Func[] {GetROMByte, GetROMWord, GetROMLong, GetROMDoubleWord}; + } - public void Initiate(byte[] data, ROMMapMode mode, ROMSpeed speed) + public void Initiate(byte[] actualRomBytes, Data.ROMMapMode mode, Data.ROMSpeed speed) { RomMapMode = mode; RomSpeed = speed; - int size = data.Length; - Labels = new Dictionary(); - Comments = new Dictionary(); - RomBytes = new RomBytes(); - for (int i = 0; i < size; i++) + CreateRomBytesFromRom(actualRomBytes); + } + + private void CreateRomBytesFromRom(IEnumerable actualRomBytes) + { + foreach (var fileByte in actualRomBytes) { - var r = new ROMByte + RomBytes.Add(new ROMByte { - Rom = data[i], + Rom = fileByte, DataBank = 0, DirectPage = 0, XFlag = false, MFlag = false, - TypeFlag = FlagType.Unreached, - Arch = Architechture.CPU65C816, + TypeFlag = Data.FlagType.Unreached, + Arch = Data.Architecture.CPU65C816, Point = 0 - }; - RomBytes.Add(r); + }); } } @@ -128,7 +125,7 @@ private byte[] GetRomBytes(int pcOffset, int count) public string GetRomNameFromRomBytes() { - return System.Text.Encoding.UTF8.GetString(GetRomBytes(0xFFC0, 21)); + return Encoding.UTF8.GetString(GetRomBytes(0xFFC0, 21)); } public int GetRomCheckSumsFromRomBytes() @@ -146,117 +143,33 @@ public void CopyRomDataIn(byte[] data) } } - public ROMMapMode GetROMMapMode() - { - return RomMapMode; - } - - public ROMSpeed GetROMSpeed() - { - return RomSpeed; - } - - public RomBytes GetTable() - { - return RomBytes; - } - - public int GetROMByte(int i) - { - return RomBytes[i].Rom; - } - - public int GetROMSize() - { - return RomBytes?.Count ?? 0; - } - - public FlagType GetFlag(int i) - { - return RomBytes[i].TypeFlag; - } - - public void SetFlag(int i, FlagType flag) - { - RomBytes[i].TypeFlag = flag; - } - - public Architechture GetArchitechture(int i) - { - return RomBytes[i].Arch; - } - - public void SetArchitechture(int i, Architechture arch) - { - RomBytes[i].Arch = arch; - } - - public InOutPoint GetInOutPoint(int i) - { - return RomBytes[i].Point; - } - - public void SetInOutPoint(int i, InOutPoint point) - { - RomBytes[i].Point |= point; - } - - public void ClearInOutPoint(int i) - { - RomBytes[i].Point = 0; - } - - public int GetDataBank(int i) - { - return RomBytes[i].DataBank; - } - - public void SetDataBank(int i, int dbank) - { - RomBytes[i].DataBank = (byte)dbank; - } - - public int GetDirectPage(int i) - { - return RomBytes[i].DirectPage; - } - - public void SetDirectPage(int i, int dpage) - { - RomBytes[i].DirectPage = 0xFFFF & dpage; - } - - public bool GetXFlag(int i) - { - return RomBytes[i].XFlag; - } - - public void SetXFlag(int i, bool x) - { - RomBytes[i].XFlag = x; - } - - public bool GetMFlag(int i) - { - return RomBytes[i].MFlag; - } - - public void SetMFlag(int i, bool m) - { - RomBytes[i].MFlag = m; - } - + public int GetROMSize() => RomBytes?.Count ?? 0; + public ROMMapMode GetROMMapMode() => RomMapMode; + public ROMSpeed GetROMSpeed() => RomSpeed; + public FlagType GetFlag(int i) => RomBytes[i].TypeFlag; + public void SetFlag(int i, FlagType flag) => RomBytes[i].TypeFlag = flag; + public Architecture GetArchitecture(int i) => RomBytes[i].Arch; + public void SetArchitechture(int i, Architecture arch) => RomBytes[i].Arch = arch; + public InOutPoint GetInOutPoint(int i) => RomBytes[i].Point; + public void SetInOutPoint(int i, InOutPoint point) => RomBytes[i].Point |= point; + public void ClearInOutPoint(int i) => RomBytes[i].Point = 0; + public int GetDataBank(int i) => RomBytes[i].DataBank; + public void SetDataBank(int i, int dbank) => RomBytes[i].DataBank = (byte)dbank; + public int GetDirectPage(int i) => RomBytes[i].DirectPage; + public void SetDirectPage(int i, int dpage) => RomBytes[i].DirectPage = 0xFFFF & dpage; + public bool GetXFlag(int i) => RomBytes[i].XFlag; + public void SetXFlag(int i, bool x) => RomBytes[i].XFlag = x; + public bool GetMFlag(int i) => RomBytes[i].MFlag; + public void SetMFlag(int i, bool m) => RomBytes[i].MFlag = m; public int GetMXFlags(int i) { return (RomBytes[i].MFlag ? 0x20 : 0) | (RomBytes[i].XFlag ? 0x10 : 0); } - public void SetMXFlags(int i, int mx) { RomBytes[i].MFlag = ((mx & 0x20) != 0); RomBytes[i].XFlag = ((mx & 0x10) != 0); } - public string GetLabelName(int i) { if (Labels.TryGetValue(i, out var val)) @@ -277,42 +190,31 @@ public void DeleteAllLabels() Labels.Clear(); } - public void AddLabel(int i, Label v, bool overwrite) + public void AddLabel(int offset, Label label, bool overwrite) { - if (v == null) + // adding null label removes it + if (label == null) { - if (Labels.ContainsKey(i)) - { - Labels.Remove(i); - // TODO: notify observers AliasList.me.RemoveRow(i); - } - } else { - if (Labels.ContainsKey(i) && overwrite) - { - Labels.Remove(i); - // // TODO: notify observers AliasList.me.RemoveRow(i); - } - - if (Labels.ContainsKey(i)) - return; - - v.CleanUp(); + if (Labels.ContainsKey(offset)) + Labels.Remove(offset); - Labels.Add(i, v); - // // TODO: notify observers AliasList.me.AddRow(i, v); + return; } - } - public Dictionary GetAllLabels() - { - return Labels; - } + if (overwrite) + { + if (Labels.ContainsKey(offset)) + Labels.Remove(offset); + } - public string GetComment(int i) - { - return Comments.TryGetValue(i, out var val) ? val : ""; + if (!Labels.ContainsKey(offset)) + { + label.CleanUp(); + Labels.Add(offset, label); + } } + public string GetComment(int i) => Comments.TryGetValue(i, out var val) ? val : ""; public void AddComment(int i, string v, bool overwrite) { if (v == null) @@ -325,50 +227,29 @@ public void AddComment(int i, string v, bool overwrite) } } - public Dictionary GetAllComments() - { - return Comments; - } - - public static int GetRomSettingOffset(ROMMapMode mode) - { - switch (mode) - { - case ROMMapMode.LoROM: return LOROM_SETTING_OFFSET; - case ROMMapMode.HiROM: return HIROM_SETTING_OFFSET; - case ROMMapMode.ExHiROM: return EXHIROM_SETTING_OFFSET; - case ROMMapMode.ExLoROM: return EXLOROM_SETTING_OFFSET; - } - return LOROM_SETTING_OFFSET; - } - - public int ConvertPCtoSNES(int offset) { return Util.ConvertPCtoSNES(offset, RomMapMode, GetROMSpeed()); } - + public int GetROMByte(int i) => RomBytes[i].Rom; public int GetROMWord(int offset) { if (offset + 1 < GetROMSize()) return GetROMByte(offset) + (GetROMByte(offset + 1) << 8); return -1; } - public int GetROMLong(int offset) { if (offset + 2 < GetROMSize()) return GetROMByte(offset) + (GetROMByte(offset + 1) << 8) + (GetROMByte(offset + 2) << 16); return -1; } - public int GetROMDoubleWord(int offset) { if (offset + 3 < GetROMSize()) return GetROMByte(offset) + (GetROMByte(offset + 1) << 8) + (GetROMByte(offset + 2) << 16) + (GetROMByte(offset + 3) << 24); return -1; } - public int GetIntermediateAddressOrPointer(int offset) { switch (GetFlag(offset)) @@ -388,14 +269,13 @@ public int GetIntermediateAddressOrPointer(int offset) public int OpcodeByteLength(int offset) { - switch (GetArchitechture(offset)) + return GetArchitecture(offset) switch { - case Data.Architechture.CPU65C816: return CPU65C816.GetInstructionLength(offset); - case Data.Architechture.APUSPC700: return 1; - case Data.Architechture.GPUSuperFX: return 1; - } - - return 1; + Data.Architecture.CPU65C816 => CPU65C816.GetInstructionLength(offset), + Data.Architecture.APUSPC700 => 1, + Data.Architecture.GPUSuperFX => 1, + _ => 1 + }; } private int UnmirroredOffset(int offset) @@ -405,22 +285,22 @@ private int UnmirroredOffset(int offset) public string GetFormattedBytes(int offset, int step, int bytes) { - string res = ""; - switch (step) + var res = step switch { - case 1: res = "db "; break; - case 2: res = "dw "; break; - case 3: res = "dl "; break; - case 4: res = "dd "; break; - } - - for (int i = 0; i < bytes; i += step) + 1 => "db ", + 2 => "dw ", + 3 => "dl ", + 4 => "dd ", + _ => "" + }; + + for (var i = 0; i < bytes; i += step) { if (i > 0) res += ","; switch (step) { - case 1: res += Util.NumberToBaseString(GetROMByte(offset + i), Util.NumberBase.Hexadecimal, 2, true); break; + case 1: res += NumberToBaseString(offset + i, step); break; case 2: res += Util.NumberToBaseString(GetROMWord(offset + i), Util.NumberBase.Hexadecimal, 4, true); break; case 3: res += Util.NumberToBaseString(GetROMLong(offset + i), Util.NumberBase.Hexadecimal, 6, true); break; case 4: res += Util.NumberToBaseString(GetROMDoubleWord(offset + i), Util.NumberBase.Hexadecimal, 8, true); break; @@ -430,6 +310,14 @@ public string GetFormattedBytes(int offset, int step, int bytes) return res; } + private readonly Func[] romMemoryOp; + + private string NumberToBaseString(int offset, int num_bytes) + { + return Util.NumberToBaseString(romMemoryOp[num_bytes](offset), + Util.NumberBase.Hexadecimal, num_bytes*2, true); + } + public int ConvertSNEStoPC(int address) { return Util.ConvertSNESToPC(address, RomMapMode, GetROMSize()); @@ -474,18 +362,20 @@ public string GetFormattedText(int offset, int bytes) public string GetDefaultLabel(int offset) { var snes = ConvertPCtoSNES(offset); - return string.Format("{0}_{1}", Util.TypeToLabel(GetFlag(offset)), Util.NumberToBaseString(snes, Util.NumberBase.Hexadecimal, 6)); + var prefix = Util.TypeToLabel(GetFlag(offset)); + var labelAddress = Util.NumberToBaseString(snes, Util.NumberBase.Hexadecimal, 6); + return $"{prefix}_{labelAddress}"; } public int Step(int offset, bool branch, bool force, int prevOffset) { - switch (GetArchitechture(offset)) + return GetArchitecture(offset) switch { - case Data.Architechture.CPU65C816: return CPU65C816.Step(offset, branch, force, prevOffset); - case Data.Architechture.APUSPC700: return offset; - case Data.Architechture.GPUSuperFX: return offset; - } - return offset; + Data.Architecture.CPU65C816 => CPU65C816.Step(offset, branch, force, prevOffset), + Data.Architecture.APUSPC700 => offset, + Data.Architecture.GPUSuperFX => offset, + _ => offset + }; } public int AutoStep(int offset, bool harsh, int amount) @@ -502,15 +392,15 @@ public int AutoStep(int offset, bool harsh, int amount) } else { - Stack stack = new Stack(); - List seenBranches = new List(); - bool keepGoing = true; + var stack = new Stack(); + var seenBranches = new List(); + var keepGoing = true; while (keepGoing) { - switch (GetArchitechture(newOffset)) + switch (GetArchitecture(newOffset)) { - case Data.Architechture.CPU65C816: + case Data.Architecture.CPU65C816: if (seenBranches.Contains(newOffset)) { keepGoing = false; @@ -573,15 +463,15 @@ public int AutoStep(int offset, bool harsh, int amount) newOffset = nextOffset; } break; - case Data.Architechture.APUSPC700: - case Data.Architechture.GPUSuperFX: + case Data.Architecture.APUSPC700: + case Data.Architecture.GPUSuperFX: nextOffset = Step(newOffset, false, true, prevOffset); prevOffset = newOffset; newOffset = nextOffset; break; } - Data.FlagType flag = GetFlag(newOffset); + var flag = GetFlag(newOffset); if (!(flag == Data.FlagType.Unreached || flag == Data.FlagType.Opcode || flag == Data.FlagType.Operand)) keepGoing = false; } } @@ -623,7 +513,7 @@ public int MarkMFlag(int offset, bool m, int count) return offset + i < size ? offset + i : size - 1; } - public int MarkArchitechture(int offset, Data.Architechture arch, int count) + public int MarkArchitechture(int offset, Data.Architecture arch, int count) { int i, size = GetROMSize(); for (i = 0; i < count && offset + i < size; i++) SetArchitechture(offset + i, arch); @@ -632,54 +522,61 @@ public int MarkArchitechture(int offset, Data.Architechture arch, int count) public int GetInstructionLength(int offset) { - switch (GetArchitechture(offset)) + return GetArchitecture(offset) switch { - case Data.Architechture.CPU65C816: return CPU65C816.GetInstructionLength(offset); - case Data.Architechture.APUSPC700: return 1; - case Data.Architechture.GPUSuperFX: return 1; - } - return 1; + Data.Architecture.CPU65C816 => CPU65C816.GetInstructionLength(offset), + Data.Architecture.APUSPC700 => 1, + Data.Architecture.GPUSuperFX => 1, + _ => 1 + }; } public int FixMisalignedFlags() { int count = 0, size = GetROMSize(); - for (int i = 0; i < size; i++) + for (var i = 0; i < size; i++) { - Data.FlagType flag = GetFlag(i); + var flag = GetFlag(i); - if (flag == Data.FlagType.Opcode) + switch (flag) { - int len = GetInstructionLength(i); - for (int j = 1; j < len && i + j < size; j++) + case FlagType.Opcode: { - if (GetFlag(i + j) != Data.FlagType.Operand) + int len = GetInstructionLength(i); + for (var j = 1; j < len && i + j < size; j++) { - SetFlag(i + j, Data.FlagType.Operand); - count++; + if (GetFlag(i + j) != Data.FlagType.Operand) + { + SetFlag(i + j, Data.FlagType.Operand); + count++; + } } + i += len - 1; + break; } - i += len - 1; - } - else if (flag == Data.FlagType.Operand) - { - SetFlag(i, Data.FlagType.Opcode); - count++; - i--; - } - else if (Util.TypeStepSize(flag) > 1) - { - int step = Util.TypeStepSize(flag); - for (int j = 1; j < step; j++) + case Data.FlagType.Operand: + SetFlag(i, Data.FlagType.Opcode); + count++; + i--; + break; + default: { - if (GetFlag(i + j) != flag) + if (Util.TypeStepSize(flag) > 1) { - SetFlag(i + j, flag); - count++; + int step = Util.TypeStepSize(flag); + for (int j = 1; j < step; j++) + { + if (GetFlag(i + j) == flag) + continue; + SetFlag(i + j, flag); + count++; + } + i += step - 1; } + + break; } - i += step - 1; } } @@ -694,16 +591,17 @@ public void RescanInOutPoints() { if (GetFlag(i) == Data.FlagType.Opcode) { - switch (GetArchitechture(i)) + switch (GetArchitecture(i)) { - case Data.Architechture.CPU65C816: CPU65C816.MarkInOutPoints(i); break; - case Data.Architechture.APUSPC700: break; - case Data.Architechture.GPUSuperFX: break; + case Data.Architecture.CPU65C816: CPU65C816.MarkInOutPoints(i); break; + case Data.Architecture.APUSPC700: break; + case Data.Architecture.GPUSuperFX: break; } } } } + // move out of here to extension method or just external method public int ImportUsageMap(byte[] usageMap) { int size = GetROMSize(); @@ -762,24 +660,24 @@ public int ImportUsageMap(byte[] usageMap) public int GetIntermediateAddress(int offset, bool resolve = false) { // FIX ME: log and generation of dp opcodes. search references - switch (GetArchitechture(offset)) + return GetArchitecture(offset) switch { - case Data.Architechture.CPU65C816: return CPU65C816.GetIntermediateAddress(offset, resolve); - case Data.Architechture.APUSPC700: return -1; - case Data.Architechture.GPUSuperFX: return -1; - } - return -1; + Data.Architecture.CPU65C816 => CPU65C816.GetIntermediateAddress(offset, resolve), + Data.Architecture.APUSPC700 => -1, + Data.Architecture.GPUSuperFX => -1, + _ => -1 + }; } public string GetInstruction(int offset) { - switch (GetArchitechture(offset)) + return GetArchitecture(offset) switch { - case Data.Architechture.CPU65C816: return CPU65C816.GetInstruction(offset); - case Data.Architechture.APUSPC700: return ""; - case Data.Architechture.GPUSuperFX: return ""; - } - return ""; + Data.Architecture.CPU65C816 => CPU65C816.GetInstruction(offset), + Data.Architecture.APUSPC700 => "", + Data.Architecture.GPUSuperFX => "", + _ => "" + }; } // this class exists for performance optimization ONLY. @@ -873,46 +771,6 @@ int GetHexValueAt(int startIndex, int length) return modified; } - public void ImportBizHawkCDL(BizHawkCdl cdl) - { - if (!cdl.TryGetValue("CARTROM", out var cdlRomFlags)) - { - throw new InvalidDataException("The CDL file does not contain CARTROM block."); - } - - var size = Math.Min(cdlRomFlags.Count, GetROMSize()); - bool m = false; - bool x = false; - for (var offset = 0; offset < size; offset++) - { - var cdlFlag = cdlRomFlags[offset]; - if (cdlFlag == BizHawkCdl.Flag.None) - continue; - - var type = Data.FlagType.Unreached; - if ((cdlFlag & BizHawkCdl.Flag.ExecFirst) != 0) - { - type = Data.FlagType.Opcode; - m = (cdlFlag & BizHawkCdl.Flag.CPUMFlag) != 0; - x = (cdlFlag & BizHawkCdl.Flag.CPUXFlag) != 0; - } - else if ((cdlFlag & BizHawkCdl.Flag.ExecOperand) != 0) - type = Data.FlagType.Operand; - else if ((cdlFlag & BizHawkCdl.Flag.CPUData) != 0) - type = Data.FlagType.Data8Bit; - else if ((cdlFlag & BizHawkCdl.Flag.DMAData) != 0) - type = Data.FlagType.Data8Bit; - Mark(offset, type, 1); - - if (type == Data.FlagType.Opcode || type == Data.FlagType.Operand) - { - // Operand reuses the last M and X flag values used in Opcode, - // since BizHawk CDL records M and X flags only in Opcode. - MarkMFlag(offset, m, 1); - MarkXFlag(offset, x, 1); - } - } - } #region Equality protected bool Equals(Data other) { diff --git a/DiztinGUIsh/core/LogCreator.cs b/DiztinGUIsh/core/LogCreator.cs index 66272a57..7bb67d0b 100644 --- a/DiztinGUIsh/core/LogCreator.cs +++ b/DiztinGUIsh/core/LogCreator.cs @@ -61,7 +61,7 @@ public class OutputResult private class AssemblerHandler : Attribute { public string token; - public int weight; + public int length; } public StreamWriter StreamOutput { get; set; } @@ -106,7 +106,7 @@ private static void CacheAssemblerAttributeInfo() { var assemblerHandler = method.GetCustomAttribute(); var token = assemblerHandler.token; - var weight = assemblerHandler.weight; + var length = assemblerHandler.length; // check your method signature if you hit this stuff. Debug.Assert(method.GetParameters().Length == 2); @@ -119,7 +119,7 @@ private static void CacheAssemblerAttributeInfo() Debug.Assert(method.ReturnType == typeof(string)); - parameters.Add(token, (new Tuple(method, weight))); + parameters.Add(token, (new Tuple(method, length))); } Debug.Assert(parameters.Count != 0); @@ -127,12 +127,12 @@ private static void CacheAssemblerAttributeInfo() public string GetParameter(int offset, string parameter, int length) { - if (!Parameters.TryGetValue(parameter, out var methodAndWeight)) + if (!Parameters.TryGetValue(parameter, out var methodAndLength)) { throw new InvalidDataException($"Unknown parameter: {parameter}"); } - var methodInfo = methodAndWeight.Item1; + var methodInfo = methodAndLength.Item1; var callParams = new object[] { offset, length }; var returnValue = methodInfo.Invoke(this, callParams); @@ -146,10 +146,16 @@ public OutputResult CreateLog() bankSize = Util.GetBankSize(Data.RomMapMode); errorCount = 0; + // TODO: this label combination isn't working well. fix. + // could create a copy of the data in the controller before we get here and + // pass that in. unsubscribe all the notify events from it first. + // ehhhh... is that a little weird... maybe. + // + // maybe just clone the list and use the local list instead, remove subscribes from just that. AddLabelSource(Data.Labels); AddLabelSource(ExtraLabels); + AddTemporaryLabels(); - // GenerateAdditionalExtraLabels(); usedLabels = new List(); @@ -161,6 +167,8 @@ public OutputResult CreateLog() int bank = -1; // show a progress bar while this happens + // TODO: this is view stuff, keep it out of here. + // call controller with "LongRunningTask" ProgressBarJob.Loop(size, () => { if (pointer >= size) @@ -205,9 +213,9 @@ private int WriteMainIncludes(int size) return pointer; } - private List> LabelSources { get; set; } = new List>(); + private List> LabelSources { get; set; } = new List>(); - public void AddLabelSource(Dictionary labelSource) + public void AddLabelSource(IDictionary labelSource) { LabelSources.Add(labelSource); } @@ -391,7 +399,7 @@ private void WriteAddress(ref int pointer, ref int bank) } var c1 = (Data.GetInOutPoint(pointer) & (Data.InOutPoint.ReadPoint)) != 0; - var c2 = (Data.GetAllLabels().TryGetValue(pointer, out var label) && label.name.Length > 0); + var c2 = (Data.Labels.TryGetValue(pointer, out var label) && label.name.Length > 0); if (c1 || c2) StreamOutput.WriteLine(GetLine(pointer, "empty")); @@ -407,7 +415,7 @@ private void WriteLabels(int pointer) var listToPrint = new Dictionary(); // part 1: important: include all labels we aren't defining somewhere else. needed for disassembly - foreach (var pair in Data.GetAllLabels()) + foreach (var pair in Data.Labels) { if (usedLabels.Contains(pair.Key)) continue; @@ -427,7 +435,7 @@ private void WriteLabels(int pointer) if (Settings.includeUnusedLabels) { SwitchOutputFile(pointer, $"{folder}/all-labels.txt"); - foreach (var pair in Data.GetAllLabels()) + foreach (var pair in Data.Labels) { // not the best place to add formatting, TODO: cleanup var category = listToPrint.ContainsKey(pair.Key) ? "INLINE" : "EXTRA "; @@ -586,14 +594,14 @@ public static bool ValidateFormat(string formatString) } // just a % - [AssemblerHandler(token = "", weight = 1)] + [AssemblerHandler(token = "", length = 1)] private string GetPercent(int offset, int length) { return "%"; } // all spaces - [AssemblerHandler(token = "%empty", weight = 1)] + [AssemblerHandler(token = "%empty", length = 1)] private string GetEmpty(int offset, int length) { return string.Format("{0," + length + "}", ""); @@ -601,7 +609,7 @@ private string GetEmpty(int offset, int length) // trim to length // negative length = right justified - [AssemblerHandler(token = "label", weight = -22)] + [AssemblerHandler(token = "label", length = -22)] private string GetLabel(int offset, int length) { var snes = Data.ConvertPCtoSNES(offset); @@ -615,7 +623,7 @@ private string GetLabel(int offset, int length) } // trim to length - [AssemblerHandler(token = "code", weight = 37)] + [AssemblerHandler(token = "code", length = 37)] private string GetCode(int offset, int length) { var bytes = GetLineByteLength(offset); @@ -660,14 +668,14 @@ private string GetCode(int offset, int length) return string.Format("{0," + (length * -1) + "}", code); } - [AssemblerHandler(token = "%org", weight = 37)] + [AssemblerHandler(token = "%org", length = 37)] private string GetORG(int offset, int length) { string org = "ORG " + Util.NumberToBaseString(Data.ConvertPCtoSNES(offset), Util.NumberBase.Hexadecimal, 6, true); return string.Format("{0," + (length * -1) + "}", org); } - [AssemblerHandler(token = "%map", weight = 37)] + [AssemblerHandler(token = "%map", length = 37)] private string GetMap(int offset, int length) { string s = ""; @@ -685,7 +693,7 @@ private string GetMap(int offset, int length) } // 0+ = bank_xx.asm, -1 = labels.asm - [AssemblerHandler(token = "%incsrc", weight = 1)] + [AssemblerHandler(token = "%incsrc", length = 1)] private string GetIncSrc(int offset, int length) { string s = "incsrc \"labels.asm\""; @@ -697,7 +705,7 @@ private string GetIncSrc(int offset, int length) return string.Format("{0," + (length * -1) + "}", s); } - [AssemblerHandler(token = "%bankcross", weight = 1)] + [AssemblerHandler(token = "%bankcross", length = 1)] private string GetBankCross(int offset, int length) { string s = "check bankcross off"; @@ -705,7 +713,7 @@ private string GetBankCross(int offset, int length) } // length forced to 6 - [AssemblerHandler(token = "ia", weight = 6)] + [AssemblerHandler(token = "ia", length = 6)] private string GetIntermediateAddress(int offset, int length) { int ia = Data.GetIntermediateAddressOrPointer(offset); @@ -713,21 +721,21 @@ private string GetIntermediateAddress(int offset, int length) } // length forced to 6 - [AssemblerHandler(token = "pc", weight = 6)] + [AssemblerHandler(token = "pc", length = 6)] private string GetProgramCounter(int offset, int length) { return Util.NumberToBaseString(Data.ConvertPCtoSNES(offset), Util.NumberBase.Hexadecimal, 6); } // trim to length - [AssemblerHandler(token = "offset", weight = -6)] + [AssemblerHandler(token = "offset", length = -6)] private string GetOffset(int offset, int length) { return string.Format("{0," + (length * -1) + "}", Util.NumberToBaseString(offset, Util.NumberBase.Hexadecimal, 0)); } // length forced to 8 - [AssemblerHandler(token = "bytes", weight = 8)] + [AssemblerHandler(token = "bytes", length = 8)] private string GetRawBytes(int offset, int length) { string bytes = ""; @@ -742,28 +750,28 @@ private string GetRawBytes(int offset, int length) } // trim to length - [AssemblerHandler(token = "comment", weight = 1)] + [AssemblerHandler(token = "comment", length = 1)] private string GetComment(int offset, int length) { return string.Format("{0," + (length * -1) + "}", Data.GetComment(Data.ConvertPCtoSNES(offset))); } // length forced to 2 - [AssemblerHandler(token = "b", weight = 2)] + [AssemblerHandler(token = "b", length = 2)] private string GetDataBank(int offset, int length) { return Util.NumberToBaseString(Data.GetDataBank(offset), Util.NumberBase.Hexadecimal, 2); } // length forced to 4 - [AssemblerHandler(token = "d", weight = 4)] + [AssemblerHandler(token = "d", length = 4)] private string GetDirectPage(int offset, int length) { return Util.NumberToBaseString(Data.GetDirectPage(offset), Util.NumberBase.Hexadecimal, 4); } // if length == 1, M/m, else 08/16 - [AssemblerHandler(token = "m", weight = 1)] + [AssemblerHandler(token = "m", length = 1)] private string GetMFlag(int offset, int length) { var m = Data.GetMFlag(offset); @@ -772,7 +780,7 @@ private string GetMFlag(int offset, int length) } // if length == 1, X/x, else 08/16 - [AssemblerHandler(token = "x", weight = 1)] + [AssemblerHandler(token = "x", length = 1)] private string GetXFlag(int offset, int length) { var x = Data.GetXFlag(offset); @@ -781,7 +789,7 @@ private string GetXFlag(int offset, int length) } // output label at snes offset, and its value - [AssemblerHandler(token = "%labelassign", weight = 1)] + [AssemblerHandler(token = "%labelassign", length = 1)] private string GetLabelAssign(int offset, int length) { var labelName = GetLabelName(offset); diff --git a/DiztinGUIsh/core/Project.cs b/DiztinGUIsh/core/Project.cs index 98318b32..bef85953 100644 --- a/DiztinGUIsh/core/Project.cs +++ b/DiztinGUIsh/core/Project.cs @@ -1,39 +1,87 @@ -using DiztinGUIsh.window; -using System; +using System; using System.Collections.Generic; using System.Diagnostics; -using System.IO; using System.Windows.Forms; -using ExtendedXmlSerializer; namespace DiztinGUIsh { - // MODEL - public class Project + public class Project : DizModel { // Any public properties will be automatically serialized to XML. - // They require a get AND set. + // They require a get AND set. Order is important. + public string ProjectFileName + { + get => projectFileName; + set => SetField(ref projectFileName, value); + } - public string ProjectFileName { get; set; } - public string AttachedRomFilename { get; set; } - public bool UnsavedChanges { get; set; } + public string AttachedRomFilename + { + get => attachedRomFilename; + set => SetField(ref attachedRomFilename, value); + } - // safety check: these are copies of data in the ROM, they must always match the ROM on project load - // or else we might be looking at the wrong file. - public string InternalRomGameName { get; set; } - public int InternalCheckSum { get; set; } = -1; + // would be cool to make this more automatic. probably hook into SetField() + // for a lot of it. + public bool UnsavedChanges + { + get => unsavedChanges; + set => SetField(ref unsavedChanges, value); + } - // needs to come last for serialization - public Data Data { get; set; } + // safety checks: + // The rom "Game name" and "Checksum" are copies of certain bytes from the ROM which + // get stored with the project file. REMEMBER: We don't store the actual ROM bytes + // in the project file, so when we load a project, we must also open the same ROM and load its + // bytes in the project. + // + // Project = Metadata + // Rom = The real data + // + // If we load a ROM, and then its checksum and name don't match what we have stored, + // then we have an issue (i.e. not the same ROM, or it was modified, or missing, etc). + // The user must either provide the correct ROM, or abort loading the project. + public string InternalRomGameName + { + get => internalRomGameName; + set => SetField(ref internalRomGameName, value); + } - public LogWriterSettings LogWriterSettings; + public int InternalCheckSum + { + get => internalCheckSum; + set => SetField(ref internalCheckSum, value); + } + + public LogWriterSettings LogWriterSettings + { + get => logWriterSettings; + set => SetField(ref logWriterSettings, value); + } + + // purely visual. what offset is currently being looked at in the main grid. + // we store it here because we want to save it out with the project file + private int currentViewOffset; + public int CurrentViewOffset + { + get => currentViewOffset; + set => SetField(ref currentViewOffset, value); + } + + // needs to come last for serialization. this is the heart of the app, the actual + // data from the ROM and metadata we add/create. + public Data Data + { + get => data; + set => SetField(ref data, value); + } public Project() { LogWriterSettings.SetDefaults(); } - public class ImportRomSettings + public struct ImportRomSettings { public Data.ROMMapMode ROMMapMode; public Data.ROMSpeed ROMSpeed; @@ -45,49 +93,26 @@ public class ImportRomSettings public string rom_filename; } - public void ImportRomAndCreateNewProject(ImportRomSettings importSettings) - { - AttachedRomFilename = importSettings.rom_filename; - UnsavedChanges = false; - ProjectFileName = null; - - Data = new Data(); - Data.Initiate(importSettings.rom_bytes, importSettings.ROMMapMode, importSettings.ROMSpeed); - - // TODO: get this UI out of here. probably just use databinding instead - // AliasList.me.ResetDataGrid(); - - if (importSettings.InitialLabels.Count > 0) - { - foreach (var pair in importSettings.InitialLabels) - Data.AddLabel(pair.Key, pair.Value, true); - UnsavedChanges = true; - } - - if (importSettings.InitialHeaderFlags.Count > 0) - { - foreach (var pair in importSettings.InitialHeaderFlags) - Data.SetFlag(pair.Key, pair.Value); - UnsavedChanges = true; - } - - // Save a copy of these identifying ROM bytes with the project file itself. - // When we reload, we will make sure the linked ROM still matches them. - InternalCheckSum = Data.GetRomCheckSumsFromRomBytes(); - InternalRomGameName = Data.GetRomNameFromRomBytes(); - } + private string projectFileName; + private string attachedRomFilename; + private bool unsavedChanges; + private string internalRomGameName; + private int internalCheckSum = -1; + private Data data; + private LogWriterSettings logWriterSettings; public byte[] ReadFromOriginalRom() { string firstRomFileWeTried; var nextFileToTry = firstRomFileWeTried = AttachedRomFilename; - byte[] rom = null; + byte[] rom; do { - var error = ReadROMIfMatchesProject(nextFileToTry, out rom); + var error = ReadRomIfMatchesProject(nextFileToTry, out rom); if (error == null) break; + // TODO: move to controller nextFileToTry = PromptForNewRom($"{error} Link a new ROM now?"); if (nextFileToTry == null) return null; @@ -101,7 +126,7 @@ public byte[] ReadFromOriginalRom() return rom; } - private string ReadROMIfMatchesProject(string filename, out byte[] rom_bytes) + private string ReadRomIfMatchesProject(string filename, out byte[] rom_bytes) { string error_msg = null; @@ -121,41 +146,21 @@ private string ReadROMIfMatchesProject(string filename, out byte[] rom_bytes) return error_msg; } - // returns error message if it's not identical, or null if everything is OK. - private string IsThisRomIsIdenticalToUs(byte[] rom) - { - var offset = Data.GetRomSettingOffset(Data.RomMapMode); - if (rom.Length <= offset + 10) - return "The linked ROM is too small. It can't be opened."; - - var romInternalGameName = Util.ReadStringFromByteArray(rom, 0x15, offset); - - var myChecksums = Util.ByteArrayToInteger(rom, offset + 7); - - if (romInternalGameName != InternalRomGameName) - return $"The linked ROM's internal name '{romInternalGameName}' doesn't " + - $"match the project's internal name of '{InternalRomGameName}'."; - - if (myChecksums != InternalCheckSum) - return $"The linked ROM's checksums '{myChecksums:X8}' " + - $"don't match the project's checksums of '{InternalCheckSum:X8}'."; - - return null; - } - + private string IsThisRomIsIdenticalToUs(byte[] romBytes) => + Util.IsThisRomIsIdenticalToUs(romBytes, Data.RomMapMode, InternalRomGameName, InternalCheckSum); private string PromptForNewRom(string promptText) { + // TODO: put this in the view, hooked up through controller. + var dialogResult = MessageBox.Show(promptText, "Error", MessageBoxButtons.YesNo, MessageBoxIcon.Error); - if (dialogResult == DialogResult.No) - return null; - - return PromptToSelectFile(); + return dialogResult == DialogResult.Yes ? PromptToSelectFile() : null; } private string PromptToSelectFile() { + // TODO: move to controller return Util.PromptToSelectFile(ProjectFileName); } diff --git a/DiztinGUIsh/core/ROMByte.cs b/DiztinGUIsh/core/ROMByte.cs index ba376bcc..c8bdb365 100644 --- a/DiztinGUIsh/core/ROMByte.cs +++ b/DiztinGUIsh/core/ROMByte.cs @@ -48,7 +48,7 @@ public override int GetHashCode() public bool XFlag { get; set; } public bool MFlag { get; set; } public Data.FlagType TypeFlag { get; set; } - public Data.Architechture Arch { get; set; } + public Data.Architecture Arch { get; set; } public Data.InOutPoint Point { get; set; } } } diff --git a/DiztinGUIsh/core/import/BizHawkCdl.cs b/DiztinGUIsh/core/import/BizHawkCdl.cs index 00852dfb..051be676 100644 --- a/DiztinGUIsh/core/import/BizHawkCdl.cs +++ b/DiztinGUIsh/core/import/BizHawkCdl.cs @@ -5,8 +5,10 @@ namespace DiztinGUIsh { - public class BizHawkCdl : Dictionary> + public class BizHawkCdl { + private Dictionary> cdl = new Dictionary>(); + [Flags] public enum Flag : byte { @@ -20,49 +22,84 @@ public enum Flag : byte BRR = 0x80 } - public static BizHawkCdl LoadFromFile(string path) + public static void Import(string filename, Data data) { - using (var fs = new FileStream(path, FileMode.Open)) - { - return LoadFromStream(fs); - } + var cdl = new BizHawkCdl(); + cdl.LoadFromFile(filename); + cdl.CopyInto(data); + } + + private void LoadFromFile(string path) + { + using var fs = new FileStream(path, FileMode.Open); + LoadFromStream(fs); } - public static BizHawkCdl LoadFromStream(Stream input) + private void LoadFromStream(Stream input) { var br = new BinaryReader(input); string id = br.ReadString(); - string subType; - if (id == "BIZHAWK-CDL-1") + string subType = id switch { - subType = "PCE"; - } - else if (id == "BIZHAWK-CDL-2") - { - subType = br.ReadString().TrimEnd(' '); - } - else - { - throw new InvalidDataException("File is not a BizHawk CDL file."); - } + "BIZHAWK-CDL-1" => "PCE", + "BIZHAWK-CDL-2" => br.ReadString().TrimEnd(' '), + _ => throw new InvalidDataException("File is not a BizHawk CDL file.") + }; if (subType != "SNES") { throw new InvalidDataException("The CDL file is not for SNES."); } - var cdl = new BizHawkCdl(); int count = br.ReadInt32(); - for (int i = 0; i < count; i++) + for (var i = 0; i < count; i++) { string key = br.ReadString(); int len = br.ReadInt32(); var data = br.ReadBytes(len).Select(b => (Flag)b).ToArray(); cdl[key] = data; } + } + private void CopyInto(Data data) + { + if (!cdl.TryGetValue("CARTROM", out var cdlRomFlags)) + { + throw new InvalidDataException("The CDL file does not contain CARTROM block."); + } - return cdl; + var size = Math.Min(cdlRomFlags.Count, data.GetROMSize()); + bool m = false; + bool x = false; + for (var offset = 0; offset < size; offset++) + { + var cdlFlag = cdlRomFlags[offset]; + if (cdlFlag == BizHawkCdl.Flag.None) + continue; + + var type = Data.FlagType.Unreached; + if ((cdlFlag & BizHawkCdl.Flag.ExecFirst) != 0) + { + type = Data.FlagType.Opcode; + m = (cdlFlag & BizHawkCdl.Flag.CPUMFlag) != 0; + x = (cdlFlag & BizHawkCdl.Flag.CPUXFlag) != 0; + } + else if ((cdlFlag & BizHawkCdl.Flag.ExecOperand) != 0) + type = Data.FlagType.Operand; + else if ((cdlFlag & BizHawkCdl.Flag.CPUData) != 0) + type = Data.FlagType.Data8Bit; + else if ((cdlFlag & BizHawkCdl.Flag.DMAData) != 0) + type = Data.FlagType.Data8Bit; + data.Mark(offset, type, 1); + + if (type != Data.FlagType.Opcode && type != Data.FlagType.Operand) + continue; + + // Operand reuses the last M and X flag values used in Opcode, + // since BizHawk CDL records M and X flags only in Opcode. + data.MarkMFlag(offset, m, 1); + data.MarkXFlag(offset, x, 1); + } } } } diff --git a/DiztinGUIsh/core/import/SampleRomData.cs b/DiztinGUIsh/core/import/SampleRomData.cs index ee755934..eaeb446c 100644 --- a/DiztinGUIsh/core/import/SampleRomData.cs +++ b/DiztinGUIsh/core/import/SampleRomData.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using DiztinGUIsh.Properties; +using DiztinGUIsh.core.util; namespace DiztinGUIsh { @@ -13,166 +8,169 @@ public static SampleRomData SampleData { get { + // take our sample data from below and construct some extra stuff into it. + // then, cache all this in a static read-only property + if (finalSampleData != null) return finalSampleData; - while (baseSampleData.RomBytes.Count < 0x8000) - baseSampleData.RomBytes.Add(new ROMByte()); + while (BaseSampleData.RomBytes.Count < 0x8000) + BaseSampleData.RomBytes.Add(new ROMByte()); - finalSampleData = baseSampleData; - return baseSampleData; + finalSampleData = BaseSampleData; + return BaseSampleData; } } - private static SampleRomData finalSampleData = null; + private static SampleRomData finalSampleData; - private static readonly SampleRomData baseSampleData = new SampleRomData + private static readonly SampleRomData BaseSampleData = new SampleRomData { // random sample code I made up; hopefully it shows a little bit of // everything so you can see how the settings will effect the output RomBytes = new RomBytes { - new ROMByte {Rom = 0x78, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true, Point = Data.InOutPoint.InPoint}, - new ROMByte {Rom = 0xA9, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true}, - new ROMByte {Rom = 0x01, TypeFlag = Data.FlagType.Operand}, - new ROMByte {Rom = 0x8D, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true}, - new ROMByte {Rom = 0x0D, TypeFlag = Data.FlagType.Operand}, - new ROMByte {Rom = 0x42, TypeFlag = Data.FlagType.Operand}, - new ROMByte {Rom = 0x5C, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true, Point = Data.InOutPoint.EndPoint}, - new ROMByte {Rom = 0x0A, TypeFlag = Data.FlagType.Operand}, - new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand}, - new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand}, - new ROMByte {Rom = 0xC2, TypeFlag = Data.FlagType.Opcode, MFlag = true, XFlag = true, Point = Data.InOutPoint.InPoint}, - new ROMByte {Rom = 0x30, TypeFlag = Data.FlagType.Operand}, - new ROMByte {Rom = 0xA9, TypeFlag = Data.FlagType.Opcode}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand}, - new ROMByte {Rom = 0x21, TypeFlag = Data.FlagType.Operand}, - new ROMByte {Rom = 0x5B, TypeFlag = Data.FlagType.Opcode}, - new ROMByte {Rom = 0x4B, TypeFlag = Data.FlagType.Opcode, DirectPage = 0x2100}, - new ROMByte {Rom = 0xAB, TypeFlag = Data.FlagType.Opcode, DirectPage = 0x2100}, - new ROMByte {Rom = 0xA2, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x07, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xBF, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x32, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x9F, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x7E, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xCA, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xCA, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x10, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xF4, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x64, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x40, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x64, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x41, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x64, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x42, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x64, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x43, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xAE, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xFC, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x3A, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x4C, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.EndPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xC0, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Data16Bit, Point = Data.InOutPoint.ReadPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x08, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x10, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x20, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x44, TypeFlag = Data.FlagType.Pointer16Bit, Point = Data.InOutPoint.ReadPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x7B, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x44, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x81, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xC4, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x81, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x0A, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x82, TypeFlag = Data.FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x08, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x8B, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x4B, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xAB, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xE2, TypeFlag = Data.FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x20, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xC2, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x10, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xA2, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x1F, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xBD, TypeFlag = Data.FlagType.Opcode, MFlag = true, Point = Data.InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x5B, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x9D, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x01, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xCA, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x10, TypeFlag = Data.FlagType.Opcode, MFlag = true, Point = Data.InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xF7, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xAB, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x28, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x60, TypeFlag = Data.FlagType.Opcode, Point = Data.InOutPoint.EndPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x45, TypeFlag = Data.FlagType.Data8Bit, Point = Data.InOutPoint.ReadPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x8D, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x69, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x83, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xB2, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x99, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x23, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x01, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xA3, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xF8, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x52, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x08, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xBB, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x29, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x5C, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x32, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xE7, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x88, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x3C, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x30, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x18, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x9A, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xB0, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x34, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x8C, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xDD, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x05, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xB7, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x83, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x34, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x6D, TypeFlag = Data.FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x78, TypeFlag = FlagType.Opcode, MFlag = true, XFlag = true, Point = InOutPoint.InPoint}, + new ROMByte {Rom = 0xA9, TypeFlag = FlagType.Opcode, MFlag = true, XFlag = true}, + new ROMByte {Rom = 0x01, TypeFlag = FlagType.Operand}, + new ROMByte {Rom = 0x8D, TypeFlag = FlagType.Opcode, MFlag = true, XFlag = true}, + new ROMByte {Rom = 0x0D, TypeFlag = FlagType.Operand}, + new ROMByte {Rom = 0x42, TypeFlag = FlagType.Operand}, + new ROMByte {Rom = 0x5C, TypeFlag = FlagType.Opcode, MFlag = true, XFlag = true, Point = InOutPoint.EndPoint}, + new ROMByte {Rom = 0x0A, TypeFlag = FlagType.Operand}, + new ROMByte {Rom = 0x80, TypeFlag = FlagType.Operand}, + new ROMByte {Rom = 0x80, TypeFlag = FlagType.Operand}, + new ROMByte {Rom = 0xC2, TypeFlag = FlagType.Opcode, MFlag = true, XFlag = true, Point = InOutPoint.InPoint}, + new ROMByte {Rom = 0x30, TypeFlag = FlagType.Operand}, + new ROMByte {Rom = 0xA9, TypeFlag = FlagType.Opcode}, + new ROMByte {Rom = 0x00, TypeFlag = FlagType.Operand}, + new ROMByte {Rom = 0x21, TypeFlag = FlagType.Operand}, + new ROMByte {Rom = 0x5B, TypeFlag = FlagType.Opcode}, + new ROMByte {Rom = 0x4B, TypeFlag = FlagType.Opcode, DirectPage = 0x2100}, + new ROMByte {Rom = 0xAB, TypeFlag = FlagType.Opcode, DirectPage = 0x2100}, + new ROMByte {Rom = 0xA2, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x07, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xBF, TypeFlag = FlagType.Opcode, Point = InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x32, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x80, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x80, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x9F, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x7E, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xCA, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xCA, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x10, TypeFlag = FlagType.Opcode, Point = InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xF4, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x64, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x40, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x64, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x41, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x64, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x42, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x64, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x43, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xAE, TypeFlag = FlagType.Opcode, Point = InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xFC, TypeFlag = FlagType.Opcode, Point = InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x3A, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x80, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x4C, TypeFlag = FlagType.Opcode, Point = InOutPoint.EndPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xC0, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = FlagType.Data16Bit, Point = InOutPoint.ReadPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x08, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x10, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x20, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x44, TypeFlag = FlagType.Pointer16Bit, Point = InOutPoint.ReadPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x80, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x7B, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x80, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x44, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x81, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xC4, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x81, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x0A, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x82, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x08, TypeFlag = FlagType.Opcode, Point = InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x8B, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x4B, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xAB, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xE2, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x20, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xC2, TypeFlag = FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x10, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xA2, TypeFlag = FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x1F, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xBD, TypeFlag = FlagType.Opcode, MFlag = true, Point = InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x5B, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x80, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x9D, TypeFlag = FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x01, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xCA, TypeFlag = FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x10, TypeFlag = FlagType.Opcode, MFlag = true, Point = InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xF7, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xAB, TypeFlag = FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x28, TypeFlag = FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x60, TypeFlag = FlagType.Opcode, Point = InOutPoint.EndPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x45, TypeFlag = FlagType.Data8Bit, Point = InOutPoint.ReadPoint, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x8D, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x69, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x83, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xB2, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x99, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x00, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x23, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x01, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xA3, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xF8, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x52, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x08, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xBB, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x29, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x5C, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x32, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xE7, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x88, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x3C, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x30, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x18, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x9A, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xB0, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x34, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x8C, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xDD, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x05, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0xB7, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x83, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x34, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new ROMByte {Rom = 0x6D, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, }, - Comments = new Dictionary + Comments = new ObservableDictionary { {0x03, "this sets FastROM"}, {0x0F, "direct page = $2100"}, {0x21, "clear APU regs"}, {0x44, "this routine copies Test_Data to $7E0100"} }, - Labels = new Dictionary + Labels = new ObservableDictionary { - {0x00, new Label() {name = "Emulation_RESET", comment = "Sample emulation reset location"}}, - {0x0A, new Label() {name = "FastRESET", comment = "Sample label"}}, - {0x32, new Label() {name = "Test_Indices"}}, - {0x3A, new Label() {name = "Pointer_Table"}}, - {0x44, new Label() {name = "First_Routine"}}, - {0x5B, new Label() {name = "Test_Data", comment = "Pretty cool huh?"}} + {0x00, new Label {name = "Emulation_RESET", comment = "Sample emulation reset location"}}, + {0x0A, new Label {name = "FastRESET", comment = "Sample label"}}, + {0x32, new Label {name = "Test_Indices"}}, + {0x3A, new Label {name = "Pointer_Table"}}, + {0x44, new Label {name = "First_Routine"}}, + {0x5B, new Label {name = "Test_Data", comment = "Pretty cool huh?"}} }, - RomMapMode = Data.ROMMapMode.LoROM, - RomSpeed = Data.ROMSpeed.FastROM, + RomMapMode = ROMMapMode.LoROM, + RomSpeed = ROMSpeed.FastROM, }; } } diff --git a/DiztinGUIsh/core/util/ObservableDictionary.cs b/DiztinGUIsh/core/util/ObservableDictionary.cs new file mode 100644 index 00000000..ccc081b7 --- /dev/null +++ b/DiztinGUIsh/core/util/ObservableDictionary.cs @@ -0,0 +1,228 @@ +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Diagnostics; + +namespace DiztinGUIsh.core.util +{ + // based on: kzu/ObservableDictionary.cs https://gist.github.com/kzu/cfe3cb6e4fe3efea6d24 + // note: does newer .NET have a native version of this? if so, replace. + + /// + /// Provides a dictionary for use with data binding. + /// + /// Specifies the type of the keys in this collection. + /// Specifies the type of the values in this collection. + [DebuggerDisplay("Count={" + nameof(Count) + "}")] + public class ObservableDictionary : + /*ICollection>,*/ + IDictionary, + INotifyCollectionChanged, INotifyPropertyChanged + { + private readonly IDictionary dictionary; + + /// Event raised when the collection changes. + public event NotifyCollectionChangedEventHandler CollectionChanged = (sender, args) => { }; + + /// Event raised when a property on the collection changes. + public event PropertyChangedEventHandler PropertyChanged = (sender, args) => { }; + + /// + /// Initializes an instance of the class. + /// + public ObservableDictionary() + : this(new Dictionary()) + { + } + + /// + /// Initializes an instance of the class using another dictionary as + /// the key/value store. + /// + public ObservableDictionary(IDictionary dictionary) + { + this.dictionary = dictionary; + } + + private void AddWithNotification(KeyValuePair item) + { + AddWithNotification(item.Key, item.Value); + } + + private void AddWithNotification(TKey key, TValue value) + { + dictionary.Add(key, value); + + CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, + new KeyValuePair(key, value))); + PropertyChanged(this, new PropertyChangedEventArgs("Count")); + PropertyChanged(this, new PropertyChangedEventArgs("Keys")); + PropertyChanged(this, new PropertyChangedEventArgs("Values")); + } + + private bool RemoveWithNotification(TKey key) + { + if (!dictionary.TryGetValue(key, out var value) || !dictionary.Remove(key)) + return false; + + CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, + new KeyValuePair(key, value))); + PropertyChanged(this, new PropertyChangedEventArgs("Count")); + PropertyChanged(this, new PropertyChangedEventArgs("Keys")); + PropertyChanged(this, new PropertyChangedEventArgs("Values")); + + return true; + } + + private void UpdateWithNotification(TKey key, TValue value) + { + if (!dictionary.TryGetValue(key, out var existing)) + { + AddWithNotification(key, value); + return; + } + + dictionary[key] = value; + + CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, + new KeyValuePair(key, value), + new KeyValuePair(key, existing))); + PropertyChanged(this, new PropertyChangedEventArgs("Values")); + } + + /// + /// Allows derived classes to raise custom property changed events. + /// + protected void RaisePropertyChanged(PropertyChangedEventArgs args) + { + PropertyChanged(this, args); + } + + #region IDictionary Members + + /// + /// Adds an element with the provided key and value to the . + /// + /// The object to use as the key of the element to add. + /// The object to use as the value of the element to add. + public void Add(TKey key, TValue value) + { + AddWithNotification(key, value); + } + + /// + /// Determines whether the contains an element with the specified key. + /// + /// The key to locate in the . + /// + /// true if the contains an element with the key; otherwise, false. + /// + public bool ContainsKey(TKey key) + { + return dictionary.ContainsKey(key); + } + + /// + /// Gets an containing the keys of the . + /// + /// An containing the keys of the object that implements . + public ICollection Keys => dictionary.Keys; + + /// + /// Removes the element with the specified key from the . + /// + /// The key of the element to remove. + /// + /// true if the element is successfully removed; otherwise, false. This method also returns false if was not found in the original . + /// + public bool Remove(TKey key) + { + return RemoveWithNotification(key); + } + + /// + /// Gets the value associated with the specified key. + /// + /// The key whose value to get. + /// When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the parameter. This parameter is passed uninitialized. + /// + /// true if the object that implements contains an element with the specified key; otherwise, false. + /// + public bool TryGetValue(TKey key, out TValue value) + { + return dictionary.TryGetValue(key, out value); + } + + /// + /// Gets an containing the values in the . + /// + /// An containing the values in the object that implements . + public ICollection Values => dictionary.Values; + + /// + /// Gets or sets the element with the specified key. + /// + /// The key. + /// + public TValue this[TKey key] + { + get => dictionary[key]; + set => UpdateWithNotification(key, value); + } + + #endregion + + #region ICollection> Members + + public void Add(KeyValuePair item) + { + AddWithNotification(item); + } + + public void Clear() + { + dictionary.Clear(); + + CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + PropertyChanged(this, new PropertyChangedEventArgs("Count")); + PropertyChanged(this, new PropertyChangedEventArgs("Keys")); + PropertyChanged(this, new PropertyChangedEventArgs("Values")); + } + + public bool Contains(KeyValuePair item) + { + return dictionary.Contains(item); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + dictionary.CopyTo(array, arrayIndex); + } + + public int Count => dictionary.Count; + + public bool IsReadOnly => dictionary.IsReadOnly; + + public bool Remove(KeyValuePair item) + { + return RemoveWithNotification(item.Key); + } + + #endregion + + #region IEnumerable> Members + + IEnumerator> IEnumerable>.GetEnumerator() + { + return dictionary.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return dictionary.GetEnumerator(); + } + + #endregion + } +} diff --git a/DiztinGUIsh/core/util/RomUtil.cs b/DiztinGUIsh/core/util/RomUtil.cs new file mode 100644 index 00000000..37b7d82c --- /dev/null +++ b/DiztinGUIsh/core/util/RomUtil.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DiztinGUIsh.core.util +{ + public static class RomUtil + { + + } +} diff --git a/DiztinGUIsh/core/util/Util.cs b/DiztinGUIsh/core/util/Util.cs index 77103ae6..be55457d 100644 --- a/DiztinGUIsh/core/util/Util.cs +++ b/DiztinGUIsh/core/util/Util.cs @@ -21,12 +21,31 @@ public static int GetBankSize(Data.ROMMapMode mode) return mode == Data.ROMMapMode.LoROM ? 0x8000 : 0x10000; } + // verify the data in the provided ROM bytes matches the data we expect it to have. + // returns error message if it's not identical, or null if everything is OK. + public static string IsThisRomIsIdenticalToUs(byte[] rom, + Data.ROMMapMode mode, string internalGameNameMustMatch, int romChecksums) + { + var offset = Util.GetRomSettingOffset(mode); + if (rom.Length <= offset + 10) + return "The linked ROM is too small. It can't be opened."; + + var internalGameNameToVerify = Util.ReadStringFromByteArray(rom, 0x15, offset); + var checksumToVerify = Util.ByteArrayToInteger(rom, offset + 7); + + if (internalGameNameToVerify != internalGameNameMustMatch) + return $"The linked ROM's internal name '{internalGameNameToVerify}' doesn't " + + $"match the project's internal name of '{internalGameNameMustMatch}'."; + + if (checksumToVerify != romChecksums) + return $"The linked ROM's checksums '{checksumToVerify:X8}' " + + $"don't match the project's checksums of '{romChecksums:X8}'."; + + return null; + } public static int ConvertSNESToPC(int address, Data.ROMMapMode mode, int size) { - int _UnmirroredOffset(int offset) - { - return Util.UnmirroredOffset(offset, size); - } + int UnmirroredOffset(int offset) => Util.UnmirroredOffset(offset, size); // WRAM is N/A to PC addressing if ((address & 0xFE0000) == 0x7E0000) return -1; @@ -41,15 +60,15 @@ int _UnmirroredOffset(int offset) // SRAM is N/A to PC addressing if (((address & 0x700000) == 0x700000) && ((address & 0x8000) == 0)) return -1; - return _UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); + return UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); } case Data.ROMMapMode.HiROM: { - return _UnmirroredOffset(address & 0x3FFFFF); + return UnmirroredOffset(address & 0x3FFFFF); } case Data.ROMMapMode.SuperMMC: { - return _UnmirroredOffset(address & 0x3FFFFF); // todo, treated as hirom atm + return UnmirroredOffset(address & 0x3FFFFF); // todo, treated as hirom atm } case Data.ROMMapMode.SA1ROM: case Data.ROMMapMode.ExSA1ROM: @@ -60,9 +79,9 @@ int _UnmirroredOffset(int offset) if (address >= 0xC00000) { if (mode == Data.ROMMapMode.ExSA1ROM) - return _UnmirroredOffset(address & 0x7FFFFF); + return UnmirroredOffset(address & 0x7FFFFF); else - return _UnmirroredOffset(address & 0x3FFFFF); + return UnmirroredOffset(address & 0x3FFFFF); } else { @@ -71,7 +90,7 @@ int _UnmirroredOffset(int offset) // SRAM is N/A to PC addressing if (((address & 0x8000) == 0)) return -1; - return _UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); + return UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); } } case Data.ROMMapMode.SuperFX: @@ -81,31 +100,31 @@ int _UnmirroredOffset(int offset) if (address < 0x400000) { - return _UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); + return UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); } else if (address < 0x600000) { - return _UnmirroredOffset(address & 0x3FFFFF); + return UnmirroredOffset(address & 0x3FFFFF); } else if (address < 0xC00000) { - return 0x200000 + _UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); + return 0x200000 + UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); } else { - return 0x400000 + _UnmirroredOffset(address & 0x3FFFFF); + return 0x400000 + UnmirroredOffset(address & 0x3FFFFF); } } case Data.ROMMapMode.ExHiROM: { - return _UnmirroredOffset(((~address & 0x800000) >> 1) | (address & 0x3FFFFF)); + return UnmirroredOffset(((~address & 0x800000) >> 1) | (address & 0x3FFFFF)); } case Data.ROMMapMode.ExLoROM: { // SRAM is N/A to PC addressing if (((address & 0x700000) == 0x700000) && ((address & 0x8000) == 0)) return -1; - return _UnmirroredOffset((((address ^ 0x800000) & 0xFF0000) >> 1) | (address & 0x7FFF)); + return UnmirroredOffset((((address ^ 0x800000) & 0xFF0000) >> 1) | (address & 0x7FFF)); } default: { @@ -407,13 +426,26 @@ public static IEnumerable ReadLines(string path) } } - public static string ArchToString(Data.Architechture arch) + public static int GetRomSettingOffset(Data.ROMMapMode mode) + { + return mode switch + { + Data.ROMMapMode.LoROM => Data.LOROM_SETTING_OFFSET, + Data.ROMMapMode.HiROM => Data.HIROM_SETTING_OFFSET, + Data.ROMMapMode.ExHiROM => Data.EXHIROM_SETTING_OFFSET, + Data.ROMMapMode.ExLoROM => Data.EXLOROM_SETTING_OFFSET, + _ => Data.LOROM_SETTING_OFFSET + }; + } + + + public static string ArchToString(Data.Architecture arch) { switch (arch) { - case Data.Architechture.CPU65C816: return "65C816"; - case Data.Architechture.APUSPC700: return "SPC700"; - case Data.Architechture.GPUSuperFX: return "SuperFX"; + case Data.Architecture.CPU65C816: return "65C816"; + case Data.Architecture.APUSPC700: return "SPC700"; + case Data.Architecture.GPUSuperFX: return "SuperFX"; } return ""; } diff --git a/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs b/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs index e81c8cc9..c8f089d9 100644 --- a/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs +++ b/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs @@ -45,8 +45,10 @@ public override Project Load(byte[] data) byte version = data[0]; ValidateProjectFileVersion(version); - var project = new Project(); - project.Data = new Data(); + var project = new Project + { + Data = new Data() + }; // version 0 needs to convert PC to SNES for some addresses Util.AddressConverter converter = address => address; @@ -83,12 +85,10 @@ public override Project Load(byte[] data) for (int i = 0; i < size; i++) project.Data.SetXFlag(i, data[pointer + 3 * size + i] != 0); for (int i = 0; i < size; i++) project.Data.SetMFlag(i, data[pointer + 4 * size + i] != 0); for (int i = 0; i < size; i++) project.Data.SetFlag(i, (Data.FlagType)data[pointer + 5 * size + i]); - for (int i = 0; i < size; i++) project.Data.SetArchitechture(i, (Data.Architechture)data[pointer + 6 * size + i]); + for (int i = 0; i < size; i++) project.Data.SetArchitechture(i, (Data.Architecture)data[pointer + 6 * size + i]); for (int i = 0; i < size; i++) project.Data.SetInOutPoint(i, (Data.InOutPoint)data[pointer + 7 * size + i]); pointer += 8 * size; - // AliasList.me.ResetDataGrid(); // need this outta here. - ReadLabels(project, data, ref pointer, converter, version >= 2); ReadComments(project, data, ref pointer, converter); @@ -132,8 +132,8 @@ private byte[] SaveVersion(Project project, int version) // save all labels ad comments List label = new List(), comment = new List(); - var all_labels = project.Data.GetAllLabels(); - var all_comments = project.Data.GetAllComments(); + var all_labels = project.Data.Labels; + var all_comments = project.Data.Comments; Util.IntegerIntoByteList(all_labels.Count, label); foreach (var pair in all_labels) @@ -167,7 +167,7 @@ private byte[] SaveVersion(Project project, int version) for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 3 * size + i] = (byte)(project.Data.GetXFlag(i) ? 1 : 0); for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 4 * size + i] = (byte)(project.Data.GetMFlag(i) ? 1 : 0); for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 5 * size + i] = (byte)project.Data.GetFlag(i); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 6 * size + i] = (byte)project.Data.GetArchitechture(i); + for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 6 * size + i] = (byte)project.Data.GetArchitecture(i); for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 7 * size + i] = (byte)project.Data.GetInOutPoint(i); // ??? label.CopyTo(data, romSettings.Length + romLocation.Length + 8 * size); diff --git a/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs b/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs index 60151954..19a16d20 100644 --- a/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs +++ b/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs @@ -1,12 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Runtime.CompilerServices; +using System.IO; using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; using System.Xml; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; diff --git a/DiztinGUIsh/loadsave/xml_serializer/RomBytesXMLSerializer.cs b/DiztinGUIsh/loadsave/xml_serializer/RomBytesXMLSerializer.cs index ddc58f69..193ef5fa 100644 --- a/DiztinGUIsh/loadsave/xml_serializer/RomBytesXMLSerializer.cs +++ b/DiztinGUIsh/loadsave/xml_serializer/RomBytesXMLSerializer.cs @@ -324,7 +324,7 @@ private ROMByte DecodeRomByte(string line) newByte.DirectPage = int.Parse(line.Substring(4, 4), asHex); var o2_str = byte.Parse(line.Substring(8, 1), asHex); - newByte.Arch = (Data.Architechture)((o2_str >> 0) & 0x3); + newByte.Arch = (Data.Architecture)((o2_str >> 0) & 0x3); var otherFlags1 = DecodeHackyBase64(o1_str); Debug.Assert(EncodeHackyBase64(otherFlags1) == o1_str); diff --git a/DiztinGUIsh/window/AliasList.Designer.cs b/DiztinGUIsh/window/AliasList.Designer.cs index f9e9ed89..7068e2a2 100644 --- a/DiztinGUIsh/window/AliasList.Designer.cs +++ b/DiztinGUIsh/window/AliasList.Designer.cs @@ -199,7 +199,6 @@ private void InitializeComponent() this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Label List"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.AliasList_FormClosing); - this.Load += new System.EventHandler(this.AliasList_Load); this.Resize += new System.EventHandler(this.AliasList_Resize); ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit(); this.statusStrip1.ResumeLayout(false); diff --git a/DiztinGUIsh/window/AliasList.cs b/DiztinGUIsh/window/AliasList.cs index ca0a69b6..96b6c585 100644 --- a/DiztinGUIsh/window/AliasList.cs +++ b/DiztinGUIsh/window/AliasList.cs @@ -1,163 +1,150 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.ComponentModel; -using System.Data; -using System.Drawing; using System.Globalization; using System.IO; using System.Linq; -using System.Text; using System.Text.RegularExpressions; -using System.Threading.Tasks; using System.Windows.Forms; namespace DiztinGUIsh.window { public partial class AliasList : Form { - // single instance - private MainWindow mw; + private readonly MainWindow parentWindow; + private ProjectController ProjectController => parentWindow?.ProjectController; + private Data Data => ProjectController?.Project?.Data; - public bool locked = false; + public bool locked; private int currentlyEditing = -1; - + public AliasList(MainWindow main) { - mw = main; + parentWindow = main; InitializeComponent(); } - private void AliasList_Load(object sender, EventArgs e) - { - - } - private void AliasList_FormClosing(object sender, FormClosingEventArgs e) { - if (e.CloseReason == CloseReason.UserClosing) - { - e.Cancel = true; - this.Hide(); - } + if (e.CloseReason != CloseReason.UserClosing) return; + e.Cancel = true; + this.Hide(); } private void AliasList_Resize(object sender, EventArgs e) { - int h = Height - 68 - 22; + var h = Height - 68 - 22; dataGridView1.Height = h; } private void jump_Click(object sender, EventArgs e) { if (!int.TryParse((string) dataGridView1.SelectedRows[0].Cells[0].Value, NumberStyles.HexNumber, null, - out int val)) return; + out var val)) return; - int offset = mw.Project.Data.ConvertSNEStoPC(val); + var offset = Data.ConvertSNEStoPC(val); if (offset >= 0) { - mw.SelectOffset(offset); + ProjectController.SelectOffset(offset); } } - private static void SplitOnFirstComma(string instr, out string first_part, out string remainder) + private static void SplitOnFirstComma(string instr, out string firstPart, out string remainder) { if (!instr.Contains(",")) { - first_part = instr; + firstPart = instr; remainder = ""; return; } - first_part = instr.Substring(0, instr.IndexOf(',')); + firstPart = instr.Substring(0, instr.IndexOf(',')); remainder = instr.Substring(instr.IndexOf(',') + 1); } - private void ImportLabelsFromCSV(bool replaceAll) + private void ImportLabelsFromCsv(bool replaceAll) { var result = openFileDialog1.ShowDialog(); if (result != DialogResult.OK || openFileDialog1.FileName == "") return; - int errLine = 0; + var errLine = 0; try { - Dictionary newValues = new Dictionary(); - string[] lines = Util.ReadLines(openFileDialog1.FileName).ToArray(); + var newValues = new Dictionary(); + var lines = Util.ReadLines(openFileDialog1.FileName).ToArray(); - Regex valid_label_chars = new Regex(@"^([a-zA-Z0-9_\-]*)$"); + var validLabelChars = new Regex(@"^([a-zA-Z0-9_\-]*)$"); // NOTE: this is kind of a risky way to parse CSV files, won't deal with weirdness in the comments // section. - for (int i = 0; i < lines.Length; i++) + for (var i = 0; i < lines.Length; i++) { - var Label = new Label(); + var label = new Label(); errLine = i + 1; SplitOnFirstComma(lines[i], out var labelAddress, out var remainder); - SplitOnFirstComma(remainder, out Label.name, out Label.comment); + SplitOnFirstComma(remainder, out label.name, out label.comment); - Label.CleanUp(); + label.CleanUp(); - Label.name = Label.name.Trim(); - if (!valid_label_chars.Match(Label.name).Success) - throw new InvalidDataException("invalid label name: " + Label.name); + label.name = label.name.Trim(); + if (!validLabelChars.Match(label.name).Success) + throw new InvalidDataException("invalid label name: " + label.name); - newValues.Add(int.Parse(labelAddress, NumberStyles.HexNumber, null), Label); + newValues.Add(int.Parse(labelAddress, NumberStyles.HexNumber, null), label); } // everything read OK, modify the existing list now. point of no return if (replaceAll) - mw.Project.Data.DeleteAllLabels(); + Data.DeleteAllLabels(); - ResetDataGrid(); + ClearAndInvalidateDataGrid(); // this will call AddRow() to add items back to the UI datagrid. - foreach (KeyValuePair pair in newValues) + foreach (var pair in newValues) { - mw.Project.Data.AddLabel(pair.Key, pair.Value, true); + Data.AddLabel(pair.Key, pair.Value, true); } } catch (Exception ex) { MessageBox.Show( "An error occurred while parsing the file.\n" + ex.Message + - (errLine > 0 ? string.Format(" (Check line {0}.)", errLine) : ""), + (errLine > 0 ? $" (Check line {errLine}.)" : ""), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void export_Click(object sender, EventArgs e) { - DialogResult result = saveFileDialog1.ShowDialog(); - if (result == DialogResult.OK && saveFileDialog1.FileName != "") + var result = saveFileDialog1.ShowDialog(); + if (result != DialogResult.OK || saveFileDialog1.FileName == "") return; + + try { - try + using var sw = new StreamWriter(saveFileDialog1.FileName); + foreach (var pair in Data.Labels) { - using (StreamWriter sw = new StreamWriter(saveFileDialog1.FileName)) - { - foreach (var pair in mw.Project.Data.GetAllLabels()) - { - sw.WriteLine( - $"{Util.NumberToBaseString(pair.Key, Util.NumberBase.Hexadecimal, 6)},{pair.Value.name},{pair.Value.comment}"); - } - } - } catch (Exception) - { - MessageBox.Show("An error occurred while saving the file.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + sw.WriteLine( + $"{Util.NumberToBaseString(pair.Key, Util.NumberBase.Hexadecimal, 6)},{pair.Value.name},{pair.Value.comment}"); } + } catch (Exception) + { + MessageBox.Show("An error occurred while saving the file.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void dataGridView1_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e) { - if (int.TryParse((string)dataGridView1.Rows[e.Row.Index].Cells[0].Value, NumberStyles.HexNumber, null, out int val)) - { - locked = true; - mw.Project.Data.AddLabel(val, null, true); - locked = false; - mw.InvalidateTable(); - } + if (!int.TryParse((string) dataGridView1.Rows[e.Row.Index].Cells[0].Value, NumberStyles.HexNumber, null, + out var val)) return; + locked = true; + Data.AddLabel(val, null, true); + locked = false; + parentWindow.InvalidateTable(); // TODO: move to mainwindow, use notifychanged in mainwindow for this } private void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) @@ -174,7 +161,7 @@ private void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEv private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) { if (dataGridView1.Rows[e.RowIndex].IsNewRow) return; - int val = -1; + var val = -1; int.TryParse((string)dataGridView1.Rows[e.RowIndex].Cells[0].Value, NumberStyles.HexNumber, null, out var oldAddress); var labelLabel = new Label @@ -193,11 +180,11 @@ private void dataGridView1_CellValidating(object sender, DataGridViewCellValidat { e.Cancel = true; toolStripStatusLabel1.Text = "Must enter a valid hex address."; - } else if (oldAddress == -1 && mw.Project.Data.GetAllLabels().ContainsKey(val)) + } else if (oldAddress == -1 && Data.Labels.ContainsKey(val)) { e.Cancel = true; toolStripStatusLabel1.Text = "This address already has a label."; - var x = mw.Project.Data.GetAllLabels(); + var x = Data.Labels; Console.WriteLine(Util.NumberToBaseString(val, Util.NumberBase.Hexadecimal)); } else if (dataGridView1.EditingControl != null) { @@ -224,41 +211,45 @@ private void dataGridView1_CellValidating(object sender, DataGridViewCellValidat locked = true; if (currentlyEditing >= 0) { - if (val >= 0) mw.Project.Data.AddLabel(oldAddress, null, true); - mw.Project.Data.AddLabel(val, labelLabel, true); + if (val >= 0) Data.AddLabel(oldAddress, null, true); + Data.AddLabel(val, labelLabel, true); } locked = false; currentlyEditing = -1; - mw.InvalidateTable(); + parentWindow.InvalidateTable(); // TODO: move to mainwindow, use notifychanged in mainwindow for this } public void AddRow(int address, Label alias) { - if (!locked) - { - dataGridView1.Rows.Add(Util.NumberToBaseString(address, Util.NumberBase.Hexadecimal, 6), alias.name, alias.comment); - dataGridView1.Invalidate(); - } + if (locked) + return; + RawAdd(address, alias); + dataGridView1.Invalidate(); + } + + private void RawAdd(int address, Label alias) + { + dataGridView1.Rows.Add(Util.NumberToBaseString(address, Util.NumberBase.Hexadecimal, 6), alias.name, alias.comment); } public void RemoveRow(int address) { - if (!locked) + if (locked) + return; + + for (var index = 0; index < dataGridView1.Rows.Count; index++) { - for (int index = 0; index < dataGridView1.Rows.Count; index++) - { - if ((string)dataGridView1.Rows[index].Cells[0].Value == Util.NumberToBaseString(address, Util.NumberBase.Hexadecimal, 6)) - { - dataGridView1.Rows.RemoveAt(index); - dataGridView1.Invalidate(); - break; - } - } + if ((string) dataGridView1.Rows[index].Cells[0].Value != + Util.NumberToBaseString(address, Util.NumberBase.Hexadecimal, 6)) continue; + + dataGridView1.Rows.RemoveAt(index); + dataGridView1.Invalidate(); + break; } } - public void ResetDataGrid() + public void ClearAndInvalidateDataGrid() { dataGridView1.Rows.Clear(); dataGridView1.Invalidate(); @@ -274,7 +265,7 @@ private void importAppend_Click(object sender, EventArgs e) "Continue?\n", "Warning", MessageBoxButtons.OKCancel) != DialogResult.OK) return; - ImportLabelsFromCSV(false); + ImportLabelsFromCsv(false); } private void btnImportReplace_Click(object sender, EventArgs e) @@ -284,7 +275,55 @@ private void btnImportReplace_Click(object sender, EventArgs e) "Continue?\n", "Warning", MessageBoxButtons.OKCancel) != DialogResult.OK) return; - ImportLabelsFromCSV(true); + ImportLabelsFromCsv(true); + } + + public void RebindProject() + { + RepopulateFromData(); + + // todo: eventually use databinding/datasource, probably. + Data.Labels.PropertyChanged += Labels_PropertyChanged; + Data.Labels.CollectionChanged += Labels_CollectionChanged; + } + + private void RepopulateFromData() + { + ClearAndInvalidateDataGrid(); + + if (Data == null) + return; + + // TODO: replace with winforms databinding eventually + foreach (var item in Data.Labels) + { + RawAdd(item.Key, item.Value); + } + dataGridView1.Invalidate(); + } + + private void Labels_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (e.NewItems != null) + { + foreach (KeyValuePair item in e.NewItems) + { + AddRow(item.Key, item.Value); + } + } + + if (e.OldItems != null) + { + foreach (KeyValuePair item in e.OldItems) + { + RemoveRow(item.Key); + } + } + } + + private void Labels_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + // if needed, catch any changes to label content here } } } diff --git a/DiztinGUIsh/window/IProjectView.cs b/DiztinGUIsh/window/IProjectView.cs index 36fe8cb2..63daac17 100644 --- a/DiztinGUIsh/window/IProjectView.cs +++ b/DiztinGUIsh/window/IProjectView.cs @@ -2,15 +2,15 @@ namespace DiztinGUIsh { - interface IProjectView + public interface IProjectView { Project Project { get; set; } - void OnProjectOpened(string filename); void OnProjectOpenFail(); void OnProjectSaved(); void OnExportFinished(LogCreator.OutputResult result); public delegate void LongRunningTaskHandler(Action task, string description = null); LongRunningTaskHandler TaskHandler { get; } + void SelectOffset(int offset, int column=-1); } } diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index c8f78735..6287e74b 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -1,28 +1,55 @@ using DiztinGUIsh.window; using System; +using System.ComponentModel; using System.Drawing; using System.Globalization; using System.IO; using System.Windows.Forms; -using DiztinGUIsh.loadsave; using DiztinGUIsh.Properties; -using ExtendedXmlSerializer.ExtensionModel.Types.Sources; namespace DiztinGUIsh { public partial class MainWindow : Form, IProjectView { + // temp: readonly project data model. eventually, get this ONLY from the controller. + // right now, it returns Project2 which will go away public Project Project { get; set; } public MainWindow() { - ProjectController = new ProjectController - { - ProjectView = this + ProjectController = new ProjectController { + ProjectView = this, }; + ProjectController.ProjectChanged += ProjectController_ProjectChanged; + InitializeComponent(); } + private void ProjectController_ProjectChanged(object sender, ProjectController.ProjectChangedEventArgs e) + { + RebindProject(); + + switch (e.ChangeType) + { + case ProjectController.ProjectChangedEventArgs.ProjectChangedType.Saved: + OnProjectSaved(); + break; + case ProjectController.ProjectChangedEventArgs.ProjectChangedType.Opened: + OnProjectOpened(e.Filename); + break; + case ProjectController.ProjectChangedEventArgs.ProjectChangedType.Imported: + OnImportedProjectSuccess(); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + private void RebindProject() + { + aliasList.RebindProject(); + } + private void MainWindow_FormClosing(object sender, FormClosingEventArgs e) { e.Cancel = !ContinueUnsavedChanges(); @@ -52,7 +79,7 @@ private void MainWindow_Load(object sender, EventArgs e) table.CellValueNeeded += new DataGridViewCellValueEventHandler(table_CellValueNeeded); table.CellValuePushed += new DataGridViewCellValueEventHandler(table_CellValuePushed); table.CellPainting += new DataGridViewCellPaintingEventHandler(table_CellPainting); - viewOffset = 0; + rowsToShow = ((table.Height - table.ColumnHeadersHeight) / table.RowTemplate.Height); // https://stackoverflow.com/a/1506066 @@ -82,7 +109,7 @@ public void UpdateWindowTitle() { this.Text = (Project.UnsavedChanges ? "*" : "") + - (Project.ProjectFileName == null ? "New Project" : Project.ProjectFileName) + + (Project.ProjectFileName ?? "New Project") + " - DiztinGUIsh"; } @@ -126,17 +153,6 @@ private string PromptForOpenFilename() return openFileDialog.ShowDialog() != DialogResult.OK ? openFileDialog.FileName : null; } - private void OnImportedProjectSuccess() - { - importCDLToolStripMenuItem.Enabled = true; - UpdateSaveOptionStates(false, true); - UpdateWindowTitle(); - UpdateDataGridView(); - UpdatePercent(); - table.Invalidate(); - EnableSubWindows(); - } - private bool TryImportProject(string romFileToOpen) { try @@ -145,7 +161,7 @@ private bool TryImportProject(string romFileToOpen) if (importSettings == null) return false; - ProjectController.ImportRomAndCreateNewProject(importSettings); + ProjectController.ImportRomAndCreateNewProject(importSettings.Value); return true; } catch (Exception ex) @@ -168,6 +184,7 @@ private void openProjectToolStripMenuItem_Click(object sender, EventArgs e) OpenProject(openProjectFile.FileName); } + // TODO: state change needs to go in controller public string LastProjectFilename { get => Settings.Default.LastOpenedFile; @@ -194,9 +211,19 @@ private void UpdateUIFromSettings() public void OnProjectOpened(string filename) { LastProjectFilename = filename; + UpdateSaveOptionStates(true, true); + RefreshUI(); + } + private void OnImportedProjectSuccess() + { + UpdateSaveOptionStates(false, true); + RefreshUI(); + } + + private void RefreshUI() + { importCDLToolStripMenuItem.Enabled = true; - UpdateSaveOptionStates(true, true); UpdateWindowTitle(); UpdateDataGridView(); UpdatePercent(); @@ -257,32 +284,30 @@ private void importCDLToolStripMenuItem_Click(object sender, EventArgs e) { openCDLDialog.InitialDirectory = Project.ProjectFileName; DialogResult result = openCDLDialog.ShowDialog(); - if (result == DialogResult.OK) - { - if (ContinueUnsavedChanges()) - { - try - { - var cdl = BizHawkCdl.LoadFromFile(openCDLDialog.FileName); - Project.Data.ImportBizHawkCDL(cdl); - } - catch (InvalidDataException ex) - { - MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - catch (EndOfStreamException ex) - { - MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } + if (result != DialogResult.OK) return; + if (!ContinueUnsavedChanges()) return; - UpdatePercent(); - UpdateWindowTitle(); - InvalidateTable(); - } + var filename = openCDLDialog.FileName; + + try + { + ProjectController.ImportBizHawkCDL(filename); } + catch (InvalidDataException ex) + { + MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + catch (EndOfStreamException ex) + { + MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + UpdatePercent(); + UpdateWindowTitle(); + InvalidateTable(); } - private readonly ProjectController ProjectController; + public ProjectController ProjectController { get; protected set; } private void exportLogToolStripMenuItem_Click(object sender, EventArgs e) { @@ -369,6 +394,9 @@ private void UpdateBase(Util.NumberBase noBase) public void UpdatePercent() { + if (Project?.Data == null || Project.Data.GetROMSize() <= 0) + return; + int totalUnreached = 0, size = Project.Data.GetROMSize(); for (int i = 0; i < size; i++) if (Project.Data.GetFlag(i) == Data.FlagType.Unreached) @@ -389,25 +417,30 @@ public void InvalidateTable() // DataGridView - private int viewOffset; + private int ViewOffset + { + get => Project.CurrentViewOffset; + set => Project.CurrentViewOffset = value; + } + private int rowsToShow; private void UpdateDataGridView() { - if (Project.Data.GetROMSize() <= 0) + if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; rowsToShow = ((table.Height - table.ColumnHeadersHeight) / table.RowTemplate.Height); - if (viewOffset + rowsToShow > Project.Data.GetROMSize()) - viewOffset = Project.Data.GetROMSize() - rowsToShow; + if (ViewOffset + rowsToShow > Project.Data.GetROMSize()) + ViewOffset = Project.Data.GetROMSize() - rowsToShow; - if (viewOffset < 0) - viewOffset = 0; + if (ViewOffset < 0) + ViewOffset = 0; vScrollBar1.Enabled = true; vScrollBar1.Maximum = Project.Data.GetROMSize() - rowsToShow; - vScrollBar1.Value = viewOffset; + vScrollBar1.Value = ViewOffset; table.RowCount = rowsToShow; importTraceLogToolStripMenuItem.Enabled = true; @@ -416,28 +449,28 @@ private void UpdateDataGridView() private void table_MouseWheel(object sender, MouseEventArgs e) { - if (Project.Data.GetROMSize() <= 0) + if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; - int selRow = table.CurrentCell.RowIndex + viewOffset, selCol = table.CurrentCell.ColumnIndex; + int selRow = table.CurrentCell.RowIndex + ViewOffset, selCol = table.CurrentCell.ColumnIndex; int amount = e.Delta / 0x18; - viewOffset -= amount; + ViewOffset -= amount; UpdateDataGridView(); - if (selRow < viewOffset) selRow = viewOffset; - else if (selRow >= viewOffset + rowsToShow) selRow = viewOffset + rowsToShow - 1; - table.CurrentCell = table.Rows[selRow - viewOffset].Cells[selCol]; + if (selRow < ViewOffset) selRow = ViewOffset; + else if (selRow >= ViewOffset + rowsToShow) selRow = ViewOffset + rowsToShow - 1; + table.CurrentCell = table.Rows[selRow - ViewOffset].Cells[selCol]; InvalidateTable(); } private void vScrollBar1_ValueChanged(object sender, EventArgs e) { - int selOffset = table.CurrentCell.RowIndex + viewOffset; - viewOffset = vScrollBar1.Value; + int selOffset = table.CurrentCell.RowIndex + ViewOffset; + ViewOffset = vScrollBar1.Value; UpdateDataGridView(); - if (selOffset < viewOffset) table.CurrentCell = table.Rows[0].Cells[table.CurrentCell.ColumnIndex]; - else if (selOffset >= viewOffset + rowsToShow) + if (selOffset < ViewOffset) table.CurrentCell = table.Rows[0].Cells[table.CurrentCell.ColumnIndex]; + else if (selOffset >= ViewOffset + rowsToShow) table.CurrentCell = table.Rows[rowsToShow - 1].Cells[table.CurrentCell.ColumnIndex]; - else table.CurrentCell = table.Rows[selOffset - viewOffset].Cells[table.CurrentCell.ColumnIndex]; + else table.CurrentCell = table.Rows[selOffset - ViewOffset].Cells[table.CurrentCell.ColumnIndex]; InvalidateTable(); } @@ -449,9 +482,9 @@ private void table_MouseDown(object sender, MouseEventArgs e) private void table_KeyDown(object sender, KeyEventArgs e) { - if (Project.Data.GetROMSize() <= 0) return; + if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; - int offset = table.CurrentCell.RowIndex + viewOffset; + int offset = table.CurrentCell.RowIndex + ViewOffset; int newOffset = offset; int amount = 0x01; @@ -538,7 +571,7 @@ private void table_KeyDown(object sender, KeyEventArgs e) private void table_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) { - int row = e.RowIndex + viewOffset; + int row = e.RowIndex + ViewOffset; if (row >= Project.Data.GetROMSize()) return; switch (e.ColumnIndex) { @@ -592,7 +625,7 @@ private void table_CellValuePushed(object sender, DataGridViewCellValueEventArgs { string value = e.Value as string; int result; - int row = e.RowIndex + viewOffset; + int row = e.RowIndex + ViewOffset; if (row >= Project.Data.GetROMSize()) return; switch (e.ColumnIndex) { @@ -715,35 +748,35 @@ public void PaintCell(int offset, DataGridViewCellStyle style, int column, int s private void table_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) { - int row = e.RowIndex + viewOffset; + int row = e.RowIndex + ViewOffset; if (row < 0 || row >= Project.Data.GetROMSize()) return; - PaintCell(row, e.CellStyle, e.ColumnIndex, table.CurrentCell.RowIndex + viewOffset); + PaintCell(row, e.CellStyle, e.ColumnIndex, table.CurrentCell.RowIndex + ViewOffset); } public void SelectOffset(int offset, int column = -1) { var col = column == -1 ? table.CurrentCell.ColumnIndex : column; - if (offset < viewOffset) + if (offset < ViewOffset) { - viewOffset = offset; + ViewOffset = offset; UpdateDataGridView(); table.CurrentCell = table.Rows[0].Cells[col]; } - else if (offset >= viewOffset + rowsToShow) + else if (offset >= ViewOffset + rowsToShow) { - viewOffset = offset - rowsToShow + 1; + ViewOffset = offset - rowsToShow + 1; UpdateDataGridView(); table.CurrentCell = table.Rows[rowsToShow - 1].Cells[col]; } else { - table.CurrentCell = table.Rows[offset - viewOffset].Cells[col]; + table.CurrentCell = table.Rows[offset - ViewOffset].Cells[col]; } } private void Step(int offset) { - Project.UnsavedChanges = true; + ProjectController.MarkChanged();; SelectOffset(Project.Data.Step(offset, false, false, offset - 1)); UpdatePercent(); UpdateWindowTitle(); @@ -751,7 +784,7 @@ private void Step(int offset) private void StepIn(int offset) { - Project.UnsavedChanges = true; + ProjectController.MarkChanged(); SelectOffset(Project.Data.Step(offset, true, false, offset - 1)); UpdatePercent(); UpdateWindowTitle(); @@ -759,7 +792,7 @@ private void StepIn(int offset) private void AutoStepSafe(int offset) { - Project.UnsavedChanges = true; + ProjectController.MarkChanged(); var destination = Project.Data.AutoStep(offset, false, 0); if (MoveWithStep) SelectOffset(destination); @@ -773,7 +806,7 @@ private void AutoStepHarsh(int offset) DialogResult result = harsh.ShowDialog(); if (result == DialogResult.OK) { - Project.UnsavedChanges = true; + ProjectController.MarkChanged(); int destination = Project.Data.AutoStep(harsh.GetOffset(), true, harsh.GetCount()); if (MoveWithStep) SelectOffset(destination); UpdatePercent(); @@ -783,7 +816,7 @@ private void AutoStepHarsh(int offset) private void Mark(int offset) { - Project.UnsavedChanges = true; + ProjectController.MarkChanged(); SelectOffset(Project.Data.Mark(offset, markFlag, Util.TypeStepSize(markFlag))); UpdatePercent(); UpdateWindowTitle(); @@ -796,7 +829,7 @@ private void MarkMany(int offset, int column) if (result != DialogResult.OK) return; - Project.UnsavedChanges = true; + ProjectController.MarkChanged(); var destination = 0; var col = mark.GetProperty(); @@ -818,7 +851,7 @@ private void MarkMany(int offset, int column) destination = Project.Data.MarkXFlag(mark.GetOffset(), (bool) mark.GetValue(), mark.GetCount()); break; case 5: - destination = Project.Data.MarkArchitechture(mark.GetOffset(), (Data.Architechture) mark.GetValue(), + destination = Project.Data.MarkArchitechture(mark.GetOffset(), (Data.Architecture) mark.GetValue(), mark.GetCount()); break; } @@ -846,7 +879,7 @@ private void GoToIntermediateAddress(int offset) private void GoToUnreached(bool end, bool direction) { - int offset = table.CurrentCell.RowIndex + viewOffset; + int offset = table.CurrentCell.RowIndex + ViewOffset; int size = Project.Data.GetROMSize(); int unreached = end ? (direction ? 0 : size - 1) : offset; @@ -882,34 +915,34 @@ private void graphicsWindowToolStripMenuItem_Click(object sender, EventArgs e) private void stepOverToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project.Data.GetROMSize() <= 0) return; - Step(table.CurrentCell.RowIndex + viewOffset); + if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + Step(table.CurrentCell.RowIndex + ViewOffset); } private void stepInToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project.Data.GetROMSize() <= 0) return; - StepIn(table.CurrentCell.RowIndex + viewOffset); + if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + StepIn(table.CurrentCell.RowIndex + ViewOffset); } private void autoStepSafeToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project.Data.GetROMSize() <= 0) return; - AutoStepSafe(table.CurrentCell.RowIndex + viewOffset); + if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + AutoStepSafe(table.CurrentCell.RowIndex + ViewOffset); } private void autoStepHarshToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project.Data.GetROMSize() <= 0) return; - AutoStepHarsh(table.CurrentCell.RowIndex + viewOffset); + if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + AutoStepHarsh(table.CurrentCell.RowIndex + ViewOffset); } private void gotoToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project.Data.GetROMSize() <= 0) + if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; - var go = new GotoDialog(viewOffset + table.CurrentCell.RowIndex, Project.Data); + var go = new GotoDialog(ViewOffset + table.CurrentCell.RowIndex, Project.Data); var result = go.ShowDialog(); if (result != DialogResult.OK) return; @@ -924,8 +957,8 @@ private void gotoToolStripMenuItem_Click(object sender, EventArgs e) private void gotoIntermediateAddressToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project.Data.GetROMSize() <= 0) return; - GoToIntermediateAddress(table.CurrentCell.RowIndex + viewOffset); + if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + GoToIntermediateAddress(table.CurrentCell.RowIndex + ViewOffset); } private void gotoFirstUnreachedToolStripMenuItem_Click(object sender, EventArgs e) @@ -945,14 +978,14 @@ private void gotoNextUnreachedToolStripMenuItem_Click(object sender, EventArgs e private void markOneToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project.Data.GetROMSize() <= 0) return; - Mark(table.CurrentCell.RowIndex + viewOffset); + if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + Mark(table.CurrentCell.RowIndex + ViewOffset); } private void markManyToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project.Data.GetROMSize() <= 0) return; - MarkMany(table.CurrentCell.RowIndex + viewOffset, 7); + if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + MarkMany(table.CurrentCell.RowIndex + ViewOffset, 7); } private void addLabelToolStripMenuItem_Click(object sender, EventArgs e) @@ -963,26 +996,26 @@ private void addLabelToolStripMenuItem_Click(object sender, EventArgs e) private void setDataBankToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project.Data.GetROMSize() <= 0) return; - MarkMany(table.CurrentCell.RowIndex + viewOffset, 8); + if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + MarkMany(table.CurrentCell.RowIndex + ViewOffset, 8); } private void setDirectPageToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project.Data.GetROMSize() <= 0) return; - MarkMany(table.CurrentCell.RowIndex + viewOffset, 9); + if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + MarkMany(table.CurrentCell.RowIndex + ViewOffset, 9); } private void toggleAccumulatorSizeMToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project.Data.GetROMSize() <= 0) return; - MarkMany(table.CurrentCell.RowIndex + viewOffset, 10); + if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + MarkMany(table.CurrentCell.RowIndex + ViewOffset, 10); } private void toggleIndexSizeToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project.Data.GetROMSize() <= 0) return; - MarkMany(table.CurrentCell.RowIndex + viewOffset, 11); + if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + MarkMany(table.CurrentCell.RowIndex + ViewOffset, 11); } private void addCommentToolStripMenuItem_Click(object sender, EventArgs e) @@ -993,7 +1026,7 @@ private void addCommentToolStripMenuItem_Click(object sender, EventArgs e) private void fixMisalignedInstructionsToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project.Data.GetROMSize() <= 0) + if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; var mis = new MisalignmentChecker(Project.Data); @@ -1005,7 +1038,7 @@ private void fixMisalignedInstructionsToolStripMenuItem_Click(object sender, Eve int count = Project.Data.FixMisalignedFlags(); if (count > 0) - Project.UnsavedChanges = true; + ProjectController.MarkChanged(); InvalidateTable(); MessageBox.Show($"Modified {count} flags!", "Done!", @@ -1014,7 +1047,7 @@ private void fixMisalignedInstructionsToolStripMenuItem_Click(object sender, Eve private void rescanForInOutPointsToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project.Data.GetROMSize() <= 0) + if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; var point = new InOutPointChecker(); @@ -1022,7 +1055,7 @@ private void rescanForInOutPointsToolStripMenuItem_Click(object sender, EventArg return; Project.Data.RescanInOutPoints(); - Project.UnsavedChanges = true; + ProjectController.MarkChanged(); InvalidateTable(); MessageBox.Show("Scan complete!", "Done!", MessageBoxButtons.OK, MessageBoxIcon.Information); } @@ -1143,7 +1176,7 @@ private void ImportUsageMapToolStripMenuItem_Click(object sender, EventArgs e) var num_modified_flags = Project.Data.ImportUsageMap(File.ReadAllBytes(openUsageMapFile.FileName)); if (num_modified_flags > 0) - Project.UnsavedChanges = true; + ProjectController.MarkChanged(); MessageBox.Show($"Modified total {num_modified_flags} flags!", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information); @@ -1164,7 +1197,7 @@ private void ImportTraceLogToolStripMenuItem_Click(object sender, EventArgs e) }); if (totalLinesSoFar > 0) - Project.UnsavedChanges = true; + ProjectController.MarkChanged(); MessageBox.Show( $"Modified total {totalLinesSoFar} flags from {openTraceLogDialog.FileNames.Length} files!", diff --git a/DiztinGUIsh/window/MainWindow.resx b/DiztinGUIsh/window/MainWindow.resx index 1d4ea7ec..a8509cac 100644 --- a/DiztinGUIsh/window/MainWindow.resx +++ b/DiztinGUIsh/window/MainWindow.resx @@ -177,9 +177,6 @@ 1096, 17 - - 1255, 17 - 953, 17 diff --git a/DiztinGUIsh/window/ProjectController.cs b/DiztinGUIsh/window/ProjectController.cs index 054e52a8..55e59075 100644 --- a/DiztinGUIsh/window/ProjectController.cs +++ b/DiztinGUIsh/window/ProjectController.cs @@ -1,19 +1,29 @@ using System; -using System.Collections.Generic; +using System.ComponentModel; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; using DiztinGUIsh.loadsave; namespace DiztinGUIsh { - class ProjectController + public class ProjectController { public IProjectView ProjectView { get; set; } public Project Project { get; private set; } + public delegate void ProjectChangedEvent(object sender, ProjectChangedEventArgs e); + public event ProjectChangedEvent ProjectChanged; + + public class ProjectChangedEventArgs + { + public enum ProjectChangedType { + Invalid, Saved, Opened, Imported + } + + public ProjectChangedType ChangeType; + public Project Project; + public string Filename; + } + // there's probably better ways to handle this. // probably replace with a UI like "start task" and "stop task" // so we can flip up a progress bar and remove it. @@ -49,7 +59,19 @@ public bool OpenProject(string filename) private void OnProjectOpened(string filename, Project project) { ProjectView.Project = Project = project; - ProjectView.OnProjectOpened(filename); + Project.PropertyChanged += Project_PropertyChanged; + + ProjectChanged?.Invoke(this, new ProjectChangedEventArgs() + { + ChangeType = ProjectChangedEventArgs.ProjectChangedType.Opened, + Filename = filename, + Project = project, + }); + } + + private void Project_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + // TODO } public void SaveProject(string filename) @@ -61,24 +83,65 @@ public void SaveProject(string filename) ProjectView.OnProjectSaved(); } - public void ImportRomAndCreateNewProject(Project.ImportRomSettings importSettings) + public void ImportBizHawkCDL(string filename) { - var project = new Project(); - project.ImportRomAndCreateNewProject(importSettings); + BizHawkCdl.Import(filename, Project.Data); + + ProjectChanged?.Invoke(this, new ProjectChangedEventArgs() + { + ChangeType = ProjectChangedEventArgs.ProjectChangedType.Imported, + Filename = filename, + Project = Project, + }); + } + + public void ImportRomAndCreateNewProject(in Project.ImportRomSettings importSettings) + { + var project = new Project + { + AttachedRomFilename = importSettings.rom_filename, + UnsavedChanges = false, + ProjectFileName = null, + Data = new Data() + }; // TODO: seems like we probably should pick a place for the Project reference to live. // either here in this class, or out in the view. // right now we're passing around our class's Project and ProjectView's project. + project.Data.Initiate(importSettings.rom_bytes, importSettings.ROMMapMode, importSettings.ROMSpeed); + + // TODO: get this UI out of here. probably just use databinding instead + // AliasList.me.ResetDataGrid(); + + if (importSettings.InitialLabels.Count > 0) + { + foreach (var pair in importSettings.InitialLabels) + project.Data.AddLabel(pair.Key, pair.Value, true); + project.UnsavedChanges = true; + } + + if (importSettings.InitialHeaderFlags.Count > 0) + { + foreach (var pair in importSettings.InitialHeaderFlags) + project.Data.SetFlag(pair.Key, pair.Value); + project.UnsavedChanges = true; + } + + // Save a copy of these identifying ROM bytes with the project file itself. + // When we reload, we will make sure the linked ROM still matches them. + project.InternalCheckSum = project.Data.GetRomCheckSumsFromRomBytes(); + project.InternalRomGameName = project.Data.GetRomNameFromRomBytes(); + OnProjectOpened(project.ProjectFileName, project); } public void WriteAssemblyOutput() { - WriteAssemblyOutput(ref Project.LogWriterSettings); + WriteAssemblyOutput(Project.LogWriterSettings); } - private void WriteAssemblyOutput(ref LogWriterSettings settings) + private void WriteAssemblyOutput(LogWriterSettings settings) { // kinda hate that we're passing in these... using var sw = new StreamWriter(settings.file); @@ -106,5 +169,16 @@ public void UpdateExportSettings(LogWriterSettings selectedSettings) Project.LogWriterSettings = selectedSettings; } + + public void MarkChanged() + { + // eventually set this via INotifyPropertyChanged or similar. + Project.UnsavedChanges = true; + } + + public void SelectOffset(int offset, int column = -1) + { + ProjectView.SelectOffset(offset, column); + } } } diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.cs b/DiztinGUIsh/window/dialog/ImportROMDialog.cs index f162e2c4..128f1123 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.cs @@ -25,7 +25,7 @@ public partial class ImportROMDialog : Form private TextBox[,] vectors; private CheckBox[,] checkboxes; - public Project.ImportRomSettings PromptForImportSettings(string filename) + public Project.ImportRomSettings? PromptForImportSettings(string filename) { importSettings = new Project.ImportRomSettings { @@ -38,7 +38,7 @@ public Project.ImportRomSettings PromptForImportSettings(string filename) UpdateOffsetAndSpeed(); if (ShowDialog() != DialogResult.OK) - importSettings = null; + return null; importSettings.InitialLabels = GetGeneratedLabels(); importSettings.InitialHeaderFlags = GetHeaderFlags(); @@ -152,7 +152,7 @@ private void UpdateUIFromRomMapDetection() private void UpdateOffsetAndSpeed() { - offset = Data.GetRomSettingOffset(importSettings.ROMMapMode); + offset = Util.GetRomSettingOffset(importSettings.ROMMapMode); if (offset >= importSettings.rom_bytes.Length) { importSettings.ROMSpeed = Data.ROMSpeed.Unknown; diff --git a/DiztinGUIsh/window/dialog/MarkManyDialog.cs b/DiztinGUIsh/window/dialog/MarkManyDialog.cs index bd985706..9b1ca8cf 100644 --- a/DiztinGUIsh/window/dialog/MarkManyDialog.cs +++ b/DiztinGUIsh/window/dialog/MarkManyDialog.cs @@ -90,9 +90,9 @@ public object GetValue() case 5: switch (archCombo.SelectedIndex) { - case 0: return Data.Architechture.CPU65C816; - case 1: return Data.Architechture.APUSPC700; - case 2: return Data.Architechture.GPUSuperFX; + case 0: return Data.Architecture.CPU65C816; + case 1: return Data.Architecture.APUSPC700; + case 2: return Data.Architecture.GPUSuperFX; } break; } From 989af0eee6109e5161929c4d0aa4c31ec6f69b7a Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Fri, 2 Oct 2020 18:42:14 -0400 Subject: [PATCH 048/136] working on databinding --- DiztinGUIsh/DiztinGUIsh.csproj | 19 + DiztinGUIsh/Program.cs | 5 +- .../DataSources/Data.Architecture.datasource | 10 + .../DataSources/Data.FlagType.datasource | 10 + .../DataSources/Data.InOutPoint.datasource | 10 + .../DataSources/Data.ROMMapMode.datasource | 10 + .../DataSources/Data.ROMSpeed.datasource | 10 + .../Properties/DataSources/Data.datasource | 10 + .../Project.ImportRomSettings.datasource | 21 + .../Properties/DataSources/Project.datasource | 10 + DiztinGUIsh/core/Data.cs | 57 +- DiztinGUIsh/core/LogCreator.cs | 14 +- DiztinGUIsh/core/Project.cs | 103 +--- DiztinGUIsh/core/ROMByte.cs | 8 +- DiztinGUIsh/core/RomBytes.cs | 23 +- DiztinGUIsh/core/util/ByteUtil.cs | 114 ++++ DiztinGUIsh/core/util/ObservableDictionary.cs | 63 +- DiztinGUIsh/core/util/RomUtil.cs | 388 ++++++++++++ DiztinGUIsh/core/util/Util.cs | 566 ++---------------- DiztinGUIsh/loadsave/ProjectFileManager.cs | 91 ++- .../binary_serializer_old/BinarySerializer.cs | 85 ++- .../xml_serializer/ProjectXMLSerializer.cs | 74 ++- .../xml_serializer/RomBytesXMLSerializer.cs | 2 +- DiztinGUIsh/window/AliasList.cs | 4 +- DiztinGUIsh/window/GuiUtil.cs | 51 ++ DiztinGUIsh/window/IProjectView.cs | 1 + DiztinGUIsh/window/MainWindow.cs | 51 +- DiztinGUIsh/window/ProjectController.cs | 55 +- DiztinGUIsh/window/dialog/GotoDialog.cs | 3 +- .../window/dialog/ImportROMDialog.Designer.cs | 55 +- DiztinGUIsh/window/dialog/ImportROMDialog.cs | 410 ++++++++----- .../window/dialog/ImportROMDialog.resx | 3 + .../window/dialog/MisalignmentChecker.cs | 7 +- .../window/dialog/TestForm.Designer.cs | 119 ++++ DiztinGUIsh/window/dialog/TestForm.cs | 42 ++ DiztinGUIsh/window/dialog/TestForm.resx | 129 ++++ 36 files changed, 1707 insertions(+), 926 deletions(-) create mode 100644 DiztinGUIsh/Properties/DataSources/Data.Architecture.datasource create mode 100644 DiztinGUIsh/Properties/DataSources/Data.FlagType.datasource create mode 100644 DiztinGUIsh/Properties/DataSources/Data.InOutPoint.datasource create mode 100644 DiztinGUIsh/Properties/DataSources/Data.ROMMapMode.datasource create mode 100644 DiztinGUIsh/Properties/DataSources/Data.ROMSpeed.datasource create mode 100644 DiztinGUIsh/Properties/DataSources/Data.datasource create mode 100644 DiztinGUIsh/Properties/DataSources/Project.ImportRomSettings.datasource create mode 100644 DiztinGUIsh/Properties/DataSources/Project.datasource create mode 100644 DiztinGUIsh/core/util/ByteUtil.cs create mode 100644 DiztinGUIsh/window/GuiUtil.cs create mode 100644 DiztinGUIsh/window/dialog/TestForm.Designer.cs create mode 100644 DiztinGUIsh/window/dialog/TestForm.cs create mode 100644 DiztinGUIsh/window/dialog/TestForm.resx diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 84c90a6a..42172e59 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -112,6 +112,7 @@
+ @@ -123,6 +124,13 @@ + + Form + + + TestForm.cs + + @@ -226,6 +234,9 @@ InOutPointChecker.cs + + TestForm.cs + MainWindow.cs Designer @@ -247,6 +258,14 @@ True + + + + + + + + SettingsSingleFileGenerator diff --git a/DiztinGUIsh/Program.cs b/DiztinGUIsh/Program.cs index cc10b405..ea4e3c3c 100644 --- a/DiztinGUIsh/Program.cs +++ b/DiztinGUIsh/Program.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading.Tasks; using System.Windows.Forms; +using DiztinGUIsh.window.dialog; namespace DiztinGUIsh { @@ -21,9 +22,7 @@ static void Main(string[] args) Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); - MainWindow window = new MainWindow(); - - if (args.Length > 0) window.OpenProject(args[0]); + var window = new MainWindow(); Application.Run(window); } diff --git a/DiztinGUIsh/Properties/DataSources/Data.Architecture.datasource b/DiztinGUIsh/Properties/DataSources/Data.Architecture.datasource new file mode 100644 index 00000000..3dcd82c1 --- /dev/null +++ b/DiztinGUIsh/Properties/DataSources/Data.Architecture.datasource @@ -0,0 +1,10 @@ + + + + DiztinGUIsh.Data+Architecture, DiztinGUIsh, Version=1.0.66.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/DiztinGUIsh/Properties/DataSources/Data.FlagType.datasource b/DiztinGUIsh/Properties/DataSources/Data.FlagType.datasource new file mode 100644 index 00000000..033a2575 --- /dev/null +++ b/DiztinGUIsh/Properties/DataSources/Data.FlagType.datasource @@ -0,0 +1,10 @@ + + + + DiztinGUIsh.Data+FlagType, DiztinGUIsh, Version=1.0.66.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/DiztinGUIsh/Properties/DataSources/Data.InOutPoint.datasource b/DiztinGUIsh/Properties/DataSources/Data.InOutPoint.datasource new file mode 100644 index 00000000..09858bc3 --- /dev/null +++ b/DiztinGUIsh/Properties/DataSources/Data.InOutPoint.datasource @@ -0,0 +1,10 @@ + + + + DiztinGUIsh.Data+InOutPoint, DiztinGUIsh, Version=1.0.66.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/DiztinGUIsh/Properties/DataSources/Data.ROMMapMode.datasource b/DiztinGUIsh/Properties/DataSources/Data.ROMMapMode.datasource new file mode 100644 index 00000000..6e4ce3eb --- /dev/null +++ b/DiztinGUIsh/Properties/DataSources/Data.ROMMapMode.datasource @@ -0,0 +1,10 @@ + + + + DiztinGUIsh.Data+ROMMapMode, DiztinGUIsh, Version=1.0.66.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/DiztinGUIsh/Properties/DataSources/Data.ROMSpeed.datasource b/DiztinGUIsh/Properties/DataSources/Data.ROMSpeed.datasource new file mode 100644 index 00000000..fcba39ce --- /dev/null +++ b/DiztinGUIsh/Properties/DataSources/Data.ROMSpeed.datasource @@ -0,0 +1,10 @@ + + + + DiztinGUIsh.Data+ROMSpeed, DiztinGUIsh, Version=1.0.66.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/DiztinGUIsh/Properties/DataSources/Data.datasource b/DiztinGUIsh/Properties/DataSources/Data.datasource new file mode 100644 index 00000000..4b9c86bc --- /dev/null +++ b/DiztinGUIsh/Properties/DataSources/Data.datasource @@ -0,0 +1,10 @@ + + + + DiztinGUIsh.Data, DiztinGUIsh, Version=1.0.66.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/DiztinGUIsh/Properties/DataSources/Project.ImportRomSettings.datasource b/DiztinGUIsh/Properties/DataSources/Project.ImportRomSettings.datasource new file mode 100644 index 00000000..460e1e49 --- /dev/null +++ b/DiztinGUIsh/Properties/DataSources/Project.ImportRomSettings.datasource @@ -0,0 +1,21 @@ + + + + DiztinGUIsh.Project+ImportRomSettings, DiztinGUIsh, Version=1.0.66.0, Culture=neutral, PublicKeyToken=null + + + + + + + + + + + + \ No newline at end of file diff --git a/DiztinGUIsh/Properties/DataSources/Project.datasource b/DiztinGUIsh/Properties/DataSources/Project.datasource new file mode 100644 index 00000000..d0d0aa7a --- /dev/null +++ b/DiztinGUIsh/Properties/DataSources/Project.datasource @@ -0,0 +1,10 @@ + + + + DiztinGUIsh.Project, DiztinGUIsh, Version=1.0.66.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/DiztinGUIsh/core/Data.cs b/DiztinGUIsh/core/Data.cs index 3ccea068..a03d1e69 100644 --- a/DiztinGUIsh/core/Data.cs +++ b/DiztinGUIsh/core/Data.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; -using System.IO; using System.Linq; using System.Text; using DiztinGUIsh.core.util; @@ -58,7 +58,24 @@ public enum BsnesPlusUsage : byte public enum ROMMapMode : byte { - LoROM, HiROM, ExHiROM, SA1ROM, ExSA1ROM, SuperFX, SuperMMC, ExLoROM + LoROM, + + HiROM, + + ExHiROM, + + [Description("SA - 1 ROM")] + SA1ROM, + + [Description("SA-1 ROM (FuSoYa's 8MB mapper)")] + ExSA1ROM, + + SuperFX, + + [Description("Super MMC")] + SuperMMC, + + ExLoROM } public enum ROMSpeed : byte @@ -89,27 +106,15 @@ public Data() romMemoryOp = new Func[] {GetROMByte, GetROMWord, GetROMLong, GetROMDoubleWord}; } - public void Initiate(byte[] actualRomBytes, Data.ROMMapMode mode, Data.ROMSpeed speed) - { - RomMapMode = mode; - RomSpeed = speed; - CreateRomBytesFromRom(actualRomBytes); - } - - private void CreateRomBytesFromRom(IEnumerable actualRomBytes) + public void CreateRomBytesFromRom(IEnumerable actualRomBytes) { + Debug.Assert(RomBytes.Count == 0); + RomBytes.Clear(); foreach (var fileByte in actualRomBytes) { RomBytes.Add(new ROMByte { Rom = fileByte, - DataBank = 0, - DirectPage = 0, - XFlag = false, - MFlag = false, - TypeFlag = Data.FlagType.Unreached, - Arch = Data.Architecture.CPU65C816, - Point = 0 }); } } @@ -130,14 +135,14 @@ public string GetRomNameFromRomBytes() public int GetRomCheckSumsFromRomBytes() { - return Util.ByteArrayToInteger(GetRomBytes(0xFFDC, 4)); + return ByteUtil.ByteArrayToInteger(GetRomBytes(0xFFDC, 4)); } public void CopyRomDataIn(byte[] data) { - int size = data.Length; + var size = data.Length; Debug.Assert(RomBytes.Count == size); - for (int i = 0; i < size; i++) + for (var i = 0; i < size; i++) { RomBytes[i].Rom = data[i]; } @@ -229,7 +234,7 @@ public void AddComment(int i, string v, bool overwrite) public int ConvertPCtoSNES(int offset) { - return Util.ConvertPCtoSNES(offset, RomMapMode, GetROMSpeed()); + return RomUtil.ConvertPCtoSNES(offset, RomMapMode, GetROMSpeed()); } public int GetROMByte(int i) => RomBytes[i].Rom; public int GetROMWord(int offset) @@ -280,7 +285,7 @@ public int OpcodeByteLength(int offset) private int UnmirroredOffset(int offset) { - return Util.UnmirroredOffset(offset, GetROMSize()); + return RomUtil.UnmirroredOffset(offset, GetROMSize()); } public string GetFormattedBytes(int offset, int step, int bytes) @@ -320,7 +325,7 @@ private string NumberToBaseString(int offset, int num_bytes) public int ConvertSNEStoPC(int address) { - return Util.ConvertSNESToPC(address, RomMapMode, GetROMSize()); + return RomUtil.ConvertSNESToPC(address, RomMapMode, GetROMSize()); } public string GetPointer(int offset, int bytes) @@ -362,7 +367,7 @@ public string GetFormattedText(int offset, int bytes) public string GetDefaultLabel(int offset) { var snes = ConvertPCtoSNES(offset); - var prefix = Util.TypeToLabel(GetFlag(offset)); + var prefix = RomUtil.TypeToLabel(GetFlag(offset)); var labelAddress = Util.NumberToBaseString(snes, Util.NumberBase.Hexadecimal, 6); return $"{prefix}_{labelAddress}"; } @@ -562,9 +567,9 @@ public int FixMisalignedFlags() break; default: { - if (Util.TypeStepSize(flag) > 1) + if (RomUtil.TypeStepSize(flag) > 1) { - int step = Util.TypeStepSize(flag); + int step = RomUtil.TypeStepSize(flag); for (int j = 1; j < step; j++) { if (GetFlag(i + j) == flag) diff --git a/DiztinGUIsh/core/LogCreator.cs b/DiztinGUIsh/core/LogCreator.cs index 7bb67d0b..92972873 100644 --- a/DiztinGUIsh/core/LogCreator.cs +++ b/DiztinGUIsh/core/LogCreator.cs @@ -1,9 +1,11 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; +using DiztinGUIsh.core.util; namespace DiztinGUIsh { @@ -143,7 +145,7 @@ public string GetParameter(int offset, string parameter, int length) public OutputResult CreateLog() { - bankSize = Util.GetBankSize(Data.RomMapMode); + bankSize = RomUtil.GetBankSize(Data.RomMapMode); errorCount = 0; // TODO: this label combination isn't working well. fix. @@ -415,7 +417,7 @@ private void WriteLabels(int pointer) var listToPrint = new Dictionary(); // part 1: important: include all labels we aren't defining somewhere else. needed for disassembly - foreach (var pair in Data.Labels) + foreach (KeyValuePair pair in Data.Labels) { if (usedLabels.Contains(pair.Key)) continue; @@ -435,7 +437,7 @@ private void WriteLabels(int pointer) if (Settings.includeUnusedLabels) { SwitchOutputFile(pointer, $"{folder}/all-labels.txt"); - foreach (var pair in Data.Labels) + foreach (KeyValuePair pair in Data.Labels) { // not the best place to add formatting, TODO: cleanup var category = listToPrint.ContainsKey(pair.Key) ? "INLINE" : "EXTRA "; @@ -484,7 +486,7 @@ private string GetLine(int offset, string special) // throw out some errors if stuff looks fishy Data.FlagType flag = Data.GetFlag(offset), check = flag == Data.FlagType.Opcode ? Data.FlagType.Operand : flag; - int step = flag == Data.FlagType.Opcode ? GetLineByteLength(offset) : Util.TypeStepSize(flag), size = Data.GetROMSize(); + int step = flag == Data.FlagType.Opcode ? GetLineByteLength(offset) : RomUtil.TypeStepSize(flag), size = Data.GetROMSize(); if (flag == Data.FlagType.Operand) StreamError.WriteLine("({0}) Offset 0x{1:X}: Bytes marked as operands formatted as Data.", ++errorCount, offset); else if (step > 1) { @@ -492,12 +494,12 @@ private string GetLine(int offset, string special) { if (offset + i >= size) { - StreamError.WriteLine("({0}) Offset 0x{1:X}: {2} extends past the end of the ROM.", ++errorCount, offset, Util.TypeToString(check)); + StreamError.WriteLine("({0}) Offset 0x{1:X}: {2} extends past the end of the ROM.", ++errorCount, offset, RomUtil.TypeToString(check)); break; } else if (Data.GetFlag(offset + i) != check) { - StreamError.WriteLine("({0}) Offset 0x{1:X}: Expected {2}, but got {3} instead.", ++errorCount, offset + i, Util.TypeToString(check), Util.TypeToString(Data.GetFlag(offset + i))); + StreamError.WriteLine("({0}) Offset 0x{1:X}: Expected {2}, but got {3} instead.", ++errorCount, offset + i, RomUtil.TypeToString(check), RomUtil.TypeToString(Data.GetFlag(offset + i))); break; } } diff --git a/DiztinGUIsh/core/Project.cs b/DiztinGUIsh/core/Project.cs index bef85953..77653cfd 100644 --- a/DiztinGUIsh/core/Project.cs +++ b/DiztinGUIsh/core/Project.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Windows.Forms; +using DiztinGUIsh.core.util; namespace DiztinGUIsh { @@ -81,16 +80,23 @@ public Project() LogWriterSettings.SetDefaults(); } - public struct ImportRomSettings + public class ImportRomSettings { - public Data.ROMMapMode ROMMapMode; - public Data.ROMSpeed ROMSpeed; + // temp + private Data.ROMMapMode mode; + public Data.ROMMapMode ROMMapMode + { + get => mode; + set => mode = value; + } + + public Data.ROMSpeed ROMSpeed { get; set; } - public Dictionary InitialLabels; - public Dictionary InitialHeaderFlags; + public Dictionary InitialLabels { get; set; } + public Dictionary InitialHeaderFlags { get; set; } - public byte[] rom_bytes; - public string rom_filename; + public byte[] RomBytes { get; set; } + public string RomFilename { get; set; } } private string projectFileName; @@ -101,87 +107,28 @@ public struct ImportRomSettings private Data data; private LogWriterSettings logWriterSettings; - public byte[] ReadFromOriginalRom() - { - string firstRomFileWeTried; - var nextFileToTry = firstRomFileWeTried = AttachedRomFilename; - byte[] rom; - - do { - var error = ReadRomIfMatchesProject(nextFileToTry, out rom); - if (error == null) - break; - - // TODO: move to controller - nextFileToTry = PromptForNewRom($"{error} Link a new ROM now?"); - if (nextFileToTry == null) - return null; - } while (true); - - AttachedRomFilename = nextFileToTry; - - if (AttachedRomFilename != firstRomFileWeTried) - UnsavedChanges = true; - - return rom; - } - - private string ReadRomIfMatchesProject(string filename, out byte[] rom_bytes) + public string ReadRomIfMatchesProject(string filename, out byte[] romBytes) { - string error_msg = null; + string errorMsg = null; try { - rom_bytes = Util.ReadAllRomBytesFromFile(filename); - if (rom_bytes != null) + romBytes = RomUtil.ReadAllRomBytesFromFile(filename); + if (romBytes != null) { - error_msg = IsThisRomIsIdenticalToUs(rom_bytes); - if (error_msg == null) + errorMsg = IsThisRomIsIdenticalToUs(romBytes); + if (errorMsg == null) return null; } } catch (Exception ex) { - error_msg = ex.Message; + errorMsg = ex.Message; } - rom_bytes = null; - return error_msg; + romBytes = null; + return errorMsg; } private string IsThisRomIsIdenticalToUs(byte[] romBytes) => - Util.IsThisRomIsIdenticalToUs(romBytes, Data.RomMapMode, InternalRomGameName, InternalCheckSum); - private string PromptForNewRom(string promptText) - { - // TODO: put this in the view, hooked up through controller. - - var dialogResult = MessageBox.Show(promptText, "Error", - MessageBoxButtons.YesNo, MessageBoxIcon.Error); - - return dialogResult == DialogResult.Yes ? PromptToSelectFile() : null; - } - - private string PromptToSelectFile() - { - // TODO: move to controller - return Util.PromptToSelectFile(ProjectFileName); - } - - public bool PostSerializationLoad() - { - // at this stage, 'Data' is populated with everything EXCEPT the actual ROM bytes. - // It would be easy to store the ROM bytes in the save file, but, for copyright reasons, - // we leave it out. - // - // So now, with all our metadata loaded successfully, we now open the .smc file on disk - // and marry the original rom's bytes with all of our metadata loaded from the project file. - - Debug.Assert(Data.RomBytes != null && Data.Labels != null && Data.Comments != null); - - var rom = ReadFromOriginalRom(); - if (rom == null) - return false; - - Data.CopyRomDataIn(rom); - return true; - } + RomUtil.IsThisRomIsIdenticalToUs(romBytes, Data.RomMapMode, InternalRomGameName, InternalCheckSum); #region Equality protected bool Equals(Project other) diff --git a/DiztinGUIsh/core/ROMByte.cs b/DiztinGUIsh/core/ROMByte.cs index c8bdb365..c203a676 100644 --- a/DiztinGUIsh/core/ROMByte.cs +++ b/DiztinGUIsh/core/ROMByte.cs @@ -8,6 +8,7 @@ namespace DiztinGUIsh { public class ROMByte { + #region Equality protected bool Equals(ROMByte other) { return Rom == other.Rom && EqualsButNoRomByte(other); @@ -41,14 +42,15 @@ public override int GetHashCode() return hashCode; } } + #endregion public byte Rom { get; set; } // never serialize this, read from ROM on load. for copyright reasons. public byte DataBank { get; set; } public int DirectPage { get; set; } public bool XFlag { get; set; } public bool MFlag { get; set; } - public Data.FlagType TypeFlag { get; set; } - public Data.Architecture Arch { get; set; } - public Data.InOutPoint Point { get; set; } + public Data.FlagType TypeFlag { get; set; } = Data.FlagType.Unreached; + public Data.Architecture Arch { get; set; } = Data.Architecture.CPU65C816; + public Data.InOutPoint Point { get; set; } = 0; } } diff --git a/DiztinGUIsh/core/RomBytes.cs b/DiztinGUIsh/core/RomBytes.cs index 8cc99a67..a114b0bf 100644 --- a/DiztinGUIsh/core/RomBytes.cs +++ b/DiztinGUIsh/core/RomBytes.cs @@ -19,7 +19,22 @@ public ROMByte this[int i] } public int Count => Bytes.Count; + public void Add(ROMByte romByte) + { + Bytes.Add(romByte); + } + + public void Create(int size) + { + for (int i = 0; i < size; ++i) + Add(new ROMByte()); + } + public void Clear() + { + Bytes.Clear(); + } + #region Equality protected bool Equals(RomBytes other) { return Bytes.SequenceEqual(other.Bytes); @@ -37,7 +52,9 @@ public override int GetHashCode() { return (Bytes != null ? Bytes.GetHashCode() : 0); } + #endregion + #region Enumerator public IEnumerator GetEnumerator() { return Bytes.GetEnumerator(); @@ -47,10 +64,6 @@ IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } - - public void Add(ROMByte romByte) - { - Bytes.Add(romByte); - } + #endregion } } diff --git a/DiztinGUIsh/core/util/ByteUtil.cs b/DiztinGUIsh/core/util/ByteUtil.cs new file mode 100644 index 00000000..49eb00bb --- /dev/null +++ b/DiztinGUIsh/core/util/ByteUtil.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DiztinGUIsh.core.util +{ + public static class ByteUtil + { + // take input addresses that look like this, and convert to an int. + // useful if pasting addresses from other editors/tools/asm/etc and + // generating a clean address. + // C0FFFF + // $C0FFFF + // C7/AAAA + // $C6/BBBB + public static bool StripFormattedAddress(ref string addressTxt, NumberStyles style, out int address) + { + address = -1; + + if (string.IsNullOrEmpty(addressTxt)) + return false; + + var inputText = new string(Array.FindAll(addressTxt.ToCharArray(), (c => + (char.IsLetterOrDigit(c) || char.IsWhiteSpace(c)) + ))); + + if (!int.TryParse(inputText, style, null, out address)) + return false; + + addressTxt = inputText; + return true; + } + + public delegate int AddressConverter(int address); + + public static int ReadStringsTable(byte[] bytes, int starting_index, int stringsPerEntry, AddressConverter converter, Action processTableEntry) + { + var strings = new List(); + + var pos = starting_index; + var num_table_entries = ByteArrayToInteger(bytes, pos); + pos += 4; + + for (var entry = 0; entry < num_table_entries; ++entry) + { + var offset = converter(ByteArrayToInteger(bytes, pos)); + pos += 4; + + strings.Clear(); + for (var j = 0; j < stringsPerEntry; ++j) + { + pos += ReadNullTerminatedString(bytes, pos, out var str); + strings.Add(str); + } + processTableEntry(offset, strings.ToArray()); + } + + return pos - starting_index; + } + + public static int ReadNullTerminatedString(byte[] bytes, int starting_offset, out string str) + { + str = ""; + var pos = starting_offset; + while (bytes[pos] != 0) + str += (char)bytes[pos++]; + pos++; + return pos - starting_offset; + } + + public static byte[] IntegerToByteArray(int a) + { + return new byte[] + { + (byte)a, + (byte)(a >> 8), + (byte)(a >> 16), + (byte)(a >> 24) + }; + } + + public static void IntegerIntoByteArray(int a, byte[] data, int offset) + { + byte[] arr = IntegerToByteArray(a); + for (int i = 0; i < arr.Length; i++) data[offset + i] = arr[i]; + } + + public static void IntegerIntoByteList(int a, List list) + { + byte[] arr = IntegerToByteArray(a); + for (int i = 0; i < arr.Length; i++) list.Add(arr[i]); + } + + public static int ByteArrayToInteger(byte[] data, int offset = 0) + { + return + data[offset] | + (data[offset + 1] << 8) | + (data[offset + 2] << 16) | + (data[offset + 3] << 24); + } + + public static byte[] StringToByteArray(string s) + { + byte[] array = new byte[s.Length + 1]; + for (int i = 0; i < s.Length; i++) array[i] = (byte)s[i]; + array[s.Length] = 0; + return array; + } + } +} diff --git a/DiztinGUIsh/core/util/ObservableDictionary.cs b/DiztinGUIsh/core/util/ObservableDictionary.cs index ccc081b7..1082eec2 100644 --- a/DiztinGUIsh/core/util/ObservableDictionary.cs +++ b/DiztinGUIsh/core/util/ObservableDictionary.cs @@ -1,4 +1,5 @@ -using System.Collections; +using System; +using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; @@ -7,7 +8,7 @@ namespace DiztinGUIsh.core.util { // based on: kzu/ObservableDictionary.cs https://gist.github.com/kzu/cfe3cb6e4fe3efea6d24 - // note: does newer .NET have a native version of this? if so, replace. + // adds implementation of IDictionary, which we need. /// /// Provides a dictionary for use with data binding. @@ -16,13 +17,14 @@ namespace DiztinGUIsh.core.util /// Specifies the type of the values in this collection. [DebuggerDisplay("Count={" + nameof(Count) + "}")] public class ObservableDictionary : - /*ICollection>,*/ + // ICollection>, IDictionary, + IDictionary, INotifyCollectionChanged, INotifyPropertyChanged { private readonly IDictionary dictionary; - /// Event raised when the collection changes. + /// Event raised when the collection changes. public event NotifyCollectionChangedEventHandler CollectionChanged = (sender, args) => { }; /// Event raised when a property on the collection changes. @@ -129,6 +131,8 @@ public bool ContainsKey(TKey key) /// An containing the keys of the object that implements . public ICollection Keys => dictionary.Keys; + // ICollection IDictionary.Values => (ICollection) dictionary.Values; + /// /// Removes the element with the specified key from the . /// @@ -154,7 +158,7 @@ public bool TryGetValue(TKey key, out TValue value) return dictionary.TryGetValue(key, out value); } - /// + /// /// Gets an containing the values in the . /// /// An containing the values in the object that implements . @@ -180,7 +184,9 @@ public void Add(KeyValuePair item) AddWithNotification(item); } - public void Clear() + + + public void Clear() { dictionary.Clear(); @@ -190,17 +196,14 @@ public void Clear() PropertyChanged(this, new PropertyChangedEventArgs("Values")); } - public bool Contains(KeyValuePair item) - { - return dictionary.Contains(item); - } + public bool Contains(KeyValuePair item) => dictionary.Contains(item); public void CopyTo(KeyValuePair[] array, int arrayIndex) { dictionary.CopyTo(array, arrayIndex); } - public int Count => dictionary.Count; + public int Count => dictionary.Count; public bool IsReadOnly => dictionary.IsReadOnly; @@ -224,5 +227,41 @@ IEnumerator IEnumerable.GetEnumerator() } #endregion - } + + + #region IDictionary + + ICollection IDictionary.Keys => (ICollection)dictionary.Keys; + ICollection IDictionary.Values => (ICollection)dictionary.Values; + public void Add(object key, object value) + { + AddWithNotification((TKey)key, (TValue)value); + } + public IDictionaryEnumerator GetEnumerator() + { + return ((IDictionary)(dictionary)).GetEnumerator(); + } + + public void Remove(object key) + { + RemoveWithNotification((TKey)key); + } + + public object this[object key] + { + get => dictionary[(TKey)key]; + set => UpdateWithNotification((TKey)key, (TValue)value); + } + public bool Contains(object key) => dictionary.Contains((KeyValuePair)key); + public void CopyTo(Array array, int index) + { + CopyTo((KeyValuePair[])(array), index); + } + + public object SyncRoot => null; // TODO? + public bool IsSynchronized => false; // TODO? + public bool IsFixedSize => false; // TODO? + + #endregion + } } diff --git a/DiztinGUIsh/core/util/RomUtil.cs b/DiztinGUIsh/core/util/RomUtil.cs index 37b7d82c..cac1157e 100644 --- a/DiztinGUIsh/core/util/RomUtil.cs +++ b/DiztinGUIsh/core/util/RomUtil.cs @@ -1,13 +1,401 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using DiztinGUIsh.Annotations; namespace DiztinGUIsh.core.util { public static class RomUtil { + public static int GetBankSize(Data.ROMMapMode mode) + { + // todo + return mode == Data.ROMMapMode.LoROM ? 0x8000 : 0x10000; + } + public static Data.ROMSpeed GetRomSpeed(int offset, IReadOnlyList romBytes) => + offset < romBytes.Count + ? (romBytes[offset] & 0x10) != 0 ? Data.ROMSpeed.FastROM : Data.ROMSpeed.SlowROM + : Data.ROMSpeed.Unknown; + + // verify the data in the provided ROM bytes matches the data we expect it to have. + // returns error message if it's not identical, or null if everything is OK. + public static string IsThisRomIsIdenticalToUs(byte[] rom, + Data.ROMMapMode mode, string requiredGameNameMatch, int requiredRomChecksumMatch) + { + var romSettingsOffset = GetRomSettingOffset(mode); + if (rom.Length <= romSettingsOffset + 10) + return "The linked ROM is too small. It can't be opened."; + + var internalGameNameToVerify = GetRomTitleName(rom, romSettingsOffset); + var checksumToVerify = ByteUtil.ByteArrayToInteger(rom, romSettingsOffset + 7); + + if (internalGameNameToVerify != requiredGameNameMatch) + return $"The linked ROM's internal name '{internalGameNameToVerify}' doesn't " + + $"match the project's internal name of '{requiredGameNameMatch}'."; + + if (checksumToVerify != requiredRomChecksumMatch) + return $"The linked ROM's checksums '{checksumToVerify:X8}' " + + $"don't match the project's checksums of '{requiredRomChecksumMatch:X8}'."; + + return null; + } + + public static string GetRomTitleName(byte[] rom, int romSettingOffset) + { + var offsetOfGameTitle = romSettingOffset - LengthOfTitleName; + var internalGameNameToVerify = ReadStringFromByteArray(rom, LengthOfTitleName, offsetOfGameTitle); + return internalGameNameToVerify; + } + + public static int ConvertSNESToPC(int address, Data.ROMMapMode mode, int size) + { + int _UnmirroredOffset(int offset) => RomUtil.UnmirroredOffset(offset, size); + + // WRAM is N/A to PC addressing + if ((address & 0xFE0000) == 0x7E0000) return -1; + + // WRAM mirror & PPU regs are N/A to PC addressing + if (((address & 0x400000) == 0) && ((address & 0x8000) == 0)) return -1; + + switch (mode) + { + case Data.ROMMapMode.LoROM: + { + // SRAM is N/A to PC addressing + if (((address & 0x700000) == 0x700000) && ((address & 0x8000) == 0)) + return -1; + + return _UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); + } + case Data.ROMMapMode.HiROM: + { + return _UnmirroredOffset(address & 0x3FFFFF); + } + case Data.ROMMapMode.SuperMMC: + { + return _UnmirroredOffset(address & 0x3FFFFF); // todo, treated as hirom atm + } + case Data.ROMMapMode.SA1ROM: + case Data.ROMMapMode.ExSA1ROM: + { + // BW-RAM is N/A to PC addressing + if (address >= 0x400000 && address <= 0x7FFFFF) return -1; + + if (address >= 0xC00000) + return mode == Data.ROMMapMode.ExSA1ROM ? _UnmirroredOffset(address & 0x7FFFFF) : _UnmirroredOffset(address & 0x3FFFFF); + + if (address >= 0x800000) address -= 0x400000; + + // SRAM is N/A to PC addressing + if (((address & 0x8000) == 0)) return -1; + + return _UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); + } + case Data.ROMMapMode.SuperFX: + { + // BW-RAM is N/A to PC addressing + if (address >= 0x600000 && address <= 0x7FFFFF) + return -1; + + if (address < 0x400000) + return _UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); + + if (address < 0x600000) + return _UnmirroredOffset(address & 0x3FFFFF); + + if (address < 0xC00000) + return 0x200000 + _UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); + + return 0x400000 + _UnmirroredOffset(address & 0x3FFFFF); + } + case Data.ROMMapMode.ExHiROM: + { + return _UnmirroredOffset(((~address & 0x800000) >> 1) | (address & 0x3FFFFF)); + } + case Data.ROMMapMode.ExLoROM: + { + // SRAM is N/A to PC addressing + if (((address & 0x700000) == 0x700000) && ((address & 0x8000) == 0)) + return -1; + + return _UnmirroredOffset((((address ^ 0x800000) & 0xFF0000) >> 1) | (address & 0x7FFF)); + } + default: + { + return -1; + } + } + } + + public static int ConvertPCtoSNES(int offset, Data.ROMMapMode romMapMode, Data.ROMSpeed romSpeed) + { + switch (romMapMode) + { + case Data.ROMMapMode.LoROM: + offset = ((offset & 0x3F8000) << 1) | 0x8000 | (offset & 0x7FFF); + if (romSpeed == Data.ROMSpeed.FastROM || offset >= 0x7E0000) offset |= 0x800000; + return offset; + case Data.ROMMapMode.HiROM: + offset |= 0x400000; + if (romSpeed == Data.ROMSpeed.FastROM || offset >= 0x7E0000) offset |= 0x800000; + return offset; + case Data.ROMMapMode.ExHiROM when offset < 0x40000: + offset |= 0xC00000; + return offset; + case Data.ROMMapMode.ExHiROM: + if (offset >= 0x7E0000) offset &= 0x3FFFFF; + return offset; + case Data.ROMMapMode.ExSA1ROM when offset >= 0x400000: + offset += 0x800000; + return offset; + } + + offset = ((offset & 0x3F8000) << 1) | 0x8000 | (offset & 0x7FFF); + if (offset >= 0x400000) offset += 0x400000; + + return offset; + } + + + // TODO: replace with Description() attribute + public static string TypeToString(Data.FlagType flag) + { + return flag switch + { + Data.FlagType.Unreached => "Unreached", + Data.FlagType.Opcode => "Opcode", + Data.FlagType.Operand => "Operand", + Data.FlagType.Data8Bit => "Data (8-bit)", + Data.FlagType.Graphics => "Graphics", + Data.FlagType.Music => "Music", + Data.FlagType.Empty => "Empty", + Data.FlagType.Data16Bit => "Data (16-bit)", + Data.FlagType.Pointer16Bit => "Pointer (16-bit)", + Data.FlagType.Data24Bit => "Data (24-bit)", + Data.FlagType.Pointer24Bit => "Pointer (24-bit)", + Data.FlagType.Data32Bit => "Data (32-bit)", + Data.FlagType.Pointer32Bit => "Pointer (32-bit)", + Data.FlagType.Text => "Text", + _ => "" + }; + } + + public static int UnmirroredOffset(int offset, int size) + { + // most of the time this is true; for efficiency + if (offset < size) + return offset; + + int repeatSize = 0x8000; + while (repeatSize < size) repeatSize <<= 1; + + int repeatedOffset = offset % repeatSize; + + // this will then be true for ROM sizes of powers of 2 + if (repeatedOffset < size) return repeatedOffset; + + // for ROM sizes not powers of 2, it's kinda ugly + int sizeOfSmallerSection = 0x8000; + while (size % (sizeOfSmallerSection << 1) == 0) sizeOfSmallerSection <<= 1; + + while (repeatedOffset >= size) repeatedOffset -= sizeOfSmallerSection; + return repeatedOffset; + } + + // TODO: use new enum GetDescription() stuff. + public static string GetRomMapModeName(Data.ROMMapMode mode) + { + return mode switch + { + Data.ROMMapMode.ExSA1ROM => "SA-1 ROM (FuSoYa's 8MB mapper)", + Data.ROMMapMode.SA1ROM => "SA-1 ROM", + Data.ROMMapMode.SuperFX => "SuperFX", + Data.ROMMapMode.LoROM => "LoROM", + Data.ROMMapMode.HiROM => "HiROM", + Data.ROMMapMode.SuperMMC => "Super MMC", + Data.ROMMapMode.ExHiROM => "ExHiROM", + Data.ROMMapMode.ExLoROM => "ExLoROM", + _ => "Unknown mapping" + }; + } + + public static string TypeToLabel(Data.FlagType flag) + { + return flag switch + { + Data.FlagType.Unreached => "UNREACH", + Data.FlagType.Opcode => "CODE", + Data.FlagType.Operand => "LOOSE_OP", + Data.FlagType.Data8Bit => "DATA8", + Data.FlagType.Graphics => "GFX", + Data.FlagType.Music => "MUSIC", + Data.FlagType.Empty => "EMPTY", + Data.FlagType.Data16Bit => "DATA16", + Data.FlagType.Pointer16Bit => "PTR16", + Data.FlagType.Data24Bit => "DATA24", + Data.FlagType.Pointer24Bit => "PTR24", + Data.FlagType.Data32Bit => "DATA32", + Data.FlagType.Pointer32Bit => "PTR32", + Data.FlagType.Text => "TEXT", + _ => "" + }; + } + + public static int TypeStepSize(Data.FlagType flag) + { + switch (flag) + { + case Data.FlagType.Unreached: + case Data.FlagType.Opcode: + case Data.FlagType.Operand: + case Data.FlagType.Data8Bit: + case Data.FlagType.Graphics: + case Data.FlagType.Music: + case Data.FlagType.Empty: + case Data.FlagType.Text: + return 1; + case Data.FlagType.Data16Bit: + case Data.FlagType.Pointer16Bit: + return 2; + case Data.FlagType.Data24Bit: + case Data.FlagType.Pointer24Bit: + return 3; + case Data.FlagType.Data32Bit: + case Data.FlagType.Pointer32Bit: + return 4; + } + return 0; + } + + public static Data.ROMMapMode DetectROMMapMode(IReadOnlyList rom_bytes, out bool couldnt_detect) + { + couldnt_detect = false; + + if ((rom_bytes[Data.LOROM_SETTING_OFFSET] & 0xEF) == 0x23) + { + return rom_bytes.Count > 0x400000 ? Data.ROMMapMode.ExSA1ROM : Data.ROMMapMode.SA1ROM; + } + else if ((rom_bytes[Data.LOROM_SETTING_OFFSET] & 0xEC) == 0x20) + { + return (rom_bytes[Data.LOROM_SETTING_OFFSET + 1] & 0xF0) == 0x10 ? Data.ROMMapMode.SuperFX : Data.ROMMapMode.LoROM; + } + else if (rom_bytes.Count >= 0x10000 && (rom_bytes[Data.HIROM_SETTING_OFFSET] & 0xEF) == 0x21) + { + return Data.ROMMapMode.HiROM; + } + else if (rom_bytes.Count >= 0x10000 && (rom_bytes[Data.HIROM_SETTING_OFFSET] & 0xE7) == 0x22) + { + return Data.ROMMapMode.SuperMMC; + } + else if (rom_bytes.Count >= 0x410000 && (rom_bytes[Data.EXHIROM_SETTING_OFFSET] & 0xEF) == 0x25) + { + return Data.ROMMapMode.ExHiROM; + } + else + { + // detection failed. take our best guess..... + couldnt_detect = true; + return rom_bytes.Count > 0x40000 ? Data.ROMMapMode.ExLoROM : Data.ROMMapMode.LoROM; + } + } + + public static int GetRomSettingOffset(Data.ROMMapMode mode) + { + return mode switch + { + Data.ROMMapMode.LoROM => Data.LOROM_SETTING_OFFSET, + Data.ROMMapMode.HiROM => Data.HIROM_SETTING_OFFSET, + Data.ROMMapMode.ExHiROM => Data.EXHIROM_SETTING_OFFSET, + Data.ROMMapMode.ExLoROM => Data.EXLOROM_SETTING_OFFSET, + _ => Data.LOROM_SETTING_OFFSET + }; + } + + public static string ArchToString(Data.Architecture arch) + { + return arch switch + { + Data.Architecture.CPU65C816 => "65C816", + Data.Architecture.APUSPC700 => "SPC700", + Data.Architecture.GPUSuperFX => "SuperFX", + _ => "" + }; + } + + public static string PointToString(Data.InOutPoint point) + { + string result; + + if ((point & Data.InOutPoint.EndPoint) == Data.InOutPoint.EndPoint) result = "X"; + else if ((point & Data.InOutPoint.OutPoint) == Data.InOutPoint.OutPoint) result = "<"; + else result = " "; + + result += ((point & Data.InOutPoint.ReadPoint) == Data.InOutPoint.ReadPoint) ? "*" : " "; + result += ((point & Data.InOutPoint.InPoint) == Data.InOutPoint.InPoint) ? ">" : " "; + + return result; + } + + public static string BoolToSize(bool b) + { + return b ? "8" : "16"; + } + + // read a fixed length string from an array of bytes. does not check for null termination + public static string ReadStringFromByteArray(byte[] bytes, int count, int offset) + { + var myName = ""; + for (var i = 0; i < count; i++) + myName += (char)bytes[offset + i]; + + return myName; + } + + public static byte[] ReadAllRomBytesFromFile(string filename) + { + var smc = File.ReadAllBytes(filename); + var rom = new byte[smc.Length & 0x7FFFFC00]; + + if ((smc.Length & 0x3FF) == 0x200) + // skip and dont include the SMC header + for (int i = 0; i < rom.Length; i++) + rom[i] = smc[i + 0x200]; + else if ((smc.Length & 0x3FF) != 0) + throw new InvalidDataException("This ROM has an unusual size. It can't be opened."); + else + rom = smc; + + if (rom.Length < 0x8000) + throw new InvalidDataException("This ROM is too small. It can't be opened."); + + return rom; + } + + public static void GetHeaderFlags(int offset, IDictionary flags, byte[] romBytes) + { + for (int i = 0; i < LengthOfTitleName; i++) flags.Add(offset - 0x15 + i, Data.FlagType.Text); + for (int i = 0; i < 7; i++) flags.Add(offset + i, Data.FlagType.Data8Bit); + for (int i = 0; i < 4; i++) flags.Add(offset + 7 + i, Data.FlagType.Data16Bit); + for (int i = 0; i < 0x20; i++) flags.Add(offset + 11 + i, Data.FlagType.Pointer16Bit); + + if (romBytes[offset - 1] == 0) + { + flags.Remove(offset - 1); + flags.Add(offset - 1, Data.FlagType.Data8Bit); + for (int i = 0; i < 0x10; i++) flags.Add(offset - 0x25 + i, Data.FlagType.Data8Bit); + } + else if (romBytes[offset + 5] == 0x33) + { + for (int i = 0; i < 6; i++) flags.Add(offset - 0x25 + i, Data.FlagType.Text); + for (int i = 0; i < 10; i++) flags.Add(offset - 0x1F + i, Data.FlagType.Data8Bit); + } + } + + public const int LengthOfTitleName = 0x15; } } diff --git a/DiztinGUIsh/core/util/Util.cs b/DiztinGUIsh/core/util/Util.cs index be55457d..9c03e876 100644 --- a/DiztinGUIsh/core/util/Util.cs +++ b/DiztinGUIsh/core/util/Util.cs @@ -1,11 +1,10 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.Globalization; using System.IO; using System.IO.Compression; +using System.Linq; using System.Text; -using System.Windows.Forms; namespace DiztinGUIsh { @@ -15,474 +14,20 @@ public enum NumberBase { Decimal = 3, Hexadecimal = 2, Binary = 8 } - public static int GetBankSize(Data.ROMMapMode mode) - { - // todo - return mode == Data.ROMMapMode.LoROM ? 0x8000 : 0x10000; - } - - // verify the data in the provided ROM bytes matches the data we expect it to have. - // returns error message if it's not identical, or null if everything is OK. - public static string IsThisRomIsIdenticalToUs(byte[] rom, - Data.ROMMapMode mode, string internalGameNameMustMatch, int romChecksums) - { - var offset = Util.GetRomSettingOffset(mode); - if (rom.Length <= offset + 10) - return "The linked ROM is too small. It can't be opened."; - - var internalGameNameToVerify = Util.ReadStringFromByteArray(rom, 0x15, offset); - var checksumToVerify = Util.ByteArrayToInteger(rom, offset + 7); - - if (internalGameNameToVerify != internalGameNameMustMatch) - return $"The linked ROM's internal name '{internalGameNameToVerify}' doesn't " + - $"match the project's internal name of '{internalGameNameMustMatch}'."; - - if (checksumToVerify != romChecksums) - return $"The linked ROM's checksums '{checksumToVerify:X8}' " + - $"don't match the project's checksums of '{romChecksums:X8}'."; - - return null; - } - public static int ConvertSNESToPC(int address, Data.ROMMapMode mode, int size) - { - int UnmirroredOffset(int offset) => Util.UnmirroredOffset(offset, size); - - // WRAM is N/A to PC addressing - if ((address & 0xFE0000) == 0x7E0000) return -1; - - // WRAM mirror & PPU regs are N/A to PC addressing - if (((address & 0x400000) == 0) && ((address & 0x8000) == 0)) return -1; - - switch (mode) - { - case Data.ROMMapMode.LoROM: - { - // SRAM is N/A to PC addressing - if (((address & 0x700000) == 0x700000) && ((address & 0x8000) == 0)) return -1; - - return UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); - } - case Data.ROMMapMode.HiROM: - { - return UnmirroredOffset(address & 0x3FFFFF); - } - case Data.ROMMapMode.SuperMMC: - { - return UnmirroredOffset(address & 0x3FFFFF); // todo, treated as hirom atm - } - case Data.ROMMapMode.SA1ROM: - case Data.ROMMapMode.ExSA1ROM: - { - // BW-RAM is N/A to PC addressing - if (address >= 0x400000 && address <= 0x7FFFFF) return -1; - - if (address >= 0xC00000) - { - if (mode == Data.ROMMapMode.ExSA1ROM) - return UnmirroredOffset(address & 0x7FFFFF); - else - return UnmirroredOffset(address & 0x3FFFFF); - } - else - { - if (address >= 0x800000) address -= 0x400000; - - // SRAM is N/A to PC addressing - if (((address & 0x8000) == 0)) return -1; - - return UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); - } - } - case Data.ROMMapMode.SuperFX: - { - // BW-RAM is N/A to PC addressing - if (address >= 0x600000 && address <= 0x7FFFFF) return -1; - - if (address < 0x400000) - { - return UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); - } - else if (address < 0x600000) - { - return UnmirroredOffset(address & 0x3FFFFF); - } - else if (address < 0xC00000) - { - return 0x200000 + UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); - } - else - { - return 0x400000 + UnmirroredOffset(address & 0x3FFFFF); - } - } - case Data.ROMMapMode.ExHiROM: - { - return UnmirroredOffset(((~address & 0x800000) >> 1) | (address & 0x3FFFFF)); - } - case Data.ROMMapMode.ExLoROM: - { - // SRAM is N/A to PC addressing - if (((address & 0x700000) == 0x700000) && ((address & 0x8000) == 0)) return -1; - - return UnmirroredOffset((((address ^ 0x800000) & 0xFF0000) >> 1) | (address & 0x7FFF)); - } - default: - { - return -1; - } - } - } - - public static int ConvertPCtoSNES(int offset, Data.ROMMapMode romMapMode, Data.ROMSpeed romSpeed) - { - switch (romMapMode) - { - case Data.ROMMapMode.LoROM: - offset = ((offset & 0x3F8000) << 1) | 0x8000 | (offset & 0x7FFF); - if (romSpeed == Data.ROMSpeed.FastROM || offset >= 0x7E0000) offset |= 0x800000; - return offset; - case Data.ROMMapMode.HiROM: - offset |= 0x400000; - if (romSpeed == Data.ROMSpeed.FastROM || offset >= 0x7E0000) offset |= 0x800000; - return offset; - case Data.ROMMapMode.ExHiROM when offset < 0x40000: - offset |= 0xC00000; - return offset; - case Data.ROMMapMode.ExHiROM: - if (offset >= 0x7E0000) offset &= 0x3FFFFF; - return offset; - case Data.ROMMapMode.ExSA1ROM when offset >= 0x400000: - offset += 0x800000; - return offset; - } - - offset = ((offset & 0x3F8000) << 1) | 0x8000 | (offset & 0x7FFF); - if (offset >= 0x400000) offset += 0x400000; - - return offset; - } - - public delegate int AddressConverter(int address); - - public static int ReadStringsTable(byte[] bytes, int starting_index, int stringsPerEntry, AddressConverter converter, Action processTableEntry) - { - var strings = new List(); - - var pos = starting_index; - var num_table_entries = Util.ByteArrayToInteger(bytes, pos); - pos += 4; - - for (var entry = 0; entry < num_table_entries; ++entry) - { - var offset = converter(Util.ByteArrayToInteger(bytes, pos)); - pos += 4; - - strings.Clear(); - for (var j = 0; j < stringsPerEntry; ++j) - { - pos += Util.ReadNullTerminatedString(bytes, pos, out var str); - strings.Add(str); - } - processTableEntry(offset, strings.ToArray()); - } - - return pos - starting_index; - } - - public static int ReadNullTerminatedString(byte[] bytes, int starting_offset, out string str) - { - str = ""; - var pos = starting_offset; - while (bytes[pos] != 0) - str += (char)bytes[pos++]; - pos++; - return pos - starting_offset; - } - - public static byte[] IntegerToByteArray(int a) - { - return new byte[] - { - (byte)a, - (byte)(a >> 8), - (byte)(a >> 16), - (byte)(a >> 24) - }; - } - - public static void IntegerIntoByteArray(int a, byte[] data, int offset) - { - byte[] arr = IntegerToByteArray(a); - for (int i = 0; i < arr.Length; i++) data[offset + i] = arr[i]; - } - - public static void IntegerIntoByteList(int a, List list) - { - byte[] arr = IntegerToByteArray(a); - for (int i = 0; i < arr.Length; i++) list.Add(arr[i]); - } - - public static int ByteArrayToInteger(byte[] data, int offset = 0) - { - return - data[offset] | - (data[offset + 1] << 8) | - (data[offset + 2] << 16) | - (data[offset + 3] << 24); - } - - // deal with addresses that look like this, - // might be pasted from other editors - // C0FFFF - // $C0FFFF - // C7/AAAA - // $C6/BBBB - public static bool StripFormattedAddress(ref string addressTxt, NumberStyles style, out int address) - { - address = -1; - - if (string.IsNullOrEmpty(addressTxt)) - return false; - - var inputText = new string(Array.FindAll(addressTxt.ToCharArray(), (c => - (char.IsLetterOrDigit(c) || char.IsWhiteSpace(c)) - ))); - - if (int.TryParse(inputText, style, null, out address)) - { - addressTxt = inputText; - return true; - } - - return false; - } - - public static string TypeToString(Data.FlagType flag) - { - switch (flag) - { - case Data.FlagType.Unreached: return "Unreached"; - case Data.FlagType.Opcode: return "Opcode"; - case Data.FlagType.Operand: return "Operand"; - case Data.FlagType.Data8Bit: return "Data (8-bit)"; - case Data.FlagType.Graphics: return "Graphics"; - case Data.FlagType.Music: return "Music"; - case Data.FlagType.Empty: return "Empty"; - case Data.FlagType.Data16Bit: return "Data (16-bit)"; - case Data.FlagType.Pointer16Bit: return "Pointer (16-bit)"; - case Data.FlagType.Data24Bit: return "Data (24-bit)"; - case Data.FlagType.Pointer24Bit: return "Pointer (24-bit)"; - case Data.FlagType.Data32Bit: return "Data (32-bit)"; - case Data.FlagType.Pointer32Bit: return "Pointer (32-bit)"; - case Data.FlagType.Text: return "Text"; - } - return ""; - } - - public static int UnmirroredOffset(int offset, int size) - { - // most of the time this is true; for efficiency - if (offset < size) return offset; - - int repeatSize = 0x8000; - while (repeatSize < size) repeatSize <<= 1; - - int repeatedOffset = offset % repeatSize; - - // this will then be true for ROM sizes of powers of 2 - if (repeatedOffset < size) return repeatedOffset; - - // for ROM sizes not powers of 2, it's kinda ugly - int sizeOfSmallerSection = 0x8000; - while (size % (sizeOfSmallerSection << 1) == 0) sizeOfSmallerSection <<= 1; - - while (repeatedOffset >= size) repeatedOffset -= sizeOfSmallerSection; - return repeatedOffset; - } - - public static string GetRomMapModeName(Data.ROMMapMode mode) - { - switch (mode) - { - case Data.ROMMapMode.ExSA1ROM: - return "SA-1 ROM (FuSoYa's 8MB mapper)"; - - case Data.ROMMapMode.SA1ROM: - return "SA-1 ROM"; - - case Data.ROMMapMode.SuperFX: - return "SuperFX"; - - case Data.ROMMapMode.LoROM: - return "LoROM"; - - case Data.ROMMapMode.HiROM: - return "HiROM"; - - case Data.ROMMapMode.SuperMMC: - return "Super MMC"; - - case Data.ROMMapMode.ExHiROM: - return "ExHiROM"; - - case Data.ROMMapMode.ExLoROM: - return "ExLoROM"; - - default: - return "Unknown mapping"; - } - } - - public static string TypeToLabel(Data.FlagType flag) - { - switch (flag) - { - case Data.FlagType.Unreached: return "UNREACH"; - case Data.FlagType.Opcode: return "CODE"; - case Data.FlagType.Operand: return "LOOSE_OP"; - case Data.FlagType.Data8Bit: return "DATA8"; - case Data.FlagType.Graphics: return "GFX"; - case Data.FlagType.Music: return "MUSIC"; - case Data.FlagType.Empty: return "EMPTY"; - case Data.FlagType.Data16Bit: return "DATA16"; - case Data.FlagType.Pointer16Bit: return "PTR16"; - case Data.FlagType.Data24Bit: return "DATA24"; - case Data.FlagType.Pointer24Bit: return "PTR24"; - case Data.FlagType.Data32Bit: return "DATA32"; - case Data.FlagType.Pointer32Bit: return "PTR32"; - case Data.FlagType.Text: return "TEXT"; - } - return ""; - } - - public static int TypeStepSize(Data.FlagType flag) - { - switch (flag) - { - case Data.FlagType.Unreached: - case Data.FlagType.Opcode: - case Data.FlagType.Operand: - case Data.FlagType.Data8Bit: - case Data.FlagType.Graphics: - case Data.FlagType.Music: - case Data.FlagType.Empty: - case Data.FlagType.Text: - return 1; - case Data.FlagType.Data16Bit: - case Data.FlagType.Pointer16Bit: - return 2; - case Data.FlagType.Data24Bit: - case Data.FlagType.Pointer24Bit: - return 3; - case Data.FlagType.Data32Bit: - case Data.FlagType.Pointer32Bit: - return 4; - } - return 0; - } - - public static Data.ROMMapMode DetectROMMapMode(IReadOnlyList rom_bytes, out bool couldnt_detect) - { - couldnt_detect = false; - - if ((rom_bytes[Data.LOROM_SETTING_OFFSET] & 0xEF) == 0x23) - { - return rom_bytes.Count > 0x400000 ? Data.ROMMapMode.ExSA1ROM : Data.ROMMapMode.SA1ROM; - } - else if ((rom_bytes[Data.LOROM_SETTING_OFFSET] & 0xEC) == 0x20) - { - return (rom_bytes[Data.LOROM_SETTING_OFFSET + 1] & 0xF0) == 0x10 ? Data.ROMMapMode.SuperFX : Data.ROMMapMode.LoROM; - } - else if (rom_bytes.Count >= 0x10000 && (rom_bytes[Data.HIROM_SETTING_OFFSET] & 0xEF) == 0x21) - { - return Data.ROMMapMode.HiROM; - } - else if (rom_bytes.Count >= 0x10000 && (rom_bytes[Data.HIROM_SETTING_OFFSET] & 0xE7) == 0x22) - { - return Data.ROMMapMode.SuperMMC; - } - else if (rom_bytes.Count >= 0x410000 && (rom_bytes[Data.EXHIROM_SETTING_OFFSET] & 0xEF) == 0x25) - { - return Data.ROMMapMode.ExHiROM; - } - else - { - // detection failed. take our best guess..... - couldnt_detect = true; - return rom_bytes.Count > 0x40000 ? Data.ROMMapMode.ExLoROM : Data.ROMMapMode.LoROM; - } - } - - public static IEnumerable ReadLines(string path) - { - using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 0x1000, FileOptions.SequentialScan)) - using (var sr = new StreamReader(fs, Encoding.UTF8)) - { - string line; - while ((line = sr.ReadLine()) != null) - { - yield return line; - } - } - } - - public static int GetRomSettingOffset(Data.ROMMapMode mode) - { - return mode switch - { - Data.ROMMapMode.LoROM => Data.LOROM_SETTING_OFFSET, - Data.ROMMapMode.HiROM => Data.HIROM_SETTING_OFFSET, - Data.ROMMapMode.ExHiROM => Data.EXHIROM_SETTING_OFFSET, - Data.ROMMapMode.ExLoROM => Data.EXLOROM_SETTING_OFFSET, - _ => Data.LOROM_SETTING_OFFSET - }; - } - - - public static string ArchToString(Data.Architecture arch) - { - switch (arch) - { - case Data.Architecture.CPU65C816: return "65C816"; - case Data.Architecture.APUSPC700: return "SPC700"; - case Data.Architecture.GPUSuperFX: return "SuperFX"; - } - return ""; - } - - public static string PointToString(Data.InOutPoint point) - { - string result; - - if ((point & Data.InOutPoint.EndPoint) == Data.InOutPoint.EndPoint) result = "X"; - else if ((point & Data.InOutPoint.OutPoint) == Data.InOutPoint.OutPoint) result = "<"; - else result = " "; - - result += ((point & Data.InOutPoint.ReadPoint) == Data.InOutPoint.ReadPoint) ? "*" : " "; - result += ((point & Data.InOutPoint.InPoint) == Data.InOutPoint.InPoint) ? ">" : " "; - - return result; - } - - public static string BoolToSize(bool b) - { - return b ? "8" : "16"; - } public static string NumberToBaseString(int v, NumberBase noBase, int d = -1, bool showPrefix = false) { - int digits = d < 0 ? (int)noBase : d; + var digits = d < 0 ? (int)noBase : d; switch (noBase) { case NumberBase.Decimal: - if (digits == 0) return v.ToString("D"); - return v.ToString("D" + digits); + return digits == 0 ? v.ToString("D") : v.ToString("D" + digits); case NumberBase.Hexadecimal: if (digits == 0) return v.ToString("X"); return (showPrefix ? "$" : "") + v.ToString("X" + digits); case NumberBase.Binary: - string b = ""; - int i = 0; + var b = ""; + var i = 0; while (digits == 0 ? v > 0 : i < digits) { b += (v & 1); @@ -494,74 +39,53 @@ public static string NumberToBaseString(int v, NumberBase noBase, int d = -1, bo return ""; } - public static byte[] StringToByteArray(string s) + public static IEnumerable ReadLines(string path) { - byte[] array = new byte[s.Length + 1]; - for (int i = 0; i < s.Length; i++) array[i] = (byte)s[i]; - array[s.Length] = 0; - return array; - } + using var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 0x1000, FileOptions.SequentialScan); + using var sr = new StreamReader(fs, Encoding.UTF8); - // read a fixed length string from an array of bytes. does not check for null termination - public static string ReadStringFromByteArray(byte[] bytes, int count, int offset) - { - var myName = ""; - for (var i = 0; i < count; i++) - myName += (char)bytes[offset - count + i]; - return myName; + string line; + while ((line = sr.ReadLine()) != null) + { + yield return line; + } } public static long GetFileSizeInBytes(string filename) { - FileInfo fi = new FileInfo(filename); + var fi = new FileInfo(filename); if (!fi.Exists) return -1; return fi.Length; } - public static void InvokeIfRequired(this ISynchronizeInvoke obj, MethodInvoker action) - { - if (obj.InvokeRequired) - { - var args = new object[0]; - obj.Invoke(action, args); - } - else - { - action(); - } - } - // https://stackoverflow.com/questions/33119119/unzip-byte-array-in-c-sharp public static byte[] TryUnzip(byte[] data) { try { - using (MemoryStream comp = new MemoryStream(data)) - using (GZipStream gzip = new GZipStream(comp, CompressionMode.Decompress)) - using (MemoryStream res = new MemoryStream()) - { - gzip.CopyTo(res); - return res.ToArray(); - } + using var comp = new MemoryStream(data); + using var gzip = new GZipStream(comp, CompressionMode.Decompress); + using var res = new MemoryStream(); + gzip.CopyTo(res); + return res.ToArray(); } catch (Exception) { return null; } } + public static byte[] TryZip(byte[] data) { try { - using (MemoryStream comp = new MemoryStream()) - using (GZipStream gzip = new GZipStream(comp, CompressionMode.Compress)) - { - gzip.Write(data, 0, data.Length); - gzip.Close(); - return comp.ToArray(); - } + using var comp = new MemoryStream(); + using var gzip = new GZipStream(comp, CompressionMode.Compress); + gzip.Write(data, 0, data.Length); + gzip.Close(); + return comp.ToArray(); } catch (Exception) { @@ -569,28 +93,34 @@ public static byte[] TryZip(byte[] data) } } - public static byte[] ReadAllRomBytesFromFile(string filename) + public static string GetEnumDescription(Enum value) { - var smc = File.ReadAllBytes(filename); - var rom = new byte[smc.Length & 0x7FFFFC00]; + // example: + // type = Data.ROMMapMode (the entire enum) + // value = ExSA1ROM (one particular entry from the enum) + // description = "SA-1 ROM (FuSoYa's 8MB mapper)", (contents of [Description] attribute) - if ((smc.Length & 0x3FF) == 0x200) - for (int i = 0; i < rom.Length; i++) - rom[i] = smc[i + 0x200]; - else if ((smc.Length & 0x3FF) != 0) - throw new InvalidDataException("This ROM has an unusual size. It can't be opened."); - else - rom = smc; + var type = value.GetType(); + var memberInfo = type.GetField(value.ToString()); + var descAttr = (Attribute.GetCustomAttribute(memberInfo, typeof(DescriptionAttribute)) as DescriptionAttribute); + var name = descAttr?.Description ?? value.ToString(); + return name; + } - if (rom.Length < 0x8000) - throw new InvalidDataException("This ROM is too small. It can't be opened."); - return rom; - } - public static string PromptToSelectFile(string initialDirectory = null) + // take a enum type that has [Description] attributes, + // return a List with with kvp pairs of enum vs description + public static List> + GetEnumDescriptions() where TEnum : Enum { - var open = new OpenFileDialog { InitialDirectory = initialDirectory }; - return open.ShowDialog() == DialogResult.OK ? open.FileName : null; + var type = typeof(TEnum); + return Enum.GetValues(type) + .Cast() + .Select(value => new + KeyValuePair(key: value, value: GetEnumDescription(value)) + ) + .OrderBy(item => item.Key) + .ToList(); } } } diff --git a/DiztinGUIsh/loadsave/ProjectFileManager.cs b/DiztinGUIsh/loadsave/ProjectFileManager.cs index 0d9d5d45..2f423b92 100644 --- a/DiztinGUIsh/loadsave/ProjectFileManager.cs +++ b/DiztinGUIsh/loadsave/ProjectFileManager.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.IO; using System.Windows.Forms; using DiztinGUIsh.loadsave.binary_serializer_old; @@ -6,22 +7,23 @@ namespace DiztinGUIsh.loadsave { - static class ProjectFileManager + public static class ProjectFileManager { - public static Project Open(string filename) + public static Project Open(string filename, Func romPromptFn) { try { - return DoOpen(filename); + return DoOpen(filename, romPromptFn); } catch (Exception e) { + // TODO: remove direct GUI stuff from here. MessageBox.Show(e.Message, "Error opening project file", MessageBoxButtons.OK, MessageBoxIcon.Error); return null; } } - private static Project DoOpen(string filename) + private static Project DoOpen(string filename, Func romPromptFn) { var data = File.ReadAllBytes(filename); @@ -33,9 +35,60 @@ private static Project DoOpen(string filename) project.ProjectFileName = filename; + PostSerialize(project, romPromptFn); + return project; } + private static bool PostSerialize(Project project, Func romPromptFn) + { + // at this stage, 'Data' is populated with everything EXCEPT the actual ROM bytes. + // It would be easy to store the ROM bytes in the save file, but, for copyright reasons, + // we leave it out. + // + // So now, with all our metadata loaded successfully, we now open the .smc file on disk + // and marry the original rom's bytes with all of our metadata loaded from the project file. + + var data = project.Data; + + Debug.Assert(data.Labels != null && data.Comments != null); + Debug.Assert(data.RomBytes != null && data.RomBytes.Count > 0); + + var rom = ReadFromOriginalRom(project, romPromptFn); + if (rom == null) + return false; + + data.CopyRomDataIn(rom); + return true; + } + + public static byte[] ReadFromOriginalRom(Project project, Func romPromptFn) + { + string firstRomFileWeTried; + var nextFileToTry = firstRomFileWeTried = project.AttachedRomFilename; + byte[] rom; + + // try to open a ROM that matches us, if not, ask the user until they give up + do + { + var error = project.ReadRomIfMatchesProject(nextFileToTry, out rom); + if (error == null) + break; + + nextFileToTry = romPromptFn(error); + if (nextFileToTry == null) + return null; + } while (true); + + project.AttachedRomFilename = nextFileToTry; + + if (project.AttachedRomFilename != firstRomFileWeTried) + project.UnsavedChanges = true; + + return rom; + } + + private static ProjectSerializer GetSerializerForFormat(byte[] data) { if (BinarySerializer.IsBinaryFileFormat(data)) @@ -76,5 +129,35 @@ private static byte[] DoSave(Project project, string filename, ProjectSerializer return data; } + + public static Project ImportRomAndCreateNewProject(Project.ImportRomSettings importSettings) + { + var project = new Project + { + AttachedRomFilename = importSettings.RomFilename, + UnsavedChanges = false, + ProjectFileName = null, + Data = new Data() + }; + + project.Data.RomMapMode = importSettings.ROMMapMode; + project.Data.RomSpeed = importSettings.ROMSpeed; + project.Data.CreateRomBytesFromRom(importSettings.RomBytes); + + foreach (var pair in importSettings.InitialLabels) + project.Data.AddLabel(pair.Key, pair.Value, true); + + foreach (var pair in importSettings.InitialHeaderFlags) + project.Data.SetFlag(pair.Key, pair.Value); + + // Save a copy of these identifying ROM bytes with the project file itself. + // When we reload, we will make sure the linked ROM still matches them. + project.InternalCheckSum = project.Data.GetRomCheckSumsFromRomBytes(); + project.InternalRomGameName = project.Data.GetRomNameFromRomBytes(); + + project.UnsavedChanges = true; + + return project; + } } } diff --git a/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs b/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs index c8f089d9..a4b18a65 100644 --- a/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs +++ b/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs @@ -6,6 +6,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using DiztinGUIsh.core.util; using DiztinGUIsh.window; namespace DiztinGUIsh.loadsave.binary_serializer_old @@ -31,7 +32,7 @@ public override byte[] Save(Project project) byte[] everything = new byte[HEADER_SIZE + data.Length]; everything[0] = versionToSave; - Util.StringToByteArray(Watermark).CopyTo(everything, 1); + ByteUtil.StringToByteArray(Watermark).CopyTo(everything, 1); data.CopyTo(everything, HEADER_SIZE); return data; @@ -51,22 +52,22 @@ public override Project Load(byte[] data) }; // version 0 needs to convert PC to SNES for some addresses - Util.AddressConverter converter = address => address; + ByteUtil.AddressConverter converter = address => address; if (version == 0) converter = project.Data.ConvertPCtoSNES; // read mode, speed, size project.Data.RomMapMode = (Data.ROMMapMode)data[HEADER_SIZE]; project.Data.RomSpeed = (Data.ROMSpeed)data[HEADER_SIZE + 1]; - var size = Util.ByteArrayToInteger(data, HEADER_SIZE + 2); + var size = ByteUtil.ByteArrayToInteger(data, HEADER_SIZE + 2); // read internal title var pointer = HEADER_SIZE + 6; - for (var i = 0; i < 0x15; i++) - project.InternalRomGameName += (char)data[pointer++]; + RomUtil.ReadStringFromByteArray(data, RomUtil.LengthOfTitleName, pointer); + pointer += RomUtil.LengthOfTitleName; // read checksums - project.InternalCheckSum = Util.ByteArrayToInteger(data, pointer); + project.InternalCheckSum = ByteUtil.ByteArrayToInteger(data, pointer); pointer += 4; // read full filepath to the ROM .sfc file @@ -74,11 +75,7 @@ public override Project Load(byte[] data) project.AttachedRomFilename += (char)data[pointer++]; pointer++; - var rom = project.ReadFromOriginalRom(); - if (rom == null) - throw new Exception("Couldn't open the ROM file!"); - - project.Data.Initiate(rom, project.Data.RomMapMode, project.Data.RomSpeed); + project.Data.RomBytes.Create(size); for (int i = 0; i < size; i++) project.Data.SetDataBank(i, data[pointer + i]); for (int i = 0; i < size; i++) project.Data.SetDirectPage(i, data[pointer + size + i] | (data[pointer + 2 * size + i] << 8)); @@ -97,7 +94,7 @@ public override Project Load(byte[] data) return project; } - private static void SaveStringToBytes(string str, List bytes) + private static void SaveStringToBytes(string str, ICollection bytes) { // TODO: combine with Util.StringToByteArray() probably. if (str != null) { @@ -120,7 +117,7 @@ private byte[] SaveVersion(Project project, int version) romSettings[1] = (byte)project.Data.GetROMSpeed(); // save the size, 4 bytes - Util.IntegerIntoByteArray(size, romSettings, 2); + ByteUtil.IntegerIntoByteArray(size, romSettings, 2); var romName = project.Data.GetRomNameFromRomBytes(); romName.ToCharArray().CopyTo(romSettings, 6); @@ -135,10 +132,10 @@ private byte[] SaveVersion(Project project, int version) var all_labels = project.Data.Labels; var all_comments = project.Data.Comments; - Util.IntegerIntoByteList(all_labels.Count, label); - foreach (var pair in all_labels) + ByteUtil.IntegerIntoByteList(all_labels.Count, label); + foreach (KeyValuePair pair in all_labels) { - Util.IntegerIntoByteList(pair.Key, label); + ByteUtil.IntegerIntoByteList(pair.Key, label); SaveStringToBytes(pair.Value.name, label); if (version >= 2) @@ -147,28 +144,52 @@ private byte[] SaveVersion(Project project, int version) } } - Util.IntegerIntoByteList(all_comments.Count, comment); + ByteUtil.IntegerIntoByteList(all_comments.Count, comment); foreach (KeyValuePair pair in all_comments) { - Util.IntegerIntoByteList(pair.Key, comment); + ByteUtil.IntegerIntoByteList(pair.Key, comment); SaveStringToBytes(pair.Value, comment); } // save current Rom full path - "c:\whatever\someRom.sfc" - byte[] romLocation = Util.StringToByteArray(project.AttachedRomFilename); + var romLocation = ByteUtil.StringToByteArray(project.AttachedRomFilename); - byte[] data = new byte[romSettings.Length + romLocation.Length + 8 * size + label.Count + comment.Count]; + var data = new byte[romSettings.Length + romLocation.Length + 8 * size + label.Count + comment.Count]; romSettings.CopyTo(data, 0); for (int i = 0; i < romLocation.Length; i++) data[romSettings.Length + i] = romLocation[i]; - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + i] = (byte)project.Data.GetDataBank(i); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + size + i] = (byte)project.Data.GetDirectPage(i); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 2 * size + i] = (byte)(project.Data.GetDirectPage(i) >> 8); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 3 * size + i] = (byte)(project.Data.GetXFlag(i) ? 1 : 0); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 4 * size + i] = (byte)(project.Data.GetMFlag(i) ? 1 : 0); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 5 * size + i] = (byte)project.Data.GetFlag(i); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 6 * size + i] = (byte)project.Data.GetArchitecture(i); - for (int i = 0; i < size; i++) data[romSettings.Length + romLocation.Length + 7 * size + i] = (byte)project.Data.GetInOutPoint(i); + var readOps = new Func[] + { + i => (byte)project.Data.GetDataBank(i), + i => (byte)project.Data.GetDataBank(i), + i => (byte)project.Data.GetDirectPage(i), + i => (byte)(project.Data.GetDirectPage(i) >> 8), + i => (byte)(project.Data.GetXFlag(i) ? 1 : 0), + i => (byte)(project.Data.GetMFlag(i) ? 1 : 0), + i => (byte)project.Data.GetFlag(i), + i => (byte)project.Data.GetArchitecture(i), + i => (byte)project.Data.GetInOutPoint(i), + }; + + void ReadOperation(int startIdx, int whichOp) + { + if (whichOp <= 0 || whichOp > readOps.Length) + throw new ArgumentOutOfRangeException(nameof(whichOp)); + + var baseidx = startIdx + whichOp * size; + var op = readOps[whichOp]; + for (var i = 0; i < size; i++) + { + data[baseidx + i] = (byte)op(i); + } + } + + for (var i = 0; i < readOps.Length; ++i) + { + var start = romSettings.Length + romLocation.Length; + ReadOperation(start, i); + } + // ??? label.CopyTo(data, romSettings.Length + romLocation.Length + 8 * size); comment.CopyTo(data, romSettings.Length + romLocation.Length + 8 * size + label.Count); @@ -205,10 +226,10 @@ private static void ValidateProjectFileVersion(int version) } } - private void ReadComments(Project project, byte[] bytes, ref int pointer, Util.AddressConverter converter) + private void ReadComments(Project project, byte[] bytes, ref int pointer, ByteUtil.AddressConverter converter) { const int stringsPerEntry = 1; - pointer += Util.ReadStringsTable(bytes, pointer, stringsPerEntry, converter, + pointer += ByteUtil.ReadStringsTable(bytes, pointer, stringsPerEntry, converter, (int offset, string[] strings) => { Debug.Assert(strings.Length == 1); @@ -216,10 +237,10 @@ private void ReadComments(Project project, byte[] bytes, ref int pointer, Util.A }); } - private void ReadLabels(Project project, byte[] bytes, ref int pointer, Util.AddressConverter converter, bool readAliasComments) + private void ReadLabels(Project project, byte[] bytes, ref int pointer, ByteUtil.AddressConverter converter, bool readAliasComments) { var stringsPerEntry = readAliasComments ? 2 : 1; - pointer += Util.ReadStringsTable(bytes, pointer, stringsPerEntry, converter, + pointer += ByteUtil.ReadStringsTable(bytes, pointer, stringsPerEntry, converter, (int offset, string[] strings) => { Debug.Assert(strings.Length == stringsPerEntry); diff --git a/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs b/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs index 19a16d20..c112876a 100644 --- a/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs +++ b/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs @@ -1,11 +1,77 @@ -using System.IO; +using System.Collections; +using System.IO; +using System.Reflection; using System.Text; using System.Xml; +using DiztinGUIsh.core.util; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; +using ExtendedXmlSerializer.ContentModel; +using ExtendedXmlSerializer.ContentModel.Content; +using ExtendedXmlSerializer.ContentModel.Format; +using ExtendedXmlSerializer.Core; +using ExtendedXmlSerializer.ExtensionModel; namespace DiztinGUIsh.loadsave.xml_serializer { + /*internal class ObservableDictionarySerializer : ISerializerExtension + { + public IServiceRepository Get(IServiceRepository parameter) + { + throw new System.NotImplementedException(); + } + + public void Execute(IServices parameter) + { + throw new System.NotImplementedException(); + } + } + + + sealed class Extension : ISerializerExtension + { + public static Extension Default { get; } = new Extension(); + + Extension() { } + + public IServiceRepository Get(IServiceRepository parameter) => parameter.DecorateContentsWith() + .Then(); + + void ICommand.Execute(IServices parameter) { } + + sealed class Contents : IContents + { + readonly IContents _previous; + readonly ISerializer _number; + + public Contents(IContents previous) + : this(previous, new AnswerToEverythingSerializer(previous.Get(typeof(int)).For())) { } + + public Contents(IContents previous, ISerializer number) + { + _previous = previous; + _number = number; + } + + public ISerializer Get(TypeInfo parameter) + => parameter == typeof(int) ? _number.Adapt() : _previous.Get(parameter); + } + + sealed class AnswerToEverythingSerializer : ISerializer + { + readonly ISerializer _previous; + + public AnswerToEverythingSerializer(ISerializer previous) => _previous = previous; + + public int Get(IFormatReader parameter) => _previous.Get(parameter) + 42; + + public void Write(IFormatWriter writer, int instance) + { + _previous.Write(writer, instance + 42); + } + } + }*/ + internal class ProjectXmlSerializer : ProjectSerializer { // NEVER CHANGE THIS ONE. @@ -20,7 +86,10 @@ internal class ProjectXmlSerializer : ProjectSerializer private static IExtendedXmlSerializer GetSerializer() { return new ConfigurationContainer() - .Type().Register().Serializer().Using(RomBytesSerializer.Default) + .Type().Register() + .Serializer().Using(RomBytesSerializer.Default) + //.Type>() + //.Extend(new ObservableDictionarySerializer()) .UseOptimizedNamespaces() .UseAutoFormatting() .EnableImplicitTyping(typeof(Data)) @@ -97,7 +166,6 @@ public override Project Load(byte[] data) var project = root.Project; - project.PostSerializationLoad(); return project; } } diff --git a/DiztinGUIsh/loadsave/xml_serializer/RomBytesXMLSerializer.cs b/DiztinGUIsh/loadsave/xml_serializer/RomBytesXMLSerializer.cs index 193ef5fa..8f2c134c 100644 --- a/DiztinGUIsh/loadsave/xml_serializer/RomBytesXMLSerializer.cs +++ b/DiztinGUIsh/loadsave/xml_serializer/RomBytesXMLSerializer.cs @@ -12,7 +12,7 @@ // // This uses some hacky compression methods designed to preserve: // 1) newlines -// 2) slight human readability for merging +// 2) slight human readability for merging, so projects can be collaborated on in source control // 3) using pattern substitution tables that won't change from PC to PC. // // The easiest thing would be use zlib (and we can use it with the output of the entire XML if we want) diff --git a/DiztinGUIsh/window/AliasList.cs b/DiztinGUIsh/window/AliasList.cs index 96b6c585..f0a979cf 100644 --- a/DiztinGUIsh/window/AliasList.cs +++ b/DiztinGUIsh/window/AliasList.cs @@ -126,7 +126,7 @@ private void export_Click(object sender, EventArgs e) try { using var sw = new StreamWriter(saveFileDialog1.FileName); - foreach (var pair in Data.Labels) + foreach (KeyValuePair pair in Data.Labels) { sw.WriteLine( $"{Util.NumberToBaseString(pair.Key, Util.NumberBase.Hexadecimal, 6)},{pair.Value.name},{pair.Value.comment}"); @@ -295,7 +295,7 @@ private void RepopulateFromData() return; // TODO: replace with winforms databinding eventually - foreach (var item in Data.Labels) + foreach (KeyValuePair item in Data.Labels) { RawAdd(item.Key, item.Value); } diff --git a/DiztinGUIsh/window/GuiUtil.cs b/DiztinGUIsh/window/GuiUtil.cs new file mode 100644 index 00000000..229ea84c --- /dev/null +++ b/DiztinGUIsh/window/GuiUtil.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace DiztinGUIsh.window +{ + public static class GuiUtil + { + public static void InvokeIfRequired(this ISynchronizeInvoke obj, MethodInvoker action) + { + if (obj.InvokeRequired) + { + var args = new object[0]; + obj.Invoke(action, args); + } + else + { + action(); + } + } + + public static string PromptToSelectFile(string initialDirectory = null) + { + var open = new OpenFileDialog { InitialDirectory = initialDirectory }; + return open.ShowDialog() == DialogResult.OK ? open.FileName : null; + } + + public static string AskIfWeShouldSelectFilename(string promptSubject, string promptText, Func confirmAction) + { + var dialogResult = MessageBox.Show(promptText, promptSubject, + MessageBoxButtons.YesNo, MessageBoxIcon.Error); + + return dialogResult == DialogResult.Yes ? confirmAction() : null; + } + + public static string GetDescription(this Enum value) + { + var valueStr = value.ToString(); + var field = value.GetType().GetField(valueStr); + var attribs = field.GetCustomAttributes(typeof(DescriptionAttribute), true); + return attribs.Length > 0 ? ((DescriptionAttribute)attribs[0]).Description : valueStr; + } + } +} diff --git a/DiztinGUIsh/window/IProjectView.cs b/DiztinGUIsh/window/IProjectView.cs index 63daac17..edc66609 100644 --- a/DiztinGUIsh/window/IProjectView.cs +++ b/DiztinGUIsh/window/IProjectView.cs @@ -12,5 +12,6 @@ public interface IProjectView public delegate void LongRunningTaskHandler(Action task, string description = null); LongRunningTaskHandler TaskHandler { get; } void SelectOffset(int offset, int column=-1); + string AskToSelectNewRomFilename(string promptSubject, string promptText); } } diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 6287e74b..5d4b8548 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -5,7 +5,9 @@ using System.Globalization; using System.IO; using System.Windows.Forms; +using DiztinGUIsh.core.util; using DiztinGUIsh.Properties; +using DiztinGUIsh.window.dialog; namespace DiztinGUIsh { @@ -101,8 +103,16 @@ private void MainWindow_Load(object sender, EventArgs e) private void openLastProject() { - if (Settings.Default.LastOpenedFile != "") - OpenProject(Settings.Default.LastOpenedFile); + if (LastProjectFilename == "") + return; + + // safeguard: if we crash opening this project, + // then next time we load make sure we don't try it again. + // this will be reset later + var projectToOpen = LastProjectFilename; + LastProjectFilename = ""; + + OpenProject(projectToOpen); } public void UpdateWindowTitle() @@ -149,29 +159,34 @@ private void newProjectToolStripMenuItem_Click(object sender, EventArgs e) private string PromptForOpenFilename() { // TODO: combine with another function in Project that looks like this - openFileDialog.InitialDirectory = Project.ProjectFileName; - return openFileDialog.ShowDialog() != DialogResult.OK ? openFileDialog.FileName : null; + openFileDialog.InitialDirectory = Project?.ProjectFileName ?? ""; + return openFileDialog.ShowDialog() == DialogResult.OK ? openFileDialog.FileName : null; } private bool TryImportProject(string romFileToOpen) { try { - var importSettings = new ImportROMDialog().PromptForImportSettings(romFileToOpen); + var importSettings = PromptForImportSettings(romFileToOpen); if (importSettings == null) return false; - ProjectController.ImportRomAndCreateNewProject(importSettings.Value); + ProjectController.ImportRomAndCreateNewProject(importSettings); return true; } catch (Exception ex) { - MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show(ex.Message, "Error importing project", MessageBoxButtons.OK, MessageBoxIcon.Error); } return false; } + private static Project.ImportRomSettings PromptForImportSettings(string romFileToOpen) + { + return new ImportRomDialog().PromptForImportSettings(romFileToOpen); + } + private void openProjectToolStripMenuItem_Click(object sender, EventArgs e) { if (!ContinueUnsavedChanges()) @@ -210,9 +225,10 @@ private void UpdateUIFromSettings() public void OnProjectOpened(string filename) { - LastProjectFilename = filename; UpdateSaveOptionStates(true, true); RefreshUI(); + + LastProjectFilename = filename; // do this last. } private void OnImportedProjectSuccess() @@ -419,7 +435,7 @@ public void InvalidateTable() private int ViewOffset { - get => Project.CurrentViewOffset; + get => Project?.CurrentViewOffset ?? 0; set => Project.CurrentViewOffset = value; } @@ -588,7 +604,7 @@ private void table_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e.Value = Util.NumberToBaseString(Project.Data.GetROMByte(row), DisplayBase); break; case 4: - e.Value = Util.PointToString(Project.Data.GetInOutPoint(row)); + e.Value = RomUtil.PointToString(Project.Data.GetInOutPoint(row)); break; case 5: int len = Project.Data.GetInstructionLength(row); @@ -601,7 +617,7 @@ private void table_CellValueNeeded(object sender, DataGridViewCellValueEventArgs else e.Value = ""; break; case 7: - e.Value = Util.TypeToString(Project.Data.GetFlag(row)); + e.Value = RomUtil.TypeToString(Project.Data.GetFlag(row)); break; case 8: e.Value = Util.NumberToBaseString(Project.Data.GetDataBank(row), Util.NumberBase.Hexadecimal, 2); @@ -610,10 +626,10 @@ private void table_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e.Value = Util.NumberToBaseString(Project.Data.GetDirectPage(row), Util.NumberBase.Hexadecimal, 4); break; case 10: - e.Value = Util.BoolToSize(Project.Data.GetMFlag(row)); + e.Value = RomUtil.BoolToSize(Project.Data.GetMFlag(row)); break; case 11: - e.Value = Util.BoolToSize(Project.Data.GetXFlag(row)); + e.Value = RomUtil.BoolToSize(Project.Data.GetXFlag(row)); break; case 12: e.Value = Project.Data.GetComment(Project.Data.ConvertPCtoSNES(row)); @@ -817,7 +833,7 @@ private void AutoStepHarsh(int offset) private void Mark(int offset) { ProjectController.MarkChanged(); - SelectOffset(Project.Data.Mark(offset, markFlag, Util.TypeStepSize(markFlag))); + SelectOffset(Project.Data.Mark(offset, markFlag, RomUtil.TypeStepSize(markFlag))); UpdatePercent(); UpdateWindowTitle(); } @@ -1216,5 +1232,12 @@ private void toolStripOpenLast_Click(object sender, EventArgs e) { openLastProject(); } + + public string AskToSelectNewRomFilename(string promptSubject, string promptText) + { + return GuiUtil.AskIfWeShouldSelectFilename(promptSubject, promptText, + () => GuiUtil.PromptToSelectFile(Project.ProjectFileName) + ); + } } } \ No newline at end of file diff --git a/DiztinGUIsh/window/ProjectController.cs b/DiztinGUIsh/window/ProjectController.cs index 55e59075..9571a7ee 100644 --- a/DiztinGUIsh/window/ProjectController.cs +++ b/DiztinGUIsh/window/ProjectController.cs @@ -30,20 +30,17 @@ public enum ProjectChangedType { public void DoLongRunningTask(Action task, string description = null) { if (ProjectView.TaskHandler != null) - { ProjectView.TaskHandler(task, description); - } else - { task(); - } } public bool OpenProject(string filename) { Project project = null; + DoLongRunningTask(delegate { - project = ProjectFileManager.Open(filename); + project = ProjectFileManager.Open(filename, AskToSelectNewRomFilename); }, $"Opening {Path.GetFileName(filename)}..."); if (project == null) @@ -52,11 +49,11 @@ public bool OpenProject(string filename) return false; } - OnProjectOpened(filename, project); + OnProjectOpenSuccess(filename, project); return true; } - private void OnProjectOpened(string filename, Project project) + private void OnProjectOpenSuccess(string filename, Project project) { ProjectView.Project = Project = project; Project.PropertyChanged += Project_PropertyChanged; @@ -95,45 +92,15 @@ public void ImportBizHawkCDL(string filename) }); } - public void ImportRomAndCreateNewProject(in Project.ImportRomSettings importSettings) + public void ImportRomAndCreateNewProject(Project.ImportRomSettings importSettings) { - var project = new Project - { - AttachedRomFilename = importSettings.rom_filename, - UnsavedChanges = false, - ProjectFileName = null, - Data = new Data() - }; - - // TODO: seems like we probably should pick a place for the Project reference to live. - // either here in this class, or out in the view. - // right now we're passing around our class's Project and ProjectView's project. - - project.Data.Initiate(importSettings.rom_bytes, importSettings.ROMMapMode, importSettings.ROMSpeed); - - // TODO: get this UI out of here. probably just use databinding instead - // AliasList.me.ResetDataGrid(); - - if (importSettings.InitialLabels.Count > 0) - { - foreach (var pair in importSettings.InitialLabels) - project.Data.AddLabel(pair.Key, pair.Value, true); - project.UnsavedChanges = true; - } - - if (importSettings.InitialHeaderFlags.Count > 0) - { - foreach (var pair in importSettings.InitialHeaderFlags) - project.Data.SetFlag(pair.Key, pair.Value); - project.UnsavedChanges = true; - } + var project = ProjectFileManager.ImportRomAndCreateNewProject(importSettings); + OnProjectOpenSuccess(project.ProjectFileName, project); + } - // Save a copy of these identifying ROM bytes with the project file itself. - // When we reload, we will make sure the linked ROM still matches them. - project.InternalCheckSum = project.Data.GetRomCheckSumsFromRomBytes(); - project.InternalRomGameName = project.Data.GetRomNameFromRomBytes(); - - OnProjectOpened(project.ProjectFileName, project); + private string AskToSelectNewRomFilename(string error) + { + return ProjectView.AskToSelectNewRomFilename("Error", $"{error} Link a new ROM now?"); } public void WriteAssemblyOutput() diff --git a/DiztinGUIsh/window/dialog/GotoDialog.cs b/DiztinGUIsh/window/dialog/GotoDialog.cs index 16b565be..fa69b269 100644 --- a/DiztinGUIsh/window/dialog/GotoDialog.cs +++ b/DiztinGUIsh/window/dialog/GotoDialog.cs @@ -8,6 +8,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using DiztinGUIsh.core.util; namespace DiztinGUIsh { @@ -57,7 +58,7 @@ private bool UpdateTextChanged(string txtChanged, Action= 0) + if (ByteUtil.StripFormattedAddress(ref txtChanged, style, out var address) && address >= 0) { onSuccess(txtChanged, address, noBase); result = true; diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs b/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs index 5ea99597..b473884f 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs @@ -1,6 +1,6 @@ -namespace DiztinGUIsh +namespace DiztinGUIsh.window.dialog { - partial class ImportROMDialog + partial class ImportRomDialog { /// /// Required designer variable. @@ -28,9 +28,10 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.detectMessage = new System.Windows.Forms.Label(); this.checkData = new System.Windows.Forms.Label(); - this.comboBox1 = new System.Windows.Forms.ComboBox(); + this.cmbRomMapMode = new System.Windows.Forms.ComboBox(); this.mapmode = new System.Windows.Forms.Label(); this.label4 = new System.Windows.Forms.Label(); this.label5 = new System.Windows.Forms.Label(); @@ -76,8 +77,10 @@ private void InitializeComponent() this.label2 = new System.Windows.Forms.Label(); this.label1 = new System.Windows.Forms.Label(); this.checkHeader = new System.Windows.Forms.CheckBox(); + this.importRomSettingsBindingSource = new System.Windows.Forms.BindingSource(this.components); this.groupBox1.SuspendLayout(); this.groupBox2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.importRomSettingsBindingSource)).BeginInit(); this.SuspendLayout(); // // detectMessage @@ -100,23 +103,20 @@ private void InitializeComponent() this.checkData.Text = "Does the following info look correct?"; this.checkData.TextAlign = System.Drawing.ContentAlignment.TopCenter; // - // comboBox1 - // - this.comboBox1.FormattingEnabled = true; - this.comboBox1.Items.AddRange(new object[] { - "(0) LoROM", - "(1) HiROM", - "(2) Super MMC", - "(3) SA-1 ROM", - "(3) SA-1 ROM (FuSoYa\'s 8MB mapper)", - "(4) SuperFX", - "(5) ExHiROM", - "(6) ExLoROM"}); - this.comboBox1.Location = new System.Drawing.Point(103, 18); - this.comboBox1.Name = "comboBox1"; - this.comboBox1.Size = new System.Drawing.Size(121, 21); - this.comboBox1.TabIndex = 1; - this.comboBox1.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged); + // cmbRomMapMode + // + this.cmbRomMapMode.DataBindings.Add(new System.Windows.Forms.Binding("SelectedItem", this.importRomSettingsBindingSource, "ROMMapMode", true)); + this.cmbRomMapMode.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.importRomSettingsBindingSource, "ROMMapMode", true)); + this.cmbRomMapMode.DataSource = this.importRomSettingsBindingSource; + this.cmbRomMapMode.FormattingEnabled = true; + this.cmbRomMapMode.Location = new System.Drawing.Point(103, 18); + this.cmbRomMapMode.Name = "cmbRomMapMode"; + this.cmbRomMapMode.Size = new System.Drawing.Size(121, 21); + this.cmbRomMapMode.TabIndex = 1; + this.cmbRomMapMode.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged); + this.cmbRomMapMode.DropDownClosed += new System.EventHandler(this.comboBox1_DropDownClosed); + this.cmbRomMapMode.TextChanged += new System.EventHandler(this.comboBox1_TextChanged); + this.cmbRomMapMode.Validating += new System.ComponentModel.CancelEventHandler(this.comboBox1_Validating); // // mapmode // @@ -208,7 +208,7 @@ private void InitializeComponent() // groupBox1 // this.groupBox1.Controls.Add(this.mapmode); - this.groupBox1.Controls.Add(this.comboBox1); + this.groupBox1.Controls.Add(this.cmbRomMapMode); this.groupBox1.Controls.Add(this.label4); this.groupBox1.Controls.Add(this.romtitle); this.groupBox1.Controls.Add(this.label5); @@ -606,7 +606,12 @@ private void InitializeComponent() this.checkHeader.Text = "Auto generate flags for Internal ROM Header"; this.checkHeader.UseVisualStyleBackColor = true; // - // ImportROMDialog + // importRomSettingsBindingSource + // + this.importRomSettingsBindingSource.DataSource = typeof(DiztinGUIsh.Project.ImportRomSettings); + this.importRomSettingsBindingSource.CurrentChanged += new System.EventHandler(this.importRomSettingsBindingSource_CurrentChanged); + // + // ImportRomDialog // this.AcceptButton = this.okay; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -623,7 +628,7 @@ private void InitializeComponent() this.Controls.Add(this.checkData); this.Controls.Add(this.detectMessage); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; - this.Name = "ImportROMDialog"; + this.Name = "ImportRomDialog"; this.ShowIcon = false; this.ShowInTaskbar = false; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; @@ -633,6 +638,7 @@ private void InitializeComponent() this.groupBox1.PerformLayout(); this.groupBox2.ResumeLayout(false); this.groupBox2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.importRomSettingsBindingSource)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -642,7 +648,7 @@ private void InitializeComponent() private System.Windows.Forms.Label detectMessage; private System.Windows.Forms.Label checkData; - private System.Windows.Forms.ComboBox comboBox1; + private System.Windows.Forms.ComboBox cmbRomMapMode; private System.Windows.Forms.Label mapmode; private System.Windows.Forms.Label label4; private System.Windows.Forms.Label label5; @@ -688,5 +694,6 @@ private void InitializeComponent() private System.Windows.Forms.Label label2; private System.Windows.Forms.Label label1; private System.Windows.Forms.CheckBox checkHeader; + private System.Windows.Forms.BindingSource importRomSettingsBindingSource; } } \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.cs b/DiztinGUIsh/window/dialog/ImportROMDialog.cs index 128f1123..e09b6b37 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.cs @@ -1,63 +1,172 @@ using System; using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; +using DiztinGUIsh.core.util; -namespace DiztinGUIsh +namespace DiztinGUIsh.window.dialog { - public partial class ImportROMDialog : Form + public partial class ImportRomDialog : Form { - private Project.ImportRomSettings importSettings; - private bool couldnt_detect_rom_type; + public Project.ImportRomSettings ImportSettings { get; protected set; } + public bool romTypeNotDetectedCorrectly = true; - private string title; - private int offset; - private string[,] vectorNames = new string[2, 6] - { + public string title; + public int RomSettingsOffset; + private readonly string[,] vectorNames = { { "Native_COP", "Native_BRK", "Native_ABORT", "Native_NMI", "Native_RESET", "Native_IRQ"}, { "Emulation_COP", "Emulation_Unknown", "Emulation_ABORT", "Emulation_NMI", "Emulation_RESET", "Emulation_IRQBRK"} }; - private TextBox[,] vectors; - private CheckBox[,] checkboxes; + private readonly TextBox[,] vectors; + private readonly CheckBox[,] checkboxes; - public Project.ImportRomSettings? PromptForImportSettings(string filename) + public ImportRomDialog() { - importSettings = new Project.ImportRomSettings + InitializeComponent(); + vectors = new[,] + { + { textNativeCOP, textNativeBRK, textNativeABORT, textNativeNMI, textNativeRESET, textNativeIRQ }, + { textEmuCOP, textEmuBRK, textEmuABORT, textEmuNMI, textEmuRESET, textEmuIRQ }, + }; + checkboxes = new[,] { - rom_filename = filename, - rom_bytes = Util.ReadAllRomBytesFromFile(filename), - ROMMapMode = Util.DetectROMMapMode(importSettings.rom_bytes, out couldnt_detect_rom_type) + { checkboxNativeCOP, checkboxNativeBRK, checkboxNativeABORT, checkboxNativeNMI, checkboxNativeRESET, checkboxNativeIRQ }, + { checkboxEmuCOP, checkboxEmuBRK, checkboxEmuABORT, checkboxEmuNMI, checkboxEmuRESET, checkboxEmuIRQ }, }; + } + + public Project.ImportRomSettings PromptForImportSettings(string filename) + { + CreateRomImportSettingsFor(filename); + + DataBind(); - UpdateUIFromRomMapDetection(); + // UpdateUiFromRomMapDetection(); UpdateOffsetAndSpeed(); if (ShowDialog() != DialogResult.OK) return null; - importSettings.InitialLabels = GetGeneratedLabels(); - importSettings.InitialHeaderFlags = GetHeaderFlags(); + ImportSettings.InitialLabels = GetGeneratedLabels(); + ImportSettings.InitialHeaderFlags = GetHeaderFlags(); - return importSettings; + return ImportSettings; } - public ImportROMDialog() + private void DataBind() { - InitializeComponent(); - vectors = new TextBox[2, 6] + // common for everything on the page + /*importRomSettingsBindingSource.DataSource = ImportSettings; + + // specific to this combo. datasource is a static list of enum values + var dataSource = Util.GetEnumDescriptions(); + cmbRomMapMode.DataSource = new BindingSource(dataSource, null); + cmbRomMapMode.ValueMember = "Key"; // names of properties of each item on datasource. + cmbRomMapMode.DisplayMember = "Value"; + + // bind comboboxes "SelectedIndex" property to store its value in settings.ROMMapMode + cmbRomMapMode.DataBindings.Add(new Binding("SelectedIndex", ImportSettings, "ROMMapMode", false, DataSourceUpdateMode.OnPropertyChanged)); + */ + + importRomSettingsBindingSource.DataSource = ImportSettings; + + // specific to this combo. datasource is a static list of enum values + var dataSource = Util.GetEnumDescriptions(); + cmbRomMapMode.DataSource = new BindingSource(dataSource, null); + cmbRomMapMode.ValueMember = "Key"; // names of properties of each item on datasource. + cmbRomMapMode.DisplayMember = "Value"; + + // bind comboboxes "SelectedIndex" property to store its value in settings.ROMMapMode + cmbRomMapMode.DataBindings.Add(new Binding("SelectedIndex", ImportSettings, "ROMMapMode", false, DataSourceUpdateMode.OnPropertyChanged)); + + /* + var dataSource = Util.GetEnumDescriptions(); + + var bs = new BindingSource(dataSource, null); + comboBox1.DataSource = bs; + comboBox1.ValueMember = "Key"; + comboBox1.DisplayMember = "Value"; + + comboBox1.DataBindings.Add(new Binding("SelectedIndex", ImportSettings, "ROMMapMode", false, DataSourceUpdateMode.OnPropertyChanged)); + + bs.CurrentChanged += Bs_CurrentChanged; + bs.CurrentItemChanged += Bs_CurrentItemChanged;*/ + + // Call ResetBindings after manual update to update the textboxes. + // bindingSource1.ResetBindings(false); + + + //LoadEnumToCombo(comboBox1); + // comboBox1.DataSource = Enum.GetValues(typeof(Data.ROMMapMode)); + // comboBox1.DataBindings.Add(new Binding("SelectedValue", ImportSettings.ROMMapMode, "StoreObjectROMMapMode")); + + //comboBox1.DataBindings.Add( + // new Binding("SelectedIndex", ImportSettings, "ROMMapMode")); + + //rOMMapModeBindingSource.DataSource = Enum.GetValues(typeof(Data.ROMMapMode)); + //importRomSettingsBindingSource.DataSource = ImportSettings.ROMMapMode; + + // rOMMapModeBindingSource.DataSource = comboBox1DataSource; + // importRomSettingsBindingSource + // importRomSettingsBindingSource = new BindingSource(ImportSettings.ROMMapMode); + } + + + private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) + { + // ImportSettings.ROMMapMode = SelectRomMapModeFromUi(comboBox1.SelectedIndex); + UpdateUI(); + } + + private void UpdateUI() + { + UpdateOffsetAndSpeed(); + UpdateTextboxes(); + } + + void UpdateFromDatabinding(IBindableComponent sender) + { + // ValidateChildren(); + //Validate(true); + + // this seems to work the best to get the values flushed out in realtime + foreach (var i in sender.DataBindings) { - { textNativeCOP, textNativeBRK, textNativeABORT, textNativeNMI, textNativeRESET, textNativeIRQ }, - { textEmuCOP, textEmuBRK, textEmuABORT, textEmuNMI, textEmuRESET, textEmuIRQ }, - }; - checkboxes = new CheckBox[2, 6] + var q = i as Binding; + // flushes the cached value back out to the real data structure + q.WriteValue(); + } + } + + private void importRomSettingsBindingSource_CurrentChanged(object sender, EventArgs e) + { + int x = 3; + UpdateUI(); + } + + private void comboBox1_DropDownClosed(object sender, EventArgs e) + { + int x = 3; + } + + private void comboBox1_Validating(object sender, System.ComponentModel.CancelEventArgs e) + { + int x = 3; + } + + private void comboBox1_TextChanged(object sender, EventArgs e) + { ; + //Validate(true); + UpdateFromDatabinding(sender as IBindableComponent); + } + + private void CreateRomImportSettingsFor(string filename) + { + var romBytes = RomUtil.ReadAllRomBytesFromFile(filename); + ImportSettings = new Project.ImportRomSettings { - { checkboxNativeCOP, checkboxNativeBRK, checkboxNativeABORT, checkboxNativeNMI, checkboxNativeRESET, checkboxNativeIRQ }, - { checkboxEmuCOP, checkboxEmuBRK, checkboxEmuABORT, checkboxEmuNMI, checkboxEmuRESET, checkboxEmuIRQ }, + RomFilename = filename, + RomBytes = romBytes, + ROMMapMode = RomUtil.DetectROMMapMode(romBytes, out romTypeNotDetectedCorrectly) }; } @@ -72,10 +181,10 @@ private Dictionary GetGeneratedLabels() if (!checkboxes[i, j].Checked) continue; - int index = offset + 15 + 0x10 * i + 2 * j; - int val = importSettings.rom_bytes[index] + (importSettings.rom_bytes[index + 1] << 8); - int pc = Util.ConvertSNESToPC(val, importSettings.ROMMapMode, importSettings.rom_bytes.Length); - if (pc >= 0 && pc < importSettings.rom_bytes.Length && !labels.ContainsKey(val)) + int index = RomSettingsOffset + 15 + 0x10 * i + 2 * j; + int val = ImportSettings.RomBytes[index] + (ImportSettings.RomBytes[index + 1] << 8); + int pc = RomUtil.ConvertSNESToPC(val, ImportSettings.ROMMapMode, ImportSettings.RomBytes.Length); + if (pc >= 0 && pc < ImportSettings.RomBytes.Length && !labels.ContainsKey(val)) labels.Add(val, new Label() {name = vectorNames[i, j]}); } } @@ -87,39 +196,132 @@ private Dictionary GetGeneratedLabels() { var flags = new Dictionary(); - if (checkHeader.Checked) - { - for (int i = 0; i < 0x15; i++) flags.Add(offset - 0x15 + i, Data.FlagType.Text); - for (int i = 0; i < 7; i++) flags.Add(offset + i, Data.FlagType.Data8Bit); - for (int i = 0; i < 4; i++) flags.Add(offset + 7 + i, Data.FlagType.Data16Bit); - for (int i = 0; i < 0x20; i++) flags.Add(offset + 11 + i, Data.FlagType.Pointer16Bit); + if (checkHeader.Checked) + RomUtil.GetHeaderFlags(RomSettingsOffset, flags, ImportSettings.RomBytes); + + return flags; + } + + private void UpdateOffsetAndSpeed() + { + RomSettingsOffset = RomUtil.GetRomSettingOffset(ImportSettings.ROMMapMode); + var romSpeed = ImportSettings.ROMSpeed; + var romBytes = ImportSettings.RomBytes; + + romSpeed = RomUtil.GetRomSpeed(RomSettingsOffset, romBytes); + + okay.Enabled = ImportSettings.ROMSpeed != Data.ROMSpeed.Unknown; + } - if (importSettings.rom_bytes[offset - 1] == 0) + private bool IsOffsetInRange(int offset, int count = 0) + { + return offset > 0 && offset <= ImportSettings.RomBytes.Length; + } + + private void UpdateTextboxes() + { + if (IsProbablyValidDetection()) + { + try { + UpdateDetectedValues(); + return; + } + catch (Exception) { - flags.Remove(offset - 1); - flags.Add(offset - 1, Data.FlagType.Data8Bit); - for (int i = 0; i < 0x10; i++) flags.Add(offset - 0x25 + i, Data.FlagType.Data8Bit); + // ignored } - else if (importSettings.rom_bytes[offset + 5] == 0x33) + } + + SetDefaultsIfDetectionFailed(); + } + + private bool IsProbablyValidDetection() + { + return + ImportSettings.ROMSpeed != Data.ROMSpeed.Unknown && + IsOffsetInRange(RomSettingsOffset); + } + + private void SetDefaultsIfDetectionFailed() + { + romspeed.Text = "????"; + romtitle.Text = "?????????????????????"; + for (int i = 0; i < vectors.GetLength(0); i++) + for (int j = 0; j < vectors.GetLength(1); j++) + vectors[i, j].Text = "????"; + return; + } + + private void UpdateDetectedValues() + { + // caution: things can go wrong here if we didn't guess settings correctly, + // you usually want to call this function with a try/catch around it. + + var romspeedStr = ImportSettings.ROMSpeed == Data.ROMSpeed.SlowROM ? "SlowROM" : "FastROM"; + var romTitleName = RomUtil.GetRomTitleName(ImportSettings.RomBytes, RomSettingsOffset); + + for (int i = 0; i < vectors.GetLength(0); i++) + { + for (int j = 0; j < vectors.GetLength(1); j++) { - for (int i = 0; i < 6; i++) flags.Add(offset - 0x25 + i, Data.FlagType.Text); - for (int i = 0; i < 10; i++) flags.Add(offset - 0x1F + i, Data.FlagType.Data8Bit); + int index = RomSettingsOffset + 15 + 0x10 * i + 2 * j; + int val = ImportSettings.RomBytes[index] + (ImportSettings.RomBytes[index + 1] << 8); + vectors[i, j].Text = Util.NumberToBaseString(val, Util.NumberBase.Hexadecimal, 4); + + if (val < 0x8000) + { + checkboxes[i, j].Checked = false; + checkboxes[i, j].Enabled = false; + } + else + { + checkboxes[i, j].Enabled = true; + } } } - return flags; + romspeed.Text = romspeedStr; + romtitle.Text = romTitleName; + } + + private void ImportROMDialog_Load(object sender, EventArgs e) + { + UpdateTextboxes(); + } + + private void okay_Click(object sender, EventArgs e) { DialogResult = DialogResult.OK; } + + private void cancel_Click(object sender, EventArgs e) { Close(); } + + + /*private Data.ROMMapMode SelectRomMapModeFromUi(int selectedIndex) + { + // TODO: there's definitely a better way. Databinding, or use a dict at worst. + var mode = selectedIndex switch + { + 0 => Data.ROMMapMode.LoROM, + 1 => Data.ROMMapMode.HiROM, + 2 => Data.ROMMapMode.SuperMMC, + 3 => Data.ROMMapMode.SA1ROM, + 4 => Data.ROMMapMode.ExSA1ROM, + 5 => Data.ROMMapMode.SuperFX, + 6 => Data.ROMMapMode.ExHiROM, + 7 => Data.ROMMapMode.ExLoROM, + _ => ImportSettings.ROMMapMode + }; + return mode; } - private void UpdateUIFromRomMapDetection() + private void UpdateUiFromRomMapDetection() { - if (couldnt_detect_rom_type) + if (romTypeNotDetectedCorrectly) detectMessage.Text = "Couldn't auto detect ROM Map Mode!"; else - detectMessage.Text = "ROM Map Mode Detected: " + Util.GetRomMapModeName(importSettings.ROMMapMode); + detectMessage.Text = "ROM Map Mode Detected: " + RomUtil.GetRomMapModeName(ImportSettings.ROMMapMode); // TODO: there's definitely a better way. probably have the control read from a data table, // then have it update itself based on the value of importSettings.ROMMapMode. - switch (importSettings.ROMMapMode) + switch (ImportSettings.ROMMapMode) { case Data.ROMMapMode.LoROM: comboBox1.SelectedIndex = 0; @@ -127,8 +329,8 @@ private void UpdateUIFromRomMapDetection() case Data.ROMMapMode.HiROM: comboBox1.SelectedIndex = 1; break; - case Data.ROMMapMode.ExHiROM: - comboBox1.SelectedIndex = 6; + case Data.ROMMapMode.SuperMMC: + comboBox1.SelectedIndex = 2; break; case Data.ROMMapMode.SA1ROM: comboBox1.SelectedIndex = 3; @@ -139,99 +341,13 @@ private void UpdateUIFromRomMapDetection() case Data.ROMMapMode.SuperFX: comboBox1.SelectedIndex = 5; break; - case Data.ROMMapMode.SuperMMC: - comboBox1.SelectedIndex = 2; + case Data.ROMMapMode.ExHiROM: + comboBox1.SelectedIndex = 6; break; case Data.ROMMapMode.ExLoROM: comboBox1.SelectedIndex = 7; break; - default: - break; } - } - - private void UpdateOffsetAndSpeed() - { - offset = Util.GetRomSettingOffset(importSettings.ROMMapMode); - if (offset >= importSettings.rom_bytes.Length) - { - importSettings.ROMSpeed = Data.ROMSpeed.Unknown; - okay.Enabled = false; - } else - { - okay.Enabled = true; - importSettings.ROMSpeed = (importSettings.rom_bytes[offset] & 0x10) != 0 ? Data.ROMSpeed.FastROM : Data.ROMSpeed.SlowROM; - } - } - - private void UpdateTextboxes() - { - if (importSettings.ROMSpeed == Data.ROMSpeed.Unknown) - { - romspeed.Text = "????"; - romtitle.Text = "?????????????????????"; - for (int i = 0; i < vectors.GetLength(0); i++) for (int j = 0; j < vectors.GetLength(1); j++) vectors[i, j].Text = "????"; - } else - { - if (importSettings.ROMSpeed == Data.ROMSpeed.SlowROM) romspeed.Text = "SlowROM"; - else romspeed.Text = "FastROM"; - - title = ""; - for (int i = 0; i < 0x15; i++) title += (char)importSettings.rom_bytes[offset - 0x15 + i]; - romtitle.Text = title; - - for (int i = 0; i < vectors.GetLength(0); i++) - { - for (int j = 0; j < vectors.GetLength(1); j++) - { - int index = offset + 15 + 0x10 * i + 2 * j; - int val = importSettings.rom_bytes[index] + (importSettings.rom_bytes[index + 1] << 8); - vectors[i, j].Text = Util.NumberToBaseString(val, Util.NumberBase.Hexadecimal, 4); - - if (val < 0x8000) - { - checkboxes[i, j].Checked = false; - checkboxes[i, j].Enabled = false; - } else - { - checkboxes[i, j].Enabled = true; - } - } - } - } - } - - private void ImportROMDialog_Load(object sender, EventArgs e) - { - UpdateTextboxes(); - } - - private void okay_Click(object sender, EventArgs e) - { - this.DialogResult = DialogResult.OK; - } - - private void cancel_Click(object sender, EventArgs e) - { - this.Close(); - } - - private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) - { - // TODO: there's definitely a better way, we'll get to it :) - switch (comboBox1.SelectedIndex) - { - case 0: importSettings.ROMMapMode = Data.ROMMapMode.LoROM; break; - case 1: importSettings.ROMMapMode = Data.ROMMapMode.HiROM; break; - case 2: importSettings.ROMMapMode = Data.ROMMapMode.SuperMMC; break; - case 3: importSettings.ROMMapMode = Data.ROMMapMode.SA1ROM; break; - case 4: importSettings.ROMMapMode = Data.ROMMapMode.ExSA1ROM; break; - case 5: importSettings.ROMMapMode = Data.ROMMapMode.SuperFX; break; - case 6: importSettings.ROMMapMode = Data.ROMMapMode.ExHiROM; break; - case 7: importSettings.ROMMapMode = Data.ROMMapMode.ExLoROM; break; - } - UpdateOffsetAndSpeed(); - UpdateTextboxes(); - } + }*/ } } diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.resx b/DiztinGUIsh/window/dialog/ImportROMDialog.resx index 1af7de15..248a70dc 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.resx +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.resx @@ -117,4 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/MisalignmentChecker.cs b/DiztinGUIsh/window/dialog/MisalignmentChecker.cs index dcc1c43d..735dcc19 100644 --- a/DiztinGUIsh/window/dialog/MisalignmentChecker.cs +++ b/DiztinGUIsh/window/dialog/MisalignmentChecker.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using DiztinGUIsh.core.util; namespace DiztinGUIsh { @@ -32,7 +33,7 @@ private void buttonScan_Click(object sender, EventArgs e) while (found < 500 && offset < Data.GetROMSize()) { Data.FlagType flag = Data.GetFlag(offset), check = flag == Data.FlagType.Opcode ? Data.FlagType.Operand : flag; - int step = flag == Data.FlagType.Opcode ? Data.GetInstructionLength(offset) : Util.TypeStepSize(flag); + int step = flag == Data.FlagType.Opcode ? Data.GetInstructionLength(offset) : RomUtil.TypeStepSize(flag); if (flag == Data.FlagType.Operand) { @@ -50,8 +51,8 @@ private void buttonScan_Click(object sender, EventArgs e) textLog.Text += string.Format("{0} (0x{1}): {2} is not {3}\r\n", Util.NumberToBaseString(Data.ConvertPCtoSNES(offset + i), Util.NumberBase.Hexadecimal, 6, true), Util.NumberToBaseString(offset + i, Util.NumberBase.Hexadecimal, 0), - Util.TypeToString(Data.GetFlag(offset + i)), - Util.TypeToString(check)); + RomUtil.TypeToString(Data.GetFlag(offset + i)), + RomUtil.TypeToString(check)); } } } diff --git a/DiztinGUIsh/window/dialog/TestForm.Designer.cs b/DiztinGUIsh/window/dialog/TestForm.Designer.cs new file mode 100644 index 00000000..e2fef50e --- /dev/null +++ b/DiztinGUIsh/window/dialog/TestForm.Designer.cs @@ -0,0 +1,119 @@ +namespace DiztinGUIsh.window.dialog +{ + partial class TestForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.Windows.Forms.Label rOMMapModeLabel; + System.Windows.Forms.Label rOMMapModeLabel1; + this.project_ImportRomSettingsBindingSource = new System.Windows.Forms.BindingSource(this.components); + this.rOMMapModeComboBox = new System.Windows.Forms.ComboBox(); + this.button1 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); + rOMMapModeLabel = new System.Windows.Forms.Label(); + rOMMapModeLabel1 = new System.Windows.Forms.Label(); + ((System.ComponentModel.ISupportInitialize)(this.project_ImportRomSettingsBindingSource)).BeginInit(); + this.SuspendLayout(); + // + // rOMMapModeLabel + // + rOMMapModeLabel.AutoSize = true; + rOMMapModeLabel.Location = new System.Drawing.Point(129, 149); + rOMMapModeLabel.Name = "rOMMapModeLabel"; + rOMMapModeLabel.Size = new System.Drawing.Size(86, 13); + rOMMapModeLabel.TabIndex = 1; + rOMMapModeLabel.Text = "ROMMap Mode:"; + // + // rOMMapModeLabel1 + // + rOMMapModeLabel1.AutoSize = true; + rOMMapModeLabel1.Location = new System.Drawing.Point(241, 150); + rOMMapModeLabel1.Name = "rOMMapModeLabel1"; + rOMMapModeLabel1.Size = new System.Drawing.Size(86, 13); + rOMMapModeLabel1.TabIndex = 1; + rOMMapModeLabel1.Text = "ROMMap Mode:"; + // + // project_ImportRomSettingsBindingSource + // + this.project_ImportRomSettingsBindingSource.DataSource = typeof(DiztinGUIsh.Project.ImportRomSettings); + // + // rOMMapModeComboBox + // + this.rOMMapModeComboBox.DataBindings.Add(new System.Windows.Forms.Binding("SelectedValue", this.project_ImportRomSettingsBindingSource, "ROMMapMode", true)); + this.rOMMapModeComboBox.FormattingEnabled = true; + this.rOMMapModeComboBox.Location = new System.Drawing.Point(333, 147); + this.rOMMapModeComboBox.Name = "rOMMapModeComboBox"; + this.rOMMapModeComboBox.Size = new System.Drawing.Size(121, 21); + this.rOMMapModeComboBox.TabIndex = 2; + this.rOMMapModeComboBox.SelectedIndexChanged += new System.EventHandler(this.rOMMapModeComboBox_SelectedIndexChanged_1); + // + // button1 + // + this.button1.Location = new System.Drawing.Point(501, 215); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(75, 23); + this.button1.TabIndex = 3; + this.button1.Text = "button1"; + this.button1.UseVisualStyleBackColor = true; + // + // button2 + // + this.button2.Location = new System.Drawing.Point(378, 306); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(75, 23); + this.button2.TabIndex = 4; + this.button2.Text = "button2"; + this.button2.UseVisualStyleBackColor = true; + // + // TestForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Controls.Add(this.button2); + this.Controls.Add(this.button1); + this.Controls.Add(rOMMapModeLabel1); + this.Controls.Add(this.rOMMapModeComboBox); + this.Controls.Add(rOMMapModeLabel); + this.Name = "TestForm"; + this.Text = "TestForm"; + this.Load += new System.EventHandler(this.TestForm_Load); + ((System.ComponentModel.ISupportInitialize)(this.project_ImportRomSettingsBindingSource)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.BindingSource project_ImportRomSettingsBindingSource; + private System.Windows.Forms.ComboBox rOMMapModeComboBox; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button2; + } +} \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/TestForm.cs b/DiztinGUIsh/window/dialog/TestForm.cs new file mode 100644 index 00000000..47763090 --- /dev/null +++ b/DiztinGUIsh/window/dialog/TestForm.cs @@ -0,0 +1,42 @@ +using System; +using System.Windows.Forms; + +namespace DiztinGUIsh.window.dialog +{ + public partial class TestForm : Form + { + public Project.ImportRomSettings settings = new Project.ImportRomSettings() + { + ROMMapMode = Data.ROMMapMode.SuperFX + }; + + public TestForm() + { + InitializeComponent(); + + // common for everything on the page + project_ImportRomSettingsBindingSource.DataSource = settings; + + // specific to this combo. datasource is a static list of enum values + var dataSource = Util.GetEnumDescriptions(); + rOMMapModeComboBox.DataSource = new BindingSource(dataSource, null); + rOMMapModeComboBox.ValueMember = "Key"; // names of properties of each item on datasource. + rOMMapModeComboBox.DisplayMember = "Value"; + + // bind comboboxes "SelectedIndex" property to store its value in settings.ROMMapMode + rOMMapModeComboBox.DataBindings.Add(new Binding("SelectedIndex", settings, "ROMMapMode", false, DataSourceUpdateMode.OnPropertyChanged)); + } + + private void TestForm_Load(object sender, EventArgs e) + { + + } + + private void rOMMapModeComboBox_SelectedIndexChanged_1(object sender, EventArgs e) + { + // force the control to flush the new value to the + // datasource as soon as you click on it. + Validate(true); + } + } +} diff --git a/DiztinGUIsh/window/dialog/TestForm.resx b/DiztinGUIsh/window/dialog/TestForm.resx new file mode 100644 index 00000000..dfd6b453 --- /dev/null +++ b/DiztinGUIsh/window/dialog/TestForm.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + + False + + + 17, 17 + + \ No newline at end of file From be63d3d9c313ea5b5b0064b1159821753a390717 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Fri, 2 Oct 2020 19:32:09 -0400 Subject: [PATCH 049/136] working databinding! mostly. off by one. it's a good start. --- .../window/dialog/ImportROMDialog.Designer.cs | 13 ------- DiztinGUIsh/window/dialog/ImportROMDialog.cs | 37 +++++++++++++++++-- .../window/dialog/ImportROMDialog.resx | 3 -- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs b/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs index b473884f..5b34c198 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs @@ -28,7 +28,6 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - this.components = new System.ComponentModel.Container(); this.detectMessage = new System.Windows.Forms.Label(); this.checkData = new System.Windows.Forms.Label(); this.cmbRomMapMode = new System.Windows.Forms.ComboBox(); @@ -77,10 +76,8 @@ private void InitializeComponent() this.label2 = new System.Windows.Forms.Label(); this.label1 = new System.Windows.Forms.Label(); this.checkHeader = new System.Windows.Forms.CheckBox(); - this.importRomSettingsBindingSource = new System.Windows.Forms.BindingSource(this.components); this.groupBox1.SuspendLayout(); this.groupBox2.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.importRomSettingsBindingSource)).BeginInit(); this.SuspendLayout(); // // detectMessage @@ -105,9 +102,6 @@ private void InitializeComponent() // // cmbRomMapMode // - this.cmbRomMapMode.DataBindings.Add(new System.Windows.Forms.Binding("SelectedItem", this.importRomSettingsBindingSource, "ROMMapMode", true)); - this.cmbRomMapMode.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.importRomSettingsBindingSource, "ROMMapMode", true)); - this.cmbRomMapMode.DataSource = this.importRomSettingsBindingSource; this.cmbRomMapMode.FormattingEnabled = true; this.cmbRomMapMode.Location = new System.Drawing.Point(103, 18); this.cmbRomMapMode.Name = "cmbRomMapMode"; @@ -606,11 +600,6 @@ private void InitializeComponent() this.checkHeader.Text = "Auto generate flags for Internal ROM Header"; this.checkHeader.UseVisualStyleBackColor = true; // - // importRomSettingsBindingSource - // - this.importRomSettingsBindingSource.DataSource = typeof(DiztinGUIsh.Project.ImportRomSettings); - this.importRomSettingsBindingSource.CurrentChanged += new System.EventHandler(this.importRomSettingsBindingSource_CurrentChanged); - // // ImportRomDialog // this.AcceptButton = this.okay; @@ -638,7 +627,6 @@ private void InitializeComponent() this.groupBox1.PerformLayout(); this.groupBox2.ResumeLayout(false); this.groupBox2.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.importRomSettingsBindingSource)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -694,6 +682,5 @@ private void InitializeComponent() private System.Windows.Forms.Label label2; private System.Windows.Forms.Label label1; private System.Windows.Forms.CheckBox checkHeader; - private System.Windows.Forms.BindingSource importRomSettingsBindingSource; } } \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.cs b/DiztinGUIsh/window/dialog/ImportROMDialog.cs index e09b6b37..e32d5e35 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Windows.Forms; using DiztinGUIsh.core.util; @@ -10,6 +11,27 @@ public partial class ImportRomDialog : Form public Project.ImportRomSettings ImportSettings { get; protected set; } public bool romTypeNotDetectedCorrectly = true; + public class ImportRomViewModel + { + private readonly Project.ImportRomSettings settings; + + public int SelectedRomMappingIndex + { + get => (int)settings.ROMMapMode; + set => settings.ROMMapMode = (Data.ROMMapMode)value; + } + + public List> SelectedRomMappingList { get; } + = Util.GetEnumDescriptions(); + + public ImportRomViewModel(Project.ImportRomSettings settingsDataSource) + { + Debug.Assert(settingsDataSource != null); + settings = settingsDataSource; + } + } + + public string title; public int RomSettingsOffset; private readonly string[,] vectorNames = { @@ -67,7 +89,7 @@ private void DataBind() cmbRomMapMode.DataBindings.Add(new Binding("SelectedIndex", ImportSettings, "ROMMapMode", false, DataSourceUpdateMode.OnPropertyChanged)); */ - importRomSettingsBindingSource.DataSource = ImportSettings; + // importRomSettingsBindingSource.DataSource = ImportSettings; // specific to this combo. datasource is a static list of enum values var dataSource = Util.GetEnumDescriptions(); @@ -76,7 +98,10 @@ private void DataBind() cmbRomMapMode.DisplayMember = "Value"; // bind comboboxes "SelectedIndex" property to store its value in settings.ROMMapMode - cmbRomMapMode.DataBindings.Add(new Binding("SelectedIndex", ImportSettings, "ROMMapMode", false, DataSourceUpdateMode.OnPropertyChanged)); + cmbRomMapMode.DataBindings.Add(new Binding( + "SelectedIndex", ImportViewModel, + "SelectedRomMappingIndex", false, + DataSourceUpdateMode.OnPropertyChanged)); /* var dataSource = Util.GetEnumDescriptions(); @@ -129,12 +154,12 @@ void UpdateFromDatabinding(IBindableComponent sender) //Validate(true); // this seems to work the best to get the values flushed out in realtime - foreach (var i in sender.DataBindings) + /*foreach (var i in sender.DataBindings) { var q = i as Binding; // flushes the cached value back out to the real data structure q.WriteValue(); - } + }*/ } private void importRomSettingsBindingSource_CurrentChanged(object sender, EventArgs e) @@ -159,6 +184,8 @@ private void comboBox1_TextChanged(object sender, EventArgs e) UpdateFromDatabinding(sender as IBindableComponent); } + ImportRomViewModel ImportViewModel; + private void CreateRomImportSettingsFor(string filename) { var romBytes = RomUtil.ReadAllRomBytesFromFile(filename); @@ -168,6 +195,8 @@ private void CreateRomImportSettingsFor(string filename) RomBytes = romBytes, ROMMapMode = RomUtil.DetectROMMapMode(romBytes, out romTypeNotDetectedCorrectly) }; + + ImportViewModel = new ImportRomViewModel(ImportSettings); } private Dictionary GetGeneratedLabels() diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.resx b/DiztinGUIsh/window/dialog/ImportROMDialog.resx index 248a70dc..1af7de15 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.resx +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.resx @@ -117,7 +117,4 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 17, 17 - \ No newline at end of file From 27ac837e09080d7789ce7ae3ae132996f22870c9 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Fri, 2 Oct 2020 19:43:49 -0400 Subject: [PATCH 050/136] working databinding! that took forevvvvvvvvvvvvvvvvver --- DiztinGUIsh/window/dialog/ImportROMDialog.cs | 62 ++++---------------- 1 file changed, 13 insertions(+), 49 deletions(-) diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.cs b/DiztinGUIsh/window/dialog/ImportROMDialog.cs index e32d5e35..6799beb7 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.cs @@ -76,24 +76,14 @@ public Project.ImportRomSettings PromptForImportSettings(string filename) private void DataBind() { - // common for everything on the page - /*importRomSettingsBindingSource.DataSource = ImportSettings; - - // specific to this combo. datasource is a static list of enum values - var dataSource = Util.GetEnumDescriptions(); - cmbRomMapMode.DataSource = new BindingSource(dataSource, null); - cmbRomMapMode.ValueMember = "Key"; // names of properties of each item on datasource. - cmbRomMapMode.DisplayMember = "Value"; - - // bind comboboxes "SelectedIndex" property to store its value in settings.ROMMapMode - cmbRomMapMode.DataBindings.Add(new Binding("SelectedIndex", ImportSettings, "ROMMapMode", false, DataSourceUpdateMode.OnPropertyChanged)); - */ - // importRomSettingsBindingSource.DataSource = ImportSettings; // specific to this combo. datasource is a static list of enum values var dataSource = Util.GetEnumDescriptions(); - cmbRomMapMode.DataSource = new BindingSource(dataSource, null); + var bs = new BindingSource(dataSource, null); + bs.CurrentChanged += Bs_CurrentChanged; + + cmbRomMapMode.DataSource = bs; cmbRomMapMode.ValueMember = "Key"; // names of properties of each item on datasource. cmbRomMapMode.DisplayMember = "Value"; @@ -102,44 +92,18 @@ private void DataBind() "SelectedIndex", ImportViewModel, "SelectedRomMappingIndex", false, DataSourceUpdateMode.OnPropertyChanged)); - - /* - var dataSource = Util.GetEnumDescriptions(); - - var bs = new BindingSource(dataSource, null); - comboBox1.DataSource = bs; - comboBox1.ValueMember = "Key"; - comboBox1.DisplayMember = "Value"; - - comboBox1.DataBindings.Add(new Binding("SelectedIndex", ImportSettings, "ROMMapMode", false, DataSourceUpdateMode.OnPropertyChanged)); - bs.CurrentChanged += Bs_CurrentChanged; - bs.CurrentItemChanged += Bs_CurrentItemChanged;*/ - - // Call ResetBindings after manual update to update the textboxes. - // bindingSource1.ResetBindings(false); - - - //LoadEnumToCombo(comboBox1); - // comboBox1.DataSource = Enum.GetValues(typeof(Data.ROMMapMode)); - // comboBox1.DataBindings.Add(new Binding("SelectedValue", ImportSettings.ROMMapMode, "StoreObjectROMMapMode")); - - //comboBox1.DataBindings.Add( - // new Binding("SelectedIndex", ImportSettings, "ROMMapMode")); - - //rOMMapModeBindingSource.DataSource = Enum.GetValues(typeof(Data.ROMMapMode)); - //importRomSettingsBindingSource.DataSource = ImportSettings.ROMMapMode; - - // rOMMapModeBindingSource.DataSource = comboBox1DataSource; - // importRomSettingsBindingSource - // importRomSettingsBindingSource = new BindingSource(ImportSettings.ROMMapMode); + } + private void Bs_CurrentChanged(object sender, EventArgs e) + { + UpdateUI(); + } private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) { - // ImportSettings.ROMMapMode = SelectRomMapModeFromUi(comboBox1.SelectedIndex); - UpdateUI(); + } private void UpdateUI() @@ -165,7 +129,7 @@ void UpdateFromDatabinding(IBindableComponent sender) private void importRomSettingsBindingSource_CurrentChanged(object sender, EventArgs e) { int x = 3; - UpdateUI(); + // UpdateUI(); } private void comboBox1_DropDownClosed(object sender, EventArgs e) @@ -179,9 +143,9 @@ private void comboBox1_Validating(object sender, System.ComponentModel.CancelEve } private void comboBox1_TextChanged(object sender, EventArgs e) - { ; + { //Validate(true); - UpdateFromDatabinding(sender as IBindableComponent); + // UpdateFromDatabinding(sender as IBindableComponent); } ImportRomViewModel ImportViewModel; From 1f4db1afc41c28b3592b90637c0a5cc037e1b012 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 3 Oct 2020 08:29:58 -0400 Subject: [PATCH 051/136] probably the real databinding --- DiztinGUIsh/DiztinGUIsh.csproj | 13 +- DiztinGUIsh/Model.cs | 10 +- .../DataSources/Data.FlagType.datasource | 10 -- .../DataSources/Data.InOutPoint.datasource | 10 -- .../DataSources/Data.ROMMapMode.datasource | 10 -- .../DataSources/Data.ROMSpeed.datasource | 10 -- .../Properties/DataSources/Data.datasource | 10 -- ...Ish.loadsave.ImportRomSettings.datasource} | 4 +- ...g.ImportRomDialog+EnumMapper`1.datasource} | 4 +- ...ortRomDialog+ImportRomViewModel.datasource | 29 +++++ .../Properties/DataSources/Project.datasource | 10 -- .../Properties/DataSources/ROMByte.datasource | 10 -- DiztinGUIsh/core/Project.cs | 20 +-- DiztinGUIsh/loadsave/ImportSettings.cs | 45 +++++++ DiztinGUIsh/loadsave/ProjectFileManager.cs | 2 +- DiztinGUIsh/window/MainWindow.cs | 27 ++-- DiztinGUIsh/window/ProjectController.cs | 4 +- .../window/dialog/ImportROMDialog.Designer.cs | 52 ++++---- DiztinGUIsh/window/dialog/ImportROMDialog.cs | 123 +++++++++--------- .../window/dialog/ImportROMDialog.resx | 3 + .../window/dialog/TestForm.Designer.cs | 2 +- DiztinGUIsh/window/dialog/TestForm.cs | 3 +- 22 files changed, 203 insertions(+), 208 deletions(-) delete mode 100644 DiztinGUIsh/Properties/DataSources/Data.FlagType.datasource delete mode 100644 DiztinGUIsh/Properties/DataSources/Data.InOutPoint.datasource delete mode 100644 DiztinGUIsh/Properties/DataSources/Data.ROMMapMode.datasource delete mode 100644 DiztinGUIsh/Properties/DataSources/Data.ROMSpeed.datasource delete mode 100644 DiztinGUIsh/Properties/DataSources/Data.datasource rename DiztinGUIsh/Properties/DataSources/{Project.ImportRomSettings.datasource => DiztinGUIsh.loadsave.ImportRomSettings.datasource} (77%) rename DiztinGUIsh/Properties/DataSources/{Data.Architecture.datasource => DiztinGUIsh.window.dialog.ImportRomDialog+EnumMapper`1.datasource} (55%) create mode 100644 DiztinGUIsh/Properties/DataSources/DiztinGUIsh.window.dialog.ImportRomDialog+ImportRomViewModel.datasource delete mode 100644 DiztinGUIsh/Properties/DataSources/Project.datasource delete mode 100644 DiztinGUIsh/Properties/DataSources/ROMByte.datasource create mode 100644 DiztinGUIsh/loadsave/ImportSettings.cs diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 42172e59..0406f05a 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -117,6 +117,7 @@ + @@ -258,15 +259,9 @@ True - - - - - - - - - + + + SettingsSingleFileGenerator Settings.Designer.cs diff --git a/DiztinGUIsh/Model.cs b/DiztinGUIsh/Model.cs index 18c9e1c8..c665c0f1 100644 --- a/DiztinGUIsh/Model.cs +++ b/DiztinGUIsh/Model.cs @@ -5,7 +5,15 @@ namespace DiztinGUIsh { - public class DizModel : INotifyPropertyChanged + public class DizDataModel : PropertyNotifyChanged + { + + } + public class DizViewModel : PropertyNotifyChanged + { + + } + public class PropertyNotifyChanged : INotifyPropertyChanged { // this stuff lets other parts of code subscribe to events that get fired anytime // properties of our class change. diff --git a/DiztinGUIsh/Properties/DataSources/Data.FlagType.datasource b/DiztinGUIsh/Properties/DataSources/Data.FlagType.datasource deleted file mode 100644 index 033a2575..00000000 --- a/DiztinGUIsh/Properties/DataSources/Data.FlagType.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - DiztinGUIsh.Data+FlagType, DiztinGUIsh, Version=1.0.66.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/DiztinGUIsh/Properties/DataSources/Data.InOutPoint.datasource b/DiztinGUIsh/Properties/DataSources/Data.InOutPoint.datasource deleted file mode 100644 index 09858bc3..00000000 --- a/DiztinGUIsh/Properties/DataSources/Data.InOutPoint.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - DiztinGUIsh.Data+InOutPoint, DiztinGUIsh, Version=1.0.66.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/DiztinGUIsh/Properties/DataSources/Data.ROMMapMode.datasource b/DiztinGUIsh/Properties/DataSources/Data.ROMMapMode.datasource deleted file mode 100644 index 6e4ce3eb..00000000 --- a/DiztinGUIsh/Properties/DataSources/Data.ROMMapMode.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - DiztinGUIsh.Data+ROMMapMode, DiztinGUIsh, Version=1.0.66.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/DiztinGUIsh/Properties/DataSources/Data.ROMSpeed.datasource b/DiztinGUIsh/Properties/DataSources/Data.ROMSpeed.datasource deleted file mode 100644 index fcba39ce..00000000 --- a/DiztinGUIsh/Properties/DataSources/Data.ROMSpeed.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - DiztinGUIsh.Data+ROMSpeed, DiztinGUIsh, Version=1.0.66.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/DiztinGUIsh/Properties/DataSources/Data.datasource b/DiztinGUIsh/Properties/DataSources/Data.datasource deleted file mode 100644 index 4b9c86bc..00000000 --- a/DiztinGUIsh/Properties/DataSources/Data.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - DiztinGUIsh.Data, DiztinGUIsh, Version=1.0.66.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/DiztinGUIsh/Properties/DataSources/Project.ImportRomSettings.datasource b/DiztinGUIsh/Properties/DataSources/DiztinGUIsh.loadsave.ImportRomSettings.datasource similarity index 77% rename from DiztinGUIsh/Properties/DataSources/Project.ImportRomSettings.datasource rename to DiztinGUIsh/Properties/DataSources/DiztinGUIsh.loadsave.ImportRomSettings.datasource index 460e1e49..5cd28ffa 100644 --- a/DiztinGUIsh/Properties/DataSources/Project.ImportRomSettings.datasource +++ b/DiztinGUIsh/Properties/DataSources/DiztinGUIsh.loadsave.ImportRomSettings.datasource @@ -5,8 +5,8 @@ Renaming the file extension or editing the content of this file may cause the file to be unrecognizable by the program. --> - - DiztinGUIsh.Project+ImportRomSettings, DiztinGUIsh, Version=1.0.66.0, Culture=neutral, PublicKeyToken=null + + DiztinGUIsh.loadsave.ImportRomSettings, DiztinGUIsh, Version=1.0.69.0, Culture=neutral, PublicKeyToken=null diff --git a/DiztinGUIsh/Properties/DataSources/Data.Architecture.datasource b/DiztinGUIsh/Properties/DataSources/DiztinGUIsh.window.dialog.ImportRomDialog+EnumMapper`1.datasource similarity index 55% rename from DiztinGUIsh/Properties/DataSources/Data.Architecture.datasource rename to DiztinGUIsh/Properties/DataSources/DiztinGUIsh.window.dialog.ImportRomDialog+EnumMapper`1.datasource index 3dcd82c1..d2491cf1 100644 --- a/DiztinGUIsh/Properties/DataSources/Data.Architecture.datasource +++ b/DiztinGUIsh/Properties/DataSources/DiztinGUIsh.window.dialog.ImportRomDialog+EnumMapper`1.datasource @@ -5,6 +5,6 @@ Renaming the file extension or editing the content of this file may cause the file to be unrecognizable by the program. --> - - DiztinGUIsh.Data+Architecture, DiztinGUIsh, Version=1.0.66.0, Culture=neutral, PublicKeyToken=null + + DiztinGUIsh.window.dialog.ImportRomDialog+EnumMapper`1, DiztinGUIsh, Version=1.0.69.0, Culture=neutral, PublicKeyToken=null \ No newline at end of file diff --git a/DiztinGUIsh/Properties/DataSources/DiztinGUIsh.window.dialog.ImportRomDialog+ImportRomViewModel.datasource b/DiztinGUIsh/Properties/DataSources/DiztinGUIsh.window.dialog.ImportRomDialog+ImportRomViewModel.datasource new file mode 100644 index 00000000..08e8d697 --- /dev/null +++ b/DiztinGUIsh/Properties/DataSources/DiztinGUIsh.window.dialog.ImportRomDialog+ImportRomViewModel.datasource @@ -0,0 +1,29 @@ + + + + + + DiztinGUIsh.window.dialog.ImportRomDialog+EnumMapper`1[[DiztinGUIsh.Data+ROMMapMode, DiztinGUIsh, Version=1.0.69.0, Culture=neutral, PublicKeyToken=null]], DiztinGUIsh, Version=1.0.69.0, Culture=neutral, PublicKeyToken=null + + + + + + + + + + + + + + System.Collections.Generic.KeyValuePair`2[[DiztinGUIsh.Data+ROMMapMode, DiztinGUIsh, Version=1.0.69.0, Culture=neutral, PublicKeyToken=null],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + DiztinGUIsh.window.dialog.ImportRomDialog+ImportRomViewModel, DiztinGUIsh, Version=1.0.69.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/DiztinGUIsh/Properties/DataSources/Project.datasource b/DiztinGUIsh/Properties/DataSources/Project.datasource deleted file mode 100644 index d0d0aa7a..00000000 --- a/DiztinGUIsh/Properties/DataSources/Project.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - DiztinGUIsh.Project, DiztinGUIsh, Version=1.0.66.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/DiztinGUIsh/Properties/DataSources/ROMByte.datasource b/DiztinGUIsh/Properties/DataSources/ROMByte.datasource deleted file mode 100644 index 2773c6d8..00000000 --- a/DiztinGUIsh/Properties/DataSources/ROMByte.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - DiztinGUIsh.ROMByte, DiztinGUIsh, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/DiztinGUIsh/core/Project.cs b/DiztinGUIsh/core/Project.cs index 77653cfd..964f7dcf 100644 --- a/DiztinGUIsh/core/Project.cs +++ b/DiztinGUIsh/core/Project.cs @@ -4,7 +4,7 @@ namespace DiztinGUIsh { - public class Project : DizModel + public class Project : DizDataModel { // Any public properties will be automatically serialized to XML. // They require a get AND set. Order is important. @@ -80,24 +80,6 @@ public Project() LogWriterSettings.SetDefaults(); } - public class ImportRomSettings - { - // temp - private Data.ROMMapMode mode; - public Data.ROMMapMode ROMMapMode - { - get => mode; - set => mode = value; - } - - public Data.ROMSpeed ROMSpeed { get; set; } - - public Dictionary InitialLabels { get; set; } - public Dictionary InitialHeaderFlags { get; set; } - - public byte[] RomBytes { get; set; } - public string RomFilename { get; set; } - } private string projectFileName; private string attachedRomFilename; diff --git a/DiztinGUIsh/loadsave/ImportSettings.cs b/DiztinGUIsh/loadsave/ImportSettings.cs new file mode 100644 index 00000000..7ef2c448 --- /dev/null +++ b/DiztinGUIsh/loadsave/ImportSettings.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DiztinGUIsh.core.util; + +namespace DiztinGUIsh.loadsave +{ + public class ImportRomSettings : PropertyNotifyChanged + { + private Data.ROMMapMode mode; + private Data.ROMSpeed romSpeed; + private byte[] romBytes; + private string romFilename; + + public Data.ROMMapMode ROMMapMode + { + get => mode; + set => SetField(ref mode, value); + } + + public Data.ROMSpeed ROMSpeed + { + get => romSpeed; + set => SetField(ref romSpeed, value); + } + + // todo: add INotify stuff if we care. probably dont need to. + public Dictionary InitialLabels { get; set; } + public Dictionary InitialHeaderFlags { get; set; } + + public byte[] RomBytes + { + get => romBytes; + set => SetField(ref romBytes, value); + } + + public string RomFilename + { + get => romFilename; + set => SetField(ref romFilename, value); + } + } +} \ No newline at end of file diff --git a/DiztinGUIsh/loadsave/ProjectFileManager.cs b/DiztinGUIsh/loadsave/ProjectFileManager.cs index 2f423b92..4b44e3e7 100644 --- a/DiztinGUIsh/loadsave/ProjectFileManager.cs +++ b/DiztinGUIsh/loadsave/ProjectFileManager.cs @@ -130,7 +130,7 @@ private static byte[] DoSave(Project project, string filename, ProjectSerializer return data; } - public static Project ImportRomAndCreateNewProject(Project.ImportRomSettings importSettings) + public static Project ImportRomAndCreateNewProject(ImportRomSettings importSettings) { var project = new Project { diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 5d4b8548..2ea64e92 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -6,6 +6,7 @@ using System.IO; using System.Windows.Forms; using DiztinGUIsh.core.util; +using DiztinGUIsh.loadsave; using DiztinGUIsh.Properties; using DiztinGUIsh.window.dialog; @@ -165,24 +166,24 @@ private string PromptForOpenFilename() private bool TryImportProject(string romFileToOpen) { - try - { - var importSettings = PromptForImportSettings(romFileToOpen); - if (importSettings == null) - return false; + //try // temp remove this for debuggin. + //{ + var importSettings = PromptForImportSettings(romFileToOpen); + if (importSettings == null) + return false; - ProjectController.ImportRomAndCreateNewProject(importSettings); - return true; - } - catch (Exception ex) - { - MessageBox.Show(ex.Message, "Error importing project", MessageBoxButtons.OK, MessageBoxIcon.Error); - } + ProjectController.ImportRomAndCreateNewProject(importSettings); + return true; + //} + //catch (Exception ex) + //{ + // MessageBox.Show(ex.Message, "Error importing project", MessageBoxButtons.OK, MessageBoxIcon.Error); + //} return false; } - private static Project.ImportRomSettings PromptForImportSettings(string romFileToOpen) + private static ImportRomSettings PromptForImportSettings(string romFileToOpen) { return new ImportRomDialog().PromptForImportSettings(romFileToOpen); } diff --git a/DiztinGUIsh/window/ProjectController.cs b/DiztinGUIsh/window/ProjectController.cs index 9571a7ee..7cdbb722 100644 --- a/DiztinGUIsh/window/ProjectController.cs +++ b/DiztinGUIsh/window/ProjectController.cs @@ -3,7 +3,7 @@ using System.IO; using DiztinGUIsh.loadsave; -namespace DiztinGUIsh +namespace DiztinGUIsh.window { public class ProjectController { @@ -92,7 +92,7 @@ public void ImportBizHawkCDL(string filename) }); } - public void ImportRomAndCreateNewProject(Project.ImportRomSettings importSettings) + public void ImportRomAndCreateNewProject(ImportRomSettings importSettings) { var project = ProjectFileManager.ImportRomAndCreateNewProject(importSettings); OnProjectOpenSuccess(project.ProjectFileName, project); diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs b/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs index 5b34c198..72b46ca9 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs @@ -28,10 +28,9 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + System.Windows.Forms.Label sourceLabel; this.detectMessage = new System.Windows.Forms.Label(); this.checkData = new System.Windows.Forms.Label(); - this.cmbRomMapMode = new System.Windows.Forms.ComboBox(); - this.mapmode = new System.Windows.Forms.Label(); this.label4 = new System.Windows.Forms.Label(); this.label5 = new System.Windows.Forms.Label(); this.cancel = new System.Windows.Forms.Button(); @@ -41,6 +40,7 @@ private void InitializeComponent() this.label3 = new System.Windows.Forms.Label(); this.label6 = new System.Windows.Forms.Label(); this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.cmbRomMapMode = new System.Windows.Forms.ComboBox(); this.groupBox2 = new System.Windows.Forms.GroupBox(); this.label13 = new System.Windows.Forms.Label(); this.checkboxEmuIRQ = new System.Windows.Forms.CheckBox(); @@ -76,10 +76,20 @@ private void InitializeComponent() this.label2 = new System.Windows.Forms.Label(); this.label1 = new System.Windows.Forms.Label(); this.checkHeader = new System.Windows.Forms.CheckBox(); + sourceLabel = new System.Windows.Forms.Label(); this.groupBox1.SuspendLayout(); this.groupBox2.SuspendLayout(); this.SuspendLayout(); // + // sourceLabel + // + sourceLabel.AutoSize = true; + sourceLabel.Location = new System.Drawing.Point(14, 22); + sourceLabel.Name = "sourceLabel"; + sourceLabel.Size = new System.Drawing.Size(83, 13); + sourceLabel.TabIndex = 5; + sourceLabel.Text = "Rom Map Mode"; + // // detectMessage // this.detectMessage.AutoSize = true; @@ -100,27 +110,6 @@ private void InitializeComponent() this.checkData.Text = "Does the following info look correct?"; this.checkData.TextAlign = System.Drawing.ContentAlignment.TopCenter; // - // cmbRomMapMode - // - this.cmbRomMapMode.FormattingEnabled = true; - this.cmbRomMapMode.Location = new System.Drawing.Point(103, 18); - this.cmbRomMapMode.Name = "cmbRomMapMode"; - this.cmbRomMapMode.Size = new System.Drawing.Size(121, 21); - this.cmbRomMapMode.TabIndex = 1; - this.cmbRomMapMode.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged); - this.cmbRomMapMode.DropDownClosed += new System.EventHandler(this.comboBox1_DropDownClosed); - this.cmbRomMapMode.TextChanged += new System.EventHandler(this.comboBox1_TextChanged); - this.cmbRomMapMode.Validating += new System.ComponentModel.CancelEventHandler(this.comboBox1_Validating); - // - // mapmode - // - this.mapmode.AutoSize = true; - this.mapmode.Location = new System.Drawing.Point(11, 21); - this.mapmode.Name = "mapmode"; - this.mapmode.Size = new System.Drawing.Size(89, 13); - this.mapmode.TabIndex = 0; - this.mapmode.Text = "ROM Map Mode:"; - // // label4 // this.label4.AutoSize = true; @@ -201,19 +190,27 @@ private void InitializeComponent() // // groupBox1 // - this.groupBox1.Controls.Add(this.mapmode); this.groupBox1.Controls.Add(this.cmbRomMapMode); + this.groupBox1.Controls.Add(sourceLabel); this.groupBox1.Controls.Add(this.label4); this.groupBox1.Controls.Add(this.romtitle); this.groupBox1.Controls.Add(this.label5); this.groupBox1.Controls.Add(this.romspeed); this.groupBox1.Location = new System.Drawing.Point(12, 74); this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(235, 89); + this.groupBox1.Size = new System.Drawing.Size(374, 257); this.groupBox1.TabIndex = 4; this.groupBox1.TabStop = false; this.groupBox1.Text = "ROM Information"; // + // cmbRomMapMode + // + this.cmbRomMapMode.FormattingEnabled = true; + this.cmbRomMapMode.Location = new System.Drawing.Point(102, 18); + this.cmbRomMapMode.Name = "cmbRomMapMode"; + this.cmbRomMapMode.Size = new System.Drawing.Size(142, 21); + this.cmbRomMapMode.TabIndex = 6; + // // groupBox2 // this.groupBox2.Controls.Add(this.label13); @@ -606,7 +603,7 @@ private void InitializeComponent() this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.cancel; - this.ClientSize = new System.Drawing.Size(261, 424); + this.ClientSize = new System.Drawing.Size(262, 424); this.Controls.Add(this.checkHeader); this.Controls.Add(this.groupBox2); this.Controls.Add(this.groupBox1); @@ -636,8 +633,6 @@ private void InitializeComponent() private System.Windows.Forms.Label detectMessage; private System.Windows.Forms.Label checkData; - private System.Windows.Forms.ComboBox cmbRomMapMode; - private System.Windows.Forms.Label mapmode; private System.Windows.Forms.Label label4; private System.Windows.Forms.Label label5; private System.Windows.Forms.Button cancel; @@ -682,5 +677,6 @@ private void InitializeComponent() private System.Windows.Forms.Label label2; private System.Windows.Forms.Label label1; private System.Windows.Forms.CheckBox checkHeader; + private System.Windows.Forms.ComboBox cmbRomMapMode; } } \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.cs b/DiztinGUIsh/window/dialog/ImportROMDialog.cs index 6799beb7..20558879 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.cs @@ -1,33 +1,49 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.Windows.Forms; using DiztinGUIsh.core.util; +using DiztinGUIsh.loadsave; namespace DiztinGUIsh.window.dialog { public partial class ImportRomDialog : Form { - public Project.ImportRomSettings ImportSettings { get; protected set; } + public ImportRomSettings ImportSettings { get; protected set; } public bool romTypeNotDetectedCorrectly = true; - public class ImportRomViewModel + public class EnumMapper where TEnum : Enum { - private readonly Project.ImportRomSettings settings; + public TEnum Source { get; set; } - public int SelectedRomMappingIndex + // surely... there is some third party library that handles this. + // for now, here we are. + public int SelectedIndex { - get => (int)settings.ROMMapMode; - set => settings.ROMMapMode = (Data.ROMMapMode)value; + get => Convert.ToInt32(Source); + set => Source = (TEnum)Enum.ToObject(typeof(TEnum), value); } - public List> SelectedRomMappingList { get; } - = Util.GetEnumDescriptions(); + public List> Descriptions { get; } + = Util.GetEnumDescriptions(); + } + + public class ImportRomViewModel + { + private readonly ImportRomSettings settings; + + public EnumMapper RomMapMode { get; } = new EnumMapper(); - public ImportRomViewModel(Project.ImportRomSettings settingsDataSource) + public ImportRomViewModel(ImportRomSettings settingsDataSource) { Debug.Assert(settingsDataSource != null); settings = settingsDataSource; + + settingsDataSource.PropertyChanged += (sender, args) => + { + RomMapMode.Source = settingsDataSource.ROMMapMode; + }; } } @@ -56,7 +72,7 @@ public ImportRomDialog() }; } - public Project.ImportRomSettings PromptForImportSettings(string filename) + public ImportRomSettings PromptForImportSettings(string filename) { CreateRomImportSettingsFor(filename); @@ -79,21 +95,46 @@ private void DataBind() // importRomSettingsBindingSource.DataSource = ImportSettings; // specific to this combo. datasource is a static list of enum values - var dataSource = Util.GetEnumDescriptions(); + var dataSource = ImportViewModel.RomMapMode.Descriptions; var bs = new BindingSource(dataSource, null); bs.CurrentChanged += Bs_CurrentChanged; + // bind comboboxes "SelectedIndex" property to store its value in settings.ROMMapMode + /*cmbRomMapMode.DataBindings.Add(new Binding( + "SelectedIndex", ImportSettings, + "ROMMapMode", false, + DataSourceUpdateMode.OnPropertyChanged));*/ + + + // try this next. + cmbRomMapMode.DataBindings.Add(new Binding( + "SelectedValue", ImportSettings, // if not try SelectedValue + "ROMMapMode", false, + DataSourceUpdateMode.OnPropertyChanged)); + cmbRomMapMode.DataSource = bs; - cmbRomMapMode.ValueMember = "Key"; // names of properties of each item on datasource. cmbRomMapMode.DisplayMember = "Value"; + cmbRomMapMode.ValueMember = "Key"; // names of properties of each item on datasource. + + // importRomSettingsBindingSource.DataSource = ImportSettings; + + // specific to this combo. datasource is a static list of enum values + // var bl = new BindingList() {ImportViewModel}; + //var bl = new [] {ImportViewModel}; + //var bs = new BindingSource(bl, null); + //bs.CurrentChanged += Bs_CurrentChanged; + + // ImportViewModel.RomMapMode.Source + // cmbRomMapMode.ValueMember = "Key"; // names of properties of each item on datasource + // cmbRomMapMode.DisplayMember = "Value"; // bind comboboxes "SelectedIndex" property to store its value in settings.ROMMapMode - cmbRomMapMode.DataBindings.Add(new Binding( - "SelectedIndex", ImportViewModel, - "SelectedRomMappingIndex", false, - DataSourceUpdateMode.OnPropertyChanged)); + /*comboBox1.DataBindings.Add(new Binding( + "SelectedValue", ImportViewModel, + "RomMapMode.Source", false, + DataSourceUpdateMode.OnPropertyChanged));*/ - + // cmbRomMapMode.DataSource = settingsBindingSource; } private void Bs_CurrentChanged(object sender, EventArgs e) @@ -101,59 +142,18 @@ private void Bs_CurrentChanged(object sender, EventArgs e) UpdateUI(); } - private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) - { - - } - private void UpdateUI() { UpdateOffsetAndSpeed(); UpdateTextboxes(); } - void UpdateFromDatabinding(IBindableComponent sender) - { - // ValidateChildren(); - //Validate(true); - - // this seems to work the best to get the values flushed out in realtime - /*foreach (var i in sender.DataBindings) - { - var q = i as Binding; - // flushes the cached value back out to the real data structure - q.WriteValue(); - }*/ - } - - private void importRomSettingsBindingSource_CurrentChanged(object sender, EventArgs e) - { - int x = 3; - // UpdateUI(); - } - - private void comboBox1_DropDownClosed(object sender, EventArgs e) - { - int x = 3; - } - - private void comboBox1_Validating(object sender, System.ComponentModel.CancelEventArgs e) - { - int x = 3; - } - - private void comboBox1_TextChanged(object sender, EventArgs e) - { - //Validate(true); - // UpdateFromDatabinding(sender as IBindableComponent); - } - ImportRomViewModel ImportViewModel; private void CreateRomImportSettingsFor(string filename) { var romBytes = RomUtil.ReadAllRomBytesFromFile(filename); - ImportSettings = new Project.ImportRomSettings + ImportSettings = new ImportRomSettings { RomFilename = filename, RomBytes = romBytes, @@ -286,6 +286,11 @@ private void ImportROMDialog_Load(object sender, EventArgs e) private void cancel_Click(object sender, EventArgs e) { Close(); } + private void cmbRomMapMode_SelectedIndexChanged(object sender, EventArgs e) + { + + } + /*private Data.ROMMapMode SelectRomMapModeFromUi(int selectedIndex) { diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.resx b/DiztinGUIsh/window/dialog/ImportROMDialog.resx index 1af7de15..83afe152 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.resx +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.resx @@ -117,4 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + False + \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/TestForm.Designer.cs b/DiztinGUIsh/window/dialog/TestForm.Designer.cs index e2fef50e..61fa3969 100644 --- a/DiztinGUIsh/window/dialog/TestForm.Designer.cs +++ b/DiztinGUIsh/window/dialog/TestForm.Designer.cs @@ -60,7 +60,7 @@ private void InitializeComponent() // // project_ImportRomSettingsBindingSource // - this.project_ImportRomSettingsBindingSource.DataSource = typeof(DiztinGUIsh.Project.ImportRomSettings); + this.project_ImportRomSettingsBindingSource.DataSource = typeof(DiztinGUIsh.loadsave.ImportRomSettings); // // rOMMapModeComboBox // diff --git a/DiztinGUIsh/window/dialog/TestForm.cs b/DiztinGUIsh/window/dialog/TestForm.cs index 47763090..4ee14fa2 100644 --- a/DiztinGUIsh/window/dialog/TestForm.cs +++ b/DiztinGUIsh/window/dialog/TestForm.cs @@ -1,11 +1,12 @@ using System; using System.Windows.Forms; +using DiztinGUIsh.loadsave; namespace DiztinGUIsh.window.dialog { public partial class TestForm : Form { - public Project.ImportRomSettings settings = new Project.ImportRomSettings() + public ImportRomSettings settings = new ImportRomSettings() { ROMMapMode = Data.ROMMapMode.SuperFX }; From edbbbb19fd02f648dbb2058f9519ec2862fae0df Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 3 Oct 2020 08:35:24 -0400 Subject: [PATCH 052/136] final databinding, this is the right way to go --- DiztinGUIsh/window/dialog/ImportROMDialog.cs | 46 ++++---------------- 1 file changed, 9 insertions(+), 37 deletions(-) diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.cs b/DiztinGUIsh/window/dialog/ImportROMDialog.cs index 20558879..6f932d8d 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.cs @@ -29,7 +29,8 @@ public int SelectedIndex = Util.GetEnumDescriptions(); } - public class ImportRomViewModel + // hey. maybe we don't explicitly need this. + /*public class ImportRomViewModel { private readonly ImportRomSettings settings; @@ -45,7 +46,7 @@ public ImportRomViewModel(ImportRomSettings settingsDataSource) RomMapMode.Source = settingsDataSource.ROMMapMode; }; } - } + }*/ public string title; @@ -92,49 +93,20 @@ public ImportRomSettings PromptForImportSettings(string filename) private void DataBind() { - // importRomSettingsBindingSource.DataSource = ImportSettings; - - // specific to this combo. datasource is a static list of enum values - var dataSource = ImportViewModel.RomMapMode.Descriptions; - var bs = new BindingSource(dataSource, null); + var enumValuesAndDescriptionsKVP = Util.GetEnumDescriptions(); + var bs = new BindingSource(enumValuesAndDescriptionsKVP, null); bs.CurrentChanged += Bs_CurrentChanged; - // bind comboboxes "SelectedIndex" property to store its value in settings.ROMMapMode - /*cmbRomMapMode.DataBindings.Add(new Binding( - "SelectedIndex", ImportSettings, - "ROMMapMode", false, - DataSourceUpdateMode.OnPropertyChanged));*/ - + // var bs = new BindingSource(ImportViewModel.RomMapMode.Descriptions, null); - // try this next. cmbRomMapMode.DataBindings.Add(new Binding( - "SelectedValue", ImportSettings, // if not try SelectedValue + "SelectedValue", ImportSettings, "ROMMapMode", false, DataSourceUpdateMode.OnPropertyChanged)); cmbRomMapMode.DataSource = bs; cmbRomMapMode.DisplayMember = "Value"; cmbRomMapMode.ValueMember = "Key"; // names of properties of each item on datasource. - - // importRomSettingsBindingSource.DataSource = ImportSettings; - - // specific to this combo. datasource is a static list of enum values - // var bl = new BindingList() {ImportViewModel}; - //var bl = new [] {ImportViewModel}; - //var bs = new BindingSource(bl, null); - //bs.CurrentChanged += Bs_CurrentChanged; - - // ImportViewModel.RomMapMode.Source - // cmbRomMapMode.ValueMember = "Key"; // names of properties of each item on datasource - // cmbRomMapMode.DisplayMember = "Value"; - - // bind comboboxes "SelectedIndex" property to store its value in settings.ROMMapMode - /*comboBox1.DataBindings.Add(new Binding( - "SelectedValue", ImportViewModel, - "RomMapMode.Source", false, - DataSourceUpdateMode.OnPropertyChanged));*/ - - // cmbRomMapMode.DataSource = settingsBindingSource; } private void Bs_CurrentChanged(object sender, EventArgs e) @@ -148,7 +120,7 @@ private void UpdateUI() UpdateTextboxes(); } - ImportRomViewModel ImportViewModel; + //ImportRomViewModel ImportViewModel; private void CreateRomImportSettingsFor(string filename) { @@ -160,7 +132,7 @@ private void CreateRomImportSettingsFor(string filename) ROMMapMode = RomUtil.DetectROMMapMode(romBytes, out romTypeNotDetectedCorrectly) }; - ImportViewModel = new ImportRomViewModel(ImportSettings); + //ImportViewModel = new ImportRomViewModel(ImportSettings); } private Dictionary GetGeneratedLabels() From 71ab19f830a61b13a2b62bc42bf452fe5f6195ec Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 3 Oct 2020 10:51:02 -0400 Subject: [PATCH 053/136] - Finish import dialog (I think!) - Start replacing enum to string functions with GetEnumDescription() --- DiztinGUIsh/core/CPU65C816.cs | 1 + DiztinGUIsh/core/Data.cs | 16 +- DiztinGUIsh/core/LogCreator.cs | 5 +- DiztinGUIsh/core/Project.cs | 1 + DiztinGUIsh/core/ROMByte.cs | 1 + DiztinGUIsh/core/import/BizHawkCdl.cs | 1 + DiztinGUIsh/core/import/SampleRomData.cs | 3 +- DiztinGUIsh/core/util/RomUtil.cs | 130 +++----- DiztinGUIsh/loadsave/ImportSettings.cs | 1 + DiztinGUIsh/loadsave/ProjectFileManager.cs | 1 + .../binary_serializer_old/BinarySerializer.cs | 1 + .../xml_serializer/ProjectXMLSerializer.cs | 1 + .../xml_serializer/RomBytesXMLSerializer.cs | 1 + DiztinGUIsh/window/AliasList.cs | 1 + DiztinGUIsh/window/GuiUtil.cs | 55 ++-- DiztinGUIsh/window/MainWindow.cs | 9 +- .../window/dialog/ExportDisassembly.cs | 1 + DiztinGUIsh/window/dialog/GotoDialog.cs | 1 + DiztinGUIsh/window/dialog/HarshAutoStep.cs | 1 + .../window/dialog/ImportROMDialog.Designer.cs | 266 ++++++++-------- DiztinGUIsh/window/dialog/ImportROMDialog.cs | 289 +++++++----------- DiztinGUIsh/window/dialog/MarkManyDialog.cs | 1 + .../window/dialog/MisalignmentChecker.cs | 5 +- DiztinGUIsh/window/dialog/TestForm.cs | 1 + 24 files changed, 360 insertions(+), 433 deletions(-) diff --git a/DiztinGUIsh/core/CPU65C816.cs b/DiztinGUIsh/core/CPU65C816.cs index 2ef283a1..63e9de56 100644 --- a/DiztinGUIsh/core/CPU65C816.cs +++ b/DiztinGUIsh/core/CPU65C816.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using DiztinGUIsh.core; namespace DiztinGUIsh { diff --git a/DiztinGUIsh/core/Data.cs b/DiztinGUIsh/core/Data.cs index a03d1e69..dba2bd2c 100644 --- a/DiztinGUIsh/core/Data.cs +++ b/DiztinGUIsh/core/Data.cs @@ -6,7 +6,7 @@ using System.Text; using DiztinGUIsh.core.util; -namespace DiztinGUIsh +namespace DiztinGUIsh.core { public class Data { @@ -15,16 +15,16 @@ public enum FlagType : byte Unreached = 0x00, Opcode = 0x10, Operand = 0x11, - Data8Bit = 0x20, + [Description("Data (8-bit)")] Data8Bit = 0x20, Graphics = 0x21, Music = 0x22, Empty = 0x23, - Data16Bit = 0x30, - Pointer16Bit = 0x31, - Data24Bit = 0x40, - Pointer24Bit = 0x41, - Data32Bit = 0x50, - Pointer32Bit = 0x51, + [Description("Data (16-bit)")] Data16Bit = 0x30, + [Description("Pointer (16-bit)")] Pointer16Bit = 0x31, + [Description("Data (24-bit)")] Data24Bit = 0x40, + [Description("Pointer (24-bit)")] Pointer24Bit = 0x41, + [Description("Data (32-bit)")] Data32Bit = 0x50, + [Description("Pointer (32-bit)")] Pointer32Bit = 0x51, Text = 0x60 } diff --git a/DiztinGUIsh/core/LogCreator.cs b/DiztinGUIsh/core/LogCreator.cs index 92972873..07bf1be0 100644 --- a/DiztinGUIsh/core/LogCreator.cs +++ b/DiztinGUIsh/core/LogCreator.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Reflection; +using DiztinGUIsh.core; using DiztinGUIsh.core.util; namespace DiztinGUIsh @@ -494,12 +495,12 @@ private string GetLine(int offset, string special) { if (offset + i >= size) { - StreamError.WriteLine("({0}) Offset 0x{1:X}: {2} extends past the end of the ROM.", ++errorCount, offset, RomUtil.TypeToString(check)); + StreamError.WriteLine("({0}) Offset 0x{1:X}: {2} extends past the end of the ROM.", ++errorCount, offset, Util.GetEnumDescription(check)); break; } else if (Data.GetFlag(offset + i) != check) { - StreamError.WriteLine("({0}) Offset 0x{1:X}: Expected {2}, but got {3} instead.", ++errorCount, offset + i, RomUtil.TypeToString(check), RomUtil.TypeToString(Data.GetFlag(offset + i))); + StreamError.WriteLine("({0}) Offset 0x{1:X}: Expected {2}, but got {3} instead.", ++errorCount, offset + i, Util.GetEnumDescription(check), Util.GetEnumDescription(Data.GetFlag(offset + i))); break; } } diff --git a/DiztinGUIsh/core/Project.cs b/DiztinGUIsh/core/Project.cs index 964f7dcf..65c2e991 100644 --- a/DiztinGUIsh/core/Project.cs +++ b/DiztinGUIsh/core/Project.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using DiztinGUIsh.core; using DiztinGUIsh.core.util; namespace DiztinGUIsh diff --git a/DiztinGUIsh/core/ROMByte.cs b/DiztinGUIsh/core/ROMByte.cs index c203a676..87cd1512 100644 --- a/DiztinGUIsh/core/ROMByte.cs +++ b/DiztinGUIsh/core/ROMByte.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using DiztinGUIsh.core; namespace DiztinGUIsh { diff --git a/DiztinGUIsh/core/import/BizHawkCdl.cs b/DiztinGUIsh/core/import/BizHawkCdl.cs index 051be676..5346048d 100644 --- a/DiztinGUIsh/core/import/BizHawkCdl.cs +++ b/DiztinGUIsh/core/import/BizHawkCdl.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using DiztinGUIsh.core; namespace DiztinGUIsh { diff --git a/DiztinGUIsh/core/import/SampleRomData.cs b/DiztinGUIsh/core/import/SampleRomData.cs index eaeb446c..361b2bbc 100644 --- a/DiztinGUIsh/core/import/SampleRomData.cs +++ b/DiztinGUIsh/core/import/SampleRomData.cs @@ -1,4 +1,5 @@ -using DiztinGUIsh.core.util; +using DiztinGUIsh.core; +using DiztinGUIsh.core.util; namespace DiztinGUIsh { diff --git a/DiztinGUIsh/core/util/RomUtil.cs b/DiztinGUIsh/core/util/RomUtil.cs index cac1157e..a4eae585 100644 --- a/DiztinGUIsh/core/util/RomUtil.cs +++ b/DiztinGUIsh/core/util/RomUtil.cs @@ -1,11 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; +using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using DiztinGUIsh.Annotations; namespace DiztinGUIsh.core.util { @@ -54,7 +48,7 @@ public static string GetRomTitleName(byte[] rom, int romSettingOffset) public static int ConvertSNESToPC(int address, Data.ROMMapMode mode, int size) { - int _UnmirroredOffset(int offset) => RomUtil.UnmirroredOffset(offset, size); + int _UnmirroredOffset(int offset) => UnmirroredOffset(offset, size); // WRAM is N/A to PC addressing if ((address & 0xFE0000) == 0x7E0000) return -1; @@ -161,30 +155,6 @@ public static int ConvertPCtoSNES(int offset, Data.ROMMapMode romMapMode, Data.R return offset; } - - // TODO: replace with Description() attribute - public static string TypeToString(Data.FlagType flag) - { - return flag switch - { - Data.FlagType.Unreached => "Unreached", - Data.FlagType.Opcode => "Opcode", - Data.FlagType.Operand => "Operand", - Data.FlagType.Data8Bit => "Data (8-bit)", - Data.FlagType.Graphics => "Graphics", - Data.FlagType.Music => "Music", - Data.FlagType.Empty => "Empty", - Data.FlagType.Data16Bit => "Data (16-bit)", - Data.FlagType.Pointer16Bit => "Pointer (16-bit)", - Data.FlagType.Data24Bit => "Data (24-bit)", - Data.FlagType.Pointer24Bit => "Pointer (24-bit)", - Data.FlagType.Data32Bit => "Data (32-bit)", - Data.FlagType.Pointer32Bit => "Pointer (32-bit)", - Data.FlagType.Text => "Text", - _ => "" - }; - } - public static int UnmirroredOffset(int offset, int size) { // most of the time this is true; for efficiency @@ -207,23 +177,6 @@ public static int UnmirroredOffset(int offset, int size) return repeatedOffset; } - // TODO: use new enum GetDescription() stuff. - public static string GetRomMapModeName(Data.ROMMapMode mode) - { - return mode switch - { - Data.ROMMapMode.ExSA1ROM => "SA-1 ROM (FuSoYa's 8MB mapper)", - Data.ROMMapMode.SA1ROM => "SA-1 ROM", - Data.ROMMapMode.SuperFX => "SuperFX", - Data.ROMMapMode.LoROM => "LoROM", - Data.ROMMapMode.HiROM => "HiROM", - Data.ROMMapMode.SuperMMC => "Super MMC", - Data.ROMMapMode.ExHiROM => "ExHiROM", - Data.ROMMapMode.ExLoROM => "ExLoROM", - _ => "Unknown mapping" - }; - } - public static string TypeToLabel(Data.FlagType flag) { return flag switch @@ -272,36 +225,28 @@ public static int TypeStepSize(Data.FlagType flag) return 0; } - public static Data.ROMMapMode DetectROMMapMode(IReadOnlyList rom_bytes, out bool couldnt_detect) + public static Data.ROMMapMode DetectROMMapMode(IReadOnlyList romBytes, out bool detectedValidRomMapType) { - couldnt_detect = false; + detectedValidRomMapType = true; - if ((rom_bytes[Data.LOROM_SETTING_OFFSET] & 0xEF) == 0x23) - { - return rom_bytes.Count > 0x400000 ? Data.ROMMapMode.ExSA1ROM : Data.ROMMapMode.SA1ROM; - } - else if ((rom_bytes[Data.LOROM_SETTING_OFFSET] & 0xEC) == 0x20) - { - return (rom_bytes[Data.LOROM_SETTING_OFFSET + 1] & 0xF0) == 0x10 ? Data.ROMMapMode.SuperFX : Data.ROMMapMode.LoROM; - } - else if (rom_bytes.Count >= 0x10000 && (rom_bytes[Data.HIROM_SETTING_OFFSET] & 0xEF) == 0x21) - { + if ((romBytes[Data.LOROM_SETTING_OFFSET] & 0xEF) == 0x23) + return romBytes.Count > 0x400000 ? Data.ROMMapMode.ExSA1ROM : Data.ROMMapMode.SA1ROM; + + if ((romBytes[Data.LOROM_SETTING_OFFSET] & 0xEC) == 0x20) + return (romBytes[Data.LOROM_SETTING_OFFSET + 1] & 0xF0) == 0x10 ? Data.ROMMapMode.SuperFX : Data.ROMMapMode.LoROM; + + if (romBytes.Count >= 0x10000 && (romBytes[Data.HIROM_SETTING_OFFSET] & 0xEF) == 0x21) return Data.ROMMapMode.HiROM; - } - else if (rom_bytes.Count >= 0x10000 && (rom_bytes[Data.HIROM_SETTING_OFFSET] & 0xE7) == 0x22) - { + + if (romBytes.Count >= 0x10000 && (romBytes[Data.HIROM_SETTING_OFFSET] & 0xE7) == 0x22) return Data.ROMMapMode.SuperMMC; - } - else if (rom_bytes.Count >= 0x410000 && (rom_bytes[Data.EXHIROM_SETTING_OFFSET] & 0xEF) == 0x25) - { + + if (romBytes.Count >= 0x410000 && (romBytes[Data.EXHIROM_SETTING_OFFSET] & 0xEF) == 0x25) return Data.ROMMapMode.ExHiROM; - } - else - { - // detection failed. take our best guess..... - couldnt_detect = true; - return rom_bytes.Count > 0x40000 ? Data.ROMMapMode.ExLoROM : Data.ROMMapMode.LoROM; - } + + // detection failed. take our best guess..... + detectedValidRomMapType = false; + return romBytes.Count > 0x40000 ? Data.ROMMapMode.ExLoROM : Data.ROMMapMode.LoROM; } public static int GetRomSettingOffset(Data.ROMMapMode mode) @@ -376,23 +321,34 @@ public static byte[] ReadAllRomBytesFromFile(string filename) return rom; } - public static void GetHeaderFlags(int offset, IDictionary flags, byte[] romBytes) + public static void GenerateHeaderFlags(int romSettingsOffset, IDictionary flags, byte[] romBytes) { - for (int i = 0; i < LengthOfTitleName; i++) flags.Add(offset - 0x15 + i, Data.FlagType.Text); - for (int i = 0; i < 7; i++) flags.Add(offset + i, Data.FlagType.Data8Bit); - for (int i = 0; i < 4; i++) flags.Add(offset + 7 + i, Data.FlagType.Data16Bit); - for (int i = 0; i < 0x20; i++) flags.Add(offset + 11 + i, Data.FlagType.Pointer16Bit); - - if (romBytes[offset - 1] == 0) + for (int i = 0; i < LengthOfTitleName; i++) + flags.Add(romSettingsOffset - LengthOfTitleName + i, Data.FlagType.Text); + + for (int i = 0; i < 7; i++) + flags.Add(romSettingsOffset + i, Data.FlagType.Data8Bit); + + for (int i = 0; i < 4; i++) + flags.Add(romSettingsOffset + 7 + i, Data.FlagType.Data16Bit); + + for (int i = 0; i < 0x20; i++) + flags.Add(romSettingsOffset + 11 + i, Data.FlagType.Pointer16Bit); + + if (romBytes[romSettingsOffset - 1] == 0) { - flags.Remove(offset - 1); - flags.Add(offset - 1, Data.FlagType.Data8Bit); - for (int i = 0; i < 0x10; i++) flags.Add(offset - 0x25 + i, Data.FlagType.Data8Bit); + flags.Remove(romSettingsOffset - 1); + flags.Add(romSettingsOffset - 1, Data.FlagType.Data8Bit); + for (int i = 0; i < 0x10; i++) + flags.Add(romSettingsOffset - 0x25 + i, Data.FlagType.Data8Bit); } - else if (romBytes[offset + 5] == 0x33) + else if (romBytes[romSettingsOffset + 5] == 0x33) { - for (int i = 0; i < 6; i++) flags.Add(offset - 0x25 + i, Data.FlagType.Text); - for (int i = 0; i < 10; i++) flags.Add(offset - 0x1F + i, Data.FlagType.Data8Bit); + for (int i = 0; i < 6; i++) + flags.Add(romSettingsOffset - 0x25 + i, Data.FlagType.Text); + + for (int i = 0; i < 10; i++) + flags.Add(romSettingsOffset - 0x1F + i, Data.FlagType.Data8Bit); } } diff --git a/DiztinGUIsh/loadsave/ImportSettings.cs b/DiztinGUIsh/loadsave/ImportSettings.cs index 7ef2c448..b195b835 100644 --- a/DiztinGUIsh/loadsave/ImportSettings.cs +++ b/DiztinGUIsh/loadsave/ImportSettings.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using DiztinGUIsh.core; using DiztinGUIsh.core.util; namespace DiztinGUIsh.loadsave diff --git a/DiztinGUIsh/loadsave/ProjectFileManager.cs b/DiztinGUIsh/loadsave/ProjectFileManager.cs index 4b44e3e7..bf787cab 100644 --- a/DiztinGUIsh/loadsave/ProjectFileManager.cs +++ b/DiztinGUIsh/loadsave/ProjectFileManager.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.IO; using System.Windows.Forms; +using DiztinGUIsh.core; using DiztinGUIsh.loadsave.binary_serializer_old; using DiztinGUIsh.loadsave.xml_serializer; diff --git a/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs b/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs index a4b18a65..126add10 100644 --- a/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs +++ b/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs @@ -6,6 +6,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using DiztinGUIsh.core; using DiztinGUIsh.core.util; using DiztinGUIsh.window; diff --git a/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs b/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs index c112876a..7f4524fb 100644 --- a/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs +++ b/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs @@ -3,6 +3,7 @@ using System.Reflection; using System.Text; using System.Xml; +using DiztinGUIsh.core; using DiztinGUIsh.core.util; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; diff --git a/DiztinGUIsh/loadsave/xml_serializer/RomBytesXMLSerializer.cs b/DiztinGUIsh/loadsave/xml_serializer/RomBytesXMLSerializer.cs index 8f2c134c..df486655 100644 --- a/DiztinGUIsh/loadsave/xml_serializer/RomBytesXMLSerializer.cs +++ b/DiztinGUIsh/loadsave/xml_serializer/RomBytesXMLSerializer.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.IO; using System.Linq; +using DiztinGUIsh.core; using ExtendedXmlSerializer.ContentModel; using ExtendedXmlSerializer.ContentModel.Format; diff --git a/DiztinGUIsh/window/AliasList.cs b/DiztinGUIsh/window/AliasList.cs index f0a979cf..379fd9c6 100644 --- a/DiztinGUIsh/window/AliasList.cs +++ b/DiztinGUIsh/window/AliasList.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Text.RegularExpressions; using System.Windows.Forms; +using DiztinGUIsh.core; namespace DiztinGUIsh.window { diff --git a/DiztinGUIsh/window/GuiUtil.cs b/DiztinGUIsh/window/GuiUtil.cs index 229ea84c..dc22f992 100644 --- a/DiztinGUIsh/window/GuiUtil.cs +++ b/DiztinGUIsh/window/GuiUtil.cs @@ -1,12 +1,5 @@ using System; -using System.Collections.Generic; using System.ComponentModel; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; namespace DiztinGUIsh.window @@ -28,24 +21,50 @@ public static void InvokeIfRequired(this ISynchronizeInvoke obj, MethodInvoker a public static string PromptToSelectFile(string initialDirectory = null) { - var open = new OpenFileDialog { InitialDirectory = initialDirectory }; + var open = new OpenFileDialog {InitialDirectory = initialDirectory}; return open.ShowDialog() == DialogResult.OK ? open.FileName : null; } - public static string AskIfWeShouldSelectFilename(string promptSubject, string promptText, Func confirmAction) + // prompt the user to confirm they'd like to do something. if yes, call 'confirmAction' + public static T PromptToConfirmAction(string promptSubject, string promptText, Func confirmAction) { - var dialogResult = MessageBox.Show(promptText, promptSubject, - MessageBoxButtons.YesNo, MessageBoxIcon.Error); + var dialogResult = + MessageBox.Show(promptText, promptSubject, MessageBoxButtons.YesNo, MessageBoxIcon.Error); - return dialogResult == DialogResult.Yes ? confirmAction() : null; + return dialogResult == DialogResult.Yes ? confirmAction() : default; } - public static string GetDescription(this Enum value) + /// + /// Generate data bindings so that a combobox control will populate from an enum list + /// Shortcut for doing these actions manually. + /// + /// + public static void BindListControlToEnum(ComboBox cb, object boundObject, string propertyName) + where TEnum : Enum { - var valueStr = value.ToString(); - var field = value.GetType().GetField(valueStr); - var attribs = field.GetCustomAttributes(typeof(DescriptionAttribute), true); - return attribs.Length > 0 ? ((DescriptionAttribute)attribs[0]).Description : valueStr; + // I feel like there's gotta be a better way to do all this. But, I can live with this for now. + // + // future improvements: would be great if we didn't have to pass in a string, and instead passed + // in a property meta-info that we could generate the string value from. + + // take an enum type and create a list of each member, with the enum as the key, and anything in a [Description] attribute as the value + var enumValuesAndDescriptionsKvp = Util.GetEnumDescriptions(); + var bs = new BindingSource(enumValuesAndDescriptionsKvp, null); + + BindListControlToEnum(cb, boundObject, propertyName, bs); + } + + private static void BindListControlToEnum(ComboBox cb, object boundObject, string propertyName, + BindingSource bs) + { + cb.DataBindings.Add(new Binding( + "SelectedValue", boundObject, + propertyName, false, + DataSourceUpdateMode.OnPropertyChanged)); + + cb.DataSource = bs; + cb.DisplayMember = "Value"; + cb.ValueMember = "Key"; } } -} +} \ No newline at end of file diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 2ea64e92..b67ed95a 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -5,6 +5,7 @@ using System.Globalization; using System.IO; using System.Windows.Forms; +using DiztinGUIsh.core; using DiztinGUIsh.core.util; using DiztinGUIsh.loadsave; using DiztinGUIsh.Properties; @@ -14,8 +15,6 @@ namespace DiztinGUIsh { public partial class MainWindow : Form, IProjectView { - // temp: readonly project data model. eventually, get this ONLY from the controller. - // right now, it returns Project2 which will go away public Project Project { get; set; } public MainWindow() @@ -43,8 +42,6 @@ private void ProjectController_ProjectChanged(object sender, ProjectController.P case ProjectController.ProjectChangedEventArgs.ProjectChangedType.Imported: OnImportedProjectSuccess(); break; - default: - throw new ArgumentOutOfRangeException(); } } @@ -618,7 +615,7 @@ private void table_CellValueNeeded(object sender, DataGridViewCellValueEventArgs else e.Value = ""; break; case 7: - e.Value = RomUtil.TypeToString(Project.Data.GetFlag(row)); + e.Value = Util.GetEnumDescription(Project.Data.GetFlag(row)); break; case 8: e.Value = Util.NumberToBaseString(Project.Data.GetDataBank(row), Util.NumberBase.Hexadecimal, 2); @@ -1236,7 +1233,7 @@ private void toolStripOpenLast_Click(object sender, EventArgs e) public string AskToSelectNewRomFilename(string promptSubject, string promptText) { - return GuiUtil.AskIfWeShouldSelectFilename(promptSubject, promptText, + return GuiUtil.PromptToConfirmAction(promptSubject, promptText, () => GuiUtil.PromptToSelectFile(Project.ProjectFileName) ); } diff --git a/DiztinGUIsh/window/dialog/ExportDisassembly.cs b/DiztinGUIsh/window/dialog/ExportDisassembly.cs index f63d4cf1..82203fb0 100644 --- a/DiztinGUIsh/window/dialog/ExportDisassembly.cs +++ b/DiztinGUIsh/window/dialog/ExportDisassembly.cs @@ -2,6 +2,7 @@ using System.IO; using System.Text; using System.Windows.Forms; +using DiztinGUIsh.core; namespace DiztinGUIsh { diff --git a/DiztinGUIsh/window/dialog/GotoDialog.cs b/DiztinGUIsh/window/dialog/GotoDialog.cs index fa69b269..68c3632e 100644 --- a/DiztinGUIsh/window/dialog/GotoDialog.cs +++ b/DiztinGUIsh/window/dialog/GotoDialog.cs @@ -8,6 +8,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using DiztinGUIsh.core; using DiztinGUIsh.core.util; namespace DiztinGUIsh diff --git a/DiztinGUIsh/window/dialog/HarshAutoStep.cs b/DiztinGUIsh/window/dialog/HarshAutoStep.cs index c02613c6..c34a5492 100644 --- a/DiztinGUIsh/window/dialog/HarshAutoStep.cs +++ b/DiztinGUIsh/window/dialog/HarshAutoStep.cs @@ -9,6 +9,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using DiztinGUIsh.core; namespace DiztinGUIsh { diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs b/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs index 72b46ca9..9d49ca61 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs @@ -31,16 +31,10 @@ private void InitializeComponent() System.Windows.Forms.Label sourceLabel; this.detectMessage = new System.Windows.Forms.Label(); this.checkData = new System.Windows.Forms.Label(); - this.label4 = new System.Windows.Forms.Label(); - this.label5 = new System.Windows.Forms.Label(); this.cancel = new System.Windows.Forms.Button(); this.okay = new System.Windows.Forms.Button(); - this.romspeed = new System.Windows.Forms.Label(); - this.romtitle = new System.Windows.Forms.Label(); this.label3 = new System.Windows.Forms.Label(); this.label6 = new System.Windows.Forms.Label(); - this.groupBox1 = new System.Windows.Forms.GroupBox(); - this.cmbRomMapMode = new System.Windows.Forms.ComboBox(); this.groupBox2 = new System.Windows.Forms.GroupBox(); this.label13 = new System.Windows.Forms.Label(); this.checkboxEmuIRQ = new System.Windows.Forms.CheckBox(); @@ -76,62 +70,42 @@ private void InitializeComponent() this.label2 = new System.Windows.Forms.Label(); this.label1 = new System.Windows.Forms.Label(); this.checkHeader = new System.Windows.Forms.CheckBox(); + this.label14 = new System.Windows.Forms.Label(); + this.romspeed = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.romtitle = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.cmbRomMapMode = new System.Windows.Forms.ComboBox(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); sourceLabel = new System.Windows.Forms.Label(); - this.groupBox1.SuspendLayout(); this.groupBox2.SuspendLayout(); + this.groupBox1.SuspendLayout(); this.SuspendLayout(); // - // sourceLabel - // - sourceLabel.AutoSize = true; - sourceLabel.Location = new System.Drawing.Point(14, 22); - sourceLabel.Name = "sourceLabel"; - sourceLabel.Size = new System.Drawing.Size(83, 13); - sourceLabel.TabIndex = 5; - sourceLabel.Text = "Rom Map Mode"; - // // detectMessage // this.detectMessage.AutoSize = true; - this.detectMessage.Location = new System.Drawing.Point(36, 7); + this.detectMessage.Location = new System.Drawing.Point(123, 7); this.detectMessage.Name = "detectMessage"; - this.detectMessage.Size = new System.Drawing.Size(187, 13); + this.detectMessage.Size = new System.Drawing.Size(85, 13); this.detectMessage.TabIndex = 0; - this.detectMessage.Text = "Couldn\'t auto detect ROM Map Mode!"; + this.detectMessage.Text = "[detectedStatus]"; this.detectMessage.TextAlign = System.Drawing.ContentAlignment.TopCenter; // // checkData // this.checkData.AutoSize = true; - this.checkData.Location = new System.Drawing.Point(39, 23); + this.checkData.Location = new System.Drawing.Point(39, 29); this.checkData.Name = "checkData"; this.checkData.Size = new System.Drawing.Size(179, 13); this.checkData.TabIndex = 1; this.checkData.Text = "Does the following info look correct?"; this.checkData.TextAlign = System.Drawing.ContentAlignment.TopCenter; // - // label4 - // - this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(31, 44); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(69, 13); - this.label4.TabIndex = 2; - this.label4.Text = "ROM Speed:"; - // - // label5 - // - this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(34, 66); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(66, 13); - this.label5.TabIndex = 4; - this.label5.Text = "ROM Name:"; - // // cancel // this.cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.cancel.Location = new System.Drawing.Point(12, 388); + this.cancel.Location = new System.Drawing.Point(12, 394); this.cancel.Name = "cancel"; this.cancel.Size = new System.Drawing.Size(75, 23); this.cancel.TabIndex = 8; @@ -142,7 +116,7 @@ private void InitializeComponent() // // okay // - this.okay.Location = new System.Drawing.Point(172, 388); + this.okay.Location = new System.Drawing.Point(172, 394); this.okay.Name = "okay"; this.okay.Size = new System.Drawing.Size(75, 23); this.okay.TabIndex = 7; @@ -150,28 +124,10 @@ private void InitializeComponent() this.okay.UseVisualStyleBackColor = true; this.okay.Click += new System.EventHandler(this.okay_Click); // - // romspeed - // - this.romspeed.AutoSize = true; - this.romspeed.Location = new System.Drawing.Point(103, 44); - this.romspeed.Name = "romspeed"; - this.romspeed.Size = new System.Drawing.Size(55, 13); - this.romspeed.TabIndex = 3; - this.romspeed.Text = "SlowROM"; - // - // romtitle - // - this.romtitle.AutoSize = true; - this.romtitle.Location = new System.Drawing.Point(103, 66); - this.romtitle.Name = "romtitle"; - this.romtitle.Size = new System.Drawing.Size(27, 13); - this.romtitle.TabIndex = 5; - this.romtitle.Text = "Title"; - // // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(32, 39); + this.label3.Location = new System.Drawing.Point(32, 45); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(198, 13); this.label3.TabIndex = 2; @@ -181,36 +137,13 @@ private void InitializeComponent() // label6 // this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(3, 55); + this.label6.Location = new System.Drawing.Point(3, 61); this.label6.Name = "label6"; this.label6.Size = new System.Drawing.Size(255, 13); this.label6.TabIndex = 3; this.label6.Text = "This cannot be changed once the project is created."; this.label6.TextAlign = System.Drawing.ContentAlignment.TopCenter; // - // groupBox1 - // - this.groupBox1.Controls.Add(this.cmbRomMapMode); - this.groupBox1.Controls.Add(sourceLabel); - this.groupBox1.Controls.Add(this.label4); - this.groupBox1.Controls.Add(this.romtitle); - this.groupBox1.Controls.Add(this.label5); - this.groupBox1.Controls.Add(this.romspeed); - this.groupBox1.Location = new System.Drawing.Point(12, 74); - this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(374, 257); - this.groupBox1.TabIndex = 4; - this.groupBox1.TabStop = false; - this.groupBox1.Text = "ROM Information"; - // - // cmbRomMapMode - // - this.cmbRomMapMode.FormattingEnabled = true; - this.cmbRomMapMode.Location = new System.Drawing.Point(102, 18); - this.cmbRomMapMode.Name = "cmbRomMapMode"; - this.cmbRomMapMode.Size = new System.Drawing.Size(142, 21); - this.cmbRomMapMode.TabIndex = 6; - // // groupBox2 // this.groupBox2.Controls.Add(this.label13); @@ -246,9 +179,9 @@ private void InitializeComponent() this.groupBox2.Controls.Add(this.label7); this.groupBox2.Controls.Add(this.label2); this.groupBox2.Controls.Add(this.label1); - this.groupBox2.Location = new System.Drawing.Point(12, 169); + this.groupBox2.Location = new System.Drawing.Point(12, 175); this.groupBox2.Name = "groupBox2"; - this.groupBox2.Size = new System.Drawing.Size(235, 189); + this.groupBox2.Size = new System.Drawing.Size(244, 189); this.groupBox2.TabIndex = 5; this.groupBox2.TabStop = false; this.groupBox2.Text = "Vectors @ $00FFE0"; @@ -256,7 +189,7 @@ private void InitializeComponent() // label13 // this.label13.AutoSize = true; - this.label13.Location = new System.Drawing.Point(10, 168); + this.label13.Location = new System.Drawing.Point(15, 174); this.label13.Name = "label13"; this.label13.Size = new System.Drawing.Size(214, 13); this.label13.TabIndex = 32; @@ -266,7 +199,7 @@ private void InitializeComponent() // checkboxEmuIRQ // this.checkboxEmuIRQ.AutoSize = true; - this.checkboxEmuIRQ.Location = new System.Drawing.Point(197, 146); + this.checkboxEmuIRQ.Location = new System.Drawing.Point(197, 152); this.checkboxEmuIRQ.Name = "checkboxEmuIRQ"; this.checkboxEmuIRQ.Size = new System.Drawing.Size(15, 14); this.checkboxEmuIRQ.TabIndex = 31; @@ -277,7 +210,7 @@ private void InitializeComponent() this.checkboxEmuRESET.AutoSize = true; this.checkboxEmuRESET.Checked = true; this.checkboxEmuRESET.CheckState = System.Windows.Forms.CheckState.Checked; - this.checkboxEmuRESET.Location = new System.Drawing.Point(197, 124); + this.checkboxEmuRESET.Location = new System.Drawing.Point(197, 130); this.checkboxEmuRESET.Name = "checkboxEmuRESET"; this.checkboxEmuRESET.Size = new System.Drawing.Size(15, 14); this.checkboxEmuRESET.TabIndex = 29; @@ -286,7 +219,7 @@ private void InitializeComponent() // checkboxEmuNMI // this.checkboxEmuNMI.AutoSize = true; - this.checkboxEmuNMI.Location = new System.Drawing.Point(197, 102); + this.checkboxEmuNMI.Location = new System.Drawing.Point(197, 108); this.checkboxEmuNMI.Name = "checkboxEmuNMI"; this.checkboxEmuNMI.Size = new System.Drawing.Size(15, 14); this.checkboxEmuNMI.TabIndex = 27; @@ -295,7 +228,7 @@ private void InitializeComponent() // checkboxEmuABORT // this.checkboxEmuABORT.AutoSize = true; - this.checkboxEmuABORT.Location = new System.Drawing.Point(197, 80); + this.checkboxEmuABORT.Location = new System.Drawing.Point(197, 86); this.checkboxEmuABORT.Name = "checkboxEmuABORT"; this.checkboxEmuABORT.Size = new System.Drawing.Size(15, 14); this.checkboxEmuABORT.TabIndex = 25; @@ -304,7 +237,7 @@ private void InitializeComponent() // checkboxEmuBRK // this.checkboxEmuBRK.AutoSize = true; - this.checkboxEmuBRK.Location = new System.Drawing.Point(197, 58); + this.checkboxEmuBRK.Location = new System.Drawing.Point(197, 64); this.checkboxEmuBRK.Name = "checkboxEmuBRK"; this.checkboxEmuBRK.Size = new System.Drawing.Size(15, 14); this.checkboxEmuBRK.TabIndex = 23; @@ -313,7 +246,7 @@ private void InitializeComponent() // checkboxEmuCOP // this.checkboxEmuCOP.AutoSize = true; - this.checkboxEmuCOP.Location = new System.Drawing.Point(197, 36); + this.checkboxEmuCOP.Location = new System.Drawing.Point(197, 42); this.checkboxEmuCOP.Name = "checkboxEmuCOP"; this.checkboxEmuCOP.Size = new System.Drawing.Size(15, 14); this.checkboxEmuCOP.TabIndex = 21; @@ -324,7 +257,7 @@ private void InitializeComponent() this.checkboxNativeIRQ.AutoSize = true; this.checkboxNativeIRQ.Checked = true; this.checkboxNativeIRQ.CheckState = System.Windows.Forms.CheckState.Checked; - this.checkboxNativeIRQ.Location = new System.Drawing.Point(120, 146); + this.checkboxNativeIRQ.Location = new System.Drawing.Point(120, 152); this.checkboxNativeIRQ.Name = "checkboxNativeIRQ"; this.checkboxNativeIRQ.Size = new System.Drawing.Size(15, 14); this.checkboxNativeIRQ.TabIndex = 19; @@ -333,7 +266,7 @@ private void InitializeComponent() // checkboxNativeRESET // this.checkboxNativeRESET.AutoSize = true; - this.checkboxNativeRESET.Location = new System.Drawing.Point(120, 124); + this.checkboxNativeRESET.Location = new System.Drawing.Point(120, 130); this.checkboxNativeRESET.Name = "checkboxNativeRESET"; this.checkboxNativeRESET.Size = new System.Drawing.Size(15, 14); this.checkboxNativeRESET.TabIndex = 17; @@ -344,7 +277,7 @@ private void InitializeComponent() this.checkboxNativeNMI.AutoSize = true; this.checkboxNativeNMI.Checked = true; this.checkboxNativeNMI.CheckState = System.Windows.Forms.CheckState.Checked; - this.checkboxNativeNMI.Location = new System.Drawing.Point(120, 102); + this.checkboxNativeNMI.Location = new System.Drawing.Point(120, 108); this.checkboxNativeNMI.Name = "checkboxNativeNMI"; this.checkboxNativeNMI.Size = new System.Drawing.Size(15, 14); this.checkboxNativeNMI.TabIndex = 15; @@ -353,7 +286,7 @@ private void InitializeComponent() // checkboxNativeABORT // this.checkboxNativeABORT.AutoSize = true; - this.checkboxNativeABORT.Location = new System.Drawing.Point(120, 80); + this.checkboxNativeABORT.Location = new System.Drawing.Point(120, 86); this.checkboxNativeABORT.Name = "checkboxNativeABORT"; this.checkboxNativeABORT.Size = new System.Drawing.Size(15, 14); this.checkboxNativeABORT.TabIndex = 13; @@ -364,7 +297,7 @@ private void InitializeComponent() this.checkboxNativeBRK.AutoSize = true; this.checkboxNativeBRK.Checked = true; this.checkboxNativeBRK.CheckState = System.Windows.Forms.CheckState.Checked; - this.checkboxNativeBRK.Location = new System.Drawing.Point(120, 58); + this.checkboxNativeBRK.Location = new System.Drawing.Point(120, 64); this.checkboxNativeBRK.Name = "checkboxNativeBRK"; this.checkboxNativeBRK.Size = new System.Drawing.Size(15, 14); this.checkboxNativeBRK.TabIndex = 11; @@ -375,7 +308,7 @@ private void InitializeComponent() this.checkboxNativeCOP.AutoSize = true; this.checkboxNativeCOP.Checked = true; this.checkboxNativeCOP.CheckState = System.Windows.Forms.CheckState.Checked; - this.checkboxNativeCOP.Location = new System.Drawing.Point(120, 36); + this.checkboxNativeCOP.Location = new System.Drawing.Point(120, 42); this.checkboxNativeCOP.Name = "checkboxNativeCOP"; this.checkboxNativeCOP.Size = new System.Drawing.Size(15, 14); this.checkboxNativeCOP.TabIndex = 9; @@ -384,7 +317,7 @@ private void InitializeComponent() // label12 // this.label12.AutoSize = true; - this.label12.Location = new System.Drawing.Point(158, 17); + this.label12.Location = new System.Drawing.Point(158, 23); this.label12.Name = "label12"; this.label12.Size = new System.Drawing.Size(53, 13); this.label12.TabIndex = 1; @@ -393,7 +326,7 @@ private void InitializeComponent() // label11 // this.label11.AutoSize = true; - this.label11.Location = new System.Drawing.Point(86, 17); + this.label11.Location = new System.Drawing.Point(86, 23); this.label11.Name = "label11"; this.label11.Size = new System.Drawing.Size(38, 13); this.label11.TabIndex = 0; @@ -401,7 +334,7 @@ private void InitializeComponent() // // textEmuIRQ // - this.textEmuIRQ.Location = new System.Drawing.Point(156, 143); + this.textEmuIRQ.Location = new System.Drawing.Point(156, 149); this.textEmuIRQ.MaxLength = 4; this.textEmuIRQ.Name = "textEmuIRQ"; this.textEmuIRQ.ReadOnly = true; @@ -412,7 +345,7 @@ private void InitializeComponent() // // textEmuRESET // - this.textEmuRESET.Location = new System.Drawing.Point(156, 121); + this.textEmuRESET.Location = new System.Drawing.Point(156, 127); this.textEmuRESET.MaxLength = 4; this.textEmuRESET.Name = "textEmuRESET"; this.textEmuRESET.ReadOnly = true; @@ -423,7 +356,7 @@ private void InitializeComponent() // // textEmuNMI // - this.textEmuNMI.Location = new System.Drawing.Point(156, 99); + this.textEmuNMI.Location = new System.Drawing.Point(156, 105); this.textEmuNMI.MaxLength = 4; this.textEmuNMI.Name = "textEmuNMI"; this.textEmuNMI.ReadOnly = true; @@ -434,7 +367,7 @@ private void InitializeComponent() // // textEmuABORT // - this.textEmuABORT.Location = new System.Drawing.Point(156, 77); + this.textEmuABORT.Location = new System.Drawing.Point(156, 83); this.textEmuABORT.MaxLength = 4; this.textEmuABORT.Name = "textEmuABORT"; this.textEmuABORT.ReadOnly = true; @@ -445,7 +378,7 @@ private void InitializeComponent() // // textEmuBRK // - this.textEmuBRK.Location = new System.Drawing.Point(156, 55); + this.textEmuBRK.Location = new System.Drawing.Point(156, 61); this.textEmuBRK.MaxLength = 4; this.textEmuBRK.Name = "textEmuBRK"; this.textEmuBRK.ReadOnly = true; @@ -456,7 +389,7 @@ private void InitializeComponent() // // textEmuCOP // - this.textEmuCOP.Location = new System.Drawing.Point(156, 33); + this.textEmuCOP.Location = new System.Drawing.Point(156, 39); this.textEmuCOP.MaxLength = 4; this.textEmuCOP.Name = "textEmuCOP"; this.textEmuCOP.ReadOnly = true; @@ -467,7 +400,7 @@ private void InitializeComponent() // // textNativeIRQ // - this.textNativeIRQ.Location = new System.Drawing.Point(79, 143); + this.textNativeIRQ.Location = new System.Drawing.Point(79, 149); this.textNativeIRQ.MaxLength = 4; this.textNativeIRQ.Name = "textNativeIRQ"; this.textNativeIRQ.ReadOnly = true; @@ -478,7 +411,7 @@ private void InitializeComponent() // // textNativeRESET // - this.textNativeRESET.Location = new System.Drawing.Point(79, 121); + this.textNativeRESET.Location = new System.Drawing.Point(79, 127); this.textNativeRESET.MaxLength = 4; this.textNativeRESET.Name = "textNativeRESET"; this.textNativeRESET.ReadOnly = true; @@ -489,7 +422,7 @@ private void InitializeComponent() // // textNativeNMI // - this.textNativeNMI.Location = new System.Drawing.Point(79, 99); + this.textNativeNMI.Location = new System.Drawing.Point(79, 105); this.textNativeNMI.MaxLength = 4; this.textNativeNMI.Name = "textNativeNMI"; this.textNativeNMI.ReadOnly = true; @@ -500,7 +433,7 @@ private void InitializeComponent() // // textNativeABORT // - this.textNativeABORT.Location = new System.Drawing.Point(79, 77); + this.textNativeABORT.Location = new System.Drawing.Point(79, 83); this.textNativeABORT.MaxLength = 4; this.textNativeABORT.Name = "textNativeABORT"; this.textNativeABORT.ReadOnly = true; @@ -511,7 +444,7 @@ private void InitializeComponent() // // textNativeBRK // - this.textNativeBRK.Location = new System.Drawing.Point(79, 55); + this.textNativeBRK.Location = new System.Drawing.Point(79, 61); this.textNativeBRK.MaxLength = 4; this.textNativeBRK.Name = "textNativeBRK"; this.textNativeBRK.ReadOnly = true; @@ -522,7 +455,7 @@ private void InitializeComponent() // // textNativeCOP // - this.textNativeCOP.Location = new System.Drawing.Point(79, 33); + this.textNativeCOP.Location = new System.Drawing.Point(79, 39); this.textNativeCOP.MaxLength = 4; this.textNativeCOP.Name = "textNativeCOP"; this.textNativeCOP.ReadOnly = true; @@ -534,7 +467,7 @@ private void InitializeComponent() // label10 // this.label10.AutoSize = true; - this.label10.Location = new System.Drawing.Point(41, 146); + this.label10.Location = new System.Drawing.Point(41, 152); this.label10.Name = "label10"; this.label10.Size = new System.Drawing.Size(26, 13); this.label10.TabIndex = 7; @@ -543,7 +476,7 @@ private void InitializeComponent() // label9 // this.label9.AutoSize = true; - this.label9.Location = new System.Drawing.Point(25, 124); + this.label9.Location = new System.Drawing.Point(25, 130); this.label9.Name = "label9"; this.label9.Size = new System.Drawing.Size(43, 13); this.label9.TabIndex = 6; @@ -552,7 +485,7 @@ private void InitializeComponent() // label8 // this.label8.AutoSize = true; - this.label8.Location = new System.Drawing.Point(40, 102); + this.label8.Location = new System.Drawing.Point(40, 108); this.label8.Name = "label8"; this.label8.Size = new System.Drawing.Size(27, 13); this.label8.TabIndex = 5; @@ -561,7 +494,7 @@ private void InitializeComponent() // label7 // this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(24, 80); + this.label7.Location = new System.Drawing.Point(24, 86); this.label7.Name = "label7"; this.label7.Size = new System.Drawing.Size(44, 13); this.label7.TabIndex = 4; @@ -570,7 +503,7 @@ private void InitializeComponent() // label2 // this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(38, 58); + this.label2.Location = new System.Drawing.Point(38, 64); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(29, 13); this.label2.TabIndex = 3; @@ -579,7 +512,7 @@ private void InitializeComponent() // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(39, 36); + this.label1.Location = new System.Drawing.Point(39, 42); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(29, 13); this.label1.TabIndex = 2; @@ -590,20 +523,98 @@ private void InitializeComponent() this.checkHeader.AutoSize = true; this.checkHeader.Checked = true; this.checkHeader.CheckState = System.Windows.Forms.CheckState.Checked; - this.checkHeader.Location = new System.Drawing.Point(12, 365); + this.checkHeader.Location = new System.Drawing.Point(12, 371); this.checkHeader.Name = "checkHeader"; this.checkHeader.Size = new System.Drawing.Size(237, 17); this.checkHeader.TabIndex = 6; this.checkHeader.Text = "Auto generate flags for Internal ROM Header"; this.checkHeader.UseVisualStyleBackColor = true; // + // label14 + // + this.label14.AutoSize = true; + this.label14.Location = new System.Drawing.Point(9, 7); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(112, 13); + this.label14.TabIndex = 9; + this.label14.Text = "Detected Rom Mode: "; + // + // romspeed + // + this.romspeed.AutoSize = true; + this.romspeed.Location = new System.Drawing.Point(103, 50); + this.romspeed.Name = "romspeed"; + this.romspeed.Size = new System.Drawing.Size(55, 13); + this.romspeed.TabIndex = 3; + this.romspeed.Text = "SlowROM"; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(34, 72); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(66, 13); + this.label5.TabIndex = 4; + this.label5.Text = "ROM Name:"; + // + // romtitle + // + this.romtitle.AutoSize = true; + this.romtitle.Location = new System.Drawing.Point(103, 72); + this.romtitle.Name = "romtitle"; + this.romtitle.Size = new System.Drawing.Size(27, 13); + this.romtitle.TabIndex = 5; + this.romtitle.Text = "Title"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(31, 50); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(69, 13); + this.label4.TabIndex = 2; + this.label4.Text = "ROM Speed:"; + // + // sourceLabel + // + sourceLabel.AutoSize = true; + sourceLabel.Location = new System.Drawing.Point(14, 28); + sourceLabel.Name = "sourceLabel"; + sourceLabel.Size = new System.Drawing.Size(83, 13); + sourceLabel.TabIndex = 5; + sourceLabel.Text = "Rom Map Mode"; + // + // cmbRomMapMode + // + this.cmbRomMapMode.FormattingEnabled = true; + this.cmbRomMapMode.Location = new System.Drawing.Point(102, 24); + this.cmbRomMapMode.Name = "cmbRomMapMode"; + this.cmbRomMapMode.Size = new System.Drawing.Size(142, 21); + this.cmbRomMapMode.TabIndex = 6; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.cmbRomMapMode); + this.groupBox1.Controls.Add(sourceLabel); + this.groupBox1.Controls.Add(this.label4); + this.groupBox1.Controls.Add(this.romtitle); + this.groupBox1.Controls.Add(this.label5); + this.groupBox1.Controls.Add(this.romspeed); + this.groupBox1.Location = new System.Drawing.Point(12, 80); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(246, 89); + this.groupBox1.TabIndex = 4; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "ROM Information"; + // // ImportRomDialog // this.AcceptButton = this.okay; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.cancel; - this.ClientSize = new System.Drawing.Size(262, 424); + this.ClientSize = new System.Drawing.Size(272, 424); + this.Controls.Add(this.label14); this.Controls.Add(this.checkHeader); this.Controls.Add(this.groupBox2); this.Controls.Add(this.groupBox1); @@ -620,10 +631,10 @@ private void InitializeComponent() this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "New Project"; this.Load += new System.EventHandler(this.ImportROMDialog_Load); - this.groupBox1.ResumeLayout(false); - this.groupBox1.PerformLayout(); this.groupBox2.ResumeLayout(false); this.groupBox2.PerformLayout(); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -633,15 +644,10 @@ private void InitializeComponent() private System.Windows.Forms.Label detectMessage; private System.Windows.Forms.Label checkData; - private System.Windows.Forms.Label label4; - private System.Windows.Forms.Label label5; private System.Windows.Forms.Button cancel; private System.Windows.Forms.Button okay; - private System.Windows.Forms.Label romspeed; - private System.Windows.Forms.Label romtitle; private System.Windows.Forms.Label label3; private System.Windows.Forms.Label label6; - private System.Windows.Forms.GroupBox groupBox1; private System.Windows.Forms.GroupBox groupBox2; private System.Windows.Forms.Label label13; private System.Windows.Forms.CheckBox checkboxEmuIRQ; @@ -677,6 +683,12 @@ private void InitializeComponent() private System.Windows.Forms.Label label2; private System.Windows.Forms.Label label1; private System.Windows.Forms.CheckBox checkHeader; + private System.Windows.Forms.Label label14; + private System.Windows.Forms.Label romspeed; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label romtitle; + private System.Windows.Forms.Label label4; private System.Windows.Forms.ComboBox cmbRomMapMode; + private System.Windows.Forms.GroupBox groupBox1; } } \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.cs b/DiztinGUIsh/window/dialog/ImportROMDialog.cs index 6f932d8d..38341935 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.Diagnostics; using System.Windows.Forms; +using DiztinGUIsh.core; using DiztinGUIsh.core.util; using DiztinGUIsh.loadsave; @@ -10,159 +11,121 @@ namespace DiztinGUIsh.window.dialog { public partial class ImportRomDialog : Form { - public ImportRomSettings ImportSettings { get; protected set; } - public bool romTypeNotDetectedCorrectly = true; - - public class EnumMapper where TEnum : Enum + // NOTE: all this could be converted to use databinding and be easier to deal with, but, + // probably more work than its worth. this is fine, if a bit manual. it's unlikely to ever need to change. + private CheckBox[,] GetVectorsCheckboxes() => new[,] { - public TEnum Source { get; set; } - - // surely... there is some third party library that handles this. - // for now, here we are. - public int SelectedIndex - { - get => Convert.ToInt32(Source); - set => Source = (TEnum)Enum.ToObject(typeof(TEnum), value); - } - - public List> Descriptions { get; } - = Util.GetEnumDescriptions(); - } - - // hey. maybe we don't explicitly need this. - /*public class ImportRomViewModel + {checkboxNativeCOP, checkboxNativeBRK, checkboxNativeABORT, checkboxNativeNMI, checkboxNativeRESET, checkboxNativeIRQ}, + {checkboxEmuCOP, checkboxEmuBRK, checkboxEmuABORT, checkboxEmuNMI, checkboxEmuRESET, checkboxEmuIRQ}, + }; + private TextBox[,] GetVectorsTextBoxes() => new[,] { - private readonly ImportRomSettings settings; - - public EnumMapper RomMapMode { get; } = new EnumMapper(); - - public ImportRomViewModel(ImportRomSettings settingsDataSource) - { - Debug.Assert(settingsDataSource != null); - settings = settingsDataSource; - - settingsDataSource.PropertyChanged += (sender, args) => - { - RomMapMode.Source = settingsDataSource.ROMMapMode; - }; - } - }*/ - - - public string title; - public int RomSettingsOffset; + {textNativeCOP, textNativeBRK, textNativeABORT, textNativeNMI, textNativeRESET, textNativeIRQ}, + {textEmuCOP, textEmuBRK, textEmuABORT, textEmuNMI, textEmuRESET, textEmuIRQ}, + }; private readonly string[,] vectorNames = { - { "Native_COP", "Native_BRK", "Native_ABORT", "Native_NMI", "Native_RESET", "Native_IRQ"}, - { "Emulation_COP", "Emulation_Unknown", "Emulation_ABORT", "Emulation_NMI", "Emulation_RESET", "Emulation_IRQBRK"} + {"Native_COP", "Native_BRK", "Native_ABORT", "Native_NMI", "Native_RESET", "Native_IRQ"}, + {"Emulation_COP", "Emulation_Unknown", "Emulation_ABORT", "Emulation_NMI", "Emulation_RESET", "Emulation_IRQBRK"} }; private readonly TextBox[,] vectors; private readonly CheckBox[,] checkboxes; + public ImportRomSettings ImportSettings { get; protected set; } + private int RomSettingsOffset = -1; + private Data.ROMMapMode? DetectedMapMode = null; + public ImportRomDialog() { InitializeComponent(); - vectors = new[,] - { - { textNativeCOP, textNativeBRK, textNativeABORT, textNativeNMI, textNativeRESET, textNativeIRQ }, - { textEmuCOP, textEmuBRK, textEmuABORT, textEmuNMI, textEmuRESET, textEmuIRQ }, - }; - checkboxes = new[,] - { - { checkboxNativeCOP, checkboxNativeBRK, checkboxNativeABORT, checkboxNativeNMI, checkboxNativeRESET, checkboxNativeIRQ }, - { checkboxEmuCOP, checkboxEmuBRK, checkboxEmuABORT, checkboxEmuNMI, checkboxEmuRESET, checkboxEmuIRQ }, - }; + vectors = GetVectorsTextBoxes(); + checkboxes = GetVectorsCheckboxes(); } - public ImportRomSettings PromptForImportSettings(string filename) + private void DataBind() { - CreateRomImportSettingsFor(filename); + Debug.Assert(ImportSettings != null); + GuiUtil.BindListControlToEnum(cmbRomMapMode, ImportSettings, "ROMMapMode"); + ImportSettings.PropertyChanged += ImportSettingsOnPropertyChanged; + } + public ImportRomSettings PromptForImportSettings(string filename) + { + CreateNewRomImportSettingsFor(filename); DataBind(); - - // UpdateUiFromRomMapDetection(); - UpdateOffsetAndSpeed(); + UpdateUI(); if (ShowDialog() != DialogResult.OK) return null; - ImportSettings.InitialLabels = GetGeneratedLabels(); - ImportSettings.InitialHeaderFlags = GetHeaderFlags(); + ImportSettings.PropertyChanged -= ImportSettingsOnPropertyChanged; + ImportSettings.InitialLabels = GenerateVectorLabels(); + ImportSettings.InitialHeaderFlags = GenerateHeaderFlags(); return ImportSettings; } - private void DataBind() - { - var enumValuesAndDescriptionsKVP = Util.GetEnumDescriptions(); - var bs = new BindingSource(enumValuesAndDescriptionsKVP, null); - bs.CurrentChanged += Bs_CurrentChanged; - - // var bs = new BindingSource(ImportViewModel.RomMapMode.Descriptions, null); - - cmbRomMapMode.DataBindings.Add(new Binding( - "SelectedValue", ImportSettings, - "ROMMapMode", false, - DataSourceUpdateMode.OnPropertyChanged)); - - cmbRomMapMode.DataSource = bs; - cmbRomMapMode.DisplayMember = "Value"; - cmbRomMapMode.ValueMember = "Key"; // names of properties of each item on datasource. - } - - private void Bs_CurrentChanged(object sender, EventArgs e) + private void ImportSettingsOnPropertyChanged(object sender, PropertyChangedEventArgs e) { UpdateUI(); } - private void UpdateUI() - { - UpdateOffsetAndSpeed(); - UpdateTextboxes(); - } - - //ImportRomViewModel ImportViewModel; - - private void CreateRomImportSettingsFor(string filename) + private void CreateNewRomImportSettingsFor(string filename) { var romBytes = RomUtil.ReadAllRomBytesFromFile(filename); ImportSettings = new ImportRomSettings { RomFilename = filename, RomBytes = romBytes, - ROMMapMode = RomUtil.DetectROMMapMode(romBytes, out romTypeNotDetectedCorrectly) + ROMMapMode = RomUtil.DetectROMMapMode(romBytes, out var detectedMapModeSuccess) }; - //ImportViewModel = new ImportRomViewModel(ImportSettings); + if (detectedMapModeSuccess) + { + DetectedMapMode = ImportSettings.ROMMapMode; + detectMessage.Text = Util.GetEnumDescription(ImportSettings.ROMMapMode); + } + else + { + detectMessage.Text = "Couldn't auto detect ROM Map Mode!"; + } + } + + private void UpdateUI() + { + UpdateOffsetAndSpeed(); + UpdateTextboxes(); } - private Dictionary GetGeneratedLabels() + private Dictionary GenerateVectorLabels() { + // TODO: bounds check that generated addresses are inside the rom. + var labels = new Dictionary(); - + for (int i = 0; i < checkboxes.GetLength(0); i++) { for (int j = 0; j < checkboxes.GetLength(1); j++) { - if (!checkboxes[i, j].Checked) + if (!checkboxes[i, j].Checked) continue; int index = RomSettingsOffset + 15 + 0x10 * i + 2 * j; - int val = ImportSettings.RomBytes[index] + (ImportSettings.RomBytes[index + 1] << 8); - int pc = RomUtil.ConvertSNESToPC(val, ImportSettings.ROMMapMode, ImportSettings.RomBytes.Length); - if (pc >= 0 && pc < ImportSettings.RomBytes.Length && !labels.ContainsKey(val)) - labels.Add(val, new Label() {name = vectorNames[i, j]}); + int offset = ImportSettings.RomBytes[index] + (ImportSettings.RomBytes[index + 1] << 8); + int pc = RomUtil.ConvertSNESToPC(offset, ImportSettings.ROMMapMode, ImportSettings.RomBytes.Length); + if (pc >= 0 && pc < ImportSettings.RomBytes.Length && !labels.ContainsKey(offset)) + labels.Add(offset, new Label() {name = vectorNames[i, j]}); } } return labels; } - private Dictionary GetHeaderFlags() + private Dictionary GenerateHeaderFlags() { var flags = new Dictionary(); - if (checkHeader.Checked) - RomUtil.GetHeaderFlags(RomSettingsOffset, flags, ImportSettings.RomBytes); + if (checkHeader.Checked) + RomUtil.GenerateHeaderFlags(RomSettingsOffset, flags, ImportSettings.RomBytes); return flags; } @@ -170,24 +133,22 @@ private Dictionary GetGeneratedLabels() private void UpdateOffsetAndSpeed() { RomSettingsOffset = RomUtil.GetRomSettingOffset(ImportSettings.ROMMapMode); - var romSpeed = ImportSettings.ROMSpeed; - var romBytes = ImportSettings.RomBytes; - - romSpeed = RomUtil.GetRomSpeed(RomSettingsOffset, romBytes); + ImportSettings.ROMSpeed = RomUtil.GetRomSpeed(RomSettingsOffset, ImportSettings.RomBytes); - okay.Enabled = ImportSettings.ROMSpeed != Data.ROMSpeed.Unknown; + UpdateOkayButtonEnabled(); } - private bool IsOffsetInRange(int offset, int count = 0) + private void UpdateOkayButtonEnabled() { - return offset > 0 && offset <= ImportSettings.RomBytes.Length; + okay.Enabled = ImportSettings.ROMSpeed != Data.ROMSpeed.Unknown; } - + private void UpdateTextboxes() { if (IsProbablyValidDetection()) { - try { + try + { UpdateDetectedValues(); return; } @@ -200,10 +161,13 @@ private void UpdateTextboxes() SetDefaultsIfDetectionFailed(); } + private bool IsOffsetInRange(int offset, int count = 0) => + offset > 0 && offset <= ImportSettings.RomBytes.Length; + private bool IsProbablyValidDetection() { - return - ImportSettings.ROMSpeed != Data.ROMSpeed.Unknown && + return + ImportSettings.ROMSpeed != Data.ROMSpeed.Unknown && IsOffsetInRange(RomSettingsOffset); } @@ -211,26 +175,21 @@ private void SetDefaultsIfDetectionFailed() { romspeed.Text = "????"; romtitle.Text = "?????????????????????"; - for (int i = 0; i < vectors.GetLength(0); i++) - for (int j = 0; j < vectors.GetLength(1); j++) + for (var i = 0; i < vectors.GetLength(0); i++) + for (var j = 0; j < vectors.GetLength(1); j++) vectors[i, j].Text = "????"; - return; } private void UpdateDetectedValues() { // caution: things can go wrong here if we didn't guess settings correctly, // you usually want to call this function with a try/catch around it. - - var romspeedStr = ImportSettings.ROMSpeed == Data.ROMSpeed.SlowROM ? "SlowROM" : "FastROM"; - var romTitleName = RomUtil.GetRomTitleName(ImportSettings.RomBytes, RomSettingsOffset); - - for (int i = 0; i < vectors.GetLength(0); i++) + for (var i = 0; i < vectors.GetLength(0); i++) { - for (int j = 0; j < vectors.GetLength(1); j++) + for (var j = 0; j < vectors.GetLength(1); j++) { - int index = RomSettingsOffset + 15 + 0x10 * i + 2 * j; - int val = ImportSettings.RomBytes[index] + (ImportSettings.RomBytes[index + 1] << 8); + var index = RomSettingsOffset + 15 + 0x10 * i + 2 * j; + var val = ImportSettings.RomBytes[index] + (ImportSettings.RomBytes[index + 1] << 8); vectors[i, j].Text = Util.NumberToBaseString(val, Util.NumberBase.Hexadecimal, 4); if (val < 0x8000) @@ -244,80 +203,46 @@ private void UpdateDetectedValues() } } } + var romSpeedStr = Util.GetEnumDescription(ImportSettings.ROMSpeed); + var romTitleName = RomUtil.GetRomTitleName(ImportSettings.RomBytes, RomSettingsOffset); - romspeed.Text = romspeedStr; + romspeed.Text = romSpeedStr; romtitle.Text = romTitleName; } - private void ImportROMDialog_Load(object sender, EventArgs e) - { - UpdateTextboxes(); - } - - private void okay_Click(object sender, EventArgs e) { DialogResult = DialogResult.OK; } + private void ImportROMDialog_Load(object sender, EventArgs e) => UpdateUI(); - private void cancel_Click(object sender, EventArgs e) { Close(); } - - private void cmbRomMapMode_SelectedIndexChanged(object sender, EventArgs e) + private void okay_Click(object sender, EventArgs e) { + static bool Warn(string msg) + { + return PromptToConfirmAction(msg + + "\nIf you proceed with this import, settings might be wrong.\n" + + "Proceed anyway?\n\n (Experts only, otherwise say No here and fix import settings)"); + } - } + if (!DetectedMapMode.HasValue) + { + if (!Warn("ROM Map type couldn't be detected.")) + return; + } else if (DetectedMapMode.Value != ImportSettings.ROMMapMode) { + if (!Warn("The ROM map type selected is different than what was detected.")) + return; + } + SetFinished(); + } - /*private Data.ROMMapMode SelectRomMapModeFromUi(int selectedIndex) + private static bool PromptToConfirmAction(string msg) { - // TODO: there's definitely a better way. Databinding, or use a dict at worst. - var mode = selectedIndex switch - { - 0 => Data.ROMMapMode.LoROM, - 1 => Data.ROMMapMode.HiROM, - 2 => Data.ROMMapMode.SuperMMC, - 3 => Data.ROMMapMode.SA1ROM, - 4 => Data.ROMMapMode.ExSA1ROM, - 5 => Data.ROMMapMode.SuperFX, - 6 => Data.ROMMapMode.ExHiROM, - 7 => Data.ROMMapMode.ExLoROM, - _ => ImportSettings.ROMMapMode - }; - return mode; + return GuiUtil.PromptToConfirmAction("Warning", msg, () => true); } - private void UpdateUiFromRomMapDetection() + private void SetFinished() { - if (romTypeNotDetectedCorrectly) - detectMessage.Text = "Couldn't auto detect ROM Map Mode!"; - else - detectMessage.Text = "ROM Map Mode Detected: " + RomUtil.GetRomMapModeName(ImportSettings.ROMMapMode); + DialogResult = DialogResult.OK; + } - // TODO: there's definitely a better way. probably have the control read from a data table, - // then have it update itself based on the value of importSettings.ROMMapMode. - switch (ImportSettings.ROMMapMode) - { - case Data.ROMMapMode.LoROM: - comboBox1.SelectedIndex = 0; - break; - case Data.ROMMapMode.HiROM: - comboBox1.SelectedIndex = 1; - break; - case Data.ROMMapMode.SuperMMC: - comboBox1.SelectedIndex = 2; - break; - case Data.ROMMapMode.SA1ROM: - comboBox1.SelectedIndex = 3; - break; - case Data.ROMMapMode.ExSA1ROM: - comboBox1.SelectedIndex = 4; - break; - case Data.ROMMapMode.SuperFX: - comboBox1.SelectedIndex = 5; - break; - case Data.ROMMapMode.ExHiROM: - comboBox1.SelectedIndex = 6; - break; - case Data.ROMMapMode.ExLoROM: - comboBox1.SelectedIndex = 7; - break; - } - }*/ + private void cancel_Click(object sender, EventArgs e) => Close(); } -} +} \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/MarkManyDialog.cs b/DiztinGUIsh/window/dialog/MarkManyDialog.cs index 9b1ca8cf..c05cac8d 100644 --- a/DiztinGUIsh/window/dialog/MarkManyDialog.cs +++ b/DiztinGUIsh/window/dialog/MarkManyDialog.cs @@ -8,6 +8,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using DiztinGUIsh.core; namespace DiztinGUIsh { diff --git a/DiztinGUIsh/window/dialog/MisalignmentChecker.cs b/DiztinGUIsh/window/dialog/MisalignmentChecker.cs index 735dcc19..42c11591 100644 --- a/DiztinGUIsh/window/dialog/MisalignmentChecker.cs +++ b/DiztinGUIsh/window/dialog/MisalignmentChecker.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using DiztinGUIsh.core; using DiztinGUIsh.core.util; namespace DiztinGUIsh @@ -51,8 +52,8 @@ private void buttonScan_Click(object sender, EventArgs e) textLog.Text += string.Format("{0} (0x{1}): {2} is not {3}\r\n", Util.NumberToBaseString(Data.ConvertPCtoSNES(offset + i), Util.NumberBase.Hexadecimal, 6, true), Util.NumberToBaseString(offset + i, Util.NumberBase.Hexadecimal, 0), - RomUtil.TypeToString(Data.GetFlag(offset + i)), - RomUtil.TypeToString(check)); + Util.GetEnumDescription(Data.GetFlag(offset + i)), + Util.GetEnumDescription(check)); } } } diff --git a/DiztinGUIsh/window/dialog/TestForm.cs b/DiztinGUIsh/window/dialog/TestForm.cs index 4ee14fa2..2823bc26 100644 --- a/DiztinGUIsh/window/dialog/TestForm.cs +++ b/DiztinGUIsh/window/dialog/TestForm.cs @@ -1,5 +1,6 @@ using System; using System.Windows.Forms; +using DiztinGUIsh.core; using DiztinGUIsh.loadsave; namespace DiztinGUIsh.window.dialog From 63147fc4d8f4dda045272307810249cd8baa89ef Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 3 Oct 2020 18:57:30 -0400 Subject: [PATCH 054/136] basically done with the ROM importer overhaul --- DiztinGUIsh/DiztinGUIsh.csproj | 2 + DiztinGUIsh/core/Data.cs | 3 + DiztinGUIsh/core/import/BSNESUsageMap.cs | 13 ++ DiztinGUIsh/core/util/RomUtil.cs | 51 ++++-- DiztinGUIsh/window/IProjectView.cs | 2 + DiztinGUIsh/window/MainWindow.cs | 77 +++----- DiztinGUIsh/window/ProjectController.cs | 17 +- .../window/dialog/ImportROMDialog.Designer.cs | 20 ++- DiztinGUIsh/window/dialog/ImportROMDialog.cs | 167 ++++++++---------- .../dialog/ImportROMDialogController.cs | 100 +++++++++++ 10 files changed, 286 insertions(+), 166 deletions(-) create mode 100644 DiztinGUIsh/core/import/BSNESUsageMap.cs create mode 100644 DiztinGUIsh/window/dialog/ImportROMDialogController.cs diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 0406f05a..f8fc6faf 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -112,6 +112,7 @@ + @@ -125,6 +126,7 @@ + Form diff --git a/DiztinGUIsh/core/Data.cs b/DiztinGUIsh/core/Data.cs index dba2bd2c..c8dd7ff1 100644 --- a/DiztinGUIsh/core/Data.cs +++ b/DiztinGUIsh/core/Data.cs @@ -30,8 +30,11 @@ public enum FlagType : byte public enum Architecture : byte { + [Description("65C816")] CPU65C816 = 0x00, + [Description("SPC700")] APUSPC700 = 0x01, + [Description("SuperFX")] GPUSuperFX = 0x02 } diff --git a/DiztinGUIsh/core/import/BSNESUsageMap.cs b/DiztinGUIsh/core/import/BSNESUsageMap.cs new file mode 100644 index 00000000..bb56a1c7 --- /dev/null +++ b/DiztinGUIsh/core/import/BSNESUsageMap.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DiztinGUIsh.core.import +{ + class BSNESUsageMapImporter + { + + } +} diff --git a/DiztinGUIsh/core/util/RomUtil.cs b/DiztinGUIsh/core/util/RomUtil.cs index a4eae585..9640574e 100644 --- a/DiztinGUIsh/core/util/RomUtil.cs +++ b/DiztinGUIsh/core/util/RomUtil.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics; using System.IO; namespace DiztinGUIsh.core.util @@ -177,6 +178,7 @@ public static int UnmirroredOffset(int offset, int size) return repeatedOffset; } + // TODO: these can be attributes on the enum itself. like [AsmLabel("UNREACH")] public static string TypeToLabel(Data.FlagType flag) { return flag switch @@ -261,17 +263,6 @@ public static int GetRomSettingOffset(Data.ROMMapMode mode) }; } - public static string ArchToString(Data.Architecture arch) - { - return arch switch - { - Data.Architecture.CPU65C816 => "65C816", - Data.Architecture.APUSPC700 => "SPC700", - Data.Architecture.GPUSuperFX => "SuperFX", - _ => "" - }; - } - public static string PointToString(Data.InOutPoint point) { string result; @@ -352,6 +343,44 @@ public static void GenerateHeaderFlags(int romSettingsOffset, IDictionary GenerateVectorLabels(Dictionary vectorNames, int romSettingsOffset, IReadOnlyList romBytes, Data.ROMMapMode mode) + { + // TODO: probably better to just use a data structure for this instead of generating the + // offsets with table/entry vars + + var labels = new Dictionary(); + + var baseOffset = romSettingsOffset + 15; + + var table = 0; const int tableCount = 2; + var entry = 0; const int entryCount = 6; + foreach (var vectorEntry in vectorNames) + { + Debug.Assert(table >= 0 && table < tableCount); + Debug.Assert(entry >= 0 && entry < entryCount); + // table = 0,1 // which table of Native vs Emulation + // entry = 0,1,2,3,4,5 // which offset + // + // 16*i = 16,32, + + var index = baseOffset + (16 * table) + (2 * entry); + var offset = romBytes[index] + (romBytes[index + 1] << 8); + var pc = ConvertSNESToPC(offset, mode, romBytes.Count); + if (pc >= 0 && pc < romBytes.Count && !labels.ContainsKey(offset)) + labels.Add(offset, new Label() { name = vectorEntry.Key }); + + if (++entry < entryCount) + continue; + + entry = 0; + if (++table >= tableCount) + break; + } + + return labels; + } + public const int LengthOfTitleName = 0x15; } } diff --git a/DiztinGUIsh/window/IProjectView.cs b/DiztinGUIsh/window/IProjectView.cs index edc66609..d6389c9d 100644 --- a/DiztinGUIsh/window/IProjectView.cs +++ b/DiztinGUIsh/window/IProjectView.cs @@ -1,4 +1,5 @@ using System; +using DiztinGUIsh.window.dialog; namespace DiztinGUIsh { @@ -13,5 +14,6 @@ public interface IProjectView LongRunningTaskHandler TaskHandler { get; } void SelectOffset(int offset, int column=-1); string AskToSelectNewRomFilename(string promptSubject, string promptText); + IImportRomDialogView GetImportView(); } } diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index b67ed95a..a684d29d 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -1,13 +1,11 @@ using DiztinGUIsh.window; using System; -using System.ComponentModel; using System.Drawing; using System.Globalization; using System.IO; using System.Windows.Forms; using DiztinGUIsh.core; using DiztinGUIsh.core.util; -using DiztinGUIsh.loadsave; using DiztinGUIsh.Properties; using DiztinGUIsh.window.dialog; @@ -96,10 +94,10 @@ private void MainWindow_Load(object sender, EventArgs e) UpdateUIFromSettings(); if (Settings.Default.OpenLastFileAutomatically) - openLastProject(); + OpenLastProject(); } - private void openLastProject() + private void OpenLastProject() { if (LastProjectFilename == "") return; @@ -132,10 +130,10 @@ private bool ContinueUnsavedChanges() } - public void UpdateSaveOptionStates(bool save, bool saveas) + public void UpdateSaveOptionStates(bool saveEnabled, bool saveAsEnabled) { - saveProjectToolStripMenuItem.Enabled = save; - saveProjectAsToolStripMenuItem.Enabled = saveas; + saveProjectToolStripMenuItem.Enabled = saveEnabled; + saveProjectAsToolStripMenuItem.Enabled = saveAsEnabled; exportLogToolStripMenuItem.Enabled = true; } @@ -148,43 +146,16 @@ private void newProjectToolStripMenuItem_Click(object sender, EventArgs e) if (string.IsNullOrEmpty(romFilename)) return; - if (!TryImportProject(openFileDialog.FileName)) - return; - - OnImportedProjectSuccess(); + ProjectController.ImportRomAndCreateNewProject(openFileDialog.FileName); } private string PromptForOpenFilename() { - // TODO: combine with another function in Project that looks like this + // TODO: combine with another function in Project that feels similar to this openFileDialog.InitialDirectory = Project?.ProjectFileName ?? ""; return openFileDialog.ShowDialog() == DialogResult.OK ? openFileDialog.FileName : null; } - private bool TryImportProject(string romFileToOpen) - { - //try // temp remove this for debuggin. - //{ - var importSettings = PromptForImportSettings(romFileToOpen); - if (importSettings == null) - return false; - - ProjectController.ImportRomAndCreateNewProject(importSettings); - return true; - //} - //catch (Exception ex) - //{ - // MessageBox.Show(ex.Message, "Error importing project", MessageBoxButtons.OK, MessageBoxIcon.Error); - //} - - return false; - } - - private static ImportRomSettings PromptForImportSettings(string romFileToOpen) - { - return new ImportRomDialog().PromptForImportSettings(romFileToOpen); - } - private void openProjectToolStripMenuItem_Click(object sender, EventArgs e) { if (!ContinueUnsavedChanges()) @@ -197,7 +168,7 @@ private void openProjectToolStripMenuItem_Click(object sender, EventArgs e) OpenProject(openProjectFile.FileName); } - // TODO: state change needs to go in controller + // TODO: state change should be moved into the controller public string LastProjectFilename { get => Settings.Default.LastOpenedFile; @@ -212,7 +183,7 @@ public string LastProjectFilename private void UpdateUIFromSettings() { - bool lastOpenedFilePresent = Settings.Default.LastOpenedFile != ""; + var lastOpenedFilePresent = Settings.Default.LastOpenedFile != ""; toolStripOpenLast.Enabled = lastOpenedFilePresent; toolStripOpenLast.Text = "Open Last File"; if (lastOpenedFilePresent) @@ -250,7 +221,6 @@ public void OnProjectOpenFail() LastProjectFilename = ""; } - public void OpenProject(string filename) { ProjectController.OpenProject(filename); @@ -297,9 +267,11 @@ private void saveProjectAsToolStripMenuItem_Click(object sender, EventArgs e) private void importCDLToolStripMenuItem_Click(object sender, EventArgs e) { openCDLDialog.InitialDirectory = Project.ProjectFileName; - DialogResult result = openCDLDialog.ShowDialog(); - if (result != DialogResult.OK) return; - if (!ContinueUnsavedChanges()) return; + if (openCDLDialog.ShowDialog() != DialogResult.OK) + return; + + if (!ContinueUnsavedChanges()) + return; var filename = openCDLDialog.FileName; @@ -431,6 +403,13 @@ public void InvalidateTable() // DataGridView + // TODO: add a handler so we get notified when CurrentViewOffset changes. + // then, we split most of our functions up into + // 1. things that change ViewOffset + // 2. things that react to ViewOffset changes. + // + // This will allow more flexibility and synchronizing different views (i.e. main table, graphics, layout, etc) + // and this lets us save this value with the project file itself. private int ViewOffset { get => Project?.CurrentViewOffset ?? 0; @@ -466,7 +445,7 @@ private void table_MouseWheel(object sender, MouseEventArgs e) if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; int selRow = table.CurrentCell.RowIndex + ViewOffset, selCol = table.CurrentCell.ColumnIndex; - int amount = e.Delta / 0x18; + var amount = e.Delta / 0x18; ViewOffset -= amount; UpdateDataGridView(); if (selRow < ViewOffset) selRow = ViewOffset; @@ -1164,11 +1143,6 @@ private void moveWithStepToolStripMenuItem_Click(object sender, EventArgs e) moveWithStepToolStripMenuItem.Checked = MoveWithStep; } - public OpenFileDialog GetRomOpenFileDialog() - { - return openFileDialog; - } - // sub windows public AliasList aliasList; @@ -1228,7 +1202,7 @@ private void openLastProjectAutomaticallyToolStripMenuItem_Click(object sender, private void toolStripOpenLast_Click(object sender, EventArgs e) { - openLastProject(); + OpenLastProject(); } public string AskToSelectNewRomFilename(string promptSubject, string promptText) @@ -1237,5 +1211,10 @@ public string AskToSelectNewRomFilename(string promptSubject, string promptText) () => GuiUtil.PromptToSelectFile(Project.ProjectFileName) ); } + + public IImportRomDialogView GetImportView() + { + return new ImportRomDialog(); + } } } \ No newline at end of file diff --git a/DiztinGUIsh/window/ProjectController.cs b/DiztinGUIsh/window/ProjectController.cs index 7cdbb722..a513c438 100644 --- a/DiztinGUIsh/window/ProjectController.cs +++ b/DiztinGUIsh/window/ProjectController.cs @@ -2,6 +2,7 @@ using System.ComponentModel; using System.IO; using DiztinGUIsh.loadsave; +using DiztinGUIsh.window.dialog; namespace DiztinGUIsh.window { @@ -92,6 +93,20 @@ public void ImportBizHawkCDL(string filename) }); } + public bool ImportRomAndCreateNewProject(string ROMFilename) + { + // let the user select settings on the GUI + var importController = new ImportROMDialogController {View = ProjectView.GetImportView()}; + importController.View.Controller = importController; + var importSettings = importController.PromptUserForRomSettings(ROMFilename); + if (importSettings == null) + return false; + + // actually do the import + ImportRomAndCreateNewProject(importSettings); + return true; + } + public void ImportRomAndCreateNewProject(ImportRomSettings importSettings) { var project = ProjectFileManager.ImportRomAndCreateNewProject(importSettings); @@ -132,7 +147,7 @@ private void WriteAssemblyOutput(LogWriterSettings settings) public void UpdateExportSettings(LogWriterSettings selectedSettings) { - // TODO: ref readonly or similar here, to save us an extra copy of the struct. + // TODO: ref readonly or similar here, to save us an extra copy of the struct? Project.LogWriterSettings = selectedSettings; } diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs b/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs index 9d49ca61..413b3155 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.Designer.cs @@ -82,6 +82,15 @@ private void InitializeComponent() this.groupBox1.SuspendLayout(); this.SuspendLayout(); // + // sourceLabel + // + sourceLabel.AutoSize = true; + sourceLabel.Location = new System.Drawing.Point(14, 28); + sourceLabel.Name = "sourceLabel"; + sourceLabel.Size = new System.Drawing.Size(83, 13); + sourceLabel.TabIndex = 5; + sourceLabel.Text = "Rom Map Mode"; + // // detectMessage // this.detectMessage.AutoSize = true; @@ -529,6 +538,7 @@ private void InitializeComponent() this.checkHeader.TabIndex = 6; this.checkHeader.Text = "Auto generate flags for Internal ROM Header"; this.checkHeader.UseVisualStyleBackColor = true; + this.checkHeader.CheckedChanged += new System.EventHandler(this.checkHeader_CheckedChanged); // // label14 // @@ -575,15 +585,6 @@ private void InitializeComponent() this.label4.TabIndex = 2; this.label4.Text = "ROM Speed:"; // - // sourceLabel - // - sourceLabel.AutoSize = true; - sourceLabel.Location = new System.Drawing.Point(14, 28); - sourceLabel.Name = "sourceLabel"; - sourceLabel.Size = new System.Drawing.Size(83, 13); - sourceLabel.TabIndex = 5; - sourceLabel.Text = "Rom Map Mode"; - // // cmbRomMapMode // this.cmbRomMapMode.FormattingEnabled = true; @@ -630,6 +631,7 @@ private void InitializeComponent() this.ShowInTaskbar = false; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "New Project"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ImportRomDialog_FormClosing); this.Load += new System.EventHandler(this.ImportROMDialog_Load); this.groupBox2.ResumeLayout(false); this.groupBox2.PerformLayout(); diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.cs b/DiztinGUIsh/window/dialog/ImportROMDialog.cs index 38341935..face4672 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; +using System.Security; using System.Windows.Forms; using DiztinGUIsh.core; using DiztinGUIsh.core.util; @@ -9,7 +10,7 @@ namespace DiztinGUIsh.window.dialog { - public partial class ImportRomDialog : Form + public partial class ImportRomDialog : Form, IImportRomDialogView { // NOTE: all this could be converted to use databinding and be easier to deal with, but, // probably more work than its worth. this is fine, if a bit manual. it's unlikely to ever need to change. @@ -23,20 +24,30 @@ public partial class ImportRomDialog : Form {textNativeCOP, textNativeBRK, textNativeABORT, textNativeNMI, textNativeRESET, textNativeIRQ}, {textEmuCOP, textEmuBRK, textEmuABORT, textEmuNMI, textEmuRESET, textEmuIRQ}, }; - private readonly string[,] vectorNames = { - {"Native_COP", "Native_BRK", "Native_ABORT", "Native_NMI", "Native_RESET", "Native_IRQ"}, - {"Emulation_COP", "Emulation_Unknown", "Emulation_ABORT", "Emulation_NMI", "Emulation_RESET", "Emulation_IRQBRK"} - }; private readonly TextBox[,] vectors; private readonly CheckBox[,] checkboxes; - public ImportRomSettings ImportSettings { get; protected set; } - private int RomSettingsOffset = -1; - private Data.ROMMapMode? DetectedMapMode = null; + private ImportROMDialogController controller; + public ImportROMDialogController Controller + { + get => controller; + set + { + if (controller != null) + controller.SettingsCreated -= Controller_SettingsCreated; + + controller = value; + + if (controller != null) + controller.SettingsCreated += Controller_SettingsCreated; + } + } + public ImportRomSettings ImportSettings => Controller?.ImportSettings; public ImportRomDialog() { InitializeComponent(); + vectors = GetVectorsTextBoxes(); checkboxes = GetVectorsCheckboxes(); } @@ -45,97 +56,65 @@ private void DataBind() { Debug.Assert(ImportSettings != null); GuiUtil.BindListControlToEnum(cmbRomMapMode, ImportSettings, "ROMMapMode"); + + checkHeader.Checked = Controller.ShouldCheckHeader; // todo: databind this instead. ImportSettings.PropertyChanged += ImportSettingsOnPropertyChanged; } - public ImportRomSettings PromptForImportSettings(string filename) + public bool ShowAndWaitForUserToConfirmSettings() { - CreateNewRomImportSettingsFor(filename); - DataBind(); - UpdateUI(); - - if (ShowDialog() != DialogResult.OK) - return null; - - ImportSettings.PropertyChanged -= ImportSettingsOnPropertyChanged; - ImportSettings.InitialLabels = GenerateVectorLabels(); - ImportSettings.InitialHeaderFlags = GenerateHeaderFlags(); - - return ImportSettings; + return ShowDialog() == DialogResult.OK; } - private void ImportSettingsOnPropertyChanged(object sender, PropertyChangedEventArgs e) + private void Controller_SettingsCreated() { - UpdateUI(); + DataBind(); + RefreshUI(); } - private void CreateNewRomImportSettingsFor(string filename) + private void ImportSettingsOnPropertyChanged(object sender, PropertyChangedEventArgs e) { - var romBytes = RomUtil.ReadAllRomBytesFromFile(filename); - ImportSettings = new ImportRomSettings - { - RomFilename = filename, - RomBytes = romBytes, - ROMMapMode = RomUtil.DetectROMMapMode(romBytes, out var detectedMapModeSuccess) - }; - - if (detectedMapModeSuccess) - { - DetectedMapMode = ImportSettings.ROMMapMode; - detectMessage.Text = Util.GetEnumDescription(ImportSettings.ROMMapMode); - } - else - { - detectMessage.Text = "Couldn't auto detect ROM Map Mode!"; - } + RefreshUI(); } - private void UpdateUI() + private void RefreshUI() { UpdateOffsetAndSpeed(); UpdateTextboxes(); + UpdateOkayButtonEnabled(); + detectMessage.Text = GetDetectionMessage(); + UpdateVectorTable(); } - private Dictionary GenerateVectorLabels() + private string GetDetectionMessage() => + Controller.DetectedMapMode.HasValue ? Util.GetEnumDescription(ImportSettings.ROMMapMode) : "Couldn't auto detect ROM Map Mode!"; + + public void UpdateVectorTable() { - // TODO: bounds check that generated addresses are inside the rom. + // it'd probably be easier to just setup a lookup table for this stuff + // it's probably also better to databind all this, but might be complex. this is OK for now. - var labels = new Dictionary(); + string[,] vectorNames = { + {"Native_COP", "Native_BRK", "Native_ABORT", "Native_NMI", "Native_RESET", "Native_IRQ"}, + {"Emulation_COP", "Emulation_Unknown", "Emulation_ABORT", "Emulation_NMI", "Emulation_RESET", "Emulation_IRQBRK"} + }; - for (int i = 0; i < checkboxes.GetLength(0); i++) + Controller.VectorTableEntriesEnabled.Clear(); + Debug.Assert(checkboxes.GetLength(0) == vectorNames.GetLength(0)); + Debug.Assert(checkboxes.GetLength(1) == vectorNames.GetLength(1)); + for (var i = 0; i < checkboxes.GetLength(0); i++) { - for (int j = 0; j < checkboxes.GetLength(1); j++) + for (var j = 0; j < checkboxes.GetLength(1); j++) { - if (!checkboxes[i, j].Checked) - continue; - - int index = RomSettingsOffset + 15 + 0x10 * i + 2 * j; - int offset = ImportSettings.RomBytes[index] + (ImportSettings.RomBytes[index + 1] << 8); - int pc = RomUtil.ConvertSNESToPC(offset, ImportSettings.ROMMapMode, ImportSettings.RomBytes.Length); - if (pc >= 0 && pc < ImportSettings.RomBytes.Length && !labels.ContainsKey(offset)) - labels.Add(offset, new Label() {name = vectorNames[i, j]}); + Controller.VectorTableEntriesEnabled.Add(vectorNames[i, j], checkboxes[i,j].Checked); } } - - return labels; - } - - private Dictionary GenerateHeaderFlags() - { - var flags = new Dictionary(); - - if (checkHeader.Checked) - RomUtil.GenerateHeaderFlags(RomSettingsOffset, flags, ImportSettings.RomBytes); - - return flags; } private void UpdateOffsetAndSpeed() { - RomSettingsOffset = RomUtil.GetRomSettingOffset(ImportSettings.ROMMapMode); - ImportSettings.ROMSpeed = RomUtil.GetRomSpeed(RomSettingsOffset, ImportSettings.RomBytes); - - UpdateOkayButtonEnabled(); + Controller.RomSettingsOffset = RomUtil.GetRomSettingOffset(ImportSettings.ROMMapMode); + ImportSettings.ROMSpeed = RomUtil.GetRomSpeed(Controller.RomSettingsOffset, ImportSettings.RomBytes); } private void UpdateOkayButtonEnabled() @@ -164,12 +143,8 @@ private void UpdateTextboxes() private bool IsOffsetInRange(int offset, int count = 0) => offset > 0 && offset <= ImportSettings.RomBytes.Length; - private bool IsProbablyValidDetection() - { - return - ImportSettings.ROMSpeed != Data.ROMSpeed.Unknown && - IsOffsetInRange(RomSettingsOffset); - } + private bool IsProbablyValidDetection() => + ImportSettings.ROMSpeed != Data.ROMSpeed.Unknown && IsOffsetInRange(Controller.RomSettingsOffset); private void SetDefaultsIfDetectionFailed() { @@ -188,7 +163,7 @@ private void UpdateDetectedValues() { for (var j = 0; j < vectors.GetLength(1); j++) { - var index = RomSettingsOffset + 15 + 0x10 * i + 2 * j; + var index = Controller.RomSettingsOffset + 15 + 0x10 * i + 2 * j; var val = ImportSettings.RomBytes[index] + (ImportSettings.RomBytes[index + 1] << 8); vectors[i, j].Text = Util.NumberToBaseString(val, Util.NumberBase.Hexadecimal, 4); @@ -204,36 +179,23 @@ private void UpdateDetectedValues() } } var romSpeedStr = Util.GetEnumDescription(ImportSettings.ROMSpeed); - var romTitleName = RomUtil.GetRomTitleName(ImportSettings.RomBytes, RomSettingsOffset); + var romTitleName = RomUtil.GetRomTitleName(ImportSettings.RomBytes, Controller.RomSettingsOffset); romspeed.Text = romSpeedStr; romtitle.Text = romTitleName; } - private void ImportROMDialog_Load(object sender, EventArgs e) => UpdateUI(); + private void ImportROMDialog_Load(object sender, EventArgs e) => RefreshUI(); private void okay_Click(object sender, EventArgs e) { - static bool Warn(string msg) - { - return PromptToConfirmAction(msg + - "\nIf you proceed with this import, settings might be wrong.\n" + - "Proceed anyway?\n\n (Experts only, otherwise say No here and fix import settings)"); - } - - if (!DetectedMapMode.HasValue) - { - if (!Warn("ROM Map type couldn't be detected.")) - return; - } else if (DetectedMapMode.Value != ImportSettings.ROMMapMode) { - if (!Warn("The ROM map type selected is different than what was detected.")) - return; - } + if (!Controller.Submit()) + return; SetFinished(); } - private static bool PromptToConfirmAction(string msg) + public bool PromptToConfirmAction(string msg) { return GuiUtil.PromptToConfirmAction("Warning", msg, () => true); } @@ -244,5 +206,18 @@ private void SetFinished() } private void cancel_Click(object sender, EventArgs e) => Close(); + + private void checkHeader_CheckedChanged(object sender, EventArgs e) + { + Controller.ShouldCheckHeader = checkHeader.Checked; // todo: databind this instead. + } + + private void ImportRomDialog_FormClosing(object sender, FormClosingEventArgs e) + { + if (ImportSettings != null) + ImportSettings.PropertyChanged -= ImportSettingsOnPropertyChanged; + + Controller = null; + } } } \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/ImportROMDialogController.cs b/DiztinGUIsh/window/dialog/ImportROMDialogController.cs new file mode 100644 index 00000000..417cbc67 --- /dev/null +++ b/DiztinGUIsh/window/dialog/ImportROMDialogController.cs @@ -0,0 +1,100 @@ +using System.Collections.Generic; +using DiztinGUIsh.core; +using DiztinGUIsh.core.util; +using DiztinGUIsh.loadsave; + +namespace DiztinGUIsh.window.dialog +{ + public interface IImportRomDialogView + { + bool PromptToConfirmAction(string msg); + bool ShowAndWaitForUserToConfirmSettings(); + ImportROMDialogController Controller { get; set; } + } + + public class ImportROMDialogController + { + public IImportRomDialogView View { get; set; } + public ImportRomSettings ImportSettings { get; protected set; } + public Data.ROMMapMode? DetectedMapMode { get; protected set; } + + public int RomSettingsOffset { get; set; }= -1; + public bool ShouldCheckHeader { get; set; } = true; + public Dictionary VectorTableEntriesEnabled { get; set; } = new Dictionary(); + + public delegate void SettingsCreatedEvent(); + public event SettingsCreatedEvent SettingsCreated; + + public ImportRomSettings PromptUserForRomSettings(string romFilename) + { + CreateSettingsFromRom(romFilename); + + var shouldContinue = View.ShowAndWaitForUserToConfirmSettings(); + if (!shouldContinue) + return null; + + ImportSettings.InitialLabels = GenerateVectorLabels(); + ImportSettings.InitialHeaderFlags = GenerateHeaderFlags(); + + return ImportSettings; + } + + public void CreateSettingsFromRom(string filename) + { + var romBytes = RomUtil.ReadAllRomBytesFromFile(filename); + ImportSettings = new ImportRomSettings + { + RomFilename = filename, + RomBytes = romBytes, + ROMMapMode = RomUtil.DetectROMMapMode(romBytes, out var detectedMapModeSuccess) + }; + + if (detectedMapModeSuccess) + DetectedMapMode = ImportSettings.ROMMapMode; + + OnSettingsCreated(); + } + + protected virtual void OnSettingsCreated() + { + SettingsCreated?.Invoke(); + } + + private bool Warn(string msg) + { + return View.PromptToConfirmAction(msg + + "\nIf you proceed with this import, imported data might be wrong.\n" + + "Proceed anyway?\n\n (Experts only, otherwise say No)"); + } + + public bool Submit() + { + if (!DetectedMapMode.HasValue) + { + if (!Warn("ROM Map type couldn't be detected.")) + return false; + } + else if (DetectedMapMode.Value != ImportSettings.ROMMapMode) + { + if (!Warn("The ROM map type selected is different than what was detected.")) + return false; + } + + return true; + } + + private Dictionary GenerateVectorLabels() => + RomUtil.GenerateVectorLabels( + VectorTableEntriesEnabled, RomSettingsOffset, ImportSettings.RomBytes, ImportSettings.ROMMapMode); + + public Dictionary GenerateHeaderFlags() + { + var flags = new Dictionary(); + + if (ShouldCheckHeader) + RomUtil.GenerateHeaderFlags(RomSettingsOffset, flags, ImportSettings.RomBytes); + + return flags; + } + } +} From c2c12124cb43aec7a3c6e3305377fd8966fbe62b Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 3 Oct 2020 19:55:59 -0400 Subject: [PATCH 055/136] move importer stuff out of Data --- DiztinGUIsh/DiztinGUIsh.csproj | 4 +- DiztinGUIsh/core/Data.cs | 159 ---------------- DiztinGUIsh/core/import/BSNESImporter.cs | 172 ++++++++++++++++++ DiztinGUIsh/core/import/BSNESUsageMap.cs | 13 -- .../{BizHawkCdl.cs => BizHawkCdlImporter.cs} | 20 +- DiztinGUIsh/window/MainWindow.cs | 24 +-- DiztinGUIsh/window/ProjectController.cs | 34 +++- 7 files changed, 222 insertions(+), 204 deletions(-) create mode 100644 DiztinGUIsh/core/import/BSNESImporter.cs delete mode 100644 DiztinGUIsh/core/import/BSNESUsageMap.cs rename DiztinGUIsh/core/import/{BizHawkCdl.cs => BizHawkCdlImporter.cs} (80%) diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index f8fc6faf..527fb2c4 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -111,8 +111,8 @@ - - + + diff --git a/DiztinGUIsh/core/Data.cs b/DiztinGUIsh/core/Data.cs index c8dd7ff1..18a2bef7 100644 --- a/DiztinGUIsh/core/Data.cs +++ b/DiztinGUIsh/core/Data.cs @@ -47,18 +47,6 @@ public enum InOutPoint : byte ReadPoint = 0x08 } - // TODO: move BsnesPlusUsage stuff to its own class outside of Data - [Flags] - public enum BsnesPlusUsage : byte - { - UsageRead = 0x80, - UsageWrite = 0x40, - UsageExec = 0x20, - UsageOpcode = 0x10, - UsageFlagM = 0x02, - UsageFlagX = 0x01, - }; - public enum ROMMapMode : byte { LoROM, @@ -609,62 +597,6 @@ public void RescanInOutPoints() } } - // move out of here to extension method or just external method - public int ImportUsageMap(byte[] usageMap) - { - int size = GetROMSize(); - int modified = 0; - int prevFlags = 0; - - for (int map = 0; map <= 0xFFFFFF; map++) - { - var i = ConvertSNEStoPC(map); - - if (i == -1 || i >= size) - { - // branch predictor may optimize this - continue; - } - - var flags = (Data.BsnesPlusUsage)usageMap[map]; - - if (flags == 0) - { - // no information available - continue; - } - - if (GetFlag(i) != Data.FlagType.Unreached) - { - // skip if there is something already set.. - continue; - } - - // opcode: 0x30, operand: 0x20 - if (flags.HasFlag(Data.BsnesPlusUsage.UsageExec)) - { - SetFlag(i, Data.FlagType.Operand); - - if (flags.HasFlag(Data.BsnesPlusUsage.UsageOpcode)) - { - prevFlags = ((int)flags & 3) << 4; - SetFlag(i, Data.FlagType.Opcode); - } - - SetMXFlags(i, prevFlags); - modified++; - } - else if (flags.HasFlag(Data.BsnesPlusUsage.UsageRead)) - { - SetFlag(i, Data.FlagType.Data8Bit); - modified++; - } - } - - return modified; - } - - public int GetIntermediateAddress(int offset, bool resolve = false) { // FIX ME: log and generation of dp opcodes. search references @@ -688,97 +620,6 @@ public string GetInstruction(int offset) }; } - // this class exists for performance optimization ONLY. - // class representing offsets into a trace log - // we calculate it once from sample data and hang onto it - private class CachedTraceLineIndex - { - // NOTE: newer versions of BSNES use different text for flags. check for completeness. - private string sample = - "028cde rep #$30 A:0004 X:0000 Y:0004 S:1fdd D:0000 DB:02 nvmxdiZC V:133 H: 654 F:36"; - - // index of the start of the info - public readonly int - addr, - D, DB, - flags, - f_N, f_V, f_M, f_X, f_D, f_I, f_Z, f_C; - - public CachedTraceLineIndex() - { - int SkipToken(string token) - { - return sample.IndexOf(token) + token.Length; - } - - addr = 0; - D = SkipToken("D:"); - DB = SkipToken("DB:"); - flags = DB + 3; - - // flags: nvmxdizc - f_N = flags + 0; - f_V = flags + 1; - f_M = flags + 2; - f_X = flags + 3; - f_D = flags + 4; - f_I = flags + 5; - f_Z = flags + 6; - f_C = flags + 7; - } - } - - private static readonly CachedTraceLineIndex CachedIdx = new CachedTraceLineIndex(); - - public int ImportTraceLogLine(string line) - { - // caution: very performance-sensitive function, please take care when making modifications - // string.IndexOf() is super-slow too. - // Input lines must follow this strict format and be this exact formatting and column indices. - // 028cde rep #$30 A:0004 X:0000 Y:0004 S:1fdd D:0000 DB:02 nvmxdiZC V:133 H: 654 F:36 - - int GetHexValueAt(int startIndex, int length) - { - return Convert.ToInt32(line.Substring(startIndex, length), 16); - } - - if (line.Length < 80) - return 0; - - int snesAddress = GetHexValueAt(0, 6); - int pc = ConvertSNEStoPC(snesAddress); - if (pc == -1) - return 0; - - // TODO: error treatment - - int directPage = GetHexValueAt(CachedIdx.D, 4); - int dataBank = GetHexValueAt(CachedIdx.DB, 2); - - // 'X' = unchecked in bsnesplus debugger UI = (8bit), 'x' or '.' = checked (16bit) - bool xflag_set = line[CachedIdx.f_X] == 'X'; - - // 'M' = unchecked in bsnesplus debugger UI = (8bit), 'm' or '.' = checked (16bit) - bool mflag_set = line[CachedIdx.f_M] == 'M'; - - SetFlag(pc, Data.FlagType.Opcode); - - int modified = 0; - int size = GetROMSize(); - do - { - SetDataBank(pc, dataBank); - SetDirectPage(pc, directPage); - SetXFlag(pc, xflag_set); - SetMFlag(pc, mflag_set); - - pc++; - modified++; - } while (pc < size && GetFlag(pc) == Data.FlagType.Operand); - - return modified; - } - #region Equality protected bool Equals(Data other) { diff --git a/DiztinGUIsh/core/import/BSNESImporter.cs b/DiztinGUIsh/core/import/BSNESImporter.cs new file mode 100644 index 00000000..838eee2d --- /dev/null +++ b/DiztinGUIsh/core/import/BSNESImporter.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DiztinGUIsh.core.import +{ + class BSNESUsageMapImporter + { + // TODO: move BsnesPlusUsage stuff to its own class outside of Data + [Flags] + public enum BsnesPlusUsage : byte + { + UsageRead = 0x80, + UsageWrite = 0x40, + UsageExec = 0x20, + UsageOpcode = 0x10, + UsageFlagM = 0x02, + UsageFlagX = 0x01, + }; + + // move out of here to extension method or just external method + public int ImportUsageMap(byte[] usageMap, Data data) + { + int size = data.GetROMSize(); + int modified = 0; + int prevFlags = 0; + + for (int map = 0; map <= 0xFFFFFF; map++) + { + var i = data.ConvertSNEStoPC(map); + + if (i == -1 || i >= size) + { + // branch predictor may optimize this + continue; + } + + var flags = (BsnesPlusUsage) usageMap[map]; + + if (flags == 0) + { + // no information available + continue; + } + + if (data.GetFlag(i) != Data.FlagType.Unreached) + { + // skip if there is something already set.. + continue; + } + + // opcode: 0x30, operand: 0x20 + if (flags.HasFlag(BsnesPlusUsage.UsageExec)) + { + data.SetFlag(i, Data.FlagType.Operand); + + if (flags.HasFlag(BsnesPlusUsage.UsageOpcode)) + { + prevFlags = ((int) flags & 3) << 4; + data.SetFlag(i, Data.FlagType.Opcode); + } + + data.SetMXFlags(i, prevFlags); + modified++; + } + else if (flags.HasFlag(BsnesPlusUsage.UsageRead)) + { + data.SetFlag(i, Data.FlagType.Data8Bit); + modified++; + } + } + + return modified; + } + } + + class BSNESTraceLogImporter + { + // this class exists for performance optimization ONLY. + // class representing offsets into a trace log + // we calculate it once from sample data and hang onto it + private class CachedTraceLineIndex + { + // NOTE: newer versions of BSNES use different text for flags. check for completeness. + private string sample = + "028cde rep #$30 A:0004 X:0000 Y:0004 S:1fdd D:0000 DB:02 nvmxdiZC V:133 H: 654 F:36"; + + // index of the start of the info + public readonly int + addr, + D, DB, + flags, + f_N, f_V, f_M, f_X, f_D, f_I, f_Z, f_C; + + public CachedTraceLineIndex() + { + int SkipToken(string token) + { + return sample.IndexOf(token) + token.Length; + } + + addr = 0; + D = SkipToken("D:"); + DB = SkipToken("DB:"); + flags = DB + 3; + + // flags: nvmxdizc + f_N = flags + 0; + f_V = flags + 1; + f_M = flags + 2; + f_X = flags + 3; + f_D = flags + 4; + f_I = flags + 5; + f_Z = flags + 6; + f_C = flags + 7; + } + } + + private static readonly CachedTraceLineIndex CachedIdx = new CachedTraceLineIndex(); + + public int ImportTraceLogLine(string line, Data data) + { + // caution: very performance-sensitive function, please take care when making modifications + // string.IndexOf() is super-slow too. + // Input lines must follow this strict format and be this exact formatting and column indices. + // 028cde rep #$30 A:0004 X:0000 Y:0004 S:1fdd D:0000 DB:02 nvmxdiZC V:133 H: 654 F:36 + + int GetHexValueAt(int startIndex, int length) + { + return Convert.ToInt32(line.Substring(startIndex, length), 16); + } + + if (line.Length < 80) + return 0; + + int snesAddress = GetHexValueAt(0, 6); + int pc = data.ConvertSNEStoPC(snesAddress); + if (pc == -1) + return 0; + + // TODO: error treatment / validation + + int directPage = GetHexValueAt(CachedIdx.D, 4); + int dataBank = GetHexValueAt(CachedIdx.DB, 2); + + // 'X' = unchecked in bsnesplus debugger UI = (8bit), 'x' or '.' = checked (16bit) + bool xflag_set = line[CachedIdx.f_X] == 'X'; + + // 'M' = unchecked in bsnesplus debugger UI = (8bit), 'm' or '.' = checked (16bit) + bool mflag_set = line[CachedIdx.f_M] == 'M'; + + data.SetFlag(pc, Data.FlagType.Opcode); + + int modified = 0; + int size = data.GetROMSize(); + do + { + data.SetDataBank(pc, dataBank); + data.SetDirectPage(pc, directPage); + data.SetXFlag(pc, xflag_set); + data.SetMFlag(pc, mflag_set); + + pc++; + modified++; + } while (pc < size && data.GetFlag(pc) == Data.FlagType.Operand); + + return modified; + } + } +} diff --git a/DiztinGUIsh/core/import/BSNESUsageMap.cs b/DiztinGUIsh/core/import/BSNESUsageMap.cs deleted file mode 100644 index bb56a1c7..00000000 --- a/DiztinGUIsh/core/import/BSNESUsageMap.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace DiztinGUIsh.core.import -{ - class BSNESUsageMapImporter - { - - } -} diff --git a/DiztinGUIsh/core/import/BizHawkCdl.cs b/DiztinGUIsh/core/import/BizHawkCdlImporter.cs similarity index 80% rename from DiztinGUIsh/core/import/BizHawkCdl.cs rename to DiztinGUIsh/core/import/BizHawkCdlImporter.cs index 5346048d..2be734c8 100644 --- a/DiztinGUIsh/core/import/BizHawkCdl.cs +++ b/DiztinGUIsh/core/import/BizHawkCdlImporter.cs @@ -6,9 +6,9 @@ namespace DiztinGUIsh { - public class BizHawkCdl + public class BizHawkCdlImporter { - private Dictionary> cdl = new Dictionary>(); + private readonly Dictionary> cdl = new Dictionary>(); [Flags] public enum Flag : byte @@ -25,7 +25,7 @@ public enum Flag : byte public static void Import(string filename, Data data) { - var cdl = new BizHawkCdl(); + var cdl = new BizHawkCdlImporter(); cdl.LoadFromFile(filename); cdl.CopyInto(data); } @@ -75,21 +75,21 @@ private void CopyInto(Data data) for (var offset = 0; offset < size; offset++) { var cdlFlag = cdlRomFlags[offset]; - if (cdlFlag == BizHawkCdl.Flag.None) + if (cdlFlag == BizHawkCdlImporter.Flag.None) continue; var type = Data.FlagType.Unreached; - if ((cdlFlag & BizHawkCdl.Flag.ExecFirst) != 0) + if ((cdlFlag & BizHawkCdlImporter.Flag.ExecFirst) != 0) { type = Data.FlagType.Opcode; - m = (cdlFlag & BizHawkCdl.Flag.CPUMFlag) != 0; - x = (cdlFlag & BizHawkCdl.Flag.CPUXFlag) != 0; + m = (cdlFlag & BizHawkCdlImporter.Flag.CPUMFlag) != 0; + x = (cdlFlag & BizHawkCdlImporter.Flag.CPUXFlag) != 0; } - else if ((cdlFlag & BizHawkCdl.Flag.ExecOperand) != 0) + else if ((cdlFlag & BizHawkCdlImporter.Flag.ExecOperand) != 0) type = Data.FlagType.Operand; - else if ((cdlFlag & BizHawkCdl.Flag.CPUData) != 0) + else if ((cdlFlag & BizHawkCdlImporter.Flag.CPUData) != 0) type = Data.FlagType.Data8Bit; - else if ((cdlFlag & BizHawkCdl.Flag.DMAData) != 0) + else if ((cdlFlag & BizHawkCdlImporter.Flag.DMAData) != 0) type = Data.FlagType.Data8Bit; data.Mark(offset, type, 1); diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index a684d29d..1eb99961 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -1161,12 +1161,9 @@ private void ImportUsageMapToolStripMenuItem_Click(object sender, EventArgs e) if (openUsageMapFile.ShowDialog() != DialogResult.OK) return; - var num_modified_flags = Project.Data.ImportUsageMap(File.ReadAllBytes(openUsageMapFile.FileName)); + var numModifiedFlags = ProjectController.ImportBSNESUsageMap(openUsageMapFile.FileName); - if (num_modified_flags > 0) - ProjectController.MarkChanged(); - - MessageBox.Show($"Modified total {num_modified_flags} flags!", "Done", + MessageBox.Show($"Modified total {numModifiedFlags} flags!", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information); } @@ -1176,21 +1173,10 @@ private void ImportTraceLogToolStripMenuItem_Click(object sender, EventArgs e) if (openTraceLogDialog.ShowDialog() != DialogResult.OK) return; - var totalLinesSoFar = 0L; - - // caution: trace logs can be gigantic, even a few seconds can be > 1GB - LargeFilesReader.ReadFilesLines(openTraceLogDialog.FileNames, delegate (string line) - { - totalLinesSoFar += Project.Data.ImportTraceLogLine(line); - }); + var numModifiedFlags = ProjectController.ImportBSNESTraceLogs(openUsageMapFile.FileNames); - if (totalLinesSoFar > 0) - ProjectController.MarkChanged(); - - MessageBox.Show( - $"Modified total {totalLinesSoFar} flags from {openTraceLogDialog.FileNames.Length} files!", - "Done", - MessageBoxButtons.OK, MessageBoxIcon.Information); + MessageBox.Show($"Modified total {numModifiedFlags} flags from {openTraceLogDialog.FileNames.Length} files!", "Done", + MessageBoxButtons.OK, MessageBoxIcon.Information); } private void openLastProjectAutomaticallyToolStripMenuItem_Click(object sender, EventArgs e) diff --git a/DiztinGUIsh/window/ProjectController.cs b/DiztinGUIsh/window/ProjectController.cs index a513c438..7ecef62a 100644 --- a/DiztinGUIsh/window/ProjectController.cs +++ b/DiztinGUIsh/window/ProjectController.cs @@ -1,6 +1,7 @@ using System; using System.ComponentModel; using System.IO; +using DiztinGUIsh.core.import; using DiztinGUIsh.loadsave; using DiztinGUIsh.window.dialog; @@ -83,7 +84,7 @@ public void SaveProject(string filename) public void ImportBizHawkCDL(string filename) { - BizHawkCdl.Import(filename, Project.Data); + BizHawkCdlImporter.Import(filename, Project.Data); ProjectChanged?.Invoke(this, new ProjectChangedEventArgs() { @@ -162,5 +163,36 @@ public void SelectOffset(int offset, int column = -1) { ProjectView.SelectOffset(offset, column); } + + public long ImportBSNESUsageMap(string fileName) + { + var importer = new BSNESUsageMapImporter(); + + var linesModified = importer.ImportUsageMap(File.ReadAllBytes(fileName), Project.Data); + + if (linesModified > 0) + MarkChanged(); + + return linesModified; + } + + public long ImportBSNESTraceLogs(string[] fileNames) + { + var totalLinesSoFar = 0L; + + var importer = new BSNESTraceLogImporter(); + + // caution: trace logs can be gigantic, even a few seconds can be > 1GB + // inside here, performance becomes critical. + LargeFilesReader.ReadFilesLines(fileNames, delegate (string line) + { + totalLinesSoFar += importer.ImportTraceLogLine(line, Project.Data); + }); + + if (totalLinesSoFar > 0) + MarkChanged(); + + return totalLinesSoFar; + } } } From 061f9b555a57c4886d4fcf5b164fd6ed55173e80 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 4 Oct 2020 09:30:34 -0400 Subject: [PATCH 056/136] use an external library for ObservableDictionary --- DiztinGUIsh/DiztinGUIsh.csproj | 30 +- DiztinGUIsh/core/Data.cs | 5 +- DiztinGUIsh/core/import/SampleRomData.cs | 1 + DiztinGUIsh/core/util/ObservableDictionary.cs | 267 ------------------ 4 files changed, 33 insertions(+), 270 deletions(-) delete mode 100644 DiztinGUIsh/core/util/ObservableDictionary.cs diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 527fb2c4..d21179d7 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -63,6 +63,33 @@ ..\packages\ExtendedXmlSerializer.3.3.0\lib\net452\ExtendedXmlSerializer.dll + + ..\packages\IX.Abstractions.0.5.3\lib\net472\IX.Abstractions.dll + + + ..\packages\IX.Abstractions.Collections.0.5.3\lib\net472\IX.Abstractions.Collections.dll + + + ..\packages\IX.Abstractions.Threading.0.5.3\lib\net472\IX.Abstractions.Threading.dll + + + ..\packages\IX.Observable.0.5.3\lib\net472\IX.Observable.dll + + + ..\packages\IX.StandardExtensions.0.5.3\lib\net472\IX.StandardExtensions.dll + + + ..\packages\IX.StandardExtensions.ComponentModel.0.5.3\lib\net472\IX.StandardExtensions.ComponentModel.dll + + + ..\packages\IX.StandardExtensions.Threading.0.5.3\lib\net472\IX.StandardExtensions.Threading.dll + + + ..\packages\IX.Undoable.0.5.3\lib\net472\IX.Undoable.dll + + + ..\packages\JetBrains.Annotations.2019.1.3\lib\net20\JetBrains.Annotations.dll + ..\packages\LightInject.6.3.5\lib\net46\LightInject.dll @@ -79,6 +106,7 @@ ..\packages\System.Collections.Immutable.1.7.1\lib\net461\System.Collections.Immutable.dll + ..\packages\System.Interactive.4.1.1\lib\net45\System.Interactive.dll @@ -96,6 +124,7 @@ ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + ..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll @@ -115,7 +144,6 @@ - diff --git a/DiztinGUIsh/core/Data.cs b/DiztinGUIsh/core/Data.cs index 18a2bef7..ba0cce4a 100644 --- a/DiztinGUIsh/core/Data.cs +++ b/DiztinGUIsh/core/Data.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text; using DiztinGUIsh.core.util; +using IX.Observable; namespace DiztinGUIsh.core { @@ -85,8 +86,8 @@ public const int // when we figure it out. public ROMMapMode RomMapMode { get; set; } public ROMSpeed RomSpeed { get; set; } - public ObservableDictionary Comments { get; set; } = new ObservableDictionary< int, string>(); - public ObservableDictionary Labels { get; set; } = new ObservableDictionary< int, Label>(); + public ObservableDictionary Comments { get; set; } = new ObservableDictionary(); + public ObservableDictionary Labels { get; set; } = new ObservableDictionary(); public RomBytes RomBytes { get; set; } = new RomBytes(); private CPU65C816 CPU65C816 { get; set; } diff --git a/DiztinGUIsh/core/import/SampleRomData.cs b/DiztinGUIsh/core/import/SampleRomData.cs index 361b2bbc..eb3e0f4b 100644 --- a/DiztinGUIsh/core/import/SampleRomData.cs +++ b/DiztinGUIsh/core/import/SampleRomData.cs @@ -1,5 +1,6 @@ using DiztinGUIsh.core; using DiztinGUIsh.core.util; +using IX.Observable; namespace DiztinGUIsh { diff --git a/DiztinGUIsh/core/util/ObservableDictionary.cs b/DiztinGUIsh/core/util/ObservableDictionary.cs deleted file mode 100644 index 1082eec2..00000000 --- a/DiztinGUIsh/core/util/ObservableDictionary.cs +++ /dev/null @@ -1,267 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Diagnostics; - -namespace DiztinGUIsh.core.util -{ - // based on: kzu/ObservableDictionary.cs https://gist.github.com/kzu/cfe3cb6e4fe3efea6d24 - // adds implementation of IDictionary, which we need. - - /// - /// Provides a dictionary for use with data binding. - /// - /// Specifies the type of the keys in this collection. - /// Specifies the type of the values in this collection. - [DebuggerDisplay("Count={" + nameof(Count) + "}")] - public class ObservableDictionary : - // ICollection>, - IDictionary, - IDictionary, - INotifyCollectionChanged, INotifyPropertyChanged - { - private readonly IDictionary dictionary; - - /// Event raised when the collection changes. - public event NotifyCollectionChangedEventHandler CollectionChanged = (sender, args) => { }; - - /// Event raised when a property on the collection changes. - public event PropertyChangedEventHandler PropertyChanged = (sender, args) => { }; - - /// - /// Initializes an instance of the class. - /// - public ObservableDictionary() - : this(new Dictionary()) - { - } - - /// - /// Initializes an instance of the class using another dictionary as - /// the key/value store. - /// - public ObservableDictionary(IDictionary dictionary) - { - this.dictionary = dictionary; - } - - private void AddWithNotification(KeyValuePair item) - { - AddWithNotification(item.Key, item.Value); - } - - private void AddWithNotification(TKey key, TValue value) - { - dictionary.Add(key, value); - - CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, - new KeyValuePair(key, value))); - PropertyChanged(this, new PropertyChangedEventArgs("Count")); - PropertyChanged(this, new PropertyChangedEventArgs("Keys")); - PropertyChanged(this, new PropertyChangedEventArgs("Values")); - } - - private bool RemoveWithNotification(TKey key) - { - if (!dictionary.TryGetValue(key, out var value) || !dictionary.Remove(key)) - return false; - - CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, - new KeyValuePair(key, value))); - PropertyChanged(this, new PropertyChangedEventArgs("Count")); - PropertyChanged(this, new PropertyChangedEventArgs("Keys")); - PropertyChanged(this, new PropertyChangedEventArgs("Values")); - - return true; - } - - private void UpdateWithNotification(TKey key, TValue value) - { - if (!dictionary.TryGetValue(key, out var existing)) - { - AddWithNotification(key, value); - return; - } - - dictionary[key] = value; - - CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, - new KeyValuePair(key, value), - new KeyValuePair(key, existing))); - PropertyChanged(this, new PropertyChangedEventArgs("Values")); - } - - /// - /// Allows derived classes to raise custom property changed events. - /// - protected void RaisePropertyChanged(PropertyChangedEventArgs args) - { - PropertyChanged(this, args); - } - - #region IDictionary Members - - /// - /// Adds an element with the provided key and value to the . - /// - /// The object to use as the key of the element to add. - /// The object to use as the value of the element to add. - public void Add(TKey key, TValue value) - { - AddWithNotification(key, value); - } - - /// - /// Determines whether the contains an element with the specified key. - /// - /// The key to locate in the . - /// - /// true if the contains an element with the key; otherwise, false. - /// - public bool ContainsKey(TKey key) - { - return dictionary.ContainsKey(key); - } - - /// - /// Gets an containing the keys of the . - /// - /// An containing the keys of the object that implements . - public ICollection Keys => dictionary.Keys; - - // ICollection IDictionary.Values => (ICollection) dictionary.Values; - - /// - /// Removes the element with the specified key from the . - /// - /// The key of the element to remove. - /// - /// true if the element is successfully removed; otherwise, false. This method also returns false if was not found in the original . - /// - public bool Remove(TKey key) - { - return RemoveWithNotification(key); - } - - /// - /// Gets the value associated with the specified key. - /// - /// The key whose value to get. - /// When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the parameter. This parameter is passed uninitialized. - /// - /// true if the object that implements contains an element with the specified key; otherwise, false. - /// - public bool TryGetValue(TKey key, out TValue value) - { - return dictionary.TryGetValue(key, out value); - } - - /// - /// Gets an containing the values in the . - /// - /// An containing the values in the object that implements . - public ICollection Values => dictionary.Values; - - /// - /// Gets or sets the element with the specified key. - /// - /// The key. - /// - public TValue this[TKey key] - { - get => dictionary[key]; - set => UpdateWithNotification(key, value); - } - - #endregion - - #region ICollection> Members - - public void Add(KeyValuePair item) - { - AddWithNotification(item); - } - - - - public void Clear() - { - dictionary.Clear(); - - CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); - PropertyChanged(this, new PropertyChangedEventArgs("Count")); - PropertyChanged(this, new PropertyChangedEventArgs("Keys")); - PropertyChanged(this, new PropertyChangedEventArgs("Values")); - } - - public bool Contains(KeyValuePair item) => dictionary.Contains(item); - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - dictionary.CopyTo(array, arrayIndex); - } - - public int Count => dictionary.Count; - - public bool IsReadOnly => dictionary.IsReadOnly; - - public bool Remove(KeyValuePair item) - { - return RemoveWithNotification(item.Key); - } - - #endregion - - #region IEnumerable> Members - - IEnumerator> IEnumerable>.GetEnumerator() - { - return dictionary.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return dictionary.GetEnumerator(); - } - - #endregion - - - #region IDictionary - - ICollection IDictionary.Keys => (ICollection)dictionary.Keys; - ICollection IDictionary.Values => (ICollection)dictionary.Values; - public void Add(object key, object value) - { - AddWithNotification((TKey)key, (TValue)value); - } - public IDictionaryEnumerator GetEnumerator() - { - return ((IDictionary)(dictionary)).GetEnumerator(); - } - - public void Remove(object key) - { - RemoveWithNotification((TKey)key); - } - - public object this[object key] - { - get => dictionary[(TKey)key]; - set => UpdateWithNotification((TKey)key, (TValue)value); - } - public bool Contains(object key) => dictionary.Contains((KeyValuePair)key); - public void CopyTo(Array array, int index) - { - CopyTo((KeyValuePair[])(array), index); - } - - public object SyncRoot => null; // TODO? - public bool IsSynchronized => false; // TODO? - public bool IsFixedSize => false; // TODO? - - #endregion - } -} From 75e9a171affc30bb0b258c0a28baa2502696e3d8 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 4 Oct 2020 09:30:47 -0400 Subject: [PATCH 057/136] fix not storing the ROM title name --- DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs b/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs index 126add10..1b06bffe 100644 --- a/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs +++ b/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs @@ -64,7 +64,7 @@ public override Project Load(byte[] data) // read internal title var pointer = HEADER_SIZE + 6; - RomUtil.ReadStringFromByteArray(data, RomUtil.LengthOfTitleName, pointer); + project.InternalRomGameName = RomUtil.ReadStringFromByteArray(data, RomUtil.LengthOfTitleName, pointer); pointer += RomUtil.LengthOfTitleName; // read checksums From c2a751bdca2ef8a3eedbcdc6c4ce8f7f8b17cbda Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 4 Oct 2020 09:31:10 -0400 Subject: [PATCH 058/136] add new observabledict package --- DiztinGUIsh/packages.config | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/DiztinGUIsh/packages.config b/DiztinGUIsh/packages.config index c53ecd53..9d262c35 100644 --- a/DiztinGUIsh/packages.config +++ b/DiztinGUIsh/packages.config @@ -2,6 +2,15 @@ + + + + + + + + + From f8bed304942859eb9606a1e9c6ac874551a4af38 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 4 Oct 2020 09:31:52 -0400 Subject: [PATCH 059/136] fix null err, we don't have Project at this stage yet --- DiztinGUIsh/window/MainWindow.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 1eb99961..7889a30e 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -1193,8 +1193,9 @@ private void toolStripOpenLast_Click(object sender, EventArgs e) public string AskToSelectNewRomFilename(string promptSubject, string promptText) { + string initialDir = null; // TODO: Project.ProjectFileName return GuiUtil.PromptToConfirmAction(promptSubject, promptText, - () => GuiUtil.PromptToSelectFile(Project.ProjectFileName) + () => GuiUtil.PromptToSelectFile(initialDir) ); } From 04142c39799f2602f4e6216c4334029c7137f254 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 4 Oct 2020 09:32:29 -0400 Subject: [PATCH 060/136] fix dialog box threading not allowing a dialog to popup while we're in another thread. - unsure of full ramifications of this choice, but it works --- DiztinGUIsh/core/util/ProgressBarWorker.cs | 6 +++++- DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/DiztinGUIsh/core/util/ProgressBarWorker.cs b/DiztinGUIsh/core/util/ProgressBarWorker.cs index 74cd2adc..3cd06af4 100644 --- a/DiztinGUIsh/core/util/ProgressBarWorker.cs +++ b/DiztinGUIsh/core/util/ProgressBarWorker.cs @@ -3,7 +3,8 @@ using DiztinGUIsh.window.dialog; namespace DiztinGUIsh -{ +{ + // TODO: use https://www.wpf-tutorial.com/misc/multi-threading-with-the-backgroundworker/ backgroundworker public abstract class ProgressBarWorker { private ProgressDialog Dialog = null; @@ -45,6 +46,9 @@ protected virtual void Setup() // setup, but don't start, the new thread backgroundThread = new Thread(new ThreadStart(Thread_Main)); + + // honestly, not sure about this. works around some Invoke() stuff + backgroundThread.SetApartmentState(ApartmentState.STA); } // blocking function diff --git a/DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs b/DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs index 5553d7fc..11420369 100644 --- a/DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs +++ b/DiztinGUIsh/window/dialog/ProgressDialog.Designer.cs @@ -90,7 +90,6 @@ private void InitializeComponent() this.ShowInTaskbar = false; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "Working..."; - this.TopMost = true; ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); From 76d73ecc82175508d7a8de2c41275934063c3ab8 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 6 Oct 2020 09:51:50 -0400 Subject: [PATCH 061/136] WIP fixing Dictionay serialization support --- DiztinGUIsh/App.config | 4 + DiztinGUIsh/DiztinGUIsh.csproj | 14 +- DiztinGUIsh/core/Data.cs | 6 +- DiztinGUIsh/core/LogCreator.cs | 2 +- DiztinGUIsh/core/import/SampleRomData.cs | 4 +- .../core/util/ObservableDictionaryAdaptor.cs | 102 ++++++++++++++ DiztinGUIsh/loadsave/ProjectFileManager.cs | 2 +- DiztinGUIsh/loadsave/ProjectSerializer.cs | 2 +- .../xml_serializer/ProjectXMLSerializer.cs | 125 ++++-------------- .../xml_serializer/XMLSerializerSupport.cs | 49 +++++++ DiztinGUIsh/packages.config | 6 +- DiztinGUIsh/window/AliasList.cs | 5 +- DiztinGUIsh/window/ProjectController.cs | 24 +++- 13 files changed, 226 insertions(+), 119 deletions(-) create mode 100644 DiztinGUIsh/core/util/ObservableDictionaryAdaptor.cs create mode 100644 DiztinGUIsh/loadsave/xml_serializer/XMLSerializerSupport.cs diff --git a/DiztinGUIsh/App.config b/DiztinGUIsh/App.config index 1b9f114e..98dfa8bc 100644 --- a/DiztinGUIsh/App.config +++ b/DiztinGUIsh/App.config @@ -28,6 +28,10 @@ + + + + diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index d21179d7..444041f9 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -60,8 +60,8 @@ DiztinGUIsh.Program - - ..\packages\ExtendedXmlSerializer.3.3.0\lib\net452\ExtendedXmlSerializer.dll + + ..\packages\ExtendedXmlSerializer.3.3.0.1-xbhphjmm\lib\net452\ExtendedXmlSerializer.dll ..\packages\IX.Abstractions.0.5.3\lib\net472\IX.Abstractions.dll @@ -87,8 +87,8 @@ ..\packages\IX.Undoable.0.5.3\lib\net472\IX.Undoable.dll - - ..\packages\JetBrains.Annotations.2019.1.3\lib\net20\JetBrains.Annotations.dll + + ..\packages\JetBrains.Annotations.2020.1.0\lib\net20\JetBrains.Annotations.dll ..\packages\LightInject.6.3.5\lib\net46\LightInject.dll @@ -144,6 +144,7 @@ + @@ -152,6 +153,7 @@ + @@ -324,11 +326,11 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + \ No newline at end of file diff --git a/DiztinGUIsh/core/Data.cs b/DiztinGUIsh/core/Data.cs index ba0cce4a..3dd12769 100644 --- a/DiztinGUIsh/core/Data.cs +++ b/DiztinGUIsh/core/Data.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; @@ -86,8 +87,9 @@ public const int // when we figure it out. public ROMMapMode RomMapMode { get; set; } public ROMSpeed RomSpeed { get; set; } - public ObservableDictionary Comments { get; set; } = new ObservableDictionary(); - public ObservableDictionary Labels { get; set; } = new ObservableDictionary(); + + public ObservableDictionaryAdaptor Comments { get; set; } = new ObservableDictionaryAdaptor(); + public ObservableDictionaryAdaptor Labels { get; set; } = new ObservableDictionaryAdaptor(); public RomBytes RomBytes { get; set; } = new RomBytes(); private CPU65C816 CPU65C816 { get; set; } diff --git a/DiztinGUIsh/core/LogCreator.cs b/DiztinGUIsh/core/LogCreator.cs index 07bf1be0..b347d827 100644 --- a/DiztinGUIsh/core/LogCreator.cs +++ b/DiztinGUIsh/core/LogCreator.cs @@ -155,7 +155,7 @@ public OutputResult CreateLog() // ehhhh... is that a little weird... maybe. // // maybe just clone the list and use the local list instead, remove subscribes from just that. - AddLabelSource(Data.Labels); + AddLabelSource(Data.Labels.Dict); AddLabelSource(ExtraLabels); AddTemporaryLabels(); diff --git a/DiztinGUIsh/core/import/SampleRomData.cs b/DiztinGUIsh/core/import/SampleRomData.cs index eb3e0f4b..cb353b9c 100644 --- a/DiztinGUIsh/core/import/SampleRomData.cs +++ b/DiztinGUIsh/core/import/SampleRomData.cs @@ -155,14 +155,14 @@ public static SampleRomData SampleData new ROMByte {Rom = 0x34, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, new ROMByte {Rom = 0x6D, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, }, - Comments = new ObservableDictionary + Comments = new ObservableDictionaryAdaptor() { {0x03, "this sets FastROM"}, {0x0F, "direct page = $2100"}, {0x21, "clear APU regs"}, {0x44, "this routine copies Test_Data to $7E0100"} }, - Labels = new ObservableDictionary + Labels = new ObservableDictionaryAdaptor() { {0x00, new Label {name = "Emulation_RESET", comment = "Sample emulation reset location"}}, {0x0A, new Label {name = "FastRESET", comment = "Sample label"}}, diff --git a/DiztinGUIsh/core/util/ObservableDictionaryAdaptor.cs b/DiztinGUIsh/core/util/ObservableDictionaryAdaptor.cs new file mode 100644 index 00000000..f2867464 --- /dev/null +++ b/DiztinGUIsh/core/util/ObservableDictionaryAdaptor.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using IX.Observable; + +namespace DiztinGUIsh.core.util +{ + // wrap an ObservableDictionary so we can implement non-generic IDictionary + // this basically exists to work around ExtendedXmlSerializer trying to cast us to IDictionary and failing. + // there's probably settings we can tweak in ExtendedXmlSerializer (particularly, Interceptor), and then + // we can remove the need for this adaptor. + + public class ObservableDictionaryAdaptor : IDictionary, IEnumerable> + { + private readonly ObservableDictionary dict = new ObservableDictionary(); + public bool Contains(object key) + { + return dict.Keys.Contains((TKey)key); + } + + public void Add(object key, object value) + { + dict.Add((TKey)key, (TValue)value); + } + + public void Clear() + { + dict.Clear(); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return dict.GetEnumerator(); + } + + IDictionaryEnumerator IDictionary.GetEnumerator() + { + return new ODEnumerator(dict); + } + + public void Remove(object key) + { + dict.Remove((TKey)key); + } + + public object this[object key] + { + get => dict[(TKey)key]; + set => dict[(TKey)key] = (TValue)value; + } + + public ICollection Keys => (ICollection)dict.Keys; + public ICollection Values => (ICollection)dict.Values; + public bool IsReadOnly => dict.IsReadOnly; + public bool IsFixedSize => false; + + public IEnumerator GetEnumerator() + { + return ((IEnumerable)dict).GetEnumerator(); + } + public void CopyTo(Array array, int index) + { + ((ICollection)dict).CopyTo(array, index); + } + + public int Count => dict.Count; + + public object SyncRoot => dict.SyncRoot; + + public bool IsSynchronized => dict.IsSynchronized; + public ObservableDictionary Dict => dict; + + public bool TryGetValue(TKey key, out TValue value) => dict.TryGetValue(key, out value); + + public bool ContainsKey(TKey key) + { + return dict.ContainsKey(key); + } + } + class ODEnumerator : IDictionaryEnumerator, IDisposable + { + private readonly IEnumerator> impl; + public void Dispose() { impl.Dispose(); } + public ODEnumerator(IDictionary value) + { + impl = value.GetEnumerator(); + } + public void Reset() { impl.Reset(); } + public bool MoveNext() { return impl.MoveNext(); } + public DictionaryEntry Entry + { + get + { + var pair = impl.Current; + return new DictionaryEntry(pair.Key, pair.Value); + } + } + public object Key => impl.Current.Key; + public object Value => impl.Current.Value; + public object Current => Entry; + } +} diff --git a/DiztinGUIsh/loadsave/ProjectFileManager.cs b/DiztinGUIsh/loadsave/ProjectFileManager.cs index bf787cab..b541d259 100644 --- a/DiztinGUIsh/loadsave/ProjectFileManager.cs +++ b/DiztinGUIsh/loadsave/ProjectFileManager.cs @@ -41,7 +41,7 @@ private static Project DoOpen(string filename, Func romPromptFn) return project; } - private static bool PostSerialize(Project project, Func romPromptFn) + public static bool PostSerialize(Project project, Func romPromptFn) { // at this stage, 'Data' is populated with everything EXCEPT the actual ROM bytes. // It would be easy to store the ROM bytes in the save file, but, for copyright reasons, diff --git a/DiztinGUIsh/loadsave/ProjectSerializer.cs b/DiztinGUIsh/loadsave/ProjectSerializer.cs index 9861871a..818ac9a9 100644 --- a/DiztinGUIsh/loadsave/ProjectSerializer.cs +++ b/DiztinGUIsh/loadsave/ProjectSerializer.cs @@ -31,7 +31,7 @@ protected static void DebugVerifyProjectEquality(Project project1, Project proje { for (int i = 0; i < project1.Data.RomBytes.Count; ++i) { - Debug.Assert(project1.Data.RomBytes[i].Equals(project2.Data.RomBytes[i])); + Debug.Assert(project1.Data.RomBytes[i].EqualsButNoRomByte(project2.Data.RomBytes[i])); } Debug.Assert(project1.Data.RomBytes.Equals(project2.Data.RomBytes)); diff --git a/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs b/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs index 7f4524fb..9a07e7ab 100644 --- a/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs +++ b/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs @@ -1,102 +1,20 @@ -using System.Collections; -using System.IO; -using System.Reflection; +using System.IO; using System.Text; using System.Xml; -using DiztinGUIsh.core; -using DiztinGUIsh.core.util; using ExtendedXmlSerializer; -using ExtendedXmlSerializer.Configuration; -using ExtendedXmlSerializer.ContentModel; -using ExtendedXmlSerializer.ContentModel.Content; -using ExtendedXmlSerializer.ContentModel.Format; -using ExtendedXmlSerializer.Core; -using ExtendedXmlSerializer.ExtensionModel; namespace DiztinGUIsh.loadsave.xml_serializer { - /*internal class ObservableDictionarySerializer : ISerializerExtension - { - public IServiceRepository Get(IServiceRepository parameter) - { - throw new System.NotImplementedException(); - } - - public void Execute(IServices parameter) - { - throw new System.NotImplementedException(); - } - } - - - sealed class Extension : ISerializerExtension - { - public static Extension Default { get; } = new Extension(); - - Extension() { } - - public IServiceRepository Get(IServiceRepository parameter) => parameter.DecorateContentsWith() - .Then(); - - void ICommand.Execute(IServices parameter) { } - - sealed class Contents : IContents - { - readonly IContents _previous; - readonly ISerializer _number; - - public Contents(IContents previous) - : this(previous, new AnswerToEverythingSerializer(previous.Get(typeof(int)).For())) { } - - public Contents(IContents previous, ISerializer number) - { - _previous = previous; - _number = number; - } - - public ISerializer Get(TypeInfo parameter) - => parameter == typeof(int) ? _number.Adapt() : _previous.Get(parameter); - } - - sealed class AnswerToEverythingSerializer : ISerializer - { - readonly ISerializer _previous; - - public AnswerToEverythingSerializer(ISerializer previous) => _previous = previous; - - public int Get(IFormatReader parameter) => _previous.Get(parameter) + 42; - - public void Write(IFormatWriter writer, int instance) - { - _previous.Write(writer, instance + 42); - } - } - }*/ - internal class ProjectXmlSerializer : ProjectSerializer { // NEVER CHANGE THIS ONE. - private const int FIRST_SAVE_FORMAT_VERSION = 100; + private const int FIRST_SAVE_FORMAT_VERSION = 100; - // increment this if you change the XML file format - private const int CURRENT_SAVE_FORMAT_VERSION = FIRST_SAVE_FORMAT_VERSION; + // increment this if you change the XML file format + private const int CURRENT_SAVE_FORMAT_VERSION = FIRST_SAVE_FORMAT_VERSION; - // update this if we are dropped support for really old save formats. - private const int EARLIEST_SUPPORTED_SAVE_FORMAT_VERSION = FIRST_SAVE_FORMAT_VERSION; - - private static IExtendedXmlSerializer GetSerializer() - { - return new ConfigurationContainer() - .Type().Register() - .Serializer().Using(RomBytesSerializer.Default) - //.Type>() - //.Extend(new ObservableDictionarySerializer()) - .UseOptimizedNamespaces() - .UseAutoFormatting() - .EnableImplicitTyping(typeof(Data)) - .EnableImplicitTyping(typeof(Label)) - .Create(); - } + // update this if we are dropped support for really old save formats. + private const int EARLIEST_SUPPORTED_SAVE_FORMAT_VERSION = FIRST_SAVE_FORMAT_VERSION; internal class Root { @@ -108,7 +26,8 @@ internal class Root // to change 'Project' public int SaveVersion { get; set; } = -1; public string Watermark { get; set; } - + public string Extra1 { get; set; } = ""; // reserved for future use + public string Extra2 { get; set; } = ""; // reserved for future use // The actual project itself. Almost any change you want to make should go in here. public Project Project { get; set; } @@ -116,11 +35,8 @@ internal class Root public override byte[] Save(Project project) { - // TODO: figure out how to not save Project.unsavedChanges property in XML - // Wrap the project in a top-level root element with some info about the XML file - // format version. Note that each serializer has its own implementation of this. - + // format version. Note that each serializer has its own implementation of storing this metadata var rootElement = new Root() { SaveVersion = CURRENT_SAVE_FORMAT_VERSION, @@ -128,27 +44,36 @@ public override byte[] Save(Project project) Project = project, }; - var xml_str = GetSerializer().Serialize( + var xmlStr = XmlSerializerSupport.GetSerializer().Serialize( new XmlWriterSettings { Indent = true }, rootElement); - var final_bytes = Encoding.UTF8.GetBytes(xml_str); + var finalBytes = Encoding.UTF8.GetBytes(xmlStr); // if you want some sanity checking, run this to verify everything saved correctly - DebugVerifyProjectEquality(project, Load(final_bytes)); + DebugVerifyProjectEquality(project, finalBytes); + // end debug + + return finalBytes; + } - return final_bytes; + private void DebugVerifyProjectEquality(Project project1, byte[] finalBytes_project2) + { + var project2 = Load(finalBytes_project2); + ProjectFileManager.PostSerialize(project2, null); + DebugVerifyProjectEquality(project1, project2); } public override Project Load(byte[] data) { - // TODO: it would be much more reliable if we could deserialize the Root element ALONE - // first, check for version/watermark, and only then try to deserialize the rest of the doc. + // TODO: it would be much more user-friendly/reliable if we could deserialize the + // Root element ALONE first, check for valid version/watermark, and only then try + // to deserialize the rest of the doc. // // Also, we can do data migrations based on versioning, and ExtendedXmlSerializer var text = Encoding.UTF8.GetString(data); - var root = GetSerializer().Deserialize(text); + var root = XmlSerializerSupport.GetSerializer().Deserialize(text); if (root.Watermark != Watermark) throw new InvalidDataException("This file doesn't appear to be a valid DiztinGUIsh XML file (missing/invalid watermark element in XML)"); diff --git a/DiztinGUIsh/loadsave/xml_serializer/XMLSerializerSupport.cs b/DiztinGUIsh/loadsave/xml_serializer/XMLSerializerSupport.cs new file mode 100644 index 00000000..aa3a35c5 --- /dev/null +++ b/DiztinGUIsh/loadsave/xml_serializer/XMLSerializerSupport.cs @@ -0,0 +1,49 @@ +using DiztinGUIsh.core; +using ExtendedXmlSerializer; +using ExtendedXmlSerializer.Configuration; + +namespace DiztinGUIsh.loadsave.xml_serializer +{ + public static class XmlSerializerSupport + { + public static IExtendedXmlSerializer GetSerializer() + { + // var sourceD = new Data.ObservableDictionaryAdaptor(); + // IDictionary IDict = (IDictionary)sourceD; + + // TODO: doesn't work for saving ObservableDictionary related stuff yet. fix. + + return new ConfigurationContainer() + .Type() + .Member(x => x.UnsavedChanges).Ignore() + .Type() + .Register().Serializer().Using(RomBytesSerializer.Default) + .Type() + //.Member(x => x.Comments).Ignore() + //.Member(x => x.Labels).Ignore() + // .Type>() + // .Extend(ObservableDictionaryExtension.Default) + //.EnableImplicitTyping(typeof(Data.ObservableDictionaryAdaptor)) + //.Type>() + //.Register().Serializer().ByCalling(dSerialize, dDeserialize) + //.Type() + //.Type() + //.WithInterceptor(new InterceptorGuy()) + .UseOptimizedNamespaces() + .UseAutoFormatting() + .EnableImplicitTyping(typeof(Data)) + .EnableImplicitTyping(typeof(Label)) + .Create(); + } + + /*private static Data.ObservableDictionaryAdaptor dDeserialize(IFormatReader arg) + { + throw new NotImplementedException(); + } + + private static void dSerialize(IFormatWriter arg1, Data.ObservableDictionaryAdaptor arg2) + { + throw new NotImplementedException(); + }*/ + } +} \ No newline at end of file diff --git a/DiztinGUIsh/packages.config b/DiztinGUIsh/packages.config index 9d262c35..004248fa 100644 --- a/DiztinGUIsh/packages.config +++ b/DiztinGUIsh/packages.config @@ -1,7 +1,7 @@  - - + + @@ -10,7 +10,7 @@ - + diff --git a/DiztinGUIsh/window/AliasList.cs b/DiztinGUIsh/window/AliasList.cs index 379fd9c6..206d5bcf 100644 --- a/DiztinGUIsh/window/AliasList.cs +++ b/DiztinGUIsh/window/AliasList.cs @@ -284,8 +284,9 @@ public void RebindProject() RepopulateFromData(); // todo: eventually use databinding/datasource, probably. - Data.Labels.PropertyChanged += Labels_PropertyChanged; - Data.Labels.CollectionChanged += Labels_CollectionChanged; + // Todo: modify observabledictionary wrapper to avoid having to do the .Dict call here. + Data.Labels.Dict.PropertyChanged += Labels_PropertyChanged; + Data.Labels.Dict.CollectionChanged += Labels_CollectionChanged; } private void RepopulateFromData() diff --git a/DiztinGUIsh/window/ProjectController.cs b/DiztinGUIsh/window/ProjectController.cs index 7ecef62a..0889e632 100644 --- a/DiztinGUIsh/window/ProjectController.cs +++ b/DiztinGUIsh/window/ProjectController.cs @@ -5,6 +5,27 @@ using DiztinGUIsh.loadsave; using DiztinGUIsh.window.dialog; +// Model-View-Controller architecture. +// goal: while this class's purpose is to be the middleman between dumb GUI elements and +// our underlying data, we should strive to keep all direct GUI stuff out of this class. +// i.e. it's OK for this class to deal with confirming the user wants to do something, +// but not OK to directly use GUI functions to show a form. instead, it should reach +// out to the view classes and ask them to do things like popup dialog boxes/change form elements/etc. +// +// The idea here is that because there's no direct GUI stuff going on, we can run automations +// and unit testing on this class, and eventually add undo/redo support +// +// Where possible, let the GUI elements (forms) subscribe to data notifications on our model +// instead of trying to middleman everything. +// +// This separation of concerns isn't perfect yet, but, keep it in mind as you add functionality. +// +// example: +// ProjectView -> A form that displays an opened project to the user +// ProjectController -> When the form needs to change any state, it talks to ProjectController +// i.e. when user clicks "Open Project", it sends the filename to us for handling +// Project -> The actual data, the model. It knows nothing about GUI, just is the low-level business logic + namespace DiztinGUIsh.window { public class ProjectController @@ -70,7 +91,8 @@ private void OnProjectOpenSuccess(string filename, Project project) private void Project_PropertyChanged(object sender, PropertyChangedEventArgs e) { - // TODO + // TODO: use this to listen to interesting change events in Project/Data + // so we can react appropriately. } public void SaveProject(string filename) From 833f64c12c00c4e51f27eca44714a02c56e7df92 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 6 Oct 2020 11:30:41 -0400 Subject: [PATCH 062/136] move all core functionality into its own project - enforces hard separation of GUI stuff from biz logic - enable the way for unit testing --- Diz.Core/Diz.Core.csproj | 144 ++++++++++++++++++ {DiztinGUIsh => Diz.Core}/Model.cs | 6 +- Diz.Core/Properties/AssemblyInfo.cs | 36 +++++ Diz.Core/app.config | 11 ++ {DiztinGUIsh => Diz.Core}/core/CPU65C816.cs | 0 {DiztinGUIsh => Diz.Core}/core/Data.cs | 0 {DiztinGUIsh => Diz.Core}/core/Label.cs | 0 {DiztinGUIsh => Diz.Core}/core/LogCreator.cs | 27 ++-- {DiztinGUIsh => Diz.Core}/core/Project.cs | 0 {DiztinGUIsh => Diz.Core}/core/ROMByte.cs | 0 {DiztinGUIsh => Diz.Core}/core/RomBytes.cs | 0 .../core/import/BSNESImporter.cs | 4 +- .../core/import/BizHawkCdlImporter.cs | 0 .../core/import/SampleRomData.cs | 2 +- .../core/util/ByteUtil.cs | 0 .../core/util/ObservableDictionaryAdaptor.cs | 0 .../core/util/RomUtil.cs | 0 {DiztinGUIsh => Diz.Core}/core/util/Util.cs | 0 .../loadsave/ImportSettings.cs | 0 .../loadsave/ProjectFileManager.cs | 15 -- .../loadsave/ProjectSerializer.cs | 0 .../binary_serializer_old/BinarySerializer.cs | 8 +- .../xml_serializer/ProjectXMLSerializer.cs | 0 .../xml_serializer/RomBytesXMLSerializer.cs | 0 .../xml_serializer/XMLSerializerSupport.cs | 0 Diz.Core/packages.config | 23 +++ DiztinGUIsh.sln | 10 +- DiztinGUIsh/DiztinGUIsh.csproj | 46 ++---- DiztinGUIsh/Program.cs | 4 - DiztinGUIsh/packages.config | 3 - .../{core/util => window}/LargeFilesReader.cs | 0 .../util => window}/ProgressBarWorker.cs | 0 DiztinGUIsh/window/ProjectController.cs | 16 +- .../window/dialog/ExportDisassembly.cs | 30 ++-- 34 files changed, 282 insertions(+), 103 deletions(-) create mode 100644 Diz.Core/Diz.Core.csproj rename {DiztinGUIsh => Diz.Core}/Model.cs (92%) create mode 100644 Diz.Core/Properties/AssemblyInfo.cs create mode 100644 Diz.Core/app.config rename {DiztinGUIsh => Diz.Core}/core/CPU65C816.cs (100%) rename {DiztinGUIsh => Diz.Core}/core/Data.cs (100%) rename {DiztinGUIsh => Diz.Core}/core/Label.cs (100%) rename {DiztinGUIsh => Diz.Core}/core/LogCreator.cs (98%) rename {DiztinGUIsh => Diz.Core}/core/Project.cs (100%) rename {DiztinGUIsh => Diz.Core}/core/ROMByte.cs (100%) rename {DiztinGUIsh => Diz.Core}/core/RomBytes.cs (100%) rename {DiztinGUIsh => Diz.Core}/core/import/BSNESImporter.cs (98%) rename {DiztinGUIsh => Diz.Core}/core/import/BizHawkCdlImporter.cs (100%) rename {DiztinGUIsh => Diz.Core}/core/import/SampleRomData.cs (99%) rename {DiztinGUIsh => Diz.Core}/core/util/ByteUtil.cs (100%) rename {DiztinGUIsh => Diz.Core}/core/util/ObservableDictionaryAdaptor.cs (100%) rename {DiztinGUIsh => Diz.Core}/core/util/RomUtil.cs (100%) rename {DiztinGUIsh => Diz.Core}/core/util/Util.cs (100%) rename {DiztinGUIsh => Diz.Core}/loadsave/ImportSettings.cs (100%) rename {DiztinGUIsh => Diz.Core}/loadsave/ProjectFileManager.cs (91%) rename {DiztinGUIsh => Diz.Core}/loadsave/ProjectSerializer.cs (100%) rename {DiztinGUIsh => Diz.Core}/loadsave/binary_serializer_old/BinarySerializer.cs (97%) rename {DiztinGUIsh => Diz.Core}/loadsave/xml_serializer/ProjectXMLSerializer.cs (100%) rename {DiztinGUIsh => Diz.Core}/loadsave/xml_serializer/RomBytesXMLSerializer.cs (100%) rename {DiztinGUIsh => Diz.Core}/loadsave/xml_serializer/XMLSerializerSupport.cs (100%) create mode 100644 Diz.Core/packages.config rename DiztinGUIsh/{core/util => window}/LargeFilesReader.cs (100%) rename DiztinGUIsh/{core/util => window}/ProgressBarWorker.cs (100%) diff --git a/Diz.Core/Diz.Core.csproj b/Diz.Core/Diz.Core.csproj new file mode 100644 index 00000000..1cd5d39c --- /dev/null +++ b/Diz.Core/Diz.Core.csproj @@ -0,0 +1,144 @@ + + + + + Debug + AnyCPU + {50646B00-03D8-4CEC-9ED1-3EF4CB199E8B} + Library + Properties + Diz.Core + Diz.Core + v4.8 + 512 + true + 8.0 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\ExtendedXmlSerializer.3.3.0\lib\net452\ExtendedXmlSerializer.dll + + + ..\packages\IX.Abstractions.0.5.3\lib\net472\IX.Abstractions.dll + + + ..\packages\IX.Abstractions.Collections.0.5.3\lib\net472\IX.Abstractions.Collections.dll + + + ..\packages\IX.Abstractions.Threading.0.5.3\lib\net472\IX.Abstractions.Threading.dll + + + ..\packages\IX.Observable.0.5.3\lib\net472\IX.Observable.dll + + + ..\packages\IX.StandardExtensions.0.5.3\lib\net472\IX.StandardExtensions.dll + + + ..\packages\IX.StandardExtensions.ComponentModel.0.5.3\lib\net472\IX.StandardExtensions.ComponentModel.dll + + + ..\packages\IX.StandardExtensions.Threading.0.5.3\lib\net472\IX.StandardExtensions.Threading.dll + + + ..\packages\IX.Undoable.0.5.3\lib\net472\IX.Undoable.dll + + + ..\packages\JetBrains.Annotations.2019.1.3\lib\net20\JetBrains.Annotations.dll + + + ..\packages\LightInject.6.2.0\lib\net46\LightInject.dll + + + ..\packages\NReco.LambdaParser.1.0.11\lib\net45\NReco.LambdaParser.dll + + + ..\packages\Sprache.2.2.0\lib\net45\Sprache.dll + + + + ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll + + + ..\packages\System.Collections.Immutable.1.7.0\lib\netstandard2.0\System.Collections.Immutable.dll + + + + + ..\packages\System.Interactive.4.0.0\lib\net45\System.Interactive.dll + + + + + ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll + + + + ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll + + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + + + + ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DiztinGUIsh/Model.cs b/Diz.Core/Model.cs similarity index 92% rename from DiztinGUIsh/Model.cs rename to Diz.Core/Model.cs index c665c0f1..46d69983 100644 --- a/DiztinGUIsh/Model.cs +++ b/Diz.Core/Model.cs @@ -1,17 +1,13 @@ using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; -using DiztinGUIsh.Annotations; +using JetBrains.Annotations; namespace DiztinGUIsh { public class DizDataModel : PropertyNotifyChanged { - } - public class DizViewModel : PropertyNotifyChanged - { - } public class PropertyNotifyChanged : INotifyPropertyChanged { diff --git a/Diz.Core/Properties/AssemblyInfo.cs b/Diz.Core/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..505f44b1 --- /dev/null +++ b/Diz.Core/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Diz.Core")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Diz.Core")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("50646b00-03d8-4cec-9ed1-3ef4cb199e8b")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Diz.Core/app.config b/Diz.Core/app.config new file mode 100644 index 00000000..72259e86 --- /dev/null +++ b/Diz.Core/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/DiztinGUIsh/core/CPU65C816.cs b/Diz.Core/core/CPU65C816.cs similarity index 100% rename from DiztinGUIsh/core/CPU65C816.cs rename to Diz.Core/core/CPU65C816.cs diff --git a/DiztinGUIsh/core/Data.cs b/Diz.Core/core/Data.cs similarity index 100% rename from DiztinGUIsh/core/Data.cs rename to Diz.Core/core/Data.cs diff --git a/DiztinGUIsh/core/Label.cs b/Diz.Core/core/Label.cs similarity index 100% rename from DiztinGUIsh/core/Label.cs rename to Diz.Core/core/Label.cs diff --git a/DiztinGUIsh/core/LogCreator.cs b/Diz.Core/core/LogCreator.cs similarity index 98% rename from DiztinGUIsh/core/LogCreator.cs rename to Diz.Core/core/LogCreator.cs index b347d827..948b007c 100644 --- a/DiztinGUIsh/core/LogCreator.cs +++ b/Diz.Core/core/LogCreator.cs @@ -27,6 +27,8 @@ public struct LogWriterSettings public string file; public string error; + public bool wasInitialized; + public void SetDefaults() { format = "%label:-22% %code:37%;%pc%|%bytes%|%ia%; %comment%"; @@ -37,6 +39,15 @@ public void SetDefaults() printLabelSpecificComments = false; file = ""; // path to file or folder, rename error = ""; // path to file or folder, rename + wasInitialized = true; + } + + public bool Validate() + { + // TODO: add more validation. + + // for now, just make sure it was initialized somewhere by someone + return wasInitialized; } } @@ -149,7 +160,7 @@ public OutputResult CreateLog() bankSize = RomUtil.GetBankSize(Data.RomMapMode); errorCount = 0; - // TODO: this label combination isn't working well. fix. + // TODO: this label combination idea isn't working well. fix. // could create a copy of the data in the controller before we get here and // pass that in. unsubscribe all the notify events from it first. // ehhhh... is that a little weird... maybe. @@ -169,18 +180,10 @@ public OutputResult CreateLog() int bank = -1; - // show a progress bar while this happens - // TODO: this is view stuff, keep it out of here. - // call controller with "LongRunningTask" - ProgressBarJob.Loop(size, () => - { - if (pointer >= size) - return -1; // means "stop looping" - + // perf: this is the meat of the export, takes a while + while (pointer < size) { WriteAddress(ref pointer, ref bank); - - return (long) pointer; // report current address as the progress - }); + } WriteLabels(pointer); diff --git a/DiztinGUIsh/core/Project.cs b/Diz.Core/core/Project.cs similarity index 100% rename from DiztinGUIsh/core/Project.cs rename to Diz.Core/core/Project.cs diff --git a/DiztinGUIsh/core/ROMByte.cs b/Diz.Core/core/ROMByte.cs similarity index 100% rename from DiztinGUIsh/core/ROMByte.cs rename to Diz.Core/core/ROMByte.cs diff --git a/DiztinGUIsh/core/RomBytes.cs b/Diz.Core/core/RomBytes.cs similarity index 100% rename from DiztinGUIsh/core/RomBytes.cs rename to Diz.Core/core/RomBytes.cs diff --git a/DiztinGUIsh/core/import/BSNESImporter.cs b/Diz.Core/core/import/BSNESImporter.cs similarity index 98% rename from DiztinGUIsh/core/import/BSNESImporter.cs rename to Diz.Core/core/import/BSNESImporter.cs index 838eee2d..55b07dfe 100644 --- a/DiztinGUIsh/core/import/BSNESImporter.cs +++ b/Diz.Core/core/import/BSNESImporter.cs @@ -6,7 +6,7 @@ namespace DiztinGUIsh.core.import { - class BSNESUsageMapImporter + public class BSNESUsageMapImporter { // TODO: move BsnesPlusUsage stuff to its own class outside of Data [Flags] @@ -76,7 +76,7 @@ public int ImportUsageMap(byte[] usageMap, Data data) } } - class BSNESTraceLogImporter + public class BSNESTraceLogImporter { // this class exists for performance optimization ONLY. // class representing offsets into a trace log diff --git a/DiztinGUIsh/core/import/BizHawkCdlImporter.cs b/Diz.Core/core/import/BizHawkCdlImporter.cs similarity index 100% rename from DiztinGUIsh/core/import/BizHawkCdlImporter.cs rename to Diz.Core/core/import/BizHawkCdlImporter.cs diff --git a/DiztinGUIsh/core/import/SampleRomData.cs b/Diz.Core/core/import/SampleRomData.cs similarity index 99% rename from DiztinGUIsh/core/import/SampleRomData.cs rename to Diz.Core/core/import/SampleRomData.cs index cb353b9c..b93d65fc 100644 --- a/DiztinGUIsh/core/import/SampleRomData.cs +++ b/Diz.Core/core/import/SampleRomData.cs @@ -4,7 +4,7 @@ namespace DiztinGUIsh { - internal class SampleRomData : Data + public class SampleRomData : Data { public static SampleRomData SampleData { diff --git a/DiztinGUIsh/core/util/ByteUtil.cs b/Diz.Core/core/util/ByteUtil.cs similarity index 100% rename from DiztinGUIsh/core/util/ByteUtil.cs rename to Diz.Core/core/util/ByteUtil.cs diff --git a/DiztinGUIsh/core/util/ObservableDictionaryAdaptor.cs b/Diz.Core/core/util/ObservableDictionaryAdaptor.cs similarity index 100% rename from DiztinGUIsh/core/util/ObservableDictionaryAdaptor.cs rename to Diz.Core/core/util/ObservableDictionaryAdaptor.cs diff --git a/DiztinGUIsh/core/util/RomUtil.cs b/Diz.Core/core/util/RomUtil.cs similarity index 100% rename from DiztinGUIsh/core/util/RomUtil.cs rename to Diz.Core/core/util/RomUtil.cs diff --git a/DiztinGUIsh/core/util/Util.cs b/Diz.Core/core/util/Util.cs similarity index 100% rename from DiztinGUIsh/core/util/Util.cs rename to Diz.Core/core/util/Util.cs diff --git a/DiztinGUIsh/loadsave/ImportSettings.cs b/Diz.Core/loadsave/ImportSettings.cs similarity index 100% rename from DiztinGUIsh/loadsave/ImportSettings.cs rename to Diz.Core/loadsave/ImportSettings.cs diff --git a/DiztinGUIsh/loadsave/ProjectFileManager.cs b/Diz.Core/loadsave/ProjectFileManager.cs similarity index 91% rename from DiztinGUIsh/loadsave/ProjectFileManager.cs rename to Diz.Core/loadsave/ProjectFileManager.cs index b541d259..92d9bcbf 100644 --- a/DiztinGUIsh/loadsave/ProjectFileManager.cs +++ b/Diz.Core/loadsave/ProjectFileManager.cs @@ -1,7 +1,6 @@ using System; using System.Diagnostics; using System.IO; -using System.Windows.Forms; using DiztinGUIsh.core; using DiztinGUIsh.loadsave.binary_serializer_old; using DiztinGUIsh.loadsave.xml_serializer; @@ -11,20 +10,6 @@ namespace DiztinGUIsh.loadsave public static class ProjectFileManager { public static Project Open(string filename, Func romPromptFn) - { - try - { - return DoOpen(filename, romPromptFn); - } - catch (Exception e) - { - // TODO: remove direct GUI stuff from here. - MessageBox.Show(e.Message, "Error opening project file", MessageBoxButtons.OK, MessageBoxIcon.Error); - return null; - } - } - - private static Project DoOpen(string filename, Func romPromptFn) { var data = File.ReadAllBytes(filename); diff --git a/DiztinGUIsh/loadsave/ProjectSerializer.cs b/Diz.Core/loadsave/ProjectSerializer.cs similarity index 100% rename from DiztinGUIsh/loadsave/ProjectSerializer.cs rename to Diz.Core/loadsave/ProjectSerializer.cs diff --git a/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs b/Diz.Core/loadsave/binary_serializer_old/BinarySerializer.cs similarity index 97% rename from DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs rename to Diz.Core/loadsave/binary_serializer_old/BinarySerializer.cs index 1b06bffe..31eae88f 100644 --- a/DiztinGUIsh/loadsave/binary_serializer_old/BinarySerializer.cs +++ b/Diz.Core/loadsave/binary_serializer_old/BinarySerializer.cs @@ -3,12 +3,8 @@ using System.Diagnostics; using System.IO; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; using DiztinGUIsh.core; using DiztinGUIsh.core.util; -using DiztinGUIsh.window; namespace DiztinGUIsh.loadsave.binary_serializer_old { @@ -214,11 +210,11 @@ private static void ValidateProjectFileVersion(int version) } else if (version != LATEST_FILE_FORMAT_VERSION) { - MessageBox.Show( + throw new ArgumentException( "This project file is in an older format.\n" + "You may want to back up your work or 'Save As' in case the conversion goes wrong.\n" + "The project file will be untouched until it is saved again.", - "Project File Out of Date", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + "Project File Out of Date"); } if (version < 0) diff --git a/DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs b/Diz.Core/loadsave/xml_serializer/ProjectXMLSerializer.cs similarity index 100% rename from DiztinGUIsh/loadsave/xml_serializer/ProjectXMLSerializer.cs rename to Diz.Core/loadsave/xml_serializer/ProjectXMLSerializer.cs diff --git a/DiztinGUIsh/loadsave/xml_serializer/RomBytesXMLSerializer.cs b/Diz.Core/loadsave/xml_serializer/RomBytesXMLSerializer.cs similarity index 100% rename from DiztinGUIsh/loadsave/xml_serializer/RomBytesXMLSerializer.cs rename to Diz.Core/loadsave/xml_serializer/RomBytesXMLSerializer.cs diff --git a/DiztinGUIsh/loadsave/xml_serializer/XMLSerializerSupport.cs b/Diz.Core/loadsave/xml_serializer/XMLSerializerSupport.cs similarity index 100% rename from DiztinGUIsh/loadsave/xml_serializer/XMLSerializerSupport.cs rename to Diz.Core/loadsave/xml_serializer/XMLSerializerSupport.cs diff --git a/Diz.Core/packages.config b/Diz.Core/packages.config new file mode 100644 index 00000000..e0d70f50 --- /dev/null +++ b/Diz.Core/packages.config @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DiztinGUIsh.sln b/DiztinGUIsh.sln index 60f3fa16..4f4b8af5 100644 --- a/DiztinGUIsh.sln +++ b/DiztinGUIsh.sln @@ -1,10 +1,12 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.421 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30503.244 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiztinGUIsh", "DiztinGUIsh\DiztinGUIsh.csproj", "{2A2DD3C1-9E64-4CD7-98A5-310D9FED2CA3}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Diz.Core", "Diz.Core\Diz.Core.csproj", "{50646B00-03D8-4CEC-9ED1-3EF4CB199E8B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +17,10 @@ Global {2A2DD3C1-9E64-4CD7-98A5-310D9FED2CA3}.Debug|Any CPU.Build.0 = Debug|Any CPU {2A2DD3C1-9E64-4CD7-98A5-310D9FED2CA3}.Release|Any CPU.ActiveCfg = Release|Any CPU {2A2DD3C1-9E64-4CD7-98A5-310D9FED2CA3}.Release|Any CPU.Build.0 = Release|Any CPU + {50646B00-03D8-4CEC-9ED1-3EF4CB199E8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {50646B00-03D8-4CEC-9ED1-3EF4CB199E8B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {50646B00-03D8-4CEC-9ED1-3EF4CB199E8B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {50646B00-03D8-4CEC-9ED1-3EF4CB199E8B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 444041f9..6b262e1a 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -14,6 +14,8 @@ true false + + publish\ true Disk @@ -28,8 +30,6 @@ 1.0.0.%2a false true - - AnyCPU @@ -60,9 +60,6 @@ DiztinGUIsh.Program - - ..\packages\ExtendedXmlSerializer.3.3.0.1-xbhphjmm\lib\net452\ExtendedXmlSerializer.dll - ..\packages\IX.Abstractions.0.5.3\lib\net472\IX.Abstractions.dll @@ -93,12 +90,6 @@ ..\packages\LightInject.6.3.5\lib\net46\LightInject.dll - - ..\packages\NReco.LambdaParser.1.0.12\lib\net45\NReco.LambdaParser.dll - - - ..\packages\Sprache.2.3.1\lib\net45\Sprache.dll - ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll @@ -140,21 +131,8 @@ - - - - - - - - - - - - - - - + + @@ -165,17 +143,13 @@ - - - Form About.cs - Form @@ -212,7 +186,6 @@ InOutPointChecker.cs - Form @@ -238,11 +211,7 @@ MisalignmentChecker.cs - - - - AliasList.cs @@ -324,7 +293,12 @@ false - + + + {50646b00-03d8-4cec-9ed1-3ef4cb199e8b} + Diz.Core + + diff --git a/DiztinGUIsh/Program.cs b/DiztinGUIsh/Program.cs index ea4e3c3c..575c0f6d 100644 --- a/DiztinGUIsh/Program.cs +++ b/DiztinGUIsh/Program.cs @@ -1,9 +1,5 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using System.Windows.Forms; -using DiztinGUIsh.window.dialog; namespace DiztinGUIsh { diff --git a/DiztinGUIsh/packages.config b/DiztinGUIsh/packages.config index 004248fa..c8e86364 100644 --- a/DiztinGUIsh/packages.config +++ b/DiztinGUIsh/packages.config @@ -1,6 +1,5 @@  - @@ -12,8 +11,6 @@ - - diff --git a/DiztinGUIsh/core/util/LargeFilesReader.cs b/DiztinGUIsh/window/LargeFilesReader.cs similarity index 100% rename from DiztinGUIsh/core/util/LargeFilesReader.cs rename to DiztinGUIsh/window/LargeFilesReader.cs diff --git a/DiztinGUIsh/core/util/ProgressBarWorker.cs b/DiztinGUIsh/window/ProgressBarWorker.cs similarity index 100% rename from DiztinGUIsh/core/util/ProgressBarWorker.cs rename to DiztinGUIsh/window/ProgressBarWorker.cs diff --git a/DiztinGUIsh/window/ProjectController.cs b/DiztinGUIsh/window/ProjectController.cs index 0889e632..83d7975a 100644 --- a/DiztinGUIsh/window/ProjectController.cs +++ b/DiztinGUIsh/window/ProjectController.cs @@ -62,8 +62,13 @@ public bool OpenProject(string filename) { Project project = null; + // TODO: try/catch for ProjectFileManager DoLongRunningTask(delegate { - project = ProjectFileManager.Open(filename, AskToSelectNewRomFilename); + try { + project = ProjectFileManager.Open(filename, AskToSelectNewRomFilename); + } catch (Exception) { + project = null; + } }, $"Opening {Path.GetFileName(filename)}..."); if (project == null) @@ -143,10 +148,10 @@ private string AskToSelectNewRomFilename(string error) public void WriteAssemblyOutput() { - WriteAssemblyOutput(Project.LogWriterSettings); + WriteAssemblyOutput(Project.LogWriterSettings, true); } - private void WriteAssemblyOutput(LogWriterSettings settings) + private void WriteAssemblyOutput(LogWriterSettings settings, bool showProgressBarUpdates = false) { // kinda hate that we're passing in these... using var sw = new StreamWriter(settings.file); @@ -160,7 +165,10 @@ private void WriteAssemblyOutput(LogWriterSettings settings) StreamError = er, }; - var result = lc.CreateLog(); + LogCreator.OutputResult result = null; + DoLongRunningTask(delegate { + result = lc.CreateLog(); + }, $"Exporting assembly source code..."); if (result.error_count == 0) File.Delete(settings.error); diff --git a/DiztinGUIsh/window/dialog/ExportDisassembly.cs b/DiztinGUIsh/window/dialog/ExportDisassembly.cs index 82203fb0..9577c8c0 100644 --- a/DiztinGUIsh/window/dialog/ExportDisassembly.cs +++ b/DiztinGUIsh/window/dialog/ExportDisassembly.cs @@ -32,6 +32,9 @@ public ExportDisassembly(Project project) Project = project; settings = project.LogWriterSettings; // copy + if (!settings.Validate()) + settings.SetDefaults(); + InitializeComponent(); UpdateUiFromProjectSettings(); RegenerateSampleOutput(); @@ -64,20 +67,21 @@ private void button2_Click(object sender, EventArgs e) // Prompt user for either a filename to save, or a folder location private string PromptForLogPathFromFileOrFolderDialog(bool askForFile) { - if (askForFile) - { - saveLogSingleFile.InitialDirectory = Project.ProjectFileName; - if (saveLogSingleFile.ShowDialog() == DialogResult.OK && saveLogSingleFile.FileName != "") - return saveLogSingleFile.FileName; - } - else - { - chooseLogFolder.SelectedPath = Path.GetDirectoryName(Project.ProjectFileName); - if (chooseLogFolder.ShowDialog() == DialogResult.OK && chooseLogFolder.SelectedPath != "") - return saveLogSingleFile.FileName; - } + return askForFile ? PromptSaveLogFile() : PromptSaveLogPath(); + } - return null; + private string PromptSaveLogPath() + { + chooseLogFolder.SelectedPath = Path.GetDirectoryName(Project.ProjectFileName); + return chooseLogFolder.ShowDialog() == DialogResult.OK && chooseLogFolder.SelectedPath != "" + ? chooseLogFolder.SelectedPath : null; + } + + private string PromptSaveLogFile() + { + saveLogSingleFile.InitialDirectory = Project.ProjectFileName; + return saveLogSingleFile.ShowDialog() == DialogResult.OK && saveLogSingleFile.FileName != "" + ? saveLogSingleFile.FileName : null; } private bool PromptForPath() From c41db276a8982d51b33c3aeca89c57c130f77bb8 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 6 Oct 2020 11:58:37 -0400 Subject: [PATCH 063/136] add Xunit unit testing framework and sample test --- Diz.Core/core/Data.cs | 1 + Diz.Core/core/ROMByte.cs | 14 ++- Diz.Core/core/RomBytes.cs | 1 + Diz.Core/core/import/SampleRomData.cs | 3 +- .../xml_serializer/RomBytesXMLSerializer.cs | 1 + Diz.Test/Diz.Test.csproj | 92 +++++++++++++++++++ Diz.Test/Properties/AssemblyInfo.cs | 36 ++++++++ Diz.Test/RomByteTests.cs | 55 +++++++++++ Diz.Test/packages.config | 12 +++ DiztinGUIsh.sln | 6 ++ 10 files changed, 212 insertions(+), 9 deletions(-) create mode 100644 Diz.Test/Diz.Test.csproj create mode 100644 Diz.Test/Properties/AssemblyInfo.cs create mode 100644 Diz.Test/RomByteTests.cs create mode 100644 Diz.Test/packages.config diff --git a/Diz.Core/core/Data.cs b/Diz.Core/core/Data.cs index 3dd12769..0cd99900 100644 --- a/Diz.Core/core/Data.cs +++ b/Diz.Core/core/Data.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Linq; using System.Text; +using Diz.Core.core; using DiztinGUIsh.core.util; using IX.Observable; diff --git a/Diz.Core/core/ROMByte.cs b/Diz.Core/core/ROMByte.cs index 87cd1512..e810b4bb 100644 --- a/Diz.Core/core/ROMByte.cs +++ b/Diz.Core/core/ROMByte.cs @@ -1,11 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using DiztinGUIsh.core; +using DiztinGUIsh.core; -namespace DiztinGUIsh +namespace Diz.Core.core { public class ROMByte { @@ -45,7 +40,10 @@ public override int GetHashCode() } #endregion - public byte Rom { get; set; } // never serialize this, read from ROM on load. for copyright reasons. + // holds the original byte from the source ROM + public byte Rom { get; set; } // never serialize this, read from ROM on load. (for copyright reasons) + + // everything else is metadata that describes the source byte above public byte DataBank { get; set; } public int DirectPage { get; set; } public bool XFlag { get; set; } diff --git a/Diz.Core/core/RomBytes.cs b/Diz.Core/core/RomBytes.cs index a114b0bf..013de33d 100644 --- a/Diz.Core/core/RomBytes.cs +++ b/Diz.Core/core/RomBytes.cs @@ -1,6 +1,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using Diz.Core.core; namespace DiztinGUIsh { diff --git a/Diz.Core/core/import/SampleRomData.cs b/Diz.Core/core/import/SampleRomData.cs index b93d65fc..3ae3eae2 100644 --- a/Diz.Core/core/import/SampleRomData.cs +++ b/Diz.Core/core/import/SampleRomData.cs @@ -1,4 +1,5 @@ -using DiztinGUIsh.core; +using Diz.Core.core; +using DiztinGUIsh.core; using DiztinGUIsh.core.util; using IX.Observable; diff --git a/Diz.Core/loadsave/xml_serializer/RomBytesXMLSerializer.cs b/Diz.Core/loadsave/xml_serializer/RomBytesXMLSerializer.cs index df486655..a4d582f6 100644 --- a/Diz.Core/loadsave/xml_serializer/RomBytesXMLSerializer.cs +++ b/Diz.Core/loadsave/xml_serializer/RomBytesXMLSerializer.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.IO; using System.Linq; +using Diz.Core.core; using DiztinGUIsh.core; using ExtendedXmlSerializer.ContentModel; using ExtendedXmlSerializer.ContentModel.Format; diff --git a/Diz.Test/Diz.Test.csproj b/Diz.Test/Diz.Test.csproj new file mode 100644 index 00000000..c76690dd --- /dev/null +++ b/Diz.Test/Diz.Test.csproj @@ -0,0 +1,92 @@ + + + + + + + + Debug + AnyCPU + {594DE30A-343F-4C09-828D-65A67626A491} + Library + Properties + Diz.Test + Diz.Test + v4.8 + 512 + true + 8.0 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + ..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll + + + ..\packages\xunit.assert.2.4.1\lib\netstandard1.1\xunit.assert.dll + + + ..\packages\xunit.extensibility.core.2.4.1\lib\net452\xunit.core.dll + + + ..\packages\xunit.extensibility.execution.2.4.1\lib\net452\xunit.execution.desktop.dll + + + + + + + + + + + + + + + {50646b00-03d8-4cec-9ed1-3ef4cb199e8b} + Diz.Core + + + {2a2dd3c1-9e64-4cd7-98a5-310d9fed2ca3} + DiztinGUIsh + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + \ No newline at end of file diff --git a/Diz.Test/Properties/AssemblyInfo.cs b/Diz.Test/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..9260ec1f --- /dev/null +++ b/Diz.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Diz.Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Diz.Test")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("594de30a-343f-4c09-828d-65a67626a491")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Diz.Test/RomByteTests.cs b/Diz.Test/RomByteTests.cs new file mode 100644 index 00000000..7e078cc4 --- /dev/null +++ b/Diz.Test/RomByteTests.cs @@ -0,0 +1,55 @@ +using Diz.Core.core; +using DiztinGUIsh.core; +using Xunit; + +namespace Diz.Test +{ + public sealed class RomByteTests + { + private static ROMByte SampleRomByte1() + { + return new ROMByte() { + Arch = Data.Architecture.APUSPC700, + DataBank = 90, + DirectPage = 3, + MFlag = true, + XFlag = false, + TypeFlag = Data.FlagType.Graphics, + Point = Data.InOutPoint.InPoint | Data.InOutPoint.ReadPoint, + Rom = 0x78, + }; + } + + private static ROMByte SampleRomByte2() + { + // same as above, but just change .Rom + var rb = SampleRomByte1(); + rb.Rom = 0x99; + return rb; + } + + [Fact] + public void TestEqualsButNotCompareByte() + { + var rb1 = SampleRomByte1(); + var rb2 = SampleRomByte2(); + + Assert.True(rb1.EqualsButNoRomByte(rb2)); + Assert.False(rb1.Equals(rb2)); + + rb1.Point = Data.InOutPoint.EndPoint; + Assert.False(rb1.EqualsButNoRomByte(rb2)); + Assert.False(rb1.Equals(rb2)); + } + + [Fact] + public void TestEquals() + { + var rb1 = SampleRomByte1(); + var rb2 = SampleRomByte1(); + + Assert.True(rb1.Equals(rb2)); + Assert.True(rb1.EqualsButNoRomByte(rb2)); + } + } +} diff --git a/Diz.Test/packages.config b/Diz.Test/packages.config new file mode 100644 index 00000000..3cc692e6 --- /dev/null +++ b/Diz.Test/packages.config @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/DiztinGUIsh.sln b/DiztinGUIsh.sln index 4f4b8af5..e9b78e65 100644 --- a/DiztinGUIsh.sln +++ b/DiztinGUIsh.sln @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiztinGUIsh", "DiztinGUIsh\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Diz.Core", "Diz.Core\Diz.Core.csproj", "{50646B00-03D8-4CEC-9ED1-3EF4CB199E8B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Diz.Test", "Diz.Test\Diz.Test.csproj", "{594DE30A-343F-4C09-828D-65A67626A491}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +23,10 @@ Global {50646B00-03D8-4CEC-9ED1-3EF4CB199E8B}.Debug|Any CPU.Build.0 = Debug|Any CPU {50646B00-03D8-4CEC-9ED1-3EF4CB199E8B}.Release|Any CPU.ActiveCfg = Release|Any CPU {50646B00-03D8-4CEC-9ED1-3EF4CB199E8B}.Release|Any CPU.Build.0 = Release|Any CPU + {594DE30A-343F-4C09-828D-65A67626A491}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {594DE30A-343F-4C09-828D-65A67626A491}.Debug|Any CPU.Build.0 = Debug|Any CPU + {594DE30A-343F-4C09-828D-65A67626A491}.Release|Any CPU.ActiveCfg = Release|Any CPU + {594DE30A-343F-4C09-828D-65A67626A491}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 8eacfe543b29a3a1773685e9bde395699f7214e9 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 6 Oct 2020 13:03:25 -0400 Subject: [PATCH 064/136] WIP unit test to figure out IDictionary Serializer stuff --- Diz.Core/core/CPU65C816.cs | 30 +++++----- Diz.Test/Diz.Test.csproj | 69 ++++++++++++++++++++++ Diz.Test/SerializerTest.cs | 114 +++++++++++++++++++++++++++++++++++++ Diz.Test/app.config | 11 ++++ Diz.Test/packages.config | 20 +++++++ 5 files changed, 230 insertions(+), 14 deletions(-) create mode 100644 Diz.Test/SerializerTest.cs create mode 100644 Diz.Test/app.config diff --git a/Diz.Core/core/CPU65C816.cs b/Diz.Core/core/CPU65C816.cs index 63e9de56..03efafc8 100644 --- a/Diz.Core/core/CPU65C816.cs +++ b/Diz.Core/core/CPU65C816.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using DiztinGUIsh.core; +using DiztinGUIsh.core; namespace DiztinGUIsh { @@ -269,7 +264,7 @@ private string GetMnemonic(int offset, bool showHint = true) return mn; } - private int BytesToShow(AddressMode mode) + private static int BytesToShow(AddressMode mode) { switch (mode) { @@ -308,7 +303,7 @@ private int BytesToShow(AddressMode mode) // {2} = operand 2 for block move private string GetInstructionFormatString(int offset) { - AddressMode mode = GetAddressMode(offset); + var mode = GetAddressMode(offset); switch (mode) { case AddressMode.IMPLIED: @@ -357,10 +352,17 @@ private string GetInstructionFormatString(int offset) private AddressMode GetAddressMode(int offset) { - AddressMode mode = addressingModes[Data.GetROMByte(offset)]; - if (mode == AddressMode.IMMEDIATE_M_FLAG_DEPENDENT) return Data.GetMFlag(offset) ? AddressMode.IMMEDIATE_8 : AddressMode.IMMEDIATE_16; - else if (mode == AddressMode.IMMEDIATE_X_FLAG_DEPENDENT) return Data.GetXFlag(offset) ? AddressMode.IMMEDIATE_8 : AddressMode.IMMEDIATE_16; - return mode; + var mode = addressingModes[Data.GetROMByte(offset)]; + return mode switch + { + AddressMode.IMMEDIATE_M_FLAG_DEPENDENT => Data.GetMFlag(offset) + ? AddressMode.IMMEDIATE_8 + : AddressMode.IMMEDIATE_16, + AddressMode.IMMEDIATE_X_FLAG_DEPENDENT => Data.GetXFlag(offset) + ? AddressMode.IMMEDIATE_8 + : AddressMode.IMMEDIATE_16, + _ => mode + }; } public enum AddressMode : byte @@ -376,7 +378,7 @@ public enum AddressMode : byte LONG, LONG_X_INDEX, BLOCK_MOVE, RELATIVE_8, RELATIVE_16 } - private static string[] mnemonics = + private static readonly string[] mnemonics = { "BRK", "ORA", "COP", "ORA", "TSB", "ORA", "ASL", "ORA", "PHP", "ORA", "ASL", "PHD", "TSB", "ORA", "ASL", "ORA", "BPL", "ORA", "ORA", "ORA", "TRB", "ORA", "ASL", "ORA", "CLC", "ORA", "INC", "TCS", "TRB", "ORA", "ASL", "ORA", @@ -396,7 +398,7 @@ public enum AddressMode : byte "BEQ", "SBC", "SBC", "SBC", "PEA", "SBC", "INC", "SBC", "SED", "SBC", "PLX", "XCE", "JSR", "SBC", "INC", "SBC" }; - private static AddressMode[] addressingModes = + private static readonly AddressMode[] addressingModes = { AddressMode.CONSTANT_8, AddressMode.DIRECT_PAGE_X_INDEX_INDIRECT, AddressMode.CONSTANT_8, AddressMode.DIRECT_PAGE_S_INDEX, AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE_LONG_INDIRECT, diff --git a/Diz.Test/Diz.Test.csproj b/Diz.Test/Diz.Test.csproj index c76690dd..39e2e183 100644 --- a/Diz.Test/Diz.Test.csproj +++ b/Diz.Test/Diz.Test.csproj @@ -37,8 +37,75 @@ 4 + + ..\packages\ExtendedXmlSerializer.3.3.0\lib\net452\ExtendedXmlSerializer.dll + + + ..\packages\IX.Abstractions.0.5.3\lib\net472\IX.Abstractions.dll + + + ..\packages\IX.Abstractions.Collections.0.5.3\lib\net472\IX.Abstractions.Collections.dll + + + ..\packages\IX.Abstractions.Threading.0.5.3\lib\net472\IX.Abstractions.Threading.dll + + + ..\packages\IX.Observable.0.5.3\lib\net472\IX.Observable.dll + + + ..\packages\IX.StandardExtensions.0.5.3\lib\net472\IX.StandardExtensions.dll + + + ..\packages\IX.StandardExtensions.ComponentModel.0.5.3\lib\net472\IX.StandardExtensions.ComponentModel.dll + + + ..\packages\IX.StandardExtensions.Threading.0.5.3\lib\net472\IX.StandardExtensions.Threading.dll + + + ..\packages\IX.Undoable.0.5.3\lib\net472\IX.Undoable.dll + + + ..\packages\JetBrains.Annotations.2019.1.3\lib\net20\JetBrains.Annotations.dll + + + ..\packages\LightInject.6.2.0\lib\net46\LightInject.dll + + + ..\packages\NReco.LambdaParser.1.0.11\lib\net45\NReco.LambdaParser.dll + + + ..\packages\Sprache.2.2.0\lib\net45\Sprache.dll + + + ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll + + + ..\packages\System.Collections.Immutable.1.7.0\lib\netstandard2.0\System.Collections.Immutable.dll + + + + ..\packages\System.Interactive.4.0.0\lib\net45\System.Interactive.dll + + + + + ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll + + + + ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll + + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + + + + ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll + @@ -61,8 +128,10 @@ + + diff --git a/Diz.Test/SerializerTest.cs b/Diz.Test/SerializerTest.cs new file mode 100644 index 00000000..429dbeab --- /dev/null +++ b/Diz.Test/SerializerTest.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Xml; +using ExtendedXmlSerializer; +using ExtendedXmlSerializer.Configuration; +using IX.Observable; +using IX.Undoable; +using Xunit; + +namespace Diz.Test +{ + public class SerializerTest + { + internal class Root + { + private ODWrapper wrap { get; set; } = new ODWrapper + { + OD = { + [3] = "Test3", + [4] = "Test4" + } + }; +} + internal class ODWrapper : ICollection> + { + //public ObservableDictionaryAdaptor dict { get; set; } + // = new ObservableDictionaryAdaptor(); + + public ObservableDictionary OD { get; set; } = new ObservableDictionary(); + + public Dictionary Dict + { + get => new Dictionary(OD); + set + { + OD.Clear(); + foreach (var item in value) + { + OD.Add(item); + } + } + } + + public IEnumerator> GetEnumerator() + { + return OD.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void Add(KeyValuePair item) + { + OD.Add(item.Key, item.Value); + } + + public void Clear() + { + OD.Clear(); + } + + public bool Contains(KeyValuePair item) + { + return OD.Contains(item); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + OD.CopyTo(array, arrayIndex); + } + + public bool Remove(KeyValuePair item) + { + return OD.Remove(item); + } + + public int Count => OD.Count; + public bool IsReadOnly => OD.IsReadOnly; + } + + private static IExtendedXmlSerializer GetSerializer() + { + return new ConfigurationContainer() + // .UseAutoFormatting() + .EnableImplicitTyping(typeof(Root)) + .EnableImplicitTyping(typeof(ODWrapper)) + .Type>() + .Member(x=>x.OD).Ignore() + .UseOptimizedNamespaces() + .Create(); + } + + [Fact] + private void Serializer() + { + var serializer = GetSerializer(); + + var rootElement = new Root(); + + var xmlStr = serializer.Serialize( + new XmlWriterSettings {Indent = true}, + rootElement); + + // NOT WORKING. doesn't output the right text, skipping all elements + Console.WriteLine(xmlStr); + Assert.Equal("asdf", xmlStr); + } + } +} \ No newline at end of file diff --git a/Diz.Test/app.config b/Diz.Test/app.config new file mode 100644 index 00000000..72259e86 --- /dev/null +++ b/Diz.Test/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Diz.Test/packages.config b/Diz.Test/packages.config index 3cc692e6..eb318828 100644 --- a/Diz.Test/packages.config +++ b/Diz.Test/packages.config @@ -1,5 +1,25 @@  + + + + + + + + + + + + + + + + + + + + From b4c1ffdbc01bc59a372bdee059d10caee485e17e Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 6 Oct 2020 15:22:32 -0400 Subject: [PATCH 065/136] working (but messy as all hell) observabledict serializer --- Diz.Test/SerializerTest.cs | 170 ++++++++++++++++++++++++++++++++++--- 1 file changed, 156 insertions(+), 14 deletions(-) diff --git a/Diz.Test/SerializerTest.cs b/Diz.Test/SerializerTest.cs index 429dbeab..13b0bb7e 100644 --- a/Diz.Test/SerializerTest.cs +++ b/Diz.Test/SerializerTest.cs @@ -3,9 +3,18 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Reflection; +using System.Threading; using System.Xml; +using System.Xml.Linq; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; +using ExtendedXmlSerializer.ContentModel; +using ExtendedXmlSerializer.ContentModel.Content; +using ExtendedXmlSerializer.ContentModel.Format; +using ExtendedXmlSerializer.Core.Specifications; +using ExtendedXmlSerializer.ExtensionModel; +using ExtendedXmlSerializer.ExtensionModel.Instances; using IX.Observable; using IX.Undoable; using Xunit; @@ -14,24 +23,62 @@ namespace Diz.Test { public class SerializerTest { - internal class Root + public class Root { - private ODWrapper wrap { get; set; } = new ODWrapper + // public ODWrapper wrap { get; set; } = new ODWrapper + public ODWrapper ODW { get; set; } = new ODWrapper() { - OD = { - [3] = "Test3", - [4] = "Test4" + ObservableDict = + { + {1, "test1"}, + {2, "test3"}, } }; -} - internal class ODWrapper : ICollection> + } + + public class ODWrapper// : ICollection> { + private ObservableDictionary dict = new ObservableDictionary(); + + + public ObservableDictionary ObservableDict + { + get => dict; + set => dict = value; + } + + public Dictionary DictToSave + { + /*get + { + return dict; + } + set + { + dict = value; + }*/ + get => new Dictionary(dict); + set + { + dict.Clear(); + foreach (var item in value) + { + dict.Add(item); + } + } + } + + public ODWrapper() + { + + } + //public ObservableDictionaryAdaptor dict { get; set; } // = new ObservableDictionaryAdaptor(); - public ObservableDictionary OD { get; set; } = new ObservableDictionary(); + // public ObservableDictionary OD { get; set; } = new ObservableDictionary(); - public Dictionary Dict + /*public Dictionary Dict { get => new Dictionary(OD); set @@ -80,21 +127,57 @@ public bool Remove(KeyValuePair item) } public int Count => OD.Count; - public bool IsReadOnly => OD.IsReadOnly; + public bool IsReadOnly => OD.IsReadOnly;*/ } private static IExtendedXmlSerializer GetSerializer() { + // THIS WORKS. makes a copy but it works. + //var od = new ObservableDictionary() {{1,"Asdf"}}; + //var dd = new Dictionary(od); + //var id = (IDictionary) dd; + return new ConfigurationContainer() - // .UseAutoFormatting() - .EnableImplicitTyping(typeof(Root)) - .EnableImplicitTyping(typeof(ODWrapper)) + .EnableImplicitlyDefinedDefaultValues() + .EnableMemberExceptionHandling() // debug only .Type>() - .Member(x=>x.OD).Ignore() + .Member(x=>x.ObservableDict) + .Ignore() + /* // .UseAutoFormatting() + + + .EnableImplicitTyping(typeof(ObservableDictionary)) + // .EnableImplicitTyping(typeof(ODWrapper)) + //.Type>() + .Member(x=>x.OD).CustomSerializer(ser, deser) + .Type>() + .WithInterceptor(new Interc()) + .Type() + .WithInterceptor(new Interc()) + .Type>() + .WithInterceptor(new Interc()) + .Type>() + .WithInterceptor(new Interc2()) + .Extend(new ObservableDictionaryExtension()) + // .Type>().Register().Serializer().Using(new ObsSerializer()) + // .Type().WithInterceptor(new Interc()) + // .Type>().CustomSerializer(ser, deser) // WORKS + */ .UseOptimizedNamespaces() .Create(); } + private static ODWrapper deser(XElement arg) + { + throw new NotImplementedException(); + } + + private static void ser(XmlWriter arg1, ODWrapper arg2) + { + + // throw new NotImplementedException(); + } + [Fact] private void Serializer() { @@ -111,4 +194,63 @@ private void Serializer() Assert.Equal("asdf", xmlStr); } } + + public class Interc2 : SerializationActivator + { + public override object Activating(Type instanceType) + { + // processor should be retrieved from IoC container, but created manually for simplicity of test + //var processor = new Processor(new Service()); + //return processor; + throw new NotImplementedException(); + } + } + + internal class ObservableDictionaryExtension : ISerializerExtension + { + public IServiceRepository Get(IServiceRepository parameter) + { + // idea. return parameter.Decorate(Register).Decorate(Register).Decorate(Register); + // parameter.Decorate(ISpecification>)(Register); + // return parameter + return null; + } + + public void Execute(IServices parameter) + { + throw new NotImplementedException(); + } + } + + internal class Interc : ISerializationInterceptor + { + public object Serializing(IFormatWriter writer, object instance) + { + throw new NotImplementedException(); + } + + public object Activating(Type instanceType) + { + throw new NotImplementedException(); + } + + public object Deserialized(IFormatReader reader, object instance) + { + throw new NotImplementedException(); + } + } + + internal class ObsSerializer : ISerializer> + { + public ObservableDictionary Get(IFormatReader parameter) + { + int x = 3; + return null; + } + + public void Write(IFormatWriter writer, ObservableDictionary instance) + { + int x = 3; + } + } } \ No newline at end of file From a33f01d04100baf0f03b79c6550247d5f722dc13 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 6 Oct 2020 15:25:43 -0400 Subject: [PATCH 066/136] cleanup for a working unit test, we'll clean further from here --- Diz.Test/SerializerTest.cs | 175 ++++--------------------------------- 1 file changed, 16 insertions(+), 159 deletions(-) diff --git a/Diz.Test/SerializerTest.cs b/Diz.Test/SerializerTest.cs index 13b0bb7e..b5b87009 100644 --- a/Diz.Test/SerializerTest.cs +++ b/Diz.Test/SerializerTest.cs @@ -67,117 +67,20 @@ public Dictionary DictToSave } } } - - public ODWrapper() - { - - } - - //public ObservableDictionaryAdaptor dict { get; set; } - // = new ObservableDictionaryAdaptor(); - - // public ObservableDictionary OD { get; set; } = new ObservableDictionary(); - - /*public Dictionary Dict - { - get => new Dictionary(OD); - set - { - OD.Clear(); - foreach (var item in value) - { - OD.Add(item); - } - } - } - - public IEnumerator> GetEnumerator() - { - return OD.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public void Add(KeyValuePair item) - { - OD.Add(item.Key, item.Value); - } - - public void Clear() - { - OD.Clear(); - } - - public bool Contains(KeyValuePair item) - { - return OD.Contains(item); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - OD.CopyTo(array, arrayIndex); - } - - public bool Remove(KeyValuePair item) - { - return OD.Remove(item); - } - - public int Count => OD.Count; - public bool IsReadOnly => OD.IsReadOnly;*/ } private static IExtendedXmlSerializer GetSerializer() { - // THIS WORKS. makes a copy but it works. - //var od = new ObservableDictionary() {{1,"Asdf"}}; - //var dd = new Dictionary(od); - //var id = (IDictionary) dd; - return new ConfigurationContainer() .EnableImplicitlyDefinedDefaultValues() .EnableMemberExceptionHandling() // debug only .Type>() .Member(x=>x.ObservableDict) .Ignore() - /* // .UseAutoFormatting() - - - .EnableImplicitTyping(typeof(ObservableDictionary)) - // .EnableImplicitTyping(typeof(ODWrapper)) - //.Type>() - .Member(x=>x.OD).CustomSerializer(ser, deser) - .Type>() - .WithInterceptor(new Interc()) - .Type() - .WithInterceptor(new Interc()) - .Type>() - .WithInterceptor(new Interc()) - .Type>() - .WithInterceptor(new Interc2()) - .Extend(new ObservableDictionaryExtension()) - // .Type>().Register().Serializer().Using(new ObsSerializer()) - // .Type().WithInterceptor(new Interc()) - // .Type>().CustomSerializer(ser, deser) // WORKS - */ .UseOptimizedNamespaces() .Create(); } - private static ODWrapper deser(XElement arg) - { - throw new NotImplementedException(); - } - - private static void ser(XmlWriter arg1, ODWrapper arg2) - { - - // throw new NotImplementedException(); - } - [Fact] private void Serializer() { @@ -189,68 +92,22 @@ private void Serializer() new XmlWriterSettings {Indent = true}, rootElement); - // NOT WORKING. doesn't output the right text, skipping all elements - Console.WriteLine(xmlStr); - Assert.Equal("asdf", xmlStr); - } - } - - public class Interc2 : SerializationActivator - { - public override object Activating(Type instanceType) - { - // processor should be retrieved from IoC container, but created manually for simplicity of test - //var processor = new Processor(new Service()); - //return processor; - throw new NotImplementedException(); - } - } - - internal class ObservableDictionaryExtension : ISerializerExtension - { - public IServiceRepository Get(IServiceRepository parameter) - { - // idea. return parameter.Decorate(Register).Decorate(Register).Decorate(Register); - // parameter.Decorate(ISpecification>)(Register); - // return parameter - return null; - } - - public void Execute(IServices parameter) - { - throw new NotImplementedException(); - } - } - - internal class Interc : ISerializationInterceptor - { - public object Serializing(IFormatWriter writer, object instance) - { - throw new NotImplementedException(); - } - - public object Activating(Type instanceType) - { - throw new NotImplementedException(); - } - - public object Deserialized(IFormatReader reader, object instance) - { - throw new NotImplementedException(); - } - } - - internal class ObsSerializer : ISerializer> - { - public ObservableDictionary Get(IFormatReader parameter) - { - int x = 3; - return null; - } - - public void Write(IFormatWriter writer, ObservableDictionary instance) - { - int x = 3; + // Console.WriteLine(xmlStr); + Assert.Equal($@" + + + + + 1 + test1 + + + 2 + test3 + + + +", xmlStr); } } } \ No newline at end of file From 30c76c2650aabe33a62a44382257baa0f0e668c0 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 6 Oct 2020 15:27:30 -0400 Subject: [PATCH 067/136] further cleanup, ready for improving this more --- Diz.Test/SerializerTest.cs | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/Diz.Test/SerializerTest.cs b/Diz.Test/SerializerTest.cs index b5b87009..20c96a01 100644 --- a/Diz.Test/SerializerTest.cs +++ b/Diz.Test/SerializerTest.cs @@ -25,8 +25,7 @@ public class SerializerTest { public class Root { - // public ODWrapper wrap { get; set; } = new ODWrapper - public ODWrapper ODW { get; set; } = new ODWrapper() + public OdWrapper ODW { get; set; } = new OdWrapper() { ObservableDict = { @@ -36,34 +35,20 @@ public class Root }; } - public class ODWrapper// : ICollection> + public class OdWrapper { - private ObservableDictionary dict = new ObservableDictionary(); - - - public ObservableDictionary ObservableDict - { - get => dict; - set => dict = value; - } + public ObservableDictionary ObservableDict { get; set; } + = new ObservableDictionary(); public Dictionary DictToSave { - /*get - { - return dict; - } - set - { - dict = value; - }*/ - get => new Dictionary(dict); + get => new Dictionary(ObservableDict); set { - dict.Clear(); + ObservableDict.Clear(); foreach (var item in value) { - dict.Add(item); + ObservableDict.Add(item); } } } @@ -74,7 +59,7 @@ private static IExtendedXmlSerializer GetSerializer() return new ConfigurationContainer() .EnableImplicitlyDefinedDefaultValues() .EnableMemberExceptionHandling() // debug only - .Type>() + .Type>() .Member(x=>x.ObservableDict) .Ignore() .UseOptimizedNamespaces() From 9f4fd72113761f7bdae9bad43c881d6bfc94d3e3 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 6 Oct 2020 16:12:32 -0400 Subject: [PATCH 068/136] working IDictionary export --- Diz.Test/SerializerTest.cs | 55 ++++++++++++++------------------------ 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/Diz.Test/SerializerTest.cs b/Diz.Test/SerializerTest.cs index 20c96a01..608313fd 100644 --- a/Diz.Test/SerializerTest.cs +++ b/Diz.Test/SerializerTest.cs @@ -1,36 +1,33 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Reflection; -using System.Threading; using System.Xml; -using System.Xml.Linq; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; -using ExtendedXmlSerializer.ContentModel; -using ExtendedXmlSerializer.ContentModel.Content; -using ExtendedXmlSerializer.ContentModel.Format; -using ExtendedXmlSerializer.Core.Specifications; -using ExtendedXmlSerializer.ExtensionModel; -using ExtendedXmlSerializer.ExtensionModel.Instances; using IX.Observable; -using IX.Undoable; using Xunit; +using Xunit.Abstractions; +using Xunit.Sdk; namespace Diz.Test { public class SerializerTest { + private readonly ITestOutputHelper testOutputHelper; + + public SerializerTest(ITestOutputHelper testOutputHelper) + { + this.testOutputHelper = testOutputHelper; + } + public class Root { public OdWrapper ODW { get; set; } = new OdWrapper() { ObservableDict = { - {1, "test1"}, - {2, "test3"}, + {1, "Xtest1"}, + {2, "Xtest3"}, } }; } @@ -40,7 +37,7 @@ public class OdWrapper public ObservableDictionary ObservableDict { get; set; } = new ObservableDictionary(); - public Dictionary DictToSave + public IDictionary DictToSave { get => new Dictionary(ObservableDict); set @@ -48,7 +45,7 @@ public Dictionary DictToSave ObservableDict.Clear(); foreach (var item in value) { - ObservableDict.Add(item); + ObservableDict.Add((KeyValuePair)(item)); } } } @@ -59,8 +56,8 @@ private static IExtendedXmlSerializer GetSerializer() return new ConfigurationContainer() .EnableImplicitlyDefinedDefaultValues() .EnableMemberExceptionHandling() // debug only - .Type>() - .Member(x=>x.ObservableDict) + .Type>() + .Member(x => x.ObservableDict) .Ignore() .UseOptimizedNamespaces() .Create(); @@ -74,25 +71,13 @@ private void Serializer() var rootElement = new Root(); var xmlStr = serializer.Serialize( - new XmlWriterSettings {Indent = true}, + new XmlWriterSettings() {}, rootElement); - // Console.WriteLine(xmlStr); - Assert.Equal($@" - - - - - 1 - test1 - - - 2 - test3 - - - -", xmlStr); + testOutputHelper.WriteLine(xmlStr); + const string expected = @"1Xtest12Xtest3"; + + Assert.Equal(expected, xmlStr); } } } \ No newline at end of file From cf5e40ce0b10dfb1424348f6bc79c92258ce1e93 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 6 Oct 2020 16:25:24 -0400 Subject: [PATCH 069/136] working serialize/deserialize complete test - ready to iterate --- Diz.Test/SerializerTest.cs | 70 ++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 7 deletions(-) diff --git a/Diz.Test/SerializerTest.cs b/Diz.Test/SerializerTest.cs index 608313fd..05f4be56 100644 --- a/Diz.Test/SerializerTest.cs +++ b/Diz.Test/SerializerTest.cs @@ -1,7 +1,9 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; using System.Xml; +using DiztinGUIsh.loadsave.xml_serializer; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; using IX.Observable; @@ -30,6 +32,29 @@ public class Root {2, "Xtest3"}, } }; + + #region Equality + + protected bool Equals(Root other) + { + return Equals(ODW, other.ODW); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((Root) obj); + } + + public override int GetHashCode() + { + return (ODW != null ? ODW.GetHashCode() : 0); + } + + #endregion + } public class OdWrapper @@ -43,12 +68,34 @@ public IDictionary DictToSave set { ObservableDict.Clear(); - foreach (var item in value) + foreach (DictionaryEntry item in value) { - ObservableDict.Add((KeyValuePair)(item)); + ObservableDict.Add((TKey)item.Key, (TValue)item.Value); } } } + + #region Equality + + protected bool Equals(OdWrapper other) + { + return ObservableDict.SequenceEqual(other.ObservableDict); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((OdWrapper) obj); + } + + public override int GetHashCode() + { + return (ObservableDict != null ? ObservableDict.GetHashCode() : 0); + } + + #endregion } private static IExtendedXmlSerializer GetSerializer() @@ -68,16 +115,25 @@ private void Serializer() { var serializer = GetSerializer(); - var rootElement = new Root(); - var xmlStr = serializer.Serialize( new XmlWriterSettings() {}, - rootElement); + rootElementGood); testOutputHelper.WriteLine(xmlStr); - const string expected = @"1Xtest12Xtest3"; - Assert.Equal(expected, xmlStr); + Assert.Equal(xmlShouldBe, xmlStr); } + + [Fact] + private void DeSerialize() + { + var serializer = GetSerializer(); + var restoredRoot = serializer.Deserialize(xmlShouldBe); + + Assert.Equal(rootElementGood, restoredRoot); + } + + readonly Root rootElementGood = new Root(); + const string xmlShouldBe = @"1Xtest12Xtest3"; } } \ No newline at end of file From 980120515832e6b24dec4b9767d5a76242c45a9d Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 6 Oct 2020 17:30:35 -0400 Subject: [PATCH 070/136] rework and fix test again --- Diz.Core/core/Data.cs | 4 +- Diz.Core/core/LogCreator.cs | 2 +- Diz.Core/core/import/SampleRomData.cs | 4 +- .../core/util/ObservableDictionaryAdaptor.cs | 140 +++++++++++++++++- Diz.Test/SerializerTest.cs | 58 +------- DiztinGUIsh/window/AliasList.cs | 4 +- 6 files changed, 144 insertions(+), 68 deletions(-) diff --git a/Diz.Core/core/Data.cs b/Diz.Core/core/Data.cs index 0cd99900..26a06afb 100644 --- a/Diz.Core/core/Data.cs +++ b/Diz.Core/core/Data.cs @@ -89,8 +89,8 @@ public const int public ROMMapMode RomMapMode { get; set; } public ROMSpeed RomSpeed { get; set; } - public ObservableDictionaryAdaptor Comments { get; set; } = new ObservableDictionaryAdaptor(); - public ObservableDictionaryAdaptor Labels { get; set; } = new ObservableDictionaryAdaptor(); + public ObservableDictionary Comments { get; set; } = new ObservableDictionary(); + public ObservableDictionary Labels { get; set; } = new ObservableDictionary(); public RomBytes RomBytes { get; set; } = new RomBytes(); private CPU65C816 CPU65C816 { get; set; } diff --git a/Diz.Core/core/LogCreator.cs b/Diz.Core/core/LogCreator.cs index 948b007c..6a07a342 100644 --- a/Diz.Core/core/LogCreator.cs +++ b/Diz.Core/core/LogCreator.cs @@ -166,7 +166,7 @@ public OutputResult CreateLog() // ehhhh... is that a little weird... maybe. // // maybe just clone the list and use the local list instead, remove subscribes from just that. - AddLabelSource(Data.Labels.Dict); + AddLabelSource(Data.Labels); AddLabelSource(ExtraLabels); AddTemporaryLabels(); diff --git a/Diz.Core/core/import/SampleRomData.cs b/Diz.Core/core/import/SampleRomData.cs index 3ae3eae2..501c72cc 100644 --- a/Diz.Core/core/import/SampleRomData.cs +++ b/Diz.Core/core/import/SampleRomData.cs @@ -156,14 +156,14 @@ public static SampleRomData SampleData new ROMByte {Rom = 0x34, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, new ROMByte {Rom = 0x6D, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, }, - Comments = new ObservableDictionaryAdaptor() + Comments = new ObservableDictionary() { {0x03, "this sets FastROM"}, {0x0F, "direct page = $2100"}, {0x21, "clear APU regs"}, {0x44, "this routine copies Test_Data to $7E0100"} }, - Labels = new ObservableDictionaryAdaptor() + Labels = new ObservableDictionary() { {0x00, new Label {name = "Emulation_RESET", comment = "Sample emulation reset location"}}, {0x0A, new Label {name = "FastRESET", comment = "Sample label"}}, diff --git a/Diz.Core/core/util/ObservableDictionaryAdaptor.cs b/Diz.Core/core/util/ObservableDictionaryAdaptor.cs index f2867464..a20327db 100644 --- a/Diz.Core/core/util/ObservableDictionaryAdaptor.cs +++ b/Diz.Core/core/util/ObservableDictionaryAdaptor.cs @@ -1,6 +1,9 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; +using ExtendedXmlSerializer; +using ExtendedXmlSerializer.Configuration; using IX.Observable; namespace DiztinGUIsh.core.util @@ -8,9 +11,70 @@ namespace DiztinGUIsh.core.util // wrap an ObservableDictionary so we can implement non-generic IDictionary // this basically exists to work around ExtendedXmlSerializer trying to cast us to IDictionary and failing. // there's probably settings we can tweak in ExtendedXmlSerializer (particularly, Interceptor), and then - // we can remove the need for this adaptor. + // we can remove the need for this wrapper. + public class OdWrapper + { + public ObservableDictionary ObservableDict { get; set; } + = new ObservableDictionary(); + + public IDictionary DictToSave + { + get => new Dictionary(ObservableDict); + set + { + ObservableDict.Clear(); + foreach (DictionaryEntry item in value) + { + ObservableDict.Add((TKey)item.Key, (TValue)item.Value); + } + } + } + + #region Equality + + protected bool Equals(OdWrapper other) + { + return ObservableDict.SequenceEqual(other.ObservableDict); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((OdWrapper)obj); + } + + public override int GetHashCode() + { + return (ObservableDict != null ? ObservableDict.GetHashCode() : 0); + } + + #endregion + } + + // this is pretty hacky. + // anytime you use OdWrapper, you need to use this to tell the xml serialize to ignore the ObservableDict property + // on OdWrapper. + // + // This really needs to go away and be solved more elegantly with some better use of ExtendedXmlSerializer. + // + // or... just move away from dictionaries for data storage. which would be a shame but probably easier + public static class ObservedDictionaryHelper { + public static IConfigurationContainer AppendDisablingType(this IConfigurationContainer @this) + => @this.EnableImplicitTyping(typeof(OdWrapper)) + .Type>() + .Member(x => x.ObservableDict) + .Ignore(); + } + - public class ObservableDictionaryAdaptor : IDictionary, IEnumerable> + + + + // older junkier attempts below. leaving for now, I'm still messing with this -Dom + + /*public class ObservableDictionaryAdaptor : IDictionary, IEnumerable> { private readonly ObservableDictionary dict = new ObservableDictionary(); public bool Contains(object key) @@ -65,8 +129,10 @@ public void CopyTo(Array array, int index) public int Count => dict.Count; +#pragma warning disable CS0618 public object SyncRoot => dict.SyncRoot; +#pragma warning disable CS0618 public bool IsSynchronized => dict.IsSynchronized; public ObservableDictionary Dict => dict; @@ -76,17 +142,75 @@ public bool ContainsKey(TKey key) { return dict.ContainsKey(key); } + }*/ + + /* + public class OdWrapper : IDictionary + { + public ObservableDictionary ObservableDict { get; set; } + = new ObservableDictionary(); + + public IDictionary DictToSave + { + get => new Dictionary(ObservableDict); + set + { + ObservableDict.Clear(); + foreach (DictionaryEntry item in value) + { + ObservableDict.Add((TKey)item.Key, (TValue)item.Value); + } + } + } + + #region Equality + + protected bool Equals(OdWrapper other) + { + return ObservableDict.SequenceEqual(other.ObservableDict); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((OdWrapper)obj); + } + + public override int GetHashCode() + { + return (ObservableDict != null ? ObservableDict.GetHashCode() : 0); + } + + #endregion } - class ODEnumerator : IDictionaryEnumerator, IDisposable + + /* + public class ODEnumerator_Full_But_Not_Working : IDictionaryEnumerator, IDisposable { private readonly IEnumerator> impl; - public void Dispose() { impl.Dispose(); } + + public void Dispose() + { + impl.Dispose(); + } + public ODEnumerator(IDictionary value) { impl = value.GetEnumerator(); } - public void Reset() { impl.Reset(); } - public bool MoveNext() { return impl.MoveNext(); } + + public void Reset() + { + impl.Reset(); + } + + public bool MoveNext() + { + return impl.MoveNext(); + } + public DictionaryEntry Entry { get @@ -95,8 +219,10 @@ public DictionaryEntry Entry return new DictionaryEntry(pair.Key, pair.Value); } } + public object Key => impl.Current.Key; public object Value => impl.Current.Value; public object Current => Entry; } -} + */ +} \ No newline at end of file diff --git a/Diz.Test/SerializerTest.cs b/Diz.Test/SerializerTest.cs index 05f4be56..9fdd9db3 100644 --- a/Diz.Test/SerializerTest.cs +++ b/Diz.Test/SerializerTest.cs @@ -1,15 +1,9 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Xml; -using DiztinGUIsh.loadsave.xml_serializer; +using System.Xml; +using DiztinGUIsh.core.util; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; -using IX.Observable; using Xunit; using Xunit.Abstractions; -using Xunit.Sdk; namespace Diz.Test { @@ -53,48 +47,6 @@ public override int GetHashCode() return (ODW != null ? ODW.GetHashCode() : 0); } - #endregion - - } - - public class OdWrapper - { - public ObservableDictionary ObservableDict { get; set; } - = new ObservableDictionary(); - - public IDictionary DictToSave - { - get => new Dictionary(ObservableDict); - set - { - ObservableDict.Clear(); - foreach (DictionaryEntry item in value) - { - ObservableDict.Add((TKey)item.Key, (TValue)item.Value); - } - } - } - - #region Equality - - protected bool Equals(OdWrapper other) - { - return ObservableDict.SequenceEqual(other.ObservableDict); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((OdWrapper) obj); - } - - public override int GetHashCode() - { - return (ObservableDict != null ? ObservableDict.GetHashCode() : 0); - } - #endregion } @@ -103,9 +55,7 @@ private static IExtendedXmlSerializer GetSerializer() return new ConfigurationContainer() .EnableImplicitlyDefinedDefaultValues() .EnableMemberExceptionHandling() // debug only - .Type>() - .Member(x => x.ObservableDict) - .Ignore() + .AppendDisablingType() .UseOptimizedNamespaces() .Create(); } @@ -134,6 +84,6 @@ private void DeSerialize() } readonly Root rootElementGood = new Root(); - const string xmlShouldBe = @"1Xtest12Xtest3"; + private const string xmlShouldBe = "1Xtest12Xtest3"; } } \ No newline at end of file diff --git a/DiztinGUIsh/window/AliasList.cs b/DiztinGUIsh/window/AliasList.cs index 206d5bcf..bc4edb91 100644 --- a/DiztinGUIsh/window/AliasList.cs +++ b/DiztinGUIsh/window/AliasList.cs @@ -285,8 +285,8 @@ public void RebindProject() // todo: eventually use databinding/datasource, probably. // Todo: modify observabledictionary wrapper to avoid having to do the .Dict call here. - Data.Labels.Dict.PropertyChanged += Labels_PropertyChanged; - Data.Labels.Dict.CollectionChanged += Labels_CollectionChanged; + Data.Labels.PropertyChanged += Labels_PropertyChanged; + Data.Labels.CollectionChanged += Labels_CollectionChanged; } private void RepopulateFromData() From 3912c0888f66a54ac17547ecd838cd02927b43d1 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 6 Oct 2020 19:22:30 -0400 Subject: [PATCH 071/136] working XML serializer for dictionary class! woo --- Diz.Core/core/Data.cs | 33 ++++---- Diz.Core/core/LogCreator.cs | 8 +- Diz.Core/core/import/SampleRomData.cs | 31 +++---- .../core/util/ObservableDictionaryAdaptor.cs | 80 +++++++++++++++---- .../binary_serializer_old/BinarySerializer.cs | 8 +- Diz.Test/SerializerTest.cs | 37 ++++++++- DiztinGUIsh/window/AliasList.cs | 10 +-- 7 files changed, 145 insertions(+), 62 deletions(-) diff --git a/Diz.Core/core/Data.cs b/Diz.Core/core/Data.cs index 26a06afb..f604a5f0 100644 --- a/Diz.Core/core/Data.cs +++ b/Diz.Core/core/Data.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Text; using Diz.Core.core; +using Diz.Core.core.util; using DiztinGUIsh.core.util; using IX.Observable; @@ -89,8 +90,8 @@ public const int public ROMMapMode RomMapMode { get; set; } public ROMSpeed RomSpeed { get; set; } - public ObservableDictionary Comments { get; set; } = new ObservableDictionary(); - public ObservableDictionary Labels { get; set; } = new ObservableDictionary(); + public OdWrapper Comments { get; set; } = new OdWrapper(); + public OdWrapper Labels { get; set; } = new OdWrapper(); public RomBytes RomBytes { get; set; } = new RomBytes(); private CPU65C816 CPU65C816 { get; set; } @@ -172,14 +173,14 @@ public void SetMXFlags(int i, int mx) } public string GetLabelName(int i) { - if (Labels.TryGetValue(i, out var val)) + if (Labels.Dict.TryGetValue(i, out var val)) return val?.name ?? ""; return ""; } public string GetLabelComment(int i) { - if (Labels.TryGetValue(i, out var val)) + if (Labels.Dict.TryGetValue(i, out var val)) return val?.comment ?? ""; return ""; @@ -187,7 +188,7 @@ public string GetLabelComment(int i) public void DeleteAllLabels() { - Labels.Clear(); + Labels.Dict.Clear(); } public void AddLabel(int offset, Label label, bool overwrite) @@ -195,35 +196,35 @@ public void AddLabel(int offset, Label label, bool overwrite) // adding null label removes it if (label == null) { - if (Labels.ContainsKey(offset)) - Labels.Remove(offset); + if (Labels.Dict.ContainsKey(offset)) + Labels.Dict.Remove(offset); return; } if (overwrite) { - if (Labels.ContainsKey(offset)) - Labels.Remove(offset); + if (Labels.Dict.ContainsKey(offset)) + Labels.Dict.Remove(offset); } - if (!Labels.ContainsKey(offset)) + if (!Labels.Dict.ContainsKey(offset)) { label.CleanUp(); - Labels.Add(offset, label); + Labels.Dict.Add(offset, label); } } - public string GetComment(int i) => Comments.TryGetValue(i, out var val) ? val : ""; + public string GetComment(int i) => Comments.Dict.TryGetValue(i, out var val) ? val : ""; public void AddComment(int i, string v, bool overwrite) { if (v == null) { - if (Comments.ContainsKey(i)) Comments.Remove(i); + if (Comments.Dict.ContainsKey(i)) Comments.Dict.Remove(i); } else { - if (Comments.ContainsKey(i) && overwrite) Comments.Remove(i); - if (!Comments.ContainsKey(i)) Comments.Add(i, v); + if (Comments.Dict.ContainsKey(i) && overwrite) Comments.Dict.Remove(i); + if (!Comments.Dict.ContainsKey(i)) Comments.Dict.Add(i, v); } } @@ -627,7 +628,7 @@ public string GetInstruction(int offset) #region Equality protected bool Equals(Data other) { - return Labels.SequenceEqual(other.Labels) && RomMapMode == other.RomMapMode && RomSpeed == other.RomSpeed && Comments.SequenceEqual(other.Comments) && RomBytes.Equals(other.RomBytes); + return Labels.Dict.SequenceEqual(other.Labels.Dict) && RomMapMode == other.RomMapMode && RomSpeed == other.RomSpeed && Comments.Dict.SequenceEqual(other.Comments.Dict) && RomBytes.Equals(other.RomBytes); } public override bool Equals(object obj) diff --git a/Diz.Core/core/LogCreator.cs b/Diz.Core/core/LogCreator.cs index 6a07a342..faf9418a 100644 --- a/Diz.Core/core/LogCreator.cs +++ b/Diz.Core/core/LogCreator.cs @@ -166,7 +166,7 @@ public OutputResult CreateLog() // ehhhh... is that a little weird... maybe. // // maybe just clone the list and use the local list instead, remove subscribes from just that. - AddLabelSource(Data.Labels); + AddLabelSource(Data.Labels.Dict); AddLabelSource(ExtraLabels); AddTemporaryLabels(); @@ -405,7 +405,7 @@ private void WriteAddress(ref int pointer, ref int bank) } var c1 = (Data.GetInOutPoint(pointer) & (Data.InOutPoint.ReadPoint)) != 0; - var c2 = (Data.Labels.TryGetValue(pointer, out var label) && label.name.Length > 0); + var c2 = (Data.Labels.Dict.TryGetValue(pointer, out var label) && label.name.Length > 0); if (c1 || c2) StreamOutput.WriteLine(GetLine(pointer, "empty")); @@ -421,7 +421,7 @@ private void WriteLabels(int pointer) var listToPrint = new Dictionary(); // part 1: important: include all labels we aren't defining somewhere else. needed for disassembly - foreach (KeyValuePair pair in Data.Labels) + foreach (KeyValuePair pair in Data.Labels.Dict) { if (usedLabels.Contains(pair.Key)) continue; @@ -441,7 +441,7 @@ private void WriteLabels(int pointer) if (Settings.includeUnusedLabels) { SwitchOutputFile(pointer, $"{folder}/all-labels.txt"); - foreach (KeyValuePair pair in Data.Labels) + foreach (KeyValuePair pair in Data.Labels.Dict) { // not the best place to add formatting, TODO: cleanup var category = listToPrint.ContainsKey(pair.Key) ? "INLINE" : "EXTRA "; diff --git a/Diz.Core/core/import/SampleRomData.cs b/Diz.Core/core/import/SampleRomData.cs index 501c72cc..501fa3ed 100644 --- a/Diz.Core/core/import/SampleRomData.cs +++ b/Diz.Core/core/import/SampleRomData.cs @@ -1,7 +1,6 @@ using Diz.Core.core; +using Diz.Core.core.util; using DiztinGUIsh.core; -using DiztinGUIsh.core.util; -using IX.Observable; namespace DiztinGUIsh { @@ -156,21 +155,25 @@ public static SampleRomData SampleData new ROMByte {Rom = 0x34, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, new ROMByte {Rom = 0x6D, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, }, - Comments = new ObservableDictionary() + Comments = new OdWrapper() { - {0x03, "this sets FastROM"}, - {0x0F, "direct page = $2100"}, - {0x21, "clear APU regs"}, - {0x44, "this routine copies Test_Data to $7E0100"} + Dict = { + {0x03, "this sets FastROM"}, + {0x0F, "direct page = $2100"}, + {0x21, "clear APU regs"}, + {0x44, "this routine copies Test_Data to $7E0100"} + } }, - Labels = new ObservableDictionary() + Labels = new OdWrapper() { - {0x00, new Label {name = "Emulation_RESET", comment = "Sample emulation reset location"}}, - {0x0A, new Label {name = "FastRESET", comment = "Sample label"}}, - {0x32, new Label {name = "Test_Indices"}}, - {0x3A, new Label {name = "Pointer_Table"}}, - {0x44, new Label {name = "First_Routine"}}, - {0x5B, new Label {name = "Test_Data", comment = "Pretty cool huh?"}} + Dict = { + {0x00, new Label {name = "Emulation_RESET", comment = "Sample emulation reset location"}}, + {0x0A, new Label {name = "FastRESET", comment = "Sample label"}}, + {0x32, new Label {name = "Test_Indices"}}, + {0x3A, new Label {name = "Pointer_Table"}}, + {0x44, new Label {name = "First_Routine"}}, + {0x5B, new Label {name = "Test_Data", comment = "Pretty cool huh?"}} + } }, RomMapMode = ROMMapMode.LoROM, RomSpeed = ROMSpeed.FastROM, diff --git a/Diz.Core/core/util/ObservableDictionaryAdaptor.cs b/Diz.Core/core/util/ObservableDictionaryAdaptor.cs index a20327db..5df7dfbe 100644 --- a/Diz.Core/core/util/ObservableDictionaryAdaptor.cs +++ b/Diz.Core/core/util/ObservableDictionaryAdaptor.cs @@ -1,31 +1,87 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; +using System.Linq.Expressions; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; using IX.Observable; -namespace DiztinGUIsh.core.util +namespace Diz.Core.core.util { + public static class OdWrapperRegistration + { + // we're going to register and then call a bunch of these with different types + public static IConfigurationContainer AppendDisablingType(this IConfigurationContainer @this) + => @this + .EnableImplicitTyping(typeof(OdWrapper)) + .Type>() + // .Member(x => MatchesType(x)) + .Member(x => x.Dict) + .Ignore(); + + private static bool MatchesType(OdWrapper x) + { + return x.GetType().ToString().Contains("ObservableDictionary"); + } + + private static readonly List> operationFNs = new List>(); + + public static void Register(OdWrapper wrapper) + { + Debug.Assert(wrapper != null); + Func fn = delegate(IConfigurationContainer container) + { + return container.AppendDisablingType(); + }; + + operationFNs.Add(fn); + Debug.Assert(operationFNs.Count != 0); + } + + public static IConfigurationContainer ApplyAllOdWrapperConfigurations(this IConfigurationContainer @this) + { + var target = @this; + foreach (var fn in operationFNs) + { + target = fn(target); + } + + return target; + } + /*operationFNs.Aggregate( + @this, + (current, fn) => fn(current));*/ + } + // wrap an ObservableDictionary so we can implement non-generic IDictionary // this basically exists to work around ExtendedXmlSerializer trying to cast us to IDictionary and failing. // there's probably settings we can tweak in ExtendedXmlSerializer (particularly, Interceptor), and then // we can remove the need for this wrapper. + // + // this entire mess is because no matter what I do I can't do (IDictionary)ObservableDictionary + // which is what ExtendedXmlSerializer needs public class OdWrapper { - public ObservableDictionary ObservableDict { get; set; } - = new ObservableDictionary(); + // dictionary data we will wrap + public ObservableDictionary Dict { get; set; } = new ObservableDictionary(); + + public OdWrapper() + { + OdWrapperRegistration.Register(this); + } + // expose it as IDictionary for extendedxmlserializer to load/save from public IDictionary DictToSave { - get => new Dictionary(ObservableDict); + get => new Dictionary(Dict); set { - ObservableDict.Clear(); + Dict.Clear(); foreach (DictionaryEntry item in value) { - ObservableDict.Add((TKey)item.Key, (TValue)item.Value); + Dict.Add((TKey)item.Key, (TValue)item.Value); } } } @@ -34,7 +90,7 @@ public IDictionary DictToSave protected bool Equals(OdWrapper other) { - return ObservableDict.SequenceEqual(other.ObservableDict); + return Dict.SequenceEqual(other.Dict); } public override bool Equals(object obj) @@ -47,7 +103,7 @@ public override bool Equals(object obj) public override int GetHashCode() { - return (ObservableDict != null ? ObservableDict.GetHashCode() : 0); + return Dict.GetHashCode(); } #endregion @@ -60,13 +116,7 @@ public override int GetHashCode() // This really needs to go away and be solved more elegantly with some better use of ExtendedXmlSerializer. // // or... just move away from dictionaries for data storage. which would be a shame but probably easier - public static class ObservedDictionaryHelper { - public static IConfigurationContainer AppendDisablingType(this IConfigurationContainer @this) - => @this.EnableImplicitTyping(typeof(OdWrapper)) - .Type>() - .Member(x => x.ObservableDict) - .Ignore(); - } + diff --git a/Diz.Core/loadsave/binary_serializer_old/BinarySerializer.cs b/Diz.Core/loadsave/binary_serializer_old/BinarySerializer.cs index 31eae88f..6a073432 100644 --- a/Diz.Core/loadsave/binary_serializer_old/BinarySerializer.cs +++ b/Diz.Core/loadsave/binary_serializer_old/BinarySerializer.cs @@ -129,8 +129,8 @@ private byte[] SaveVersion(Project project, int version) var all_labels = project.Data.Labels; var all_comments = project.Data.Comments; - ByteUtil.IntegerIntoByteList(all_labels.Count, label); - foreach (KeyValuePair pair in all_labels) + ByteUtil.IntegerIntoByteList(all_labels.Dict.Count, label); + foreach (KeyValuePair pair in all_labels.Dict) { ByteUtil.IntegerIntoByteList(pair.Key, label); @@ -141,8 +141,8 @@ private byte[] SaveVersion(Project project, int version) } } - ByteUtil.IntegerIntoByteList(all_comments.Count, comment); - foreach (KeyValuePair pair in all_comments) + ByteUtil.IntegerIntoByteList(all_comments.Dict.Count, comment); + foreach (KeyValuePair pair in all_comments.Dict) { ByteUtil.IntegerIntoByteList(pair.Key, comment); SaveStringToBytes(pair.Value, comment); diff --git a/Diz.Test/SerializerTest.cs b/Diz.Test/SerializerTest.cs index 9fdd9db3..dde3defd 100644 --- a/Diz.Test/SerializerTest.cs +++ b/Diz.Test/SerializerTest.cs @@ -1,4 +1,5 @@ using System.Xml; +using Diz.Core.core.util; using DiztinGUIsh.core.util; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; @@ -20,8 +21,7 @@ public class Root { public OdWrapper ODW { get; set; } = new OdWrapper() { - ObservableDict = - { + Dict = { {1, "Xtest1"}, {2, "Xtest3"}, } @@ -55,7 +55,11 @@ private static IExtendedXmlSerializer GetSerializer() return new ConfigurationContainer() .EnableImplicitlyDefinedDefaultValues() .EnableMemberExceptionHandling() // debug only - .AppendDisablingType() + + // .ApplyAllOdWrapperConfigurations() // the important one for ODWrapper + + .AppendDisablingType() + .UseOptimizedNamespaces() .Create(); } @@ -84,6 +88,31 @@ private void DeSerialize() } readonly Root rootElementGood = new Root(); - private const string xmlShouldBe = "1Xtest12Xtest3"; + string xmlShouldBe = "<" + + "ODW>1" + + "Xtest1<" + + "/Value>2" + + "Xtest3"; } } \ No newline at end of file diff --git a/DiztinGUIsh/window/AliasList.cs b/DiztinGUIsh/window/AliasList.cs index bc4edb91..c8412762 100644 --- a/DiztinGUIsh/window/AliasList.cs +++ b/DiztinGUIsh/window/AliasList.cs @@ -127,7 +127,7 @@ private void export_Click(object sender, EventArgs e) try { using var sw = new StreamWriter(saveFileDialog1.FileName); - foreach (KeyValuePair pair in Data.Labels) + foreach (KeyValuePair pair in Data.Labels.Dict) { sw.WriteLine( $"{Util.NumberToBaseString(pair.Key, Util.NumberBase.Hexadecimal, 6)},{pair.Value.name},{pair.Value.comment}"); @@ -181,7 +181,7 @@ private void dataGridView1_CellValidating(object sender, DataGridViewCellValidat { e.Cancel = true; toolStripStatusLabel1.Text = "Must enter a valid hex address."; - } else if (oldAddress == -1 && Data.Labels.ContainsKey(val)) + } else if (oldAddress == -1 && Data.Labels.Dict.ContainsKey(val)) { e.Cancel = true; toolStripStatusLabel1.Text = "This address already has a label."; @@ -285,8 +285,8 @@ public void RebindProject() // todo: eventually use databinding/datasource, probably. // Todo: modify observabledictionary wrapper to avoid having to do the .Dict call here. - Data.Labels.PropertyChanged += Labels_PropertyChanged; - Data.Labels.CollectionChanged += Labels_CollectionChanged; + Data.Labels.Dict.PropertyChanged += Labels_PropertyChanged; + Data.Labels.Dict.CollectionChanged += Labels_CollectionChanged; } private void RepopulateFromData() @@ -297,7 +297,7 @@ private void RepopulateFromData() return; // TODO: replace with winforms databinding eventually - foreach (KeyValuePair item in Data.Labels) + foreach (KeyValuePair item in Data.Labels.Dict) { RawAdd(item.Key, item.Value); } From 16798bfec24d6c74980e53ec969b8e4eced37f4a Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 6 Oct 2020 20:16:31 -0400 Subject: [PATCH 072/136] cleanup and add check for multiple odwrapper --- Diz.Core/core/import/SampleRomData.cs | 2 +- Diz.Core/core/util/ByteUtil.cs | 8 +- .../core/util/ObservableDictionaryAdaptor.cs | 237 +++--------------- .../xml_serializer/ProjectXMLSerializer.cs | 2 + .../xml_serializer/XMLSerializerSupport.cs | 35 +-- Diz.Test/SerializerTest.cs | 54 ++-- 6 files changed, 64 insertions(+), 274 deletions(-) diff --git a/Diz.Core/core/import/SampleRomData.cs b/Diz.Core/core/import/SampleRomData.cs index 501fa3ed..c3cd10cd 100644 --- a/Diz.Core/core/import/SampleRomData.cs +++ b/Diz.Core/core/import/SampleRomData.cs @@ -10,7 +10,7 @@ public static SampleRomData SampleData { get { - // take our sample data from below and construct some extra stuff into it. + // one-time: take our sample data from below and bolt some extra stuff on top of it. // then, cache all this in a static read-only property if (finalSampleData != null) diff --git a/Diz.Core/core/util/ByteUtil.cs b/Diz.Core/core/util/ByteUtil.cs index 49eb00bb..2083929b 100644 --- a/Diz.Core/core/util/ByteUtil.cs +++ b/Diz.Core/core/util/ByteUtil.cs @@ -9,9 +9,8 @@ namespace DiztinGUIsh.core.util { public static class ByteUtil { - // take input addresses that look like this, and convert to an int. - // useful if pasting addresses from other editors/tools/asm/etc and - // generating a clean address. + // take input addresses that be in any formats that look like this, and convert to an int. + // This is useful if pasting addresses from other editors/tools/asm/etc trying to get a clean address. // C0FFFF // $C0FFFF // C7/AAAA @@ -91,7 +90,8 @@ public static void IntegerIntoByteArray(int a, byte[] data, int offset) public static void IntegerIntoByteList(int a, List list) { byte[] arr = IntegerToByteArray(a); - for (int i = 0; i < arr.Length; i++) list.Add(arr[i]); + foreach (var t in arr) + list.Add(t); } public static int ByteArrayToInteger(byte[] data, int offset = 0) diff --git a/Diz.Core/core/util/ObservableDictionaryAdaptor.cs b/Diz.Core/core/util/ObservableDictionaryAdaptor.cs index 5df7dfbe..4902eec3 100644 --- a/Diz.Core/core/util/ObservableDictionaryAdaptor.cs +++ b/Diz.Core/core/util/ObservableDictionaryAdaptor.cs @@ -3,221 +3,86 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Linq.Expressions; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; using IX.Observable; namespace Diz.Core.core.util { + // OdwWrapper is wrapping an issue we are having where ExtendedXmlSerializer is having issues + // serializing ObservableDictionary<> correctly. It's failing to cast to IDictionary, which is either + // a problem with ObservableDictionary, or, a misconfiguration in the default config of ExtendedXmlSerializer + // + // Either way, the code in this file works around it (in kind of a clumsy way). We should rip it out + // as soon as we can. public static class OdWrapperRegistration { - // we're going to register and then call a bunch of these with different types + // tell ExtendedXmlSerializer NOT to serialize .Dict on OdWrapper public static IConfigurationContainer AppendDisablingType(this IConfigurationContainer @this) => @this .EnableImplicitTyping(typeof(OdWrapper)) .Type>() - // .Member(x => MatchesType(x)) - .Member(x => x.Dict) - .Ignore(); - - private static bool MatchesType(OdWrapper x) - { - return x.GetType().ToString().Contains("ObservableDictionary"); - } + .Member(x => x.Dict).Ignore(); // the important bit private static readonly List> operationFNs = new List>(); - public static void Register(OdWrapper wrapper) + // allow multiple OdWrapper type combos to be excluded. + public static void Register() { - Debug.Assert(wrapper != null); - Func fn = delegate(IConfigurationContainer container) - { - return container.AppendDisablingType(); - }; + Func fn = container => + container.AppendDisablingType(); operationFNs.Add(fn); Debug.Assert(operationFNs.Count != 0); } - public static IConfigurationContainer ApplyAllOdWrapperConfigurations(this IConfigurationContainer @this) - { - var target = @this; - foreach (var fn in operationFNs) - { - target = fn(target); - } - - return target; - } - /*operationFNs.Aggregate( - @this, - (current, fn) => fn(current));*/ + public static IConfigurationContainer ApplyAllOdWrapperConfigurations(this IConfigurationContainer @this) => + operationFNs.Aggregate(@this, (current, fn) => fn(current)); } - // wrap an ObservableDictionary so we can implement non-generic IDictionary + // wrapper around an ObservableDictionary so we can implement non-generic IDictionary // this basically exists to work around ExtendedXmlSerializer trying to cast us to IDictionary and failing. // there's probably settings we can tweak in ExtendedXmlSerializer (particularly, Interceptor), and then // we can remove the need for this wrapper. // // this entire mess is because no matter what I do I can't do (IDictionary)ObservableDictionary - // which is what ExtendedXmlSerializer needs + // which is what ExtendedXmlSerializer needs. this code all needs to GO public class OdWrapper { - // dictionary data we will wrap + // Real data we care about will live here in Dict. + // The XML serializer will ignore Dict when saving/loading + // The app code should use this directly. public ObservableDictionary Dict { get; set; } = new ObservableDictionary(); - public OdWrapper() - { - OdWrapperRegistration.Register(this); - } + private static bool _registered = false; - // expose it as IDictionary for extendedxmlserializer to load/save from + // Expose a copy of Dict just for the XML serialization. + // App code should NOT touch this except for XML save/load. public IDictionary DictToSave { - get => new Dictionary(Dict); + get => new Dictionary(Dict); // copy. potentially expensive. set { Dict.Clear(); - foreach (DictionaryEntry item in value) - { + foreach (DictionaryEntry item in value) { Dict.Add((TKey)item.Key, (TValue)item.Value); } } } - - #region Equality - - protected bool Equals(OdWrapper other) - { - return Dict.SequenceEqual(other.Dict); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((OdWrapper)obj); - } - - public override int GetHashCode() - { - return Dict.GetHashCode(); - } - - #endregion - } - - // this is pretty hacky. - // anytime you use OdWrapper, you need to use this to tell the xml serialize to ignore the ObservableDict property - // on OdWrapper. - // - // This really needs to go away and be solved more elegantly with some better use of ExtendedXmlSerializer. - // - // or... just move away from dictionaries for data storage. which would be a shame but probably easier - - - - - - - // older junkier attempts below. leaving for now, I'm still messing with this -Dom - - /*public class ObservableDictionaryAdaptor : IDictionary, IEnumerable> - { - private readonly ObservableDictionary dict = new ObservableDictionary(); - public bool Contains(object key) - { - return dict.Keys.Contains((TKey)key); - } - - public void Add(object key, object value) - { - dict.Add((TKey)key, (TValue)value); - } - - public void Clear() - { - dict.Clear(); - } - - IEnumerator> IEnumerable>.GetEnumerator() - { - return dict.GetEnumerator(); - } - - IDictionaryEnumerator IDictionary.GetEnumerator() - { - return new ODEnumerator(dict); - } - - public void Remove(object key) - { - dict.Remove((TKey)key); - } - - public object this[object key] - { - get => dict[(TKey)key]; - set => dict[(TKey)key] = (TValue)value; - } - - public ICollection Keys => (ICollection)dict.Keys; - public ICollection Values => (ICollection)dict.Values; - public bool IsReadOnly => dict.IsReadOnly; - public bool IsFixedSize => false; - - public IEnumerator GetEnumerator() - { - return ((IEnumerable)dict).GetEnumerator(); - } - public void CopyTo(Array array, int index) + public OdWrapper() { - ((ICollection)dict).CopyTo(array, index); - } - - public int Count => dict.Count; - -#pragma warning disable CS0618 - public object SyncRoot => dict.SyncRoot; - -#pragma warning disable CS0618 - public bool IsSynchronized => dict.IsSynchronized; - public ObservableDictionary Dict => dict; - - public bool TryGetValue(TKey key, out TValue value) => dict.TryGetValue(key, out value); + if (_registered) // reminder: this is per- combo + return; - public bool ContainsKey(TKey key) - { - return dict.ContainsKey(key); - } - }*/ - - /* - public class OdWrapper : IDictionary - { - public ObservableDictionary ObservableDict { get; set; } - = new ObservableDictionary(); - - public IDictionary DictToSave - { - get => new Dictionary(ObservableDict); - set - { - ObservableDict.Clear(); - foreach (DictionaryEntry item in value) - { - ObservableDict.Add((TKey)item.Key, (TValue)item.Value); - } - } + OdWrapperRegistration.Register(); + _registered = true; } #region Equality protected bool Equals(OdWrapper other) { - return ObservableDict.SequenceEqual(other.ObservableDict); + return Dict.SequenceEqual(other.Dict); } public override bool Equals(object obj) @@ -230,49 +95,9 @@ public override bool Equals(object obj) public override int GetHashCode() { - return (ObservableDict != null ? ObservableDict.GetHashCode() : 0); + return Dict.GetHashCode(); } #endregion } - - /* - public class ODEnumerator_Full_But_Not_Working : IDictionaryEnumerator, IDisposable - { - private readonly IEnumerator> impl; - - public void Dispose() - { - impl.Dispose(); - } - - public ODEnumerator(IDictionary value) - { - impl = value.GetEnumerator(); - } - - public void Reset() - { - impl.Reset(); - } - - public bool MoveNext() - { - return impl.MoveNext(); - } - - public DictionaryEntry Entry - { - get - { - var pair = impl.Current; - return new DictionaryEntry(pair.Key, pair.Value); - } - } - - public object Key => impl.Current.Key; - public object Value => impl.Current.Value; - public object Current => Entry; - } - */ } \ No newline at end of file diff --git a/Diz.Core/loadsave/xml_serializer/ProjectXMLSerializer.cs b/Diz.Core/loadsave/xml_serializer/ProjectXMLSerializer.cs index 9a07e7ab..745014c3 100644 --- a/Diz.Core/loadsave/xml_serializer/ProjectXMLSerializer.cs +++ b/Diz.Core/loadsave/xml_serializer/ProjectXMLSerializer.cs @@ -57,6 +57,8 @@ public override byte[] Save(Project project) return finalBytes; } + // just for debugging purposes, compare two projects together to make sure they serialize/deserialize + // correctly. private void DebugVerifyProjectEquality(Project project1, byte[] finalBytes_project2) { var project2 = Load(finalBytes_project2); diff --git a/Diz.Core/loadsave/xml_serializer/XMLSerializerSupport.cs b/Diz.Core/loadsave/xml_serializer/XMLSerializerSupport.cs index aa3a35c5..b6405e3a 100644 --- a/Diz.Core/loadsave/xml_serializer/XMLSerializerSupport.cs +++ b/Diz.Core/loadsave/xml_serializer/XMLSerializerSupport.cs @@ -1,4 +1,5 @@ -using DiztinGUIsh.core; +using Diz.Core.core.util; +using DiztinGUIsh.core; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; @@ -8,10 +9,13 @@ public static class XmlSerializerSupport { public static IExtendedXmlSerializer GetSerializer() { - // var sourceD = new Data.ObservableDictionaryAdaptor(); - // IDictionary IDict = (IDictionary)sourceD; + // This configuration changes how parts of the data structures are serialized back/forth to XML. + // This is using the ExtendedXmlSerializer library, which has a zillion config options and is + // awesome. - // TODO: doesn't work for saving ObservableDictionary related stuff yet. fix. + // TODO: doesn't work for saving ObservableDictionary related stuff yet. we are working + // around it with a wrapper, but, it's clumsy. Somewhere in these options is a way to fix it, + // just gotta figure it out. return new ConfigurationContainer() .Type() @@ -19,31 +23,14 @@ public static IExtendedXmlSerializer GetSerializer() .Type() .Register().Serializer().Using(RomBytesSerializer.Default) .Type() - //.Member(x => x.Comments).Ignore() - //.Member(x => x.Labels).Ignore() - // .Type>() - // .Extend(ObservableDictionaryExtension.Default) - //.EnableImplicitTyping(typeof(Data.ObservableDictionaryAdaptor)) - //.Type>() - //.Register().Serializer().ByCalling(dSerialize, dDeserialize) - //.Type() - //.Type() - //.WithInterceptor(new InterceptorGuy()) + + .ApplyAllOdWrapperConfigurations() // important for ODWrapper to serialize correctly. + .UseOptimizedNamespaces() .UseAutoFormatting() .EnableImplicitTyping(typeof(Data)) .EnableImplicitTyping(typeof(Label)) .Create(); } - - /*private static Data.ObservableDictionaryAdaptor dDeserialize(IFormatReader arg) - { - throw new NotImplementedException(); - } - - private static void dSerialize(IFormatWriter arg1, Data.ObservableDictionaryAdaptor arg2) - { - throw new NotImplementedException(); - }*/ } } \ No newline at end of file diff --git a/Diz.Test/SerializerTest.cs b/Diz.Test/SerializerTest.cs index dde3defd..b24f4542 100644 --- a/Diz.Test/SerializerTest.cs +++ b/Diz.Test/SerializerTest.cs @@ -1,6 +1,6 @@ using System.Xml; using Diz.Core.core.util; -using DiztinGUIsh.core.util; +using DiztinGUIsh; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; using Xunit; @@ -19,13 +19,14 @@ public SerializerTest(ITestOutputHelper testOutputHelper) public class Root { - public OdWrapper ODW { get; set; } = new OdWrapper() - { - Dict = { - {1, "Xtest1"}, - {2, "Xtest3"}, - } - }; + public OdWrapper ODW { get; set; } = new OdWrapper() { Dict = { + {1, "Z test1"}, + {2, "Z test3"}, + }}; + public OdWrapper ODW2 { get; set; } = new OdWrapper() { Dict = { + {100, new Label {comment = "c1", name = "location1"}}, + {200, new Label {comment = "c2", name = "location2"}}, + }}; #region Equality @@ -53,14 +54,13 @@ public override int GetHashCode() private static IExtendedXmlSerializer GetSerializer() { return new ConfigurationContainer() + .UseOptimizedNamespaces() .EnableImplicitlyDefinedDefaultValues() - .EnableMemberExceptionHandling() // debug only - // .ApplyAllOdWrapperConfigurations() // the important one for ODWrapper + .EnableMemberExceptionHandling() // debug only - .AppendDisablingType() + .ApplyAllOdWrapperConfigurations() // the important one for ODWrapper - .UseOptimizedNamespaces() .Create(); } @@ -87,32 +87,8 @@ private void DeSerialize() Assert.Equal(rootElementGood, restoredRoot); } - readonly Root rootElementGood = new Root(); - string xmlShouldBe = "<" + - "ODW>1" + - "Xtest1<" + - "/Value>2" + - "Xtest3"; + private readonly Root rootElementGood = new Root(); + + private const string xmlShouldBe = "1<" + "/Key>Z test1<" + "/Value>2" + "Z test3100locat" + "ion1" + "c1" + "200location2c2"; } } \ No newline at end of file From d9f2672c90397085cce8794c9355a6d06b02ca5e Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 6 Oct 2020 20:30:41 -0400 Subject: [PATCH 073/136] re-organize folders --- Diz.Core/Diz.Core.csproj | 48 +++++++++---------- Diz.Core/{core/import => }/SampleRomData.cs | 0 Diz.Core/{core => arch}/CPU65C816.cs | 0 Diz.Core/{core => export}/LogCreator.cs | 0 Diz.Core/{core => }/import/BSNESImporter.cs | 0 .../{core => }/import/BizHawkCdlImporter.cs | 0 Diz.Core/{core => model}/Data.cs | 0 Diz.Core/{core => model}/Label.cs | 0 Diz.Core/{ => model}/Model.cs | 0 Diz.Core/{core => model}/Project.cs | 0 Diz.Core/{core => model}/ROMByte.cs | 0 Diz.Core/{core => model}/RomBytes.cs | 0 .../ImportSettings.cs | 0 .../ProjectFileManager.cs | 0 .../ProjectSerializer.cs | 0 .../binary_serializer_old/BinarySerializer.cs | 0 .../xml_serializer/ProjectXMLSerializer.cs | 0 .../xml_serializer/RomBytesXMLSerializer.cs | 0 .../xml_serializer/XMLSerializerSupport.cs | 0 Diz.Core/{core => }/util/ByteUtil.cs | 0 .../util/ObservableDictionaryAdaptor.cs | 0 Diz.Core/{core => }/util/RomUtil.cs | 0 Diz.Core/{core => }/util/Util.cs | 0 DiztinGUIsh/DiztinGUIsh.csproj | 11 +++-- .../{window => controller}/IProjectView.cs | 0 .../ProjectController.cs | 0 DiztinGUIsh/{window => util}/GuiUtil.cs | 0 .../{window => util}/LargeFilesReader.cs | 0 .../{window => util}/ProgressBarWorker.cs | 0 29 files changed, 29 insertions(+), 30 deletions(-) rename Diz.Core/{core/import => }/SampleRomData.cs (100%) rename Diz.Core/{core => arch}/CPU65C816.cs (100%) rename Diz.Core/{core => export}/LogCreator.cs (100%) rename Diz.Core/{core => }/import/BSNESImporter.cs (100%) rename Diz.Core/{core => }/import/BizHawkCdlImporter.cs (100%) rename Diz.Core/{core => model}/Data.cs (100%) rename Diz.Core/{core => model}/Label.cs (100%) rename Diz.Core/{ => model}/Model.cs (100%) rename Diz.Core/{core => model}/Project.cs (100%) rename Diz.Core/{core => model}/ROMByte.cs (100%) rename Diz.Core/{core => model}/RomBytes.cs (100%) rename Diz.Core/{loadsave => serialization}/ImportSettings.cs (100%) rename Diz.Core/{loadsave => serialization}/ProjectFileManager.cs (100%) rename Diz.Core/{loadsave => serialization}/ProjectSerializer.cs (100%) rename Diz.Core/{loadsave => serialization}/binary_serializer_old/BinarySerializer.cs (100%) rename Diz.Core/{loadsave => serialization}/xml_serializer/ProjectXMLSerializer.cs (100%) rename Diz.Core/{loadsave => serialization}/xml_serializer/RomBytesXMLSerializer.cs (100%) rename Diz.Core/{loadsave => serialization}/xml_serializer/XMLSerializerSupport.cs (100%) rename Diz.Core/{core => }/util/ByteUtil.cs (100%) rename Diz.Core/{core => }/util/ObservableDictionaryAdaptor.cs (100%) rename Diz.Core/{core => }/util/RomUtil.cs (100%) rename Diz.Core/{core => }/util/Util.cs (100%) rename DiztinGUIsh/{window => controller}/IProjectView.cs (100%) rename DiztinGUIsh/{window => controller}/ProjectController.cs (100%) rename DiztinGUIsh/{window => util}/GuiUtil.cs (100%) rename DiztinGUIsh/{window => util}/LargeFilesReader.cs (100%) rename DiztinGUIsh/{window => util}/ProgressBarWorker.cs (100%) diff --git a/Diz.Core/Diz.Core.csproj b/Diz.Core/Diz.Core.csproj index 1cd5d39c..ba6eb371 100644 --- a/Diz.Core/Diz.Core.csproj +++ b/Diz.Core/Diz.Core.csproj @@ -109,33 +109,31 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - + + diff --git a/Diz.Core/core/import/SampleRomData.cs b/Diz.Core/SampleRomData.cs similarity index 100% rename from Diz.Core/core/import/SampleRomData.cs rename to Diz.Core/SampleRomData.cs diff --git a/Diz.Core/core/CPU65C816.cs b/Diz.Core/arch/CPU65C816.cs similarity index 100% rename from Diz.Core/core/CPU65C816.cs rename to Diz.Core/arch/CPU65C816.cs diff --git a/Diz.Core/core/LogCreator.cs b/Diz.Core/export/LogCreator.cs similarity index 100% rename from Diz.Core/core/LogCreator.cs rename to Diz.Core/export/LogCreator.cs diff --git a/Diz.Core/core/import/BSNESImporter.cs b/Diz.Core/import/BSNESImporter.cs similarity index 100% rename from Diz.Core/core/import/BSNESImporter.cs rename to Diz.Core/import/BSNESImporter.cs diff --git a/Diz.Core/core/import/BizHawkCdlImporter.cs b/Diz.Core/import/BizHawkCdlImporter.cs similarity index 100% rename from Diz.Core/core/import/BizHawkCdlImporter.cs rename to Diz.Core/import/BizHawkCdlImporter.cs diff --git a/Diz.Core/core/Data.cs b/Diz.Core/model/Data.cs similarity index 100% rename from Diz.Core/core/Data.cs rename to Diz.Core/model/Data.cs diff --git a/Diz.Core/core/Label.cs b/Diz.Core/model/Label.cs similarity index 100% rename from Diz.Core/core/Label.cs rename to Diz.Core/model/Label.cs diff --git a/Diz.Core/Model.cs b/Diz.Core/model/Model.cs similarity index 100% rename from Diz.Core/Model.cs rename to Diz.Core/model/Model.cs diff --git a/Diz.Core/core/Project.cs b/Diz.Core/model/Project.cs similarity index 100% rename from Diz.Core/core/Project.cs rename to Diz.Core/model/Project.cs diff --git a/Diz.Core/core/ROMByte.cs b/Diz.Core/model/ROMByte.cs similarity index 100% rename from Diz.Core/core/ROMByte.cs rename to Diz.Core/model/ROMByte.cs diff --git a/Diz.Core/core/RomBytes.cs b/Diz.Core/model/RomBytes.cs similarity index 100% rename from Diz.Core/core/RomBytes.cs rename to Diz.Core/model/RomBytes.cs diff --git a/Diz.Core/loadsave/ImportSettings.cs b/Diz.Core/serialization/ImportSettings.cs similarity index 100% rename from Diz.Core/loadsave/ImportSettings.cs rename to Diz.Core/serialization/ImportSettings.cs diff --git a/Diz.Core/loadsave/ProjectFileManager.cs b/Diz.Core/serialization/ProjectFileManager.cs similarity index 100% rename from Diz.Core/loadsave/ProjectFileManager.cs rename to Diz.Core/serialization/ProjectFileManager.cs diff --git a/Diz.Core/loadsave/ProjectSerializer.cs b/Diz.Core/serialization/ProjectSerializer.cs similarity index 100% rename from Diz.Core/loadsave/ProjectSerializer.cs rename to Diz.Core/serialization/ProjectSerializer.cs diff --git a/Diz.Core/loadsave/binary_serializer_old/BinarySerializer.cs b/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs similarity index 100% rename from Diz.Core/loadsave/binary_serializer_old/BinarySerializer.cs rename to Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs diff --git a/Diz.Core/loadsave/xml_serializer/ProjectXMLSerializer.cs b/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs similarity index 100% rename from Diz.Core/loadsave/xml_serializer/ProjectXMLSerializer.cs rename to Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs diff --git a/Diz.Core/loadsave/xml_serializer/RomBytesXMLSerializer.cs b/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs similarity index 100% rename from Diz.Core/loadsave/xml_serializer/RomBytesXMLSerializer.cs rename to Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs diff --git a/Diz.Core/loadsave/xml_serializer/XMLSerializerSupport.cs b/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs similarity index 100% rename from Diz.Core/loadsave/xml_serializer/XMLSerializerSupport.cs rename to Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs diff --git a/Diz.Core/core/util/ByteUtil.cs b/Diz.Core/util/ByteUtil.cs similarity index 100% rename from Diz.Core/core/util/ByteUtil.cs rename to Diz.Core/util/ByteUtil.cs diff --git a/Diz.Core/core/util/ObservableDictionaryAdaptor.cs b/Diz.Core/util/ObservableDictionaryAdaptor.cs similarity index 100% rename from Diz.Core/core/util/ObservableDictionaryAdaptor.cs rename to Diz.Core/util/ObservableDictionaryAdaptor.cs diff --git a/Diz.Core/core/util/RomUtil.cs b/Diz.Core/util/RomUtil.cs similarity index 100% rename from Diz.Core/core/util/RomUtil.cs rename to Diz.Core/util/RomUtil.cs diff --git a/Diz.Core/core/util/Util.cs b/Diz.Core/util/Util.cs similarity index 100% rename from Diz.Core/core/util/Util.cs rename to Diz.Core/util/Util.cs diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 6b262e1a..0cb09cdc 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -131,8 +131,8 @@ - - + + @@ -141,9 +141,9 @@ TestForm.cs - - - + + + Form @@ -299,6 +299,7 @@ Diz.Core + diff --git a/DiztinGUIsh/window/IProjectView.cs b/DiztinGUIsh/controller/IProjectView.cs similarity index 100% rename from DiztinGUIsh/window/IProjectView.cs rename to DiztinGUIsh/controller/IProjectView.cs diff --git a/DiztinGUIsh/window/ProjectController.cs b/DiztinGUIsh/controller/ProjectController.cs similarity index 100% rename from DiztinGUIsh/window/ProjectController.cs rename to DiztinGUIsh/controller/ProjectController.cs diff --git a/DiztinGUIsh/window/GuiUtil.cs b/DiztinGUIsh/util/GuiUtil.cs similarity index 100% rename from DiztinGUIsh/window/GuiUtil.cs rename to DiztinGUIsh/util/GuiUtil.cs diff --git a/DiztinGUIsh/window/LargeFilesReader.cs b/DiztinGUIsh/util/LargeFilesReader.cs similarity index 100% rename from DiztinGUIsh/window/LargeFilesReader.cs rename to DiztinGUIsh/util/LargeFilesReader.cs diff --git a/DiztinGUIsh/window/ProgressBarWorker.cs b/DiztinGUIsh/util/ProgressBarWorker.cs similarity index 100% rename from DiztinGUIsh/window/ProgressBarWorker.cs rename to DiztinGUIsh/util/ProgressBarWorker.cs From 58e800b2013005061c70aa28fd0bb68dbc67daae Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 6 Oct 2020 20:59:09 -0400 Subject: [PATCH 074/136] minor but widespread cleanup / namespace cleanup --- Diz.Core/SampleRomData.cs | 7 +- Diz.Core/arch/CPU65C816.cs | 67 ++++++++------- Diz.Core/export/LogCreator.cs | 7 +- Diz.Core/import/BSNESImporter.cs | 7 +- Diz.Core/import/BizHawkCdlImporter.cs | 4 +- Diz.Core/model/Data.cs | 10 +-- Diz.Core/model/Label.cs | 8 +- Diz.Core/model/Project.cs | 8 +- Diz.Core/model/ROMByte.cs | 7 +- Diz.Core/model/RomBytes.cs | 3 +- Diz.Core/serialization/ImportSettings.cs | 12 +-- Diz.Core/serialization/ProjectFileManager.cs | 9 +- Diz.Core/serialization/ProjectSerializer.cs | 17 ++-- .../binary_serializer_old/BinarySerializer.cs | 11 +-- .../xml_serializer/ProjectXMLSerializer.cs | 4 +- .../xml_serializer/RomBytesXMLSerializer.cs | 6 +- .../xml_serializer/XMLSerializerSupport.cs | 7 +- Diz.Core/util/ByteUtil.cs | 5 +- Diz.Core/util/ObservableDictionaryAdaptor.cs | 2 +- Diz.Core/util/RomUtil.cs | 3 +- Diz.Core/util/Util.cs | 2 +- Diz.Test/RomByteTests.cs | 3 +- Diz.Test/SerializerTest.cs | 4 +- DiztinGUIsh/Program.cs | 1 + DiztinGUIsh/Properties/Annotations.cs | 3 +- DiztinGUIsh/Properties/AssemblyInfo.cs | 1 - DiztinGUIsh/controller/IProjectView.cs | 4 +- DiztinGUIsh/controller/ProjectController.cs | 13 +-- DiztinGUIsh/util/GuiUtil.cs | 1 + DiztinGUIsh/util/LargeFilesReader.cs | 32 +++---- DiztinGUIsh/util/ProgressBarWorker.cs | 20 ++--- DiztinGUIsh/window/AliasList.cs | 7 +- DiztinGUIsh/window/MainWindow.Designer.cs | 2 +- DiztinGUIsh/window/MainWindow.cs | 28 +++--- DiztinGUIsh/window/dialog/About.cs | 77 ++++++----------- .../window/dialog/ExportDisassembly.cs | 7 +- .../window/dialog/GotoDialog.Designer.cs | 2 +- DiztinGUIsh/window/dialog/GotoDialog.cs | 33 +++---- DiztinGUIsh/window/dialog/HarshAutoStep.cs | 12 +-- DiztinGUIsh/window/dialog/ImportROMDialog.cs | 10 +-- .../dialog/ImportROMDialogController.cs | 6 +- DiztinGUIsh/window/dialog/MarkManyDialog.cs | 86 ++++++++----------- .../window/dialog/MisalignmentChecker.cs | 33 +++---- DiztinGUIsh/window/dialog/ProgressDialog.cs | 2 +- .../window/dialog/TestForm.Designer.cs | 6 +- DiztinGUIsh/window/dialog/TestForm.cs | 5 +- 46 files changed, 260 insertions(+), 344 deletions(-) diff --git a/Diz.Core/SampleRomData.cs b/Diz.Core/SampleRomData.cs index c3cd10cd..827cd60a 100644 --- a/Diz.Core/SampleRomData.cs +++ b/Diz.Core/SampleRomData.cs @@ -1,8 +1,7 @@ -using Diz.Core.core; -using Diz.Core.core.util; -using DiztinGUIsh.core; +using Diz.Core.model; +using Diz.Core.util; -namespace DiztinGUIsh +namespace Diz.Core { public class SampleRomData : Data { diff --git a/Diz.Core/arch/CPU65C816.cs b/Diz.Core/arch/CPU65C816.cs index 03efafc8..67b2ed28 100644 --- a/Diz.Core/arch/CPU65C816.cs +++ b/Diz.Core/arch/CPU65C816.cs @@ -1,6 +1,7 @@ -using DiztinGUIsh.core; +using Diz.Core.model; +using Diz.Core.util; -namespace DiztinGUIsh +namespace Diz.Core.arch { public class CPU65C816 { @@ -11,9 +12,9 @@ public CPU65C816(Data data) } public int Step(int offset, bool branch, bool force, int prevOffset) { - int opcode = Data.GetROMByte(offset); - int prevDirectPage = Data.GetDirectPage(offset); - int prevDataBank = Data.GetDataBank(offset); + var opcode = Data.GetROMByte(offset); + var prevDirectPage = Data.GetDirectPage(offset); + var prevDataBank = Data.GetDataBank(offset); bool prevX = Data.GetXFlag(offset), prevM = Data.GetMFlag(offset); while (prevOffset >= 0 && Data.GetFlag(prevOffset) == Data.FlagType.Operand) prevOffset--; @@ -38,9 +39,9 @@ public int Step(int offset, bool branch, bool force, int prevOffset) Data.SetXFlag(offset, prevX); Data.SetMFlag(offset, prevM); - int length = GetInstructionLength(offset); + var length = GetInstructionLength(offset); - for (int i = 1; i < length; i++) + for (var i = 1; i < length; i++) { Data.SetFlag(offset + i, Data.FlagType.Operand); Data.SetDataBank(offset + i, prevDataBank); @@ -51,17 +52,17 @@ public int Step(int offset, bool branch, bool force, int prevOffset) MarkInOutPoints(offset); - int nextOffset = offset + length; + var nextOffset = offset + length; - if (!force && (opcode == 0x4C || opcode == 0x5C || opcode == 0x80 || opcode == 0x82 // JMP JML BRA BRL - || (branch && (opcode == 0x10 || opcode == 0x30 || opcode == 0x50 // BPL BMI BVC - || opcode == 0x70 || opcode == 0x90 || opcode == 0xB0 || opcode == 0xD0 // BVS BCC BCS BNE - || opcode == 0xF0 || opcode == 0x20 || opcode == 0x22)))) // BEQ JSR JSL - { - int iaNextOffsetPC = Data.ConvertSNEStoPC(GetIntermediateAddress(offset, true)); - if (iaNextOffsetPC >= 0) - nextOffset = iaNextOffsetPC; - } + if (force || (opcode != 0x4C && opcode != 0x5C && opcode != 0x80 && opcode != 0x82 && (!branch || + (opcode != 0x10 && opcode != 0x30 && opcode != 0x50 && opcode != 0x70 && opcode != 0x90 && + opcode != 0xB0 && opcode != 0xD0 && opcode != 0xF0 && opcode != 0x20 && + opcode != 0x22)))) + return nextOffset; + + var iaNextOffsetPc = Data.ConvertSNEStoPC(GetIntermediateAddress(offset, true)); + if (iaNextOffsetPc >= 0) + nextOffset = iaNextOffsetPc; return nextOffset; } @@ -69,7 +70,7 @@ public int Step(int offset, bool branch, bool force, int prevOffset) public int GetIntermediateAddress(int offset, bool resolve) { int bank, directPage, operand, programCounter; - int opcode = Data.GetROMByte(offset); + var opcode = Data.GetROMByte(offset); var mode = GetAddressMode(offset); switch (mode) @@ -246,22 +247,22 @@ private string FormatOperandAddress(int offset, AddressMode mode) private string GetMnemonic(int offset, bool showHint = true) { - string mn = mnemonics[Data.GetROMByte(offset)]; - if (showHint) + var mn = mnemonics[Data.GetROMByte(offset)]; + if (!showHint) + return mn; + + var mode = GetAddressMode(offset); + var count = BytesToShow(mode); + + if (mode == AddressMode.CONSTANT_8 || mode == AddressMode.RELATIVE_16 || mode == AddressMode.RELATIVE_8) return mn; + + return count switch { - AddressMode mode = GetAddressMode(offset); - int count = BytesToShow(mode); - - if (mode == AddressMode.CONSTANT_8 || mode == AddressMode.RELATIVE_16 || mode == AddressMode.RELATIVE_8) return mn; - - switch (count) - { - case 1: return mn += ".B"; - case 2: return mn += ".W"; - case 3: return mn += ".L"; - } - } - return mn; + 1 => mn += ".B", + 2 => mn += ".W", + 3 => mn += ".L", + _ => mn + }; } private static int BytesToShow(AddressMode mode) diff --git a/Diz.Core/export/LogCreator.cs b/Diz.Core/export/LogCreator.cs index faf9418a..b38b1e65 100644 --- a/Diz.Core/export/LogCreator.cs +++ b/Diz.Core/export/LogCreator.cs @@ -1,14 +1,13 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; -using DiztinGUIsh.core; -using DiztinGUIsh.core.util; +using Diz.Core.model; +using Diz.Core.util; -namespace DiztinGUIsh +namespace Diz.Core.export { public struct LogWriterSettings { diff --git a/Diz.Core/import/BSNESImporter.cs b/Diz.Core/import/BSNESImporter.cs index 55b07dfe..c0908366 100644 --- a/Diz.Core/import/BSNESImporter.cs +++ b/Diz.Core/import/BSNESImporter.cs @@ -1,10 +1,7 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Diz.Core.model; -namespace DiztinGUIsh.core.import +namespace Diz.Core.import { public class BSNESUsageMapImporter { diff --git a/Diz.Core/import/BizHawkCdlImporter.cs b/Diz.Core/import/BizHawkCdlImporter.cs index 2be734c8..c4d1cb07 100644 --- a/Diz.Core/import/BizHawkCdlImporter.cs +++ b/Diz.Core/import/BizHawkCdlImporter.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using DiztinGUIsh.core; +using Diz.Core.model; -namespace DiztinGUIsh +namespace Diz.Core.import { public class BizHawkCdlImporter { diff --git a/Diz.Core/model/Data.cs b/Diz.Core/model/Data.cs index f604a5f0..6446764e 100644 --- a/Diz.Core/model/Data.cs +++ b/Diz.Core/model/Data.cs @@ -1,16 +1,14 @@ using System; -using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Text; -using Diz.Core.core; -using Diz.Core.core.util; -using DiztinGUIsh.core.util; -using IX.Observable; +using Diz.Core.arch; +using Diz.Core.util; +using DiztinGUIsh; -namespace DiztinGUIsh.core +namespace Diz.Core.model { public class Data { diff --git a/Diz.Core/model/Label.cs b/Diz.Core/model/Label.cs index 9099944b..9710f227 100644 --- a/Diz.Core/model/Label.cs +++ b/Diz.Core/model/Label.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace DiztinGUIsh +namespace Diz.Core.model { // represent a label at a particular address // NOTE: you can have labels at addresses in: diff --git a/Diz.Core/model/Project.cs b/Diz.Core/model/Project.cs index 65c2e991..13faf790 100644 --- a/Diz.Core/model/Project.cs +++ b/Diz.Core/model/Project.cs @@ -1,9 +1,9 @@ using System; -using System.Collections.Generic; -using DiztinGUIsh.core; -using DiztinGUIsh.core.util; +using Diz.Core.export; +using Diz.Core.util; +using DiztinGUIsh; -namespace DiztinGUIsh +namespace Diz.Core.model { public class Project : DizDataModel { diff --git a/Diz.Core/model/ROMByte.cs b/Diz.Core/model/ROMByte.cs index e810b4bb..737a40ca 100644 --- a/Diz.Core/model/ROMByte.cs +++ b/Diz.Core/model/ROMByte.cs @@ -1,6 +1,4 @@ -using DiztinGUIsh.core; - -namespace Diz.Core.core +namespace Diz.Core.model { public class ROMByte { @@ -19,8 +17,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((ROMByte) obj); + return obj.GetType() == this.GetType() && Equals((ROMByte) obj); } public override int GetHashCode() diff --git a/Diz.Core/model/RomBytes.cs b/Diz.Core/model/RomBytes.cs index 013de33d..ba2bf40a 100644 --- a/Diz.Core/model/RomBytes.cs +++ b/Diz.Core/model/RomBytes.cs @@ -1,9 +1,8 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -using Diz.Core.core; -namespace DiztinGUIsh +namespace Diz.Core.model { public class RomBytes : IEnumerable { diff --git a/Diz.Core/serialization/ImportSettings.cs b/Diz.Core/serialization/ImportSettings.cs index b195b835..27f65d48 100644 --- a/Diz.Core/serialization/ImportSettings.cs +++ b/Diz.Core/serialization/ImportSettings.cs @@ -1,12 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using DiztinGUIsh.core; -using DiztinGUIsh.core.util; +using System.Collections.Generic; +using Diz.Core.model; +using DiztinGUIsh; -namespace DiztinGUIsh.loadsave +namespace Diz.Core.serialization { public class ImportRomSettings : PropertyNotifyChanged { diff --git a/Diz.Core/serialization/ProjectFileManager.cs b/Diz.Core/serialization/ProjectFileManager.cs index 92d9bcbf..29e8fc2b 100644 --- a/Diz.Core/serialization/ProjectFileManager.cs +++ b/Diz.Core/serialization/ProjectFileManager.cs @@ -1,11 +1,12 @@ using System; using System.Diagnostics; using System.IO; -using DiztinGUIsh.core; -using DiztinGUIsh.loadsave.binary_serializer_old; -using DiztinGUIsh.loadsave.xml_serializer; +using Diz.Core.model; +using Diz.Core.serialization.binary_serializer_old; +using Diz.Core.serialization.xml_serializer; +using Diz.Core.util; -namespace DiztinGUIsh.loadsave +namespace Diz.Core.serialization { public static class ProjectFileManager { diff --git a/Diz.Core/serialization/ProjectSerializer.cs b/Diz.Core/serialization/ProjectSerializer.cs index 818ac9a9..6b8ffae3 100644 --- a/Diz.Core/serialization/ProjectSerializer.cs +++ b/Diz.Core/serialization/ProjectSerializer.cs @@ -1,12 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; +using System.Diagnostics; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Diz.Core.model; +using DiztinGUIsh; -namespace DiztinGUIsh.loadsave +namespace Diz.Core.serialization { abstract class ProjectSerializer { @@ -25,11 +22,11 @@ public Project LoadFromFile(string filename) return Load(File.ReadAllBytes(filename)); } - protected static void DebugVerifyProjectEquality(Project project1, Project project2, bool deepcut = true) + protected static void DebugVerifyProjectEquality(Project project1, Project project2, bool deepCut = true) { - if (deepcut) + if (deepCut) { - for (int i = 0; i < project1.Data.RomBytes.Count; ++i) + for (var i = 0; i < project1.Data.RomBytes.Count; ++i) { Debug.Assert(project1.Data.RomBytes[i].EqualsButNoRomByte(project2.Data.RomBytes[i])); } diff --git a/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs b/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs index 6a073432..1b4775b3 100644 --- a/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs +++ b/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs @@ -3,10 +3,11 @@ using System.Diagnostics; using System.IO; using System.Linq; -using DiztinGUIsh.core; -using DiztinGUIsh.core.util; +using Diz.Core.model; +using Diz.Core.util; +using DiztinGUIsh; -namespace DiztinGUIsh.loadsave.binary_serializer_old +namespace Diz.Core.serialization.binary_serializer_old { internal class BinarySerializer : ProjectSerializer { @@ -25,9 +26,9 @@ public static bool IsBinaryFileFormat(byte[] data) public override byte[] Save(Project project) { const int versionToSave = LATEST_FILE_FORMAT_VERSION; - byte[] data = SaveVersion(project, versionToSave); + var data = SaveVersion(project, versionToSave); - byte[] everything = new byte[HEADER_SIZE + data.Length]; + var everything = new byte[HEADER_SIZE + data.Length]; everything[0] = versionToSave; ByteUtil.StringToByteArray(Watermark).CopyTo(everything, 1); data.CopyTo(everything, HEADER_SIZE); diff --git a/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs b/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs index 745014c3..fd3ac5a2 100644 --- a/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs +++ b/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs @@ -1,9 +1,11 @@ using System.IO; using System.Text; using System.Xml; +using Diz.Core.model; +using DiztinGUIsh; using ExtendedXmlSerializer; -namespace DiztinGUIsh.loadsave.xml_serializer +namespace Diz.Core.serialization.xml_serializer { internal class ProjectXmlSerializer : ProjectSerializer { diff --git a/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs b/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs index a4d582f6..ac993c62 100644 --- a/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs +++ b/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs @@ -3,8 +3,8 @@ using System.Diagnostics; using System.IO; using System.Linq; -using Diz.Core.core; -using DiztinGUIsh.core; +using Diz.Core.model; +using DiztinGUIsh; using ExtendedXmlSerializer.ContentModel; using ExtendedXmlSerializer.ContentModel.Format; @@ -22,7 +22,7 @@ // is a must. We aim for a tradeoff between decent compression and some small semblance of human readability. // // It's not.. super-pretty code, but it compresses well. -namespace DiztinGUIsh.loadsave.xml_serializer +namespace Diz.Core.serialization.xml_serializer { sealed class RomBytesSerializer : ISerializer { diff --git a/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs b/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs index b6405e3a..96109917 100644 --- a/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs +++ b/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs @@ -1,9 +1,10 @@ -using Diz.Core.core.util; -using DiztinGUIsh.core; +using Diz.Core.model; +using Diz.Core.util; +using DiztinGUIsh; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; -namespace DiztinGUIsh.loadsave.xml_serializer +namespace Diz.Core.serialization.xml_serializer { public static class XmlSerializerSupport { diff --git a/Diz.Core/util/ByteUtil.cs b/Diz.Core/util/ByteUtil.cs index 2083929b..b2f44707 100644 --- a/Diz.Core/util/ByteUtil.cs +++ b/Diz.Core/util/ByteUtil.cs @@ -1,11 +1,8 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace DiztinGUIsh.core.util +namespace Diz.Core.util { public static class ByteUtil { diff --git a/Diz.Core/util/ObservableDictionaryAdaptor.cs b/Diz.Core/util/ObservableDictionaryAdaptor.cs index 4902eec3..4ae57ede 100644 --- a/Diz.Core/util/ObservableDictionaryAdaptor.cs +++ b/Diz.Core/util/ObservableDictionaryAdaptor.cs @@ -7,7 +7,7 @@ using ExtendedXmlSerializer.Configuration; using IX.Observable; -namespace Diz.Core.core.util +namespace Diz.Core.util { // OdwWrapper is wrapping an issue we are having where ExtendedXmlSerializer is having issues // serializing ObservableDictionary<> correctly. It's failing to cast to IDictionary, which is either diff --git a/Diz.Core/util/RomUtil.cs b/Diz.Core/util/RomUtil.cs index 9640574e..372d8868 100644 --- a/Diz.Core/util/RomUtil.cs +++ b/Diz.Core/util/RomUtil.cs @@ -1,8 +1,9 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using Diz.Core.model; -namespace DiztinGUIsh.core.util +namespace Diz.Core.util { public static class RomUtil { diff --git a/Diz.Core/util/Util.cs b/Diz.Core/util/Util.cs index 9c03e876..550213a2 100644 --- a/Diz.Core/util/Util.cs +++ b/Diz.Core/util/Util.cs @@ -6,7 +6,7 @@ using System.Linq; using System.Text; -namespace DiztinGUIsh +namespace Diz.Core.util { public static class Util { diff --git a/Diz.Test/RomByteTests.cs b/Diz.Test/RomByteTests.cs index 7e078cc4..7b0674a4 100644 --- a/Diz.Test/RomByteTests.cs +++ b/Diz.Test/RomByteTests.cs @@ -1,5 +1,4 @@ -using Diz.Core.core; -using DiztinGUIsh.core; +using Diz.Core.model; using Xunit; namespace Diz.Test diff --git a/Diz.Test/SerializerTest.cs b/Diz.Test/SerializerTest.cs index b24f4542..39b61377 100644 --- a/Diz.Test/SerializerTest.cs +++ b/Diz.Test/SerializerTest.cs @@ -1,6 +1,6 @@ using System.Xml; -using Diz.Core.core.util; -using DiztinGUIsh; +using Diz.Core.model; +using Diz.Core.util; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; using Xunit; diff --git a/DiztinGUIsh/Program.cs b/DiztinGUIsh/Program.cs index 575c0f6d..7f67523b 100644 --- a/DiztinGUIsh/Program.cs +++ b/DiztinGUIsh/Program.cs @@ -1,5 +1,6 @@ using System; using System.Windows.Forms; +using DiztinGUIsh.window; namespace DiztinGUIsh { diff --git a/DiztinGUIsh/Properties/Annotations.cs b/DiztinGUIsh/Properties/Annotations.cs index 71e20aff..1e718aae 100644 --- a/DiztinGUIsh/Properties/Annotations.cs +++ b/DiztinGUIsh/Properties/Annotations.cs @@ -24,6 +24,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ using System; + // ReSharper disable InheritdocConsiderUsage #pragma warning disable 1591 @@ -34,7 +35,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // ReSharper disable MemberCanBeProtected.Global // ReSharper disable InconsistentNaming -namespace DiztinGUIsh.Annotations +namespace DiztinGUIsh.Properties { /// /// Indicates that the value of the marked element could be null sometimes, diff --git a/DiztinGUIsh/Properties/AssemblyInfo.cs b/DiztinGUIsh/Properties/AssemblyInfo.cs index f43946cd..bcd3058c 100644 --- a/DiztinGUIsh/Properties/AssemblyInfo.cs +++ b/DiztinGUIsh/Properties/AssemblyInfo.cs @@ -1,6 +1,5 @@ using System.Reflection; using System.Runtime.InteropServices; -using System.Windows.Forms; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information diff --git a/DiztinGUIsh/controller/IProjectView.cs b/DiztinGUIsh/controller/IProjectView.cs index d6389c9d..c26eff23 100644 --- a/DiztinGUIsh/controller/IProjectView.cs +++ b/DiztinGUIsh/controller/IProjectView.cs @@ -1,7 +1,9 @@ using System; +using Diz.Core.export; +using Diz.Core.model; using DiztinGUIsh.window.dialog; -namespace DiztinGUIsh +namespace DiztinGUIsh.controller { public interface IProjectView { diff --git a/DiztinGUIsh/controller/ProjectController.cs b/DiztinGUIsh/controller/ProjectController.cs index 83d7975a..ebd73551 100644 --- a/DiztinGUIsh/controller/ProjectController.cs +++ b/DiztinGUIsh/controller/ProjectController.cs @@ -1,8 +1,11 @@ using System; using System.ComponentModel; using System.IO; -using DiztinGUIsh.core.import; -using DiztinGUIsh.loadsave; +using Diz.Core.export; +using Diz.Core.import; +using Diz.Core.model; +using Diz.Core.serialization; +using DiztinGUIsh.util; using DiztinGUIsh.window.dialog; // Model-View-Controller architecture. @@ -12,7 +15,7 @@ // but not OK to directly use GUI functions to show a form. instead, it should reach // out to the view classes and ask them to do things like popup dialog boxes/change form elements/etc. // -// The idea here is that because there's no direct GUI stuff going on, we can run automations +// The idea here is that because there's no direct GUI stuff going on, we can run automation // and unit testing on this class, and eventually add undo/redo support // // Where possible, let the GUI elements (forms) subscribe to data notifications on our model @@ -26,7 +29,7 @@ // i.e. when user clicks "Open Project", it sends the filename to us for handling // Project -> The actual data, the model. It knows nothing about GUI, just is the low-level business logic -namespace DiztinGUIsh.window +namespace DiztinGUIsh.controller { public class ProjectController { @@ -168,7 +171,7 @@ private void WriteAssemblyOutput(LogWriterSettings settings, bool showProgressBa LogCreator.OutputResult result = null; DoLongRunningTask(delegate { result = lc.CreateLog(); - }, $"Exporting assembly source code..."); + }, "Exporting assembly source code..."); if (result.error_count == 0) File.Delete(settings.error); diff --git a/DiztinGUIsh/util/GuiUtil.cs b/DiztinGUIsh/util/GuiUtil.cs index dc22f992..40467f9b 100644 --- a/DiztinGUIsh/util/GuiUtil.cs +++ b/DiztinGUIsh/util/GuiUtil.cs @@ -1,6 +1,7 @@ using System; using System.ComponentModel; using System.Windows.Forms; +using Diz.Core.util; namespace DiztinGUIsh.window { diff --git a/DiztinGUIsh/util/LargeFilesReader.cs b/DiztinGUIsh/util/LargeFilesReader.cs index 9e242ab6..e2d133cd 100644 --- a/DiztinGUIsh/util/LargeFilesReader.cs +++ b/DiztinGUIsh/util/LargeFilesReader.cs @@ -1,8 +1,9 @@ using System; using System.Collections.Generic; using System.IO; +using Diz.Core.util; -namespace DiztinGUIsh +namespace DiztinGUIsh.util { public class LargeFilesReader : ProgressBarWorker { @@ -21,29 +22,28 @@ protected override void Thread_DoWork() } BytesReadFromPreviousFiles = 0L; - foreach (var filename in Filenames) { - using (var fs = File.Open(filename, FileMode.Open, FileAccess.Read)) - using (var bs = new BufferedStream(fs)) - using (var sr = new StreamReader(bs)) + foreach (var filename in Filenames) + { + using var fs = File.Open(filename, FileMode.Open, FileAccess.Read); + using var bs = new BufferedStream(fs); + using var sr = new StreamReader(bs); + string line; + while ((line = sr.ReadLine()) != null) { - string line; - while ((line = sr.ReadLine()) != null) - { - this.LineReadCallback(line); - this.UpdateProgress(fs.Position); - } - - BytesReadFromPreviousFiles += fs.Length; + LineReadCallback(line); + UpdateProgress(fs.Position); } + + BytesReadFromPreviousFiles += fs.Length; } } - private int previousProgress = 0; + private int previousProgress; protected void UpdateProgress(long currentPositionInBytes) { - float percent = (float)(BytesReadFromPreviousFiles + currentPositionInBytes) / (float)SumFileLengthsInBytes; - int progressValue = (int)(percent * 100); + var percent = (BytesReadFromPreviousFiles + currentPositionInBytes) / (float)SumFileLengthsInBytes; + var progressValue = (int)(percent * 100); if (progressValue <= previousProgress) return; diff --git a/DiztinGUIsh/util/ProgressBarWorker.cs b/DiztinGUIsh/util/ProgressBarWorker.cs index 3cd06af4..e35f416d 100644 --- a/DiztinGUIsh/util/ProgressBarWorker.cs +++ b/DiztinGUIsh/util/ProgressBarWorker.cs @@ -7,11 +7,11 @@ namespace DiztinGUIsh // TODO: use https://www.wpf-tutorial.com/misc/multi-threading-with-the-backgroundworker/ backgroundworker public abstract class ProgressBarWorker { - private ProgressDialog Dialog = null; - private bool IsRunning = false; - private Thread backgroundThread = null; - public bool IsMarquee { get; set; } = false; - public string TextOverride { get; set; } = null; + private ProgressDialog Dialog; + private bool IsRunning; + private Thread backgroundThread; + public bool IsMarquee { get; set; } + public string TextOverride { get; set; } protected void UpdateProgress(int i) { @@ -45,7 +45,7 @@ protected virtual void Setup() Dialog = new ProgressDialog(IsMarquee, TextOverride); // setup, but don't start, the new thread - backgroundThread = new Thread(new ThreadStart(Thread_Main)); + backgroundThread = new Thread(Thread_Main); // honestly, not sure about this. works around some Invoke() stuff backgroundThread.SetApartmentState(ApartmentState.STA); @@ -94,7 +94,7 @@ public class ProgressBarJob : ProgressBarWorker // a version that keeps calling 'callback' until it returns -1 public static void Loop(long maxProgress, NextAction callback, string overrideTxt = null) { - var j = new ProgressBarJob() + var j = new ProgressBarJob { MaxProgress = maxProgress, Callback = callback, @@ -127,15 +127,15 @@ protected override void Thread_DoWork() } while (progress > 0); } - private int previousProgress = 0; + private int previousProgress; protected void UpdateProgress(long currentProgress) { if (MaxProgress <= 0) return; - float percent = (float)(currentProgress) / (float)MaxProgress; - int progressValue = (int)(percent * 100); + var percent = currentProgress / (float)MaxProgress; + var progressValue = (int)(percent * 100); if (progressValue <= previousProgress) return; diff --git a/DiztinGUIsh/window/AliasList.cs b/DiztinGUIsh/window/AliasList.cs index c8412762..6bc63b5d 100644 --- a/DiztinGUIsh/window/AliasList.cs +++ b/DiztinGUIsh/window/AliasList.cs @@ -7,7 +7,10 @@ using System.Linq; using System.Text.RegularExpressions; using System.Windows.Forms; -using DiztinGUIsh.core; +using Diz.Core.model; +using Diz.Core.util; +using DiztinGUIsh.controller; +using Label = Diz.Core.model.Label; namespace DiztinGUIsh.window { @@ -185,7 +188,7 @@ private void dataGridView1_CellValidating(object sender, DataGridViewCellValidat { e.Cancel = true; toolStripStatusLabel1.Text = "This address already has a label."; - var x = Data.Labels; + Console.WriteLine(Util.NumberToBaseString(val, Util.NumberBase.Hexadecimal)); } else if (dataGridView1.EditingControl != null) { diff --git a/DiztinGUIsh/window/MainWindow.Designer.cs b/DiztinGUIsh/window/MainWindow.Designer.cs index adb460e6..3e58e04a 100644 --- a/DiztinGUIsh/window/MainWindow.Designer.cs +++ b/DiztinGUIsh/window/MainWindow.Designer.cs @@ -1,4 +1,4 @@ -namespace DiztinGUIsh +namespace DiztinGUIsh.window { partial class MainWindow { diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 7889a30e..c61ea182 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -1,15 +1,17 @@ -using DiztinGUIsh.window; -using System; +using System; using System.Drawing; using System.Globalization; using System.IO; using System.Windows.Forms; -using DiztinGUIsh.core; -using DiztinGUIsh.core.util; +using Diz.Core.export; +using Diz.Core.model; +using Diz.Core.util; +using DiztinGUIsh.controller; using DiztinGUIsh.Properties; using DiztinGUIsh.window.dialog; +using Label = Diz.Core.model.Label; -namespace DiztinGUIsh +namespace DiztinGUIsh.window { public partial class MainWindow : Form, IProjectView { @@ -388,12 +390,12 @@ public void UpdatePercent() if (Project.Data.GetFlag(i) == Data.FlagType.Unreached) totalUnreached++; int reached = size - totalUnreached; - percentComplete.Text = string.Format("{0:N3}% ({1:D}/{2:D})", reached * 100.0 / size, reached, size); + percentComplete.Text = $"{reached * 100.0 / size:N3}% ({reached:D}/{size:D})"; } public void UpdateMarkerLabel() { - currentMarker.Text = string.Format("Marker: {0}", markFlag.ToString()); + currentMarker.Text = $"Marker: {markFlag.ToString()}"; } public void InvalidateTable() @@ -584,14 +586,12 @@ private void table_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e.Value = RomUtil.PointToString(Project.Data.GetInOutPoint(row)); break; case 5: - int len = Project.Data.GetInstructionLength(row); - if (row + len <= Project.Data.GetROMSize()) e.Value = Project.Data.GetInstruction(row); - else e.Value = ""; + var len = Project.Data.GetInstructionLength(row); + e.Value = row + len <= Project.Data.GetROMSize() ? Project.Data.GetInstruction(row) : ""; break; case 6: - int ia = Project.Data.GetIntermediateAddressOrPointer(row); - if (ia >= 0) e.Value = Util.NumberToBaseString(ia, Util.NumberBase.Hexadecimal, 6); - else e.Value = ""; + var ia = Project.Data.GetIntermediateAddressOrPointer(row); + e.Value = ia >= 0 ? Util.NumberToBaseString(ia, Util.NumberBase.Hexadecimal, 6) : ""; break; case 7: e.Value = Util.GetEnumDescription(Project.Data.GetFlag(row)); @@ -940,7 +940,7 @@ private void gotoToolStripMenuItem_Click(object sender, EventArgs e) if (result != DialogResult.OK) return; - int offset = go.GetPcOffset(); + var offset = go.GetPcOffset(); if (offset >= 0 && offset < Project.Data.GetROMSize()) SelectOffset(offset); else diff --git a/DiztinGUIsh/window/dialog/About.cs b/DiztinGUIsh/window/dialog/About.cs index a190b92f..6097ed1f 100644 --- a/DiztinGUIsh/window/dialog/About.cs +++ b/DiztinGUIsh/window/dialog/About.cs @@ -1,10 +1,5 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Linq; using System.Reflection; -using System.Threading.Tasks; using System.Windows.Forms; namespace DiztinGUIsh @@ -14,12 +9,12 @@ partial class About : Form public About() { InitializeComponent(); - this.Text = String.Format("About {0}", AssemblyTitle); - this.labelProductName.Text = AssemblyProduct; - this.labelVersion.Text = String.Format("Version {0}", AssemblyVersion); - this.labelCopyright.Text = AssemblyCopyright; - this.labelCompanyName.Text = AssemblyCompany; - this.textBoxDescription.Text = AssemblyDescription; + Text = $"About {AssemblyTitle}"; + labelProductName.Text = AssemblyProduct; + labelVersion.Text = $"Version {AssemblyVersion}"; + labelCopyright.Text = AssemblyCopyright; + labelCompanyName.Text = AssemblyCompany; + textBoxDescription.Text = AssemblyDescription; } #region Assembly Attribute Accessors @@ -28,37 +23,27 @@ public string AssemblyTitle { get { - object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false); - if (attributes.Length > 0) - { - AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0]; - if (titleAttribute.Title != "") - { - return titleAttribute.Title; - } - } - return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase); + var attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false); + if (attributes.Length <= 0) + return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase); + + var titleAttribute = (AssemblyTitleAttribute)attributes[0]; + return titleAttribute.Title != "" + ? titleAttribute.Title + : System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase); } } - public string AssemblyVersion - { - get - { - return Assembly.GetExecutingAssembly().GetName().Version.ToString(); - } - } + public string AssemblyVersion => Assembly.GetExecutingAssembly().GetName().Version.ToString(); public string AssemblyDescription { get { - object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false); - if (attributes.Length == 0) - { - return ""; - } - return ((AssemblyDescriptionAttribute)attributes[0]).Description; + var attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false); + return attributes.Length == 0 + ? "" + : ((AssemblyDescriptionAttribute)attributes[0]).Description; } } @@ -66,12 +51,8 @@ public string AssemblyProduct { get { - object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false); - if (attributes.Length == 0) - { - return ""; - } - return ((AssemblyProductAttribute)attributes[0]).Product; + var attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false); + return attributes.Length == 0 ? "" : ((AssemblyProductAttribute)attributes[0]).Product; } } @@ -79,12 +60,8 @@ public string AssemblyCopyright { get { - object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); - if (attributes.Length == 0) - { - return ""; - } - return ((AssemblyCopyrightAttribute)attributes[0]).Copyright; + var attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); + return attributes.Length == 0 ? "" : ((AssemblyCopyrightAttribute)attributes[0]).Copyright; } } @@ -92,12 +69,8 @@ public string AssemblyCompany { get { - object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); - if (attributes.Length == 0) - { - return ""; - } - return ((AssemblyCompanyAttribute)attributes[0]).Company; + var attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); + return attributes.Length == 0 ? "" : ((AssemblyCompanyAttribute)attributes[0]).Company; } } #endregion diff --git a/DiztinGUIsh/window/dialog/ExportDisassembly.cs b/DiztinGUIsh/window/dialog/ExportDisassembly.cs index 9577c8c0..828724b8 100644 --- a/DiztinGUIsh/window/dialog/ExportDisassembly.cs +++ b/DiztinGUIsh/window/dialog/ExportDisassembly.cs @@ -2,7 +2,9 @@ using System.IO; using System.Text; using System.Windows.Forms; -using DiztinGUIsh.core; +using Diz.Core; +using Diz.Core.export; +using Diz.Core.model; namespace DiztinGUIsh { @@ -10,7 +12,6 @@ namespace DiztinGUIsh // end. public partial class ExportDisassembly : Form { - private Data Data => Project.Data; private readonly Project Project; // Our copy. At the end, if everything is correct, we'll return this. @@ -161,8 +162,6 @@ private string CreateSampleOutput() var sampleSettings = settings; sampleSettings.structure = LogCreator.FormatStructure.SingleFile; - Data sampleData = SampleRomData.SampleData; - var lc = new LogCreator() { Settings = sampleSettings, diff --git a/DiztinGUIsh/window/dialog/GotoDialog.Designer.cs b/DiztinGUIsh/window/dialog/GotoDialog.Designer.cs index 3cab1c30..e0343fc0 100644 --- a/DiztinGUIsh/window/dialog/GotoDialog.Designer.cs +++ b/DiztinGUIsh/window/dialog/GotoDialog.Designer.cs @@ -1,4 +1,4 @@ -namespace DiztinGUIsh +namespace DiztinGUIsh.window.dialog { partial class GotoDialog { diff --git a/DiztinGUIsh/window/dialog/GotoDialog.cs b/DiztinGUIsh/window/dialog/GotoDialog.cs index 68c3632e..45c5095d 100644 --- a/DiztinGUIsh/window/dialog/GotoDialog.cs +++ b/DiztinGUIsh/window/dialog/GotoDialog.cs @@ -1,17 +1,10 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; -using DiztinGUIsh.core; -using DiztinGUIsh.core.util; +using Diz.Core.model; +using Diz.Core.util; -namespace DiztinGUIsh +namespace DiztinGUIsh.window.dialog { public partial class GotoDialog : Form { @@ -47,7 +40,7 @@ private void Go() this.DialogResult = DialogResult.OK; } - private bool updatingText = false; + private bool updatingText; private bool UpdateTextChanged(string txtChanged, Action onSuccess) { @@ -56,8 +49,8 @@ private bool UpdateTextChanged(string txtChanged, Action= 0) { @@ -76,7 +69,7 @@ private bool UpdateTextChanged(string txtChanged, Action + private bool IsOffsetInRange(int offset) => offset > 0 && offset <= ImportSettings.RomBytes.Length; private bool IsProbablyValidDetection() => diff --git a/DiztinGUIsh/window/dialog/ImportROMDialogController.cs b/DiztinGUIsh/window/dialog/ImportROMDialogController.cs index 417cbc67..50916ee3 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialogController.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialogController.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; -using DiztinGUIsh.core; -using DiztinGUIsh.core.util; -using DiztinGUIsh.loadsave; +using Diz.Core.model; +using Diz.Core.serialization; +using Diz.Core.util; namespace DiztinGUIsh.window.dialog { diff --git a/DiztinGUIsh/window/dialog/MarkManyDialog.cs b/DiztinGUIsh/window/dialog/MarkManyDialog.cs index c05cac8d..0edff915 100644 --- a/DiztinGUIsh/window/dialog/MarkManyDialog.cs +++ b/DiztinGUIsh/window/dialog/MarkManyDialog.cs @@ -1,14 +1,8 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; -using DiztinGUIsh.core; +using Diz.Core.model; +using Diz.Core.util; namespace DiztinGUIsh { @@ -110,7 +104,7 @@ private void UpdateGroup() value = property.SelectedIndex == 1 ? Data.GetDataBank(start) : Data.GetDirectPage(start); } - private bool updatingText = false; + private bool updatingText; private void UpdateText(TextBox selected) { @@ -136,39 +130,33 @@ private void UpdateText(TextBox selected) private void textCount_TextChanged(object sender, EventArgs e) { - if (!updatingText) - { - updatingText = true; - NumberStyles style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; - - int result = 0; - if (int.TryParse(textCount.Text, style, null, out result)) - { - count = result; - end = start + count; - } + if (updatingText) return; + updatingText = true; + var style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; - UpdateText(textCount); + if (int.TryParse(textCount.Text, style, null, out var result)) + { + count = result; + end = start + count; } + + UpdateText(textCount); } private void textEnd_TextChanged(object sender, EventArgs e) { - if (!updatingText) + if (updatingText) return; + updatingText = true; + var style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; + + if (int.TryParse(textEnd.Text, style, null, out var result)) { - updatingText = true; - NumberStyles style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; - - int result = 0; - if (int.TryParse(textEnd.Text, style, null, out result)) - { - if (radioROM.Checked) result = Data.ConvertSNEStoPC(result); - end = result; - count = end - start; - } - - UpdateText(textEnd); + if (radioROM.Checked) result = Data.ConvertSNEStoPC(result); + end = result; + count = end - start; } + + UpdateText(textEnd); } private void property_SelectedIndexChanged(object sender, EventArgs e) @@ -178,10 +166,9 @@ private void property_SelectedIndexChanged(object sender, EventArgs e) private void regValue_TextChanged(object sender, EventArgs e) { - NumberStyles style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; + var style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; - int result = 0; - if (int.TryParse(regValue.Text, style, null, out result)) + if (int.TryParse(regValue.Text, style, null, out var result)) { value = result; } @@ -194,26 +181,23 @@ private void okay_Click(object sender, EventArgs e) private void cancel_Click(object sender, EventArgs e) { - this.Close(); + Close(); } private void textStart_TextChanged(object sender, EventArgs e) { - if (!updatingText) + if (updatingText) return; + updatingText = true; + var style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; + + if (int.TryParse(textStart.Text, style, null, out var result)) { - updatingText = true; - NumberStyles style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; - - int result = 0; - if (int.TryParse(textStart.Text, style, null, out result)) - { - if (radioROM.Checked) result = Data.ConvertSNEStoPC(result); - start = result; - count = end - start; - } - - UpdateText(textStart); + if (radioROM.Checked) result = Data.ConvertSNEStoPC(result); + start = result; + count = end - start; } + + UpdateText(textStart); } private void radioHex_CheckedChanged(object sender, EventArgs e) diff --git a/DiztinGUIsh/window/dialog/MisalignmentChecker.cs b/DiztinGUIsh/window/dialog/MisalignmentChecker.cs index 42c11591..c24c94c5 100644 --- a/DiztinGUIsh/window/dialog/MisalignmentChecker.cs +++ b/DiztinGUIsh/window/dialog/MisalignmentChecker.cs @@ -1,14 +1,7 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; -using DiztinGUIsh.core; -using DiztinGUIsh.core.util; +using Diz.Core.model; +using Diz.Core.util; namespace DiztinGUIsh { @@ -34,27 +27,21 @@ private void buttonScan_Click(object sender, EventArgs e) while (found < 500 && offset < Data.GetROMSize()) { Data.FlagType flag = Data.GetFlag(offset), check = flag == Data.FlagType.Opcode ? Data.FlagType.Operand : flag; - int step = flag == Data.FlagType.Opcode ? Data.GetInstructionLength(offset) : RomUtil.TypeStepSize(flag); + var step = flag == Data.FlagType.Opcode ? Data.GetInstructionLength(offset) : RomUtil.TypeStepSize(flag); if (flag == Data.FlagType.Operand) { found++; - textLog.Text += string.Format("{0} (0x{1}): Operand without Opcode\r\n", - Util.NumberToBaseString(Data.ConvertPCtoSNES(offset), Util.NumberBase.Hexadecimal, 6, true), - Util.NumberToBaseString(offset, Util.NumberBase.Hexadecimal, 0)); + textLog.Text += + $"{Util.NumberToBaseString(Data.ConvertPCtoSNES(offset), Util.NumberBase.Hexadecimal, 6, true)} (0x{Util.NumberToBaseString(offset, Util.NumberBase.Hexadecimal, 0)}): Operand without Opcode\r\n"; } else if (step > 1) { - for (int i = 1; i < step; i++) + for (var i = 1; i < step; i++) { - if (Data.GetFlag(offset + i) != check) - { - found++; - textLog.Text += string.Format("{0} (0x{1}): {2} is not {3}\r\n", - Util.NumberToBaseString(Data.ConvertPCtoSNES(offset + i), Util.NumberBase.Hexadecimal, 6, true), - Util.NumberToBaseString(offset + i, Util.NumberBase.Hexadecimal, 0), - Util.GetEnumDescription(Data.GetFlag(offset + i)), - Util.GetEnumDescription(check)); - } + if (Data.GetFlag(offset + i) == check) continue; + found++; + textLog.Text += + $"{Util.NumberToBaseString(Data.ConvertPCtoSNES(offset + i), Util.NumberBase.Hexadecimal, 6, true)} (0x{Util.NumberToBaseString(offset + i, Util.NumberBase.Hexadecimal, 0)}): {Util.GetEnumDescription(Data.GetFlag(offset + i))} is not {Util.GetEnumDescription(check)}\r\n"; } } diff --git a/DiztinGUIsh/window/dialog/ProgressDialog.cs b/DiztinGUIsh/window/dialog/ProgressDialog.cs index 4883a172..b2987735 100644 --- a/DiztinGUIsh/window/dialog/ProgressDialog.cs +++ b/DiztinGUIsh/window/dialog/ProgressDialog.cs @@ -12,7 +12,7 @@ namespace DiztinGUIsh.window.dialog { public partial class ProgressDialog : Form { - private readonly string overrideText = null; + private readonly string overrideText; public ProgressDialog(bool marquee = false, string textOverride = null) { diff --git a/DiztinGUIsh/window/dialog/TestForm.Designer.cs b/DiztinGUIsh/window/dialog/TestForm.Designer.cs index 61fa3969..f38daa0a 100644 --- a/DiztinGUIsh/window/dialog/TestForm.Designer.cs +++ b/DiztinGUIsh/window/dialog/TestForm.Designer.cs @@ -1,4 +1,6 @@ -namespace DiztinGUIsh.window.dialog +using Diz.Core.serialization; + +namespace DiztinGUIsh.window.dialog { partial class TestForm { @@ -60,7 +62,7 @@ private void InitializeComponent() // // project_ImportRomSettingsBindingSource // - this.project_ImportRomSettingsBindingSource.DataSource = typeof(DiztinGUIsh.loadsave.ImportRomSettings); + this.project_ImportRomSettingsBindingSource.DataSource = typeof(ImportRomSettings); // // rOMMapModeComboBox // diff --git a/DiztinGUIsh/window/dialog/TestForm.cs b/DiztinGUIsh/window/dialog/TestForm.cs index 2823bc26..7ab8954f 100644 --- a/DiztinGUIsh/window/dialog/TestForm.cs +++ b/DiztinGUIsh/window/dialog/TestForm.cs @@ -1,7 +1,8 @@ using System; using System.Windows.Forms; -using DiztinGUIsh.core; -using DiztinGUIsh.loadsave; +using Diz.Core.model; +using Diz.Core.serialization; +using Diz.Core.util; namespace DiztinGUIsh.window.dialog { From ebfa8fe3c9d1a23173e41999108604251327899b Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 6 Oct 2020 21:12:54 -0400 Subject: [PATCH 075/136] fix trying to save with zero odwrappers registered fix not seeing an error msg on invalid project load --- Diz.Core/serialization/ProjectSerializer.cs | 1 - Diz.Core/util/ObservableDictionaryAdaptor.cs | 9 +++++++-- DiztinGUIsh/controller/IProjectView.cs | 2 +- DiztinGUIsh/controller/ProjectController.cs | 6 ++++-- DiztinGUIsh/window/MainWindow.cs | 3 ++- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Diz.Core/serialization/ProjectSerializer.cs b/Diz.Core/serialization/ProjectSerializer.cs index 6b8ffae3..e1224934 100644 --- a/Diz.Core/serialization/ProjectSerializer.cs +++ b/Diz.Core/serialization/ProjectSerializer.cs @@ -1,7 +1,6 @@ using System.Diagnostics; using System.IO; using Diz.Core.model; -using DiztinGUIsh; namespace Diz.Core.serialization { diff --git a/Diz.Core/util/ObservableDictionaryAdaptor.cs b/Diz.Core/util/ObservableDictionaryAdaptor.cs index 4ae57ede..badf1ca7 100644 --- a/Diz.Core/util/ObservableDictionaryAdaptor.cs +++ b/Diz.Core/util/ObservableDictionaryAdaptor.cs @@ -36,8 +36,13 @@ public static void Register() Debug.Assert(operationFNs.Count != 0); } - public static IConfigurationContainer ApplyAllOdWrapperConfigurations(this IConfigurationContainer @this) => - operationFNs.Aggregate(@this, (current, fn) => fn(current)); + public static IConfigurationContainer ApplyAllOdWrapperConfigurations(this IConfigurationContainer @this) + { + if (operationFNs.Count == 0) + return @this; + + return operationFNs.Aggregate(@this, (current, fn) => fn(current)); + } } // wrapper around an ObservableDictionary so we can implement non-generic IDictionary diff --git a/DiztinGUIsh/controller/IProjectView.cs b/DiztinGUIsh/controller/IProjectView.cs index c26eff23..cb434c9b 100644 --- a/DiztinGUIsh/controller/IProjectView.cs +++ b/DiztinGUIsh/controller/IProjectView.cs @@ -8,7 +8,7 @@ namespace DiztinGUIsh.controller public interface IProjectView { Project Project { get; set; } - void OnProjectOpenFail(); + void OnProjectOpenFail(string errorMsg); void OnProjectSaved(); void OnExportFinished(LogCreator.OutputResult result); diff --git a/DiztinGUIsh/controller/ProjectController.cs b/DiztinGUIsh/controller/ProjectController.cs index ebd73551..851c152c 100644 --- a/DiztinGUIsh/controller/ProjectController.cs +++ b/DiztinGUIsh/controller/ProjectController.cs @@ -64,19 +64,21 @@ public void DoLongRunningTask(Action task, string description = null) public bool OpenProject(string filename) { Project project = null; + var errorMsg = ""; // TODO: try/catch for ProjectFileManager DoLongRunningTask(delegate { try { project = ProjectFileManager.Open(filename, AskToSelectNewRomFilename); - } catch (Exception) { + } catch (Exception ex) { project = null; + errorMsg = ex.Message; } }, $"Opening {Path.GetFileName(filename)}..."); if (project == null) { - ProjectView.OnProjectOpenFail(); + ProjectView.OnProjectOpenFail(errorMsg); return false; } diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index c61ea182..b8aff57a 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -218,9 +218,10 @@ private void RefreshUI() EnableSubWindows(); } - public void OnProjectOpenFail() + public void OnProjectOpenFail(string errorMsg) { LastProjectFilename = ""; + MessageBox.Show(errorMsg, "Error opening project", MessageBoxButtons.OK, MessageBoxIcon.Error); } public void OpenProject(string filename) From 2ceb307224813e9491d713e44e2779c00ed78ee8 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Wed, 7 Oct 2020 09:24:24 -0400 Subject: [PATCH 076/136] finish OdWrapper serialization support --- Diz.Core/model/Data.cs | 1 - .../xml_serializer/ProjectXMLSerializer.cs | 4 +- .../xml_serializer/RomBytesXMLSerializer.cs | 1 - .../xml_serializer/XMLSerializerSupport.cs | 6 +- Diz.Core/util/ObservableDictionaryAdaptor.cs | 40 +++++++---- Diz.Test/SerializerTest.cs | 72 +++++++++++++------ DiztinGUIsh/Program.cs | 4 ++ 7 files changed, 85 insertions(+), 43 deletions(-) diff --git a/Diz.Core/model/Data.cs b/Diz.Core/model/Data.cs index 6446764e..02a7b642 100644 --- a/Diz.Core/model/Data.cs +++ b/Diz.Core/model/Data.cs @@ -6,7 +6,6 @@ using System.Text; using Diz.Core.arch; using Diz.Core.util; -using DiztinGUIsh; namespace Diz.Core.model { diff --git a/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs b/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs index fd3ac5a2..d73af2e9 100644 --- a/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs +++ b/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs @@ -46,7 +46,7 @@ public override byte[] Save(Project project) Project = project, }; - var xmlStr = XmlSerializerSupport.GetSerializer().Serialize( + var xmlStr = XmlSerializerSupport.GetSerializer().Create().Serialize( new XmlWriterSettings { Indent = true }, rootElement); @@ -77,7 +77,7 @@ public override Project Load(byte[] data) // Also, we can do data migrations based on versioning, and ExtendedXmlSerializer var text = Encoding.UTF8.GetString(data); - var root = XmlSerializerSupport.GetSerializer().Deserialize(text); + var root = XmlSerializerSupport.GetSerializer().Create().Deserialize(text); if (root.Watermark != Watermark) throw new InvalidDataException("This file doesn't appear to be a valid DiztinGUIsh XML file (missing/invalid watermark element in XML)"); diff --git a/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs b/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs index ac993c62..4212963c 100644 --- a/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs +++ b/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using Diz.Core.model; -using DiztinGUIsh; using ExtendedXmlSerializer.ContentModel; using ExtendedXmlSerializer.ContentModel.Format; diff --git a/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs b/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs index 96109917..3f75d574 100644 --- a/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs +++ b/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs @@ -1,6 +1,5 @@ using Diz.Core.model; using Diz.Core.util; -using DiztinGUIsh; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; @@ -8,7 +7,7 @@ namespace Diz.Core.serialization.xml_serializer { public static class XmlSerializerSupport { - public static IExtendedXmlSerializer GetSerializer() + public static IConfigurationContainer GetSerializer() { // This configuration changes how parts of the data structures are serialized back/forth to XML. // This is using the ExtendedXmlSerializer library, which has a zillion config options and is @@ -30,8 +29,7 @@ public static IExtendedXmlSerializer GetSerializer() .UseOptimizedNamespaces() .UseAutoFormatting() .EnableImplicitTyping(typeof(Data)) - .EnableImplicitTyping(typeof(Label)) - .Create(); + .EnableImplicitTyping(typeof(Label)); } } } \ No newline at end of file diff --git a/Diz.Core/util/ObservableDictionaryAdaptor.cs b/Diz.Core/util/ObservableDictionaryAdaptor.cs index badf1ca7..7af4eb06 100644 --- a/Diz.Core/util/ObservableDictionaryAdaptor.cs +++ b/Diz.Core/util/ObservableDictionaryAdaptor.cs @@ -1,8 +1,8 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; +using System.Runtime.CompilerServices; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; using IX.Observable; @@ -22,19 +22,13 @@ public static IConfigurationContainer AppendDisablingType(this ICo => @this .EnableImplicitTyping(typeof(OdWrapper)) .Type>() - .Member(x => x.Dict).Ignore(); // the important bit + .Member(x => x.Dict).Ignore(); // this is the heart of everything private static readonly List> operationFNs = new List>(); // allow multiple OdWrapper type combos to be excluded. - public static void Register() - { - Func fn = container => - container.AppendDisablingType(); - - operationFNs.Add(fn); - Debug.Assert(operationFNs.Count != 0); - } + public static void Register() => + operationFNs.Add(container => container.AppendDisablingType()); public static IConfigurationContainer ApplyAllOdWrapperConfigurations(this IConfigurationContainer @this) { @@ -43,6 +37,20 @@ public static IConfigurationContainer ApplyAllOdWrapperConfigurations(this IConf return operationFNs.Aggregate(@this, (current, fn) => fn(current)); } + + // helper method to force the static stuff in the above classes to start at Program start. + // we need an approach that doesn't rely on this to work. + public static void ForceStaticClassRegistration() + { + foreach (var typeHandle in AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(asm=>asm.DefinedTypes) + .SelectMany(typeInfo => typeInfo.DeclaredProperties) + .Where(propertyInfo=>propertyInfo.PropertyType.Name.Contains("OdWrapper")) + .Select(propertyInfo=>propertyInfo.PropertyType.TypeHandle) + ) { + RuntimeHelpers.RunClassConstructor(typeHandle); // will call OdWrapper.Register for each generic type + } + } } // wrapper around an ObservableDictionary so we can implement non-generic IDictionary @@ -59,7 +67,7 @@ public class OdWrapper // The app code should use this directly. public ObservableDictionary Dict { get; set; } = new ObservableDictionary(); - private static bool _registered = false; + private static bool _registered = Register(); // Expose a copy of Dict just for the XML serialization. // App code should NOT touch this except for XML save/load. @@ -74,13 +82,17 @@ public IDictionary DictToSave } } } - public OdWrapper() + + public OdWrapper() { Register(); } + + private static bool Register() { - if (_registered) // reminder: this is per- combo - return; + if (_registered) // reminder: this is unique per- combo + return true; OdWrapperRegistration.Register(); _registered = true; + return true; } #region Equality diff --git a/Diz.Test/SerializerTest.cs b/Diz.Test/SerializerTest.cs index 39b61377..52ea673a 100644 --- a/Diz.Test/SerializerTest.cs +++ b/Diz.Test/SerializerTest.cs @@ -1,5 +1,6 @@ using System.Xml; using Diz.Core.model; +using Diz.Core.serialization.xml_serializer; using Diz.Core.util; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; @@ -17,7 +18,7 @@ public SerializerTest(ITestOutputHelper testOutputHelper) this.testOutputHelper = testOutputHelper; } - public class Root + public class TestRoot { public OdWrapper ODW { get; set; } = new OdWrapper() { Dict = { {1, "Z test1"}, @@ -30,7 +31,7 @@ public class Root #region Equality - protected bool Equals(Root other) + protected bool Equals(TestRoot other) { return Equals(ODW, other.ODW); } @@ -40,7 +41,7 @@ public override bool Equals(object obj) if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; - return Equals((Root) obj); + return Equals((TestRoot) obj); } public override int GetHashCode() @@ -51,27 +52,20 @@ public override int GetHashCode() #endregion } - private static IExtendedXmlSerializer GetSerializer() + private static IConfigurationContainer GetSerializer() { - return new ConfigurationContainer() - .UseOptimizedNamespaces() - .EnableImplicitlyDefinedDefaultValues() - - .EnableMemberExceptionHandling() // debug only - - .ApplyAllOdWrapperConfigurations() // the important one for ODWrapper - - .Create(); + return XmlSerializerSupport.GetSerializer() + .EnableImplicitTyping(typeof(TestRoot)); } [Fact] private void Serializer() { - var serializer = GetSerializer(); + var serializer = GetSerializer().Create(); var xmlStr = serializer.Serialize( new XmlWriterSettings() {}, - rootElementGood); + testRootElementGood); testOutputHelper.WriteLine(xmlStr); @@ -81,14 +75,50 @@ private void Serializer() [Fact] private void DeSerialize() { - var serializer = GetSerializer(); - var restoredRoot = serializer.Deserialize(xmlShouldBe); + var serializer = GetSerializer().Create(); + var restoredRoot = serializer.Deserialize(xmlShouldBe); - Assert.Equal(rootElementGood, restoredRoot); + Assert.Equal(testRootElementGood, restoredRoot); } - private readonly Root rootElementGood = new Root(); - - private const string xmlShouldBe = "1<" + "/Key>Z test1<" + "/Value>2" + "Z test3100locat" + "ion1" + "c1" + "200location2c2"; + private readonly TestRoot testRootElementGood = new TestRoot(); + + string xmlShouldBe = "<" + + "DictToSave exs:type=" + + "\"sys:Dictionary[sys" + + ":int,ns2:Label]\">" + + "" + + ""; } } \ No newline at end of file diff --git a/DiztinGUIsh/Program.cs b/DiztinGUIsh/Program.cs index 7f67523b..33b791bd 100644 --- a/DiztinGUIsh/Program.cs +++ b/DiztinGUIsh/Program.cs @@ -1,5 +1,6 @@ using System; using System.Windows.Forms; +using Diz.Core.util; using DiztinGUIsh.window; namespace DiztinGUIsh @@ -12,6 +13,9 @@ static class Program [STAThread] static void Main(string[] args) { + // hack. this needs to go away. register some types for the XML serializer to work. + OdWrapperRegistration.ForceStaticClassRegistration(); + if (Environment.OSVersion.Version.Major >= 6) { SetProcessDPIAware(); From 75dda396406215719cfb2a71c7fa097b43dbcc6a Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Wed, 7 Oct 2020 10:46:12 -0400 Subject: [PATCH 077/136] delete tmp file --- tmp.txt | 2566 ------------------------------------------------------- 1 file changed, 2566 deletions(-) delete mode 100644 tmp.txt diff --git a/tmp.txt b/tmp.txt deleted file mode 100644 index 4720d4b0..00000000 --- a/tmp.txt +++ /dev/null @@ -1,2566 +0,0 @@ -Microsoft (R) Build Engine version 16.7.0+b89cb5fde for .NET Framework -Copyright (C) Microsoft Corporation. All rights reserved. - -C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe -v:diag .\DiztinGUIsh.sln -Building the projects in this solution one at a time. To enable parallel build, please add the "-m" switch. -Build started 9/28/2020 4:45:56 PM. -Environment at start of build: -ALLUSERSPROFILE = C:\ProgramData -APPDATA = C:\Users\Dominic Cerquetti\AppData\Roaming -CommonProgramFiles = C:\Program Files (x86)\Common Files -CommonProgramFiles(x86) = C:\Program Files (x86)\Common Files -CommonProgramW6432 = C:\Program Files\Common Files -COMPUTERNAME = LAPTOP-DOM-CERQ -ComSpec = C:\Windows\system32\cmd.exe -DriverData = C:\Windows\System32\Drivers\DriverData -FPS_BROWSER_APP_PROFILE_STRING = Internet Explorer -FPS_BROWSER_USER_PROFILE_STRING = Default -HOMEDRIVE = C: -HOMEPATH = \Users\Dominic Cerquetti -LOCALAPPDATA = C:\Users\Dominic Cerquetti\AppData\Local -LOGONSERVER = \\LAPTOP-DOM-CERQ -MSBuildLoadMicrosoftTargetsReadOnly = true -NDI_RUNTIME_DIR_V2 = C:\Program Files\NewTek\NDI 4 Runtime\v4 -NDI_RUNTIME_DIR_V3 = C:\Program Files\NewTek\NDI 4 Runtime\v4 -NDI_RUNTIME_DIR_V4 = C:\Program Files\NewTek\NDI 4 Runtime\v4 -NUMBER_OF_PROCESSORS = 8 -OneDrive = C:\Users\Dominic Cerquetti\OneDrive - AA Recycle II LLC -OneDriveCommercial = C:\Users\Dominic Cerquetti\OneDrive - AA Recycle II LLC -OS = Windows_NT -Path = D:\installs\msys64\mingw64\bin;D:\installs\msys64\usr\bin\;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\Microsoft SQL Server\130\Tools\Binn\;C:\Program Files\Perforce\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR;C:\Program Files\PuTTY\;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\;C:\Program Files\Git\cmd;C:\Program Files\nodejs\;C:\Program Files\dotnet\;C:\Users\Dominic Cerquetti\AppData\Local\Microsoft\WindowsApps;C:\Users\Dominic Cerquetti\.dotnet\tools;C:\Users\Dominic Cerquetti\.platformio\penv\Scripts\;C:\Users\Dominic Cerquetti\AppData\Local\Programs\Python\Python38-32\python.exe;C:\Users\Dominic Cerquetti\AppData\Local\Programs\Microsoft VS Code\bin;C:\Program Files (x86)\Nmap;C:\Users\Dominic Cerquetti\AppData\Roaming\npm;C:\Users\Dominic Cerquetti\.dotnet\tools;D:\installs\msys64\mingw64\bin; -PATHEXT = .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC -PROCESSOR_ARCHITECTURE = x86 -PROCESSOR_ARCHITEW6432 = AMD64 -PROCESSOR_IDENTIFIER = Intel64 Family 6 Model 158 Stepping 9, GenuineIntel -PROCESSOR_LEVEL = 6 -PROCESSOR_REVISION = 9e09 -ProgramData = C:\ProgramData -ProgramFiles = C:\Program Files (x86) -ProgramFiles(x86) = C:\Program Files (x86) -ProgramW6432 = C:\Program Files -PROMPT = $P$G -PSModulePath = C:\Program Files (x86)\WindowsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules;C:\Program Files (x86)\AutoIt3\AutoItX -PUBLIC = C:\Users\Public -SESSIONNAME = Console -SystemDrive = C: -SystemRoot = C:\Windows -TEMP = C:\Users\DOMINI~1\AppData\Local\Temp -TMP = C:\Users\DOMINI~1\AppData\Local\Temp -USERDOMAIN = LAPTOP-DOM-CERQ -USERDOMAIN_ROAMINGPROFILE = LAPTOP-DOM-CERQ -USERNAME = Dominic Cerquetti -USERPROFILE = C:\Users\Dominic Cerquetti -VBOX_MSI_INSTALL_PATH = C:\Program Files\Oracle\VirtualBox\ -windir = C:\Windows -WWISEROOT = C:\Program Files (x86)\Audiokinetic\Wwise 2019.2.4.7329 -WWISESDK = C:\Program Files (x86)\Audiokinetic\Wwise 2019.2.4.7329\SDK - -Process = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe" -MSBuild executable path = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe" -Command line arguments = ""C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe" -v:diag " -Current directory = "d:\projects\cthack\src\diztinguish" -MSBuild version = "16.7.0+b89cb5fde" -Project "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln" on node 1 (default targets). -Initial Properties: -_DirectorySolutionPropsBasePath = -_DirectorySolutionPropsFile = Directory.Solution.props -_DirectorySolutionTargetsBasePath = -_DirectorySolutionTargetsFile = Directory.Solution.targets -_GenerateRestoreGraphProjectEntryInputProperties = - ExcludeRestorePackageImports=true; - _RestoreSolutionFileUsed=true; - SolutionDir=d:\projects\cthack\src\diztinguish\; - SolutionName=DiztinGUIsh; - SolutionFileName=DiztinGUIsh.sln; - SolutionPath=d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln; - SolutionExt=.sln; - -_RestoreSolutionFileUsed = true -ALLUSERSPROFILE = C:\ProgramData -AndroidTargetsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\MDD\Android\V150\ -APPDATA = C:\Users\Dominic Cerquetti\AppData\Roaming -AspNetConfiguration = Debug -CommonProgramFiles = C:\Program Files (x86)\Common Files -CommonProgramW6432 = C:\Program Files\Common Files -COMPUTERNAME = LAPTOP-DOM-CERQ -ComSpec = C:\Windows\system32\cmd.exe -Configuration = Debug -CurrentSolutionConfigurationContents = - Debug|AnyCPU - -DriverData = C:\Windows\System32\Drivers\DriverData -FPS_BROWSER_APP_PROFILE_STRING = Internet Explorer -FPS_BROWSER_USER_PROFILE_STRING = Default -FrameworkSDKRoot = C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\ -HideWarningsAndErrors = false -HOMEDRIVE = C: -HOMEPATH = \Users\Dominic Cerquetti -iOSTargetsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\MDD\iOS\V150\ -IsRestoreTargetsFileLoaded = true -LOCALAPPDATA = C:\Users\Dominic Cerquetti\AppData\Local -LOGONSERVER = \\LAPTOP-DOM-CERQ -MSBuildAllProjects = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\SolutionFile\ImportAfter\Microsoft.NuGet.Solution.ImportAfter.targets;;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.targets -MSBuildAssemblyVersion = 16.0 -MSBuildBinPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin -MSBuildExtensionsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild -MSBuildExtensionsPath32 = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild -MSBuildExtensionsPath64 = C:\Program Files\MSBuild -MSBuildFrameworkToolsPath = C:\Windows\Microsoft.NET\Framework\v4.0.30319\ -MSBuildFrameworkToolsPath32 = C:\Windows\Microsoft.NET\Framework\v4.0.30319\ -MSBuildFrameworkToolsPath64 = C:\Windows\Microsoft.NET\Framework64\v4.0.30319\ -MSBuildFrameworkToolsRoot = C:\Windows\Microsoft.NET\Framework\ -MSBuildLoadMicrosoftTargetsReadOnly = true -MSBuildNodeCount = 1 -MSBuildProgramFiles32 = C:\Program Files (x86) -MSBuildProjectDefaultTargets = Build -MSBuildProjectDirectory = d:\projects\cthack\src\diztinguish -MSBuildProjectDirectoryNoRoot = projects\cthack\src\diztinguish -MSBuildProjectExtension = .metaproj -MSBuildProjectFile = DiztinGUIsh.sln.metaproj -MSBuildProjectFullPath = d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln.metaproj -MSBuildProjectName = DiztinGUIsh.sln -MSBuildRuntimeType = Full -MSBuildRuntimeVersion = 4.0.30319 -MSBuildSDKsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Sdks -MSBuildStartupDirectory = d:\projects\cthack\src\diztinguish -MSBuildToolsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin -MSBuildToolsPath32 = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin -MSBuildToolsPath64 = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\amd64 -MSBuildToolsRoot = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild -MSBuildToolsVersion = Current -MSBuildUserExtensionsPath = C:\Users\Dominic Cerquetti\AppData\Local\Microsoft\MSBuild -MSBuildVersion = 16.7.0 -NDI_RUNTIME_DIR_V2 = C:\Program Files\NewTek\NDI 4 Runtime\v4 -NDI_RUNTIME_DIR_V3 = C:\Program Files\NewTek\NDI 4 Runtime\v4 -NDI_RUNTIME_DIR_V4 = C:\Program Files\NewTek\NDI 4 Runtime\v4 -NuGetInteractive = -NuGetRestoreTargets = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\..\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.targets -NUMBER_OF_PROCESSORS = 8 -OneDrive = C:\Users\Dominic Cerquetti\OneDrive - AA Recycle II LLC -OneDriveCommercial = C:\Users\Dominic Cerquetti\OneDrive - AA Recycle II LLC -OS = Windows_NT -PackageDownloadSupported = true -Path = D:\installs\msys64\mingw64\bin;D:\installs\msys64\usr\bin\;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\Microsoft SQL Server\130\Tools\Binn\;C:\Program Files\Perforce\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR;C:\Program Files\PuTTY\;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\;C:\Program Files\Git\cmd;C:\Program Files\nodejs\;C:\Program Files\dotnet\;C:\Users\Dominic Cerquetti\AppData\Local\Microsoft\WindowsApps;C:\Users\Dominic Cerquetti\.dotnet\tools;C:\Users\Dominic Cerquetti\.platformio\penv\Scripts\;C:\Users\Dominic Cerquetti\AppData\Local\Programs\Python\Python38-32\python.exe;C:\Users\Dominic Cerquetti\AppData\Local\Programs\Microsoft VS Code\bin;C:\Program Files (x86)\Nmap;C:\Users\Dominic Cerquetti\AppData\Roaming\npm;C:\Users\Dominic Cerquetti\.dotnet\tools;D:\installs\msys64\mingw64\bin; -PATHEXT = .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC -Platform = Any CPU -PROCESSOR_ARCHITECTURE = x86 -PROCESSOR_ARCHITEW6432 = AMD64 -PROCESSOR_IDENTIFIER = Intel64 Family 6 Model 158 Stepping 9, GenuineIntel -PROCESSOR_LEVEL = 6 -PROCESSOR_REVISION = 9e09 -ProgramData = C:\ProgramData -ProgramFiles = C:\Program Files (x86) -ProgramW6432 = C:\Program Files -PROMPT = $P$G -PSModulePath = C:\Program Files (x86)\WindowsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules;C:\Program Files (x86)\AutoIt3\AutoItX -PUBLIC = C:\Users\Public -RestoreBuildInParallel = true -RestoreContinueOnError = WarnAndContinue -RestoreRecursive = true -RestoreTaskAssemblyFile = NuGet.Build.Tasks.dll -RestoreUseSkipNonexistentTargets = true -RoslynTargetsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Roslyn -SDK35ToolsPath = C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\ -SDK40ToolsPath = C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\ -SESSIONNAME = Console -SolutionDir = d:\projects\cthack\src\diztinguish\ -SolutionExt = .sln -SolutionFileName = DiztinGUIsh.sln -SolutionName = DiztinGUIsh -SolutionPath = d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln -SystemDrive = C: -SystemRoot = C:\Windows -TargetFrameworkVersion = v4.0 -TEMP = C:\Users\DOMINI~1\AppData\Local\Temp -TMP = C:\Users\DOMINI~1\AppData\Local\Temp -USERDOMAIN = LAPTOP-DOM-CERQ -USERDOMAIN_ROAMINGPROFILE = LAPTOP-DOM-CERQ -USERNAME = Dominic Cerquetti -USERPROFILE = C:\Users\Dominic Cerquetti -ValidateRuntimeIdentifierCompatibility = false -VBOX_MSI_INSTALL_PATH = C:\Program Files\Oracle\VirtualBox\ -VCTargetsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VC\v160\ -VCTargetsPath10 = C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\ -VCTargetsPath11 = C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V110\ -VCTargetsPath12 = C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\ -VCTargetsPath14 = C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\ -VisualStudioVersion = 16.0 -VsInstallRoot = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community -windir = C:\Windows -WindowsSDK80Path = -WWISEROOT = C:\Program Files (x86)\Audiokinetic\Wwise 2019.2.4.7329 -WWISESDK = C:\Program Files (x86)\Audiokinetic\Wwise 2019.2.4.7329\SDK - -Initial Items: -ProjectReference - d:\projects\cthack\src\diztinguish\DiztinGUIsh\DiztinGUIsh.csproj - ToolsVersion = - SkipNonexistentProjects = False - AdditionalProperties = Configuration=Debug; Platform=AnyCPU - Configuration = Debug - Platform = AnyCPU -SolutionConfiguration - Debug|Any CPU - Configuration = Debug - Platform = Any CPU - Content = - Debug|AnyCPU - - Release|Any CPU - Configuration = Release - Platform = Any CPU - Content = - Release|AnyCPU - - -Building with tools version "Current". -Target "ValidateSolutionConfiguration: (TargetId:2)" in file "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln.metaproj" from project "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln" (entry point): -Task "Error" skipped, due to false condition; (('$(CurrentSolutionConfigurationContents)' == '') and ('$(SkipInvalidConfigurations)' != 'true')) was evaluated as ((' - Debug|AnyCPU -' == '') and ('' != 'true')). -Task "Warning" skipped, due to false condition; (('$(CurrentSolutionConfigurationContents)' == '') and ('$(SkipInvalidConfigurations)' == 'true')) was evaluated as ((' - Debug|AnyCPU -' == '') and ('' == 'true')). -Using "Message" task from assembly "Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a". -Task "Message" (TaskId:2) - Task Parameter:Text=Building solution configuration "Debug|Any CPU". (TaskId:2) - Building solution configuration "Debug|Any CPU". (TaskId:2) -Done executing task "Message". (TaskId:2) -Done building target "ValidateSolutionConfiguration" in project "DiztinGUIsh.sln".: (TargetId:2) -Target "ValidateToolsVersions: (TargetId:3)" in file "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln.metaproj" from project "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln" (entry point): -Task "Error" skipped, due to false condition; ('$(MSBuildToolsVersion)' == '2.0' and ('$(ProjectToolsVersion)' != '2.0' and '$(ProjectToolsVersion)' != '')) was evaluated as ('Current' == '2.0' and ('' != '2.0' and '' != '')). -Done building target "ValidateToolsVersions" in project "DiztinGUIsh.sln".: (TargetId:3) -Target "ValidateProjects: (TargetId:4)" in file "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln.metaproj" from project "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln" (entry point): -Done building target "ValidateProjects" in project "DiztinGUIsh.sln".: (TargetId:4) -Target "Build: (TargetId:5)" in file "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln.metaproj" from project "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln" (entry point): -Using "MSBuild" task from assembly "Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a". -Task "MSBuild" (TaskId:3) - Task Parameter: - Projects= - d:\projects\cthack\src\diztinguish\DiztinGUIsh\DiztinGUIsh.csproj - AdditionalProperties=Configuration=Debug; Platform=AnyCPU - Configuration=Debug - Platform=AnyCPU - SkipNonexistentProjects=False - ToolsVersion= (TaskId:3) - Task Parameter:BuildInParallel=True (TaskId:3) - Task Parameter: - Properties= - BuildingSolutionFile=true - CurrentSolutionConfigurationContents= - Debug|AnyCPU - - SolutionDir=d:\projects\cthack\src\diztinguish\ - SolutionExt=.sln - SolutionFileName=DiztinGUIsh.sln - SolutionName=DiztinGUIsh - SolutionPath=d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln (TaskId:3) - Task Parameter:SkipNonexistentProjects=False (TaskId:3) - Global Properties: (TaskId:3) - BuildingSolutionFile=true (TaskId:3) - CurrentSolutionConfigurationContents= - Debug|AnyCPU - (TaskId:3) - SolutionDir=d:\projects\cthack\src\diztinguish\ (TaskId:3) - SolutionExt=.sln (TaskId:3) - SolutionFileName=DiztinGUIsh.sln (TaskId:3) - SolutionName=DiztinGUIsh (TaskId:3) - SolutionPath=d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln (TaskId:3) - Additional Properties for project "d:\projects\cthack\src\diztinguish\DiztinGUIsh\DiztinGUIsh.csproj": (TaskId:3) - Configuration=Debug (TaskId:3) - Platform=AnyCPU (TaskId:3) -Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild -Trying to import C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\$(MSBuildToolsVersion)\Microsoft.Common.props using extensions path C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild -Property reassignment: $(MSBuildProjectExtensionsPath)="d:\projects\cthack\src\diztinguish\DiztinGUIsh\obj\" (previous value: "obj\") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Microsoft.Common.props (56,5) -Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild -Trying to import C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\$(MSBuildToolsVersion)\Imports\Microsoft.Common.props\ImportBefore\* using extensions path C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild -Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild -The "Configuration" property is a global property, and cannot be modified. -The "Platform" property is a global property, and cannot be modified. -Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild -Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild -The "Configuration" property is a global property, and cannot be modified. -The "Platform" property is a global property, and cannot be modified. -Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild -Property reassignment: $(DefineCommonItemSchemas)="false" (previous value: "true") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\Managed\Microsoft.Managed.DesignTime.targets (12,5) -Property reassignment: $(DefineCommonCapabilities)="false" (previous value: "true") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\Managed\Microsoft.Managed.DesignTime.targets (13,5) -Property reassignment: $(DefineCommonReferenceSchemas)="false" (previous value: "true") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\Managed\Microsoft.Managed.DesignTime.targets (14,5) -Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild -Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild -Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild -Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild -The "Configuration" property is a global property, and cannot be modified. -The "Platform" property is a global property, and cannot be modified. -Property reassignment: $(_DebugSymbolsProduced)="true" (previous value: "false") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets (149,5) -Property reassignment: $(_DocumentationFileProduced)="false" (previous value: "true") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets (158,5) -The "SolutionName" property is a global property, and cannot be modified. -The "SolutionFileName" property is a global property, and cannot be modified. -The "SolutionPath" property is a global property, and cannot be modified. -The "SolutionDir" property is a global property, and cannot be modified. -The "SolutionExt" property is a global property, and cannot be modified. -Property reassignment: $(_DeploymentUrl)="publish\" (previous value: "") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets (432,5) -Property reassignment: $(_DeploymentUrl)="publish\DiztinGUIsh.application" (previous value: "publish\") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets (434,5) -Property reassignment: $(_DeploymentUrl)="" (previous value: "publish\DiztinGUIsh.application") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets (441,5) -Property reassignment: $(ProcessorArchitecture)="msil" (previous value: "AnyCPU") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets (473,5) -Property reassignment: $(DelaySign)="" (previous value: "false") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets (527,5) -Property reassignment: $(_SGenGenerateSerializationAssembliesConfig)="Auto" (previous value: "") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets (3491,5) -Property reassignment: $(_SGenGenerateSerializationAssembliesConfig)="Off" (previous value: "Auto") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets (3492,5) -Property reassignment: $(PrepareForRunDependsOn)=" - CopyFilesToOutputDirectory - ;RunCodeAnalysis" (previous value: " - CopyFilesToOutputDirectory - ") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\v16.0\CodeAnalysis\Microsoft.CodeAnalysis.targets (199,9) -Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild -Property reassignment: $(ResolveReferencesDependsOn)=" - - BeforeResolveReferences; - AssignProjectConfiguration; - ResolveProjectReferences; - FindInvalidProjectReferences; - ResolveNativeReferences; - ResolveAssemblyReferences; - GenerateBindingRedirects; - ResolveComReferences; - AfterResolveReferences - ; - ImplicitlyExpandDesignTimeFacades - " (previous value: " - BeforeResolveReferences; - AssignProjectConfiguration; - ResolveProjectReferences; - FindInvalidProjectReferences; - ResolveNativeReferences; - ResolveAssemblyReferences; - GenerateBindingRedirects; - ResolveComReferences; - AfterResolveReferences - ") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.NETFramework.CurrentVersion.targets (75,5) -Property reassignment: $(PrepareResourceNamesDependsOn)=" - AssignWinFXEmbeddedResource; - - AssignTargetPaths; - SplitResourcesByCulture; - CreateManifestResourceNames; - CreateCustomManifestResourceNames - - " (previous value: " - AssignTargetPaths; - SplitResourcesByCulture; - CreateManifestResourceNames; - CreateCustomManifestResourceNames - ") at C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.WinFx.targets (97,7) -Property reassignment: $(PrepareResourcesDependsOn)=" - MarkupCompilePass1; - AfterMarkupCompilePass1; - MarkupCompilePass2ForMainAssembly; - FileClassification; - MainResourcesGeneration; - - ; - PrepareResourceNames; - ResGen; - CompileLicxFiles - - " (previous value: " - ; - PrepareResourceNames; - ResGen; - CompileLicxFiles - ") at C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.WinFx.targets (108,7) -Property reassignment: $(CompileDependsOn)=" - - ResolveReferences; - ResolveKeySource; - SetWin32ManifestProperties; - FindReferenceAssembliesForReferences; - _GenerateCompileInputs; - BeforeCompile; - _TimeStampBeforeCompile; - _GenerateCompileDependencyCache; - CoreCompile; - _TimeStampAfterCompile; - AfterCompile; - ; - _AfterCompileWinFXInternal - " (previous value: " - ResolveReferences; - ResolveKeySource; - SetWin32ManifestProperties; - FindReferenceAssembliesForReferences; - _GenerateCompileInputs; - BeforeCompile; - _TimeStampBeforeCompile; - _GenerateCompileDependencyCache; - CoreCompile; - _TimeStampAfterCompile; - AfterCompile; - ") at C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.WinFx.targets (184,5) -Property reassignment: $(PublishBuildDependsOn)=" - BuildOnlySettings; - PrepareForBuild; - ResolveReferences; - PrepareResources; - ResolveKeySource; - PrepareResourcesForSatelliteAssemblies; - GenerateSerializationAssemblies; - CreateSatelliteAssemblies; - " (previous value: " - BuildOnlySettings; - PrepareForBuild; - ResolveReferences; - PrepareResources; - ResolveKeySource; - GenerateSerializationAssemblies; - CreateSatelliteAssemblies; - ") at C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.WinFx.targets (813,9) -Property reassignment: $(BuildDependsOn)=" - EntityDeploy; - - BeforeBuild; - CoreBuild; - AfterBuild - - " (previous value: " - BeforeBuild; - CoreBuild; - AfterBuild - ") at C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Data.Entity.targets (35,5) -Property reassignment: $(CleanDependsOn)=" - - BeforeClean; - UnmanagedUnregistration; - CoreClean; - CleanReferencedProjects; - CleanPublishFolder; - AfterClean - ; - EntityClean; - " (previous value: " - BeforeClean; - UnmanagedUnregistration; - CoreClean; - CleanReferencedProjects; - CleanPublishFolder; - AfterClean - ") at C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Data.Entity.targets (42,5) -Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild -Property reassignment: $(PrepareResourcesDependsOn)=" - XamlMarkupCompilePass1; - XamlMarkupCompilePass2; - - MarkupCompilePass1; - AfterMarkupCompilePass1; - MarkupCompilePass2ForMainAssembly; - FileClassification; - MainResourcesGeneration; - - ; - PrepareResourceNames; - ResGen; - CompileLicxFiles - - - " (previous value: " - MarkupCompilePass1; - AfterMarkupCompilePass1; - MarkupCompilePass2ForMainAssembly; - FileClassification; - MainResourcesGeneration; - - ; - PrepareResourceNames; - ResGen; - CompileLicxFiles - - ") at C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Xaml.targets (35,5) -Property reassignment: $(PrepareResourcesDependsOn)=" - ValidationExtension; - ExpressionBuildExtension; - - XamlMarkupCompilePass1; - XamlMarkupCompilePass2; - - MarkupCompilePass1; - AfterMarkupCompilePass1; - MarkupCompilePass2ForMainAssembly; - FileClassification; - MainResourcesGeneration; - - ; - PrepareResourceNames; - ResGen; - CompileLicxFiles - - - - " (previous value: " - XamlMarkupCompilePass1; - XamlMarkupCompilePass2; - - MarkupCompilePass1; - AfterMarkupCompilePass1; - MarkupCompilePass2ForMainAssembly; - FileClassification; - MainResourcesGeneration; - - ; - PrepareResourceNames; - ResGen; - CompileLicxFiles - - - ") at C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.WorkflowBuildExtensions.targets (16,5) -Property reassignment: $(ResolveReferencesDependsOn)=" - - - BeforeResolveReferences; - AssignProjectConfiguration; - ResolveProjectReferences; - FindInvalidProjectReferences; - ResolveNativeReferences; - ResolveAssemblyReferences; - GenerateBindingRedirects; - ResolveComReferences; - AfterResolveReferences - ; - ImplicitlyExpandDesignTimeFacades - ; - ResolveTestReferences - " (previous value: " - - BeforeResolveReferences; - AssignProjectConfiguration; - ResolveProjectReferences; - FindInvalidProjectReferences; - ResolveNativeReferences; - ResolveAssemblyReferences; - GenerateBindingRedirects; - ResolveComReferences; - AfterResolveReferences - ; - ImplicitlyExpandDesignTimeFacades - ") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\v16.0\TeamTest\Microsoft.TeamTest.targets (4,5) -Property reassignment: $(MSBuildAllProjects)=";C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Xaml.targets;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.targets" (previous value: ";C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Xaml.targets") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.targets (45,5) -Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild -Trying to import C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\$(MSBuildToolsVersion)\Microsoft.Common.targets\ImportAfter\* using extensions path C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild -Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild -Trying to import C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Sdks\Microsoft.Docker.Sdk\build\Microsoft.Docker.targets using extensions path C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild -Property reassignment: $(MSBuildAllProjects)=";C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Xaml.targets;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.targets;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\NuGet\16.0\Microsoft.NuGet.targets" (previous value: ";C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Xaml.targets;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.targets") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\NuGet\16.0\Microsoft.NuGet.targets (67,5) -Property reassignment: $(ResolveAssemblyReferencesDependsOn)=" - ResolveProjectReferences; - FindInvalidProjectReferences; - GetFrameworkPaths; - GetReferenceAssemblyPaths; - PrepareForBuild; - ResolveSDKReferences; - ExpandSDKReferences; - ;ResolveNuGetPackageAssets" (previous value: " - ResolveProjectReferences; - FindInvalidProjectReferences; - GetFrameworkPaths; - GetReferenceAssemblyPaths; - PrepareForBuild; - ResolveSDKReferences; - ExpandSDKReferences; - ") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\NuGet\16.0\Microsoft.NuGet.targets (173,5) -Property reassignment: $(PrepareResourcesDependsOn)="ResolveNuGetPackageAssets; - ValidationExtension; - ExpressionBuildExtension; - - XamlMarkupCompilePass1; - XamlMarkupCompilePass2; - - MarkupCompilePass1; - AfterMarkupCompilePass1; - MarkupCompilePass2ForMainAssembly; - FileClassification; - MainResourcesGeneration; - - ; - PrepareResourceNames; - ResGen; - CompileLicxFiles - - - - " (previous value: " - ValidationExtension; - ExpressionBuildExtension; - - XamlMarkupCompilePass1; - XamlMarkupCompilePass2; - - MarkupCompilePass1; - AfterMarkupCompilePass1; - MarkupCompilePass2ForMainAssembly; - FileClassification; - MainResourcesGeneration; - - ; - PrepareResourceNames; - ResGen; - CompileLicxFiles - - - - ") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\NuGet\16.0\Microsoft.NuGet.targets (174,5) -Property reassignment: $(_HandlePackageFileConflictsAfter)="ResolveNuGetPackageAssets;ResolveNuGetPackageAssetsNonAOT" (previous value: "ResolveNuGetPackageAssets") at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\NuGet\16.0\Microsoft.NuGet.targets (255,5) -Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild -Search paths being used for $(MSBuildExtensionsPath) are C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild;$(MSBuildProgramFiles32)\MSBuild -Property reassignment: $(CoreCompileDependsOn)=" - GitInfo; - GitVersion; - GitThisAssembly; - GitInfoReport; - ;_ComputeNonExistentFileProperty;ResolveCodeAnalysisRuleSet - " (previous value: ";_ComputeNonExistentFileProperty;ResolveCodeAnalysisRuleSet") at d:\projects\cthack\src\diztinguish\packages\GitInfo.2.1.1\build\GitInfo.targets (125,3) -Overriding target "ResolveFrameworkReferences" in project "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\Managed\Microsoft.Managed.DesignTime.targets" with target "ResolveFrameworkReferences" from project "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets". -Overriding target "GetFrameworkPaths" in project "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets" with target "GetFrameworkPaths" from project "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.NETFramework.CurrentVersion.targets". -Overriding target "SatelliteDllsProjectOutputGroup" in project "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets" with target "SatelliteDllsProjectOutputGroup" from project "C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.WinFx.targets". -Overriding target "GenerateCompiledExpressionsTempFile" in project "C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.WorkflowBuildExtensions.targets" with target "GenerateCompiledExpressionsTempFile" from project "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.WorkflowBuildExtensions.targets". -Overriding target "CollectPackageReferences" in project "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\Managed\Microsoft.Managed.DesignTime.targets" with target "CollectPackageReferences" from project "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.targets". -The target "ClCompile" listed in an AfterTargets attribute at "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\v16.0\CodeAnalysis\Microsoft.CodeAnalysis.targets (478,11)" does not exist in the project, and will be ignored. -Project "d:\projects\cthack\src\diztinguish\DiztinGUIsh.sln" (1) is building "d:\projects\cthack\src\diztinguish\DiztinGUIsh\DiztinGUIsh.csproj" (2) on node 1 (default targets). -Initial Properties: -_AfterCompileWinFXInternalDependsOn = - PrepareResourcesForSatelliteAssemblies; - MergeLocalizationDirectives; - AfterCompileWinFX - -_CommitDateFormat = %%cI -_CompileTargetNameForLocalType = _CompileTemporaryAssembly -_DebugSymbolsProduced = true -_DeploymentApplicationManifestIdentity = DiztinGUIsh.exe -_DeploymentBuiltUpdateInterval = 0 -_DeploymentBuiltUpdateIntervalUnits = Days -_DeploymentDeployManifestIdentity = DiztinGUIsh.application -_DeploymentFileMappingExtension = .deploy -_DeploymentPublishableProjectDefault = true -_DeploymentTargetApplicationManifestFileName = DiztinGUIsh.exe.manifest -_DeploymentUrl = -_DirectoryBuildPropsBasePath = -_DirectoryBuildPropsFile = Directory.Build.props -_DirectoryBuildTargetsBasePath = -_DirectoryBuildTargetsFile = Directory.Build.targets -_DirectoryPackagesPropsBasePath = -_DirectoryPackagesPropsFile = Directory.Packages.props -_DocumentationFileProduced = false -_GenerateBindingRedirectsIntermediateAppConfig = obj\Debug\DiztinGUIsh.exe.config -_GenerateRestoreGraphProjectEntryInputProperties = ExcludeRestorePackageImports=true -_GetChildProjectCopyToOutputDirectoryItems = true -_GitInfoFile = obj\Debug\GitInfo.cache -_HandlePackageFileConflictsAfter = ResolveNuGetPackageAssets;ResolveNuGetPackageAssetsNonAOT -_HandlePackageFileConflictsBefore = ResolveAssemblyReferences -_InitialBaseIntermediateOutputPath = obj\ -_InitialMSBuildProjectExtensionsPath = d:\projects\cthack\src\diztinguish\DiztinGUIsh\obj\ -_LongShaFormat = %%H -_MaxSupportedLangVersion = 7.3 -_NuGetRuntimeIdentifierWithoutAot = win -_OriginalConfiguration = Debug -_OriginalPlatform = AnyCPU -_ProjectDefaultTargets = Build -_RecursiveTargetForContentCopying = GetCopyToOutputDirectoryItems -_RequireMCPass2ForMainAssembly = false -_RequireMCPass2ForSatelliteAssemblyOnly = false -_ResolveReferenceDependencies = false -_ResourceNameInMainAssembly = DiztinGUIsh.g.resources -_SGenDllCreated = false -_SGenDllName = DiztinGUIsh.XmlSerializers.dll -_SGenGenerateSerializationAssembliesConfig = Off -_ShortShaFormat = %%h -_TargetFrameworkVersionWithoutV = 4.8 -_TargetsThatPrepareProjectReferences = _SplitProjectReferencesByFileExistence -AddAdditionalExplicitAssemblyReferences = true -AddAppConfigToBuildOutputs = true -AddItemTemplatesGuid = {FAE04EC0-301F-11d3-BF4B-00C04F79EFBC} -AdditionalExplicitAssemblyReferences = System.Core; -AllowedReferenceAssemblyFileExtensions = - .winmd; - .dll; - .exe - -AllowedReferenceRelatedFileExtensions = - .pdb; - .xml; - .pri; - .dll.config; - .exe.config - -ALLUSERSPROFILE = C:\ProgramData -AlwaysCompileMarkupFilesInSeparateDomain = true -AlwaysUseNumericalSuffixInItemNames = true -AndroidTargetsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\MDD\Android\V150\ -APPDATA = C:\Users\Dominic Cerquetti\AppData\Roaming -AppDesignerFolder = Properties -AppDesignerFolderContentsVisibleOnlyInShowAllFiles = false -ApplicationIcon = diz-4.ico -ApplicationRevision = 0 -ApplicationVersion = 1.0.0.* -AssemblyFoldersConfigFile = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\AssemblyFolders.config -AssemblyFoldersConfigFileSearchPath = {AssemblyFoldersFromConfig:C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\AssemblyFolders.config,v4.8}; -AssemblyFoldersSuffix = AssemblyFoldersEx -AssemblyName = DiztinGUIsh -AssemblySearchPaths = - {CandidateAssemblyFiles}; - ; - {HintPathFromItem}; - {TargetFrameworkDirectory}; - {AssemblyFoldersFromConfig:C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\AssemblyFolders.config,v4.8}; - {Registry:Software\Microsoft\.NETFramework,v4.8,AssemblyFoldersEx}; - {AssemblyFolders}; - {GAC}; - {RawFileName}; - bin\Debug\ - -AssignTargetPathsDependsOn = -AutoGenerateBindingRedirects = true -AutoUnifyAssemblyReferences = true -AvailablePlatforms = Any CPU,x86,x64 -BaseIntermediateOutputPath = obj\ -BaseNuGetRuntimeIdentifier = win -BootstrapperEnabled = true -BootstrapperUrlHistory = -BuildCompileAction = Build -BuildDependsOn = - EntityDeploy; - - BeforeBuild; - CoreBuild; - AfterBuild - - -BuildGenerateSourcesAction = Build -BuildingProject = false -BuildingSolutionFile = true -BuildInParallel = true -BuildLinkAction = Build -BuildProjectReferences = true -BuildSystem = MSBuild -BuildTaskAssembly = PresentationBuildTasks, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 -BuiltProjectOutputGroupDependenciesDependsOn = - ; - - ; - BuildOnlySettings; - PrepareForBuild; - AssignTargetPaths; - ResolveReferences - - -BuiltProjectOutputGroupDependsOn = PrepareForBuild -CleanDependsOn = - - BeforeClean; - UnmanagedUnregistration; - CoreClean; - CleanReferencedProjects; - CleanPublishFolder; - AfterClean - ; - EntityClean; - -CleanFile = DiztinGUIsh.csproj.FileListAbsolute.txt -CmdUIContextGuid = {FAE04EC1-301F-11d3-BF4B-00C04F79EFBC} -CodeAnalysisApplyLogFileXsl = false -CodeAnalysisFailOnMissingRules = false -CodeAnalysisForceOutput = true -CodeAnalysisGenerateSuccessFile = true -CodeAnalysisIgnoreGeneratedCode = true -CodeAnalysisIgnoreInvalidTargets = true -CodeAnalysisIgnoreMissingIndirectReferences = false -CodeAnalysisInputAssembly = bin\Debug\DiztinGUIsh.exe -CodeAnalysisLogFile = bin\Debug\DiztinGUIsh.exe.CodeAnalysisLog.xml -CodeAnalysisModuleSuppressionsFile = GlobalSuppressions.cs -CodeAnalysisOutputToConsole = false -CodeAnalysisOverrideRuleVisibilities = false -CodeAnalysisPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Team Tools\Static Analysis Tools\FxCop\ -CodeAnalysisQuiet = false -CodeAnalysisRuleDirectories = ;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Team Tools\Static Analysis Tools\FxCop\\Rules -CodeAnalysisRuleSet = MinimumRecommendedRules.ruleset -CodeAnalysisRuleSetDirectories = ;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Team Tools\Static Analysis Tools\\Rule Sets -CodeAnalysisSaveMessagesToReport = Active -CodeAnalysisSearchGlobalAssemblyCache = true -CodeAnalysisStaticAnalysisDirectory = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Team Tools\Static Analysis Tools\ -CodeAnalysisSucceededFile = bin\Debug\DiztinGUIsh.exe.lastcodeanalysissucceeded -CodeAnalysisSummary = false -CodeAnalysisTargets = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\v16.0\CodeAnalysis\Microsoft.CodeAnalysis.targets -CodeAnalysisTimeout = 120 -CodeAnalysisTreatWarningsAsErrors = false -CodeAnalysisUpdateProject = false -CodeAnalysisUseTypeNameInSuppression = true -CodeAnalysisVerbose = false -CommonOutputGroupsDependsOn = - ; - BuildOnlySettings; - PrepareForBuild; - AssignTargetPaths; - ResolveReferences - -CommonProgramFiles = C:\Program Files (x86)\Common Files -CommonProgramW6432 = C:\Program Files\Common Files -CommonTargetsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets -CommonXamlResourcesDirectory = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\\ -CompileDependsOn = - - ResolveReferences; - ResolveKeySource; - SetWin32ManifestProperties; - FindReferenceAssembliesForReferences; - _GenerateCompileInputs; - BeforeCompile; - _TimeStampBeforeCompile; - _GenerateCompileDependencyCache; - CoreCompile; - _TimeStampAfterCompile; - AfterCompile; - ; - _AfterCompileWinFXInternal - -CompileLicxFilesDependsOn = -CompileTargetNameForTemporaryAssembly = CompileTemporaryAssembly -ComputeIntermediateSatelliteAssembliesDependsOn = - CreateManifestResourceNames - -COMPUTERNAME = LAPTOP-DOM-CERQ -ComReferenceExecuteAsTool = false -ComReferenceNoClassMembers = false -ComSpec = C:\Windows\system32\cmd.exe -Configuration = Debug -ConfigurationName = Debug -ConsiderPlatformAsProcessorArchitecture = true -ContentFilesProjectOutputGroupDependsOn = PrepareForBuild;AssignTargetPaths -ContinueOnError = false -CopyNuGetImplementations = true -CoreBuildDependsOn = - BuildOnlySettings; - PrepareForBuild; - PreBuildEvent; - ResolveReferences; - PrepareResources; - ResolveKeySource; - Compile; - ExportWindowsMDFile; - UnmanagedUnregistration; - GenerateSerializationAssemblies; - CreateSatelliteAssemblies; - GenerateManifests; - GetTargetPath; - PrepareForRun; - UnmanagedRegistration; - IncrementalClean; - PostBuildEvent - -CoreCleanDependsOn = -CoreCompileDependsOn = - GitInfo; - GitVersion; - GitThisAssembly; - GitInfoReport; - ;_ComputeNonExistentFileProperty;ResolveCodeAnalysisRuleSet - -CoreResGenDependsOn = FindReferenceAssembliesForReferences -CreateCustomManifestResourceNamesDependsOn = -CreateHardLinksForCopyAdditionalFilesIfPossible = false -CreateManifestResourceNamesDependsOn = -CreateSatelliteAssembliesDependsOn = - _GenerateSatelliteAssemblyInputs; - ComputeIntermediateSatelliteAssemblies; - GenerateSatelliteAssemblies - -CreateSymbolicLinksForCopyAdditionalFilesIfPossible = false -CSharpCoreTargetsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Roslyn\Microsoft.CSharp.Core.targets -CSharpDesignTimeTargetsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\Managed\Microsoft.CSharp.DesignTime.targets -CSharpTargetsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.CSharp.CurrentVersion.targets -CurrentSolutionConfigurationContents = - Debug|AnyCPU - -CustomAfterMicrosoftCommonProps = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\vCurrent\Custom.After.Microsoft.Common.props -CustomAfterMicrosoftCommonTargets = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\vCurrent\Custom.After.Microsoft.Common.targets -CustomAfterMicrosoftCSharpTargets = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\vCurrent\Custom.After.Microsoft.CSharp.targets -CustomBeforeMicrosoftCommonProps = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\vCurrent\Custom.Before.Microsoft.Common.props -CustomBeforeMicrosoftCommonTargets = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\vCurrent\Custom.Before.Microsoft.Common.targets -CustomBeforeMicrosoftCSharpTargets = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\vCurrent\Custom.Before.Microsoft.CSharp.targets -DebuggerFlavor = ProjectDebugger -DebugSymbols = true -DebugSymbolsProjectOutputGroupDependenciesDependsOn = - ; - - ; - BuildOnlySettings; - PrepareForBuild; - AssignTargetPaths; - ResolveReferences - - -DebugSymbolsProjectOutputGroupDependsOn = -DebugType = full -DefaultLanguageSourceExtension = .cs -DefaultProjectTypeGuid = {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} -DeferredValidationErrorsFileName = obj\Debug\\AC2C1ABA-CCF6-44D4-8127-588FD4D0A860-DeferredValidationErrors.xml -DefineCommonCapabilities = false -DefineCommonItemSchemas = false -DefineCommonManagedCapabilities = true -DefineCommonManagedItemSchemas = true -DefineCommonManagedReferenceSchemas = true -DefineCommonReferenceSchemas = false -DefineConstants = DEBUG;TRACE -DefineCSharpItemSchemas = false -DelaySign = -DeploymentType = Installed -DesignerFunctionVisibility = Private -DesignerHiddenCodeGeneration = Declarations -DesignerRuntimeImplementationProjectOutputGroupDependsOn = - ; - - ; - BuildOnlySettings; - PrepareForBuild; - AssignTargetPaths; - ResolveReferences - - -DesignerVariableNaming = Camel -DesignTimeIntermediateOutputPath = obj\Debug\InProcessTempFiles\ -DesignTimeResolveAssemblyReferencesDependsOn = - GetFrameworkPaths; - GetReferenceAssemblyPaths; - ResolveReferences - -Deterministic = true -DevEnvDir = *Undefined* -DisableLogTaskParameter_ConvertToAbsolutePath_Path = true -DisableLogTaskParameter_FindUnderPath_OutOfPath = true -DisableLogTaskParameter_RemoveDuplicates_Inputs = true -DisableLogTaskParameterItemMetadata_ConvertToAbsolutePath_AbsolutePaths = true -DisableLogTaskParameterItemMetadata_Copy_CopiedFiles = true -DisableLogTaskParameterItemMetadata_Copy_DestinationFiles = true -DisableLogTaskParameterItemMetadata_Copy_SourceFiles = true -DisableLogTaskParameterItemMetadata_FindUnderPath_Files = true -DisableLogTaskParameterItemMetadata_FindUnderPath_InPath = true -DisableLogTaskParameterItemMetadata_GenerateResource_FilesWritten = true -DisableLogTaskParameterItemMetadata_Hash_ItemsToHash = true -DisableLogTaskParameterItemMetadata_RemoveDuplicates_Filtered = true -DisableLogTaskParameterItemMetadata_WriteLinesToFile_Lines = true -DockerBuildTasksAssembly = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Sdks\Microsoft.Docker.Sdk\build\..\tools\Microsoft.Docker.BuildTasks.dll -DockerIntermediateOutputPath = obj\Docker -DockerPublishDirectory = obj\Docker\publish -DocumentationProjectOutputGroupDependenciesDependsOn = - ; - - ; - BuildOnlySettings; - PrepareForBuild; - AssignTargetPaths; - ResolveReferences - - -DocumentationProjectOutputGroupDependsOn = -DriverData = C:\Windows\System32\Drivers\DriverData -EmbeddedWin32Manifest = -EntityDeployDependsOn = -EntityDeployIntermediateResourcePath = obj\Debug\edmxResourcesToEmbed\ -ErrorReport = prompt -ErrorReportUrlHistory = -ExpandSDKAllowedReferenceExtensions = - .winmd; - .dll - -ExpandSDKReferencesDependsOn = - ResolveSDKReferences - -FallbackCulture = en-US -FileAlignment = 512 -FindInvalidProjectReferencesDependsOn = - GetReferenceTargetPlatformMonikers - -FPS_BROWSER_APP_PROFILE_STRING = Internet Explorer -FPS_BROWSER_USER_PROFILE_STRING = Default -Framework20Dir = @(_TargetFramework20DirectoryItem) -Framework30Dir = @(_TargetFramework30DirectoryItem) -Framework35Dir = @(_TargetFramework35DirectoryItem) -Framework40Dir = @(_TargetFramework40DirectoryItem) -FrameworkDir = @(_TargetFramework40DirectoryItem) -FrameworkPathOverride = C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8 -FrameworkRegistryBase = Software\Microsoft\.NETFramework -FrameworkSDKDir = @(_TargetFrameworkSDKDirectoryItem) -FrameworkSDKRoot = C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\ -FullReferenceAssemblyNames = Full -GenerateBindingRedirectsOutputType = true -GenerateClickOnceManifests = -GenerateCompiledExpressionsTempFilePathForEditing = obj\Debug\\TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs -GenerateCompiledExpressionsTempFilePathForTypeInfer = obj\Debug\\TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs -GenerateCompiledExpressionsTempFilePathForValidation = obj\Debug\\TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs -GeneratedFileExtension = .g.cs -GeneratedMSBuildEditorConfigFile = DiztinGUIsh.GeneratedMSBuildEditorConfig.editorconfig -GenerateManifestsDependsOn = - SetWin32ManifestProperties; - GenerateApplicationManifest; - GenerateDeploymentManifest - -GenerateMSBuildEditorConfigFile = true -GenerateTargetFrameworkAttribute = true -GeneratorsTypeGuid = {FAE04EC1-301F-11d3-BF4B-00C04F79EFBC} -GetCopyToOutputDirectoryItemsDependsOn = - AssignTargetPaths; - _SplitProjectReferencesByFileExistence; - _GetProjectReferenceTargetFrameworkProperties; - _PopulateCommonStateForGetCopyToOutputDirectoryItems - -GetFrameworkPathsDependsOn = -GetReferenceAssemblyPathsDependsOn = - ; - GetWinFXPath - -GetTargetPathDependsOn = -GetTargetPathWithTargetPlatformMonikerDependsOn = -GitBaseVersionRegex = v?(?\d+)\.(?\d+)(?:\-(? private void InitializeComponent() { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(About)); this.tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); this.logoPictureBox = new System.Windows.Forms.PictureBox(); this.labelProductName = new System.Windows.Forms.Label(); @@ -43,7 +42,7 @@ private void InitializeComponent() // tableLayoutPanel // this.tableLayoutPanel.ColumnCount = 2; - this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 136F)); + this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 256F)); this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); this.tableLayoutPanel.Controls.Add(this.logoPictureBox, 0, 0); this.tableLayoutPanel.Controls.Add(this.labelProductName, 1, 1); @@ -61,33 +60,33 @@ private void InitializeComponent() this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); - this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 35F)); - this.tableLayoutPanel.Size = new System.Drawing.Size(338, 229); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 32F)); + this.tableLayoutPanel.Size = new System.Drawing.Size(673, 326); this.tableLayoutPanel.TabIndex = 0; // // logoPictureBox // this.logoPictureBox.Dock = System.Windows.Forms.DockStyle.Fill; - this.logoPictureBox.Image = ((System.Drawing.Image)(resources.GetObject("logoPictureBox.Image"))); + this.logoPictureBox.Image = global::DiztinGUIsh.Properties.Resources.diz_4; this.logoPictureBox.Location = new System.Drawing.Point(0, 0); this.logoPictureBox.Margin = new System.Windows.Forms.Padding(0); this.logoPictureBox.Name = "logoPictureBox"; this.tableLayoutPanel.SetRowSpan(this.logoPictureBox, 7); - this.logoPictureBox.Size = new System.Drawing.Size(136, 229); - this.logoPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.logoPictureBox.Size = new System.Drawing.Size(256, 326); + this.logoPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize; this.logoPictureBox.TabIndex = 12; this.logoPictureBox.TabStop = false; // // labelProductName // this.labelProductName.Dock = System.Windows.Forms.DockStyle.Fill; - this.labelProductName.Location = new System.Drawing.Point(139, 15); + this.labelProductName.Location = new System.Drawing.Point(259, 15); this.labelProductName.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0); this.labelProductName.MaximumSize = new System.Drawing.Size(0, 17); this.labelProductName.Name = "labelProductName"; - this.labelProductName.Size = new System.Drawing.Size(199, 17); + this.labelProductName.Size = new System.Drawing.Size(414, 17); this.labelProductName.TabIndex = 0; this.labelProductName.Text = "Product Name"; this.labelProductName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; @@ -95,11 +94,11 @@ private void InitializeComponent() // labelVersion // this.labelVersion.Dock = System.Windows.Forms.DockStyle.Fill; - this.labelVersion.Location = new System.Drawing.Point(139, 35); + this.labelVersion.Location = new System.Drawing.Point(259, 35); this.labelVersion.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0); this.labelVersion.MaximumSize = new System.Drawing.Size(0, 17); this.labelVersion.Name = "labelVersion"; - this.labelVersion.Size = new System.Drawing.Size(199, 17); + this.labelVersion.Size = new System.Drawing.Size(414, 17); this.labelVersion.TabIndex = 1; this.labelVersion.Text = "Version"; this.labelVersion.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; @@ -107,11 +106,11 @@ private void InitializeComponent() // labelCopyright // this.labelCopyright.Dock = System.Windows.Forms.DockStyle.Fill; - this.labelCopyright.Location = new System.Drawing.Point(139, 55); + this.labelCopyright.Location = new System.Drawing.Point(259, 55); this.labelCopyright.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0); this.labelCopyright.MaximumSize = new System.Drawing.Size(0, 17); this.labelCopyright.Name = "labelCopyright"; - this.labelCopyright.Size = new System.Drawing.Size(199, 17); + this.labelCopyright.Size = new System.Drawing.Size(414, 17); this.labelCopyright.TabIndex = 2; this.labelCopyright.Text = "Copyright"; this.labelCopyright.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; @@ -119,11 +118,11 @@ private void InitializeComponent() // labelCompanyName // this.labelCompanyName.Dock = System.Windows.Forms.DockStyle.Fill; - this.labelCompanyName.Location = new System.Drawing.Point(139, 75); + this.labelCompanyName.Location = new System.Drawing.Point(259, 75); this.labelCompanyName.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0); this.labelCompanyName.MaximumSize = new System.Drawing.Size(0, 17); this.labelCompanyName.Name = "labelCompanyName"; - this.labelCompanyName.Size = new System.Drawing.Size(199, 17); + this.labelCompanyName.Size = new System.Drawing.Size(414, 17); this.labelCompanyName.TabIndex = 3; this.labelCompanyName.Text = "Company Name"; this.labelCompanyName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; @@ -131,12 +130,12 @@ private void InitializeComponent() // textBoxDescription // this.textBoxDescription.Dock = System.Windows.Forms.DockStyle.Fill; - this.textBoxDescription.Location = new System.Drawing.Point(139, 98); + this.textBoxDescription.Location = new System.Drawing.Point(259, 101); this.textBoxDescription.Multiline = true; this.textBoxDescription.Name = "textBoxDescription"; this.textBoxDescription.ReadOnly = true; this.textBoxDescription.ScrollBars = System.Windows.Forms.ScrollBars.Both; - this.textBoxDescription.Size = new System.Drawing.Size(196, 93); + this.textBoxDescription.Size = new System.Drawing.Size(411, 189); this.textBoxDescription.TabIndex = 4; this.textBoxDescription.TabStop = false; this.textBoxDescription.Text = "Description"; @@ -145,18 +144,19 @@ private void InitializeComponent() // this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.okButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.okButton.Location = new System.Drawing.Point(255, 203); + this.okButton.Location = new System.Drawing.Point(590, 300); this.okButton.Name = "okButton"; this.okButton.Size = new System.Drawing.Size(80, 23); this.okButton.TabIndex = 5; this.okButton.Text = "&OK"; + this.okButton.Click += new System.EventHandler(this.okButton_Click); // // About // this.AcceptButton = this.okButton; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(338, 229); + this.ClientSize = new System.Drawing.Size(673, 326); this.Controls.Add(this.tableLayoutPanel); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; this.MaximizeBox = false; diff --git a/DiztinGUIsh/window/dialog/About.cs b/DiztinGUIsh/window/dialog/About.cs index 6097ed1f..b6dafbbf 100644 --- a/DiztinGUIsh/window/dialog/About.cs +++ b/DiztinGUIsh/window/dialog/About.cs @@ -41,9 +41,22 @@ public string AssemblyDescription get { var attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false); - return attributes.Length == 0 - ? "" - : ((AssemblyDescriptionAttribute)attributes[0]).Description; + var assembly = attributes.Length == 0 + ? null + : ((AssemblyDescriptionAttribute)attributes[0]); + + if (assembly == null) + return ""; + + var description = + assembly.Description + "\r\n" + "\r\n" + "Build info:\r\n" + + "Git branch: " + ThisAssembly.Git.Branch + "\r\n" + + "Git commit: " + ThisAssembly.Git.Commit + "\r\n" + + "Git repo URL: " + ThisAssembly.Git.RepositoryUrl + "\r\n" + + "Git tag: " + ThisAssembly.Git.Tag + "\r\n" + + "Git last commit date: " + ThisAssembly.Git.CommitDate + "\r\n"; + + return description; } } @@ -79,5 +92,10 @@ private void About_Load(object sender, EventArgs e) { } + + private void okButton_Click(object sender, EventArgs e) + { + + } } } diff --git a/DiztinGUIsh/window/dialog/About.resx b/DiztinGUIsh/window/dialog/About.resx index e4963227..1af7de15 100644 --- a/DiztinGUIsh/window/dialog/About.resx +++ b/DiztinGUIsh/window/dialog/About.resx @@ -117,591 +117,4 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - iVBORw0KGgoAAAANSUhEUgAAAIgAAADkCAYAAABDjGxzAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAL - EwAACxMBAJqcGAAAh/9JREFUeF61vWvwfNFVlpkPM6IIgjdEEINch0EpEBFhcBiBAR3Ly6AUjlKog1Iq - OjgWyIDKoFRQA0gFNBhFoQIRpAJDDCKg3BRMBRDUGJD7PeQmAQQE+fCb/ax3P3ut0/37B4TwYdU+ffp2 - +uznvOtd65zufspbvOfXPhhv/ju+ZsVXV7zZu3/Zid/w2/954t2+qOJN/6fn7Xj+w1Pf9f97eOq7PPfh - 1/+2z3349e/8nIc3+a2fueLZD7/uHf9+4rd82sMb/+Zn7Xjmwxu/w99+eKO3/6SHX/t2n7ji41c8/eEN - f+PHPrzhb/oba/y4Wv41/+PH7Pjohzf4Hz7y4Ve/9Yft+PCHX/WWfz7xFn+uxl/55h+y4k8//Irf8CdW - /PEVH/Twy5/6gRWv/yZ/aI0fsMb3r2XG1/t177fiD+zlP/Dwy97o9674PQ+v98a/v4Ll133D91nxu07U - c974fR9e5w3e6+F1fvW7P/zSX/Xbd7zbincd69614rV/xTut+K0Vv+SXv+N9vP477PHtKn7x6/3Gvfz2 - uf3L3nbE2zy81uu+9WU58ZYdr/MWJ37RL32zFW+6R5efeon//pe88Yg3GuHtNzzxlLd4jxc+vOV7fcMC - 5OsDynu8oABhFI43e/cvH6B88QLjCzcozz+gAMhT3+XzFiSfXZAARgD5h4m1XID85k+teKO3/+QCJbAA - CsAAy9Mqfs3b/tWC5A3e5i8XJAHlw1d8RMWvessP3QEwH1qQ/Mo3/1MblA/aoPzRDcsHBJRf/4cTCxYh - OYAsCGr51/7uSwCGUL3OG7zHit/R4wZjLgea334BJMD8tgHIAuEAsmDZYGR8hwPMFZC3Obez7tUB8maX - 5UCyQXntN7nEFZQG5L97rTeocSnIAuNAopKgIlETgYmafHkBUkriuEEBjKjI55SCtJpsRRGYAgVIgGWp - SinKMwYkH3+BJIB8VMe6HVCIKAtqEiWJmjwZlMDSkLzfUZUat4IcUNbIep4HICgLcLzuG773BuUaAUQl - ebeCYirKAaTgAAyVRGAGHGtsFWkwOt62wLkF5WcExLiD5AmAvNV7v2irx9cvSL5xQ/L1D2/+v/zLwLHG - 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 - - \ No newline at end of file From 479487f5afeeab2a23348738d040e6b80ef30d15 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 11 Oct 2020 10:05:27 -0400 Subject: [PATCH 089/136] upgrade to preview version of ExtendedXmlSerializer AND! with the bugfix in from upstream, fix serialization of generic IDictionary. That means we can serialize ObservableDictionary directly now! - remove ODWrapper junk workaround, not needed anmore! --- Diz.Core/Diz.Core.csproj | 33 +++-- Diz.Core/SampleRomData.cs | 29 ++--- Diz.Core/export/LogCreator.cs | 12 +- Diz.Core/model/Data.cs | 33 ++--- Diz.Core/packages.config | 20 +-- .../binary_serializer_old/BinarySerializer.cs | 10 +- .../xml_serializer/XMLSerializerSupport.cs | 2 - Diz.Core/util/ObservableDictionaryAdaptor.cs | 120 ------------------ Diz.Test/Diz.Test.csproj | 32 ++--- Diz.Test/LogCreator.cs | 12 +- Diz.Test/SerializerTest.cs | 20 +-- Diz.Test/app.config | 8 ++ Diz.Test/packages.config | 20 +-- DiztinGUIsh/DiztinGUIsh.csproj | 3 - DiztinGUIsh/Program.cs | 3 - DiztinGUIsh/window/AliasList.cs | 10 +- 16 files changed, 121 insertions(+), 246 deletions(-) delete mode 100644 Diz.Core/util/ObservableDictionaryAdaptor.cs diff --git a/Diz.Core/Diz.Core.csproj b/Diz.Core/Diz.Core.csproj index d65f3056..b05ab383 100644 --- a/Diz.Core/Diz.Core.csproj +++ b/Diz.Core/Diz.Core.csproj @@ -32,8 +32,8 @@ 4 - - ..\packages\ExtendedXmlSerializer.3.3.0\lib\net452\ExtendedXmlSerializer.dll + + ..\packages\ExtendedXmlSerializer.3.3.0.6-pexchapm\lib\net452\ExtendedXmlSerializer.dll ..\packages\IX.Abstractions.0.5.3\lib\net472\IX.Abstractions.dll @@ -62,39 +62,39 @@ ..\packages\JetBrains.Annotations.2019.1.3\lib\net20\JetBrains.Annotations.dll - - ..\packages\LightInject.6.2.0\lib\net46\LightInject.dll + + ..\packages\LightInject.6.3.5\lib\net46\LightInject.dll - ..\packages\NReco.LambdaParser.1.0.11\lib\net45\NReco.LambdaParser.dll + ..\packages\NReco.LambdaParser.1.0.12\lib\net45\NReco.LambdaParser.dll - - ..\packages\Sprache.2.2.0\lib\net45\Sprache.dll + + ..\packages\Sprache.2.3.1\lib\net45\Sprache.dll - - ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll + + ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll - ..\packages\System.Collections.Immutable.1.7.0\lib\netstandard2.0\System.Collections.Immutable.dll + ..\packages\System.Collections.Immutable.1.7.1\lib\net461\System.Collections.Immutable.dll - - ..\packages\System.Interactive.4.0.0\lib\net45\System.Interactive.dll + + ..\packages\System.Interactive.4.1.1\lib\net45\System.Interactive.dll - ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll + ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll - - ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll - ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\net461\System.Runtime.CompilerServices.Unsafe.dll @@ -123,7 +123,6 @@ - diff --git a/Diz.Core/SampleRomData.cs b/Diz.Core/SampleRomData.cs index 0905c0b3..d85ab9cc 100644 --- a/Diz.Core/SampleRomData.cs +++ b/Diz.Core/SampleRomData.cs @@ -1,5 +1,6 @@ using Diz.Core.model; using Diz.Core.util; +using IX.Observable; namespace Diz.Core { @@ -184,25 +185,21 @@ public static SampleRomData SampleData new ROMByte {Rom = 0x34, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, new ROMByte {Rom = 0x6D, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, }, - Comments = new OdWrapper() + Comments = new ObservableDictionary() { - Dict = { - {0x808000 + 0x03, "this sets FastROM"}, - {0x808000 + 0x0F, "direct page = $2100"}, - {0x808000 + 0x21, "clear APU regs"}, - {0x808000 + 0x44, "this routine copies Test_Data to $7E0100"} - } + {0x808000 + 0x03, "this sets FastROM"}, + {0x808000 + 0x0F, "direct page = $2100"}, + {0x808000 + 0x21, "clear APU regs"}, + {0x808000 + 0x44, "this routine copies Test_Data to $7E0100"} }, - Labels = new OdWrapper() + Labels = new ObservableDictionary() { - Dict = { - {0x808000 + 0x00, new Label {name = "Emulation_RESET", comment = "Sample emulation reset location"}}, - {0x808000 + 0x0A, new Label {name = "FastRESET", comment = "Sample label"}}, - {0x808000 + 0x32, new Label {name = "Test_Indices"}}, - {0x808000 + 0x3A, new Label {name = "Pointer_Table"}}, - {0x808000 + 0x44, new Label {name = "First_Routine"}}, - {0x808000 + 0x5B, new Label {name = "Test_Data", comment = "Pretty cool huh?"}} - } + {0x808000 + 0x00, new Label {name = "Emulation_RESET", comment = "Sample emulation reset location"}}, + {0x808000 + 0x0A, new Label {name = "FastRESET", comment = "Sample label"}}, + {0x808000 + 0x32, new Label {name = "Test_Indices"}}, + {0x808000 + 0x3A, new Label {name = "Pointer_Table"}}, + {0x808000 + 0x44, new Label {name = "First_Routine"}}, + {0x808000 + 0x5B, new Label {name = "Test_Data", comment = "Pretty cool huh?"}} }, }; } diff --git a/Diz.Core/export/LogCreator.cs b/Diz.Core/export/LogCreator.cs index dbc70e2f..0555da16 100644 --- a/Diz.Core/export/LogCreator.cs +++ b/Diz.Core/export/LogCreator.cs @@ -85,7 +85,7 @@ protected void RestoreUnderlyingDataLabels() // SUPER IMPORTANT. THIS MUST GET DONE, ALWAYS. PROTECT THIS WITH TRY/CATCH if (backupOfOriginalLabelsBeforeModifying != null) - Data.Labels.Dict = backupOfOriginalLabelsBeforeModifying; + Data.Labels = backupOfOriginalLabelsBeforeModifying; backupOfOriginalLabelsBeforeModifying = null; } @@ -121,8 +121,8 @@ protected void WriteGeneratedLabelsIntoUnderlyingData() // TODO: I really don't like us modifying and restoring the // underlying labels or anything in Data. Data should ideally be immutable by us. // we should either clone all of Data before modifying, or generate these labels on the fly. - backupOfOriginalLabelsBeforeModifying = Data.Labels.Dict; - Data.Labels.Dict = new ObservableDictionary(Data.Labels.Dict); + backupOfOriginalLabelsBeforeModifying = Data.Labels; + Data.Labels = new ObservableDictionary(Data.Labels); // write the new generated labels in, don't let them overwrite any real labels // i.e. if the user defined a label like "PlayerSwimmingSprites", and our auto-generated @@ -239,7 +239,7 @@ private void WriteBlankLineIfEndPoint(int pointer) private void WriteBlankLineIfStartingNewParagraph(int pointer) { var isLocationAReadPoint = (Data.GetInOutPoint(pointer) & Data.InOutPoint.ReadPoint) != 0; - var anyLabelsPresent = Data.Labels.Dict.TryGetValue(pointer, out var label) && label.name.Length > 0; + var anyLabelsPresent = Data.Labels.TryGetValue(pointer, out var label) && label.name.Length > 0; if (isLocationAReadPoint || anyLabelsPresent) output.WriteLine(GetLine(pointer, "empty")); @@ -284,7 +284,7 @@ private Dictionary GetUnvisitedLabels() var unvisitedLabels = new Dictionary(); // part 1: important: include all labels we aren't defining somewhere else. needed for disassembly - foreach (KeyValuePair pair in Data.Labels.Dict) + foreach (var pair in Data.Labels) { if (labelsWeVisited.Contains(pair.Key)) continue; @@ -314,7 +314,7 @@ private void PrintAllLabelsIfRequested(int pointer, Dictionary unvis return; SwitchOutputStream(pointer, "all-labels.txt"); // TODO: csv in the future. escape commas - foreach (KeyValuePair pair in Data.Labels.Dict) + foreach (var pair in Data.Labels) { // not the best place to add formatting, TODO: cleanup var category = unvisitedLabels.ContainsKey(pair.Key) ? "UNUSED" : "USED"; diff --git a/Diz.Core/model/Data.cs b/Diz.Core/model/Data.cs index 12cf2d53..c9a855cb 100644 --- a/Diz.Core/model/Data.cs +++ b/Diz.Core/model/Data.cs @@ -6,6 +6,7 @@ using System.Text; using Diz.Core.arch; using Diz.Core.util; +using IX.Observable; namespace Diz.Core.model { @@ -88,8 +89,8 @@ public const int public ROMSpeed RomSpeed { get; set; } // dictionaries store in SNES address format (since memory labels can't be represented as a PC address) - public OdWrapper Comments { get; set; } = new OdWrapper(); - public OdWrapper Labels { get; set; } = new OdWrapper(); + public ObservableDictionary Comments { get; set; } = new ObservableDictionary(); + public ObservableDictionary Labels { get; set; } = new ObservableDictionary(); // RomBytes stored as PC file offset addresses (since ROM will always be mapped to disk) public RomBytes RomBytes { get; set; } = new RomBytes(); @@ -172,14 +173,14 @@ public void SetMXFlags(int i, int mx) } public string GetLabelName(int i) { - if (Labels.Dict.TryGetValue(i, out var val)) + if (Labels.TryGetValue(i, out var val)) return val?.name ?? ""; return ""; } public string GetLabelComment(int i) { - if (Labels.Dict.TryGetValue(i, out var val)) + if (Labels.TryGetValue(i, out var val)) return val?.comment ?? ""; return ""; @@ -187,7 +188,7 @@ public string GetLabelComment(int i) public void DeleteAllLabels() { - Labels.Dict.Clear(); + Labels.Clear(); } public void AddLabel(int offset, Label label, bool overwrite) @@ -195,35 +196,35 @@ public void AddLabel(int offset, Label label, bool overwrite) // adding null label removes it if (label == null) { - if (Labels.Dict.ContainsKey(offset)) - Labels.Dict.Remove(offset); + if (Labels.ContainsKey(offset)) + Labels.Remove(offset); return; } if (overwrite) { - if (Labels.Dict.ContainsKey(offset)) - Labels.Dict.Remove(offset); + if (Labels.ContainsKey(offset)) + Labels.Remove(offset); } - if (!Labels.Dict.ContainsKey(offset)) + if (!Labels.ContainsKey(offset)) { label.CleanUp(); - Labels.Dict.Add(offset, label); + Labels.Add(offset, label); } } - public string GetComment(int i) => Comments.Dict.TryGetValue(i, out var val) ? val : ""; + public string GetComment(int i) => Comments.TryGetValue(i, out var val) ? val : ""; public void AddComment(int i, string v, bool overwrite) { if (v == null) { - if (Comments.Dict.ContainsKey(i)) Comments.Dict.Remove(i); + if (Comments.ContainsKey(i)) Comments.Remove(i); } else { - if (Comments.Dict.ContainsKey(i) && overwrite) Comments.Dict.Remove(i); - if (!Comments.Dict.ContainsKey(i)) Comments.Dict.Add(i, v); + if (Comments.ContainsKey(i) && overwrite) Comments.Remove(i); + if (!Comments.ContainsKey(i)) Comments.Add(i, v); } } @@ -619,7 +620,7 @@ public string GetInstruction(int offset) #region Equality protected bool Equals(Data other) { - return Labels.Dict.SequenceEqual(other.Labels.Dict) && RomMapMode == other.RomMapMode && RomSpeed == other.RomSpeed && Comments.Dict.SequenceEqual(other.Comments.Dict) && RomBytes.Equals(other.RomBytes); + return Labels.SequenceEqual(other.Labels) && RomMapMode == other.RomMapMode && RomSpeed == other.RomSpeed && Comments.SequenceEqual(other.Comments) && RomBytes.Equals(other.RomBytes); } public override bool Equals(object obj) diff --git a/Diz.Core/packages.config b/Diz.Core/packages.config index e0d70f50..9b9291c1 100644 --- a/Diz.Core/packages.config +++ b/Diz.Core/packages.config @@ -1,6 +1,6 @@  - + @@ -10,14 +10,14 @@ - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs b/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs index 37f48f9f..05f837a3 100644 --- a/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs +++ b/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs @@ -3,10 +3,8 @@ using System.Diagnostics; using System.IO; using System.Linq; -using System.Runtime.CompilerServices; using Diz.Core.model; using Diz.Core.util; -using DiztinGUIsh; namespace Diz.Core.serialization.binary_serializer_old { @@ -139,8 +137,8 @@ private byte[] SaveVersion(Project project, int version) var all_labels = project.Data.Labels; var all_comments = project.Data.Comments; - ByteUtil.IntegerIntoByteList(all_labels.Dict.Count, label); - foreach (KeyValuePair pair in all_labels.Dict) + ByteUtil.IntegerIntoByteList(all_labels.Count, label); + foreach (var pair in all_labels) { ByteUtil.IntegerIntoByteList(pair.Key, label); @@ -151,8 +149,8 @@ private byte[] SaveVersion(Project project, int version) } } - ByteUtil.IntegerIntoByteList(all_comments.Dict.Count, comment); - foreach (KeyValuePair pair in all_comments.Dict) + ByteUtil.IntegerIntoByteList(all_comments.Count, comment); + foreach (KeyValuePair pair in all_comments) { ByteUtil.IntegerIntoByteList(pair.Key, comment); SaveStringToBytes(pair.Value, comment); diff --git a/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs b/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs index 3f75d574..9e367de8 100644 --- a/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs +++ b/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs @@ -24,8 +24,6 @@ public static IConfigurationContainer GetSerializer() .Register().Serializer().Using(RomBytesSerializer.Default) .Type() - .ApplyAllOdWrapperConfigurations() // important for ODWrapper to serialize correctly. - .UseOptimizedNamespaces() .UseAutoFormatting() .EnableImplicitTyping(typeof(Data)) diff --git a/Diz.Core/util/ObservableDictionaryAdaptor.cs b/Diz.Core/util/ObservableDictionaryAdaptor.cs deleted file mode 100644 index 7af4eb06..00000000 --- a/Diz.Core/util/ObservableDictionaryAdaptor.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; -using ExtendedXmlSerializer; -using ExtendedXmlSerializer.Configuration; -using IX.Observable; - -namespace Diz.Core.util -{ - // OdwWrapper is wrapping an issue we are having where ExtendedXmlSerializer is having issues - // serializing ObservableDictionary<> correctly. It's failing to cast to IDictionary, which is either - // a problem with ObservableDictionary, or, a misconfiguration in the default config of ExtendedXmlSerializer - // - // Either way, the code in this file works around it (in kind of a clumsy way). We should rip it out - // as soon as we can. - public static class OdWrapperRegistration - { - // tell ExtendedXmlSerializer NOT to serialize .Dict on OdWrapper - public static IConfigurationContainer AppendDisablingType(this IConfigurationContainer @this) - => @this - .EnableImplicitTyping(typeof(OdWrapper)) - .Type>() - .Member(x => x.Dict).Ignore(); // this is the heart of everything - - private static readonly List> operationFNs = new List>(); - - // allow multiple OdWrapper type combos to be excluded. - public static void Register() => - operationFNs.Add(container => container.AppendDisablingType()); - - public static IConfigurationContainer ApplyAllOdWrapperConfigurations(this IConfigurationContainer @this) - { - if (operationFNs.Count == 0) - return @this; - - return operationFNs.Aggregate(@this, (current, fn) => fn(current)); - } - - // helper method to force the static stuff in the above classes to start at Program start. - // we need an approach that doesn't rely on this to work. - public static void ForceStaticClassRegistration() - { - foreach (var typeHandle in AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(asm=>asm.DefinedTypes) - .SelectMany(typeInfo => typeInfo.DeclaredProperties) - .Where(propertyInfo=>propertyInfo.PropertyType.Name.Contains("OdWrapper")) - .Select(propertyInfo=>propertyInfo.PropertyType.TypeHandle) - ) { - RuntimeHelpers.RunClassConstructor(typeHandle); // will call OdWrapper.Register for each generic type - } - } - } - - // wrapper around an ObservableDictionary so we can implement non-generic IDictionary - // this basically exists to work around ExtendedXmlSerializer trying to cast us to IDictionary and failing. - // there's probably settings we can tweak in ExtendedXmlSerializer (particularly, Interceptor), and then - // we can remove the need for this wrapper. - // - // this entire mess is because no matter what I do I can't do (IDictionary)ObservableDictionary - // which is what ExtendedXmlSerializer needs. this code all needs to GO - public class OdWrapper - { - // Real data we care about will live here in Dict. - // The XML serializer will ignore Dict when saving/loading - // The app code should use this directly. - public ObservableDictionary Dict { get; set; } = new ObservableDictionary(); - - private static bool _registered = Register(); - - // Expose a copy of Dict just for the XML serialization. - // App code should NOT touch this except for XML save/load. - public IDictionary DictToSave - { - get => new Dictionary(Dict); // copy. potentially expensive. - set - { - Dict.Clear(); - foreach (DictionaryEntry item in value) { - Dict.Add((TKey)item.Key, (TValue)item.Value); - } - } - } - - public OdWrapper() { Register(); } - - private static bool Register() - { - if (_registered) // reminder: this is unique per- combo - return true; - - OdWrapperRegistration.Register(); - _registered = true; - return true; - } - - #region Equality - - protected bool Equals(OdWrapper other) - { - return Dict.SequenceEqual(other.Dict); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((OdWrapper)obj); - } - - public override int GetHashCode() - { - return Dict.GetHashCode(); - } - - #endregion - } -} \ No newline at end of file diff --git a/Diz.Test/Diz.Test.csproj b/Diz.Test/Diz.Test.csproj index 23592661..532b8c01 100644 --- a/Diz.Test/Diz.Test.csproj +++ b/Diz.Test/Diz.Test.csproj @@ -40,8 +40,8 @@ ..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll - - ..\packages\ExtendedXmlSerializer.3.3.0\lib\net452\ExtendedXmlSerializer.dll + + ..\packages\ExtendedXmlSerializer.3.3.0.6-pexchapm\lib\net452\ExtendedXmlSerializer.dll ..\packages\IX.Abstractions.0.5.3\lib\net472\IX.Abstractions.dll @@ -70,43 +70,43 @@ ..\packages\JetBrains.Annotations.2019.1.3\lib\net20\JetBrains.Annotations.dll - - ..\packages\LightInject.6.2.0\lib\net46\LightInject.dll + + ..\packages\LightInject.6.3.5\lib\net46\LightInject.dll ..\packages\Moq.4.14.6\lib\net45\Moq.dll - ..\packages\NReco.LambdaParser.1.0.11\lib\net45\NReco.LambdaParser.dll + ..\packages\NReco.LambdaParser.1.0.12\lib\net45\NReco.LambdaParser.dll - - ..\packages\Sprache.2.2.0\lib\net45\Sprache.dll + + ..\packages\Sprache.2.3.1\lib\net45\Sprache.dll - - ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll + + ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll - ..\packages\System.Collections.Immutable.1.7.0\lib\netstandard2.0\System.Collections.Immutable.dll + ..\packages\System.Collections.Immutable.1.7.1\lib\net461\System.Collections.Immutable.dll - - ..\packages\System.Interactive.4.0.0\lib\net45\System.Interactive.dll + + ..\packages\System.Interactive.4.1.1\lib\net45\System.Interactive.dll - ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll + ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll - - ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll - ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\net461\System.Runtime.CompilerServices.Unsafe.dll diff --git a/Diz.Test/LogCreator.cs b/Diz.Test/LogCreator.cs index 9ad472a1..e01297cd 100644 --- a/Diz.Test/LogCreator.cs +++ b/Diz.Test/LogCreator.cs @@ -4,6 +4,7 @@ using Diz.Core.export; using Diz.Core.model; using Diz.Core.util; +using IX.Observable; using Xunit; namespace Diz.Test @@ -112,14 +113,11 @@ public void TestAFewLines() var inputData = new Data { - Labels = new OdWrapper + Labels = new ObservableDictionary { - Dict = - { - {0x808000 + 0x06, new Label {name = "Test22"}}, - {0x808000 + 0x5B, new Label {name = "Test_Data", comment = "Pretty cool huh?"}}, - // the CODE_XXXXXX labels are autogenerated - } + {0x808000 + 0x06, new Label {name = "Test22"}}, + {0x808000 + 0x5B, new Label {name = "Test_Data", comment = "Pretty cool huh?"}}, + // the CODE_XXXXXX labels are autogenerated }, RomMapMode = Data.ROMMapMode.LoROM, RomSpeed = Data.ROMSpeed.FastROM, diff --git a/Diz.Test/SerializerTest.cs b/Diz.Test/SerializerTest.cs index 52ea673a..1dfdff49 100644 --- a/Diz.Test/SerializerTest.cs +++ b/Diz.Test/SerializerTest.cs @@ -4,6 +4,7 @@ using Diz.Core.util; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; +using IX.Observable; using Xunit; using Xunit.Abstractions; @@ -20,20 +21,19 @@ public SerializerTest(ITestOutputHelper testOutputHelper) public class TestRoot { - public OdWrapper ODW { get; set; } = new OdWrapper() { Dict = { + public ObservableDictionary ODW { get; set; } = new ObservableDictionary() { {1, "Z test1"}, {2, "Z test3"}, - }}; - public OdWrapper ODW2 { get; set; } = new OdWrapper() { Dict = { + }; + public ObservableDictionary ODW2 { get; set; } = new ObservableDictionary() { {100, new Label {comment = "c1", name = "location1"}}, {200, new Label {comment = "c2", name = "location2"}}, - }}; + }; #region Equality - protected bool Equals(TestRoot other) { - return Equals(ODW, other.ODW); + return Equals(ODW, other.ODW) && Equals(ODW2, other.ODW2); } public override bool Equals(object obj) @@ -41,14 +41,16 @@ public override bool Equals(object obj) if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; - return Equals((TestRoot) obj); + return Equals((TestRoot)obj); } public override int GetHashCode() { - return (ODW != null ? ODW.GetHashCode() : 0); + unchecked + { + return ((ODW != null ? ODW.GetHashCode() : 0) * 397) ^ (ODW2 != null ? ODW2.GetHashCode() : 0); + } } - #endregion } diff --git a/Diz.Test/app.config b/Diz.Test/app.config index 72259e86..5df19485 100644 --- a/Diz.Test/app.config +++ b/Diz.Test/app.config @@ -6,6 +6,14 @@ + + + + + + + + \ No newline at end of file diff --git a/Diz.Test/packages.config b/Diz.Test/packages.config index f9ada2cd..843e70d6 100644 --- a/Diz.Test/packages.config +++ b/Diz.Test/packages.config @@ -1,7 +1,7 @@  - + @@ -11,16 +11,16 @@ - + - - - - - - - - + + + + + + + + diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 70d88ffc..7adaeb33 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -86,9 +86,6 @@ ..\packages\JetBrains.Annotations.2020.1.0\lib\net20\JetBrains.Annotations.dll - - ..\packages\LightInject.6.3.5\lib\net46\LightInject.dll - ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll diff --git a/DiztinGUIsh/Program.cs b/DiztinGUIsh/Program.cs index 1b87d504..d2ae3aa5 100644 --- a/DiztinGUIsh/Program.cs +++ b/DiztinGUIsh/Program.cs @@ -13,9 +13,6 @@ static class Program [STAThread] static void Main(string[] args) { - // hack. this needs to go away. register some types for the XML serializer to work. - OdWrapperRegistration.ForceStaticClassRegistration(); - if (Environment.OSVersion.Version.Major >= 6) { SetProcessDPIAware(); diff --git a/DiztinGUIsh/window/AliasList.cs b/DiztinGUIsh/window/AliasList.cs index 6bc63b5d..dd3bce5f 100644 --- a/DiztinGUIsh/window/AliasList.cs +++ b/DiztinGUIsh/window/AliasList.cs @@ -130,7 +130,7 @@ private void export_Click(object sender, EventArgs e) try { using var sw = new StreamWriter(saveFileDialog1.FileName); - foreach (KeyValuePair pair in Data.Labels.Dict) + foreach (var pair in Data.Labels) { sw.WriteLine( $"{Util.NumberToBaseString(pair.Key, Util.NumberBase.Hexadecimal, 6)},{pair.Value.name},{pair.Value.comment}"); @@ -184,7 +184,7 @@ private void dataGridView1_CellValidating(object sender, DataGridViewCellValidat { e.Cancel = true; toolStripStatusLabel1.Text = "Must enter a valid hex address."; - } else if (oldAddress == -1 && Data.Labels.Dict.ContainsKey(val)) + } else if (oldAddress == -1 && Data.Labels.ContainsKey(val)) { e.Cancel = true; toolStripStatusLabel1.Text = "This address already has a label."; @@ -288,8 +288,8 @@ public void RebindProject() // todo: eventually use databinding/datasource, probably. // Todo: modify observabledictionary wrapper to avoid having to do the .Dict call here. - Data.Labels.Dict.PropertyChanged += Labels_PropertyChanged; - Data.Labels.Dict.CollectionChanged += Labels_CollectionChanged; + Data.Labels.PropertyChanged += Labels_PropertyChanged; + Data.Labels.CollectionChanged += Labels_CollectionChanged; } private void RepopulateFromData() @@ -300,7 +300,7 @@ private void RepopulateFromData() return; // TODO: replace with winforms databinding eventually - foreach (KeyValuePair item in Data.Labels.Dict) + foreach (var item in Data.Labels) { RawAdd(item.Key, item.Value); } From b49e2050c72b3ee42370f4288bb6004927f539ae Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 11 Oct 2020 10:41:52 -0400 Subject: [PATCH 090/136] fix unit tests --- Diz.Test/SerializerTest.cs | 43 +++++--------------------------------- 1 file changed, 5 insertions(+), 38 deletions(-) diff --git a/Diz.Test/SerializerTest.cs b/Diz.Test/SerializerTest.cs index 1dfdff49..c3ada6b2 100644 --- a/Diz.Test/SerializerTest.cs +++ b/Diz.Test/SerializerTest.cs @@ -5,6 +5,7 @@ using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; using IX.Observable; +using IX.StandardExtensions; using Xunit; using Xunit.Abstractions; @@ -33,7 +34,9 @@ public class TestRoot #region Equality protected bool Equals(TestRoot other) { - return Equals(ODW, other.ODW) && Equals(ODW2, other.ODW2); + return + System.Linq.Enumerable.SequenceEqual(ODW, other.ODW) && + System.Linq.Enumerable.SequenceEqual(ODW2, other.ODW2); } public override bool Equals(object obj) @@ -85,42 +88,6 @@ private void DeSerialize() private readonly TestRoot testRootElementGood = new TestRoot(); - string xmlShouldBe = "<" + - "DictToSave exs:type=" + - "\"sys:Dictionary[sys" + - ":int,ns2:Label]\">" + - "" + - ""; + string xmlShouldBe = ""; } } \ No newline at end of file From d5855c113a3332007b0a2fc432a2e030d76d0584 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 11 Oct 2020 12:07:32 -0400 Subject: [PATCH 091/136] trying to publish, VS wanted to change this stuff. not sure we need this. --- DiztinGUIsh/DiztinGUIsh.csproj | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 7adaeb33..5b58bd7a 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -26,9 +26,10 @@ false false true - 0 + 1 1.0.0.%2a false + true true @@ -58,6 +59,18 @@ DiztinGUIsh.Program + + B5957BD4F7F637E843EB8B06E2C40D418498E46C + + + DiztinGUIsh_TemporaryKey.pfx + + + true + + + true + ..\packages\IX.Abstractions.0.5.3\lib\net472\IX.Abstractions.dll @@ -246,6 +259,7 @@ Resources.resx True + From 7dcf8b9f4c17de8416684a40c1c06f4bea6ab555 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Thu, 15 Oct 2020 08:22:19 -0400 Subject: [PATCH 092/136] WIP - diztinguish support for tracelog capturing via socket - needs cleanup --- Diz.Core/import/BSNESImporter.cs | 164 +++++++++++++-- Diz.Core/model/Data.cs | 2 +- .../binary_serializer_old/BinarySerializer.cs | 4 +- Diz.Core/util/ByteUtil.cs | 21 +- Diz.Core/util/RomUtil.cs | 2 +- DiztinGUIsh/DiztinGUIsh.csproj | 22 +- DiztinGUIsh/Program.cs | 29 +++ DiztinGUIsh/controller/ProjectController.cs | 58 ++++-- .../packages.config.new.20201015004634 | 20 ++ DiztinGUIsh/window/MainWindow.Designer.cs | 99 +++++---- DiztinGUIsh/window/MainWindow.cs | 133 +++++++----- .../BSNESTraceLogBinaryMonitor.Designer.cs | 196 ++++++++++++++++++ .../dialog/BSNESTraceLogBinaryMonitor.cs | 129 ++++++++++++ .../dialog/BSNESTraceLogBinaryMonitor.resx | 132 ++++++++++++ 14 files changed, 868 insertions(+), 143 deletions(-) create mode 100644 DiztinGUIsh/packages.config.new.20201015004634 create mode 100644 DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.Designer.cs create mode 100644 DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.cs create mode 100644 DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.resx diff --git a/Diz.Core/import/BSNESImporter.cs b/Diz.Core/import/BSNESImporter.cs index c0908366..c3a13c4f 100644 --- a/Diz.Core/import/BSNESImporter.cs +++ b/Diz.Core/import/BSNESImporter.cs @@ -1,5 +1,8 @@ using System; +using System.Diagnostics; +using System.Runtime.ExceptionServices; using Diz.Core.model; +using Diz.Core.util; namespace Diz.Core.import { @@ -75,6 +78,15 @@ public int ImportUsageMap(byte[] usageMap, Data data) public class BSNESTraceLogImporter { + private readonly Data Data; + int romSize; + + public BSNESTraceLogImporter(Data data) + { + Data = data; + romSize = Data.GetROMSize(); + } + // this class exists for performance optimization ONLY. // class representing offsets into a trace log // we calculate it once from sample data and hang onto it @@ -87,9 +99,17 @@ private class CachedTraceLineIndex // index of the start of the info public readonly int addr, - D, DB, + D, + DB, flags, - f_N, f_V, f_M, f_X, f_D, f_I, f_Z, f_C; + f_N, + f_V, + f_M, + f_X, + f_D, + f_I, + f_Z, + f_C; public CachedTraceLineIndex() { @@ -117,7 +137,7 @@ int SkipToken(string token) private static readonly CachedTraceLineIndex CachedIdx = new CachedTraceLineIndex(); - public int ImportTraceLogLine(string line, Data data) + public (int numChanged, int numLinesAnalyzed) ImportTraceLogLine(string line) { // caution: very performance-sensitive function, please take care when making modifications // string.IndexOf() is super-slow too. @@ -130,12 +150,12 @@ int GetHexValueAt(int startIndex, int length) } if (line.Length < 80) - return 0; + return (0,0); int snesAddress = GetHexValueAt(0, 6); - int pc = data.ConvertSNEStoPC(snesAddress); + int pc = Data.ConvertSNEStoPC(snesAddress); if (pc == -1) - return 0; + return (0, 0); // TODO: error treatment / validation @@ -148,22 +168,128 @@ int GetHexValueAt(int startIndex, int length) // 'M' = unchecked in bsnesplus debugger UI = (8bit), 'm' or '.' = checked (16bit) bool mflag_set = line[CachedIdx.f_M] == 'M'; - data.SetFlag(pc, Data.FlagType.Opcode); + return SetFromTraceData(pc, dataBank, directPage, xflag_set, mflag_set); + } - int modified = 0; - int size = data.GetROMSize(); - do - { - data.SetDataBank(pc, dataBank); - data.SetDirectPage(pc, directPage); - data.SetXFlag(pc, xflag_set); - data.SetMFlag(pc, mflag_set); + // this is same as above but, reads the same data from a binary format. this is for + // performance reasons to try and stream the data live from BSNES + public (int numChanged, int numLinesAnalyzed) ImportTraceLogLineBinary(byte[] bytes) + { + // extremely performance-intensive function. be really careful when adding stuff - pc++; - modified++; - } while (pc < size && data.GetFlag(pc) == Data.FlagType.Operand); + Debug.Assert(bytes.Length == 22); + var pointer = 0; - return modified; + // ----------------------------- + + var watermark = bytes[pointer++]; + if (watermark != 0xEE) + return (0, 0); + + var snesAddress = ByteUtil.ByteArrayToInt24(bytes, pointer); + pointer += 3; + + var pc = Data.ConvertSNEStoPC(snesAddress); + if (pc == -1) + return (0, 0); + + var opcodeLen = bytes[pointer++]; + + // skip opcodes. NOTE: must read all 5 butes but only use up to 'opcode_len' bytes + //var op = bytes[pointer++]; + //var op0 = bytes[pointer++]; + //var op1 = bytes[pointer++]; + //var op2 = bytes[pointer++]; + pointer += 4; + + // skip A register + pointer += 2; + + // skip X register + pointer += 2; + + // skip Y register + pointer += 2; + + // skip S register + pointer += 2; + + var directPage = ByteUtil.ByteArrayToInt24(bytes, pointer); + pointer += 2; + + var dataBank = bytes[pointer++]; + + // skip, flag 'e' for emulation mode or not + // var emuFlag = bytes[pointer++] == 0x01; + pointer++; + + // the real flags, we mainly care about X and M + var flags = bytes[pointer++]; + // n = flags & 0x80; + // v = flags & 0x40; + // m = flags & 0x20; + // d = flags & 0x08; + // i = flags & 0x04; + // z = flags & 0x02; + // c = flags & 0x01; + var xflagSet = (flags & 0x10) != 0; + var mflagSet = (flags & 0x20) != 0; + + Debug.Assert(pointer == bytes.Length); + + return SetFromTraceData(pc, dataBank, directPage, xflagSet, mflagSet, opcodeLen); + } + + // returns the number of bytes actually changed + private (int numChanged, int numLinesAnalyzed) SetFromTraceData(int pc, int dataBank, int directPage, bool xflagSet, bool mflagSet, + int opcodeLen = -1) + { + // extremely performance-intensive function. be really careful when adding stuff + + // set this data for us and any following operands + var currentIndex = 0; + var totalModified = 0; + bool keepGoing; + + do { + var flagType = currentIndex == 0 ? Data.FlagType.Opcode : Data.FlagType.Operand; + + var modified = false; + + modified |= Data.GetFlag(pc) != flagType; + Data.SetFlag(pc, flagType); + + modified |= Data.GetDataBank(pc) != dataBank; + Data.SetDataBank(pc, dataBank); + + modified |= Data.GetDirectPage(pc) != directPage; + Data.SetDirectPage(pc, directPage); + + modified |= Data.GetXFlag(pc) != xflagSet; + Data.SetXFlag(pc, xflagSet); + + modified |= Data.GetMFlag(pc) != mflagSet; + Data.SetMFlag(pc, mflagSet); + + if (modified) + totalModified++; + + pc++; // note: should we check for crossing banks? probably should stop there. + currentIndex++; + + if (opcodeLen != -1) + { + // we know the # of bytes that should follow our opcode, so mark that many bytes + keepGoing = currentIndex < opcodeLen; + } + else + { + // only continue if the next bytes were already marked as operands + keepGoing = Data.GetFlag(pc) == Data.FlagType.Operand; + } + } while (pc < romSize && keepGoing); + + return (totalModified, currentIndex); } } } diff --git a/Diz.Core/model/Data.cs b/Diz.Core/model/Data.cs index c9a855cb..ae7b39ce 100644 --- a/Diz.Core/model/Data.cs +++ b/Diz.Core/model/Data.cs @@ -131,7 +131,7 @@ public string GetRomNameFromRomBytes() public int GetRomCheckSumsFromRomBytes() { - return ByteUtil.ByteArrayToInteger(GetRomBytes(0xFFDC, 4)); + return ByteUtil.ByteArrayToInt32(GetRomBytes(0xFFDC, 4)); } public void CopyRomDataIn(byte[] data) diff --git a/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs b/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs index 05f837a3..24701471 100644 --- a/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs +++ b/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs @@ -56,7 +56,7 @@ public override (Project project, string warning) Load(byte[] data) // read mode, speed, size project.Data.RomMapMode = (Data.ROMMapMode)data[HEADER_SIZE]; project.Data.RomSpeed = (Data.ROMSpeed)data[HEADER_SIZE + 1]; - var size = ByteUtil.ByteArrayToInteger(data, HEADER_SIZE + 2); + var size = ByteUtil.ByteArrayToInt32(data, HEADER_SIZE + 2); // read internal title var pointer = HEADER_SIZE + 6; @@ -64,7 +64,7 @@ public override (Project project, string warning) Load(byte[] data) pointer += RomUtil.LengthOfTitleName; // read checksums - project.InternalCheckSum = ByteUtil.ByteArrayToInteger(data, pointer); + project.InternalCheckSum = ByteUtil.ByteArrayToInt32(data, pointer); pointer += 4; // read full filepath to the ROM .sfc file diff --git a/Diz.Core/util/ByteUtil.cs b/Diz.Core/util/ByteUtil.cs index b2f44707..408640d9 100644 --- a/Diz.Core/util/ByteUtil.cs +++ b/Diz.Core/util/ByteUtil.cs @@ -37,12 +37,12 @@ public static int ReadStringsTable(byte[] bytes, int starting_index, int strings var strings = new List(); var pos = starting_index; - var num_table_entries = ByteArrayToInteger(bytes, pos); + var num_table_entries = ByteArrayToInt32(bytes, pos); pos += 4; for (var entry = 0; entry < num_table_entries; ++entry) { - var offset = converter(ByteArrayToInteger(bytes, pos)); + var offset = converter(ByteArrayToInt32(bytes, pos)); pos += 4; strings.Clear(); @@ -91,7 +91,7 @@ public static void IntegerIntoByteList(int a, List list) list.Add(t); } - public static int ByteArrayToInteger(byte[] data, int offset = 0) + public static int ByteArrayToInt32(byte[] data, int offset = 0) { return data[offset] | @@ -100,6 +100,21 @@ public static int ByteArrayToInteger(byte[] data, int offset = 0) (data[offset + 3] << 24); } + public static int ByteArrayToInt24(byte[] data, int offset = 0) + { + return + data[offset] | + (data[offset + 1] << 8) | + (data[offset + 2] << 16); + } + + public static int ByteArrayToInt16(byte[] data, int offset = 0) + { + return + data[offset] | + (data[offset + 1] << 8); + } + public static byte[] StringToByteArray(string s) { byte[] array = new byte[s.Length + 1]; diff --git a/Diz.Core/util/RomUtil.cs b/Diz.Core/util/RomUtil.cs index 563beb19..002c8abe 100644 --- a/Diz.Core/util/RomUtil.cs +++ b/Diz.Core/util/RomUtil.cs @@ -30,7 +30,7 @@ public static string IsThisRomIsIdenticalToUs(byte[] rom, return "The linked ROM is too small. It can't be opened."; var internalGameNameToVerify = GetRomTitleName(rom, romSettingsOffset); - var checksumToVerify = ByteUtil.ByteArrayToInteger(rom, romSettingsOffset + 7); + var checksumToVerify = ByteUtil.ByteArrayToInt32(rom, romSettingsOffset + 7); if (internalGameNameToVerify != requiredGameNameMatch) return $"The linked ROM's internal name '{internalGameNameToVerify}' doesn't " + diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 5b58bd7a..9329e3eb 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -103,14 +103,8 @@ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll - - ..\packages\System.Collections.Immutable.1.7.1\lib\net461\System.Collections.Immutable.dll - - - ..\packages\System.Interactive.4.1.1\lib\net45\System.Interactive.dll - @@ -129,13 +123,8 @@ ..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll - - - - - @@ -143,6 +132,12 @@ + + Form + + + BSNESTraceLogBinaryMonitor.cs + @@ -221,6 +216,9 @@ About.cs + + BSNESTraceLogBinaryMonitor.cs + ProgressDialog.cs @@ -303,7 +301,7 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. diff --git a/DiztinGUIsh/Program.cs b/DiztinGUIsh/Program.cs index d2ae3aa5..a5ce9bfa 100644 --- a/DiztinGUIsh/Program.cs +++ b/DiztinGUIsh/Program.cs @@ -1,4 +1,6 @@ using System; +using System.Diagnostics; +using System.IO.Pipes; using System.Windows.Forms; using Diz.Core.util; using DiztinGUIsh.window; @@ -13,6 +15,9 @@ static class Program [STAThread] static void Main(string[] args) { + // Junk(); + // return; + if (Environment.OSVersion.Version.Major >= 6) { SetProcessDPIAware(); @@ -28,6 +33,30 @@ static void Main(string[] args) Application.Run(window); } + static void Junk() + { + var bytes = new byte[22]; + + using var pipeClient = new NamedPipeClientStream(".", + "bsnes_tracelog", PipeDirection.In); + + // Connect to the pipe or wait until the pipe is available. + Console.Write("Attempting to connect to pipe..."); + pipeClient.Connect(); + + Console.WriteLine("Connected to pipe."); + Console.WriteLine("There are currently {0} pipe server instances open.", + pipeClient.NumberOfServerInstances); + + var bytesRead = 0; + do + { + bytesRead = pipeClient.Read(bytes, 0, 22); + Debug.Assert(bytesRead == 22); + Console.WriteLine(bytes[0] == 0xEE ? "yep" : "nah"); + } while (bytesRead > 0); + } + [System.Runtime.InteropServices.DllImport("user32.dll")] private static extern bool SetProcessDPIAware(); } diff --git a/DiztinGUIsh/controller/ProjectController.cs b/DiztinGUIsh/controller/ProjectController.cs index f32be66a..b040bd31 100644 --- a/DiztinGUIsh/controller/ProjectController.cs +++ b/DiztinGUIsh/controller/ProjectController.cs @@ -1,6 +1,8 @@ using System; using System.ComponentModel; +using System.Diagnostics; using System.IO; +using System.Security.Policy; using Diz.Core.export; using Diz.Core.import; using Diz.Core.model; @@ -37,12 +39,17 @@ public class ProjectController public Project Project { get; private set; } public delegate void ProjectChangedEvent(object sender, ProjectChangedEventArgs e); + public event ProjectChangedEvent ProjectChanged; public class ProjectChangedEventArgs { - public enum ProjectChangedType { - Invalid, Saved, Opened, Imported + public enum ProjectChangedType + { + Invalid, + Saved, + Opened, + Imported } public ProjectChangedType ChangeType; @@ -67,13 +74,16 @@ public bool OpenProject(string filename) var errorMsg = ""; var warningMsg = ""; - DoLongRunningTask(delegate { + DoLongRunningTask(delegate + { try { var result = ProjectFileManager.Open(filename, AskToSelectNewRomFilename); project = result.project; warningMsg = result.warning; - } catch (Exception ex) { + } + catch (Exception ex) + { project = null; errorMsg = ex.Message; } @@ -113,10 +123,8 @@ private void Project_PropertyChanged(object sender, PropertyChangedEventArgs e) public void SaveProject(string filename) { - DoLongRunningTask(delegate - { - ProjectFileManager.Save(Project, filename); - }, $"Saving {Path.GetFileName(filename)}..."); + DoLongRunningTask(delegate { ProjectFileManager.Save(Project, filename); }, + $"Saving {Path.GetFileName(filename)}..."); ProjectView.OnProjectSaved(); } @@ -171,9 +179,7 @@ private void WriteAssemblyOutput(LogWriterSettings settings, bool showProgressBa }; LogCreator.OutputResult result = null; - DoLongRunningTask(delegate { - result = lc.CreateLog(); - }, "Exporting assembly source code..."); + DoLongRunningTask(delegate { result = lc.CreateLog(); }, "Exporting assembly source code..."); ProjectView.OnExportFinished(result); } @@ -212,19 +218,39 @@ public long ImportBSNESTraceLogs(string[] fileNames) { var totalLinesSoFar = 0L; - var importer = new BSNESTraceLogImporter(); + var importer = new BSNESTraceLogImporter(Project.Data); // caution: trace logs can be gigantic, even a few seconds can be > 1GB // inside here, performance becomes critical. - LargeFilesReader.ReadFilesLines(fileNames, delegate (string line) - { - totalLinesSoFar += importer.ImportTraceLogLine(line, Project.Data); - }); + LargeFilesReader.ReadFilesLines(fileNames, + delegate(string line) { totalLinesSoFar += importer.ImportTraceLogLine(line).numChanged; }); if (totalLinesSoFar > 0) MarkChanged(); return totalLinesSoFar; } + + public int ImportBsnesTraceLogsBinary(string[] filenames) + { + var importer = new BSNESTraceLogImporter(Project.Data); + + var totalModified = 0; + foreach (var file in filenames) + { + using Stream source = File.OpenRead(file); + const int bytesPerPacket = 22; + var buffer = new byte[bytesPerPacket]; + int bytesRead; + while ((bytesRead = source.Read(buffer, 0, bytesPerPacket)) > 0) + { + Debug.Assert(bytesRead == 22); + var result = importer.ImportTraceLogLineBinary(buffer); + totalModified += result.numChanged; + } + } + + return totalModified; + } } } diff --git a/DiztinGUIsh/packages.config.new.20201015004634 b/DiztinGUIsh/packages.config.new.20201015004634 new file mode 100644 index 00000000..f3ad379b --- /dev/null +++ b/DiztinGUIsh/packages.config.new.20201015004634 @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DiztinGUIsh/window/MainWindow.Designer.cs b/DiztinGUIsh/window/MainWindow.Designer.cs index 3e58e04a..6e3793e2 100644 --- a/DiztinGUIsh/window/MainWindow.Designer.cs +++ b/DiztinGUIsh/window/MainWindow.Designer.cs @@ -65,10 +65,8 @@ private void InitializeComponent() this.saveProjectToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.saveProjectAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripMenuItem(); this.exportLogToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.importCDLToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.importTraceLogToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.importUsageMapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator(); this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -137,6 +135,11 @@ private void InitializeComponent() this.openUsageMapFile = new System.Windows.Forms.OpenFileDialog(); this.openTraceLogDialog = new System.Windows.Forms.OpenFileDialog(); this.openCDLDialog = new System.Windows.Forms.OpenFileDialog(); + this.importUsageMapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.importTraceLogBinary = new System.Windows.Forms.ToolStripMenuItem(); + this.importTraceLogText = new System.Windows.Forms.ToolStripMenuItem(); + this.importCDLToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator(); ((System.ComponentModel.ISupportInitialize)(this.table)).BeginInit(); this.menuStrip1.SuspendLayout(); this.statusStrip1.SuspendLayout(); @@ -373,10 +376,8 @@ private void InitializeComponent() this.saveProjectToolStripMenuItem, this.saveProjectAsToolStripMenuItem, this.toolStripSeparator1, + this.toolStripMenuItem2, this.exportLogToolStripMenuItem, - this.importCDLToolStripMenuItem, - this.importTraceLogToolStripMenuItem, - this.importUsageMapToolStripMenuItem, this.toolStripSeparator7, this.exitToolStripMenuItem}); this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; @@ -430,6 +431,18 @@ private void InitializeComponent() this.toolStripSeparator1.Name = "toolStripSeparator1"; this.toolStripSeparator1.Size = new System.Drawing.Size(232, 6); // + // toolStripMenuItem2 + // + this.toolStripMenuItem2.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.importUsageMapToolStripMenuItem, + this.importCDLToolStripMenuItem, + this.toolStripSeparator8, + this.importTraceLogText, + this.importTraceLogBinary}); + this.toolStripMenuItem2.Name = "toolStripMenuItem2"; + this.toolStripMenuItem2.Size = new System.Drawing.Size(235, 22); + this.toolStripMenuItem2.Text = "Import"; + // // exportLogToolStripMenuItem // this.exportLogToolStripMenuItem.Enabled = false; @@ -439,31 +452,6 @@ private void InitializeComponent() this.exportLogToolStripMenuItem.Text = "Export Disassembly..."; this.exportLogToolStripMenuItem.Click += new System.EventHandler(this.exportLogToolStripMenuItem_Click); // - // importCDLToolStripMenuItem - // - this.importCDLToolStripMenuItem.Enabled = false; - this.importCDLToolStripMenuItem.Name = "importCDLToolStripMenuItem"; - this.importCDLToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.I))); - this.importCDLToolStripMenuItem.Size = new System.Drawing.Size(235, 22); - this.importCDLToolStripMenuItem.Text = "Import CDL..."; - this.importCDLToolStripMenuItem.Click += new System.EventHandler(this.importCDLToolStripMenuItem_Click); - // - // importTraceLogToolStripMenuItem - // - this.importTraceLogToolStripMenuItem.Enabled = false; - this.importTraceLogToolStripMenuItem.Name = "importTraceLogToolStripMenuItem"; - this.importTraceLogToolStripMenuItem.Size = new System.Drawing.Size(235, 22); - this.importTraceLogToolStripMenuItem.Text = "Import Trace Log..."; - this.importTraceLogToolStripMenuItem.Click += new System.EventHandler(this.ImportTraceLogToolStripMenuItem_Click); - // - // importUsageMapToolStripMenuItem - // - this.importUsageMapToolStripMenuItem.Enabled = false; - this.importUsageMapToolStripMenuItem.Name = "importUsageMapToolStripMenuItem"; - this.importUsageMapToolStripMenuItem.Size = new System.Drawing.Size(235, 22); - this.importUsageMapToolStripMenuItem.Text = "Import Usage Map..."; - this.importUsageMapToolStripMenuItem.Click += new System.EventHandler(this.ImportUsageMapToolStripMenuItem_Click); - // // toolStripSeparator7 // this.toolStripSeparator7.Name = "toolStripSeparator7"; @@ -1009,6 +997,44 @@ private void InitializeComponent() // this.openCDLDialog.Filter = "BizHawk Code Data Logger Files|*.cdl|All Files|*.*"; // + // importUsageMapToolStripMenuItem + // + this.importUsageMapToolStripMenuItem.Enabled = false; + this.importUsageMapToolStripMenuItem.Name = "importUsageMapToolStripMenuItem"; + this.importUsageMapToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.importUsageMapToolStripMenuItem.Text = "Import BSNES Usage Map..."; + this.importUsageMapToolStripMenuItem.Click += new System.EventHandler(this.importUsageMapToolStripMenuItem_Click_1); + // + // importTraceLogBinary + // + this.importTraceLogBinary.Enabled = false; + this.importTraceLogBinary.Name = "importTraceLogBinary"; + this.importTraceLogBinary.Size = new System.Drawing.Size(253, 22); + this.importTraceLogBinary.Text = "Import BSNES Trace Log (Binary)..."; + this.importTraceLogBinary.Click += new System.EventHandler(this.toolStripMenuItem1_Click); + // + // importTraceLogText + // + this.importTraceLogText.Enabled = false; + this.importTraceLogText.Name = "importTraceLogText"; + this.importTraceLogText.Size = new System.Drawing.Size(253, 22); + this.importTraceLogText.Text = "Import BSNES Trace Log..."; + this.importTraceLogText.Click += new System.EventHandler(this.toolStripMenuItem3_Click); + // + // importCDLToolStripMenuItem + // + this.importCDLToolStripMenuItem.Enabled = false; + this.importCDLToolStripMenuItem.Name = "importCDLToolStripMenuItem"; + this.importCDLToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.I))); + this.importCDLToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.importCDLToolStripMenuItem.Text = "Import CDL..."; + this.importCDLToolStripMenuItem.Click += new System.EventHandler(this.importCDLToolStripMenuItem_Click_1); + // + // toolStripSeparator8 + // + this.toolStripSeparator8.Name = "toolStripSeparator8"; + this.toolStripSeparator8.Size = new System.Drawing.Size(250, 6); + // // MainWindow // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); @@ -1050,7 +1076,6 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem saveProjectAsToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; private System.Windows.Forms.ToolStripMenuItem exportLogToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem importCDLToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem editToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem stepOverToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem stepInToolStripMenuItem; @@ -1110,11 +1135,9 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripStatusLabel currentMarker; private System.Windows.Forms.ToolStripMenuItem rescanForInOutPointsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem githubToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem importTraceLogToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem gotoNextUnreachedToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem optionsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem moveWithStepToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem importUsageMapToolStripMenuItem; private System.Windows.Forms.OpenFileDialog openUsageMapFile; private System.Windows.Forms.DataGridViewTextBoxColumn ColumnAlias; private System.Windows.Forms.DataGridViewTextBoxColumn ColumnPC; @@ -1129,11 +1152,17 @@ private void InitializeComponent() private System.Windows.Forms.DataGridViewTextBoxColumn ColumnM; private System.Windows.Forms.DataGridViewTextBoxColumn ColumnX; private System.Windows.Forms.DataGridViewTextBoxColumn ColumnComment; - private System.Windows.Forms.OpenFileDialog openTraceLogDialog; + public System.Windows.Forms.OpenFileDialog openTraceLogDialog; private System.Windows.Forms.ToolStripMenuItem labelListToolStripMenuItem; private System.Windows.Forms.OpenFileDialog openCDLDialog; private System.Windows.Forms.ToolStripMenuItem toolStripOpenLast; private System.Windows.Forms.ToolStripMenuItem openLastProjectAutomaticallyToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem2; + private System.Windows.Forms.ToolStripMenuItem importUsageMapToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem importCDLToolStripMenuItem; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator8; + private System.Windows.Forms.ToolStripMenuItem importTraceLogText; + private System.Windows.Forms.ToolStripMenuItem importTraceLogBinary; } } diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 2008a6af..99d2101e 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -267,35 +267,6 @@ private void saveProjectAsToolStripMenuItem_Click(object sender, EventArgs e) } } - private void importCDLToolStripMenuItem_Click(object sender, EventArgs e) - { - openCDLDialog.InitialDirectory = Project.ProjectFileName; - if (openCDLDialog.ShowDialog() != DialogResult.OK) - return; - - if (!ContinueUnsavedChanges()) - return; - - var filename = openCDLDialog.FileName; - - try - { - ProjectController.ImportBizHawkCDL(filename); - } - catch (InvalidDataException ex) - { - MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - catch (EndOfStreamException ex) - { - MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - - UpdatePercent(); - UpdateWindowTitle(); - InvalidateTable(); - } - public ProjectController ProjectController { get; protected set; } private void exportLogToolStripMenuItem_Click(object sender, EventArgs e) @@ -421,6 +392,8 @@ private int ViewOffset private int rowsToShow; + private bool importerMenuItemsEnabled; + private void UpdateDataGridView() { if (Project?.Data == null || Project.Data.GetROMSize() <= 0) @@ -439,8 +412,16 @@ private void UpdateDataGridView() vScrollBar1.Value = ViewOffset; table.RowCount = rowsToShow; - importTraceLogToolStripMenuItem.Enabled = true; - importUsageMapToolStripMenuItem.Enabled = true; + importerMenuItemsEnabled = true; + UpdateImporterEnabledStatus(); + } + + private void UpdateImporterEnabledStatus() + { + importUsageMapToolStripMenuItem.Enabled = importerMenuItemsEnabled; + importCDLToolStripMenuItem.Enabled = importerMenuItemsEnabled; + importTraceLogBinary.Enabled = importerMenuItemsEnabled; + importTraceLogText.Enabled = importerMenuItemsEnabled; } private void table_MouseWheel(object sender, MouseEventArgs e) @@ -1157,29 +1138,6 @@ private void labelListToolStripMenuItem_Click(object sender, EventArgs e) aliasList.Show(); } - private void ImportUsageMapToolStripMenuItem_Click(object sender, EventArgs e) - { - if (openUsageMapFile.ShowDialog() != DialogResult.OK) - return; - - var numModifiedFlags = ProjectController.ImportBSNESUsageMap(openUsageMapFile.FileName); - - MessageBox.Show($"Modified total {numModifiedFlags} flags!", "Done", - MessageBoxButtons.OK, MessageBoxIcon.Information); - } - - private void ImportTraceLogToolStripMenuItem_Click(object sender, EventArgs e) - { - openTraceLogDialog.Multiselect = true; - if (openTraceLogDialog.ShowDialog() != DialogResult.OK) - return; - - var numModifiedFlags = ProjectController.ImportBSNESTraceLogs(openUsageMapFile.FileNames); - - MessageBox.Show($"Modified total {numModifiedFlags} flags from {openTraceLogDialog.FileNames.Length} files!", "Done", - MessageBoxButtons.OK, MessageBoxIcon.Information); - } - private void openLastProjectAutomaticallyToolStripMenuItem_Click(object sender, EventArgs e) { Settings.Default.OpenLastFileAutomatically = openLastProjectAutomaticallyToolStripMenuItem.Checked; @@ -1209,5 +1167,72 @@ public void OnProjectOpenWarning(string warningMsg) { MessageBox.Show(warningMsg, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); } + + private void importUsageMapToolStripMenuItem_Click_1(object sender, EventArgs e) + { + if (openUsageMapFile.ShowDialog() != DialogResult.OK) + return; + + var numModifiedFlags = ProjectController.ImportBSNESUsageMap(openUsageMapFile.FileName); + + MessageBox.Show($"Modified total {numModifiedFlags} flags!", "Done", + MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + private void toolStripMenuItem3_Click(object sender, EventArgs e) + { + openTraceLogDialog.Multiselect = true; + if (openTraceLogDialog.ShowDialog() != DialogResult.OK) + return; + + var numModifiedFlags = ProjectController.ImportBSNESTraceLogs(openTraceLogDialog.FileNames); + + MessageBox.Show($"Modified total {numModifiedFlags} flags from {openTraceLogDialog.FileNames.Length} files!", "Done", + MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + private void toolStripMenuItem1_Click(object sender, EventArgs e) + { + /*openTraceLogDialog.Multiselect = true; + if (openTraceLogDialog.ShowDialog() != DialogResult.OK) + return; + + var numModifiedFlags = ProjectController.ImportBsnesTraceLogsBinary(openTraceLogDialog.FileNames); + + MessageBox.Show($"Modified total {numModifiedFlags} flags from {openTraceLogDialog.FileNames.Length} files!", "Done", + MessageBoxButtons.OK, MessageBoxIcon.Information);*/ + + var bsnesForm = new BSNESTraceLogBinaryMonitor(this); + bsnesForm.ShowDialog(); + } + + private void importCDLToolStripMenuItem_Click_1(object sender, EventArgs e) + { + openCDLDialog.InitialDirectory = Project.ProjectFileName; + if (openCDLDialog.ShowDialog() != DialogResult.OK) + return; + + if (!ContinueUnsavedChanges()) + return; + + var filename = openCDLDialog.FileName; + + try + { + ProjectController.ImportBizHawkCDL(filename); + } + catch (InvalidDataException ex) + { + MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + catch (EndOfStreamException ex) + { + MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + UpdatePercent(); + UpdateWindowTitle(); + InvalidateTable(); + } } } \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.Designer.cs b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.Designer.cs new file mode 100644 index 00000000..9fadac5f --- /dev/null +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.Designer.cs @@ -0,0 +1,196 @@ +namespace DiztinGUIsh.window.dialog +{ + partial class BSNESTraceLogBinaryMonitor + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.button1 = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.lblQueuSize = new System.Windows.Forms.Label(); + this.backgroundWorker1_pipeReader = new System.ComponentModel.BackgroundWorker(); + this.timer1 = new System.Windows.Forms.Timer(this.components); + this.backgroundWorker2_processQueue = new System.ComponentModel.BackgroundWorker(); + this.btnCancel = new System.Windows.Forms.Button(); + this.lblTotalProcessed = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.lblStatus = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.lblNumberModified = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // button1 + // + this.button1.Location = new System.Drawing.Point(12, 130); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(94, 23); + this.button1.TabIndex = 0; + this.button1.Text = "Start importing"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(9, 32); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(60, 13); + this.label1.TabIndex = 1; + this.label1.Text = "Queue size"; + // + // lblQueuSize + // + this.lblQueuSize.AutoSize = true; + this.lblQueuSize.Location = new System.Drawing.Point(112, 32); + this.lblQueuSize.Name = "lblQueuSize"; + this.lblQueuSize.Size = new System.Drawing.Size(13, 13); + this.lblQueuSize.TabIndex = 2; + this.lblQueuSize.Text = "--"; + // + // backgroundWorker1_pipeReader + // + this.backgroundWorker1_pipeReader.WorkerSupportsCancellation = true; + this.backgroundWorker1_pipeReader.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork); + this.backgroundWorker1_pipeReader.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_pipeReader_RunWorkerCompleted); + // + // timer1 + // + this.timer1.Interval = 500; + this.timer1.Tick += new System.EventHandler(this.timer1_Tick); + // + // backgroundWorker2_processQueue + // + this.backgroundWorker2_processQueue.WorkerSupportsCancellation = true; + this.backgroundWorker2_processQueue.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker2_processQueue_DoWork); + this.backgroundWorker2_processQueue.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker2_processQueue_RunWorkerCompleted_1); + // + // btnCancel + // + this.btnCancel.Enabled = false; + this.btnCancel.Location = new System.Drawing.Point(112, 130); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(66, 23); + this.btnCancel.TabIndex = 3; + this.btnCancel.Text = "Finish"; + this.btnCancel.UseVisualStyleBackColor = true; + this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); + // + // lblTotalProcessed + // + this.lblTotalProcessed.AutoSize = true; + this.lblTotalProcessed.Location = new System.Drawing.Point(113, 52); + this.lblTotalProcessed.Name = "lblTotalProcessed"; + this.lblTotalProcessed.Size = new System.Drawing.Size(13, 13); + this.lblTotalProcessed.TabIndex = 6; + this.lblTotalProcessed.Text = "--"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(10, 52); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(89, 13); + this.label4.TabIndex = 5; + this.label4.Text = "# Bytes Analyzed"; + // + // lblStatus + // + this.lblStatus.AutoSize = true; + this.lblStatus.Location = new System.Drawing.Point(113, 12); + this.lblStatus.Name = "lblStatus"; + this.lblStatus.Size = new System.Drawing.Size(13, 13); + this.lblStatus.TabIndex = 8; + this.lblStatus.Text = "--"; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(10, 12); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(37, 13); + this.label5.TabIndex = 7; + this.label5.Text = "Status"; + // + // lblNumberModified + // + this.lblNumberModified.AutoSize = true; + this.lblNumberModified.Location = new System.Drawing.Point(112, 104); + this.lblNumberModified.Name = "lblNumberModified"; + this.lblNumberModified.Size = new System.Drawing.Size(13, 13); + this.lblNumberModified.TabIndex = 10; + this.lblNumberModified.Text = "--"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(9, 104); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(86, 13); + this.label3.TabIndex = 9; + this.label3.Text = "# Bytes Modified"; + // + // BSNESTraceLogBinaryMonitor + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(199, 163); + this.Controls.Add(this.lblNumberModified); + this.Controls.Add(this.label3); + this.Controls.Add(this.lblStatus); + this.Controls.Add(this.label5); + this.Controls.Add(this.lblTotalProcessed); + this.Controls.Add(this.label4); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.lblQueuSize); + this.Controls.Add(this.label1); + this.Controls.Add(this.button1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.Name = "BSNESTraceLogBinaryMonitor"; + this.Text = "BSNES Live Tracelog Capture"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label lblQueuSize; + private System.ComponentModel.BackgroundWorker backgroundWorker1_pipeReader; + private System.Windows.Forms.Timer timer1; + private System.ComponentModel.BackgroundWorker backgroundWorker2_processQueue; + private System.Windows.Forms.Button btnCancel; + private System.Windows.Forms.Label lblTotalProcessed; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label lblStatus; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label lblNumberModified; + private System.Windows.Forms.Label label3; + } +} \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.cs b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.cs new file mode 100644 index 00000000..ccaf3d7b --- /dev/null +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Concurrent; +using System.ComponentModel; +using System.Diagnostics; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Windows.Forms; +using Diz.Core.import; + +namespace DiztinGUIsh.window.dialog +{ + public partial class BSNESTraceLogBinaryMonitor : Form + { + private MainWindow MainWindow; + private CancellationTokenSource cancelToken; + private BSNESTraceLogImporter importer; + + // caution: thread safety for next items: + private BlockingCollection queue; + private int totalModified; + private int totalAnalyzed; + // end thread safety + + public BSNESTraceLogBinaryMonitor(MainWindow window) + { + MainWindow = window; + InitializeComponent(); + } + + private void button1_Click(object sender, EventArgs e) + { + importer = new BSNESTraceLogImporter(MainWindow.Project.Data); + cancelToken = new CancellationTokenSource(); + queue = new BlockingCollection(); + + totalModified = 0; + totalAnalyzed = 0; + + backgroundWorker1_pipeReader.RunWorkerAsync(); + backgroundWorker2_processQueue.RunWorkerAsync(); + + timer1.Enabled = true; + btnCancel.Enabled = true; + button1.Enabled = false; + } + + private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) + { + var bytes = new byte[22]; + + var tcpClient = new TcpClient(); + var ipEndPoint = new IPEndPoint(IPAddress.Loopback, 27015); + + tcpClient.Connect(ipEndPoint); + + var networkStream = tcpClient.GetStream(); + + while (!backgroundWorker1_pipeReader.CancellationPending) + { + var bytesRead = networkStream.Read(bytes, 0, bytes.Length); + if (bytesRead <= 0) + return; + queue.Add(bytes); + } + } + + private void backgroundWorker2_processQueue_DoWork(object sender, DoWorkEventArgs e) + { + while (!backgroundWorker2_processQueue.CancellationPending) + { + try + { + var bytes = queue.Take(cancelToken.Token); + Debug.Assert(bytes.Length == 22); + var (numChanged, numLinesAnalyzed) = importer.ImportTraceLogLineBinary(bytes); + totalModified += numChanged; + totalAnalyzed += numLinesAnalyzed; + } + catch (OperationCanceledException) + { + return; + } + } + } + + private void timer1_Tick(object sender, EventArgs e) + { + UpdateUI(); + } + + private void btnCancel_Click(object sender, EventArgs e) + { + btnCancel.Enabled = false; + button1.Enabled = true; + + cancelToken.Cancel(); + backgroundWorker1_pipeReader.CancelAsync(); + backgroundWorker2_processQueue.CancelAsync(); + + timer1.Enabled = false; + } + + private void backgroundWorker2_processQueue_RunWorkerCompleted_1(object sender, RunWorkerCompletedEventArgs e) + { + UpdateUI(); + } + + private void backgroundWorker1_pipeReader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) + { + UpdateUI(); + } + + private void UpdateUI() + { + lblQueuSize.Text = queue.Count.ToString(); + var running = backgroundWorker2_processQueue != null && backgroundWorker1_pipeReader != null; + var cancelling = cancelToken?.IsCancellationRequested ?? false; + + lblTotalProcessed.Text = totalAnalyzed.ToString(); + lblNumberModified.Text = totalModified.ToString(); + + lblStatus.Text = !running ? "Not running" : !cancelling ? "Stopping..." : "Running"; + + btnCancel.Enabled = running && !cancelling; + button1.Enabled = !running; + } + } +} \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.resx b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.resx new file mode 100644 index 00000000..fa949fe4 --- /dev/null +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 248, 17 + + + 335, 17 + + + 108 + + \ No newline at end of file From c4739146a2a769017bdfe98fca297ce5f62aad1c Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Thu, 15 Oct 2020 08:40:11 -0400 Subject: [PATCH 093/136] better modification detection --- Diz.Core/import/BSNESImporter.cs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/Diz.Core/import/BSNESImporter.cs b/Diz.Core/import/BSNESImporter.cs index c3a13c4f..11b1ee5e 100644 --- a/Diz.Core/import/BSNESImporter.cs +++ b/Diz.Core/import/BSNESImporter.cs @@ -254,26 +254,30 @@ int GetHexValueAt(int startIndex, int length) do { var flagType = currentIndex == 0 ? Data.FlagType.Opcode : Data.FlagType.Operand; - var modified = false; + // this code could be simplified, but, makes it easier to see + // exactly what is changing + var oldFlag = Data.GetFlag(pc); + var oldDB = Data.GetDataBank(pc); + var oldDP = Data.GetDirectPage(pc); + var oldXflag = Data.GetXFlag(pc); + var oldMFlag = Data.GetMFlag(pc); + + var modified = + oldFlag != flagType || + oldDB != dataBank || + oldDP != directPage || + oldXflag != xflagSet || + oldMFlag != mflagSet; - modified |= Data.GetFlag(pc) != flagType; - Data.SetFlag(pc, flagType); + if (modified) + totalModified++; - modified |= Data.GetDataBank(pc) != dataBank; + Data.SetFlag(pc, flagType); Data.SetDataBank(pc, dataBank); - - modified |= Data.GetDirectPage(pc) != directPage; Data.SetDirectPage(pc, directPage); - - modified |= Data.GetXFlag(pc) != xflagSet; Data.SetXFlag(pc, xflagSet); - - modified |= Data.GetMFlag(pc) != mflagSet; Data.SetMFlag(pc, mflagSet); - if (modified) - totalModified++; - pc++; // note: should we check for crossing banks? probably should stop there. currentIndex++; From 41369201fa3be0e23bae1600223f561838a426f2 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Thu, 15 Oct 2020 11:18:15 -0400 Subject: [PATCH 094/136] comment --- Diz.Core/import/BSNESImporter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Diz.Core/import/BSNESImporter.cs b/Diz.Core/import/BSNESImporter.cs index 11b1ee5e..1c179442 100644 --- a/Diz.Core/import/BSNESImporter.cs +++ b/Diz.Core/import/BSNESImporter.cs @@ -262,6 +262,7 @@ int GetHexValueAt(int startIndex, int length) var oldXflag = Data.GetXFlag(pc); var oldMFlag = Data.GetMFlag(pc); + // note: we'll sometimes get false positives because of the mirroring in DP and DB. var modified = oldFlag != flagType || oldDB != dataBank || From 51f24048147672dc6a7f508b8362f84355e30e91 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 17 Oct 2020 15:09:05 -0400 Subject: [PATCH 095/136] implement working version of socket capture from BSNES --- Diz.Core/Diz.Core.csproj | 4 +- Diz.Core/arch/CPU65C816.cs | 11 + Diz.Core/import/BSNESImporter.cs | 300 --------------- Diz.Core/import/BSNESTraceLogCapture.cs | 211 ++++++++++ Diz.Core/import/BSNESTraceLogImporter.cs | 290 ++++++++++++++ Diz.Core/import/BSNESUsageMapImporter.cs | 76 ++++ Diz.Core/util/RomUtil.cs | 10 + DiztinGUIsh/DiztinGUIsh.csproj | 12 +- DiztinGUIsh/Program.cs | 34 +- DiztinGUIsh/controller/ProjectController.cs | 19 +- DiztinGUIsh/window/MainWindow.Designer.cs | 4 +- DiztinGUIsh/window/MainWindow.cs | 7 +- .../BSNESTraceLogBinaryMonitor.Designer.cs | 196 ---------- .../dialog/BSNESTraceLogBinaryMonitor.cs | 129 ------- ...BSNESTraceLogBinaryMonitorForm.Designer.cs | 359 ++++++++++++++++++ .../dialog/BSNESTraceLogBinaryMonitorForm.cs | 90 +++++ ...sx => BSNESTraceLogBinaryMonitorForm.resx} | 15 +- 17 files changed, 1089 insertions(+), 678 deletions(-) delete mode 100644 Diz.Core/import/BSNESImporter.cs create mode 100644 Diz.Core/import/BSNESTraceLogCapture.cs create mode 100644 Diz.Core/import/BSNESTraceLogImporter.cs create mode 100644 Diz.Core/import/BSNESUsageMapImporter.cs delete mode 100644 DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.Designer.cs delete mode 100644 DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.cs create mode 100644 DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.Designer.cs create mode 100644 DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs rename DiztinGUIsh/window/dialog/{BSNESTraceLogBinaryMonitor.resx => BSNESTraceLogBinaryMonitorForm.resx} (87%) diff --git a/Diz.Core/Diz.Core.csproj b/Diz.Core/Diz.Core.csproj index b05ab383..adae8bfb 100644 --- a/Diz.Core/Diz.Core.csproj +++ b/Diz.Core/Diz.Core.csproj @@ -114,9 +114,11 @@ + + - + diff --git a/Diz.Core/arch/CPU65C816.cs b/Diz.Core/arch/CPU65C816.cs index c1cb5ba7..78430c4b 100644 --- a/Diz.Core/arch/CPU65C816.cs +++ b/Diz.Core/arch/CPU65C816.cs @@ -41,6 +41,17 @@ public int Step(int offset, bool branch, bool force, int prevOffset) var length = GetInstructionLength(offset); + // TODO: I don't think this is handling execution bank boundary wrapping correctly? -Dom + // If we run over the edge of a bank, we need to go back to the beginning of that bank, not go into + // the next one. While this should be really rare, it's technically valid. + // + // docs: http://www.6502.org/tutorials/65c816opcodes.html#5.1.2 + // [Note that although the 65C816 has a 24-bit address space, the Program Counter is only a 16-bit register and + // the Program Bank Register is a separate (8-bit) register. This means that instruction execution wraps at bank + // boundaries. This is true even if the bank boundary occurs in the middle of the instruction.] + // + // TODO: check other areas, anywhere we're accessing a Rom address plus some offset, might need to wrap + // in most situations. for (var i = 1; i < length; i++) { Data.SetFlag(offset + i, Data.FlagType.Operand); diff --git a/Diz.Core/import/BSNESImporter.cs b/Diz.Core/import/BSNESImporter.cs deleted file mode 100644 index 1c179442..00000000 --- a/Diz.Core/import/BSNESImporter.cs +++ /dev/null @@ -1,300 +0,0 @@ -using System; -using System.Diagnostics; -using System.Runtime.ExceptionServices; -using Diz.Core.model; -using Diz.Core.util; - -namespace Diz.Core.import -{ - public class BSNESUsageMapImporter - { - // TODO: move BsnesPlusUsage stuff to its own class outside of Data - [Flags] - public enum BsnesPlusUsage : byte - { - UsageRead = 0x80, - UsageWrite = 0x40, - UsageExec = 0x20, - UsageOpcode = 0x10, - UsageFlagM = 0x02, - UsageFlagX = 0x01, - }; - - // move out of here to extension method or just external method - public int ImportUsageMap(byte[] usageMap, Data data) - { - int size = data.GetROMSize(); - int modified = 0; - int prevFlags = 0; - - for (int map = 0; map <= 0xFFFFFF; map++) - { - var i = data.ConvertSNEStoPC(map); - - if (i == -1 || i >= size) - { - // branch predictor may optimize this - continue; - } - - var flags = (BsnesPlusUsage) usageMap[map]; - - if (flags == 0) - { - // no information available - continue; - } - - if (data.GetFlag(i) != Data.FlagType.Unreached) - { - // skip if there is something already set.. - continue; - } - - // opcode: 0x30, operand: 0x20 - if (flags.HasFlag(BsnesPlusUsage.UsageExec)) - { - data.SetFlag(i, Data.FlagType.Operand); - - if (flags.HasFlag(BsnesPlusUsage.UsageOpcode)) - { - prevFlags = ((int) flags & 3) << 4; - data.SetFlag(i, Data.FlagType.Opcode); - } - - data.SetMXFlags(i, prevFlags); - modified++; - } - else if (flags.HasFlag(BsnesPlusUsage.UsageRead)) - { - data.SetFlag(i, Data.FlagType.Data8Bit); - modified++; - } - } - - return modified; - } - } - - public class BSNESTraceLogImporter - { - private readonly Data Data; - int romSize; - - public BSNESTraceLogImporter(Data data) - { - Data = data; - romSize = Data.GetROMSize(); - } - - // this class exists for performance optimization ONLY. - // class representing offsets into a trace log - // we calculate it once from sample data and hang onto it - private class CachedTraceLineIndex - { - // NOTE: newer versions of BSNES use different text for flags. check for completeness. - private string sample = - "028cde rep #$30 A:0004 X:0000 Y:0004 S:1fdd D:0000 DB:02 nvmxdiZC V:133 H: 654 F:36"; - - // index of the start of the info - public readonly int - addr, - D, - DB, - flags, - f_N, - f_V, - f_M, - f_X, - f_D, - f_I, - f_Z, - f_C; - - public CachedTraceLineIndex() - { - int SkipToken(string token) - { - return sample.IndexOf(token) + token.Length; - } - - addr = 0; - D = SkipToken("D:"); - DB = SkipToken("DB:"); - flags = DB + 3; - - // flags: nvmxdizc - f_N = flags + 0; - f_V = flags + 1; - f_M = flags + 2; - f_X = flags + 3; - f_D = flags + 4; - f_I = flags + 5; - f_Z = flags + 6; - f_C = flags + 7; - } - } - - private static readonly CachedTraceLineIndex CachedIdx = new CachedTraceLineIndex(); - - public (int numChanged, int numLinesAnalyzed) ImportTraceLogLine(string line) - { - // caution: very performance-sensitive function, please take care when making modifications - // string.IndexOf() is super-slow too. - // Input lines must follow this strict format and be this exact formatting and column indices. - // 028cde rep #$30 A:0004 X:0000 Y:0004 S:1fdd D:0000 DB:02 nvmxdiZC V:133 H: 654 F:36 - - int GetHexValueAt(int startIndex, int length) - { - return Convert.ToInt32(line.Substring(startIndex, length), 16); - } - - if (line.Length < 80) - return (0,0); - - int snesAddress = GetHexValueAt(0, 6); - int pc = Data.ConvertSNEStoPC(snesAddress); - if (pc == -1) - return (0, 0); - - // TODO: error treatment / validation - - int directPage = GetHexValueAt(CachedIdx.D, 4); - int dataBank = GetHexValueAt(CachedIdx.DB, 2); - - // 'X' = unchecked in bsnesplus debugger UI = (8bit), 'x' or '.' = checked (16bit) - bool xflag_set = line[CachedIdx.f_X] == 'X'; - - // 'M' = unchecked in bsnesplus debugger UI = (8bit), 'm' or '.' = checked (16bit) - bool mflag_set = line[CachedIdx.f_M] == 'M'; - - return SetFromTraceData(pc, dataBank, directPage, xflag_set, mflag_set); - } - - // this is same as above but, reads the same data from a binary format. this is for - // performance reasons to try and stream the data live from BSNES - public (int numChanged, int numLinesAnalyzed) ImportTraceLogLineBinary(byte[] bytes) - { - // extremely performance-intensive function. be really careful when adding stuff - - Debug.Assert(bytes.Length == 22); - var pointer = 0; - - // ----------------------------- - - var watermark = bytes[pointer++]; - if (watermark != 0xEE) - return (0, 0); - - var snesAddress = ByteUtil.ByteArrayToInt24(bytes, pointer); - pointer += 3; - - var pc = Data.ConvertSNEStoPC(snesAddress); - if (pc == -1) - return (0, 0); - - var opcodeLen = bytes[pointer++]; - - // skip opcodes. NOTE: must read all 5 butes but only use up to 'opcode_len' bytes - //var op = bytes[pointer++]; - //var op0 = bytes[pointer++]; - //var op1 = bytes[pointer++]; - //var op2 = bytes[pointer++]; - pointer += 4; - - // skip A register - pointer += 2; - - // skip X register - pointer += 2; - - // skip Y register - pointer += 2; - - // skip S register - pointer += 2; - - var directPage = ByteUtil.ByteArrayToInt24(bytes, pointer); - pointer += 2; - - var dataBank = bytes[pointer++]; - - // skip, flag 'e' for emulation mode or not - // var emuFlag = bytes[pointer++] == 0x01; - pointer++; - - // the real flags, we mainly care about X and M - var flags = bytes[pointer++]; - // n = flags & 0x80; - // v = flags & 0x40; - // m = flags & 0x20; - // d = flags & 0x08; - // i = flags & 0x04; - // z = flags & 0x02; - // c = flags & 0x01; - var xflagSet = (flags & 0x10) != 0; - var mflagSet = (flags & 0x20) != 0; - - Debug.Assert(pointer == bytes.Length); - - return SetFromTraceData(pc, dataBank, directPage, xflagSet, mflagSet, opcodeLen); - } - - // returns the number of bytes actually changed - private (int numChanged, int numLinesAnalyzed) SetFromTraceData(int pc, int dataBank, int directPage, bool xflagSet, bool mflagSet, - int opcodeLen = -1) - { - // extremely performance-intensive function. be really careful when adding stuff - - // set this data for us and any following operands - var currentIndex = 0; - var totalModified = 0; - bool keepGoing; - - do { - var flagType = currentIndex == 0 ? Data.FlagType.Opcode : Data.FlagType.Operand; - - // this code could be simplified, but, makes it easier to see - // exactly what is changing - var oldFlag = Data.GetFlag(pc); - var oldDB = Data.GetDataBank(pc); - var oldDP = Data.GetDirectPage(pc); - var oldXflag = Data.GetXFlag(pc); - var oldMFlag = Data.GetMFlag(pc); - - // note: we'll sometimes get false positives because of the mirroring in DP and DB. - var modified = - oldFlag != flagType || - oldDB != dataBank || - oldDP != directPage || - oldXflag != xflagSet || - oldMFlag != mflagSet; - - if (modified) - totalModified++; - - Data.SetFlag(pc, flagType); - Data.SetDataBank(pc, dataBank); - Data.SetDirectPage(pc, directPage); - Data.SetXFlag(pc, xflagSet); - Data.SetMFlag(pc, mflagSet); - - pc++; // note: should we check for crossing banks? probably should stop there. - currentIndex++; - - if (opcodeLen != -1) - { - // we know the # of bytes that should follow our opcode, so mark that many bytes - keepGoing = currentIndex < opcodeLen; - } - else - { - // only continue if the next bytes were already marked as operands - keepGoing = Data.GetFlag(pc) == Data.FlagType.Operand; - } - } while (pc < romSize && keepGoing); - - return (totalModified, currentIndex); - } - } -} diff --git a/Diz.Core/import/BSNESTraceLogCapture.cs b/Diz.Core/import/BSNESTraceLogCapture.cs new file mode 100644 index 00000000..e396b8a4 --- /dev/null +++ b/Diz.Core/import/BSNESTraceLogCapture.cs @@ -0,0 +1,211 @@ +using System; +using System.Collections.Concurrent; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using Diz.Core.import; +using Diz.Core.model; + +namespace DiztinGUIsh.window.dialog +{ + public class BSNESTraceLogCapture + { + private CancellationTokenSource cancelToken; + private BackgroundWorker socketWorker, dataWorker; + + private BlockingCollection queue; // thread-safe + public int QueueLength => queue?.Count ?? 0; + + public bool Running => dataWorker != null && socketWorker != null; + + public event EventHandler Finished; + + public delegate void ThreadErrorEvent(Exception e); + public event ThreadErrorEvent Error; + public bool Finishing { get; protected set; } + + // keep thread safety in mind for variables below this line + + private readonly ReaderWriterLockSlim importerLock = new ReaderWriterLockSlim(); + private BSNESTraceLogImporter importer; + private BSNESTraceLogImporter.Stats cachedStats; + public BSNESTraceLogImporter.Stats GetStats() + { + if (importer == null) + return cachedStats; + + try + { + importerLock.EnterReadLock(); + cachedStats = importer.CurrentStats; + } + finally + { + importerLock.ExitReadLock(); + } + + return cachedStats; + } + + public void Start(Data data) + { + importer = new BSNESTraceLogImporter(data); + + cancelToken = new CancellationTokenSource(); + queue = new BlockingCollection(); + + socketWorker = new BackgroundWorker(); + dataWorker = new BackgroundWorker(); + + socketWorker.DoWork += SocketWorker_DoWork; + dataWorker.DoWork += DataWorker_DoWork; + + socketWorker.WorkerSupportsCancellation = dataWorker.WorkerSupportsCancellation = true; + + socketWorker.RunWorkerCompleted += SocketWorker_RunWorkerCompleted; + dataWorker.RunWorkerCompleted += DataWorker_RunWorkerCompleted; + + Thread.MemoryBarrier(); + + socketWorker.RunWorkerAsync(); + dataWorker.RunWorkerAsync(); + } + + private void SocketWorker_DoWork(object sender, DoWorkEventArgs e) + { + var tcpClient = new TcpClient(); + var ipEndPoint = new IPEndPoint(IPAddress.Loopback, 27015); + + tcpClient.Connect(ipEndPoint); + var networkStream = tcpClient.GetStream(); + + while (!socketWorker.CancellationPending && !cancelToken.IsCancellationRequested) + { + // perf: huge volume of data coming in. + // need to get the data read from the server as fast as possible. + // do minimal processing here then dump it over to the other thread for real processing. + ReadNextFromSocket(networkStream); + } + } + + private void ReadNextFromSocket(Stream networkStream) + { + var buffer = ReadNext(networkStream, 2, out var bytesRead); + Debug.Assert(buffer.Length == 2); + + const byte expectedWatermark = 0xEE; + if (buffer[0] != expectedWatermark) { + throw new InvalidDataException($"expected header of 0xEE, got {buffer[0]} instead."); + } + + int amountToRead = buffer[1]; + Debug.Assert(amountToRead == 21); + + buffer = ReadNext(networkStream, amountToRead, out bytesRead); + queue.Add(buffer); + } + + private static byte[] ReadNext(Stream networkStream, int count, out int bytesRead) + { + var buffer = new byte[count]; + bytesRead = 0; + var offset = 0; + + while (count > 0 && (bytesRead = networkStream.Read(buffer, offset, count)) > 0) + { + count -= bytesRead; + offset += bytesRead; + } + + if (count > 0) + throw new EndOfStreamException(); + + return buffer; + } + + private void DataWorker_DoWork(object sender, DoWorkEventArgs e) + { + while (!dataWorker.CancellationPending && !cancelToken.IsCancellationRequested) + { + try + { + // TODO: use cancelToken here instead of timeout. (can't get it to work right now...) + if (!queue.TryTake(out var bytes, 100)) + continue; + + try + { + importerLock.EnterWriteLock(); + importer.ImportTraceLogLineBinary(bytes); + } + finally + { + importerLock.ExitWriteLock(); + } + } + catch (OperationCanceledException) + { + return; + } + } + } + + public void SignalToStop() + { + Finishing = true; + + cancelToken.Cancel(false); + socketWorker.CancelAsync(); + dataWorker.CancelAsync(); + } + + private void DataWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) + { + dataWorker = null; + OnAnyThreadFinished(e); + } + + private void SocketWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) + { + socketWorker = null; + OnAnyThreadFinished(e); + } + + private void OnAnyThreadFinished(RunWorkerCompletedEventArgs e) + { + if (e.Error != null) + OnThreadError(e.Error); + + SignalIfFinished(); + } + + private void SignalIfFinished() + { + if (dataWorker == null && socketWorker == null) + OnFinished(); + } + + protected virtual void OnFinished() + { + Finishing = false; + + importer = null; + + cancelToken = null; + queue = null; + socketWorker = dataWorker = null; + + Thread.MemoryBarrier(); + + Finished?.Invoke(this, EventArgs.Empty); + } + + protected virtual void OnThreadError(Exception e) + { + Error?.Invoke(e); + } + } +} \ No newline at end of file diff --git a/Diz.Core/import/BSNESTraceLogImporter.cs b/Diz.Core/import/BSNESTraceLogImporter.cs new file mode 100644 index 00000000..3f8e8824 --- /dev/null +++ b/Diz.Core/import/BSNESTraceLogImporter.cs @@ -0,0 +1,290 @@ +using System; +using System.Diagnostics; +using System.IO; +using Diz.Core.model; +using Diz.Core.util; + +namespace Diz.Core.import +{ + public class BSNESTraceLogImporter + { + private Data Data; + int romSize; + public struct Stats + { + public long numRomBytesAnalyzed; + public long numRomBytesModified; + + public long numXFlagsModified; + public long numMFlagsModified; + public long numDBModified; + public long numDpModified; + public long numMarksModified; + } + + public Stats CurrentStats; + + public Data GetData() + { + return Data; + } + + public BSNESTraceLogImporter(Data data) + { + Data = data; + romSize = Data.GetROMSize(); + + CurrentStats.numRomBytesAnalyzed = 0; + CurrentStats.numRomBytesModified = 0; + CurrentStats.numXFlagsModified = 0; + CurrentStats.numMFlagsModified = 0; + CurrentStats.numDBModified = 0; + CurrentStats.numDpModified = 0; + CurrentStats.numMarksModified = 0; + } + + // this class exists for performance optimization ONLY. + // class representing offsets into a trace log + // we calculate it once from sample data and hang onto it + private class CachedTraceLineIndex + { + // NOTE: newer versions of BSNES use different text for flags. check for completeness. + private string sample = + "028cde rep #$30 A:0004 X:0000 Y:0004 S:1fdd D:0000 DB:02 nvmxdiZC V:133 H: 654 F:36"; + + // index of the start of the info + public readonly int + addr, + D, + DB, + flags, + f_N, + f_V, + f_M, + f_X, + f_D, + f_I, + f_Z, + f_C; + + public CachedTraceLineIndex() + { + int SkipToken(string token) + { + return sample.IndexOf(token) + token.Length; + } + + addr = 0; + D = SkipToken("D:"); + DB = SkipToken("DB:"); + flags = DB + 3; + + // flags: nvmxdizc + f_N = flags + 0; + f_V = flags + 1; + f_M = flags + 2; + f_X = flags + 3; + f_D = flags + 4; + f_I = flags + 5; + f_Z = flags + 6; + f_C = flags + 7; + } + } + + private static readonly CachedTraceLineIndex CachedIdx = new CachedTraceLineIndex(); + + public void ImportTraceLogLine(string line) + { + // caution: very performance-sensitive function, please take care when making modifications + // string.IndexOf() is super-slow too. + // Input lines must follow this strict format and be this exact formatting and column indices. + // 028cde rep #$30 A:0004 X:0000 Y:0004 S:1fdd D:0000 DB:02 nvmxdiZC V:133 H: 654 F:36 + + int GetHexValueAt(int startIndex, int length) + { + return Convert.ToInt32(line.Substring(startIndex, length), 16); + } + + if (line.Length < 80) + return; + + var snesAddress = GetHexValueAt(0, 6); + + // TODO: error treatment / validation + + var directPage = GetHexValueAt(CachedIdx.D, 4); + var dataBank = GetHexValueAt(CachedIdx.DB, 2); + + // 'X' = unchecked in bsnesplus debugger UI = (8bit), 'x' or '.' = checked (16bit) + var xflag_set = line[CachedIdx.f_X] == 'X'; + + // 'M' = unchecked in bsnesplus debugger UI = (8bit), 'm' or '.' = checked (16bit) + var mflag_set = line[CachedIdx.f_M] == 'M'; + + SetOpcodeAndOperandsFromTraceData(snesAddress, dataBank, directPage, xflag_set, mflag_set); + } + + // this is same as above but, reads the same data from a binary format. this is for + // performance reasons to try and stream the data live from BSNES + public void ImportTraceLogLineBinary(byte[] bytes) + { + // extremely performance-intensive function. be really careful when adding stuff + + Debug.Assert(bytes.Length == 21); + var pointer = 0; + + // ----------------------------- + var snesAddress = ByteUtil.ByteArrayToInt24(bytes, pointer); + pointer += 3; + + var opcodeLen = bytes[pointer++]; + + // skip opcodes. NOTE: must read all 5 bytes but only use up to 'opcode_len' bytes + //var op = bytes[pointer++]; + //var op0 = bytes[pointer++]; + //var op1 = bytes[pointer++]; + //var op2 = bytes[pointer++]; + pointer += 4; + + // skip A register + pointer += 2; + + // skip X register + pointer += 2; + + // skip Y register + pointer += 2; + + // skip S register + pointer += 2; + + var directPage = ByteUtil.ByteArrayToInt16(bytes, pointer); + pointer += 2; + + var dataBank = bytes[pointer++]; + + // skip, flag 'e' for emulation mode or not + // var emuFlag = bytes[pointer++] == 0x01; + pointer++; + + // the real flags, we mainly care about X and M + var flags = bytes[pointer++]; + // n = flags & 0x80; + // v = flags & 0x40; + // m = flags & 0x20; + // d = flags & 0x08; + // i = flags & 0x04; + // z = flags & 0x02; + // c = flags & 0x01; + var xflagSet = (flags & 0x10) != 0; + var mflagSet = (flags & 0x20) != 0; + + Debug.Assert(pointer == bytes.Length); + + SetOpcodeAndOperandsFromTraceData(snesAddress, dataBank, directPage, xflagSet, mflagSet, opcodeLen); + } + + // Mark collected trace data for a RomByte (which should be an opcode) AND any of the operands that follow us. + private void SetOpcodeAndOperandsFromTraceData( + int snesAddress, int dataBank, int directPage, + bool xflagSet, bool mflagSet, + int opcodeLen = -1) + { + // extremely performance-intensive function. be really careful when adding stuff + var currentIndex = 0; + + while (true) + { + if (!SetOneRomByteFromTraceData(snesAddress, dataBank, directPage, xflagSet, mflagSet, opcodeLen, currentIndex)) + break; + + snesAddress = RomUtil.CalculateSNESOffsetWithWrap(snesAddress, 1); + currentIndex++; + } + } + + private bool SetOneRomByteFromTraceData(int snesAddress, int dataBank, int directPage, bool xflagSet, bool mflagSet, + int opcodeLen, int currentIndex) + { + CurrentStats.numRomBytesAnalyzed++; + + var pc = Data.ConvertSNEStoPC(snesAddress); + if (!IsOKToSetThisRomByte(pc, currentIndex, opcodeLen)) + return false; + + var flagType = currentIndex == 0 ? Data.FlagType.Opcode : Data.FlagType.Operand; + + LogStats(pc, dataBank, directPage, xflagSet, mflagSet, flagType); + + // TODO: it doesn't hurt anything but, banks come back mirrored sometimes, + // would be cool to find a way to do the right thing and deal with the mirroring so we're not + // flipping and re-flipping bytes, but still maintain correctness with the game itself. + + // actually do the update + Data.SetFlag(pc, flagType); + Data.SetDataBank(pc, dataBank); + Data.SetDirectPage(pc, directPage); + Data.SetXFlag(pc, xflagSet); + Data.SetMFlag(pc, mflagSet); + + return true; + } + + private bool IsOKToSetThisRomByte(int pc, int opIndex, int instructionByteLen) + { + if (pc < 0 || pc >= romSize) + return false; + + if (instructionByteLen != -1 && (instructionByteLen < 1 || instructionByteLen > 4)) + { + throw new InvalidDataException($"Inavalid opcode+operand byte length {instructionByteLen}. Must be -1, or between 1 and 4"); + } + if (opIndex < 0 || opIndex > 4) // yes, 4, not 3. it'll bail below + { + throw new InvalidDataException($"Inavalid opcode index {opIndex}. Must be between 0 and 4"); + } + + if (instructionByteLen != -1) + { + // just make sure we're in range if we know the amount of bytes we need to process + return opIndex < instructionByteLen; + } + else + { + // we don't know how many bytes to process, so have to do some fuzzy guessing now. play it safe. + + // easy: this is the first byte, this will be the Opcode, so clear that for takeoff. + if (opIndex == 0) + return true; + + // otherwise, this is NOT the first byte (Opcode), and we don't have information about how many bytes + // past us are Operands. Could be none, could be up to 3. + // + // We're trying to mark as many bytes as operands with the flags from the tracelog. + // We can't safely know though, so, unless they've ALREADY been marked as Operands, let's + // just play it safe and stop at the first thing that's NOT an Operand. + // + // Calling code should ideally not let us get to here, and instead supply us with a valid instructionByteLen + return Data.GetFlag(pc) == Data.FlagType.Operand; + } + } + + private void LogStats(int pc, int dataBank, int directPage, bool xflagSet, bool mflagSet, Data.FlagType flagType) + { + var mMarks = Data.GetFlag(pc) != flagType; + var mDb = Data.GetDataBank(pc) != dataBank; + var mDp = Data.GetDirectPage(pc) != directPage; + var mX = Data.GetXFlag(pc) != xflagSet; + var mM = Data.GetMFlag(pc) != mflagSet; + + if (mMarks || mDb || mDp || mX || mM) + CurrentStats.numRomBytesModified++; + + CurrentStats.numMarksModified += mMarks ? 1 : 0; + CurrentStats.numDBModified += mDb ? 1 : 0; + CurrentStats.numDpModified += mDp ? 1 : 0; + CurrentStats.numXFlagsModified += mX ? 1 : 0; + CurrentStats.numMFlagsModified += mM ? 1 : 0; + } + } +} \ No newline at end of file diff --git a/Diz.Core/import/BSNESUsageMapImporter.cs b/Diz.Core/import/BSNESUsageMapImporter.cs new file mode 100644 index 00000000..e3c5f279 --- /dev/null +++ b/Diz.Core/import/BSNESUsageMapImporter.cs @@ -0,0 +1,76 @@ +using System; +using System.Runtime.ExceptionServices; +using Diz.Core.model; + +namespace Diz.Core.import +{ + public class BSNESUsageMapImporter + { + // TODO: move BsnesPlusUsage stuff to its own class outside of Data + [Flags] + public enum BsnesPlusUsage : byte + { + UsageRead = 0x80, + UsageWrite = 0x40, + UsageExec = 0x20, + UsageOpcode = 0x10, + UsageFlagM = 0x02, + UsageFlagX = 0x01, + }; + + // move out of here to extension method or just external method + public int ImportUsageMap(byte[] usageMap, Data data) + { + int size = data.GetROMSize(); + int modified = 0; + int prevFlags = 0; + + for (int map = 0; map <= 0xFFFFFF; map++) + { + var i = data.ConvertSNEStoPC(map); + + if (i == -1 || i >= size) + { + // branch predictor may optimize this + continue; + } + + var flags = (BsnesPlusUsage) usageMap[map]; + + if (flags == 0) + { + // no information available + continue; + } + + if (data.GetFlag(i) != Data.FlagType.Unreached) + { + // skip if there is something already set.. + continue; + } + + // opcode: 0x30, operand: 0x20 + if (flags.HasFlag(BsnesPlusUsage.UsageExec)) + { + data.SetFlag(i, Data.FlagType.Operand); + + if (flags.HasFlag(BsnesPlusUsage.UsageOpcode)) + { + prevFlags = ((int) flags & 3) << 4; + data.SetFlag(i, Data.FlagType.Opcode); + } + + data.SetMXFlags(i, prevFlags); + modified++; + } + else if (flags.HasFlag(BsnesPlusUsage.UsageRead)) + { + data.SetFlag(i, Data.FlagType.Data8Bit); + modified++; + } + } + + return modified; + } + } +} diff --git a/Diz.Core/util/RomUtil.cs b/Diz.Core/util/RomUtil.cs index 002c8abe..317f397a 100644 --- a/Diz.Core/util/RomUtil.cs +++ b/Diz.Core/util/RomUtil.cs @@ -9,6 +9,16 @@ namespace Diz.Core.util { public static class RomUtil { + public static int CalculateSNESOffsetWithWrap(int snesAddress, int offset) + { + return (GetBankFromSNESAddress(snesAddress) << 16) + ((snesAddress + offset) & 0xFFFF); + } + + private static int GetBankFromSNESAddress(int snesAddress) + { + return (snesAddress >> 16) & 0xFF; + } + public static int GetBankSize(Data.ROMMapMode mode) { // todo diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 9329e3eb..10771127 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -132,11 +132,11 @@ - + Form - - BSNESTraceLogBinaryMonitor.cs + + BSNESTraceLogBinaryMonitorForm.cs @@ -216,8 +216,8 @@ About.cs - - BSNESTraceLogBinaryMonitor.cs + + BSNESTraceLogBinaryMonitorForm.cs ProgressDialog.cs @@ -301,7 +301,7 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. diff --git a/DiztinGUIsh/Program.cs b/DiztinGUIsh/Program.cs index a5ce9bfa..9ec2dff4 100644 --- a/DiztinGUIsh/Program.cs +++ b/DiztinGUIsh/Program.cs @@ -1,8 +1,5 @@ using System; -using System.Diagnostics; -using System.IO.Pipes; using System.Windows.Forms; -using Diz.Core.util; using DiztinGUIsh.window; namespace DiztinGUIsh @@ -15,9 +12,6 @@ static class Program [STAThread] static void Main(string[] args) { - // Junk(); - // return; - if (Environment.OSVersion.Version.Major >= 6) { SetProcessDPIAware(); @@ -27,37 +21,13 @@ static void Main(string[] args) Application.SetCompatibleTextRenderingDefault(false); var window = new MainWindow(); - if (args.Length > 0) + if (args.Length > 0) window.OpenProject(args[0]); Application.Run(window); } - static void Junk() - { - var bytes = new byte[22]; - - using var pipeClient = new NamedPipeClientStream(".", - "bsnes_tracelog", PipeDirection.In); - - // Connect to the pipe or wait until the pipe is available. - Console.Write("Attempting to connect to pipe..."); - pipeClient.Connect(); - - Console.WriteLine("Connected to pipe."); - Console.WriteLine("There are currently {0} pipe server instances open.", - pipeClient.NumberOfServerInstances); - - var bytesRead = 0; - do - { - bytesRead = pipeClient.Read(bytes, 0, 22); - Debug.Assert(bytesRead == 22); - Console.WriteLine(bytes[0] == 0xEE ? "yep" : "nah"); - } while (bytesRead > 0); - } - [System.Runtime.InteropServices.DllImport("user32.dll")] private static extern bool SetProcessDPIAware(); } -} +} \ No newline at end of file diff --git a/DiztinGUIsh/controller/ProjectController.cs b/DiztinGUIsh/controller/ProjectController.cs index b040bd31..8deed28e 100644 --- a/DiztinGUIsh/controller/ProjectController.cs +++ b/DiztinGUIsh/controller/ProjectController.cs @@ -216,26 +216,26 @@ public long ImportBSNESUsageMap(string fileName) public long ImportBSNESTraceLogs(string[] fileNames) { - var totalLinesSoFar = 0L; - var importer = new BSNESTraceLogImporter(Project.Data); // caution: trace logs can be gigantic, even a few seconds can be > 1GB // inside here, performance becomes critical. LargeFilesReader.ReadFilesLines(fileNames, - delegate(string line) { totalLinesSoFar += importer.ImportTraceLogLine(line).numChanged; }); + (line) => + { + importer.ImportTraceLogLine(line); + }); - if (totalLinesSoFar > 0) + if (importer.CurrentStats.numRomBytesModified > 0) MarkChanged(); - return totalLinesSoFar; + return importer.CurrentStats.numRomBytesModified; } - public int ImportBsnesTraceLogsBinary(string[] filenames) + public long ImportBsnesTraceLogsBinary(string[] filenames) { var importer = new BSNESTraceLogImporter(Project.Data); - var totalModified = 0; foreach (var file in filenames) { using Stream source = File.OpenRead(file); @@ -245,12 +245,11 @@ public int ImportBsnesTraceLogsBinary(string[] filenames) while ((bytesRead = source.Read(buffer, 0, bytesPerPacket)) > 0) { Debug.Assert(bytesRead == 22); - var result = importer.ImportTraceLogLineBinary(buffer); - totalModified += result.numChanged; + importer.ImportTraceLogLineBinary(buffer); } } - return totalModified; + return importer.CurrentStats.numRomBytesModified; } } } diff --git a/DiztinGUIsh/window/MainWindow.Designer.cs b/DiztinGUIsh/window/MainWindow.Designer.cs index 6e3793e2..3f6f044f 100644 --- a/DiztinGUIsh/window/MainWindow.Designer.cs +++ b/DiztinGUIsh/window/MainWindow.Designer.cs @@ -968,11 +968,11 @@ private void InitializeComponent() // // openProjectFile // - this.openProjectFile.Filter = "DiztinGUIsh Project Files|*.diz|All Files|*.*"; + this.openProjectFile.Filter = "DiztinGUIsh Project Files|*.diz;*.dizraw|All Files|*.*"; // // saveProjectFile // - this.saveProjectFile.Filter = "DiztinGUIsh Project Files|*.diz|All Files|*.*"; + this.saveProjectFile.Filter = "DiztinGUIsh Project Files|*.diz;*.dizraw|All Files|*.*"; this.saveProjectFile.Title = "New Project.diz"; // // vScrollBar1 diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 99d2101e..c758827e 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -440,6 +440,9 @@ private void table_MouseWheel(object sender, MouseEventArgs e) private void vScrollBar1_ValueChanged(object sender, EventArgs e) { + if (table.CurrentCell == null) + return; + int selOffset = table.CurrentCell.RowIndex + ViewOffset; ViewOffset = vScrollBar1.Value; UpdateDataGridView(); @@ -1202,8 +1205,10 @@ private void toolStripMenuItem1_Click(object sender, EventArgs e) MessageBox.Show($"Modified total {numModifiedFlags} flags from {openTraceLogDialog.FileNames.Length} files!", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information);*/ - var bsnesForm = new BSNESTraceLogBinaryMonitor(this); + var bsnesForm = new BSNESTraceLogBinaryMonitorForm(this); bsnesForm.ShowDialog(); + + RefreshUI(); } private void importCDLToolStripMenuItem_Click_1(object sender, EventArgs e) diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.Designer.cs b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.Designer.cs deleted file mode 100644 index 9fadac5f..00000000 --- a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.Designer.cs +++ /dev/null @@ -1,196 +0,0 @@ -namespace DiztinGUIsh.window.dialog -{ - partial class BSNESTraceLogBinaryMonitor - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.components = new System.ComponentModel.Container(); - this.button1 = new System.Windows.Forms.Button(); - this.label1 = new System.Windows.Forms.Label(); - this.lblQueuSize = new System.Windows.Forms.Label(); - this.backgroundWorker1_pipeReader = new System.ComponentModel.BackgroundWorker(); - this.timer1 = new System.Windows.Forms.Timer(this.components); - this.backgroundWorker2_processQueue = new System.ComponentModel.BackgroundWorker(); - this.btnCancel = new System.Windows.Forms.Button(); - this.lblTotalProcessed = new System.Windows.Forms.Label(); - this.label4 = new System.Windows.Forms.Label(); - this.lblStatus = new System.Windows.Forms.Label(); - this.label5 = new System.Windows.Forms.Label(); - this.lblNumberModified = new System.Windows.Forms.Label(); - this.label3 = new System.Windows.Forms.Label(); - this.SuspendLayout(); - // - // button1 - // - this.button1.Location = new System.Drawing.Point(12, 130); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(94, 23); - this.button1.TabIndex = 0; - this.button1.Text = "Start importing"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(9, 32); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(60, 13); - this.label1.TabIndex = 1; - this.label1.Text = "Queue size"; - // - // lblQueuSize - // - this.lblQueuSize.AutoSize = true; - this.lblQueuSize.Location = new System.Drawing.Point(112, 32); - this.lblQueuSize.Name = "lblQueuSize"; - this.lblQueuSize.Size = new System.Drawing.Size(13, 13); - this.lblQueuSize.TabIndex = 2; - this.lblQueuSize.Text = "--"; - // - // backgroundWorker1_pipeReader - // - this.backgroundWorker1_pipeReader.WorkerSupportsCancellation = true; - this.backgroundWorker1_pipeReader.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork); - this.backgroundWorker1_pipeReader.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_pipeReader_RunWorkerCompleted); - // - // timer1 - // - this.timer1.Interval = 500; - this.timer1.Tick += new System.EventHandler(this.timer1_Tick); - // - // backgroundWorker2_processQueue - // - this.backgroundWorker2_processQueue.WorkerSupportsCancellation = true; - this.backgroundWorker2_processQueue.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker2_processQueue_DoWork); - this.backgroundWorker2_processQueue.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker2_processQueue_RunWorkerCompleted_1); - // - // btnCancel - // - this.btnCancel.Enabled = false; - this.btnCancel.Location = new System.Drawing.Point(112, 130); - this.btnCancel.Name = "btnCancel"; - this.btnCancel.Size = new System.Drawing.Size(66, 23); - this.btnCancel.TabIndex = 3; - this.btnCancel.Text = "Finish"; - this.btnCancel.UseVisualStyleBackColor = true; - this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); - // - // lblTotalProcessed - // - this.lblTotalProcessed.AutoSize = true; - this.lblTotalProcessed.Location = new System.Drawing.Point(113, 52); - this.lblTotalProcessed.Name = "lblTotalProcessed"; - this.lblTotalProcessed.Size = new System.Drawing.Size(13, 13); - this.lblTotalProcessed.TabIndex = 6; - this.lblTotalProcessed.Text = "--"; - // - // label4 - // - this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(10, 52); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(89, 13); - this.label4.TabIndex = 5; - this.label4.Text = "# Bytes Analyzed"; - // - // lblStatus - // - this.lblStatus.AutoSize = true; - this.lblStatus.Location = new System.Drawing.Point(113, 12); - this.lblStatus.Name = "lblStatus"; - this.lblStatus.Size = new System.Drawing.Size(13, 13); - this.lblStatus.TabIndex = 8; - this.lblStatus.Text = "--"; - // - // label5 - // - this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(10, 12); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(37, 13); - this.label5.TabIndex = 7; - this.label5.Text = "Status"; - // - // lblNumberModified - // - this.lblNumberModified.AutoSize = true; - this.lblNumberModified.Location = new System.Drawing.Point(112, 104); - this.lblNumberModified.Name = "lblNumberModified"; - this.lblNumberModified.Size = new System.Drawing.Size(13, 13); - this.lblNumberModified.TabIndex = 10; - this.lblNumberModified.Text = "--"; - // - // label3 - // - this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(9, 104); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(86, 13); - this.label3.TabIndex = 9; - this.label3.Text = "# Bytes Modified"; - // - // BSNESTraceLogBinaryMonitor - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(199, 163); - this.Controls.Add(this.lblNumberModified); - this.Controls.Add(this.label3); - this.Controls.Add(this.lblStatus); - this.Controls.Add(this.label5); - this.Controls.Add(this.lblTotalProcessed); - this.Controls.Add(this.label4); - this.Controls.Add(this.btnCancel); - this.Controls.Add(this.lblQueuSize); - this.Controls.Add(this.label1); - this.Controls.Add(this.button1); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; - this.Name = "BSNESTraceLogBinaryMonitor"; - this.Text = "BSNES Live Tracelog Capture"; - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.Button button1; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.Label lblQueuSize; - private System.ComponentModel.BackgroundWorker backgroundWorker1_pipeReader; - private System.Windows.Forms.Timer timer1; - private System.ComponentModel.BackgroundWorker backgroundWorker2_processQueue; - private System.Windows.Forms.Button btnCancel; - private System.Windows.Forms.Label lblTotalProcessed; - private System.Windows.Forms.Label label4; - private System.Windows.Forms.Label lblStatus; - private System.Windows.Forms.Label label5; - private System.Windows.Forms.Label lblNumberModified; - private System.Windows.Forms.Label label3; - } -} \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.cs b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.cs deleted file mode 100644 index ccaf3d7b..00000000 --- a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.cs +++ /dev/null @@ -1,129 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.ComponentModel; -using System.Diagnostics; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Windows.Forms; -using Diz.Core.import; - -namespace DiztinGUIsh.window.dialog -{ - public partial class BSNESTraceLogBinaryMonitor : Form - { - private MainWindow MainWindow; - private CancellationTokenSource cancelToken; - private BSNESTraceLogImporter importer; - - // caution: thread safety for next items: - private BlockingCollection queue; - private int totalModified; - private int totalAnalyzed; - // end thread safety - - public BSNESTraceLogBinaryMonitor(MainWindow window) - { - MainWindow = window; - InitializeComponent(); - } - - private void button1_Click(object sender, EventArgs e) - { - importer = new BSNESTraceLogImporter(MainWindow.Project.Data); - cancelToken = new CancellationTokenSource(); - queue = new BlockingCollection(); - - totalModified = 0; - totalAnalyzed = 0; - - backgroundWorker1_pipeReader.RunWorkerAsync(); - backgroundWorker2_processQueue.RunWorkerAsync(); - - timer1.Enabled = true; - btnCancel.Enabled = true; - button1.Enabled = false; - } - - private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) - { - var bytes = new byte[22]; - - var tcpClient = new TcpClient(); - var ipEndPoint = new IPEndPoint(IPAddress.Loopback, 27015); - - tcpClient.Connect(ipEndPoint); - - var networkStream = tcpClient.GetStream(); - - while (!backgroundWorker1_pipeReader.CancellationPending) - { - var bytesRead = networkStream.Read(bytes, 0, bytes.Length); - if (bytesRead <= 0) - return; - queue.Add(bytes); - } - } - - private void backgroundWorker2_processQueue_DoWork(object sender, DoWorkEventArgs e) - { - while (!backgroundWorker2_processQueue.CancellationPending) - { - try - { - var bytes = queue.Take(cancelToken.Token); - Debug.Assert(bytes.Length == 22); - var (numChanged, numLinesAnalyzed) = importer.ImportTraceLogLineBinary(bytes); - totalModified += numChanged; - totalAnalyzed += numLinesAnalyzed; - } - catch (OperationCanceledException) - { - return; - } - } - } - - private void timer1_Tick(object sender, EventArgs e) - { - UpdateUI(); - } - - private void btnCancel_Click(object sender, EventArgs e) - { - btnCancel.Enabled = false; - button1.Enabled = true; - - cancelToken.Cancel(); - backgroundWorker1_pipeReader.CancelAsync(); - backgroundWorker2_processQueue.CancelAsync(); - - timer1.Enabled = false; - } - - private void backgroundWorker2_processQueue_RunWorkerCompleted_1(object sender, RunWorkerCompletedEventArgs e) - { - UpdateUI(); - } - - private void backgroundWorker1_pipeReader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) - { - UpdateUI(); - } - - private void UpdateUI() - { - lblQueuSize.Text = queue.Count.ToString(); - var running = backgroundWorker2_processQueue != null && backgroundWorker1_pipeReader != null; - var cancelling = cancelToken?.IsCancellationRequested ?? false; - - lblTotalProcessed.Text = totalAnalyzed.ToString(); - lblNumberModified.Text = totalModified.ToString(); - - lblStatus.Text = !running ? "Not running" : !cancelling ? "Stopping..." : "Running"; - - btnCancel.Enabled = running && !cancelling; - button1.Enabled = !running; - } - } -} \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.Designer.cs b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.Designer.cs new file mode 100644 index 00000000..411a75b3 --- /dev/null +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.Designer.cs @@ -0,0 +1,359 @@ +namespace DiztinGUIsh.window.dialog +{ + partial class BSNESTraceLogBinaryMonitorForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(BSNESTraceLogBinaryMonitorForm)); + this.btnStart = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.lblQueueSize = new System.Windows.Forms.Label(); + this.backgroundWorker1_pipeReader = new System.ComponentModel.BackgroundWorker(); + this.timer1 = new System.Windows.Forms.Timer(this.components); + this.backgroundWorker2_processQueue = new System.ComponentModel.BackgroundWorker(); + this.btnFinish = new System.Windows.Forms.Button(); + this.lblTotalProcessed = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.lblStatus = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.lblNumberModified = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.lblModifiedXFlags = new System.Windows.Forms.Label(); + this.label6 = new System.Windows.Forms.Label(); + this.lblModifiedMFlags = new System.Windows.Forms.Label(); + this.label8 = new System.Windows.Forms.Label(); + this.lblModifiedDPs = new System.Windows.Forms.Label(); + this.label10 = new System.Windows.Forms.Label(); + this.lblModifiedDBs = new System.Windows.Forms.Label(); + this.label12 = new System.Windows.Forms.Label(); + this.lblModifiedFlags = new System.Windows.Forms.Label(); + this.label14 = new System.Windows.Forms.Label(); + this.label15 = new System.Windows.Forms.Label(); + this.label16 = new System.Windows.Forms.Label(); + this.label17 = new System.Windows.Forms.Label(); + this.label18 = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // btnStart + // + this.btnStart.Location = new System.Drawing.Point(252, 19); + this.btnStart.Name = "btnStart"; + this.btnStart.Size = new System.Drawing.Size(130, 38); + this.btnStart.TabIndex = 0; + this.btnStart.Text = "Capture from BSNES-PLUS"; + this.btnStart.UseVisualStyleBackColor = true; + this.btnStart.Click += new System.EventHandler(this.btnStart_Click); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 44); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(60, 13); + this.label1.TabIndex = 1; + this.label1.Text = "Queue size"; + // + // lblQueueSize + // + this.lblQueueSize.AutoSize = true; + this.lblQueueSize.Location = new System.Drawing.Point(131, 44); + this.lblQueueSize.Name = "lblQueueSize"; + this.lblQueueSize.Size = new System.Drawing.Size(13, 13); + this.lblQueueSize.TabIndex = 2; + this.lblQueueSize.Text = "--"; + // + // timer1 + // + this.timer1.Interval = 250; + this.timer1.Tick += new System.EventHandler(this.timer1_Tick); + // + // btnFinish + // + this.btnFinish.Enabled = false; + this.btnFinish.Location = new System.Drawing.Point(388, 19); + this.btnFinish.Name = "btnFinish"; + this.btnFinish.Size = new System.Drawing.Size(91, 38); + this.btnFinish.TabIndex = 3; + this.btnFinish.Text = "Finish"; + this.btnFinish.UseVisualStyleBackColor = true; + this.btnFinish.Click += new System.EventHandler(this.btnFinish_Click); + // + // lblTotalProcessed + // + this.lblTotalProcessed.AutoSize = true; + this.lblTotalProcessed.Location = new System.Drawing.Point(131, 254); + this.lblTotalProcessed.Name = "lblTotalProcessed"; + this.lblTotalProcessed.Size = new System.Drawing.Size(13, 13); + this.lblTotalProcessed.TabIndex = 6; + this.lblTotalProcessed.Text = "--"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(15, 254); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(99, 13); + this.label4.TabIndex = 5; + this.label4.Text = "# Bytes Considered"; + // + // lblStatus + // + this.lblStatus.AutoSize = true; + this.lblStatus.Location = new System.Drawing.Point(131, 24); + this.lblStatus.Name = "lblStatus"; + this.lblStatus.Size = new System.Drawing.Size(13, 13); + this.lblStatus.TabIndex = 8; + this.lblStatus.Text = "--"; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(13, 24); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(37, 13); + this.label5.TabIndex = 7; + this.label5.Text = "Status"; + // + // lblNumberModified + // + this.lblNumberModified.AutoSize = true; + this.lblNumberModified.Location = new System.Drawing.Point(131, 279); + this.lblNumberModified.Name = "lblNumberModified"; + this.lblNumberModified.Size = new System.Drawing.Size(13, 13); + this.lblNumberModified.TabIndex = 10; + this.lblNumberModified.Text = "--"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(15, 279); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(86, 13); + this.label3.TabIndex = 9; + this.label3.Text = "# Bytes Modified"; + // + // lblModifiedXFlags + // + this.lblModifiedXFlags.AutoSize = true; + this.lblModifiedXFlags.Location = new System.Drawing.Point(128, 126); + this.lblModifiedXFlags.Name = "lblModifiedXFlags"; + this.lblModifiedXFlags.Size = new System.Drawing.Size(13, 13); + this.lblModifiedXFlags.TabIndex = 12; + this.lblModifiedXFlags.Text = "--"; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(12, 126); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(42, 13); + this.label6.TabIndex = 11; + this.label6.Text = "X Flags"; + // + // lblModifiedMFlags + // + this.lblModifiedMFlags.AutoSize = true; + this.lblModifiedMFlags.Location = new System.Drawing.Point(128, 152); + this.lblModifiedMFlags.Name = "lblModifiedMFlags"; + this.lblModifiedMFlags.Size = new System.Drawing.Size(13, 13); + this.lblModifiedMFlags.TabIndex = 14; + this.lblModifiedMFlags.Text = "--"; + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(12, 152); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(44, 13); + this.label8.TabIndex = 13; + this.label8.Text = "M Flags"; + // + // lblModifiedDPs + // + this.lblModifiedDPs.AutoSize = true; + this.lblModifiedDPs.Location = new System.Drawing.Point(128, 176); + this.lblModifiedDPs.Name = "lblModifiedDPs"; + this.lblModifiedDPs.Size = new System.Drawing.Size(13, 13); + this.lblModifiedDPs.TabIndex = 16; + this.lblModifiedDPs.Text = "--"; + // + // label10 + // + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(12, 176); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(63, 13); + this.label10.TabIndex = 15; + this.label10.Text = "Direct Page"; + // + // lblModifiedDBs + // + this.lblModifiedDBs.AutoSize = true; + this.lblModifiedDBs.Location = new System.Drawing.Point(128, 201); + this.lblModifiedDBs.Name = "lblModifiedDBs"; + this.lblModifiedDBs.Size = new System.Drawing.Size(13, 13); + this.lblModifiedDBs.TabIndex = 18; + this.lblModifiedDBs.Text = "--"; + // + // label12 + // + this.label12.AutoSize = true; + this.label12.Location = new System.Drawing.Point(12, 201); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(58, 13); + this.label12.TabIndex = 17; + this.label12.Text = "Data Bank"; + // + // lblModifiedFlags + // + this.lblModifiedFlags.AutoSize = true; + this.lblModifiedFlags.Location = new System.Drawing.Point(128, 102); + this.lblModifiedFlags.Name = "lblModifiedFlags"; + this.lblModifiedFlags.Size = new System.Drawing.Size(13, 13); + this.lblModifiedFlags.TabIndex = 20; + this.lblModifiedFlags.Text = "--"; + // + // label14 + // + this.label14.AutoSize = true; + this.label14.Location = new System.Drawing.Point(12, 102); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(108, 13); + this.label14.TabIndex = 19; + this.label14.Text = "Bytes Marked w/type"; + // + // label15 + // + this.label15.AutoSize = true; + this.label15.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label15.Location = new System.Drawing.Point(9, 81); + this.label15.Name = "label15"; + this.label15.Size = new System.Drawing.Size(194, 13); + this.label15.TabIndex = 21; + this.label15.Text = "Data Uncovered (#modifications)"; + // + // label16 + // + this.label16.AutoSize = true; + this.label16.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label16.Location = new System.Drawing.Point(12, 7); + this.label16.Name = "label16"; + this.label16.Size = new System.Drawing.Size(116, 13); + this.label16.TabIndex = 22; + this.label16.Text = "BSNES Connection"; + // + // label17 + // + this.label17.AutoSize = true; + this.label17.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label17.Location = new System.Drawing.Point(12, 232); + this.label17.Name = "label17"; + this.label17.Size = new System.Drawing.Size(57, 13); + this.label17.TabIndex = 23; + this.label17.Text = "Summary"; + // + // label18 + // + this.label18.AutoSize = true; + this.label18.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label18.Location = new System.Drawing.Point(5, 314); + this.label18.MaximumSize = new System.Drawing.Size(500, 0); + this.label18.Name = "label18"; + this.label18.Size = new System.Drawing.Size(497, 221); + this.label18.TabIndex = 24; + this.label18.Text = resources.GetString("label18.Text"); + // + // BSNESTraceLogBinaryMonitorForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(505, 539); + this.Controls.Add(this.label18); + this.Controls.Add(this.label17); + this.Controls.Add(this.label16); + this.Controls.Add(this.label15); + this.Controls.Add(this.lblModifiedFlags); + this.Controls.Add(this.label14); + this.Controls.Add(this.lblModifiedDBs); + this.Controls.Add(this.label12); + this.Controls.Add(this.lblModifiedDPs); + this.Controls.Add(this.label10); + this.Controls.Add(this.lblModifiedMFlags); + this.Controls.Add(this.label8); + this.Controls.Add(this.lblModifiedXFlags); + this.Controls.Add(this.label6); + this.Controls.Add(this.lblNumberModified); + this.Controls.Add(this.label3); + this.Controls.Add(this.lblStatus); + this.Controls.Add(this.label5); + this.Controls.Add(this.lblTotalProcessed); + this.Controls.Add(this.label4); + this.Controls.Add(this.btnFinish); + this.Controls.Add(this.lblQueueSize); + this.Controls.Add(this.label1); + this.Controls.Add(this.btnStart); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.Name = "BSNESTraceLogBinaryMonitorForm"; + this.Text = "BSNES Live Tracelog Capture"; + this.Load += new System.EventHandler(this.BSNESTraceLogBinaryMonitorForm_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button btnStart; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label lblQueueSize; + private System.ComponentModel.BackgroundWorker backgroundWorker1_pipeReader; + private System.Windows.Forms.Timer timer1; + private System.ComponentModel.BackgroundWorker backgroundWorker2_processQueue; + private System.Windows.Forms.Button btnFinish; + private System.Windows.Forms.Label lblTotalProcessed; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label lblStatus; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label lblNumberModified; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label lblModifiedXFlags; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Label lblModifiedMFlags; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.Label lblModifiedDPs; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.Label lblModifiedDBs; + private System.Windows.Forms.Label label12; + private System.Windows.Forms.Label lblModifiedFlags; + private System.Windows.Forms.Label label14; + private System.Windows.Forms.Label label15; + private System.Windows.Forms.Label label16; + private System.Windows.Forms.Label label17; + private System.Windows.Forms.Label label18; + } +} \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs new file mode 100644 index 00000000..066aa717 --- /dev/null +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs @@ -0,0 +1,90 @@ +using System; +using System.Windows.Forms; + +namespace DiztinGUIsh.window.dialog +{ + // TODO: add controller/view for this. + // + // TODO: BSNESTraceLogCapture does a lot of threading. It's decently protected but, + // while that stuff is running, try and avoid using 'Data' anywhere outside BSNESTraceLogCapture. + // eventually, if we want to do that we need to retrofit the rest of the app to take advantage of that. + public partial class BSNESTraceLogBinaryMonitorForm : Form + { + private MainWindow MainWindow; + private BSNESTraceLogCapture capturing; + + public BSNESTraceLogBinaryMonitorForm(MainWindow window) + { + MainWindow = window; + InitializeComponent(); + } + + private void btnStart_Click(object sender, EventArgs e) + { + timer1.Enabled = true; + btnFinish.Enabled = true; + btnStart.Enabled = false; + + capturing = new BSNESTraceLogCapture(); + capturing.Finished += CapturingFinished; + capturing.Error += Capturing_Error; + + capturing.Start(MainWindow.Project.Data); + } + + private void Capturing_Error(Exception e) + { + MessageBox.Show(e.Message, "Worker Error"); + } + + private void btnFinish_Click(object sender, EventArgs e) + { + timer1.Enabled = false; + + capturing?.SignalToStop(); + + UpdateUI(); + } + + private void CapturingFinished(object sender, EventArgs e) + { + UpdateUI(); + } + + private void timer1_Tick(object sender, EventArgs e) + { + UpdateUI(); + } + + private void UpdateUI() + { + var running = capturing?.Running ?? false; + var finishing = capturing?.Finishing ?? false; + + lblStatus.Text = !running ? "Not running" : finishing ? "Stopping..." : "Running"; + + btnFinish.Enabled = !finishing && running; + btnStart.Enabled = !running; + + if (capturing == null) + return; + + lblQueueSize.Text = capturing.QueueLength.ToString(); + + // TODO: use databinding + var stats = capturing.GetStats(); // copy + lblTotalProcessed.Text = stats.numRomBytesAnalyzed.ToString(); + lblNumberModified.Text = stats.numRomBytesModified.ToString(); + lblModifiedDBs.Text = stats.numDBModified.ToString(); + lblModifiedDPs.Text = stats.numDpModified.ToString(); + lblModifiedFlags.Text = stats.numMarksModified.ToString(); + lblModifiedXFlags.Text = stats.numXFlagsModified.ToString(); + lblModifiedMFlags.Text = stats.numMFlagsModified.ToString(); + } + + private void BSNESTraceLogBinaryMonitorForm_Load(object sender, EventArgs e) + { + + } + } +} \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.resx b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.resx similarity index 87% rename from DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.resx rename to DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.resx index fa949fe4..b815b9d4 100644 --- a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitor.resx +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.resx @@ -126,7 +126,20 @@ 335, 17 + + What is this? +Connect via socket to BSNES plus and capture live tracelog as you play the game in realtime or play back a movie/recording/TAS. + +As each instruction is visited by the CPU, info like X,M,DB,D and flags are capture and logged in Diz. This will greatly aid in dissasembly. + +If you're just starting a ROM hacking project from scratch, you want to see this capture a lot of modified data for X,M,DP,DB and marking bytes as Opcode/Operands. + +If you're far into a ROM hacking project, you will start seeing fewer NEWLY DISCOVERED modifications here. Try playing through different parts of the game, menus, every combination of searching you can do to allow this tool to discover as much as it can. + +When you close this window, try exporting your disassembly and see how much you uncovered! + + - 108 + 36 \ No newline at end of file From 6ce8868294776c7f9869bb8eb360846f1844ed8b Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 18 Oct 2020 22:12:59 -0400 Subject: [PATCH 096/136] finish socket implementation --- Diz.Core/Diz.Core.csproj | 7 +- Diz.Core/import/BSNESTraceLogCapture.cs | 116 +++++++++++++++--- Diz.Core/import/BSNESTraceLogImporter.cs | 62 ++++++---- Diz.Core/packages.config | 3 +- Diz.Test/Diz.Test.csproj | 4 +- Diz.Test/packages.config | 2 +- DiztinGUIsh/DiztinGUIsh.csproj | 6 + DiztinGUIsh/packages.config | 2 + DiztinGUIsh/window/MainWindow.cs | 9 -- ...BSNESTraceLogBinaryMonitorForm.Designer.cs | 1 - .../dialog/BSNESTraceLogBinaryMonitorForm.cs | 28 +++-- 11 files changed, 167 insertions(+), 73 deletions(-) diff --git a/Diz.Core/Diz.Core.csproj b/Diz.Core/Diz.Core.csproj index adae8bfb..118b0e35 100644 --- a/Diz.Core/Diz.Core.csproj +++ b/Diz.Core/Diz.Core.csproj @@ -32,8 +32,11 @@ 4 - - ..\packages\ExtendedXmlSerializer.3.3.0.6-pexchapm\lib\net452\ExtendedXmlSerializer.dll + + ..\packages\ExtendedXmlSerializer.3.4.1\lib\net452\ExtendedXmlSerializer.dll + + + ..\packages\SharpZipLib.1.3.0\lib\net45\ICSharpCode.SharpZipLib.dll ..\packages\IX.Abstractions.0.5.3\lib\net472\IX.Abstractions.dll diff --git a/Diz.Core/import/BSNESTraceLogCapture.cs b/Diz.Core/import/BSNESTraceLogCapture.cs index e396b8a4..5a0cd4cf 100644 --- a/Diz.Core/import/BSNESTraceLogCapture.cs +++ b/Diz.Core/import/BSNESTraceLogCapture.cs @@ -6,17 +6,24 @@ using System.Net; using System.Net.Sockets; using System.Threading; -using Diz.Core.import; using Diz.Core.model; +using Diz.Core.util; +using ICSharpCode.SharpZipLib.Zip.Compression.Streams; -namespace DiztinGUIsh.window.dialog +namespace Diz.Core.import { public class BSNESTraceLogCapture { private CancellationTokenSource cancelToken; private BackgroundWorker socketWorker, dataWorker; - private BlockingCollection queue; // thread-safe + struct Packet + { + public byte[] bytes; + public int uncompressedSize; + } + + private BlockingCollection queue; // thread-safe public int QueueLength => queue?.Count ?? 0; public bool Running => dataWorker != null && socketWorker != null; @@ -32,22 +39,27 @@ public class BSNESTraceLogCapture private readonly ReaderWriterLockSlim importerLock = new ReaderWriterLockSlim(); private BSNESTraceLogImporter importer; private BSNESTraceLogImporter.Stats cachedStats; - public BSNESTraceLogImporter.Stats GetStats() + private int bytesInQueue; + + public (BSNESTraceLogImporter.Stats, int) GetStats() { if (importer == null) - return cachedStats; + return (cachedStats, 0); + + var cachedBytesInQueue = 0; try { importerLock.EnterReadLock(); cachedStats = importer.CurrentStats; + cachedBytesInQueue = bytesInQueue; } finally { importerLock.ExitReadLock(); } - return cachedStats; + return (cachedStats, cachedBytesInQueue); } public void Start(Data data) @@ -55,7 +67,8 @@ public void Start(Data data) importer = new BSNESTraceLogImporter(data); cancelToken = new CancellationTokenSource(); - queue = new BlockingCollection(); + queue = new BlockingCollection(); + bytesInQueue = 0; socketWorker = new BackgroundWorker(); dataWorker = new BackgroundWorker(); @@ -93,19 +106,33 @@ private void SocketWorker_DoWork(object sender, DoWorkEventArgs e) private void ReadNextFromSocket(Stream networkStream) { - var buffer = ReadNext(networkStream, 2, out var bytesRead); - Debug.Assert(buffer.Length == 2); + const int headerSize = 9; + var buffer = ReadNext(networkStream, headerSize, out var bytesRead); + Debug.Assert(buffer.Length == headerSize); - const byte expectedWatermark = 0xEE; - if (buffer[0] != expectedWatermark) { - throw new InvalidDataException($"expected header of 0xEE, got {buffer[0]} instead."); + if (buffer[0] != 'Z') { + throw new InvalidDataException($"expected header byte of 'Z', got {buffer[0]} instead."); } - int amountToRead = buffer[1]; - Debug.Assert(amountToRead == 21); + var originalDataSizeBytes = ByteUtil.ByteArrayToInt32(buffer, 1); + var compressedDataSize = ByteUtil.ByteArrayToInt32(buffer, 5); - buffer = ReadNext(networkStream, amountToRead, out bytesRead); - queue.Add(buffer); + buffer = ReadNext(networkStream, compressedDataSize, out bytesRead); + Debug.Assert(buffer.Length == compressedDataSize); + + // add it compressed. + queue.Add(new Packet() {bytes=buffer, uncompressedSize = originalDataSizeBytes}); + + // this is just neat stats. it's optional, remove if performance becomes an issue (seems unlikely) + try + { + importerLock.EnterWriteLock(); + bytesInQueue += compressedDataSize; + } + finally + { + importerLock.ExitWriteLock(); + } } private static byte[] ReadNext(Stream networkStream, int count, out int bytesRead) @@ -128,18 +155,55 @@ private static byte[] ReadNext(Stream networkStream, int count, out int bytesRea private void DataWorker_DoWork(object sender, DoWorkEventArgs e) { + // TODO: we're officially CPU bound now. + // probably should create multiple parallel workers + // to take items off the compressed queue + // and add them to an uncompressed queue + while (!dataWorker.CancellationPending && !cancelToken.IsCancellationRequested) { try { // TODO: use cancelToken here instead of timeout. (can't get it to work right now...) - if (!queue.TryTake(out var bytes, 100)) + if (!queue.TryTake(out var packet, 100)) continue; - + + var decompressedData = new byte[packet.uncompressedSize]; + var decompressedLength = 0; + using (var memory = new MemoryStream(packet.bytes)) + using (var inflater = new InflaterInputStream(memory)) + { + decompressedLength = inflater.Read(decompressedData, 0, decompressedData.Length); + } + Debug.Assert(decompressedLength == packet.uncompressedSize); + + using (var stream = new MemoryStream(decompressedData)) + { + var header = new byte[2]; + while (stream.Read(header, 0, 2) == 2) + { + var id = header[0]; + var len = header[1]; + + if (id != 0xEE && id != 0xEF) + throw new InvalidDataException("Missing expected watermark from unzipped data"); + + var abridgedFormat = id == 0xEE; + + var buffer = new byte[len]; + var bytesRead = stream.Read(buffer, 0, buffer.Length); + if (bytesRead != buffer.Length) + throw new InvalidDataException("Didn't read enough bytes from unzipped data"); + + ProcessOneInstruction(buffer, abridgedFormat); + } + } + + // optional, but nice stats. try { importerLock.EnterWriteLock(); - importer.ImportTraceLogLineBinary(bytes); + bytesInQueue -= packet.bytes.Length; } finally { @@ -153,6 +217,19 @@ private void DataWorker_DoWork(object sender, DoWorkEventArgs e) } } + private void ProcessOneInstruction(byte[] buffer, bool abridgedFormat) + { + try + { + importerLock.EnterWriteLock(); + importer.ImportTraceLogLineBinary(buffer, abridgedFormat); + } + finally + { + importerLock.ExitWriteLock(); + } + } + public void SignalToStop() { Finishing = true; @@ -196,6 +273,7 @@ protected virtual void OnFinished() cancelToken = null; queue = null; + bytesInQueue = 0; socketWorker = dataWorker = null; Thread.MemoryBarrier(); diff --git a/Diz.Core/import/BSNESTraceLogImporter.cs b/Diz.Core/import/BSNESTraceLogImporter.cs index 3f8e8824..336d42c0 100644 --- a/Diz.Core/import/BSNESTraceLogImporter.cs +++ b/Diz.Core/import/BSNESTraceLogImporter.cs @@ -126,11 +126,16 @@ int GetHexValueAt(int startIndex, int length) // this is same as above but, reads the same data from a binary format. this is for // performance reasons to try and stream the data live from BSNES - public void ImportTraceLogLineBinary(byte[] bytes) + public void ImportTraceLogLineBinary(byte[] bytes, bool abridgedFormat=true) { // extremely performance-intensive function. be really careful when adding stuff - Debug.Assert(bytes.Length == 21); + if (abridgedFormat) { + Debug.Assert(bytes.Length == 8); + } else { + Debug.Assert(bytes.Length == 21); + } + var pointer = 0; // ----------------------------- @@ -139,35 +144,12 @@ public void ImportTraceLogLineBinary(byte[] bytes) var opcodeLen = bytes[pointer++]; - // skip opcodes. NOTE: must read all 5 bytes but only use up to 'opcode_len' bytes - //var op = bytes[pointer++]; - //var op0 = bytes[pointer++]; - //var op1 = bytes[pointer++]; - //var op2 = bytes[pointer++]; - pointer += 4; - - // skip A register - pointer += 2; - - // skip X register - pointer += 2; - - // skip Y register - pointer += 2; - - // skip S register - pointer += 2; - var directPage = ByteUtil.ByteArrayToInt16(bytes, pointer); pointer += 2; var dataBank = bytes[pointer++]; - // skip, flag 'e' for emulation mode or not - // var emuFlag = bytes[pointer++] == 0x01; - pointer++; - - // the real flags, we mainly care about X and M + // the flags register var flags = bytes[pointer++]; // n = flags & 0x80; // v = flags & 0x40; @@ -176,9 +158,37 @@ public void ImportTraceLogLineBinary(byte[] bytes) // i = flags & 0x04; // z = flags & 0x02; // c = flags & 0x01; + + // we only care about X and M flags var xflagSet = (flags & 0x10) != 0; var mflagSet = (flags & 0x20) != 0; + if (!abridgedFormat) + { + // skip opcodes. NOTE: must read all 5 bytes but only use up to 'opcode_len' bytes + //var op = bytes[pointer++]; + //var op0 = bytes[pointer++]; + //var op1 = bytes[pointer++]; + //var op2 = bytes[pointer++]; + pointer += 4; + + // skip A register + pointer += 2; + + // skip X register + pointer += 2; + + // skip Y register + pointer += 2; + + // skip S register + pointer += 2; + + // skip, flag 'e' for emulation mode or not + // skip E(emu) flag <-- NOTE: we might... want this someday. + pointer += 1; + } + Debug.Assert(pointer == bytes.Length); SetOpcodeAndOperandsFromTraceData(snesAddress, dataBank, directPage, xflagSet, mflagSet, opcodeLen); diff --git a/Diz.Core/packages.config b/Diz.Core/packages.config index 9b9291c1..8d81d458 100644 --- a/Diz.Core/packages.config +++ b/Diz.Core/packages.config @@ -1,6 +1,6 @@  - + @@ -12,6 +12,7 @@ + diff --git a/Diz.Test/Diz.Test.csproj b/Diz.Test/Diz.Test.csproj index 532b8c01..a431ace0 100644 --- a/Diz.Test/Diz.Test.csproj +++ b/Diz.Test/Diz.Test.csproj @@ -40,8 +40,8 @@ ..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll - - ..\packages\ExtendedXmlSerializer.3.3.0.6-pexchapm\lib\net452\ExtendedXmlSerializer.dll + + ..\packages\ExtendedXmlSerializer.3.4.1\lib\net452\ExtendedXmlSerializer.dll ..\packages\IX.Abstractions.0.5.3\lib\net472\IX.Abstractions.dll diff --git a/Diz.Test/packages.config b/Diz.Test/packages.config index 843e70d6..b0f414c2 100644 --- a/Diz.Test/packages.config +++ b/Diz.Test/packages.config @@ -1,7 +1,7 @@  - + diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 10771127..2b1970fe 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -72,6 +72,12 @@ true + + ..\packages\ByteSize.2.0.0\lib\net45\ByteSize.dll + + + ..\packages\SharpZipLib.1.3.0\lib\net45\ICSharpCode.SharpZipLib.dll + ..\packages\IX.Abstractions.0.5.3\lib\net472\IX.Abstractions.dll diff --git a/DiztinGUIsh/packages.config b/DiztinGUIsh/packages.config index c8e86364..c3110b0d 100644 --- a/DiztinGUIsh/packages.config +++ b/DiztinGUIsh/packages.config @@ -1,5 +1,6 @@  + @@ -11,6 +12,7 @@ + diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index c758827e..d6e9d87c 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -1196,15 +1196,6 @@ private void toolStripMenuItem3_Click(object sender, EventArgs e) private void toolStripMenuItem1_Click(object sender, EventArgs e) { - /*openTraceLogDialog.Multiselect = true; - if (openTraceLogDialog.ShowDialog() != DialogResult.OK) - return; - - var numModifiedFlags = ProjectController.ImportBsnesTraceLogsBinary(openTraceLogDialog.FileNames); - - MessageBox.Show($"Modified total {numModifiedFlags} flags from {openTraceLogDialog.FileNames.Length} files!", "Done", - MessageBoxButtons.OK, MessageBoxIcon.Information);*/ - var bsnesForm = new BSNESTraceLogBinaryMonitorForm(this); bsnesForm.ShowDialog(); diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.Designer.cs b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.Designer.cs index 411a75b3..7d8c0e6c 100644 --- a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.Designer.cs +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.Designer.cs @@ -320,7 +320,6 @@ private void InitializeComponent() this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; this.Name = "BSNESTraceLogBinaryMonitorForm"; this.Text = "BSNES Live Tracelog Capture"; - this.Load += new System.EventHandler(this.BSNESTraceLogBinaryMonitorForm_Load); this.ResumeLayout(false); this.PerformLayout(); diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs index 066aa717..b416b49a 100644 --- a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs @@ -1,5 +1,7 @@ using System; using System.Windows.Forms; +using ByteSizeLib; +using Diz.Core.import; namespace DiztinGUIsh.window.dialog { @@ -69,22 +71,24 @@ private void UpdateUI() if (capturing == null) return; - lblQueueSize.Text = capturing.QueueLength.ToString(); + var (stats, totalQueueBytes) = capturing.GetStats(); + + var qItemCount = capturing.QueueLength.ToString(); + var qByteCount = ByteSize.FromBytes(totalQueueBytes).ToString("0.00"); + + lblQueueSize.Text = $"{qByteCount} (num groups: {qItemCount})"; // TODO: use databinding - var stats = capturing.GetStats(); // copy - lblTotalProcessed.Text = stats.numRomBytesAnalyzed.ToString(); - lblNumberModified.Text = stats.numRomBytesModified.ToString(); - lblModifiedDBs.Text = stats.numDBModified.ToString(); - lblModifiedDPs.Text = stats.numDpModified.ToString(); - lblModifiedFlags.Text = stats.numMarksModified.ToString(); - lblModifiedXFlags.Text = stats.numXFlagsModified.ToString(); - lblModifiedMFlags.Text = stats.numMFlagsModified.ToString(); - } - private void BSNESTraceLogBinaryMonitorForm_Load(object sender, EventArgs e) - { + const string format = "0.00"; + lblTotalProcessed.Text = ByteSize.FromBytes(stats.numRomBytesAnalyzed).ToString(format); + lblNumberModified.Text = ByteSize.FromBytes(stats.numRomBytesModified).ToString(format); + lblModifiedDBs.Text = ByteSize.FromBytes(stats.numDBModified).ToString(format); + lblModifiedDPs.Text = ByteSize.FromBytes(stats.numDpModified).ToString(format); + lblModifiedFlags.Text = ByteSize.FromBytes(stats.numMarksModified).ToString(format); + lblModifiedXFlags.Text = ByteSize.FromBytes(stats.numXFlagsModified).ToString(format); + lblModifiedMFlags.Text = ByteSize.FromBytes(stats.numMFlagsModified).ToString(format); } } } \ No newline at end of file From 7fe04fa90ab03a6ee2b5ee449ac2270cf85dc558 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 20 Oct 2020 18:55:56 -0400 Subject: [PATCH 097/136] overhaul internal guts of threading - good structure, but runs too slow now - creating WAY too many individual Tasks, gotta bring those back to reality --- Diz.Core/Diz.Core.csproj | 2 + Diz.Core/import/BSNESImportStreamProcessor.cs | 124 ++++++++ Diz.Core/import/BSNESTraceLogCapture.cs | 295 ++++++------------ Diz.Core/util/Util.cs | 21 +- Diz.Core/util/WorkerTaskManager.cs | 85 +++++ Diz.Test/Diz.Test.csproj | 10 +- DiztinGUIsh/DiztinGUIsh.csproj | 35 ++- DiztinGUIsh/Properties/Resources.Designer.cs | 10 + DiztinGUIsh/Properties/Resources.resx | 9 +- .../Resources/1603231497loading-green.gif | Bin 0 -> 99120 bytes DiztinGUIsh/packages.config | 5 +- ...BSNESTraceLogBinaryMonitorForm.Designer.cs | 137 +++++--- .../BSNESTraceLogBinaryMonitorForm.UI.cs | 107 +++++++ .../dialog/BSNESTraceLogBinaryMonitorForm.cs | 76 ++--- .../BSNESTraceLogBinaryMonitorForm.resx | 19 -- 15 files changed, 604 insertions(+), 331 deletions(-) create mode 100644 Diz.Core/import/BSNESImportStreamProcessor.cs create mode 100644 Diz.Core/util/WorkerTaskManager.cs create mode 100644 DiztinGUIsh/Resources/1603231497loading-green.gif create mode 100644 DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs diff --git a/Diz.Core/Diz.Core.csproj b/Diz.Core/Diz.Core.csproj index 118b0e35..5fdafe4e 100644 --- a/Diz.Core/Diz.Core.csproj +++ b/Diz.Core/Diz.Core.csproj @@ -117,8 +117,10 @@ + + diff --git a/Diz.Core/import/BSNESImportStreamProcessor.cs b/Diz.Core/import/BSNESImportStreamProcessor.cs new file mode 100644 index 00000000..eb702c61 --- /dev/null +++ b/Diz.Core/import/BSNESImportStreamProcessor.cs @@ -0,0 +1,124 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading; +using Diz.Core.util; +using ICSharpCode.SharpZipLib.Zip.Compression.Streams; + +namespace Diz.Core.import +{ + public class BSNESImportStreamProcessor + { + public struct CompressedWorkItems + { + public byte[] Bytes; + public int UncompressedSize; + } + + public struct WorkItem + { + public byte[] Buffer; + public bool AbridgedFormat; + } + + public CancellationTokenSource CancelToken { get; } = new CancellationTokenSource(); + + public IEnumerable GetCompressedWorkItems(Stream stream) + { + while (!CancelToken.IsCancellationRequested) + { + // perf: huge volume of data coming in. + // need to get the data read from the server as fast as possible. + // do minimal processing here then dump it over to the other thread for real processing. + yield return ReadPacketFromStream(stream); + } + } + + private static CompressedWorkItems ReadPacketFromStream(Stream stream) + { + const int headerSize = 9; + var buffer = Util.ReadNext(stream, headerSize, out _); + if (buffer.Length != headerSize) + { + throw new InvalidDataException($"invalid header length for compressed data chunk"); + } + + if (buffer[0] != 'Z') + { + throw new InvalidDataException($"expected header byte of 'Z', got {buffer[0]} instead."); + } + + var originalDataSizeBytes = ByteUtil.ByteArrayToInt32(buffer, 1); + var compressedDataSize = ByteUtil.ByteArrayToInt32(buffer, 5); + + buffer = Util.ReadNext(stream, compressedDataSize, out _); + if (buffer.Length != compressedDataSize) + { + throw new InvalidDataException( + $"compressed data: expected {compressedDataSize} bytes, only got {buffer.Length}"); + } + + return new CompressedWorkItems() + { + Bytes = buffer, + UncompressedSize = originalDataSizeBytes + }; + } + + public static IEnumerable ProcessCompressedWorkItems(CompressedWorkItems compressedWorkItems) + { + using var stream = new MemoryStream(DecompressWorkItems(compressedWorkItems)); + + foreach (var workItem in ReadWorkItems(stream)) + { + yield return workItem; + } + } + + private static byte[] DecompressWorkItems(CompressedWorkItems compressedWorkItems) + { + var decompressedData = new byte[compressedWorkItems.UncompressedSize]; + var decompressedLength = 0; + + using (var memory = new MemoryStream(compressedWorkItems.Bytes)) + { + using var inflater = new InflaterInputStream(memory); + decompressedLength = inflater.Read(decompressedData, 0, decompressedData.Length); + } + + if (decompressedLength != compressedWorkItems.UncompressedSize) + throw new InvalidDataException("incorrect decompressed data size"); + + return decompressedData; + } + + private static IEnumerable ReadWorkItems(Stream stream) + { + var header = new byte[2]; + while (stream.Read(header, 0, 2) == 2) + { + var id = header[0]; + var len = header[1]; + foreach (var workItem in ReadWorkItem(stream, id, len)) + { + yield return workItem; + } + } + } + + private static IEnumerable ReadWorkItem(Stream stream, byte workItemId, byte workItemLen) + { + if (workItemId != 0xEE && workItemId != 0xEF) + throw new InvalidDataException("Missing expected watermark from unzipped data"); + + var abridgedFormat = workItemId == 0xEE; + + var buffer = new byte[workItemLen]; + var bytesRead = stream.Read(buffer, 0, buffer.Length); + + if (bytesRead != buffer.Length) + throw new InvalidDataException("Didn't read enough bytes from unzipped data"); + + yield return new WorkItem() {Buffer = buffer, AbridgedFormat = abridgedFormat}; + } + } +} \ No newline at end of file diff --git a/Diz.Core/import/BSNESTraceLogCapture.cs b/Diz.Core/import/BSNESTraceLogCapture.cs index 5a0cd4cf..59922d13 100644 --- a/Diz.Core/import/BSNESTraceLogCapture.cs +++ b/Diz.Core/import/BSNESTraceLogCapture.cs @@ -1,133 +1,109 @@ using System; -using System.Collections.Concurrent; -using System.ComponentModel; -using System.Diagnostics; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading; +using System.Threading.Tasks; using Diz.Core.model; using Diz.Core.util; -using ICSharpCode.SharpZipLib.Zip.Compression.Streams; namespace Diz.Core.import { + // TODO: can probably replace this better with Dataflow TPL, investigate + public class BSNESTraceLogCapture { - private CancellationTokenSource cancelToken; - private BackgroundWorker socketWorker, dataWorker; - - struct Packet - { - public byte[] bytes; - public int uncompressedSize; - } - - private BlockingCollection queue; // thread-safe - public int QueueLength => queue?.Count ?? 0; - - public bool Running => dataWorker != null && socketWorker != null; - - public event EventHandler Finished; - - public delegate void ThreadErrorEvent(Exception e); - public event ThreadErrorEvent Error; - public bool Finishing { get; protected set; } - - // keep thread safety in mind for variables below this line + private WorkerTaskManager taskManager; + private BSNESImportStreamProcessor streamProcessor; private readonly ReaderWriterLockSlim importerLock = new ReaderWriterLockSlim(); private BSNESTraceLogImporter importer; + private int bytesToProcess = 0; + private int compressedBlocksToProcess = 0; private BSNESTraceLogImporter.Stats cachedStats; - private int bytesInQueue; - - public (BSNESTraceLogImporter.Stats, int) GetStats() - { - if (importer == null) - return (cachedStats, 0); - var cachedBytesInQueue = 0; + public bool Running { get; protected set; } + + public int BytesToProcess => bytesToProcess; + public int BlocksToProcess => compressedBlocksToProcess; + public bool Finishing => streamProcessor?.CancelToken?.IsCancellationRequested ?? false; + public void Run(Data data) + { + Setup(data); try { - importerLock.EnterReadLock(); - cachedStats = importer.CurrentStats; - cachedBytesInQueue = bytesInQueue; + Main(); + taskManager.WaitForAllTasksToComplete(); } finally { - importerLock.ExitReadLock(); + Shutdown(); } + } - return (cachedStats, cachedBytesInQueue); + private void Shutdown() + { + taskManager = null; + streamProcessor = null; + importer = null; + Running = false; } - public void Start(Data data) + private void Setup(Data data) { + Running = true; importer = new BSNESTraceLogImporter(data); - - cancelToken = new CancellationTokenSource(); - queue = new BlockingCollection(); - bytesInQueue = 0; - - socketWorker = new BackgroundWorker(); - dataWorker = new BackgroundWorker(); - - socketWorker.DoWork += SocketWorker_DoWork; - dataWorker.DoWork += DataWorker_DoWork; - - socketWorker.WorkerSupportsCancellation = dataWorker.WorkerSupportsCancellation = true; - - socketWorker.RunWorkerCompleted += SocketWorker_RunWorkerCompleted; - dataWorker.RunWorkerCompleted += DataWorker_RunWorkerCompleted; - - Thread.MemoryBarrier(); - - socketWorker.RunWorkerAsync(); - dataWorker.RunWorkerAsync(); + streamProcessor = new BSNESImportStreamProcessor(); + taskManager = new WorkerTaskManager(); } - private void SocketWorker_DoWork(object sender, DoWorkEventArgs e) + private static NetworkStream Connect() { var tcpClient = new TcpClient(); - var ipEndPoint = new IPEndPoint(IPAddress.Loopback, 27015); + //await tcpClient.ConnectAsync(IPAddress.Loopback, 27015); + //return tcpClient.GetStream(); + tcpClient.Connect(IPAddress.Loopback, 27015); + return tcpClient.GetStream(); + } - tcpClient.Connect(ipEndPoint); - var networkStream = tcpClient.GetStream(); + private void Main() + { + var networkStream = Connect(); + ProcessStreamData(networkStream); + } - while (!socketWorker.CancellationPending && !cancelToken.IsCancellationRequested) + private void ProcessStreamData(Stream networkStream) + { + using var enumerator = streamProcessor.GetCompressedWorkItems(networkStream).GetEnumerator(); + while (!streamProcessor.CancelToken.IsCancellationRequested && enumerator.MoveNext()) { - // perf: huge volume of data coming in. - // need to get the data read from the server as fast as possible. - // do minimal processing here then dump it over to the other thread for real processing. - ReadNextFromSocket(networkStream); + var compressedItems = enumerator.Current; + taskManager.Run(() => ProcessCompressedWorkItem(compressedItems)); + States_MarkQueued(compressedItems); } } - private void ReadNextFromSocket(Stream networkStream) + private async void ProcessCompressedWorkItem(BSNESImportStreamProcessor.CompressedWorkItems compressedItems) { - const int headerSize = 9; - var buffer = ReadNext(networkStream, headerSize, out var bytesRead); - Debug.Assert(buffer.Length == headerSize); + var subTasks = BSNESImportStreamProcessor.ProcessCompressedWorkItems(compressedItems) + .Select(workItem => taskManager.Run(() => { ProcessWorkItem(workItem); })) + .ToList(); - if (buffer[0] != 'Z') { - throw new InvalidDataException($"expected header byte of 'Z', got {buffer[0]} instead."); - } - - var originalDataSizeBytes = ByteUtil.ByteArrayToInt32(buffer, 1); - var compressedDataSize = ByteUtil.ByteArrayToInt32(buffer, 5); - - buffer = ReadNext(networkStream, compressedDataSize, out bytesRead); - Debug.Assert(buffer.Length == compressedDataSize); + await Task.WhenAll(subTasks); + Stats_MarkCompleted(compressedItems); + } - // add it compressed. - queue.Add(new Packet() {bytes=buffer, uncompressedSize = originalDataSizeBytes}); - - // this is just neat stats. it's optional, remove if performance becomes an issue (seems unlikely) + // this is just neat stats. it's optional, remove if performance becomes an issue (seems unlikely) + private void States_MarkQueued(BSNESImportStreamProcessor.CompressedWorkItems compressedItems) + { try { importerLock.EnterWriteLock(); - bytesInQueue += compressedDataSize; + bytesToProcess += compressedItems.Bytes.Length; + compressedBlocksToProcess++; } finally { @@ -135,94 +111,26 @@ private void ReadNextFromSocket(Stream networkStream) } } - private static byte[] ReadNext(Stream networkStream, int count, out int bytesRead) + private void Stats_MarkCompleted(BSNESImportStreamProcessor.CompressedWorkItems compressedItems) { - var buffer = new byte[count]; - bytesRead = 0; - var offset = 0; - - while (count > 0 && (bytesRead = networkStream.Read(buffer, offset, count)) > 0) + try { - count -= bytesRead; - offset += bytesRead; + importerLock.EnterWriteLock(); + bytesToProcess -= compressedItems.Bytes.Length; + compressedBlocksToProcess--; } - - if (count > 0) - throw new EndOfStreamException(); - - return buffer; - } - - private void DataWorker_DoWork(object sender, DoWorkEventArgs e) - { - // TODO: we're officially CPU bound now. - // probably should create multiple parallel workers - // to take items off the compressed queue - // and add them to an uncompressed queue - - while (!dataWorker.CancellationPending && !cancelToken.IsCancellationRequested) + finally { - try - { - // TODO: use cancelToken here instead of timeout. (can't get it to work right now...) - if (!queue.TryTake(out var packet, 100)) - continue; - - var decompressedData = new byte[packet.uncompressedSize]; - var decompressedLength = 0; - using (var memory = new MemoryStream(packet.bytes)) - using (var inflater = new InflaterInputStream(memory)) - { - decompressedLength = inflater.Read(decompressedData, 0, decompressedData.Length); - } - Debug.Assert(decompressedLength == packet.uncompressedSize); - - using (var stream = new MemoryStream(decompressedData)) - { - var header = new byte[2]; - while (stream.Read(header, 0, 2) == 2) - { - var id = header[0]; - var len = header[1]; - - if (id != 0xEE && id != 0xEF) - throw new InvalidDataException("Missing expected watermark from unzipped data"); - - var abridgedFormat = id == 0xEE; - - var buffer = new byte[len]; - var bytesRead = stream.Read(buffer, 0, buffer.Length); - if (bytesRead != buffer.Length) - throw new InvalidDataException("Didn't read enough bytes from unzipped data"); - - ProcessOneInstruction(buffer, abridgedFormat); - } - } - - // optional, but nice stats. - try - { - importerLock.EnterWriteLock(); - bytesInQueue -= packet.bytes.Length; - } - finally - { - importerLock.ExitWriteLock(); - } - } - catch (OperationCanceledException) - { - return; - } + importerLock.ExitWriteLock(); } } - private void ProcessOneInstruction(byte[] buffer, bool abridgedFormat) + private void ProcessWorkItem(BSNESImportStreamProcessor.WorkItem workItem) { try { importerLock.EnterWriteLock(); - importer.ImportTraceLogLineBinary(buffer, abridgedFormat); + importer.ImportTraceLogLineBinary(workItem.Buffer, workItem.AbridgedFormat); } finally { @@ -232,58 +140,29 @@ private void ProcessOneInstruction(byte[] buffer, bool abridgedFormat) public void SignalToStop() { - Finishing = true; - - cancelToken.Cancel(false); - socketWorker.CancelAsync(); - dataWorker.CancelAsync(); - } - - private void DataWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) - { - dataWorker = null; - OnAnyThreadFinished(e); + streamProcessor?.CancelToken?.Cancel(); + taskManager.StartFinishing(); } - private void SocketWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) + public (BSNESTraceLogImporter.Stats stats, int bytesToProcess) GetStats() { - socketWorker = null; - OnAnyThreadFinished(e); - } - - private void OnAnyThreadFinished(RunWorkerCompletedEventArgs e) - { - if (e.Error != null) - OnThreadError(e.Error); - - SignalIfFinished(); - } - - private void SignalIfFinished() - { - if (dataWorker == null && socketWorker == null) - OnFinished(); - } - - protected virtual void OnFinished() - { - Finishing = false; - - importer = null; - - cancelToken = null; - queue = null; - bytesInQueue = 0; - socketWorker = dataWorker = null; + if (importer == null) + return (cachedStats, 0); - Thread.MemoryBarrier(); + var cachedBytesInQueue = 0; - Finished?.Invoke(this, EventArgs.Empty); - } + try + { + importerLock.EnterReadLock(); + cachedStats = importer.CurrentStats; + cachedBytesInQueue = bytesToProcess; + } + finally + { + importerLock.ExitReadLock(); + } - protected virtual void OnThreadError(Exception e) - { - Error?.Invoke(e); + return (cachedStats, cachedBytesInQueue); } } } \ No newline at end of file diff --git a/Diz.Core/util/Util.cs b/Diz.Core/util/Util.cs index 550213a2..71afd8ce 100644 --- a/Diz.Core/util/Util.cs +++ b/Diz.Core/util/Util.cs @@ -93,6 +93,24 @@ public static byte[] TryZip(byte[] data) } } + public static byte[] ReadNext(Stream stream, int count, out int bytesRead) + { + var buffer = new byte[count]; + bytesRead = 0; + var offset = 0; + + while (count > 0 && (bytesRead = stream.Read(buffer, offset, count)) > 0) + { + count -= bytesRead; + offset += bytesRead; + } + + if (count > 0) + throw new EndOfStreamException(); + + return buffer; + } + public static string GetEnumDescription(Enum value) { // example: @@ -110,8 +128,7 @@ public static string GetEnumDescription(Enum value) // take a enum type that has [Description] attributes, // return a List with with kvp pairs of enum vs description - public static List> - GetEnumDescriptions() where TEnum : Enum + public static List> GetEnumDescriptions() where TEnum : Enum { var type = typeof(TEnum); return Enum.GetValues(type) diff --git a/Diz.Core/util/WorkerTaskManager.cs b/Diz.Core/util/WorkerTaskManager.cs new file mode 100644 index 00000000..d3f81059 --- /dev/null +++ b/Diz.Core/util/WorkerTaskManager.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Diz.Core.util +{ + public class WorkerTaskManager + { + private readonly List tasks = new List(); + private readonly object taskLock = new object(); + + private readonly ManualResetEvent notFinishing = new ManualResetEvent(false); + private volatile bool finished = false; + private Timer timer; + + public WorkerTaskManager() + { + var oneSecond = TimeSpan.FromSeconds(1); + timer = new Timer(state => Update(), null, oneSecond, oneSecond); + } + + public void StartFinishing() + { + notFinishing.Set(); + } + + public void Update() + { + if (finished) + { + timer.Change(-1, -1); + timer.Dispose(); + timer = null; + } + + lock (tasks) + tasks.RemoveAll(IsCompleted); + } + + public Task Run(Action action) + { + var task = new Task(action); + + lock (taskLock) + tasks.Add(task); + + task.Start(); + + return task; + } + + private static bool IsCompleted(Task task) => task.IsCompleted; + + // task-oriented version of below + /*public Task RunTask_WaitForAllTasksToComplete() + { + return Task.Run(WaitForAllTasksToComplete); + }*/ + + // blocking method + public void WaitForAllTasksToComplete() + { + // wait until we've been told we should be finishing + notFinishing.WaitOne(); + + while (true) + { + List tasksCopy; + lock (taskLock) + { + if (tasks.Count == 0) + break; + + tasksCopy = new List(tasks); + } + + // anything in our original list, let it run to completion + Task.WaitAll(tasksCopy.ToArray()); + } + + finished = true; + } + } +} \ No newline at end of file diff --git a/Diz.Test/Diz.Test.csproj b/Diz.Test/Diz.Test.csproj index a431ace0..ad2f4dfb 100644 --- a/Diz.Test/Diz.Test.csproj +++ b/Diz.Test/Diz.Test.csproj @@ -1,7 +1,7 @@  - + @@ -145,9 +145,6 @@ - - - {50646b00-03d8-4cec-9ed1-3ef4cb199e8b} @@ -158,6 +155,9 @@ DiztinGUIsh + + + @@ -165,8 +165,8 @@ - + \ No newline at end of file diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 2b1970fe..565daf5e 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -105,12 +105,33 @@ ..\packages\JetBrains.Annotations.2020.1.0\lib\net20\JetBrains.Annotations.dll + + ..\packages\LightInject.6.3.5\lib\net46\LightInject.dll + + + ..\packages\LiveCharts.0.9.7\lib\net45\LiveCharts.dll + + + ..\packages\LiveCharts.WinForms.0.9.7.1\lib\net45\LiveCharts.WinForms.dll + + + ..\packages\LiveCharts.Wpf.0.9.7\lib\net45\LiveCharts.Wpf.dll + + + ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + ..\packages\System.Collections.Immutable.1.7.1\lib\net461\System.Collections.Immutable.dll + + + + ..\packages\System.Interactive.4.1.1\lib\net45\System.Interactive.dll + @@ -126,13 +147,17 @@ - - ..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll - + + ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll + + + + + @@ -144,6 +169,9 @@ BSNESTraceLogBinaryMonitorForm.cs + + Form + @@ -283,6 +311,7 @@ + diff --git a/DiztinGUIsh/Properties/Resources.Designer.cs b/DiztinGUIsh/Properties/Resources.Designer.cs index ffef8c0a..aabbe231 100644 --- a/DiztinGUIsh/Properties/Resources.Designer.cs +++ b/DiztinGUIsh/Properties/Resources.Designer.cs @@ -60,6 +60,16 @@ internal Resources() { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap _1603231497loading_green { + get { + object obj = ResourceManager.GetObject("1603231497loading-green", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). /// diff --git a/DiztinGUIsh/Properties/Resources.resx b/DiztinGUIsh/Properties/Resources.resx index 24b377e2..b6c996d2 100644 --- a/DiztinGUIsh/Properties/Resources.resx +++ b/DiztinGUIsh/Properties/Resources.resx @@ -118,13 +118,16 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - ..\resource\diz.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\resource\diz-4.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\resource\diz.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\resource\diz-4.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\1603231497loading-green.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/DiztinGUIsh/Resources/1603231497loading-green.gif b/DiztinGUIsh/Resources/1603231497loading-green.gif new file mode 100644 index 0000000000000000000000000000000000000000..1fe0306171173cc689d08a8dec7d662f59170d9e GIT binary patch literal 99120 zcmdqp^;eUD|2O_?$>`BxFc1L|2?J1!4G}375tR_6q)R{=*j zNK1!+qU<~M^M2o-AHM&w(Hq^SJ6Tb$s8A{LXT^OuO-U8rOG{J3EtO=uoC6I7c21BD)7>^ zKG*8~u2luf)CXQ`2t^n9DwO)&sR&Xn50-BTy;mEiQTaxrHcYK9{83fJqxy(vby52D zafS`=jT_@FJ|S4%-xj4p{q#nu_9r}Qje6c3^Q0|Kr!7IFKT+dz;)|9< ztJWmVkqn*BnL3l1&!!7(TT@MX)2u$_IJRZDcVxMDXM402IP~Uub>|s>PB$3MF`h1T z_?+)SDtI+g>N!C0nkqM*D>PXww_2#M`c`4PSYy3e=Rz*`UaWK6Y;fFZaN8t0?YDRw zw0Zn&b35qtr1biB7Y6nh`;m(M`%6PVRfd16#1EB+4prc%Duafr{U>WfrW&G#>*GFu zj2Ul;A8$+8Fy5Rx+L}4po;%f^J>8u**o zz(H^5P7j{aAM~rwk1`ZW8406IMp33y7rF}OdU97jmCyIpkUwQD4dgA6Qa1++*M=(Q zKi4gOE?pU|+#Jh2n8>0`75tuvrpzT!7LzDzS(N!q%4PxOTM1>MnlfAY=bOC(%0VIJ zS1DzufwEgcp)^n^EeoG}7p7V^r}{Ui``5k>Z!An~%(s4@ZKZ7VQZ|P77shv%M!&C4 z?yd~|Uhk#swNfa(6v}4`Wr{+X-{1K5eQ)9T`zq!80)?_pp?s(Od4T`>AO0UuS{k4c z;HS{vzoYr+Hb(uU^FH2EUDntaL(iT-%x8I?q( z5&;GITdd|Mi33F55U5Ac8mu&x?7g&|?UaR{4<~O$ zC2B{;+>5vxDJ1yV7zavGzk0Jkwlroyug=<{BDXxBsC($m9GgC6RIJ;7V1=z-(MbXGMlP>bY}7KL`>mx9q$>sH{1%4sg{7dB8nc5 zt>!w)P5XYzUH$4G9s9@%U+rqAOG-12xoO^g``ZLq&HDc87pZwt$(^A1SB{m$Yo{4z zijJ_*)j0Pb%}nB+uH-Kn@@Nji$vj-&lk{Wn<9m9pIqGH3(TdYaVlHp`n_Nya*VO0i zF5S^PQ0Z_!ss#+}eH6@tmQL80X}a*ePIeVgd8yJjK=KCK%O^Z(1hh`QPQ5&)ES#1T z6LpTyU|(NPn2vz<{N%U9tNT5ulHWJkbBtCv1?{Rq6Z4Qe8jvF|eASV(G(R0C?T|Jv zeDwwSOfY>Emdh^eT?{$&)W~6Kgo=J?m$G!q{`}io7A=D(cX(?I-d}NW>q=1Rz8D*6 zY@1DlL*j#GjTZ*SOk-j+1)3G3+xpF4XTsa{HVr;4O)mXq%OIVOI|&Gn3MjEI}X*|_^g z1!u1bImufJ+sXh)V>Q#L45eeyf_wt+`9M^ZB+om3qn{#ZI4`#_DVo8Sb}1#6cXgu@ zraNNYLeCMdm; zi2V1Pv_xjc6Ph6vI9AoQI-h5uQYbN1AEY>)%fZV|n!cUQeD;>Qi#^z1{DCGAFT+g- zAWFFmlR`+aY4a&KiTLELz}VRYKZmk~qxif?XJzX`wuf#|Sd@kz9&86-{26{fDnnZ^ zKCGOO){`7Ip$v3PJ?zj>KW6-@v%HVVZ*6cKGnunF;Pk3i3(u}rMz+t;K30?LfsWc# zPI+0U)-0Maj zH4O-B5y2Xm*Wp`!2&NY4Hzq_JV!P!RLhGYw=O_Hr9C?l$qP*x<6BiRIIUSwT$fk&S z{Y1%-BQ2%*RAso|@slmsoW`6CFOvf6V?r~XZnZq0;%tz*rvQiN?3pvC@pKyXhU`_Y zej@kZ$#BH}jA7&VNKvMuIPAJ`jK>3piB&hK9**7lM@~1bKp~5*OH*B2d z&_9(r<*%i_!Fz%Qjt)CEpc>(gSRekQ9HnbI8gFB)1;4jz07`UFx|jlEk-HYk_ojtH z!>%>Tfoa?n1jCkL_eooWgybYs+G17?#*s zMe3MpGjKk~*1}BtK@gXpWl3uprl&n|AFo_g3$+b@c*MUE)~dPmXL^Sp?Uz&eIblL#H66X1XUSU;3n- z3$4SBL5%R1$XK^fdS~oO9u30yh;3yVVM>%q-z@z8R3($`83^5zo@X++a5IUVd$uNoM5 zuJ!Ag@2qIZN}?KrQ3~#`-KFt7`GQ^2(X)2NCjvK77w!(L8iLu$^n5J6Jl*yU|(8o|g zqN&KlVGBwhIxNe>f48F_SNqj^E+bp%RO8_b#&Z`0R zmr}+)aF&5lSZnA>k1umsE)D5ncFc2!#OW7JbnaxjOzt!V37*oJWBS)ykVLszCazbd z6G@hCLlfZd&giyXF9Y@*EFyHPTjZKLpzj^m%pij8^1ZQU7~rb8i0Aa;?FIG9^ zJ+<6wcPA`aded0(62U54#;9S$l`Y_1jLYzW{fO|(O<@oR2_$b%XFH5QDA|&h>^Jst z1=*IYTAsWHKDk>e)mS(W668Jds{M&GBaKgi@JkML&`AQkdP@b?gt$onn25eiPi^@+ z0jXt6PIbJJy0=OoG8>=~AOlP&(ES{D30G@+;N?Xbki-_8K=9)P(T8rquB3pNkoa67 z5R)WUpNO!@xdH+K|K0~1{=EEws4ssnfB>qH{_#jS-;v6r3)ybM1@8al(ba<2R2y9{ z!u?Ybl|e- zg;8Cs;l~)GhB)(&Nq9Ct80q}Ak#SSJRcrF| zzKlmB={h5sI#ZcXM{}M|=ju!sShuE|_GOy)XW4wpb!f|QYtM4*&T?d7}7 z$+aBLHJUDTCgph!7kYjoIF3|!4VAncFZCF&q-x1{vD|X8!fLg`db6I2B(If5$K3{} z{nkH7I%@Nx^!oJv5t4s@Nnl@@-vA+axWaFyDr~s=%|z|H!OG~N+PL9{h{=ZZFCPOI z>O&SjM$UeW86n1x5TmD?lE#}d#@lix+p@+x3#R(YXL{exw?!?s#VxhRt#(8#b|$X& z2JCcDg_N}2?@t;2uaFWc;~Deag$w-|tNo?(eMJkTto4DS_2KgQ;rjWZvdyv7T~f}$ zSjG2=nys;D%6#Hq9#L(SOWA1HnXRCFt)(oKQdS!N3aOB?Uqtyupd9?;QS0JJ^TK4` z!c^<}1XV~)`;&cZ5ZNCp$~H@-A^A5onY~ znlk9QnDeu)(uKC$@+U<^+)A^sP^M?!Cc9WhdEhYA_(@)=CTOx!B$FTv54xA808vXx zEw}8sEnq4?W$Dl^kZ*8l9Gr&D*A7CkJI%LATdSh@KXr4UL7j?~u5L9`=HFU|YMz0h z7MbtXi&|=(SEdq>2)~cm8c|X>%jT?Jt<&~++aVbbeRl@J-GoSg(Hm#AlK0syrI1

S?2)%Byu*egavH>H2yhE}LzJD<<4b+*tpMU5u-?8;S2- z`VCf(wNh@%paUnq#K?>;Ovx2!l@rgOUBJ~(0+r|O6zl756lwv@G^ZXo4V!(?228f@ z7#^*(Cwo)cz&-d9hGmWCEgZt5CJeTfdXC2p!n1e+$%tQ-8|_S1w|o^i?#>TZ5)eyO zs~&PXZ_9xO1W$hb8gLAgH5O4AS!QK^v7n?0hV_QG>oI0=&IPh@^3aK-l9~tk*+ncg zK%7o2imKf!imEOwOxl7X*8T!Bin5E`Xb^umG158r1~-57<)SX31cK9LsQGz#3YNza z_1M%D)2)^H!Q1C6tw@QrNssG!QG2+1uzRO@x}XkEZbotxZ+8$4C{@6q%*_z4b!@G? za{5D>qE4Q0(!9<&#WX=>J%Hh4TWs=%pUQkr)%$T;;Y8Oodc{ixqFlgb zbfsvWSXpnQ!$Z-=L7~`_qjVV|m0qWhmI{+x!Q#Tvk`rACus&3xIcE6X2D;+x~EKf_~1qbDvy0{>sf$EB>$52y zTbFyqlTM>aRj5FERwY!#{6!KEqPL#E7RPm&Uiemwjq}$C$wt{Z3;KDYJ@%<>xR~Py zy{fMtsu~Zc8yI5HX<1zO+F{o-(=|&UD5yh=gDGwH2ti zX2=;8>n8+fk-RNv#8yFS71b#T)-3UJTQ5Urik~g8G`wQu6w5?FN1)y^uJMlIx2=y=^4%J znq8`*dn}L>^TDvdKqXz?viBLi3!=Hi0DS-_?X;J|E~?z8quBKR5m87ydn-_%JxrRu zcjj~o`o3lSZtOB%K|%{xk-CNTb4P<&JC#3Czm0D{KB**Gb5Rbi52lqH1ECj`ABaru zCTegavIN)w8A){(P*~1&muVnhHEi>uHX zf-X}jShrwf_c&kgih&6Wg2B!$a`g-3@Bo14057;7`Lb3YGz{G-H1YCya;8AwjK+lokcZ>1(72Nj;}ofS5;n0$UGt3yKdn$87Fyl=Lc&|Sbtu|S-$rum zO)MBPw;%yBWtiJd=IVd>eiwuSd<0N5{5FUd8u2YGjS_jtqY(}B{52;*f3>&n@fM3p z6Dvv#3s{^6(#>Q1KtF-j^g?V3^}M;u@{i$0mB++ki88jJ4{cv+n_xH(hvIG5*dzHbi_z`xm(5FG-N6R&s+v90`CT$Jcz+g+C-2PjXk9Q*lssVZ@tYKSbBHkr{8KaOiF}@S#)bgr|t{TdiRL@ z`MA*;;l%r;^ZqZ=19e|1!7vsSsj@9dV&iE{!j_*mK#2SeRQuL~Pa-SczD09aail^b z&78jk7;Y}PL1H{BMlGs^UyE#kRn+AwQBdU8b2_Z^iM!Z&Q{XJotINeTFx$-C8FYaF ztqi}JPJ}Q?dd70O&idn)+PwIdyi%5&_d7r$TM*Zno4Ej#jSSR1!D$G4kUMZIm9`(8 zK_UQLf9Xy&63#>f9@5x@WL`;DJ9i5^CZ5cUV~rcB3`#I>OuE$?Cf^!%`(HTJ7fl7w)0P;mjzp?{ zp7kVClOdDl1k09Wz23A()NtspeyHxTX-zZkNq^avVc(VI(Ua}ek>k~#|EfFJv%A3b zbAk0p0Tn$~lLfDa3*AY@-n|6lnNsr^g3D-y=WwahM49_!rT0vY@qD2<`9B6)tFT$B zwc4z=Un+N4s_~ewci3!j-TX-Pko#tn<9@3;IVqUp`W=7agBX1hxrq*2J25NgwD?gs&YotlsiLiDG<35qA!_bKxy*l&-$74h5pT$3Z3 zcPFMl_Kd&nS%MLF@A;vjVmFpfiyyVIs(MQV&8lOOxm3c@_A0P~e6`id?&~YUAwF~$ zJ0s4GoXtwqfoTH%mWc02IP(eTrRmpvJ~=2)p5IrV1BhyM$aDC&fRr%0W>$JtL%`e! zV9GJPYuLPU(Krm%Y?K*YYJXWZh;WWP|KiXskpA7%=AG{IC1i6F<13pd?A(30bLjyl z`fiJHcTMr#zDwFEvoGrKJg35>-&-sunFR+T5h_J6BE3E!N^-ySMmsYpFgVR38S$>! z%m`Ss56FmgHn&K9BJeXP_@egB(4`C3(Bu-ryjGIX*_IC#V7cDe=(Y0(Jp8eA>jhKs!vP9|!QY7F?1 z@D}*&&V|-3ch=xmu*XG7Ob#lMGvp)}zNd~qQp{fXvg06a0T}nNP>;5Az@a5x@%p8< zq_Jn0g_Rt2n)HNV#GOyjHn0ux4BI`&J|)MrppgX6i{agOe=xkll!jivJfdV(S}_u9 zKe&$;I+m@(6vukL8qvw0l0Fvl*iGuvby%Ccd>>SB*#%RaQdlVzE7pH77yHaXSxEaE zuz!#CA^mC5{jM*CMn) z(`=f*zx#3zHXiyGY#yW56CQkiNRx4k^lNu$lS1)D;`yPNTSqW|$)6K`XP57yf#U~A zB%X|-Gep;+)V)EWDR3E)CV2&dkJUpo*o8k39V>~%iWs6~J2A-8Hjy8yDJTHb!aKNy zm+eiZ|Hyj#_m{1J<0}gMNKgqq1Fb1uZyC%5ylWMgeCMx+G(uWbhxAOD7*6Lyxhkvu zgxt47)HBjH-hcry=?AR3O2)i3)px`_2SOCqupAH4K)-)u=ylZ7PmhkZUl3wJve!4A zyywugXak~mRhvJ3Fm_jY%}0MaCmE1mffuU`PE0}Gs=9B$#Sz@i` z3r;!>$i@wPEMSnMw0aI-^Bsgh$1dMIZ#nQX;t_rJFqoe%BGA(Ba>CZhTu^xp0PeMc zi`>aodHU^>y?hgGO}URK11l~*R5KeYO9U|xLEIHVSOTX}0?*w8aSWU% zMr#H+5PD}tRX-T`eL9%|M{J#c0Fu+nRe1$m%W0|HBZ1q*Ig1>oELDWReGcB?=MOVK z#%hD8FY~0zN&vM6fhR-;L|8J4m}4v+gp3al8l;6+Sh4HiSh!4_GpfUEZRF&}rfP|K zF%RYKpQ4@(U92o|Wc+6N{fACy>yr$P%tCjox`|xyK8Pko9j?(4!JKt$%(Qu^K z5iFDWNW@&xi3r$ej8-BP?O$Eh#nK3p0mfyVRF6;KjYKllTbS41<(_?Q|6GlECC?{) zk)9Q403=6S`q;_o^@HEb)4EE+$0TVAB)=lXL~yi{1+$FwRV~@S3C1h&G*@^8VGr+Z zgKT@|_fH$tGMb`8*(9Ur3TBZvuD0?Uq!_cg#&z6Sv~>wOni}RcWD(mY9)qvRJ)W3; z0>H;?K$AxR4bin*>Lwc6E;;)Kg+T~$V`yvF7EYPDwir!I#Q8Dcua`qPcu)nw9BW30 zD$#;8#Ih_d0zjLS!eFPQbaFbyht&Xp2%?%&X!Mrp`Nlh@7VH>!bzzH@^DyLA0kwbu z(y!wtH29;7`7bS~J%|G_U;z()Bo2|t3t^81U|BcTALYA$#!K(zUo9}->`$S6Lso`q zteF~e5dkE*00NK!1X6d1ma1C63u~qm9$+?ZP{oI^Z&qfy6M@Iu_Gaiw!9zTRS-+G3 z0<0tI$3Uz8K)tcprpYbz7%Rc0Z2O)K-PXj6-?4-LaZB$yx9ceRrr{l$taw|eI@u|h zy0i`dnFVe++3B6EDkv&^JIv8@=93UE<>@I0$ul~=LQe~LLMPu{H8B9yzj4bvrEUfg zjuu@N0SG4mGI^dj%^O4flz+;}yR4RUW=6a~RTuWe#E*gJ@CxCJ&8xgoo@t#=R~wpM z+j+UvubE1?kG~b4L|so4b4;lUF|$2*_3>zogYt8F^M-Tjfyc6$-S(@SL}h^1u`TxOFWAV)_e*eX>iQ`j_Ur4wvwpzU~@jvsi*M6@{S0GP?I*aAHz#{77=Jq)ybMNrU8@{JsI z2n*UeU&hWZ=Ov2)jzJQ924!RYTo#mL3Os-zOvS7|-zy26d zXf;ilq&#c@aYHhQmFRsz>Gcm&JP#TyWB|`b1#=J3S%rhRs~mGX`ac;|fzv;BQ8TD>e=2&;|JZe*#FNS{ zxgxB1xzB%+D7;Kn;LVC4xrPw=QoKsJKe{^Lc4d%S`JXWAUQL*KWvF^>=!2?o#fEnp zRqr1EC7AlhSp9}L!^Y_UgRh=wwT{@k{qa-w`IA9CAjNA8CmB%{*8I1h zHz_T(84W>^em{i*1U7J2s( zTt_QjO;>o$R2wf8{ZHt$UP;xK$9x^tS)QwZ`g#8wSw1~Qe!YZ{{)&Ksvf!cekilB~ zSZ&BeUDR-0{755?TpL3E7%|hFNR5~#TeD}n3Z{CgnDSq34P9%Cm~Ty&D&fa46;rX4vDAf*)PrM}F~{?disf~A4N&5?R4slJVV z{5IOKIi3D}IOWGs;r^F2%0wY$y5eA@jxrPVw~$ALRT^cpf-+zKYp#T{(nwkU$E!lh z5jATnqfqK76l&JgIzQeyH{QBA)w40#v;L=zH@UIU@_V6~vN3Y7IJLh%MA?|2Z2Y%` zH$kC%-Cv(O+??Op+Bn!>Ki;3GP}ct63Yz|7tpA^%RCZbXmtCgYO{pL-2zf?Pfrx5h zmZbfgK^e>6*SpA$R5zGc3KCJ~L}O8C5WS9;TcUEA5Jnx1jJh6In*AUG!TyVEQkL`3 zCzB}ad03V^1g2$gy{=M`&c{j@du^(=0uA9y$qT-+d{^N~5vV%vj)7sp#M8@Kc}c3H zg<4`K>7YugRd$c)U##(-<@n0~{38qVnI}kj!o3RuEULD2pQY~6(+OGa^PpSL_ng#w zF{XCy1whY@F;ipnFHZ zD^vQ7C$AMg6-boM?*Hs=vQbBWEP_2gRT`66L_3T^G~D1ReIe%?TJJoOk4upg>qjC#%Wbo6DLyoDBO)q_<^=b0%UX z*7LNU)xV)=_z97fbYHYQPmiej%~*BX@2P_PDgcS#_a63pEHm7|hv$WSydZ%G(8_39 zjF1{U%!tV^NK;9NSY$o9sc?y6^!D7hO(qnkHzI)! zgUiX|1d1Gv#0&G(RV8YmZ*|Q%e>!BMv)7m|TM)scaz(9in$|_=`=4av1 zPq0D(2hwHTi+iLvgNQYTK#ehuA$T;ym4QcWdfUSXMrgq3q`hAFsPO~6D`W3lPss?q zXP+WI3xE*{kH;aoJI*VX8nkJNRby`Y_6A&c>Q zL={(*y14t<`TEvte$=lsZxkec?+xGP`@I=))$Zs_nA4`$ftx+W>tOJbUDhKS#I56>YaS1J zfWS;UxifpCcHT!DeBm{=g0yctD8R4hzj+Nm9u0skocM{;oHDd>vXWR=0t5<*4WL}{ z;dEi6rpc1P;dc|j%y$N0uc}cVZo&yWrO=%@yhW?A<#Wol6D~K#4^CthfM{VEuP)<; z7gCvy(F{g(kCj@1<02){*z6Z;g#1}&$pEMp`r9{jfGFJn)6*yv%Q}iy#~cHwOd8Te zcLG8;r4S*i&{OlMfUBLU!A{7ulL4}HIQ%xXfF}TQC&(&v&eB;k%%7N*?LaYQgt{^q zvte8Tupsuu1-3Sh0(%&mP9xktG#yDZ2$K5t&KEU22U7f^^yZ}%%i|m$4iRN#X??@6 zm|m09@Mf68>j+;X!AxrLOW8K)E2CzLyy#=)E)|`f2)hD^ApC0(RPbT|ToNm;e6EkU zCC1vsuqYX1(W@fh$drXb2*g#ln2V$12d-l;-?hNf#%ibr=g6~Xh2OKua)@p_UK2X8 zs*dDcCixEyFI>w#caOC+ANe4#`T9y+pAGA!4_Gw?%r7Dq#BBijmSKv%6o3CmNj~iZ zrDgVHNtpk*W9(sp;HmqD;dIt}nQKnKIXMH;jmN39_w41B*lJ1cPcX3}4d7dhU^v{I zJqg@rjyBuspUJ_|%J!|?chk}MU^_$?B8xbWN>Po=b4)trmCIa^D<~s|qcso9yMOx{ z%@{=6!Ndp{`mvE^d-3hHlbFCZ7Za`z=$8^F$9bcBkk!{78t9vi6Pfkz}$&6jO zDiaUD1<9o_?)+Eq1mCmloQ3Lltc~t|8~H$YDUsF<1BS-;t!GF? z6PL+5fP1=`r>W7t5A-&OLGUEagk>C~bPkSjF+q2AhqJtKp-7(IFr9&@8NcFJ_`2Fq)Wsx^{f+yw@(b5Eo~maHHr6{->H z{YB0RNIzLpE8B^&Wh`vX@boQm&vSnON^PKDLUHq3qaer3nkiuR6ckKMX(#wp@4V2h ztKIDFxxC9NYN6L&)ZCd>V(93+T&j#;_O~;@6)=V!Yjtsn!iO4Tp<#f5$td7F# zm6LIM;9qmT(y}nkdpob{bVgXrW$SHD`39ENFYG%zFr|=aI(}iGIB97JoxVNaZSgNt$nMN-pD6Y&(W89 zHtrHN2;#;=Zut}-(W7S4APYOe^ZSR^r&Hrh-mZyfZWCD|pldnaN(R zYqoK#?W4!Ctv+U8^R?3n!BqCXuk!Q)Bw$C=@#d<%OC{V^!d-Xf=QgVhn2&cq_<}hZ zgrD}D7`Wm6fV%cbAhgMG{MNZ3wN9ioC_ z^DLviCJ7QSvp+-g`Y^_O!R)mt5~rl@T-icrumxg8IdmU5AJSM=$9PzqLOjs8<`%UL z8IWwCtr)^ZcnehK?_vEOte^7oN-XjN33dhz;>Lp5h?ca6mV8Ke5qt1CN$86$+B>pr zg(HZat zZf_D*I4_zLEn1RvyHhkj|IL{uvvfvtpH3C%P8XWBrrETlnsleVY)f-%%XI9?^61QV zY|nM;$Z_t;_2|hr9V)OS%D0xCTE}7cx;F z{kbk~q%mTmA#tn`J6|8X@G<)9$B?O}#F5sd@#eINmh6eng6V$h4#|(Ipw+g>ugwW_ zZSm`Ue!Hzf2mMq6MQ-=Reg72xgBmOi|ASEC?qDS4b3A1<@(+h*GUj^OLuvvQ|i$ zqvlNcl=UjgTp4A(ma>{j*~|a4Px>RGy8obvx=(6dnCM@eZrhlkqG)JizW-pcg|gU8 zS?i&!jeY+*d9X1|*_fnkbWnD?D7!5bN;icv^L=-mvOi3rP=Q2UDb4L|ukY{A|JvK6 z9Q@w`B&uy<{$m?@raCqgUtb7VKqYF7>=TFz^FK@N*QIy7Md(F;L6ZS6nC(&CWj8F* z|6&okJ5f0@MNANZL~C}HWh*4n5#Qtw~uO+3bhrJ5FVLVR(Bdc`!Sk>@z8a(G!pHtAlw8$jMQUV8D4 ze64!>5mYcwU{T~Q-Z&a0p1p@M+i7QH23wu(+m&be1P^dS^^IpkhozOvlM63`tZ~j_ zL(>yo^rl4M|`2hn+w<;VgKfTf{Qk&HqJe=Pjv*+6Y$rX0-O zhfX=$=ts}b8u)6r364g)h$^EDwVldwAb(a^$~1%v%JNA2mgJ(=BZC5*7SG)b5iIou z52tf}Ne@nhpO~z~z~R%Cp|o;W;80pM7UEB(-X;v_MeEMk)UW33H{>V&NdO1n42Te1v%g2hOU!jAPj zeX@1eWAiRboMGrk9|-J`8V*ZCtABl0BlXE!T`!loBcoS7VBmhXWDtxw^=hDCZ?Ixi z-@C7StcO}l`U1(g0RUFTjM!kd9|2beZojoTm@hHtFaN`T4`Fy-MRWu=uYBPy6`a}SxAnqudmM&kr zmKo6By#h%olAZ~ZP)E-^H4f|EYUO(HOSJs$Yo~7>#c$j}$r6s;=d#r7exJ)Ru=};$ zBS`d|$uF}-gYFshg`8W?e%tW<^Yahgd%0r1O#qajkN&;SC3zD9TfX%gWF+}q1g=C> z&)CEcS#r^yolQ zRwacAS_b1+R1Q?+1V_A^pJTn<6oPB@2@~oy5vF&;NcV3)Dd%oQDQT-bN^^J{0fl1> zcvOG$Tnag>h6YQj!yUtXklu&B;%;A56>qXeD?za5e23FqNgJsExbz;_&g#d9U z!w=8N+1Dtv>Wc1PQ7^)muCIOp@TDbiN3tfWn&=ns?NZwBJ>e^N;{tVZl)<}e=3oIN z=UY)nK*^vrg`vdnLilj1aM&{HXHEZY0=o`87X-nZ4`qouf|SCciC{y&$;&*mKb6bN92yoj@kx-=ctru=83N`Wt7d!zQrc@BGvRxONm%uYJ)X}(fe{wE>a~aZ^U)=AwPZ%w1SZ$`Ps70STpO`mj5{vh%Unb z?m^tdP=CD;8BJY!ftZvEARAyUVi2Q*F|(%*hQUe5nuxvIc6D}nFsAWpzZ6Ww0C!Or z3qi?Zj_EWBU=9KrX04B*H^I&eO4PJczOUQi>b?$IVv3$Ew}=D|;;k zrz5}gnk^D(g_3-(w8ZsYh;>ZbEbzTgks*4(i=%#vjo##LgE5(J;y>0eE579!JQ;W; z^SsRpN2m6X^I~~W-Fbrn*4Xk4PW{Y}x5@zK zG+oa0bHd{E7BK8_`T}lBM+bd!PLx0jzW6q2ZN*f!gN=JPJ&Dog%2VF{k&(+0FG(}3 zM+Xz+#WEw@RDgEu0+WCeI%Z&(^YK0z#cBJDv{GpG4pH^1JZS&Qf513M6-rLCh- zg4QSX{uT+_OQA->ybGP2N8Q@TYk@;Q2V7^iMlExWVB7g zY21r5zi0P~4raE!th|J^yKL<)x_l4y6C(yONm2iCDTaRD^B@JhBjk}0H@&Abl(_EF zU!5I8d?{mXq~5ZHfeC#w4=B67YgW9Mka=M#*gJWqR=R|J(*DKW8z6X#_rb!`fd|fI zqxwG*1KfuvY!B~C@Y6>To=AlweH5)^_e--IS~nS&*iCePUHRx1luiiP6X@Z%Nd$#* zf|P|l%tjn$WL`QrTUk9dvx$MKZo##MFGWg1g;PKk@+_5gd_)n~uT8ytiWvG`UKEhM*Y+9wDoUaM4Z>(#-kfn5hKf)g>(Cvbv8X4+%64X3~M864^bu~q+RhSDTb&mD0&M#xaf0U5~30gC#ZWp`fqU4{=adP zW_R}QZ3W?iSO0D+{O{$ESlMeTYp916t`y_`$fgu4_3ySqJ?>v$4pWS$UR6*mqnhSV zYNJN2%vHX5So>DBF;cVcoo;<3^`rvzo`U7aWck+6|Iti$lyV1EGYOBHqqT@J54)nD z{s%N#{U0=j6HS`pE!&a}IzQ<4rfU9M4ozh0PUkhIFL*2SE{JX zA=hv9RLwY1J8}nYF2AYcp>|J7AHM(3cnCjO=+|Es+*j&5P!c>;@n*0FKUNboRueH; z8AUbC=Z46!#-z!{#F6IrGtEg;t!b03nN-S5^-w7jy3+b?zAb^=6uHutu+$Z?)|0&2 z?X%O2{oWb8*G)Ce+rxf8%ICkDnM&Rri25}c|9hCKnMBHD=GU&m+1|3ReOc=x`D-I( z3qy4a!&%=)vwn{h?oJd_W(eD(75kI5yVRo$3x5T(o=%y|_?zieQP%4I^5x%o1p;Ne zjnP${cZfwx6;{J+jbG*&NuP|FXSEy|6Gs z*=(k4f1>PC^PL`QeQs}ih;l%k6Hy&ANukVrU!OnTAn)%|DYHO1_}^L2;s0%C7pS-i z`!8;q<%j3w|BQ!J5|@cB%!>7_f5t=Uckv~yTC(;)6E27ak`kqbH32c0DtY}0Zkis- zvxYyT_T^L~Xo(r6RNP?npCilXa|g2@1))E+UR3#PoX36bgXNSc8STRzNDXdcRTQ5T zJxH*;fF-x&lo+|a46%*;DZ{z_`N{t3)y&827E_*(&L z5ctHG7}HZd$7@B5$!4+)|~WGv|-qfhc*f14}(EPsAYupC%k}-ANmo3 z9|d5o5l9Xnzl5{){wMC#;1pqemYleI^(U)&0FD%#(PR69hdBIA{uJMP0?^7hB*Xp- zI5O-k^5ngcHDPX(%SQGIQrugC8X)O5^jAF)9@QEJ4k8IW`C{9*Bo`lH zK4&b18>&P*8)z)eMA8I(5=6=e*xrYNSslS)i6=36N(5tlBc zMB8zD(w>f8Kl5X z+cwou21%e=?1#a|-4)KVqT1CWt59YHQEs!I$O~8lFeG}mfp=x1xaD_|T(4xST5l1} zRy(~|6NLNZCcrBhs$PmbklXGOrZ+B;Vn8qyfcyIC9qaW2J=I$|(+eEBoA<7VO7%K0 zh&M@bq3rskxi0ti-+VB+JEVTZP+rgbv_Wcs?|gVUM)mIc_t9qVM_4c<{6g`U?X-K} z0WI5m$T9UzfvU;oUYk&m>r!FWF^HLA3k|sSSYaoieKv=)ffI$qX^*4dM2N>N^dUOv zOi|B5?DN+$bMCj8fO&Tr$r^ObW<-Q4tJC{P>ap75@@V6-~*a_xghqsv6(iRY?2V|;cD;7|(F_5Y8&GyjJ2@&Ep; z%#3a9WNBncQVB_=nz3h#k|h!nl4RePnK8C3AtX!oof`XIW8Y<`?7L*o)`I)ed-;6M z_uT)$_r8A|Kg~HD=XzYv=j-uYa_=|l*q?jtzF6X)+@vECbno%=w zEon6E#;Sv%H3)Qqq99PDa3-mc^SqdrqJ$J<=#vD~b5y6Ou6Emn`A6~dysQ8Ttf`n) zR*(cmds}Y2WenGnG@*eBkmzVl!L#SSwrd2YVq}x&&%OSUwEyNQGYLbwK;TqU&EJai+HT~0 zqlCUAKmk281W7mixFt5BitgQ>zmRiA?S@Vya}vS;7j>mwGwf9a&0(tr5;l@2`x}hL zW8|?}Z5mIFUPUKK2XZX6sli;Cz&|>(AkMZ3g9r5tKKrM!X=l2eAP$jHHA3g<>uDYn z?cY!ZTFMWy``^t*F?miw6(y>)!kD(xUXd1A=}cn`m_SJ)U0G;WTdLQxC?r;?(ZLFx6#>PIhAmp}$`ZmSClOGUn*A#J^r9ek>L5-4C{vG8-T zk-YCfBNY1GeE)*4ch5}ggu%d&X;Qw~NlatAA{N3Zedx=F{vN2P$A{9HvNnc49V!+t z&EbyD6uMeZ!yu3x5k8-5R=fPAUBeh6DAstYQ5<|^ksjn&5A*2ySjN&1arwzg7V@>ro9U`VBhbc^z*|)gF$uqFC zu5~Pdg&}+i1jg{G4gp~tQf-PT{<@OtQU&3V&KhmTJ%>kf+7Ow^c@GYq*=UZQ*()M( z#__ILNQC-E@aYXBl=4)aWG41?of?rjgcB|-CP8aOHs>0{v_AL$&b-h$y(;9^2BNp+ z3rU5Xl_;;&7ut?t9e;emSHDvT@0i{p^YzlhFI|cp;t^L09;`WEZd5sF$PTR!=8XMP zy875QMOS^6vEqIwIp$J9Z^8oC*cSvx%y<8Ym8XKgUbkK3X*9?ozF-rO{@nG99P(t$ zS~uXzmvAYGxaXRyQjfU0PfV1t?tU|Q9^i_8$3erdhxyDdp*Q%=yu6t6U`?-O6fPDk znNi^N%#+z|^w+_5Bz4`34?WYcESoit!@W3mF65gIn!lD#M4N1!^zgy-+TqsF<7eA}pGJqCd0**YlySJWXEJ6i zf}=`MwU;lx_U-=3;s!zWX9kn^*X?4iB$fvI-SAXFoRO{=EcbM^XgL^v=`G!;Prr+~ z%(tMhu)!;oB663OZ}9p1!qA%x?(gC`;jeTYzB+8!TerCN|H!E4wYSOR$v1{|+U(VH z(ycNjV7Jqb-06shoBiuQk#3fxO4n)vjLFvMhux$*^29m!YJQ$|*$3%h@0b`D#blU< zE%h=^`a?36kS62=-qqOO{)dvwSta)j3z$YSVqW1|vlvpf$8(SR`TU|&wD}WTf9m(i z#1jORBS1wxzF}0vB7YBlJ*YeucG;Gw33w;2RIrmQsO|sJWYAs2s<^`aL z1AGX$YJcU*0HtG|IX(eWs|?dB3)QR&RjLWss0zPZ9cfS#{rF@2lMioi)&uuH0Mh)C z!?pjB!_`OYG`@Mz^ydVqE&iBffM}*M(Wvb|81rB#8|a?__5-u7G@FhL`^Gdt5$DjB z;o6bq+@1?0GFJVWrh~_dIG2HU4xisYnIL-t>VuI&@8OC^Ge9U)d>qOwmpxsq0MrL| z3l(m&#{vY;ueHxNs{W8nqsK0A@NYU2k1=|MdJFu;XR=2+WbTDaoLp2XRvfW3A=bP#&<=`R&r$kBN8 z(O}|_K0pYUcr=ze*OWTnp1<%ZZK*r&YgY+y;j`G6yxNny-d{352sF})milT|##6R> zayACijwbScj~4HY75)H@eC7fBLBi2m%F$fT(HuZ8dB=XZ+3H_2rAO;Ee{O#MFbojE z93T7u08>9da7-`XM!Nt%+;Jmq4rrux?#?&-oE_O*0L*aXf4F7*XuauZ?=Nl{+uj^H z+MD=?TY&s!Wp`)(aQEB64iLTo_dmP;+i>OoQa$_gBLHLm6~NKtUY(oug#yp$$_c^| z6e5Fcy}(}?4N|}0D+Yrj2D04E6h#-}sV-*xmC;}@G)%&pZN-c75CocK!z4GeHw|Wo zyb=UpOcoL?xo z3cDny_(NN;Kr)!!P(a(C{e&pyfh|{~P`_yfToZ)6-Z>zLM8cNzz?%d~Igj!)n*Ll$ zg<8!}Q2I!+Qn{I?kvUjKv-!lMT9anT#jrB)L!KRS;(ZVc1@fS|$RSvhmwRa`ZUlp zZf-JgVTv+;l<6h}PKN%@i9-jlSZOl2=Vss&k#4;pFy4Ooi7qIlCo`QY8Z!dnKDYce zH_1JRfIdt=wT*v(bc{uF#TT_NS?BZlf~)v#sHf%QuE*&A5^&;CL4!JS>KJpkpch zwaw43AB;7AbjADfR$;SR&U-AsoV4B_57yteCVi6Go_l$__JW(q`@^4A2ImidZL~1dUSL{j zx&G_h$z-ji>X8|rBM|B2e(dQRKOd}n?_R_BNWZ>(_+y=b_B8%ouX~+w>ZQZJMEtx} zT^;?HiOkXXPB=q)!(O0 zhbqb#Lx)=Nu}xiU$$|VFAB7cp-EA>e!ZW*M%a50SUW9PFHgMrKgQQQ`hnYCeFz1~{ zpE7z0vf54);0hPNEZfDF)M~~@heXNyZw67gl&O~bT7Ie9-}O!a?(2-(!UkuU6PHLr zm)maLzFLS87@IhAo0DLq2!fbSeG!$e3)1V3j46dZ61CPsbDG<|uGxNk;WVXG#hMt~ z6g4k;#jW*%cqE1izi@(&toS7E75vgSj?*G0T~C?%V_W9TPn+0`K)O&RXRz-Q1lmKQT<~hUd{2>*#1sqSP@F!ejy=T$JGUgH zxUAvYED?qT*9!<*X(9BqqggA26(vNd!kSf>J@Ac6aw>fh&NGQ$WHLD!?NRi(m8iH6%sXr963p&?RM<3{Q){v8?ukyxF)=1;wStT1jNczv6_wfh$ zaA}GGb2y9UVn4dP~6a5<5@FVC~{k(T4S)lqSAxNoILgM42Lhbc@aWE zlMkh*Eany(e1AaXb!E5Ha~$2zpf}v9aPg)Ka9G~M!=LQ%GYC7B5f*j@c8bpr)5wxO zMLG?zmaZn5EhKnsAUCE~*U4H)=-Ml>kUI@OOF;;kmGL8@bmLjQIvP_=DAyE-T1r@! z-d+NKBVrn0*Bio?Z48I|a8|bQIFPvFgVMH7Ay{K`%&(8?e~QC&J4h7;-U~Mq zT&$$hT>BnX;5pCsF}6oM(=PT|jZxm(0F%x|KiclAPgHf?%WGEG1Jubxb(f$09&AqZ z`70#Tn&&t&ym&1rGz{QeW zhsQ*CGVEpBDFpl6Z7Hx>ZX%sh6mM=XU6SBM~rVHd&F!0K5$7S75?$;T(cRg=P zO^vR)eK)TwaZ|3YkDMa1bn1_OF~TLjpIrO;b{I3_wpTn{I0pM7;j^M2E5`#|Q5gv1 z;D>9@bAk-^NdY&P+LFAg-=k-@FUzvqNuZR%%@l^7=~COD)%2MRaM{zf^;B}~Tzm|O z^2*DQiIst8a=%?%}Q}X*75<bBbeAxZIi_fVgr%Xk- z{uE+x{yM}2aSQ8`xJ%?!wu!oIf29ZZW)F4;1Al=>U9DiuLnGwKkV{zTB{4S|ODIN} zq|oD{p$QKI;nfjLMd64iwlH}z-g3l30S{9agOl(mVLjo0QK#}B)G-GI{Ox)J?raJi zg!0{hF4|ugHs_1nfvo0Qq0i+!{8b>UIVK!mz=I70HP?@iY(j9y6|`f*Q78#g`6Izr zsS4F954}?nCigKyy*5(2{Ez1V(7k<#HLiJW_95fJUG@KWZs`Bux?C#+@AKdEzPkp z-LWmhtvTDiE7!9<&!i{abU4@Y5AaxxzIW;`@a!qDA9?RG2;?@UwiCsV768w|pCZ~? z>G9dkbmejXY`gaF{@EX~!7=CbzW47WhjbT*e<~*o6bJW~kcKNl1}j27SBLkNz3M-X zYhpgvM2%AtzBHtdHsp>sq)oQwjCF+0*WuS2qGuZ4%r@iqT7hIH==Z0noi53Ca2spKoG{)BjivN9Tqlm@u-icB! zG6O-;43@2Pg&7^M;T@V{8$E#GKoY7(K@?}*CdSJo)BuT%{0ny2f#LFI2oWkAs&dX9 zPvFedW3YGAbjTf!2Z6ZtdIX>9T$1>hD~Os}B1xG0*tm{37xY%$WgrFqvPY=YIDh_f z2_(S!FpLkZ`YcactQX4b&)waMH+$3)3mqs>HYvhk-pJ)05IP*rV{ftr#<;pU;h{J6 zc+Dm1u}_CxK0?GcW|<%2N}td2dfStPi&MQvq>!-}&8G=2M;oMj{V$TF9o!BVM&L`|fuVi^Yy3u3$ z7D9KC;Bom(c=!nhS`lFg6pf`M?0i+KOA28cXi5tUf)C?p^>UXp6Re~N?1w2Qw&6L} zF^&`*Q9Cy`BcU&gl3MtpJu8ITQCAa2vm#;%jj?GL@q%GA<;aN8@Xv56KINrkKdY*O zWF{0SIevh58pH&6&%nK$z03C+Dzj6c_OB|cSu$vz z7JyVSS6oD&_~K7{q1D$pkumj75Ef0xqE+&(_V`HX_a8dkXR$i9RA@%1hpeh9?V7EMz_D1 zE~gRkmFIE&Jsu|K6SXMUvS{3rM=5_Ic0f#*g*AZO{f1Bj&dBd-1*e!G$(F zcw_h@Wa~W`VF})|sl!rLk*KL8F_53b_?~EELaC)O)XpwAGztf14#6C8Yf`8r-@BK$ zCR6FU($Mpov9O|3!0Jo*6H-`2cQyQ+Rbd0m&?(bRO znIO&ICa5e9d3t-YZ)G4B7Lna3=-vxvn0o!yl#xbQaWe?}+XT%M8_X^|g@2%Sitd@7 z+`BhnY~)sc&aPHD$xOQ!dMqT^2jLbfTKga&837pZ#4Ks}j?FE^jPrC*vvBT3KbRYy z`2S^t%Vw1!BIa};KV2mU0fCQ*sDL$$o7TP1*=LH5 z^gMOe;75BQk9}Amw}3D|UR6;R55J{paMt~E$HP={Hg{2e(bT{u!iad-C2MmDKCFg) zQS#G#3QS0^uG{J@Q!II8R*bHXApOE2Vg676a1G$);!0%`m(w$^O(H)%i|NJqPGRZT z-9Ax^eFy)D!pjTVLd2tJ*fE60ZdQ%6Z;FgJmy46!O!b*W6RVqt2RP(Ap*lFZD`M;96Fi5@Yp zU;@}PntmeM?0S+qd9m{R0x1I-;!c^X`8k&)#HkV|B4J1j4qmJRNmjw<$qM37hb`I4 zlBSH22y6XEB6qWj9OA4JMPzSGY1%grg7uv64+Pr>ne>KWA{97h86b}llVuFnljm=~ zIua}8lz7{(N%3bm7$JhdQOhgmx zyc$eo-RGbd)2pL>+XJIN4P$hs5F<-LGw4}9hTHVd2?|_#w=`2rnw{)aHPExjNe;MP z={kT6CLFPDR1y^MA-!X=FAw)LLMzaLB@??S0#vT_T4i4y{hE^zkZn(aTSvdLnusl` zKmBSR8~V)i5p%wA3)^{#xZVU`mGU2m+pfT&4jO(&Ed`}h;qW$o#Y{%NvhgncGvoI) zruDp4ryophJ(%sViT*`*94Wydx=Md$M_6Xw}+@8 zCUk$3Szj^*R{Yi`t?+yVO@4ecZ>>Ccg9hq&2b#h^a9vkUv}1 z_FV9{NAEVP^t;1*6foyOZB=%~t`J(D z@b$+R^JaOzkF;#MIM4xj~Sz+l+vsZ`a++P#(e^nUl-GD!BT zg2l%HBMUn3uNmtST>1kEFt3vp<#y-xqw+lG&$Vn%kJ39eOH?jMtvl2>*aUe=pr{mv z?dmRw?x(-39((%SHA|JjMd;}?eMY8qw?apty&!nklviT)*#%#__ix7he2Uk`jr_7z z54K-sxi&HXoDRGz5JG!i`No^NS|S(1tgK%zS*yLH{MGgs6 z>*Tkn3yEL-hrKna?Ich8+>Svs4PPQ)VG?-9TZ?W->|RRbCrwligBD)!{f91OYR@UJ z0A|D$JoJs9ZFv?nX2>3_M;JKmu(9asN}+x^C4-5D3dDNP`xBol5&~O1HnQNZWa{wn z8|j)bFeT=RMHp5`Kd3#ny*;XpfBG@$W@E^IgacjCN?mVM0L68E%$=qLgNC?c z+dzLD;CwT#fBm>V5zxLp{I|L`4pi5UwQrBR)2+KQ92(Q?Iy1f6vTR$j0o}DzSDt5k zuGyC?pt|;KFb|NwJsB-<8pwAaD6kvJGnph?jguY6N?b>Z0p}agVf#yZZS^Poah|XI zqrR^C*L!`u4AfcR*H!eQyEwADJiM#Ix39?WOIc`tMbKzvWdCvOlQ2{p{<$V;nK_1PG9NCTNx~w>#vy|Ab%aKS?VwQHd?zfnzGrSv)Pk(G*-Ad z^hb9+53B)Y9Ia&^chwfFjuuLfmj9Xp0z}tkM_Yf3uIC3EX1^TY*{n|hMYYa9MYX!4 zg|44KOYPfnMQv+wdpW@mZ&{cOhs3z z%vqMvSaz0C7;VD#Y)Jnq%RUL%f|yLQ_vkDNb|m?I46HNdmIbD1=!5uu&f)RC+07UW zJuIg3dq0GeV!Vc^%UkTnv6^u_(`2E61RbRM-#3P;4-uu%`0Ld!lhN=S96WSc4Qt~c zUeU~hP!cDYTV8hP&^un$qqj#eY@x4Tb(-g%IZS5Vna1v|4SiJY-Vk~!!b#Ju#DK<^ zyMKaTHPl$W&q`L0Z6S$u304I~MD;`YG)HCfC zl#&};%?d?A|pwg$?4V#bsgRH9@`07fH< z7xExbr=LOcx6b&(AA9!%CqCod9_;yM90@#MDRB}LC#1x z->%dPLX-K7bSy+Dj|@0zcO%dYl$?whu2c6dTv&p%_)RXS`ePYRMnt9%9qNP5L{`IX z>j?R)5U>JM5zB%Kigu=#_V8JDPTrxs`;TP$2c)av2p?}jIi*yVD#3h8{r&WWYC17_ z=d$BUT;dtAF`T66hDahkqGR4iiQZ1R2);wfH+a^C?-4~)e&oe09#&0*R0Qe^a1$z- zlzUV`DWJ@=R37ItFCn(paF{uiHpHA828I@V$R!iG27a#N0u;AlK)w0-lXWNlV<*bgC)944o6Gxn*5aby?9Ru#f?CvFfw+{rOby@S@TlZ_ge9_Nq) zxyhd8IS+btaNvdgY+(?#(ZpjNhNcSgB6oDY9$q0Y!{Oi0W#_vcLoH~F>dgA@oe_(5nH{*o_VBwe0WWJ8#ux^$RI0vyxX_vM zk9gQT^PC_39ogtA?3%?oK7z6Fw&p3iY|u+tEPCaNu@A!0=ol)f#n!=xXIp8p;Wu80 zO(KYyO~GXL>lm9iNN`3!)M+AN zki(2{criT%tTI){AueVi&5aNipvJ?tjcuvxK(tCrcq9j-KU#Pi8XhZ8NUx`npx|j3 zW*}5wHt@Owrbxai;(4YywqLgb8Qw|Pi;ANmuAPryQ;Uib97KqsqcIF4ri@U=ybRRV zKZ%p2L5?xL^pj5)pvfUA_?x{XMG2e|M1$e-Q?HUFaTw7bjBMOY5fPoU5H&KM$v2q=A@v{XGfxrJBt1Vf9ctQBc&z_G8J0TVOhD|Jx^rBZlW~ z>pnRG$NrZXNyykAw~VUpB+LxpWm&5#^;(HZ2iuF6o)RINeatC{2ia6=#t`(-izl0jlp~=}l1wk+cp_i$rvr~jY^rB{S8+z;*8MxL-m>uB5CdyTSPjGq-OEwo@y+FB3)U$)m3yZvM}z<8 zZEM~+G?q0Bww$At9s|lZR;WWZi?zEnr81jeKdb#bcc?V=JK077!BAnPo$h_QPr z<|WEGUB{Usf}hBJr0QTU?-0Ljt%Yvw3*8JwsiHGj0%M$Uo`x-v`8E77U;onCdxqK3 zxl6EHOfq8k`(k!Wgq7=1{!gLTwg=DW+bRf&Z{8m!|-WA-TlH?TA9bTN$rylS&2ZoaO+({&O1G?ml`(TB_4SUvO!riFq>F>NaT^^D1Y zi(NSdrCTA(R+8*@&Xz#qKGMMZ6T5U)HMQ>5NRdZ1_bAerGmE477F`+55K{@I`YF8_ zE!FP@rn6V59o`kQq+{VChAAk0;Liqp&QfG=nn5py!|7CCz`rQBUNanH!&S~1tB^ON|)s^p+m{y1;L+X_kpOqD5UdXB$_l6BqgqTxT3yi4{hHvPRNTAW{zk!6(Y zxnk5xny}L@HWROHriN|NdfrSNuB`ji7o3q~G_Ew9TG{0xhh!?VZw`&z) zi;@YD%f=$^^uW}OebRQihfudYg+T#5L19Y|Z2O>Wl(*fHaP?p#+_VS6Z#nMt=rU4cZgb``+9c zN_a$xdGyDJeZM>7Umv#aL@uDjwx~}5@CfL`S+%7-@6HE&Z0^TvKpE~$xekCByCeTm zPsY>1T!4)ndI~)I-rJ2A__UCXC&^ADWcRTWw?97YzujyrrO)R9TS1M(bgAuXx!q!g z=j^ek4Un_}kaTRq{&l>d>T%RT>?$C26$Nz{`wbR_43vcRSCYO|h8(Y^R=pYi5b?P- ze&hpjswQX_fTV_)v4*#w8#9KQ09!%ccxTDvr;z#jkmaV(Z*4L2_3<+ez;G%s2o$^r zY^NRzup_^>hwk9(( zhl9KTeJ9rmq z;ra}%hX^cwa?})RAfz+l=FO!?rr>QqHl_vZHC1;Z5gl}*KJ?eCo)y8R53^5sEnIbm zE>fFidW~M2BTF!j*7X=x?=CD?R<|UY^xnVs5quhO{69Hu=rOrEe1|I365fe`oB$;_ zQ!8_DTR||{#)fdbt)WKU7-lMv>8*>26_>jX7NG)WB=|9gArfrQeAupOb-NE_zn{t3+9pEV#;2YLmVBNz~w5S5Ws~3P4R%`Ni1pz z6voYrbo0&?(?|Zz5drsI#g>Kb*tmBi7(E3kSV+E+iizLh4J!SVhfgZB-f+reu!dl1 z&jA%!0aXV+3EnD_28Py=28Zjr|;K5v-PquIj+5320 zq376o6`Ef^2XfgZ{RCuy(aay3&$eOT$-r)_*o$P05I01~tMtG$U3ltFX!D!-MiVur<{crL`WS%Jv$OWFdBS~6+Ecf3(adL=MU;=siEx6 zhD)@JeWIZ}+sD}i-qN9luG0Nje3f^?8tV7Z2F-gDXTE!pqP+3rTXBaDt=!l7DY?bJ-HXwGtb$ zI|zNWen3k)`QYb@1f_O+Jn}i3F>zG}{A+)a!S(kRvt#2!K3j+? zZyz$&aatP^4tN1k9KvE5qUt$-hYSlw| zF*XHrkwfTQXb$jQLGZ)6xg!b_zRK2^gDOW3WqwQDV1fyLLb>jeNe@P??=~nb6~w3v z>h!HS1;2NgFL-G$hw${L1iW?N@mXA?#ao5;wb+-*>AL?#w4=0~{oybto|#&!~u(-}3B6C|ll zNdX__C&~uPckpYDS)#GB;tl2@nL;cVfE^a);3`Pknj>7)m_TDl@mC=ga5UL2-yQBF zu_j}(K#7*}Ku(Zm<&-CGOE@W|RbmSC(oCF0j0}5;sfyd#*TzK*AESq_$k&@SE-74C zLk-o0T{^3*iIX2h>9HE`6r9K8(^^qJOMz02Yp38B*gSM=uIijCz!Nmi=0Q5GoQp5@ z91`d=r{K>wP1#fLi9XpB(J3X@!F3Aqb)JNO9=6v3Ze-3gfWSfR!p`hHO{!1xLSx>*Sz%r~c zf+TDnfo2IfcB(0y(H@)8*85T08@(B#{`3KIG@V|2q|o>w&FIKa_STc{>JM4-HRt%B z;%H0|z8nY~LJl+29W+IHdu1B%>$$a`(;<5la?eutSA1|+P@xx7g^K^$@0>pn3se|0 zKj#UiHNp6DP_P!VQ&&DEERmAZ)KF|dX^s@L?#VeiQX}#hd6i=8f4Osdi;9zS4`UxO z$xWr!;YRy-X*-b>w{pXSIH3KmC>VKe{KuX0LVd75OKXD3XW1_e;J1?TE(d-W8uj}h zBg(QEBM_$FDw$J-{G!w!Jf^x_@j35&!E1**L4pJLk3+l9(~A?Isyv+T8gG{5#E*ZK z3$GqaVJl4tDXzhB5pc-+HjpSbB#>BtgIO*E>kJLZ|s< zm-ug{`#-W6!`5!(d9<%MZx+2iKfdfv!(s3G>%$NAJryYTI)$yguB{9CD)_O9&wdrJ6FE$Z{n%mFKNHwLx7JKlWg7f?Xe+b+W6Zmy=7svR z`K@n6_M|Lbff{4KN$BL}{g>b0`*?e%7#RKVxzKbba?Nya;e&JY6v9Bv#VNq+{^C

bDsTYrf8eT6g<79+i4|_yJbFAAg{}kw68bd4=C{GQoe6=d})M#eG(Ny4aCsQ<{z{Qtt|B0ZIVd$Ja^};de*v%H%%~yKP|5^R{2Dl7ry}tct^~dX&bvk{H zdVISI{CeIKfQnpy34Wv)khA$s)BsxQh`#dJk@8plRe+rO)o4xpNG)lmI&rAs_2;^T z(T0>^O8RJH=6GuXu!1_?O8|JEA+?Gs_U(SPq)R2{L|9rwNa z&9SBJZ(ViN(Xp;N9?(@!H)qa&%AM~#)>Y4SW_d|!CpU|jgZ<>5GUwbeI7_0yI*?t1YK~?|w+3FVt zn`b|F&W|;(dbGaR_7>WIFSH!3wEg}H?4<$$Qs2=!a3uun z1ARW)0bmH|(9Q0wEgY`Tf8PXPXzt+q+R^_qhc$pful~g#h%byJ2Zte!F~|-JMc>3A zRsV?EFpOoWViN)ZN=>V2SlI`HL~(cKqiz*vsuPPyVtNz@5ReH8%F2V}hq{1F2toq| z*Ac;*UQ~%F7BJ}|CDIC>^MVRSrIn;ehb>)chaxSrzqAh}i}KQOvjnOPXK5F^3JPVL zl&lV!$O^G=$dsQSuL*=FA6)Fb&?m;ni{`a|2f+GT*F>&CLcFha? zikMSpEnWu7hV!bqmsk!!LD?GIsa@Yl_;bR-njS@#kP4^uX4NvB|0I>)AQr2)Jy%z* zb(UJi`AP@+UCLo~D&tRgw|d$zT`JJjyS*Yfu%B}NG;H-7Y>tWYZbHmsZ(Yj?MD19^ z=1)D~SN6~eWts&7qbx6DUBGcp1okk#A{>~Gn=)l)PZu-c+e&A9LVFbsGWNsWBP$xb zAc?WaFAOT{ksMhmsaBl%8PQ_=ozhXEm&{#8!h(XxT6g%wFmvJZGZq|?K|E;LJ8Uvv z1){W01@LP-XuTN$v2o8U#7N$FlN_2#r)&CvnNcha1kILDiA7rLygJK6TbdCkFI!=3 z^2{nmQTCy$9U;u6s1^5+uXY0;hga0+fnML&yvxuJ?^*IV)x#nWi9&r%&+s)NQ=L+7 z>TQM}f;>ec^6&C(K$RO>rDq|sY#Rdcx$SjB+|Tr|-yX9|E@&~lvdURV!YrI_DzGw-Yh*~}uI^x#@afCduwKk&bY+i8C7Kr{r=xknnJKa8o%p9PX7$9gD(bdP=Yg`1T)v=qNtT^m&s6Rt=0rkG^o z1&MG;r3oHT4pvcl1K8*#t>OpnN}z4Q#)gSK3_qxx@MyR?XnTZS=3Gh7s>p`eA%uM( z-x+5lK<0+P>Q3#AXnvxT>{*R`=3M8)Pf{Gk@`$~{+Nj|xMvTw$mb9GE=Kg_uE}#Ad zY(hH#888l3zdZATrU1{CcAC^|{|PBcfH?>75JrLnYNdOaLkz2Nw)w&!{Y73(xELE2 za~)#tTyGc04XhahbFjrXU%L;vwV>KWP{rY)gs2dBW_V$s~V@=^{if3eTKqNfcn3164nnVJWXr5V)^}$^6w;S<>1hekb|GLp4Q?GnW~~ z<01l2B;%-chQoFqwjmEuSVe0GH#W9s}<%yfJb`8 z*7pmh!TrY4km8(e(l+9+9`B#xaBisM;II$${cXl~ud=ROVo}7!Sl@K zPix^Jte#pX<#CNdmy%U=wzhyJRXHYA&__TF2(M}s6whkwUjiZ6+SCreSc zU5k|hq7ngprJcsdTC)nUpI6RNx!kVB);g6T7K>w23V#jF4#r&6tCRL{gS_31O2c~P z(3;tj0GkKB+bs$X9no*U+n1vmx~!dL1(i}Z^~WTmKxhz=i5tctHu6<2>FT}LD$)5; z6$H99d=N9L?iniv3`3E^1zJJ*q7~mBw7u}&7zkQb7>!o)=E})t3qYff)(dbVl7H4_|!o)X=wZI;)bWfKFx9U;t8%7?snT+ensA}B6AmL1ExdBI=i;acYYBB1<+_A+|})oQe5L9gP$R=a``hM~7=O_?-kxb~ya31&+oL4NE$pUBWsL znf-+n&ZwkVDpG&$l~XK^SoNco(&Q+OiMg0~$?K7fulpzO4GBJ#bC$Q!_XmS)F1_h6 zoPn{wsop)&%;K2`l}=-CKT#&Zy7BwT^_M?C;fF}cmm{on%Hw*gjd#k#GUwSM-< zeX?GNBy_lnlmm)}OE;wR4;Rl)&WLkg4Gt&Pyb+rf9{$y=y<1xTQ9aP)=+{7i;%;S& zsJ#-`Ec?bi+v+wyq!bI^%yOb@ZA$nfQOmj+3Vj*5;hd!gt>Iw4QAwT>?Nh(B{nqzx za4x;`n>$-yPnMFPRwA~TE_BFWt zV6|blyyCW(bv4)TDZ|^+J+mJ6zUnxX^yp+U$0!W&iQKjtpImPhKsNtEKUn zxSn(Q9a5vUw&%*HpOxjqMxL%v>nGnTn$(58(VUNVl@2o_dbfASgKnE9 zolNs;1(BkAjUK;|J2@N3Zo?JeFu&lMN9|_5OLJPD#$6L$KKx9p<+-hr`@KDH3cJr} zx%=Z?8n59SrD%k~lp7l1&ZK9xy66F+_B@&89@7jf$T3vvFfy`9egJL&mLNBuYAlpM!Am*3-oot=LT z2T~Qj|GL@$1@*0BKZVl2J8#GLKgW855Dfrssw4CP`Sh`_?a#vL$3#Fu{f~b-TK$iI z`fmMe-G(^BhGViZXnlKo;P~bT=)3__r%xN+>UJmpb@QVO?CgvIJ39r|O{tGtQ!QJQ z?Hbcu8?zkRGF@9U9J&iUI`d6>QY?CM0K~EU^3J{|%e}Y2XrbuQ+#gXJaPYHsJhJ07 zQ~KA=&hg03e+j3Fo%z09g)h2_{rZ6c(^CJz%Fw|ozwwH&vD)L38$dIIwc!&V5nI-YDxd5jeXDx`IHzZu-pn+`FLWd>cagrg z1a7tX?X`t&9gEsRj=I8s024fao2TQy_az(+{iU5wn`tVZ?aBbMoRxm^Tz~ZfkmU@N ze;diz9?abxNk1C>urpEg>p!zQZ;v+KAI$-(>3m>z=Wv01v{rev{I6=d{Ala1@g2Z3 z-844}Bsz7gqknPCAKSrv)80bI9#DZ>={i~+`qP5z+xa@Svod(JK5?{OceLGkv<*0? zfxDpIqYXgRb__JTtMfa6rEO>Re;dmDkDH%=KLUv3`!C{@-4~E=AO^rrp<;!xU?PnB zUHGlP5Qn+`i~aO81kfw1q_;+5!4Sak%gK6NdxJ3|2^&)s0+@=5R`ZQGs3VPq#&8?Q zoYkKNbuuAPC^&G^O;&`U3MfZ6MupG17hWo=tSxh5yYa;!wkO39+IsMF$MpYj_onYq z|NsB~%$ON7#xnMuv1DH>kyJCXw-KVKhLp9kW@l!MHHjk1He}z|$krH35+X~oWb9ic zgj9T=>h*em-rwKvFZg_~I2?zIb7fAq`{O*LwQp|-=nRJBUSx0yWbG{=$b(<#Ee4qj zhyzZII7&*B;Z20QSy3q|% zsq@D)P>Xj+JvK$?{ZFbn9bN?g*znm0%x2ff8!e;SrJsK3j(N_AYb!g*D!78X3@7+C zR9rN0(>y%EGw~avjZ0N=`ItaaXV zC*#(@j%OBp^n{NBLMfJ_Vc&n4Q9XmR<3ELH3)J9DjT?lOVI~ zgh3w*ZVdGqS!56-pq~1Hm>F<;A@?GpYIcZ0z#&6d+s4j>n7#MRubSwtMvTpaFcInq zx>?0S%l(Ww+1WLEZiBpSoa zDLR3Hq8BS4)t?yw=64a2)niCvio_9we}jk&v+F3i5;okt6vT2s<~g6G^>bOsNuT(L zv{}8PygIP=Ct?M}ws%G6yL*wWobWgFw+>VlzhX9H2dIPq=`M2%7IWP!d&RzSc7s9c zjDIHNG+$Q*_9UqHo13LT);;KNsq-b3Y>QgyXs*3;#=YJ=Dh%3n4j}NwpD`{+x@)zQ z3(h^g2nY325ZkWH2TcFFajIw z7N&V6H~0F^*vxu7PM}00UKe66jy0B-q$@Q;*_mUGEU~q+fIrL>uxk~1;4DEM5cW*s zI$gQ+=a9fcU?9#JgRui!GPgpIoMh3a)uHr9Xuf3&z_rY|IkCUKUVm-!Fc$GsOozo> zj*9*Dh6>lj1koRWIGB@S`I!|}ljI2QA9|^*yKIE+`cz(-2(&0d7W`rwvai)a+c}S6 zkUWR@R^?qST(uU)>55}!*Cr14wL$ipvCSyAh327^UX0W)V+hHH#JpAtz2G^8&h2>3 z9W)sMHyjR+)+fmTc~g@w>0ISLXfbvSAO746fwvB^a5qh<(D` z&aC+C?WO03pGXHhI?$7#EJfpB(pZF3LuW^Igb0Hwpf)gY`4QDkEA9oFuT+h;(NzjkSHRI*G%O+ zmry0NRq{5|jA4i&E$=jJuZ%_ZD(1Wo&qn%&7LMuC8id4Z#_B7C+iEymr3huQ?<(jL&Lw-WBM&23bQqbir z%VJEHioDTA-N&Yi>f+!wB8Tm;5kicr3gf4lm+q2yg%V01eRpQrdmbXhHHjpt;U~yh zr$c(1;l8tb&Q@ZASA^n+s*EB+WSMJWcHgw1ep8xNPy^^H#kPLYXtE462tk z6>wwaB1FZ1T)gXLV_f5k`!m7Mhq@AhITC^qaBJ%9l!6NbTln7cb?_1OruEc&q!$?2 z3Hqep>^aG^9L6un9T^Dqyp=oW>&GDWwScey5}vC9Gr-fl3KLi$J)`W`wZz)SzpuJC zC)-F-HQG%ms@!>$aPzWEw|C6T7IM^MF})dx?DHh|1Xmm0_uCzSgMd5F7$(2a%vM+n z+cP6H-&S+WLgR&T=Q}CTS=MJA@I7}R6K8+Ow3+Gl&>2x^Mx^=h4DahTSmviMagYv} zYJ?3E5_FaG8n(Fys#6k|cAGd56rm$2DHdsHY0H_i&?^Y&PE$aynsqO%Kfb}n7h^T0RAc-QJsH_Af*mr})&rOCG(ualzr|bhV66ZQ<(1@<|A* z+{I%Lzg`Qyy*;_Q+g@As`wsG~#!31(JX8_8=j8UNzWeT}8**Q;oBR`k6I|gx+J2s2 zX<``r0(tK{lH26bVs-Lc)ccU=CtBWsJAJWt=tQ+N4w*cWGU{M);{98e-Q~Aath&L! z7H{l*d9dL>A~3%*@jhm&N-$+fVqXiHcn&rm{Co8=+ljT}6+fzT(1sZAkB-sbcTell zn}76#y=n_S{d?%<&+kN0jpl2OTW<2{4Po0tJj11|`ywhq88Rmvcz#u|Y5I-#LoL=z!bURSTk{qh< zZk>c~#G(?7eFwaK*@lCYb3?g@!-R0CN;)zTAC_($Zn7QhGOY2R_dhNF4MLg!2;Zdh z58nSM<{or;{+zu1362&6wm1I+9Rg6~DLrr@{Pk9=)gKgj)ElCJ!#BY8rd#<>ZS=w) z5HhKIsP{U~=ymKR!1GogZwKreCg5KudZ_D#7|>OCt1lb> zF(0V#-1}7G-B%dgQx2%B1NzHd$Nn#M^&jV3qx)>V`)cF8?@fPgZ@^KT_fCuduQovV zM(ivK>n%NSzV%dxeW-ZQS55v@{a^s#q9(wC06hMAHrSLj-t=gqIe7pOAv9->9thuF zjCB_NkybyLp^;ZwVwQoswvNYBZO>=kB+hn(thWOc6!QbvcRHSL^*sIwu+V>btN*aj z^Zk(*Q*Ux+-WAWi2NZC*^B;0n`>Ut>8|Q}VzK#`a4P@_)6#pK3xjy=O6TqRr*&RSy z{q^-XdgcD~%l+ksg9_%go7ly}CzuMg~R{zqC3$loTnHW$AGFM_te{O_-m z0w5IrF9@-ee1p(%L@1;9DGb)F83I2P6#p*>HEDWeV2O-u;ssiGDyS_{nIEk|X=W~n z)$mx7>2*J3l4*E@iSO)X zED2%bcm5jcL&AFma*9Vrv&un-fep@#uzINsfgLd_7j|(Sh)H+jEY*tqSklMfAGej- zV1`5KkQu*nxZ`kBwail$TqEXri)BW#7nMLh7Ps@yoH`njl$5_vswf(u8!1@r)QM2) z@=2|XXRb|u^5FX7FqQPw28@nnrPthG&5Q^Znrg0G|9buF-e<4X!FN*&z8c>GV^8UvV|Y4pSzKrG z?fkOr_8wh_+8F@Gs5H zuETZU(OLrh#r+6e3*~CBwEhXZ-i`h_BP_1%PFg3G;RtgduoGZ@kCwxtsqAvnW+1fz zg^P_+M$Xcc?L*M-blD1~F*2HidnWMZ-uu(~STKzDG`&sSm3JWIqp3KCLHl)l>h?6J zf$P?L8RP|@Nf=C3J&!f-7Fs|`OR4VDlgeLIR$be>y$A`mBoHs7uL@8KwdjKI6-ao3 zE0BCMdW@N-*b}hq)5$0FP3Iy(x1oxYI5>Z_lGci`sY?4dq+4H|7wng@F_SP>^!JyU zZG~o}GyYL8FO$oDG6Y)fPTJuovz`3$XkQU0wj^yA_Vb}%8F1mV>dSz zN?-yX=0va5X#Kn8wwD3gFB)qwaRy6rOQFD-)Q4 zWHf+VF@ip43MDGMCc(b;yU-?afm_|#{RD zLU{sn!=T@aztxTU03~wWLP{+{%s5(!6dj_Hmtn`X-4BVfSe)V=S+w<%BcF^h@o-{( zmt6t%S(llV>H}nfjn2mNVKX8s%&?201AS(wD@UUS8REz~{p3vm@vu$VdETZ>wSJ4Kx6{h1A%}KUK zRDL)O)d-x&S^t*DyJ3cHg07;IaJlZvNi+iHsKeZJt12&$}4IP zG6D*PP-aH4dLLS_SG~1Ng9R`$LBcD0Z4~Ul9H{m&L6Am8og0}|4!#!3=z^CON@`JS zC-J;oLm1?-rbb_~*1w8_f!K!IbWgc*KQ5Y41gs4t40O&~UW!rSp+r=K_8uXFYRxNn zrNwM`9cc5+AM!uW7PJ#0bs1cP&~jJM_}QU6qcU@h*SF_C8S9`7f$-a;z=%L$0)D{6`hD1OvY#E303i9`5T(3%f z?c!vX`P^!a<$#g%0jQ`^xLx{frKJu2wq)aa|;P$dF58V?N_ z6Z$dfOswbBvYYIu%vGeGy|#kG3l2XmYn57OVG0T-@qC8wQ1?)GU2Qxi3v5TIW?N{d z$cq7=A2n@BR$N0qycaMb!uaF$YsEFvqtO}UClH#GvYy|N$+k8``jE}C;rBj;BY|4e zbmH^9SpO6BlZ@@}kGq30cd_FqOxi?sgn@u^{m94mEy>Ihw;0pk(_-&+smN6ivVNm?^tr>}lr$?gk47^kjZTJZj?&$N8+`W@)#64lJ{OPfsyhQ&Y!=7EeT@t$g zzGs)Tn_J81*yiz4-7(?PUv3vo(SF9Sw}QI^CtF@GO-cuOdb`HjUx>vZ2(f{V7Cs5a z9@*g@$HV=qDJY0R&}_I-*%|_obpO|Ukf3@%BqL!XF@VR1m`6s&gAk>f0lGF8`NG~u2|>D7<0F>n=b7uZ zcc(3|pft=wvDBKU2}sI>H|rcEo`U8?ePyhMuVn(>=I` zJCI?Y{{u;v>K>kLd}7-07)X`cHvKVSw>|IvT98} z7>xcXv2V4cIJc$QcBVRXq?>mGgHh&zByKeO`X4d&LE@(+)A8L4yZ3qbItvco0=>y` z@6Pt?%<*c^_jyy~@isrOv+!mw1u$ege=6|mEe-ro8uYFV@MH%LRs{o|g#VIcyZrGa z_)pgXo&>+egKVkib}JD2`K!k!b`^&lpwfXJJ7nNsNQxY;3G1&7`&1j-{}RZS9vHI6 z8YAe93H{V(fGPo~{CuLl_(=VWO+}x(fzS^CNpW9*JGic}?Kglw4)7#I|Ll(c)}8p{ zuP^~n$c-m#0)3xBU^Y5%X8#_`oNUdW=`5b^&RFfPp6)69@}XvS06?Ys@fA)_jd%1Fdrec5LPp5R_uOz$j-^vd#9?@pUx@O0z zt78B&^{h+}uFkgZ&UXI+rmp?f19`&c643W)|5uVdu)pyiLpCrN0faR7Z`0?mA^U$_ z)93G61Q1f>e+a1#2hnDLLgC^9GR9O83C^O4aFdkJI4~qc>2%1kBA_y&+VOmGnL1Id zLXwc!Nrl(zobR$FrJUtw~lVcwvNI{y* z8yevADdtxfsgQRk854E;4ddru_@^zzqqr>nWOLAH&E$-|MV$VC&g!BX=vmg&MX;HY zLu^3-(RNqLw~9ORa~OQ=I3XNA`P}&#zlM1`lFO`c34tmbSxRs{tZ(Os?toqm7Zq45 zN<&7(n#!w~oo$A`R#KrMPO)^_LidWpK@6fA?0VYv7$Q*Aj2p>HPiu!`vg)2d<#%p2XgzgMIhMvy~qVN);T|4sR&#|?)UyW3>%aURkaRT?y7I41v zCs?d|M5-&a2hG))ORHsXE)f_pS~6((`H>XoJxFdqE1A)y=J%1#!k0`?uKR3U5YTP= zk0JV%DOhbfY2RhB1+9SA>xyLKf=)kLD!wX*j5C2C^GrW)(78IS`1oTyug9V($$?k| z;&&zqnYUe1H+WYW50|VElq4^_I);CWbIHQfHX3t9G+@-%XW`%41fh_1Ke#J_kFgO? zL%dHEZCqlhr|NAXZuQoJ(0ousCJBwxd%ycG_8j{z5KC>+|9XZh!~|j7J$VmWUoW~D zQ1klxZ#FS}UTU+D1zIqR>boH>`eV(W)UWCai}1l{e~2Zts}V2_4$a8RK9HXYUqfe3 z+z{7EidAzhJ;xX!pt?%Y=ELhDUUBU?0-+sg$D?cvW}1rtbOdoxr?aLInUr>N z2cCrDKuEe!NZOs{F`m|w!ub(lr^M~x9OusS!d%ObwNhh~j%Eq78|rdv92UFN@Ch7? zjXu=+4UTBF6Jh}nN^+esT?Ya08Uouc&|!r~?UarynfvdOElZLx;j!kQHhgfKxI|?evs|bGe$Ok!OWsD=~9g z^DIM#?>*`^QW^G+6Fx<_h4^l5q=SCjGrRV_=UV`!{}_{IMeJS-gCAu?JzT)C8$}y` zj^;x@%+vF54T+wjz7WlpQQcfTYU{9>CDhn#c=~xrr1*gKA=sj}2e$wDDkbN5?INqr zlAdrESEfdF{)O;51UU?+uPzzJMKbCarsElbyEj%J74t(g;0#?pDb+HJdHyBy0wY2J zM?40mfT@DqesEbNr*|+fD51bEfn=SHg^?c*++;*URK>rU=U=cXx|u-Zn$ZlU@!Us$ zWu{5;dV)fA&6xr=nlj&N^iT#D6(BYX)-DZ8?6y4ymH?RRo3p~vLq3Q+8cF%Y{(hcE#iJ>20YdSN9h9HHG+HTj5 z+$klz>V=_hB%#xcU%<3;C4LInaad`rhTyucGg<7=uJ6!zcQBEblB!VfuS6VKb$WWw zqE+J9w@~jc##5jv&RVn$oA_cmRN*})#Ni$}P6)3YKTOlSUGXG6<-va6Y9OPJ(4MwK zA53v{r(I)9`$;l$1a|lenzH8htw)IZT5^W%s*eZZb@WZ)etxtUD;dMHg0$?o05xlR zR;RTdr6l>PHFQW7)1Km>D>%iGNQX*uBoYn$iy%Q;9byXSZ4b>`cHNXBXToeEF5ZN2 zrsRbxMf68GHGNfo!TeSkf?GHw=-1ZVm!%G@#DFcqvjh{W)d!Tv{^ zm}aVb!kJ&6IB)E}Q(pD7!V0fATKv=>+Y?0FSxJ}2LOXc_?-@^A8!)o>>%a4DGw+@d zpA&C@b~Jtk==*sRnnS1f_rE7h2Tt7F_MYh8^LD%_JpWwZfI%P;YzPkHNmB8vO#SUL za5n90y#2`mDv*Hae}c5K_P-6HI` zYUqM~sL8yaga*+yf|FW?GPU$|F$g)H7=A&FnMy&~>w9pqM|ha&hmm|Zo%91*?E_Y% zwf}=hjsN129VlGl-|(qa!9U^C{~nMui-MG^f&oH0ULJg`l%VzB_jC{e= z1UO0i;MGu=ZUt~s_oo@V^CP!!lz<}zIF zHC7QgQhsy#KqL33Ayn=1wH^Q?-=+GyYp?zo5?T(}=qIowb%pd4k$V7*Ts3(J2%lC* z4cCMZ)kO`yiW;wf+*|WEfBJZ|KIKzW@=$B+XKETy4;pPL{)0p@bXxS+jud)Z%6tc5 z`{0-^V*Q{Y^d}&6;6q4X@B617G}l!$*HgUszGAw&WbQ*Xa6>mcShm#Pv^<`<*_XFH zkg?lO`8`sw|G9Se^S?fX6~L`synmoXDBfRg+@GyF__++MNB@%0KN`7%GrH+v;5kss z@@UuUc=sQT98e5u-J2iSnjPIdaL5hrua54oHt($zpn!_xqsXUTPw?3fDd6C zxSsoePa_B5k^jGVgc>BTb22yq(Zu99-5eIo_>n|m!uQL*@TgU zI_77zHJyPGQqqY4H5XVF$+BQoD39-&B%o!ORn1?PHlI1BVQE=^pEO#CtfHNy53XJ- zK}!zMmurd?t2hv)C;e)r86eW!jDcMV3#1Y_!a&2eu%cgFMb03pn4d=C1nQ=efxKQ$ zkb}O!)bpGI!3z8SAt4(Ysi!Xd)Ygh%truNXn|oUZ4rgTQOx!yXoaUeDu&BG3rWd$d z=btpH9)`_0(%?SloS`4AmALD-{qbZOE&%??y#=N@XfFy)X4kv!I{)LSu>SzqAr%Bc zV@P_?EpY^zHzgKN+M3i)v!Y~6Uc2e_yM_=-wTZ9+OT=qaFdEhr36kW~h#Te>x=Dny zR{1m7YtiP665zuRI5u`)R|75o<$%-p|h*It{3Bx1C!|XyJzAw-P2DpG{aj_||TDO$Cm2 zcp^wOd8%MUp*H76UB}~6rjBSyNnd5D~EROXsfoKrg$_0KNCeFY_S4w`G$#V{48+m1^ zvmX-asFrMOb^LPTvsFibN6480Gb0XJf?!FlrshwD5=+fmg08+$9GcI7+>3pDbMOAO zms{}XVA-R{avJh?+S=FLG&w(cpNAFZz&&2CXDi!pL+g8OZ6c@-LW)`V%I>|W6RVj_ zABMm}B#lA1K>DB{A^R|dYS)GsUW-$F`#GTUb=r`CT;yrqt3!g0k}3o*gO&hCc(IpG z7_*##V)YwytHy<5hbog4J_D|@s^Q{e<9&N_NAl=3Bc{R3OYxko=riF023YK{&x?GJ zm=Nw8X(FECZsi-$vICCO*;50JWKj8B8?ELN&omOB8}w@6_(vxkf0)mOUbak>as5js zl~7|Yg{;+|Ncp_+UGH1b;{Ld*M?F5^Y*D)h%nCYR>nGG0(l*|U&>iJQRF;uclsUfoCGj>RYf&XYPQQngHBPa1?k2zXQkCL>FHYStk)DRV+ zbiinSda#?qDy`GOcNmXlJ_M56Vxz)SiQrS<05n=Czv4RZREU+NFR9+0-hNn6#p&eFvV6Rbb$o_ zfJfh%v4!|qf`}a?Mz1cS_}7Rxa&VPcL_S!^=C&+R5)v2Hl_kY*7;?&QEiU$G2b-S^ z;b%8EPBTw}jq91w`H^oinuu%|O9V(_6T)=DU{=ob?OEMb3}a-~O;!r#ESamyr73gbySnCws64z~ke%Vbtlc}Zl z1xHQOgpw*=#qT2L9Dy5Cf$ALH?~6t#g7FK@@A((Z3-rEUf#qEwG8t!+E@v~D1ln@v znl~<8eq$6Wmo!)uWhu*{RiFsngrII6lE2)o87gNvS>j!+&GVtaM4~Lgl4(I#WX|bw z(UcnM3boL-nh>5K((li3sr3qH;jpZw4a&Qb#C_C1RNloVAFhCH;=x^Mu-&S-+@WoM zqCRx!B@Y@cyq68;EX%p>aJf8Lcg5-2yHP!C75v6bti5`D=%5p^reT)k{)!GWqd#Fu z++B`_KW3bMxy59Sz3U8&6|46%UhU|#NVeq=iCUSpBf3i7jmxl;J~nJUic&%(%{mC# z22r{rWJ><5nt}Sgc=ibQC(Gljkez0~;Sj?2HAcvp4-Zx)5fbss zq3|Qy%^;pN5j}u&zKC&FDA0&s6O>6a7Oz;~ZvMJoV4R7yY{9XIWMOMMAqzH*hgsdo z`VHY68yRdGCD5qRJOcM+s$5x(z98aI>R0W@3aYEJe)GwffMhL{aHwr+4d=K!Dx87liu=jp+fhu&fN(ILa%@_L#+F2LBOFecjYKf&(ygd+G~ru~|CBdT+7ivA5_ovsqVX_9f1X%Qxi3-Uf2YQ^&Xpj9gJ@W) z!sy@|jD`&q)M-S}hB_H*5dsIpW%Cqa6wn#Uy^2;8R3>;s-3RUv3Rk^xB|-`j3zDRq z*x4jcCi($^WVJYL!z2(B9um7@+E9jq8jv>agU=Je2;&GQ6}Ujzx+z0n_<`<(d5dAqf!6{l}y{9)Axt7XWFu6-W5#0%UJ2IobAr}GElHIP&xadZnnQ{wZC!sW5x1t<5vKTrh$|y zVAiG_fYB`A*Dl>(F58K)&Hr+3uTF2S zuWSLHgss)R14vrk-~ayqPpQW{B7ePoq?$GM;3vQxXo` za#ggqjCwaO+jVYYp$PV-;jGS~X)zI@3+Iw3Uh;jV_?DRon-Gd$ zYqnL*szt_`LkqM1cv<>8g2Y0EU+oCaNjeNI{^PCF3j8aaf=xpqj*p0g% zr_UvdWyuIN-o(_tDz!53)rN$(=a~qqeRe1M4#Tlo=!3wD0TnhF^K2hZ#d24&XiTRixGtu3fKP zr=xxqjPjtW4hr7V!7JB-EVaJ3A$r$Ll#FWeHA7gBK&8Fmfv9!}hRC-C7vM@U+!!^z ziM7&q?7(l2TP-WPX6mH7wu|hV;lPJ)XsRaFue*W0n&Z5uR7^PWhOO-S1f=pGo zfytLFgl@`mJxE$e&8B7XQDLlKhfK5+gioMN35~2$&Q}KCnNITuOS(WiSyb&r8P??O zetYz`KC+2ehc05NHFxLJenKk6XUHrgEwLxpJ_k>z)!9jE2jTQ)3imdTU?UVC<3k`$ z_kuP@pHr!>5x@D#a0Wi={y+`rHVYZ8-hl^C=APUgRCYLrNMT^1L6Fza`EfFXAV+V< zO4_Z#j}bD!H!-K#oQe^4d}7)vD!A{uRLows&m@a0s6~wSC}i}^IFl`<<>BTU*;F26 z57!PCqGQ6e6{grvl!k!>d!noSK3~uDHaa2yXonzE@7o8nCKy8l8YfBi z?3JF1N7ZI$lsFGFT;3`J9mBP9<{a9U^0g*cty_V8=V~K^DvrxVa&IPWA1Iy z6`}B6>d3#~QTHLu$t(x{%wE}FHB`2tD$iJ@K<{ClX{sJL4`xEe!Fo{&T;B^U2@sw# zbZDWG4b!#XOWYJAH1u3Tp6RgMg8)2exVH)fGAEx zA$Cr4pkay|WntiQwWf2p{Wh+w5$z;hSZ7YX{IWdh)|Z>G6XpfC#VRS|OZK{`Paz{k zyf4~{cupmU4%J;ol@0FEB&U`bE(fg!!xln?E6PSb+KRoT4$^qS5* zMuzW#Q7z*n*B2+oPHc*m0NY*T^C zBI_Vz-V(^IBl|g@U-N?#wce=7(69cCMd6U;j3(@zxhpVI_|g=P3Jy{cVNMCx`qE4* ziFFjzd_W*>iZw9=m5NANPo7M&WD7KK3)868)^LsKJsxFi-8!tE$sW_;@%%NC{OkGAs236lrCnE><3E$S z%-Vql4|}9hYh@(_OXXsmVm#i@-*>yoBTc?}(Fi}q{mPS&zMpFyVn^z=)$`2!*08AO zF~X7P15-SFoMcj{45la;C<(+lop9ECALHQp!iL59JXM?5Ba2up>(ERz&>r-@?Ulwq z?s%5E%kjKpOCh%SjBxD^W#DXtf{@9a!~O_+Y6-deLF%3JF1DPbB4R8}*ZT9z?@2sX zsi~5mbn?1UKfe08RsK5rz4bwX4;q#8damCP_; zyH{Q|G&A$A?LgJbYGbNMBZDvRcgnJEKCMsTsRHi%?t?cf#jY)K>VSCfK90;g8?Xcp z-lm3}+RSjiw%o9wc_9GH03`&HV0_>UK15{jzSS(&-hXtW&wozciprbC@#8F|af*knt~Zj^yTzLvPT9W!&s%3A zJr~a@ix%(M~zJ!vBm{!nOkPL0kflN--_-vZVSuiud#;{_^NezOR<4V z=6j|7G~nsciKEM#6LVmFfiRv=7N@qAU;n&@4VJjJhFuFyCvFMf=5fB^zv}h%*HFj= zCWX$hq3&_)3HVyCNF4~ZTNB(pA29KeohkOzbhz>Do0xh+@N&(a`t5*{L^LbbZaUFh z%pTLAf@1dZeKsE??1L5sk@k-eB1}O;HK)7Y1d%O#>s295Life&Y6qD!4uoT2ppt593(>3em4_ny1-uc z@d}I%I^FB}Z8PBOHv6SEA6OaaD3;0CoUAv@Zn&d^q=1f=-HJWL9hh{&C{9)3ibjM+ zT$o8bD7XXmBqzef4a{o_LeL`w>99HJ$m%#S?;05AiioWJpVK?qzuVG(W0O?jeZWPh zlpQ!O#4S|9%pIdvbn=ycy5=;$uf zo|?5jw{AW_DC>7=7Y9==4W`;QC*JylP=Aed7Nak&j%NchZo8HYmzE6M_qo8T1n`sR z+Z^AwIo@ybeA_D|G11xiwVeGH_t0yE9zk(O=@PG|hcv=V;peW(@t(4Y-cZ2AJ=+rc_07ZO zmZvk#Y16GqUpk4~9S=4Rj`5zZzf1cD80kLzjk(5cA1qHv`xChbXw_9X)s?gQzF?ud zVz#Sfwzp^z@NxH7uJkvo4CQWp%-;S~{QVQ)xBka_@W1O90GmSpvn|aPc;l>18h>U zxX6N)cHm~}UogpHetOs(dyGb6a&b4gCipnv39sl;htw0zIt-b*hr~lM_wz{%b_{1X zRU-jxs>sRfrCKVDQ#e-Ves@;f3!x@)OB&NLkQmEwmTi*6nYOp>G4o8-%U-3kU1i)U zx)t)9X2-FXSsLRzZrAE{tRz+hcidg5Y}!@j4^5wPaw}f=aw;-&`(}yn_WFw8F%>AZ zoO4fzfQ200coam)GjPk)janQmF641CJFz`nF2<)38}Q=?*|>{B^ZVMUFYM&Wa_i$+ zzgJQ`R}#Tt>5!lNco3A`ZY>@6O2cG?0BiE55!Z3IwO!e*kEU3{&hcgVFbd%(gP0nq z@4_H$+HK(s95Pd$hz~I0wI{_3AKjj{$=nR(eT*IqPB54xG0ATtY$Ifn&@Kn zwnRp;Al0jR>5o-|=eL zTbSIob|g}xue}jS<5nCLPG@h=n~1*U6onHGzvZ6C96|fEkN|JzbtFl7KAlS3Gklnh zePH;QJ1?3D86lo`UaXMF&uUtPyl}UDYvqI+Hy1r?Bb-lgOHy<#j7ED3I50bz=(aJd zfdq?CN2`ooh>|%&*~VPWBh>r7v>|Ls%4LTYFbf%*z;S$_x44GJdg5*Yj#XDQJK$9- zh@l*Zx>w!bu7L%3s!gBm=t8~n>w8ho+2y=Nb%Rs^YvYNy727Z=N^Ok24F!ruZ^jDP#W_Cg~z>|1}-2lL)G&!mCm!fpWNRG+R1ZpYc7;AbaUTe z{*wHlb1{wRp1(%s*EosOfx;pjm#cX9BA5GJ-?%;zG5>h2vPnJBsA%uSmsIE(;rr*z z-v|kU+Fz#MUS-^#V#cs@s8|gs{uuWOURIuvrBV$f!_?Np;INdU_4IQ}O*`=Fz$`{i ztu>7AVEjbUkqEgwRYnhIOf#r6OC6NAm?MvE)i1a1^II-mMxSVRQ!0nX&;ke*UzH+x&Yb$nHM)om40sLd^eQ)WgEy|+BM^?(73MG7~QLbrE9l$*wnn<@AU zJTjgDL~6>YX12Q!0}6;EHj2EKfjn0R*=z7_n3-L+RWe{W1T}~~^lO!%Xi7n_6Bx+A zEOE}jhDmzo?#qzOMKcCoZ>0gtO@}#e^*{flAjJb0yGW)}(;CelNY(bj zls%iD@6OC?e#$?u&9#X+J$y(TMj)I(Omo~=Af0NYypP!RNMD+v>9Ugu59P|p5ug^{ z+eZCLT4pG5#eAME{)hw-GK122`tdd_uq~-&9q*Qv3UES8#+trBo|E9q*@Zn5`CcGa z4K+n+lPOGeFfFOTvhAw*^Q(h-R%#IzZ0I4CS~cdI50|gpVhXF`X)RXyMsNC?%o-Zv1ek zaqg_>NNd?J)jy?1<5HzmxNIhnRy$OI&ud}0zR9Ym)YrX25rG$@ZJ2Y1IR&=JF(<)M zCS$gRUa>`I6Xatrj`6l2d&;AHyQWPvKE1KJ#Sne*3Wx=`4V7*B7J5>ZN%&Fbn~PGR zNp6$<>hT}4!3Ll`LEuT3(1gz$>%EF6hLbaw;z?ZDm<^-sFXqrZ5{5!mO-W^*Q+dGu zK34-Kx2f>{Fv7P3_AE5nuDJk)$ZFIZd z_+>lM%Sn8_x4#m1g8~_Q-J?N!TkLA>IW~sbzX;P?HHV!Wli*IT>0Ie{kEtKy#WIHV z?jM0~X=@QBnGHMHO1`Bj|C-0{@ATd=4Odej%zf_0E}e3J5dYDCmMK`XH-t4BKRn0c zYycW+d;k&~%UVA1TD|H2aCg^TQTBb<=+6m;p@&957#e9%5K(a`X#_<=!T|v(6_74x z=n?^GkOq2-H8!oas{ERGErH;+$jJ45VNRqMO?!XBeBrAM7WdFU*yXxVg%`H6WJpB*u>vl4AS4e zdDv)a2O^kSm~Onk;d>IfkO}`(%SXKBkT#^exWkTz4JmtmzpTo-tNtGHY@OKaAQ*L{ z%;%Pp7ZDm7OMLwsu@`$A;yl48`m(nX@pab(9|SeIe3?4ymI)QsQc~BK(;CH*;Y-9X zPegz?qSb^$n2s6!NiTVFqEyOx$a!`(WDG3h_x+)7$$08~n*sqUZ8*DifIP;2Bp4vk zhRRxl%W{yYU@MtefD8rK4+$i4e8xAUjw}N#(LUw|C~g!)AqaRF0;jJFV#^F1jg>-T zwd~Pk&ipjRVhE#r1>p+dJO=(UBM3J7uUSXW(N|KfF) z9k0$_+6|=t2j`wY!@0pIbT&%Vn`zsd>C~Cy0?rZjzIN%(_v$Y2>Mt;RoBMFG$Zo3W zPY5dT9V_)7Eq}UL>GiJmzeM*o7<`(X)+!y|*LkkhgYn1f!f&wTDTOMT!iQqcSMh|R8mkL@p4J6?Y2dikk0`SSqy0uT4A2P7P#_l7{38_Yow zrwgyXy^T7ZNc}Md`rN6%=X2NkOEyM8oV#@E%x}p1GG4v5?icf!*|8s@Zc{brX3r@JU?<@>%FAbk9 z60I+N*&IIFZ2!FuMxn*S&l9IRJ*P)trvwVzeg=X_Pn)n~9p7sZWp60aWROqU8q zk4-dAmu?_vyvaodr5KZ0h5T$Si`vUg%IK1K7Y8OPHi$^*jQO*|FHT-pwyHA7l;1b6 z&%M=q5Oz<(ZrYcYTRIBej=Wgol4l!}9e6-5=zTHIXhktFi)Qa6(y|$-|N4!Dc|x0I zk!y!Z3~M|h;^}3w8_lQ4)ad-gW1wF=*c8SU@zzvXWgWQhJ@t9Y$me-d&^sLl%_(-n z-nd{kPg0f9HawzjEP!$^&iWPkj7`sskDE@czGW|u8yk#8VpmQOO}ZXND?PaUAoT0d z>nvkqOEEJ=kru@^$C5`|+)qg(%8(%?2GKA|iDPM46vfzOW(OLETIQF4j7J*oy$fLC z{8HMHhw}PKFHcy@@0VrnY~M#PH6ftE!E zsZn`dc}H0;FZ09r$Q`Mi0FQQ04mkC(VP3{1S6j^MnHFuMyLy`hayu6QlSo<@rB7A59Iw|QXspyEuQqWT z3@Ghj;0dtN3r!i%C`Fqn6L+Hp4N`p@-dWtpytHD?BH~Y@wvHS`67yrPz!UF87DHmm zPQRB>5>}(pw-ZaQeH%)lXs)wtGHb?MXGL8(I(}GEIC3nC#hs@3V<==e!-X}>NI%?J z`g*e2G#M!98lIAlNsYSk3j#d-MaB+*2?vVGfV6`9^%Y`7Ff9n_N2BF;X-C56*YPwo z+#w|1Q;p=NWzQP#VTiA*;2>-PPfob6WuR#5WDzALRALbva-9xWn86vG^feAD7BLxr z13xnTx^_BnX_13d8$W1=rrLEN;bDfu7b~%dm1>0xG&qQbv5DEooxAajwq4~v!|2}DvAx_kUV}Q zC-VmtWh)M{=-77DcO;1hXATlHI`|$Y0UUJeWG20q7u-VCt|F-Mc^&fSOl+dWFA<_% zrSfpnUx_mL#gSmTC4b4yMoo8h52qgmRQ>w}zM*?8I^9pn)Z#1|klQGhT+P^5QWK(EphS;EE*g98AheeMnv3owPE156J*r&{vp^U@p&<-o@`4YKGA zFU=zJ-wji@kTqx}etQF>dm;S-hZTuFMRExAY#JND6i4xhgGL7_zkatWVbWf1b8a?{ z0VvG@50R`NvfPu`m7*@-QGwhWxHH2Gjs*)V@|vfFXhcZWwGMs8xDL#R|6r)=8tMc~ zB$H)Z`Ff}-<{@m<=!30%!!pGaciK!6%_zo3!sz3t!lV&jx^nd=14S#>Pz>Tw%lGa!I30=psM)?B*L>Ce+dqJ=Z3 zWsi5@<0lU@+mih_t)QIn#nuFz$nD){q+NN-2U*B6`m_Dj+QKKO zs0c9K=5*@>NyH5qTM5o5(dDXCT0I(lcfgAg&c-?Mw_n@1`mUZXM61f`ebfdKRSsRC zY-Q$N#Cyf@EV`=EN~2j|itgQAbZuhQD|HG7M(v>~D@KGuSK z%x@EJN*37ZkllUiLg90GQH$-7-R-p>6OF@{O6~Au_xU9$X!z~R^grVK7FMV7rmAb= zhCUg&&(BH|byRtT18dYdj5FN_H3^G$Pu5l$>a+!7eum;CnbyY=m!xVNKR!0%40FtSJ6k%H0 zO;=c8yy(V5qBT4Z9VKwJ)^!cM^9eWoWwfc&vrd#hY(#WzmCH2vO7H1sGTcb&CJn2C zMTgp9+~afHt-I2_&6NA5NS}49!6eW3K04%OJzS>mevYS$>}U3%C~Z_Qiz(p%%li6C zV(<^qcG(+ZMIK*c`S4o4ZEhKMEqgMCUCF;aARIUj4n?4ysEP~}Z?Q91@IS_HeQ}S* znZeq2z5(VieuzWup)z~BuJedjotGkgI$zVi#}BcBOYgp)|Ijw``e4K-+_ypC`Iq0y z*G6sIxzcOdkSq7JPpNfrX1j}DS`Z%z=eF4u5BEk|i8nEWGVaU2zBB5vEn9VVl5u05 zA$3?b94TcSE5s{|!Jz;55;h+l?uE22KlT*&NYmx@9}aFr;G#Ui}rj|8m_AJ2UOT|K4oy@f_$b zIQQo|^%OV{7I_U6T8!t}fJ)t5p7nS>cv$4LQ2BpY-C)r1Tx}m5Am}dSe;lq@8wBYEP^kmm?&|Hy`kjgDFMk0B zu>6_HJ$+aBW43Ys-xZ=ynWq~ir<-8zDLnmBak^Ij6C7g&_3pnzL_hzfyFsoFq`SMf z=7zp3bsR1YZLf}RuPuJr1oiI0!?liI@BaYaJ75Ny-8(x$T0D~&_Wruv;1JPYw;QzT zHjWPeSapY=|1Y!ZXe7AcU7@tRDp7TqXwFbtxhnpce*#dd62D3qt&m2(@wvVBPBI$v z?sbA3G+d%m@#8|@OLVq~m}#B6J13EP9F5@Z*mExf0+4i?z?F&0g1dgLTN4f|oJ6F- zR97*^NxB!t6RF2;;s^{-gjjP)KgE@BO$sLCJMKh3cda`U#6}99qcer!NjGi}nb?=n zr*OE}yG{mBr!!IoZaVeRxH&* zgsJwvj*w(+5)Pin*ajmGLdublF;}V6DlcTLdP}OfzYF-`({=wD{UdiaBO*Vh)kvy* zlzwPOhQv*3fu&t^z+v&>dD7TW;xkPi1t}qh_P!8TG04A8DV=iRDDrXT*HRYBb zQ|zG>YxxYqfPIKkNm`3EwC%$o?3$*-SX4p`I}>kK%)E*zlDzUDMY6?XKKSWaA1*$M z7m(*{+53v1@nPez3KJytl9eI=a0`j$(R3FQUDmM8|x`moFfBwt9 znd$r_xxU$l(hTmvtAd;TK;csom>o^IdBKPDYI%N+ zh#w`0ltU0XY$p&@K*}iB9SshpA0z4_zxQj{#k*PO$Z}v18b+3;&aN9M+2igGIc4uQ zVu745xS^MeG*yTjFW#Eb9Izl!K}zK?I-ENbJpB}%5f-2brP4)m{7jveZCs?ls_-ic za;l)vbQyk3bociNJvFRoMJ68t3|WY7r{;BdeDe0H8R<}uJicz!KzuM`uai+0`70m& zYBZBlp;rO+W7osQOTKj<7skoVjS%&|N0THiyL)~aVjzt~=k#`?4z+!Fs*=v5SGxRl z(GVhj0<>2J6urc}sZ`Fx$)RMJ-IXZ&*esS(rg|CPb!RWS^wW@|9v&J|h%J9F@2}Bd zS=Jb;&{T7(X~wIn(li_*8mq@vNCNkd47A@?j?ne*eTv{Zy6bZ11*#Y#BsV$;AG;1c z32Bp~TxZ1Z`b#{V?Ymc_6Ho$HHT@XXwYy`hr{5Qed9 zA4MPnrSmw*D#`7XrAs-+Ox=P4a+3u=CUP*%d^}-c zQTIu)Z!}##-ce`(l5DaHtTjK~W$`2_Ve5pdNdk~gnW@(?{Iv1Cg*;>TLe*pGim!hT zFrt9M>!%LNI4lWb5^V;}GE$}9xr(ZG;xm2#2tg%JhTI2j`6p{kN!# z9^~4o&=O`xJQ=DY=uaM53$KKZF{}e~gF+Ahz@>0vnbN>IC|KS27EX`0h6l+;g2rvi z9Muo;U;rq=7(%{AJ3~a|T05|~W6oILN3Q~f0*haz+!{ujOTeGdO9!5AjVtt}9`DH( z&2XzN$CHnJkG$U9!g02A@B==?8aT6nRYC@47f;``Oyn<52Ur1~M3^PW>mx!I!NLD> zlNqu{pTLkO=1ewdMj6i8agMSp^g634D%icVLuD^ayvf`sb*5W#O3A%kdxi1FQLQwC zQk1^&10$x{?wV0YCy&tw>|_}LDO0y_i19j?(f8ikUL|+IWs9wk>WuO&6~d1lEhSQ} z46K}ga*_c4(EbD{3|h*56Rt?zz|Ke!Yr0B6^CifoN4}3d9af5eDz{|}bkuP6R=%KK zX1n;}+$f%{N(6b`#)RLa%-UfuxmXY-r;t1xD^iu~0*Sai?@?x^UG;)q0EPXPH0m$n zEFy6I<89d5gt2A^Txw`jh+L5=Ep5N(!gX8q`5#kl$RM$WWLs(l{mC0U%a|ZxyL&Hx z%(P)@#NtgRgt&3jLz0^qoY`mdd71gGrJ9ENehY`%dUSi4RQ(H|Pez4ai^eX8$uJyF zgCS=sx25LIOP?o?pSnOtT_3j_+C||WT%GOLJ8ULSv34LvLu{@go2yM6{41}na8Tl) zCus&zcm-o7nx0ytd5Rsrc`=R;TJ`;l4KUyuDZ zi~uRpKcT=cNK6`dzkl}<)K&Wi_>KayK6xpS4DCm~-AQ_t9~d1G0Z>Bubb2^U;G*pP zeb5ZmKbDuTAizkyS-yb0J+*ozj0oP`ZWchdtVI69M{t>x=PLkBEwb$=Yd#Pb1qvCt zq2m`#-?d&Ah3*q^&z`a!Rf(1otDLZ*24#;&FF!#Xljkh`WcvR0$z#OVVcpiTho@aL z?_|lQvG^~_H(+`ESpsvu-dn_`uoIE2?}G0vGaq30sec_FmESid+HQ%Y*!BL_V@F4D zYh3s7xQyG31DG&Aujvryu#U42A&BE!jo^nxyOSbKkQu<03|A!=WHTS`=R;FcG*nan zUTztT665zR7@!n`UQIA=Mj;wE{aS+oBmlWj@CICw*8vDJ;~6uP({Qdo5)Gq7Vu^J~ zQO7Pa$M*ZV{_@HY?5L&&KTU-L60-|Amv1fq8X(<;=w*1g{F`ig{=cf7|2M(?pI%3> z66|$AWA53XMI!uPg8On~Fi3FAob@^p3MGNyWsqXke;OUlhDfl{0rQP|OVpjFm-m_y z?l&b_w4NDrvV`aVog?ax1<3?GLcDHA^1Y5TGQp%j1&lQh2nkm0sWx4&9`~jj_kgrq z_Fr1gWIA7esQ|nWvg*#X@5;aqD<7x|p@rSGYc$^J%2u!w_gH6z+^wu8e|3PSwt2{7xC%eE-c4HB2bcS{o+rBP=wA{qb z#=_1zm~6mar~B7t=jq3R(=Q;dF!yb9`ry;z{)fra&kJYMMBn;Pzk(45M7b9Z_C`;? zfd@qY87SJ{`E;T@f>kN#gtQV9t+NzEX$5pA&}$)j?Ptau zYp8=B7q^JP@Rs3?_QPk>M98h_r1|Qm5SFR=`hXQa>wkOY78ny4cDkER|l#2 z)uMXEsuhW8)tMk*f0H4ubTeWi-;66aJVzx#N=fJCX2_d!63!W7=86bfy8xHPs}g$W z`8Dk$isk%+3_~uNw&xgR6)UAWUer$1s1*t2syMclVzL{4$$G^;gw5#K`gWJ*L)jpf z1gDJ#-B63ALAROn{5LVd4A<()R>o}~6!?{OioTTxuRJkv#_eQ_KikQ_0(kbWsw2#~9qy2Qt={+IyRqgY!hq=`giaJ+r zF6fr%bf>{lmym5l!qzjbe9_2=ei`O^W^gW*I6F~RgYgG_-wI>xW>W1Fb0 z7|1T-Y7;diNDbB z+)la-jqWSvYx5My>)p(z8U)^l7jMZC(Ywkgy-sU5;G20CL?q3x^eE}FVHUMeKOveL zL;8mJIWA67U)A8La@$7kev|2@~d1+a;4Ie*}(>&HAV>iG$zM*%W zyTV0xXXgz|a3++IR^uYQvY`nXZ=q0*KvhMOFy4Z?xGF&}IjM4h{HVV@#AKPEgdWFh0blNs||9rBb@0qs=CmmT3iY(moB#bDI*>uV#; z15%!$S*d6R+PU8!iZ!$#HVY#g^4b-Jih{U`Su%7PhSbPrjF{2k^5^}=>LsX~)v8R|O5FLYJelV!r zzC1`@vb_?*msW=uid5`nEBgXD8go*x5A2K|F@E}3n#rt(L-u)jXDAJm&DRga*~LG; zl9Xx2@cQmkH*QCdJSW+_%fV)<1D%%zBFLQ|m>`$Z-wwLsV9Z#L6S6wY zC(4-68%*GfwH$VGK0a|luphcir$RLoAQkZD5rkL_O+uRhoby&>ien0(ei5R`c(cTY z+CQKni$98sbvW2a5eK2c;_q-<&<3Emc)IK48E!`T#yr*Mwr#uVCzKiH2+#V#Gztr# z%chCV=tT2g=oXI`ca55dGH{xO%QNI4`_;KgD6jyTP#?M$XTg2pimL37w}D0>;H|k$ z6chh)aF|98ipi^3_jVv~I6$s2bVzMCD~H&l13u9+0=<@zi*WcL&EgP* z_x8(^+<^1S*p9!r_mZX#5Rjk3jASuP=8N1dP?r>o(gLd;ooX9pQM0@1zjO-`HvY2r zWrpK}B#VC2g@|8soO+!`Um$5BXe7KxQpX8L+~BrU>Pec&VY^#IWR0;3p(ed$5MTQ2 zx81#~q@*2e+z5udAJwC6&&*B6OqEBrqIR=`$&$rsN+-S0!@jWwzv}Ymk^-RkHn-#{ zUtKh0Z}z|rMZWzlzrI-5gkl;0ASA1H)JMcY(96&SHH}t9ebRpfdN|Vhbj#ptz#cN= zPo@cI^HGtoXd?X&r7|#=I6n6xk!Y&&?BXRG2-oS&Go<&+ zHi3IERxU10SGrGh! z#US^tt< zwxljh8h&=zC5q78l4IoRGC|^iV^+%>r}d-GyqCmzf0LOradjy&;Q* z^R@(mK}MceqBg$%;R_`IksqZOb2eE3$^gV;Ye-e;0;FIoj0oxA0Dg63U&Z|y%T7K5 zthjAsIp7@+8xE0}Ns;W)agGV=miYvWHx`%fgQ0NnYiWXZV*aoatz%7g0-4u2B_d?$ z7OJk4j}w4E1YR7#COk!zRDjP1#ny0a2HEu+A?I4K_|k;5890H!e@p`%Vt+Qy#ZG`w zM&V#WraIdbXK?^}!wpKZ9dt6rb}F4bzYzclW9Jb${# zk}v)9%gCwO&+{sX9R>idz6TE zSA)u`4*aYDt2R6o=MngCGV1={Wb`jD_r~S#3DBQ$qCd$9wB^d&{s7!wGG)&s&v-dJ zXmJ0{M^cSvyc`J2$$^JJm4WhS0C(u$Dc3Z8whox1ZqyNaCq3;qnaW?PNFv3*+rCMLJBH=d(K&qgXh zhTC_d{J#eGrP0PQe{~2KTMS`%By3(DWDM_8%-hdjkhPfE%t3 zoTzy|c6JLCI@b_8UK2an1n#+}%rxUZG=o<_Y4hzl3!Oy^17(Xtp&M;+t8K4VI%9VF z)3=BG_q)KGpNP}p*lz<#Uq_;Tg67<0#Mz6t#n|5yeXAwE>V*$l4w){yf#V zHrBj0+xlrX^V>w`=~B_@V%gqQ_5NG~INkbtDfS*8z;|z*`zzoHP}fh8;r=puxHf;d4jSBD zr(cIo55TP=aItmjba&zO8<>d}&Mty>{)!6Qzt7&lfd)4yD*XS>;0BY?^M8{OqR{za zI34>n*O^3>Z1XN2&6#Tj|8_o-7qsZvbv<_t>J>PZ!bQznqE_0wXcSqMz|QAsMyZmX z-w&oa1s?STDQv%eTb50Dvgl6LN7ZV9Hf(GY_Kkd3=*vt+{jXbiU7JCA&6E}lel?Jc z*~8E96$=dmTGX({=`-n+vQD`$Uw08xCDC}E;8cZ4w0vO1g)1M_c#)r|5{2~l^;SO8 zZ@&w{zoZdKt+_B?bK&+AWZNo9abHZRTzmL;wb3E3RvO8$RGF@zH5RN! zG+D|=c3JZVi=?y-shtwtU-Iznl%VIix%wv=26Cp7U)RvMQJa>F1{q>zEzZ%V^FK^S z%(=AaD6UC|GprHy&Um18u~;HWjjko-bhre<`+o0Hm$SZw>v{UwK$i)1iRMx0J)tN* z&IjF@Zp(PdqFSuH?>zdWMRpL2H`p=^)q#DmvvOJX1q}$+h+S(9Qi_nEAq2MUF?w6w7 z(kl@);LPe{1;?Ju;NU=M&Lm6bkoF}0990OZ457k8DDar$eX7o!>is|lr@KVy-(85) z95`ugxs9yzF5uypb1KmMLHjEob51ODWi}%28rR!A^!-d2OK0PhvJUNeWdI>1&*{^H z(Wc5MoF7_r3PJnT%>}1At6g{yH|26L`7qO`R##IlCd3$jQ=lIQr_gpNfQzq-pA$?Y}np%HJy1T z<9#K1`Z;TnOGFm=1P0rTtWFVcTR8RLa=&phle|jjH#K$f*r{RV%t!Sr`g+fT1J(1& z==o*jhy*HG<%rbu=qm>=Dqq_hav8q&PLC<8YOx37&!1M;#%y2EuA+{Dz}1vd(7VIT zt5O^e>L#Mqca^10ilu*K*qtcizF#(PGcOdxFAKgNaw1aOg=_F7)ctl{_^M@J8cXfE zrxd9F@l6+J1a|;2n?{5X+cL30LB*_1_K*`Y@?#YVZ$jtJA&-Ny$+yC%@+6rXm&`MJ z*spepcWv>eUps6MVv&^_=U9v(;T;{Ilw7ZUSLDScIaZm{y(W4(B!ZOh$N6oi9 zwO`H`?pTs&m-SHC@F#!hmBLh=+x7qWEkx`lxI`0@h5zE8{>z%TUL4MedMpt{9$8xg ziT~n{P{eaxb0WPRTNZFa;f&t4x_rY%wVg(sE(8^GSAk`9H&kXTL`;n%OyFKLEx&ih zwk_io32%8uRaPV&XPLw|IRM(}N1(kC0+3wdw-m<ORiikrS$jeQn z113D8=3!Bn=`!*p&*Qbc`gPM!bYF?_6v%C%Ax@E1soBni+bR8%>ClUex0R5T@?jI! zY8jgCy@B_p`|swJIOm&5A}RalMv27=8SRGbOy~Q@?{w00P&n`#W`DqOF=aD0sT7$q zhKIj8q$_$R*^9{Xm^5Ktu1L7fO%f4pV2X}stOttC85^haZ|Z>$GWe|Y!wtz~~*$nuWdW(Kq`tkLMfUGHfMl@!8+%jFi=Of}xagE$ecc!JIw=C##s+pP43=<{p ziPxeX4ze%RPP9}OD5*hC`LM351Kk~b9)l$wxJ>BAiU)_bt+5?RcXu6&S-m5>5B2i1?w%QjFD$M-%{V(Jsh;fj9hap$zT-Tf}jX*3j+xx zsN$FGO$l!!@+wo+Q)e&Vmf^nKdnr#@6M(0F9Y3F`08tsTl~VvF(T*Je6!S^%g$%6h zu$L8u#sSjIzzf%^V#cT-W4BHUs7g&mg0TJVi#U2tIasAED-p5K&$<4`QrYLwG3=}W z0F}lO2W2dAlLPZxS~VH;7=UP-mU{+qR88$*{U-0{QeXUK*f2>9H7oG0zXhm&;E4wS z)^{ZoeXUd?0FVe!vNYq{zFgmPX2()+=s-))E$wn>cqPSex;LEAI(&?z!>oVjZSVPs z3=GRQo+YZotC*&Jp(uPi#`r!D3!1;Ej#tPbH1pQDTr9&@nGFl5q{Y#!3 zqu*Eo!{RU3z2b9r_a}0eJ%nY*@p(-DTq48xseXbJWB7i}kY(t;I+llp-Ks?diS7Ew z;*saJTsBJ=@kQYlNEY_r6@sQfkd(>Sq+39z*H>I|;mP48QOrc)DrA1` zQURx+mC-b&zC`z(0*_JW9tV+f9{V%9KY`BxmfHAqJ+jA95F_G% z51al(84%lLn{HQ>3l71$3kZiiCW!*ru<+*uZ}ETg&HoYy;8D*%>q7qrpY108M~1sn z?0Z)JRQiJ9Mx@H`@3S_khM==>^QZg))ok#hN1-nGCYW#jUi8#I|MR{r;#O_ct=1S_ z@SLYH*5t2maE2R1{D*}*Q?nB_hEwje#T&LIoMoCnaJFIZtFs~2iS!4ZskU8d*#0!5 zq3r*OHAN4*GweGvtp>8~2Xerp9?z~ESMaW~O{!ba)+te0I0jQ6DI1`wf-& zzb*9}Di0f~3LLA97_SPStP7k21?{G&iE0pvO9j`3mYP#%TSHbFQs>&U=R5M=^%gDm zgNHnUUpii{x23N3ByaZl@Am{9^?|V_{A48c>(C!4ZVFW5QV+*tPN$Pkr$Nvl{d6{C zqdRv4++Q88Tpy}g9|IljmM;rg`(v4>(>Y+Q`L$SaINN-<03zDpoY1RNaC~*G_;d{n zH2J67WvB1KE1ss)?SIou)#?6U(4gt`^bcrocFWWKd13HuRA>VP4d%~QSi!>Q)8Ogn zvBUMZho2V?Kac;~?)WFrygLBX%mKJ7H2F8v9DZK^wz~sDao}msA1Ll`togr$IQS9P z6&y}`K|6+fR!%3FlJ!cA?i<=S`u}NucImmV8Ri*8bMmOghR_M#8=Mx+zi~8~CXq!6!baW9*JUij)cLiOWt!dhgeU8s>gPC6uaOHi zCsG{R=Db#C1c&ArC2ePR&ARB_)~&A{h)49s==28dtvgvYx3L|({kAdieiR=X6KO8v zs1eTeXccF4H)wsPBD+I+?UU5Brl0H4;dv?N__qOZC-SO-m5(B)qPSj%u>FRIaRn6} z?H_E7?8y4mxP51tvo_4JmMc&6kRIJwuzQ*t<>$pO=DU1Www@c94Q>v`^LU6&2kS%@^7V2batp@X@J+~GW8-&Ya#%qu#v z?fde%+>eTp!a>tO%zkYSN zlJq{!`?1`;+oGX;@kW7pe6vY>Id818pX(9)IZx>Oo%*2z2!-GCdTgBy=qwMd63{8!^^2bZ?+zvNtV^X-B469Py*-C5No5zTSoNr zBn%ooDZaa!%oBXgDLJrJv@NG2F)|lvlC>!?U(mj-rH!X@cOfF>P1U|8+I+YaRvg*n z(e}k!r5e6l=Fn#4P!Lfv=tM+*>6ep!rgMAWgw$H<)9(76kF)pRc`!SdZBS?=cy5#= z?~c)5+TMk8*ar^qy;3oGI?1Sik0+k_@ei((QB}#e0g5_9yG*m8d9xM`f(aRAb9T1~ z_;a!lt}wn=?yG$hPmPR=hrc^*B_$Y+LR7g)7R`cbrO^g8;USfwu0+qTvdY1Q^T)=8 zG7Yrq7wGhhJaVV4-Yha2yCacY*C+8oq(aG`W#;TIYqxJ#J|Mtu)dgfV@5J6oyD}WB zSFjhvvXj{-V0`{IlDtReRA&46om)Ocic#EQhsQ>2wF{D`zF%J9!Oa-4r$~hbg2Tf* zi38lDKyX|Jgd*zQwmg9>dQhJ3sN?>QYtM~$cLyH3j&%aX4~Q?-so0R(8+4#&FeEo| zP$eXZm`I2m#p4mD#FXUI0$mbif-2LAD28KO4UNy!c><*gz|maBkwz^;{j~?NCk+V- zr~^or9~IE+?Ezh`yTTU}`QVH?B~}uNp7_4uNE+k=Hg=362b!A+M{a>8e$(C0K@%Cy z-Alt=CiT$}=jj%JgY#ceMcSjSh`x8R+eG(iWR(Yf4`<=SK>D?5)`?ZB9tiLyDI+jA z=%_@mkd3OkCMiuAbB-~;)yjZBju7~!lS}ZM0Tki>5{4i_h;)N*%4EL9GZ$IO^W)U6 zQGSCg1-!o8tO}W@UT3U7VdA?oFgvK3N6q+AF@$OEf+~;e(=?B4WT}s7pBEE)4ZOZ3x zx>&0|lnZ~EHGvMA0mPq^jAu#cq9vO@Xj*!VM~l3Sm;L=lZb^GEt3?;`%>trn*FTvn zAo*IROG!6Z4JA!i9-?=^t4B}JLug|Qji1}yendJ|9&?bu+AIK@>7TBV0z}(@Anb

}woky2IWI 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%0DEnv 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 literal 0 HcmV?d00001 diff --git a/DiztinGUIsh/packages.config b/DiztinGUIsh/packages.config index c3110b0d..175d1a47 100644 --- a/DiztinGUIsh/packages.config +++ b/DiztinGUIsh/packages.config @@ -12,6 +12,9 @@ + + + @@ -19,5 +22,5 @@ - + \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.Designer.cs b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.Designer.cs index 7d8c0e6c..115bc713 100644 --- a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.Designer.cs +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.Designer.cs @@ -29,13 +29,10 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(BSNESTraceLogBinaryMonitorForm)); this.btnStart = new System.Windows.Forms.Button(); this.label1 = new System.Windows.Forms.Label(); this.lblQueueSize = new System.Windows.Forms.Label(); - this.backgroundWorker1_pipeReader = new System.ComponentModel.BackgroundWorker(); this.timer1 = new System.Windows.Forms.Timer(this.components); - this.backgroundWorker2_processQueue = new System.ComponentModel.BackgroundWorker(); this.btnFinish = new System.Windows.Forms.Button(); this.lblTotalProcessed = new System.Windows.Forms.Label(); this.label4 = new System.Windows.Forms.Label(); @@ -56,23 +53,28 @@ private void InitializeComponent() this.label15 = new System.Windows.Forms.Label(); this.label16 = new System.Windows.Forms.Label(); this.label17 = new System.Windows.Forms.Label(); - this.label18 = new System.Windows.Forms.Label(); + this.lblResultStatus = new System.Windows.Forms.Label(); + this.label7 = new System.Windows.Forms.Label(); + this.pictureGreenSpinner = new System.Windows.Forms.PictureBox(); + this.button1 = new System.Windows.Forms.Button(); + this.cartesianChart1 = new LiveCharts.WinForms.CartesianChart(); + ((System.ComponentModel.ISupportInitialize)(this.pictureGreenSpinner)).BeginInit(); this.SuspendLayout(); // // btnStart // - this.btnStart.Location = new System.Drawing.Point(252, 19); + this.btnStart.Location = new System.Drawing.Point(478, 12); this.btnStart.Name = "btnStart"; - this.btnStart.Size = new System.Drawing.Size(130, 38); + this.btnStart.Size = new System.Drawing.Size(64, 38); this.btnStart.TabIndex = 0; - this.btnStart.Text = "Capture from BSNES-PLUS"; + this.btnStart.Text = "Start Capture"; this.btnStart.UseVisualStyleBackColor = true; this.btnStart.Click += new System.EventHandler(this.btnStart_Click); // // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(12, 44); + this.label1.Location = new System.Drawing.Point(15, 44); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(60, 13); this.label1.TabIndex = 1; @@ -81,7 +83,7 @@ private void InitializeComponent() // lblQueueSize // this.lblQueueSize.AutoSize = true; - this.lblQueueSize.Location = new System.Drawing.Point(131, 44); + this.lblQueueSize.Location = new System.Drawing.Point(149, 44); this.lblQueueSize.Name = "lblQueueSize"; this.lblQueueSize.Size = new System.Drawing.Size(13, 13); this.lblQueueSize.TabIndex = 2; @@ -95,18 +97,18 @@ private void InitializeComponent() // btnFinish // this.btnFinish.Enabled = false; - this.btnFinish.Location = new System.Drawing.Point(388, 19); + this.btnFinish.Location = new System.Drawing.Point(413, 12); this.btnFinish.Name = "btnFinish"; - this.btnFinish.Size = new System.Drawing.Size(91, 38); + this.btnFinish.Size = new System.Drawing.Size(59, 38); this.btnFinish.TabIndex = 3; - this.btnFinish.Text = "Finish"; + this.btnFinish.Text = "Stop Capture"; this.btnFinish.UseVisualStyleBackColor = true; this.btnFinish.Click += new System.EventHandler(this.btnFinish_Click); // // lblTotalProcessed // this.lblTotalProcessed.AutoSize = true; - this.lblTotalProcessed.Location = new System.Drawing.Point(131, 254); + this.lblTotalProcessed.Location = new System.Drawing.Point(428, 174); this.lblTotalProcessed.Name = "lblTotalProcessed"; this.lblTotalProcessed.Size = new System.Drawing.Size(13, 13); this.lblTotalProcessed.TabIndex = 6; @@ -115,16 +117,16 @@ private void InitializeComponent() // label4 // this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(15, 254); + this.label4.Location = new System.Drawing.Point(303, 174); this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(99, 13); + this.label4.Size = new System.Drawing.Size(117, 13); this.label4.TabIndex = 5; - this.label4.Text = "# Bytes Considered"; + this.label4.Text = "# Instructions Analyzed"; // // lblStatus // this.lblStatus.AutoSize = true; - this.lblStatus.Location = new System.Drawing.Point(131, 24); + this.lblStatus.Location = new System.Drawing.Point(149, 24); this.lblStatus.Name = "lblStatus"; this.lblStatus.Size = new System.Drawing.Size(13, 13); this.lblStatus.TabIndex = 8; @@ -142,7 +144,7 @@ private void InitializeComponent() // lblNumberModified // this.lblNumberModified.AutoSize = true; - this.lblNumberModified.Location = new System.Drawing.Point(131, 279); + this.lblNumberModified.Location = new System.Drawing.Point(428, 199); this.lblNumberModified.Name = "lblNumberModified"; this.lblNumberModified.Size = new System.Drawing.Size(13, 13); this.lblNumberModified.TabIndex = 10; @@ -151,16 +153,16 @@ private void InitializeComponent() // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(15, 279); + this.label3.Location = new System.Drawing.Point(303, 199); this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(86, 13); + this.label3.Size = new System.Drawing.Size(114, 13); this.label3.TabIndex = 9; - this.label3.Text = "# Bytes Modified"; + this.label3.Text = "# Instructions Modified"; // // lblModifiedXFlags // this.lblModifiedXFlags.AutoSize = true; - this.lblModifiedXFlags.Location = new System.Drawing.Point(128, 126); + this.lblModifiedXFlags.Location = new System.Drawing.Point(146, 126); this.lblModifiedXFlags.Name = "lblModifiedXFlags"; this.lblModifiedXFlags.Size = new System.Drawing.Size(13, 13); this.lblModifiedXFlags.TabIndex = 12; @@ -178,7 +180,7 @@ private void InitializeComponent() // lblModifiedMFlags // this.lblModifiedMFlags.AutoSize = true; - this.lblModifiedMFlags.Location = new System.Drawing.Point(128, 152); + this.lblModifiedMFlags.Location = new System.Drawing.Point(146, 152); this.lblModifiedMFlags.Name = "lblModifiedMFlags"; this.lblModifiedMFlags.Size = new System.Drawing.Size(13, 13); this.lblModifiedMFlags.TabIndex = 14; @@ -196,7 +198,7 @@ private void InitializeComponent() // lblModifiedDPs // this.lblModifiedDPs.AutoSize = true; - this.lblModifiedDPs.Location = new System.Drawing.Point(128, 176); + this.lblModifiedDPs.Location = new System.Drawing.Point(146, 176); this.lblModifiedDPs.Name = "lblModifiedDPs"; this.lblModifiedDPs.Size = new System.Drawing.Size(13, 13); this.lblModifiedDPs.TabIndex = 16; @@ -214,7 +216,7 @@ private void InitializeComponent() // lblModifiedDBs // this.lblModifiedDBs.AutoSize = true; - this.lblModifiedDBs.Location = new System.Drawing.Point(128, 201); + this.lblModifiedDBs.Location = new System.Drawing.Point(146, 201); this.lblModifiedDBs.Name = "lblModifiedDBs"; this.lblModifiedDBs.Size = new System.Drawing.Size(13, 13); this.lblModifiedDBs.TabIndex = 18; @@ -232,7 +234,7 @@ private void InitializeComponent() // lblModifiedFlags // this.lblModifiedFlags.AutoSize = true; - this.lblModifiedFlags.Location = new System.Drawing.Point(128, 102); + this.lblModifiedFlags.Location = new System.Drawing.Point(146, 102); this.lblModifiedFlags.Name = "lblModifiedFlags"; this.lblModifiedFlags.Size = new System.Drawing.Size(13, 13); this.lblModifiedFlags.TabIndex = 20; @@ -243,9 +245,9 @@ private void InitializeComponent() this.label14.AutoSize = true; this.label14.Location = new System.Drawing.Point(12, 102); this.label14.Name = "label14"; - this.label14.Size = new System.Drawing.Size(108, 13); + this.label14.Size = new System.Drawing.Size(127, 13); this.label14.TabIndex = 19; - this.label14.Text = "Bytes Marked w/type"; + this.label14.Text = "# Instructions Uncovered"; // // label15 // @@ -271,29 +273,71 @@ private void InitializeComponent() // this.label17.AutoSize = true; this.label17.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label17.Location = new System.Drawing.Point(12, 232); + this.label17.Location = new System.Drawing.Point(300, 152); this.label17.Name = "label17"; this.label17.Size = new System.Drawing.Size(57, 13); this.label17.TabIndex = 23; this.label17.Text = "Summary"; // - // label18 - // - this.label18.AutoSize = true; - this.label18.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label18.Location = new System.Drawing.Point(5, 314); - this.label18.MaximumSize = new System.Drawing.Size(500, 0); - this.label18.Name = "label18"; - this.label18.Size = new System.Drawing.Size(497, 221); - this.label18.TabIndex = 24; - this.label18.Text = resources.GetString("label18.Text"); + // lblResultStatus + // + this.lblResultStatus.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.lblResultStatus.Location = new System.Drawing.Point(310, 102); + this.lblResultStatus.Name = "lblResultStatus"; + this.lblResultStatus.Size = new System.Drawing.Size(236, 37); + this.lblResultStatus.TabIndex = 26; + this.lblResultStatus.Text = "--jhgasdjhfgasjhdgfhjasdfgasdf kfhfjhf"; + this.lblResultStatus.TextAlign = System.Drawing.ContentAlignment.TopRight; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label7.Location = new System.Drawing.Point(306, 81); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(43, 13); + this.label7.TabIndex = 25; + this.label7.Text = "Result"; + // + // pictureGreenSpinner + // + this.pictureGreenSpinner.Image = global::DiztinGUIsh.Properties.Resources._1603231497loading_green; + this.pictureGreenSpinner.Location = new System.Drawing.Point(303, 12); + this.pictureGreenSpinner.Name = "pictureGreenSpinner"; + this.pictureGreenSpinner.Size = new System.Drawing.Size(46, 37); + this.pictureGreenSpinner.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.pictureGreenSpinner.TabIndex = 27; + this.pictureGreenSpinner.TabStop = false; + // + // button1 + // + this.button1.Enabled = false; + this.button1.Location = new System.Drawing.Point(355, 12); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(52, 38); + this.button1.TabIndex = 28; + this.button1.Text = "Help"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // cartesianChart1 + // + this.cartesianChart1.Location = new System.Drawing.Point(12, 233); + this.cartesianChart1.Name = "cartesianChart1"; + this.cartesianChart1.Size = new System.Drawing.Size(533, 292); + this.cartesianChart1.TabIndex = 29; + this.cartesianChart1.Text = "cartesianChart1"; // // BSNESTraceLogBinaryMonitorForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(505, 539); - this.Controls.Add(this.label18); + this.ClientSize = new System.Drawing.Size(557, 537); + this.Controls.Add(this.cartesianChart1); + this.Controls.Add(this.button1); + this.Controls.Add(this.pictureGreenSpinner); + this.Controls.Add(this.lblResultStatus); + this.Controls.Add(this.label7); this.Controls.Add(this.label17); this.Controls.Add(this.label16); this.Controls.Add(this.label15); @@ -320,6 +364,9 @@ private void InitializeComponent() this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; this.Name = "BSNESTraceLogBinaryMonitorForm"; this.Text = "BSNES Live Tracelog Capture"; + this.Load += new System.EventHandler(this.BSNESTraceLogBinaryMonitorForm_Load); + this.Shown += new System.EventHandler(this.BSNESTraceLogBinaryMonitorForm_Shown); + ((System.ComponentModel.ISupportInitialize)(this.pictureGreenSpinner)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -330,9 +377,7 @@ private void InitializeComponent() private System.Windows.Forms.Button btnStart; private System.Windows.Forms.Label label1; private System.Windows.Forms.Label lblQueueSize; - private System.ComponentModel.BackgroundWorker backgroundWorker1_pipeReader; private System.Windows.Forms.Timer timer1; - private System.ComponentModel.BackgroundWorker backgroundWorker2_processQueue; private System.Windows.Forms.Button btnFinish; private System.Windows.Forms.Label lblTotalProcessed; private System.Windows.Forms.Label label4; @@ -353,6 +398,10 @@ private void InitializeComponent() private System.Windows.Forms.Label label15; private System.Windows.Forms.Label label16; private System.Windows.Forms.Label label17; - private System.Windows.Forms.Label label18; + private System.Windows.Forms.Label lblResultStatus; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.PictureBox pictureGreenSpinner; + private System.Windows.Forms.Button button1; + private LiveCharts.WinForms.CartesianChart cartesianChart1; } } \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs new file mode 100644 index 00000000..b06ce854 --- /dev/null +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs @@ -0,0 +1,107 @@ +using System; +using System.Drawing; +using System.Windows.Forms; +using ByteSizeLib; +using Diz.Core.import; +using LiveCharts; +using LiveCharts.Wpf; + +namespace DiztinGUIsh.window.dialog +{ + public partial class BSNESTraceLogBinaryMonitorForm + { + private bool initializedChart; + private readonly ChartValues chartValuesBytesModified = new ChartValues(); + + private void AppendToChart((BSNESTraceLogImporter.Stats stats, int bytesInQueue) currentStats) + { + InitChart(); + chartValuesBytesModified.Add(currentStats.stats.numRomBytesModified); + } + + private void InitChart() + { + if (initializedChart) + return; + + cartesianChart1.Series = new SeriesCollection + { + new LineSeries + { + Title = "Instructions Modified", + Values = chartValuesBytesModified, + }, + }; + + cartesianChart1.DisableAnimations = true; + + initializedChart = true; + } + + private void UpdateUI() + { + var running = capturing?.Running ?? false; + var finishing = capturing?.Finishing ?? false; + + lblStatus.Text = !running ? "Not running" : finishing ? "Stopping..." : "Running"; + + btnFinish.Enabled = !finishing && running; + btnStart.Enabled = !running; + + pictureGreenSpinner.Visible = pictureGreenSpinner.Enabled = running; + + if (running) + { + lblResultStatus.Text = ""; + } + else if (lastError != "") + { + lblResultStatus.Text = lastError; + lblResultStatus.ForeColor = Color.Red; + } + else + { + lblResultStatus.Text = "Success!"; + lblResultStatus.ForeColor = Color.ForestGreen; + } + + if (capturing == null) + return; + + var currentStats = capturing.GetStats(); + var (stats, totalQueueBytes) = currentStats; + + AppendToChart(currentStats); + + var qItemCount = capturing.BlocksToProcess.ToString(); + var qByteCount = ByteSize.FromBytes(totalQueueBytes).ToString("0.0"); + + lblQueueSize.Text = $"{qByteCount} (num groups: {qItemCount})"; + + // TODO: use databinding + + lblTotalProcessed.Text = ByteSize.FromBytes(stats.numRomBytesAnalyzed).ToString("0.00"); + lblNumberModified.Text = ByteSize.FromBytes(stats.numRomBytesModified).ToString("0.00"); + lblModifiedDBs.Text = ByteSize.FromBytes(stats.numDBModified).ToString("0.00"); + lblModifiedDPs.Text = ByteSize.FromBytes(stats.numDpModified).ToString("0.00"); + lblModifiedFlags.Text = ByteSize.FromBytes(stats.numMarksModified).ToString("0.00"); + lblModifiedXFlags.Text = ByteSize.FromBytes(stats.numXFlagsModified).ToString("0.00"); + lblModifiedMFlags.Text = ByteSize.FromBytes(stats.numMFlagsModified).ToString("0.00"); + } + + private void button1_Click(object sender, EventArgs e) + { + MessageBox.Show("What is this? \r\n" + + "Connect via socket to a special build of BSNES-plus and capture live tracelog as you play the game " + + "in realtime or play back a movie/recording/TAS.\r\n\r\n" + + "As each instruction is visited by the CPU, info like X,M,DB,D and flags are capture and " + + "logged in Diz. This will greatly aid in dissasembly.\r\n\r\n" + + "If you're just starting a ROM hacking project from scratch, you want to see this" + + " capture a lot of modified data for X,M,DP,DB and marking bytes as Opcode/Operands.\r\n\r\n" + + "If you're far into a ROM hacking project, you will start seeing fewer NEWLY DISCOVERED " + + "modifications here. Try playing through different parts of the game, menus, every " + + "combination of searching you can do to allow this tool to discover as much as it can.\r\n\r\n" + + "When you close this window, try exporting your disassembly and see how much you uncovered!\r\n"); + } + } +} \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs index b416b49a..6b365ea3 100644 --- a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs @@ -1,4 +1,7 @@ using System; +using System.Drawing; +using System.Linq; +using System.Threading.Tasks; using System.Windows.Forms; using ByteSizeLib; using Diz.Core.import; @@ -12,12 +15,13 @@ namespace DiztinGUIsh.window.dialog // eventually, if we want to do that we need to retrofit the rest of the app to take advantage of that. public partial class BSNESTraceLogBinaryMonitorForm : Form { - private MainWindow MainWindow; + private readonly MainWindow mainWindow; private BSNESTraceLogCapture capturing; + private string lastError; public BSNESTraceLogBinaryMonitorForm(MainWindow window) { - MainWindow = window; + mainWindow = window; InitializeComponent(); } @@ -26,69 +30,49 @@ private void btnStart_Click(object sender, EventArgs e) timer1.Enabled = true; btnFinish.Enabled = true; btnStart.Enabled = false; - + capturing = new BSNESTraceLogCapture(); - capturing.Finished += CapturingFinished; - capturing.Error += Capturing_Error; - capturing.Start(MainWindow.Project.Data); + Start(); } - private void Capturing_Error(Exception e) + private async void Start() { - MessageBox.Show(e.Message, "Worker Error"); + // TODO: error handling is busted here. + await Task.Run(() => { + capturing.Run(mainWindow.Project.Data); + }).ContinueWith(task => { + this.InvokeIfRequired(() => CapturingFinished(task.Exception)); + }); + UpdateUI(); } private void btnFinish_Click(object sender, EventArgs e) { - timer1.Enabled = false; - capturing?.SignalToStop(); - UpdateUI(); } - private void CapturingFinished(object sender, EventArgs e) + private void CapturingFinished(AggregateException ex) { - UpdateUI(); - } + if (ex != null) { + OnError(ex); + } - private void timer1_Tick(object sender, EventArgs e) - { + timer1.Enabled = false; + capturing = null; UpdateUI(); } - private void UpdateUI() - { - var running = capturing?.Running ?? false; - var finishing = capturing?.Finishing ?? false; + private void timer1_Tick(object sender, EventArgs e) => UpdateUI(); - lblStatus.Text = !running ? "Not running" : finishing ? "Stopping..." : "Running"; - - btnFinish.Enabled = !finishing && running; - btnStart.Enabled = !running; - - if (capturing == null) - return; - - var (stats, totalQueueBytes) = capturing.GetStats(); - - var qItemCount = capturing.QueueLength.ToString(); - var qByteCount = ByteSize.FromBytes(totalQueueBytes).ToString("0.00"); - - lblQueueSize.Text = $"{qByteCount} (num groups: {qItemCount})"; - - // TODO: use databinding - - const string format = "0.00"; + private void OnError(AggregateException e) + { + Console.WriteLine(e.ToString()); + lastError = e.InnerExceptions.Select(ex => ex.Message).Aggregate((line, val) => line += val + "\n"); + } - lblTotalProcessed.Text = ByteSize.FromBytes(stats.numRomBytesAnalyzed).ToString(format); - lblNumberModified.Text = ByteSize.FromBytes(stats.numRomBytesModified).ToString(format); - lblModifiedDBs.Text = ByteSize.FromBytes(stats.numDBModified).ToString(format); - lblModifiedDPs.Text = ByteSize.FromBytes(stats.numDpModified).ToString(format); - lblModifiedFlags.Text = ByteSize.FromBytes(stats.numMarksModified).ToString(format); - lblModifiedXFlags.Text = ByteSize.FromBytes(stats.numXFlagsModified).ToString(format); - lblModifiedMFlags.Text = ByteSize.FromBytes(stats.numMFlagsModified).ToString(format); - } + private void BSNESTraceLogBinaryMonitorForm_Load(object sender, EventArgs e) => UpdateUI(); + private void BSNESTraceLogBinaryMonitorForm_Shown(object sender, EventArgs e) => UpdateUI(); } } \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.resx b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.resx index b815b9d4..c866993a 100644 --- a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.resx +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.resx @@ -117,28 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 17, 17 - 248, 17 - - 335, 17 - - - What is this? -Connect via socket to BSNES plus and capture live tracelog as you play the game in realtime or play back a movie/recording/TAS. - -As each instruction is visited by the CPU, info like X,M,DB,D and flags are capture and logged in Diz. This will greatly aid in dissasembly. - -If you're just starting a ROM hacking project from scratch, you want to see this capture a lot of modified data for X,M,DP,DB and marking bytes as Opcode/Operands. - -If you're far into a ROM hacking project, you will start seeing fewer NEWLY DISCOVERED modifications here. Try playing through different parts of the game, menus, every combination of searching you can do to allow this tool to discover as much as it can. - -When you close this window, try exporting your disassembly and see how much you uncovered! - - 36 From a03d59ef776084aa6af9c7e6813ea657d54e66f2 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Thu, 22 Oct 2020 19:07:06 -0400 Subject: [PATCH 098/136] Add first pass at data visualization :) --- DiztinGUIsh/DiztinGUIsh.csproj | 9 ++ DiztinGUIsh/window/MainWindow.Designer.cs | 87 +++++++------ DiztinGUIsh/window/MainWindow.cs | 9 +- DiztinGUIsh/window/VisualizerForm.Designer.cs | 64 ++++++++++ DiztinGUIsh/window/VisualizerForm.cs | 80 ++++++++++++ DiztinGUIsh/window/VisualizerForm.resx | 120 ++++++++++++++++++ 6 files changed, 322 insertions(+), 47 deletions(-) create mode 100644 DiztinGUIsh/window/VisualizerForm.Designer.cs create mode 100644 DiztinGUIsh/window/VisualizerForm.cs create mode 100644 DiztinGUIsh/window/VisualizerForm.resx diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 565daf5e..8db72dc1 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -224,6 +224,12 @@ AliasList.cs + + Form + + + VisualizerForm.cs + Form @@ -271,6 +277,9 @@ InOutPointChecker.cs + + VisualizerForm.cs + MainWindow.cs Designer diff --git a/DiztinGUIsh/window/MainWindow.Designer.cs b/DiztinGUIsh/window/MainWindow.Designer.cs index 3f6f044f..0f036084 100644 --- a/DiztinGUIsh/window/MainWindow.Designer.cs +++ b/DiztinGUIsh/window/MainWindow.Designer.cs @@ -66,6 +66,11 @@ private void InitializeComponent() this.saveProjectAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripMenuItem(); + this.importUsageMapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.importCDLToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator(); + this.importTraceLogText = new System.Windows.Forms.ToolStripMenuItem(); + this.importTraceLogBinary = new System.Windows.Forms.ToolStripMenuItem(); this.exportLogToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator(); this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -135,11 +140,6 @@ private void InitializeComponent() this.openUsageMapFile = new System.Windows.Forms.OpenFileDialog(); this.openTraceLogDialog = new System.Windows.Forms.OpenFileDialog(); this.openCDLDialog = new System.Windows.Forms.OpenFileDialog(); - this.importUsageMapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.importTraceLogBinary = new System.Windows.Forms.ToolStripMenuItem(); - this.importTraceLogText = new System.Windows.Forms.ToolStripMenuItem(); - this.importCDLToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator(); ((System.ComponentModel.ISupportInitialize)(this.table)).BeginInit(); this.menuStrip1.SuspendLayout(); this.statusStrip1.SuspendLayout(); @@ -443,6 +443,44 @@ private void InitializeComponent() this.toolStripMenuItem2.Size = new System.Drawing.Size(235, 22); this.toolStripMenuItem2.Text = "Import"; // + // importUsageMapToolStripMenuItem + // + this.importUsageMapToolStripMenuItem.Enabled = false; + this.importUsageMapToolStripMenuItem.Name = "importUsageMapToolStripMenuItem"; + this.importUsageMapToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.importUsageMapToolStripMenuItem.Text = "Import BSNES Usage Map..."; + this.importUsageMapToolStripMenuItem.Click += new System.EventHandler(this.importUsageMapToolStripMenuItem_Click_1); + // + // importCDLToolStripMenuItem + // + this.importCDLToolStripMenuItem.Enabled = false; + this.importCDLToolStripMenuItem.Name = "importCDLToolStripMenuItem"; + this.importCDLToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.I))); + this.importCDLToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.importCDLToolStripMenuItem.Text = "Import CDL..."; + this.importCDLToolStripMenuItem.Click += new System.EventHandler(this.importCDLToolStripMenuItem_Click_1); + // + // toolStripSeparator8 + // + this.toolStripSeparator8.Name = "toolStripSeparator8"; + this.toolStripSeparator8.Size = new System.Drawing.Size(250, 6); + // + // importTraceLogText + // + this.importTraceLogText.Enabled = false; + this.importTraceLogText.Name = "importTraceLogText"; + this.importTraceLogText.Size = new System.Drawing.Size(253, 22); + this.importTraceLogText.Text = "Import BSNES Trace Log..."; + this.importTraceLogText.Click += new System.EventHandler(this.toolStripMenuItem3_Click); + // + // importTraceLogBinary + // + this.importTraceLogBinary.Enabled = false; + this.importTraceLogBinary.Name = "importTraceLogBinary"; + this.importTraceLogBinary.Size = new System.Drawing.Size(253, 22); + this.importTraceLogBinary.Text = "Import BSNES Trace Log (Binary)..."; + this.importTraceLogBinary.Click += new System.EventHandler(this.toolStripMenuItem1_Click); + // // exportLogToolStripMenuItem // this.exportLogToolStripMenuItem.Enabled = false; @@ -812,7 +850,6 @@ private void InitializeComponent() // // visualMapToolStripMenuItem // - this.visualMapToolStripMenuItem.Enabled = false; this.visualMapToolStripMenuItem.Name = "visualMapToolStripMenuItem"; this.visualMapToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.V))); this.visualMapToolStripMenuItem.Size = new System.Drawing.Size(212, 22); @@ -997,44 +1034,6 @@ private void InitializeComponent() // this.openCDLDialog.Filter = "BizHawk Code Data Logger Files|*.cdl|All Files|*.*"; // - // importUsageMapToolStripMenuItem - // - this.importUsageMapToolStripMenuItem.Enabled = false; - this.importUsageMapToolStripMenuItem.Name = "importUsageMapToolStripMenuItem"; - this.importUsageMapToolStripMenuItem.Size = new System.Drawing.Size(253, 22); - this.importUsageMapToolStripMenuItem.Text = "Import BSNES Usage Map..."; - this.importUsageMapToolStripMenuItem.Click += new System.EventHandler(this.importUsageMapToolStripMenuItem_Click_1); - // - // importTraceLogBinary - // - this.importTraceLogBinary.Enabled = false; - this.importTraceLogBinary.Name = "importTraceLogBinary"; - this.importTraceLogBinary.Size = new System.Drawing.Size(253, 22); - this.importTraceLogBinary.Text = "Import BSNES Trace Log (Binary)..."; - this.importTraceLogBinary.Click += new System.EventHandler(this.toolStripMenuItem1_Click); - // - // importTraceLogText - // - this.importTraceLogText.Enabled = false; - this.importTraceLogText.Name = "importTraceLogText"; - this.importTraceLogText.Size = new System.Drawing.Size(253, 22); - this.importTraceLogText.Text = "Import BSNES Trace Log..."; - this.importTraceLogText.Click += new System.EventHandler(this.toolStripMenuItem3_Click); - // - // importCDLToolStripMenuItem - // - this.importCDLToolStripMenuItem.Enabled = false; - this.importCDLToolStripMenuItem.Name = "importCDLToolStripMenuItem"; - this.importCDLToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.I))); - this.importCDLToolStripMenuItem.Size = new System.Drawing.Size(253, 22); - this.importCDLToolStripMenuItem.Text = "Import CDL..."; - this.importCDLToolStripMenuItem.Click += new System.EventHandler(this.importCDLToolStripMenuItem_Click_1); - // - // toolStripSeparator8 - // - this.toolStripSeparator8.Name = "toolStripSeparator8"; - this.toolStripSeparator8.Size = new System.Drawing.Size(250, 6); - // // MainWindow // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index d6e9d87c..5385ab05 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -1,14 +1,15 @@ using System; -using System.Drawing; using System.Globalization; using System.IO; using System.Windows.Forms; +using System.Windows.Media; using Diz.Core.export; using Diz.Core.model; using Diz.Core.util; using DiztinGUIsh.controller; using DiztinGUIsh.Properties; using DiztinGUIsh.window.dialog; +using Color = System.Drawing.Color; using Label = Diz.Core.model.Label; namespace DiztinGUIsh.window @@ -879,10 +880,12 @@ private void GoToUnreached(bool end, bool direction) if (Project.Data.GetFlag(unreached) == Data.FlagType.Unreached) SelectOffset(unreached, 1); } + private VisualizerForm visualForm; + private void visualMapToolStripMenuItem_Click(object sender, EventArgs e) { - // TODO - // visual map window + visualForm ??= new VisualizerForm(this); + visualForm.Show(); } private void graphicsWindowToolStripMenuItem_Click(object sender, EventArgs e) diff --git a/DiztinGUIsh/window/VisualizerForm.Designer.cs b/DiztinGUIsh/window/VisualizerForm.Designer.cs new file mode 100644 index 00000000..450776eb --- /dev/null +++ b/DiztinGUIsh/window/VisualizerForm.Designer.cs @@ -0,0 +1,64 @@ +namespace DiztinGUIsh.window +{ + partial class VisualizerForm + { + ///

+ /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // pictureBox1 + // + this.pictureBox1.Dock = System.Windows.Forms.DockStyle.Fill; + this.pictureBox1.Location = new System.Drawing.Point(0, 0); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(1189, 553); + this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.pictureBox1.TabIndex = 0; + this.pictureBox1.TabStop = false; + this.pictureBox1.Paint += new System.Windows.Forms.PaintEventHandler(this.pictureBox1_Paint); + // + // VisualizerForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(1189, 553); + this.Controls.Add(this.pictureBox1); + this.Name = "VisualizerForm"; + this.Text = "ROM Visualizer"; + this.Load += new System.EventHandler(this.VisualizerForm_Load); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.PictureBox pictureBox1; + } +} \ No newline at end of file diff --git a/DiztinGUIsh/window/VisualizerForm.cs b/DiztinGUIsh/window/VisualizerForm.cs new file mode 100644 index 00000000..d98e66b9 --- /dev/null +++ b/DiztinGUIsh/window/VisualizerForm.cs @@ -0,0 +1,80 @@ +using System.Drawing; +using System.Windows.Forms; +using Diz.Core.model; + +namespace DiztinGUIsh.window +{ + public partial class VisualizerForm : Form + { + private readonly MainWindow mainWindow; + + public VisualizerForm(MainWindow window) + { + mainWindow = window; + InitializeComponent(); + } + + private Bitmap bitmap; + + private Color GetColorForFlag(Data.FlagType flag) + { + return flag switch + { + Data.FlagType.Unreached => Color.Black, + Data.FlagType.Opcode => Color.Yellow, + Data.FlagType.Operand => Color.YellowGreen, + Data.FlagType.Graphics => Color.LightPink, + Data.FlagType.Music => Color.PowderBlue, + Data.FlagType.Data8Bit => Color.NavajoWhite, + Data.FlagType.Data16Bit => Color.NavajoWhite, + Data.FlagType.Data24Bit => Color.NavajoWhite, + Data.FlagType.Data32Bit => Color.NavajoWhite, + Data.FlagType.Pointer16Bit => Color.Orchid, + Data.FlagType.Pointer24Bit => Color.Orchid, + Data.FlagType.Pointer32Bit => Color.Orchid, + Data.FlagType.Text => Color.Aquamarine, + Data.FlagType.Empty => Color.DarkSlateGray, + _ => Color.DarkSlateGray + }; + } + + void GenerateImage() + { + if (bitmap != null) + return; + + const int pixels_per_bank = 0xFFFF; + const int bank_height = 48; + const int bank_width = pixels_per_bank / bank_height; + + const int num_banks = 64; + + const int total_height = bank_height * num_banks; + const int total_width = bank_width; + + bitmap = new Bitmap(total_width, total_height); + + for (var y = 0; y < bitmap.Height; y++) + { + for (var x = 0; x < bitmap.Width; x++) + { + var romOffset = y * bank_width + x; + var romFlag = mainWindow.Project.Data.RomBytes[romOffset].TypeFlag; + var color = GetColorForFlag(romFlag); + bitmap.SetPixel(x, y, color); + } + } + } + + private void pictureBox1_Paint(object sender, PaintEventArgs e) + { + GenerateImage(); + e.Graphics.DrawImage(bitmap, 0, 0, bitmap.Width, bitmap.Height); + } + + private void VisualizerForm_Load(object sender, System.EventArgs e) + { + + } + } +} \ No newline at end of file diff --git a/DiztinGUIsh/window/VisualizerForm.resx b/DiztinGUIsh/window/VisualizerForm.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/DiztinGUIsh/window/VisualizerForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file From 26362b80d222acbcb4693c81350d0b6da248b7f8 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Thu, 22 Oct 2020 19:07:25 -0400 Subject: [PATCH 099/136] finishing out tuning tracelog capture --- Diz.Core/import/BSNESTraceLogCapture.cs | 48 +++++++++++++++++-- .../BSNESTraceLogBinaryMonitorForm.UI.cs | 9 +++- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/Diz.Core/import/BSNESTraceLogCapture.cs b/Diz.Core/import/BSNESTraceLogCapture.cs index 59922d13..394c45b4 100644 --- a/Diz.Core/import/BSNESTraceLogCapture.cs +++ b/Diz.Core/import/BSNESTraceLogCapture.cs @@ -88,14 +88,55 @@ private void ProcessStreamData(Stream networkStream) private async void ProcessCompressedWorkItem(BSNESImportStreamProcessor.CompressedWorkItems compressedItems) { - var subTasks = BSNESImportStreamProcessor.ProcessCompressedWorkItems(compressedItems) - .Select(workItem => taskManager.Run(() => { ProcessWorkItem(workItem); })) - .ToList(); + // tune this as needed. + // we want parallel jobs going, but, we don't want too many of them at once. + // average # workItems per CompressedWorkItem is like 12K currently. + const int numItemsPerTask = 6000; + + using var enumerator = BSNESImportStreamProcessor.ProcessCompressedWorkItems(compressedItems).GetEnumerator(); + + bool keepGoing; + var itemsRemainingBeforeSend = numItemsPerTask; + var subTasks = new List(); + var workItemsForThisTask = new List(); + + do + { + var endOfList = !enumerator.MoveNext(); + keepGoing = !streamProcessor.CancelToken.IsCancellationRequested && !endOfList; + + if (!endOfList) + { + workItemsForThisTask.Add(enumerator.Current); + itemsRemainingBeforeSend--; + } + + var shouldSendNow = !keepGoing || itemsRemainingBeforeSend == 0; + if (!shouldSendNow) + continue; + + var workItemsCopy = new List(workItemsForThisTask); + subTasks.Add(taskManager.Run(() => + { + ProcessWorkItems(workItemsCopy); + })); + + itemsRemainingBeforeSend = numItemsPerTask; + workItemsForThisTask.Clear(); + } while (keepGoing); await Task.WhenAll(subTasks); Stats_MarkCompleted(compressedItems); } + private void ProcessWorkItems(IEnumerable workItemsForThisTask) + { + foreach (var workItem in workItemsForThisTask) + { + ProcessWorkItem(workItem); + } + } + // this is just neat stats. it's optional, remove if performance becomes an issue (seems unlikely) private void States_MarkQueued(BSNESImportStreamProcessor.CompressedWorkItems compressedItems) { @@ -129,6 +170,7 @@ private void ProcessWorkItem(BSNESImportStreamProcessor.WorkItem workItem) { try { + // definitely hitting lock contention. importerLock.EnterWriteLock(); importer.ImportTraceLogLineBinary(workItem.Buffer, workItem.AbridgedFormat); } diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs index b06ce854..7f385e29 100644 --- a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs @@ -1,10 +1,11 @@ using System; -using System.Drawing; using System.Windows.Forms; +using System.Windows.Media; using ByteSizeLib; using Diz.Core.import; using LiveCharts; using LiveCharts.Wpf; +using Color = System.Drawing.Color; namespace DiztinGUIsh.window.dialog { @@ -12,11 +13,14 @@ public partial class BSNESTraceLogBinaryMonitorForm { private bool initializedChart; private readonly ChartValues chartValuesBytesModified = new ChartValues(); + private long chartValueBytesModified_previous = 0; private void AppendToChart((BSNESTraceLogImporter.Stats stats, int bytesInQueue) currentStats) { InitChart(); - chartValuesBytesModified.Add(currentStats.stats.numRomBytesModified); + var diffBytes = currentStats.stats.numRomBytesModified - chartValueBytesModified_previous; + chartValueBytesModified_previous = currentStats.stats.numRomBytesModified; + chartValuesBytesModified.Add(diffBytes); } private void InitChart() @@ -30,6 +34,7 @@ private void InitChart() { Title = "Instructions Modified", Values = chartValuesBytesModified, + PointGeometry = Geometry.Empty, }, }; From 72f80c0789ca7891a8913649efdf8b03076d3821 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Fri, 23 Oct 2020 12:15:54 -0400 Subject: [PATCH 100/136] better implementation of visualizer - use notifications - update in background --- Diz.Core/Diz.Core.csproj | 7 + Diz.Core/model/Data.Constants.cs | 111 +++++++++ Diz.Core/model/Data.Properties.cs | 80 +++++++ Diz.Core/model/Data.cs | 218 +++++------------- Diz.Core/model/ROMByte.cs | 98 ++++++-- Diz.Core/model/RomBytes.cs | 41 +++- Diz.Core/packages.config | 1 + Diz.Core/util/RomVisual.cs | 176 ++++++++++++++ Diz.Core/util/Util.cs | 52 ++++- DiztinGUIsh/DiztinGUIsh.csproj | 25 +- DiztinGUIsh/packages.config | 3 +- DiztinGUIsh/window/AliasList.Designer.cs | 36 +-- DiztinGUIsh/window/MainWindow.cs | 3 +- DiztinGUIsh/window/VisualizerForm.Designer.cs | 70 +++++- DiztinGUIsh/window/VisualizerForm.cs | 81 +++---- .../usercontrols/BankLegend.Designer.cs | 59 +++++ DiztinGUIsh/window/usercontrols/BankLegend.cs | 31 +++ .../window/usercontrols/BankLegend.resx | 120 ++++++++++ .../usercontrols/BankLegendItem.Designer.cs | 88 +++++++ .../window/usercontrols/BankLegendItem.cs | 16 ++ .../window/usercontrols/BankLegendItem.resx | 120 ++++++++++ 21 files changed, 1167 insertions(+), 269 deletions(-) create mode 100644 Diz.Core/model/Data.Constants.cs create mode 100644 Diz.Core/model/Data.Properties.cs create mode 100644 Diz.Core/util/RomVisual.cs create mode 100644 DiztinGUIsh/window/usercontrols/BankLegend.Designer.cs create mode 100644 DiztinGUIsh/window/usercontrols/BankLegend.cs create mode 100644 DiztinGUIsh/window/usercontrols/BankLegend.resx create mode 100644 DiztinGUIsh/window/usercontrols/BankLegendItem.Designer.cs create mode 100644 DiztinGUIsh/window/usercontrols/BankLegendItem.cs create mode 100644 DiztinGUIsh/window/usercontrols/BankLegendItem.resx diff --git a/Diz.Core/Diz.Core.csproj b/Diz.Core/Diz.Core.csproj index 5fdafe4e..0e76a919 100644 --- a/Diz.Core/Diz.Core.csproj +++ b/Diz.Core/Diz.Core.csproj @@ -35,6 +35,9 @@ ..\packages\ExtendedXmlSerializer.3.4.1\lib\net452\ExtendedXmlSerializer.dll + + ..\packages\FastBitmapLib.2.0.0\lib\net452\FastBitmapLib.dll + ..\packages\SharpZipLib.1.3.0\lib\net45\ICSharpCode.SharpZipLib.dll @@ -83,6 +86,7 @@
+ ..\packages\System.Interactive.4.1.1\lib\net45\System.Interactive.dll @@ -120,6 +124,9 @@ + + + diff --git a/Diz.Core/model/Data.Constants.cs b/Diz.Core/model/Data.Constants.cs new file mode 100644 index 00000000..06dd905f --- /dev/null +++ b/Diz.Core/model/Data.Constants.cs @@ -0,0 +1,111 @@ +using System; +using System.ComponentModel; +using System.Drawing; + +namespace Diz.Core.model +{ + public partial class Data + { + [System.AttributeUsage(System.AttributeTargets.All)] + public class ColorDescriptionAttribute : System.Attribute + { + public KnownColor Color { get; } + + public ColorDescriptionAttribute(KnownColor c) + { + Color = c; + } + } + + public enum FlagType : byte + { + [ColorDescription(KnownColor.Black)] Unreached = 0x00, + + [ColorDescription(KnownColor.Yellow)] Opcode = 0x10, + + [ColorDescription(KnownColor.YellowGreen)] + Operand = 0x11, + + [ColorDescription(KnownColor.NavajoWhite)] [Description("Data (8-bit)")] + Data8Bit = 0x20, + + [ColorDescription(KnownColor.LightPink)] + Graphics = 0x21, + + [ColorDescription(KnownColor.PowderBlue)] + Music = 0x22, + + [ColorDescription(KnownColor.DarkSlateGray)] + Empty = 0x23, + + [ColorDescription(KnownColor.NavajoWhite)] [Description("Data (16-bit)")] + Data16Bit = 0x30, + + [ColorDescription(KnownColor.Orchid)] [Description("Pointer (16-bit)")] + Pointer16Bit = 0x31, + + [ColorDescription(KnownColor.NavajoWhite)] [Description("Data (24-bit)")] + Data24Bit = 0x40, + + [ColorDescription(KnownColor.Orchid)] [Description("Pointer (24-bit)")] + Pointer24Bit = 0x41, + + [ColorDescription(KnownColor.NavajoWhite)] [Description("Data (32-bit)")] + Data32Bit = 0x50, + + [ColorDescription(KnownColor.Orchid)] [Description("Pointer (32-bit)")] + Pointer32Bit = 0x51, + + [ColorDescription(KnownColor.Aquamarine)] + Text = 0x60 + } + + public enum Architecture : byte + { + [Description("65C816")] CPU65C816 = 0x00, + [Description("SPC700")] APUSPC700 = 0x01, + [Description("SuperFX")] GPUSuperFX = 0x02 + } + + [Flags] + public enum InOutPoint : byte + { + InPoint = 0x01, + OutPoint = 0x02, + EndPoint = 0x04, + ReadPoint = 0x08 + } + + public enum ROMMapMode : byte + { + LoROM, + + HiROM, + + ExHiROM, + + [Description("SA - 1 ROM")] SA1ROM, + + [Description("SA-1 ROM (FuSoYa's 8MB mapper)")] + ExSA1ROM, + + SuperFX, + + [Description("Super MMC")] SuperMMC, + + ExLoROM + } + + public enum ROMSpeed : byte + { + SlowROM, + FastROM, + Unknown + } + + public const int LOROM_SETTING_OFFSET = 0x7FD5; + public const int HIROM_SETTING_OFFSET = 0xFFD5; + public const int EXHIROM_SETTING_OFFSET = 0x40FFD5; + public const int EXLOROM_SETTING_OFFSET = 0x407FD5; + } +} \ No newline at end of file diff --git a/Diz.Core/model/Data.Properties.cs b/Diz.Core/model/Data.Properties.cs new file mode 100644 index 00000000..478bf047 --- /dev/null +++ b/Diz.Core/model/Data.Properties.cs @@ -0,0 +1,80 @@ +using System.Linq; +using Diz.Core.arch; +using IX.Observable; + +namespace Diz.Core.model +{ + public partial class Data + { + // don't modify these directly, always go through the public properties so + // other objects can subscribe to modification notifications + private ROMMapMode romMapMode; + private ROMSpeed romSpeed = ROMSpeed.Unknown; + private ObservableDictionary comments = new ObservableDictionary(); + private ObservableDictionary labels = new ObservableDictionary(); + private RomBytes romBytes = new RomBytes(); + + // Note: order of these public properties matters for the load/save process. Keep 'RomBytes' LAST + // TODO: should be a way in the XML serializer to control the order, remove this comment + // when we figure it out. + public ROMMapMode RomMapMode + { + get => romMapMode; + set => SetField(ref romMapMode, value); + } + + public ROMSpeed RomSpeed + { + get => romSpeed; + set => SetField(ref romSpeed, value); + } + + // next 2 dictionaries store in SNES address format (since memory labels can't be represented as a PC address) + public ObservableDictionary Comments + { + get => comments; + set => SetField(ref comments, value); + } + + public ObservableDictionary Labels + { + get => labels; + set => SetField(ref labels, value); + } + + // RomBytes stored as PC file offset addresses (since ROM will always be mapped to disk) + public RomBytes RomBytes + { + get => romBytes; + set => SetField(ref romBytes, value); + } + + + #region Equality + protected bool Equals(Data other) + { + return Labels.SequenceEqual(other.Labels) && RomMapMode == other.RomMapMode && RomSpeed == other.RomSpeed && Comments.SequenceEqual(other.Comments) && RomBytes.Equals(other.RomBytes); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + return obj.GetType() == this.GetType() && Equals((Data)obj); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = Labels.GetHashCode(); + hashCode = (hashCode * 397) ^ (int)RomMapMode; + hashCode = (hashCode * 397) ^ (int)RomSpeed; + hashCode = (hashCode * 397) ^ Comments.GetHashCode(); + hashCode = (hashCode * 397) ^ RomBytes.GetHashCode(); + return hashCode; + } + } + #endregion + } +} \ No newline at end of file diff --git a/Diz.Core/model/Data.cs b/Diz.Core/model/Data.cs index ae7b39ce..c47668a4 100644 --- a/Diz.Core/model/Data.cs +++ b/Diz.Core/model/Data.cs @@ -1,105 +1,19 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; +using System.Collections.Generic; using System.Diagnostics; -using System.Linq; using System.Text; using Diz.Core.arch; using Diz.Core.util; -using IX.Observable; +using DiztinGUIsh; namespace Diz.Core.model { - public class Data + public partial class Data : DizDataModel { - public enum FlagType : byte - { - Unreached = 0x00, - Opcode = 0x10, - Operand = 0x11, - [Description("Data (8-bit)")] Data8Bit = 0x20, - Graphics = 0x21, - Music = 0x22, - Empty = 0x23, - [Description("Data (16-bit)")] Data16Bit = 0x30, - [Description("Pointer (16-bit)")] Pointer16Bit = 0x31, - [Description("Data (24-bit)")] Data24Bit = 0x40, - [Description("Pointer (24-bit)")] Pointer24Bit = 0x41, - [Description("Data (32-bit)")] Data32Bit = 0x50, - [Description("Pointer (32-bit)")] Pointer32Bit = 0x51, - Text = 0x60 - } - - public enum Architecture : byte - { - [Description("65C816")] - CPU65C816 = 0x00, - [Description("SPC700")] - APUSPC700 = 0x01, - [Description("SuperFX")] - GPUSuperFX = 0x02 - } - - [Flags] - public enum InOutPoint : byte - { - InPoint = 0x01, - OutPoint = 0x02, - EndPoint = 0x04, - ReadPoint = 0x08 - } - - public enum ROMMapMode : byte - { - LoROM, - - HiROM, - - ExHiROM, - - [Description("SA - 1 ROM")] - SA1ROM, - - [Description("SA-1 ROM (FuSoYa's 8MB mapper)")] - ExSA1ROM, - - SuperFX, - - [Description("Super MMC")] - SuperMMC, - - ExLoROM - } - - public enum ROMSpeed : byte - { - SlowROM, FastROM, Unknown - } - - public const int - LOROM_SETTING_OFFSET = 0x7FD5, - HIROM_SETTING_OFFSET = 0xFFD5, - EXHIROM_SETTING_OFFSET = 0x40FFD5, - EXLOROM_SETTING_OFFSET = 0x407FD5; - - // Note: order of these properties matters for the load/save process. Keep 'RomBytes' LAST - // TODO: should be a way in the XML serializer to control the order, remove this comment - // when we figure it out. - public ROMMapMode RomMapMode { get; set; } - public ROMSpeed RomSpeed { get; set; } - - // dictionaries store in SNES address format (since memory labels can't be represented as a PC address) - public ObservableDictionary Comments { get; set; } = new ObservableDictionary(); - public ObservableDictionary Labels { get; set; } = new ObservableDictionary(); - - // RomBytes stored as PC file offset addresses (since ROM will always be mapped to disk) - public RomBytes RomBytes { get; set; } = new RomBytes(); - - private CPU65C816 CPU65C816 { get; set; } + private readonly CPU65C816 cpu65C816; // TODO: this really shouldn't be in Data, move to an outside 'SNESSystem' class or something public Data() { - CPU65C816 = new CPU65C816(this); + cpu65C816 = new CPU65C816(this); } public void CreateRomBytesFromRom(IEnumerable actualRomBytes) @@ -155,9 +69,9 @@ public void CopyRomDataIn(byte[] data) public void SetInOutPoint(int i, InOutPoint point) => RomBytes[i].Point |= point; public void ClearInOutPoint(int i) => RomBytes[i].Point = 0; public int GetDataBank(int i) => RomBytes[i].DataBank; - public void SetDataBank(int i, int dbank) => RomBytes[i].DataBank = (byte)dbank; + public void SetDataBank(int i, int dBank) => RomBytes[i].DataBank = (byte)dBank; public int GetDirectPage(int i) => RomBytes[i].DirectPage; - public void SetDirectPage(int i, int dpage) => RomBytes[i].DirectPage = 0xFFFF & dpage; + public void SetDirectPage(int i, int dPage) => RomBytes[i].DirectPage = 0xFFFF & dPage; public bool GetXFlag(int i) => RomBytes[i].XFlag; public void SetXFlag(int i, bool x) => RomBytes[i].XFlag = x; public bool GetMFlag(int i) => RomBytes[i].MFlag; @@ -255,26 +169,31 @@ public int GetIntermediateAddressOrPointer(int offset) { switch (GetFlag(offset)) { - case Data.FlagType.Unreached: - case Data.FlagType.Opcode: + case FlagType.Unreached: + case FlagType.Opcode: return GetIntermediateAddress(offset, true); - case Data.FlagType.Pointer16Bit: + case FlagType.Pointer16Bit: int bank = GetDataBank(offset); return (bank << 16) | GetROMWord(offset); - case Data.FlagType.Pointer24Bit: - case Data.FlagType.Pointer32Bit: + case FlagType.Pointer24Bit: + case FlagType.Pointer32Bit: return GetROMLong(offset); } return -1; } + public int GetBankSize() + { + return RomUtil.GetBankSize(RomMapMode); + } + public int OpcodeByteLength(int offset) { return GetArchitecture(offset) switch { - Data.Architecture.CPU65C816 => CPU65C816.GetInstructionLength(offset), - Data.Architecture.APUSPC700 => 1, - Data.Architecture.GPUSuperFX => 1, + Architecture.CPU65C816 => cpu65C816.GetInstructionLength(offset), + Architecture.APUSPC700 => 1, + Architecture.GPUSuperFX => 1, _ => 1 }; } @@ -318,7 +237,7 @@ public int ConvertSNEStoPC(int address) public string GetPointer(int offset, int bytes) { - int ia = -1; + var ia = -1; string format = "", param = ""; switch (bytes) { @@ -340,15 +259,15 @@ public string GetPointer(int offset, int bytes) break; } - int pc = ConvertSNEStoPC(ia); + var pc = ConvertSNEStoPC(ia); if (pc >= 0 && GetLabelName(ia) != "") param = GetLabelName(ia); return string.Format(format, param); } public string GetFormattedText(int offset, int bytes) { - string text = "db \""; - for (int i = 0; i < bytes; i++) text += (char)GetROMByte(offset + i); + var text = "db \""; + for (var i = 0; i < bytes; i++) text += (char)GetROMByte(offset + i); return text + "\""; } @@ -364,16 +283,16 @@ public int Step(int offset, bool branch, bool force, int prevOffset) { return GetArchitecture(offset) switch { - Data.Architecture.CPU65C816 => CPU65C816.Step(offset, branch, force, prevOffset), - Data.Architecture.APUSPC700 => offset, - Data.Architecture.GPUSuperFX => offset, + Architecture.CPU65C816 => cpu65C816.Step(offset, branch, force, prevOffset), + Architecture.APUSPC700 => offset, + Architecture.GPUSuperFX => offset, _ => offset }; } public int AutoStep(int offset, bool harsh, int amount) { - int newOffset = offset, prevOffset = offset - 1, nextOffset = offset; + int newOffset = offset, prevOffset = offset - 1, nextOffset; if (harsh) { while (newOffset < offset + amount) @@ -393,17 +312,17 @@ public int AutoStep(int offset, bool harsh, int amount) { switch (GetArchitecture(newOffset)) { - case Data.Architecture.CPU65C816: + case Architecture.CPU65C816: if (seenBranches.Contains(newOffset)) { keepGoing = false; break; } - int opcode = GetROMByte(newOffset); + var opcode = GetROMByte(newOffset); nextOffset = Step(newOffset, false, false, prevOffset); - int jumpOffset = Step(newOffset, true, false, prevOffset); + var jumpOffset = Step(newOffset, true, false, prevOffset); if (opcode == 0x40 || opcode == 0xCB || opcode == 0xDB || opcode == 0xF8 // RTI WAI STP SED || opcode == 0xFB || opcode == 0x00 || opcode == 0x02 || opcode == 0x42 // XCE BRK COP WDM @@ -456,8 +375,8 @@ public int AutoStep(int offset, bool harsh, int amount) newOffset = nextOffset; } break; - case Data.Architecture.APUSPC700: - case Data.Architecture.GPUSuperFX: + case Architecture.APUSPC700: + case Architecture.GPUSuperFX: nextOffset = Step(newOffset, false, true, prevOffset); prevOffset = newOffset; newOffset = nextOffset; @@ -465,13 +384,13 @@ public int AutoStep(int offset, bool harsh, int amount) } var flag = GetFlag(newOffset); - if (!(flag == Data.FlagType.Unreached || flag == Data.FlagType.Opcode || flag == Data.FlagType.Operand)) keepGoing = false; + if (!(flag == FlagType.Unreached || flag == FlagType.Opcode || flag == FlagType.Operand)) keepGoing = false; } } return newOffset; } - public int Mark(int offset, Data.FlagType type, int count) + public int Mark(int offset, FlagType type, int count) { int i, size = GetROMSize(); for (i = 0; i < count && offset + i < size; i++) SetFlag(offset + i, type); @@ -506,7 +425,7 @@ public int MarkMFlag(int offset, bool m, int count) return offset + i < size ? offset + i : size - 1; } - public int MarkArchitechture(int offset, Data.Architecture arch, int count) + public int MarkArchitechture(int offset, Architecture arch, int count) { int i, size = GetROMSize(); for (i = 0; i < count && offset + i < size; i++) SetArchitechture(offset + i, arch); @@ -517,9 +436,9 @@ public int GetInstructionLength(int offset) { return GetArchitecture(offset) switch { - Data.Architecture.CPU65C816 => CPU65C816.GetInstructionLength(offset), - Data.Architecture.APUSPC700 => 1, - Data.Architecture.GPUSuperFX => 1, + Architecture.CPU65C816 => cpu65C816.GetInstructionLength(offset), + Architecture.APUSPC700 => 1, + Architecture.GPUSuperFX => 1, _ => 1 }; } @@ -539,17 +458,17 @@ public int FixMisalignedFlags() int len = GetInstructionLength(i); for (var j = 1; j < len && i + j < size; j++) { - if (GetFlag(i + j) != Data.FlagType.Operand) + if (GetFlag(i + j) != FlagType.Operand) { - SetFlag(i + j, Data.FlagType.Operand); + SetFlag(i + j, FlagType.Operand); count++; } } i += len - 1; break; } - case Data.FlagType.Operand: - SetFlag(i, Data.FlagType.Opcode); + case FlagType.Operand: + SetFlag(i, FlagType.Opcode); count++; i--; break; @@ -578,17 +497,17 @@ public int FixMisalignedFlags() public void RescanInOutPoints() { - for (int i = 0; i < GetROMSize(); i++) ClearInOutPoint(i); + for (var i = 0; i < GetROMSize(); i++) ClearInOutPoint(i); - for (int i = 0; i < GetROMSize(); i++) + for (var i = 0; i < GetROMSize(); i++) { - if (GetFlag(i) == Data.FlagType.Opcode) + if (GetFlag(i) == FlagType.Opcode) { switch (GetArchitecture(i)) { - case Data.Architecture.CPU65C816: CPU65C816.MarkInOutPoints(i); break; - case Data.Architecture.APUSPC700: break; - case Data.Architecture.GPUSuperFX: break; + case Architecture.CPU65C816: cpu65C816.MarkInOutPoints(i); break; + case Architecture.APUSPC700: break; + case Architecture.GPUSuperFX: break; } } } @@ -599,9 +518,9 @@ public int GetIntermediateAddress(int offset, bool resolve = false) // FIX ME: log and generation of dp opcodes. search references return GetArchitecture(offset) switch { - Data.Architecture.CPU65C816 => CPU65C816.GetIntermediateAddress(offset, resolve), - Data.Architecture.APUSPC700 => -1, - Data.Architecture.GPUSuperFX => -1, + Architecture.CPU65C816 => cpu65C816.GetIntermediateAddress(offset, resolve), + Architecture.APUSPC700 => -1, + Architecture.GPUSuperFX => -1, _ => -1 }; } @@ -610,39 +529,16 @@ public string GetInstruction(int offset) { return GetArchitecture(offset) switch { - Data.Architecture.CPU65C816 => CPU65C816.GetInstruction(offset), - Data.Architecture.APUSPC700 => "", - Data.Architecture.GPUSuperFX => "", + Architecture.CPU65C816 => cpu65C816.GetInstruction(offset), + Architecture.APUSPC700 => "", + Architecture.GPUSuperFX => "", _ => "" }; } - #region Equality - protected bool Equals(Data other) + public int GetNumberOfBanks() { - return Labels.SequenceEqual(other.Labels) && RomMapMode == other.RomMapMode && RomSpeed == other.RomSpeed && Comments.SequenceEqual(other.Comments) && RomBytes.Equals(other.RomBytes); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((Data)obj); - } - - public override int GetHashCode() - { - unchecked - { - var hashCode = Labels.GetHashCode(); - hashCode = (hashCode * 397) ^ (int)RomMapMode; - hashCode = (hashCode * 397) ^ (int)RomSpeed; - hashCode = (hashCode * 397) ^ Comments.GetHashCode(); - hashCode = (hashCode * 397) ^ RomBytes.GetHashCode(); - return hashCode; - } + return RomBytes.Count / GetBankSize(); } - #endregion } } diff --git a/Diz.Core/model/ROMByte.cs b/Diz.Core/model/ROMByte.cs index 737a40ca..9483b6c4 100644 --- a/Diz.Core/model/ROMByte.cs +++ b/Diz.Core/model/ROMByte.cs @@ -1,7 +1,81 @@ -namespace Diz.Core.model +using System.ComponentModel; +using DiztinGUIsh; + +namespace Diz.Core.model { - public class ROMByte + public class ROMByte : DizDataModel { + // never modify directly. only go through the public fields + private byte rom; + private byte dataBank; + private int directPage; + private bool xFlag; + private bool mFlag; + private Data.FlagType typeFlag = Data.FlagType.Unreached; + private Data.Architecture arch = Data.Architecture.CPU65C816; + private Data.InOutPoint point = 0; + + // holds the original byte from the source ROM + public byte Rom + { + get => rom; + set => SetField(ref rom, value); + } // never serialize this, read from ROM on load. (for copyright reasons) + + // everything else is metadata that describes the source byte above + public byte DataBank + { + get => dataBank; + set => SetField(ref dataBank, value); + } + + public int DirectPage + { + get => directPage; + set => SetField(ref directPage, value); + } + + public bool XFlag + { + get => xFlag; + set => SetField(ref xFlag, value); + } + + public bool MFlag + { + get => mFlag; + set => SetField(ref mFlag, value); + } + + public Data.FlagType TypeFlag + { + get => typeFlag; + set => SetField(ref typeFlag, value); + } + + public Data.Architecture Arch + { + get => arch; + set => SetField(ref arch, value); + } + + public Data.InOutPoint Point + { + get => point; + set => SetField(ref point, value); + } + + // don't serialize. cached copy of our offset in parent collection + public int Offset { get; private set; } = -1; + + public void SetCachedOffset(int offset) + { + // not in love with this or that we're caching it. would be cool if we didn't + // need Offset, or could just derive this (quickly) from the base list. + Offset = offset; + } + + #region Equality protected bool Equals(ROMByte other) { @@ -17,7 +91,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == this.GetType() && Equals((ROMByte) obj); + return obj.GetType() == this.GetType() && Equals((ROMByte)obj); } public override int GetHashCode() @@ -29,24 +103,12 @@ public override int GetHashCode() hashCode = (hashCode * 397) ^ DirectPage; hashCode = (hashCode * 397) ^ XFlag.GetHashCode(); hashCode = (hashCode * 397) ^ MFlag.GetHashCode(); - hashCode = (hashCode * 397) ^ (int) TypeFlag; - hashCode = (hashCode * 397) ^ (int) Arch; - hashCode = (hashCode * 397) ^ (int) Point; + hashCode = (hashCode * 397) ^ (int)TypeFlag; + hashCode = (hashCode * 397) ^ (int)Arch; + hashCode = (hashCode * 397) ^ (int)Point; return hashCode; } } #endregion - - // holds the original byte from the source ROM - public byte Rom { get; set; } // never serialize this, read from ROM on load. (for copyright reasons) - - // everything else is metadata that describes the source byte above - public byte DataBank { get; set; } - public int DirectPage { get; set; } - public bool XFlag { get; set; } - public bool MFlag { get; set; } - public Data.FlagType TypeFlag { get; set; } = Data.FlagType.Unreached; - public Data.Architecture Arch { get; set; } = Data.Architecture.CPU65C816; - public Data.InOutPoint Point { get; set; } = 0; } } diff --git a/Diz.Core/model/RomBytes.cs b/Diz.Core/model/RomBytes.cs index 5911e632..fb80115b 100644 --- a/Diz.Core/model/RomBytes.cs +++ b/Diz.Core/model/RomBytes.cs @@ -1,29 +1,37 @@ -using System; -using System.Collections; +using System.Collections; using System.Collections.Generic; -using System.IO; +using System.Collections.Specialized; +using System.ComponentModel; using System.Linq; +using IX.Observable; namespace Diz.Core.model { - public class RomBytes : IEnumerable + public class RomBytes : IEnumerable, INotifyCollectionChanged, INotifyPropertyChanged { // TODO: might be able to do something more generic now that other refactorings are completed. // // This class needs to do these things that are special: // 1) Be handled specially by our custom XML serializer (compresses to save disk space) // 2) Handle Equals() by comparing each element in the list (SequenceEqual) - public List Bytes { get; } = new List(); + public ObservableList Bytes { get; } = new ObservableList(); public ROMByte this[int i] { get => Bytes[i]; set => Bytes[i] = value; } - + + public RomBytes() + { + Bytes.PropertyChanged += Bytes_PropertyChanged; + Bytes.CollectionChanged += Bytes_CollectionChanged; + } + public int Count => Bytes.Count; public void Add(ROMByte romByte) { Bytes.Add(romByte); + romByte.SetCachedOffset(Bytes.Count - 1); // I don't love this.... } public void Create(int size) @@ -67,5 +75,26 @@ IEnumerator IEnumerable.GetEnumerator() return GetEnumerator(); } #endregion + + public event NotifyCollectionChangedEventHandler CollectionChanged; + public event PropertyChangedEventHandler PropertyChanged; + + private void Bytes_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (e.NewItems != null) + foreach (ROMByte item in e.NewItems) + item.PropertyChanged += Bytes_PropertyChanged; + + if (e.OldItems != null) + foreach (ROMByte item in e.OldItems) + item.PropertyChanged -= Bytes_PropertyChanged; + + CollectionChanged?.Invoke(sender, e); + } + + private void Bytes_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + PropertyChanged?.Invoke(sender, e); + } } } diff --git a/Diz.Core/packages.config b/Diz.Core/packages.config index 8d81d458..0181b34a 100644 --- a/Diz.Core/packages.config +++ b/Diz.Core/packages.config @@ -1,6 +1,7 @@  + diff --git a/Diz.Core/util/RomVisual.cs b/Diz.Core/util/RomVisual.cs new file mode 100644 index 00000000..1418f982 --- /dev/null +++ b/Diz.Core/util/RomVisual.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using System.Security.AccessControl; +using Diz.Core.model; +using FastBitmapLib; + +namespace Diz.Core.util +{ + public class RomVisual + { + public bool AutoRefresh { get; set; } = true; + + public Data Data => Project?.Data; + + public event EventHandler ImageDataUpdated; + public event EventHandler MarkedDirty; + + public Bitmap Bitmap + { + get + { + Refresh(); + return bitmap; + } + } + + public int PixelsPerBank => Data.GetBankSize(); + + public int BankHeightPixels + { + get => bankHeightPixels; + set + { + ValidateHeight(value); + bankHeightPixels = value; + } + } + + public int BankWidthPixels + { + get + { + ValidateHeight(BankHeightPixels); + return PixelsPerBank / BankHeightPixels; + } + } + + public void ValidateHeight(int heightPixels) + { + if (PixelsPerBank % heightPixels != 0) + throw new ArgumentException("Selected Bank Height doesn't evenly divide. (pick a height that's a power of 2)"); + } + + public Project Project + { + get => project; + set + { + if (ReferenceEquals(project, value)) return; + project = value; + if (project?.Data == null) return; + project.Data.RomBytes.PropertyChanged += RomBytes_PropertyChanged; + project.Data.RomBytes.CollectionChanged += RomBytes_CollectionChanged; + InvalidateImage(); + } + } + + private Bitmap bitmap; + private Project project; + + private void RomBytes_CollectionChanged(object sender, + System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + AllDirty = true; + } + + public bool AllDirty { get; set; } = true; + public Dictionary DirtyRomBytes = new Dictionary(); + private int bankHeightPixels = 64; + + public bool NeedsUpdate => + AllDirty || + (AutoRefresh && DirtyRomBytes.Count > 0); + + private void RomBytes_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (!(sender is ROMByte romByte)) + return; + + if (e.PropertyName != "TypeFlag") + return; + + MarkDirty(romByte); + } + + private void InvalidateImage() + { + bitmap = null; + AllDirty = true; + DirtyRomBytes.Clear(); + RegenerateImage(); + } + + public void Refresh() + { + if (bitmap == null || NeedsUpdate) + RegenerateImage(); + } + + private void RegenerateImage() + { + if (Data == null) + { + bitmap = null; + return; + } + + var totalHeight = BankHeightPixels * Data.GetNumberOfBanks(); + var totalWidth = BankWidthPixels; + + // requires use of the /unsafe compiler flag, because we're manipulating memory directly. + // needed because the system bitmap SetPixel() operation is super-slow. + var shouldRecreate = bitmap == null || + bitmap.Width != totalWidth || + bitmap.Height != totalHeight; + + if (shouldRecreate) + bitmap = new Bitmap(totalWidth, totalHeight); + + var romBytes = AllDirty ? + Data.RomBytes.ToList() : + DirtyRomBytes.Values.Select(kvp => kvp); + + var fastBitmap = new FastBitmap(bitmap); + using (fastBitmap.Lock()) + { + foreach (var romByte in romBytes) + { + SetPixel(romByte, fastBitmap, totalWidth); + } + } + + DirtyRomBytes.Clear(); + AllDirty = false; + + OnBitmapUpdated(); + } + + private static void SetPixel(ROMByte romByte, FastBitmap fastBitmap, int bankWidthPixels) + { + var romOffset = romByte.Offset; + var y = romOffset / bankWidthPixels; + var x = romOffset - (y * bankWidthPixels); + var color = Util.GetColorFromFlag(romByte.TypeFlag); + fastBitmap.SetPixel(x, y, color); + } + + protected virtual void OnBitmapUpdated() + { + ImageDataUpdated?.Invoke(this, EventArgs.Empty); + } + + protected virtual void MarkDirty(ROMByte romByte) + { + if (!DirtyRomBytes.ContainsKey(romByte.Offset)) + DirtyRomBytes.Add(romByte.Offset, romByte); + else + DirtyRomBytes[romByte.Offset] = romByte; + + MarkedDirty?.Invoke(this, EventArgs.Empty); + } + } +} \ No newline at end of file diff --git a/Diz.Core/util/Util.cs b/Diz.Core/util/Util.cs index 71afd8ce..72ed99a6 100644 --- a/Diz.Core/util/Util.cs +++ b/Diz.Core/util/Util.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Drawing; using System.IO; using System.IO.Compression; using System.Linq; using System.Text; +using Diz.Core.model; namespace Diz.Core.util { @@ -118,26 +120,66 @@ public static string GetEnumDescription(Enum value) // value = ExSA1ROM (one particular entry from the enum) // description = "SA-1 ROM (FuSoYa's 8MB mapper)", (contents of [Description] attribute) + return GetEnumAttribute( + value, + (DescriptionAttribute d) => d?.Description + ) ?? value.ToString(); + } + + public static TResult GetEnumAttribute(Enum value, Func getValueFn) where TAttribute : Attribute + { var type = value.GetType(); var memberInfo = type.GetField(value.ToString()); - var descAttr = (Attribute.GetCustomAttribute(memberInfo, typeof(DescriptionAttribute)) as DescriptionAttribute); - var name = descAttr?.Description ?? value.ToString(); - return name; + var descAttr = ((TAttribute)Attribute.GetCustomAttribute(memberInfo, typeof(TAttribute))); + return getValueFn(descAttr); } - // take a enum type that has [Description] attributes, // return a List with with kvp pairs of enum vs description public static List> GetEnumDescriptions() where TEnum : Enum + { + return GetEnumInfo((value) => GetEnumDescription(value)); + } + + // perf: might be a little slow, caution when in tight loops + public static List> GetEnumColorDescriptions() where TEnum : Enum + { + return GetEnumInfo((value) => GetEnumColor(value)); + } + + private static KnownColor GetEnumColor(Enum value) + { + return GetEnumAttribute( + value, + (Data.ColorDescriptionAttribute d) => d?.Color + ) ?? KnownColor.Black; + } + + public static List> GetEnumInfo(Func getValue) where TEnum : Enum { var type = typeof(TEnum); return Enum.GetValues(type) .Cast() .Select(value => new - KeyValuePair(key: value, value: GetEnumDescription(value)) + KeyValuePair(key: value, value: getValue(value)) ) .OrderBy(item => item.Key) .ToList(); } + + // sadly, this entire conversion is a bit slow so, cache it as we look it up + private static readonly Dictionary CachedROMFlagColors = + new Dictionary(); + + public static Color GetColorFromFlag(Data.FlagType romFlag) + { + if (CachedROMFlagColors.TryGetValue(romFlag, out var color)) + return color; + + color = Color.FromKnownColor(GetEnumColor(romFlag)); // slow (comparatively) + CachedROMFlagColors[romFlag] = color; + + return color; + } } } diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 8db72dc1..1722f3c6 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -75,6 +75,9 @@ ..\packages\ByteSize.2.0.0\lib\net45\ByteSize.dll + + ..\packages\FastBitmapLib.2.0.0\lib\net452\FastBitmapLib.dll + ..\packages\SharpZipLib.1.3.0\lib\net45\ICSharpCode.SharpZipLib.dll @@ -105,8 +108,8 @@ ..\packages\JetBrains.Annotations.2020.1.0\lib\net20\JetBrains.Annotations.dll - - ..\packages\LightInject.6.3.5\lib\net46\LightInject.dll + + ..\packages\LightInject.6.4.0\lib\net46\LightInject.dll ..\packages\LiveCharts.0.9.7\lib\net45\LiveCharts.dll @@ -224,6 +227,18 @@ AliasList.cs + + UserControl + + + BankLegend.cs + + + UserControl + + + BankLegendItem.cs + Form @@ -277,6 +292,12 @@ InOutPointChecker.cs + + BankLegend.cs + + + BankLegendItem.cs + VisualizerForm.cs diff --git a/DiztinGUIsh/packages.config b/DiztinGUIsh/packages.config index 175d1a47..d3ec5c74 100644 --- a/DiztinGUIsh/packages.config +++ b/DiztinGUIsh/packages.config @@ -1,6 +1,7 @@  + @@ -11,7 +12,7 @@ - + diff --git a/DiztinGUIsh/window/AliasList.Designer.cs b/DiztinGUIsh/window/AliasList.Designer.cs index 7068e2a2..d147267e 100644 --- a/DiztinGUIsh/window/AliasList.Designer.cs +++ b/DiztinGUIsh/window/AliasList.Designer.cs @@ -28,10 +28,10 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle8 = new System.Windows.Forms.DataGridViewCellStyle(); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle5 = new System.Windows.Forms.DataGridViewCellStyle(); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle6 = new System.Windows.Forms.DataGridViewCellStyle(); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle7 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle4 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle(); this.dataGridView1 = new System.Windows.Forms.DataGridView(); this.Address = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.Alias = new System.Windows.Forms.DataGridViewTextBoxColumn(); @@ -59,14 +59,14 @@ private void InitializeComponent() this.Address, this.Alias, this.Comment}); - dataGridViewCellStyle8.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle8.BackColor = System.Drawing.SystemColors.Window; - dataGridViewCellStyle8.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - dataGridViewCellStyle8.ForeColor = System.Drawing.SystemColors.ControlText; - dataGridViewCellStyle8.SelectionBackColor = System.Drawing.Color.CornflowerBlue; - dataGridViewCellStyle8.SelectionForeColor = System.Drawing.SystemColors.HighlightText; - dataGridViewCellStyle8.WrapMode = System.Windows.Forms.DataGridViewTriState.False; - this.dataGridView1.DefaultCellStyle = dataGridViewCellStyle8; + dataGridViewCellStyle4.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle4.BackColor = System.Drawing.SystemColors.Window; + dataGridViewCellStyle4.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + dataGridViewCellStyle4.ForeColor = System.Drawing.SystemColors.ControlText; + dataGridViewCellStyle4.SelectionBackColor = System.Drawing.Color.CornflowerBlue; + dataGridViewCellStyle4.SelectionForeColor = System.Drawing.SystemColors.HighlightText; + dataGridViewCellStyle4.WrapMode = System.Windows.Forms.DataGridViewTriState.False; + this.dataGridView1.DefaultCellStyle = dataGridViewCellStyle4; this.dataGridView1.Location = new System.Drawing.Point(0, 29); this.dataGridView1.Margin = new System.Windows.Forms.Padding(0); this.dataGridView1.Name = "dataGridView1"; @@ -89,8 +89,8 @@ private void InitializeComponent() // // Address // - dataGridViewCellStyle5.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.Address.DefaultCellStyle = dataGridViewCellStyle5; + dataGridViewCellStyle1.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Address.DefaultCellStyle = dataGridViewCellStyle1; this.Address.HeaderText = "PC"; this.Address.MaxInputLength = 6; this.Address.Name = "Address"; @@ -98,8 +98,8 @@ private void InitializeComponent() // // Alias // - dataGridViewCellStyle6.Font = new System.Drawing.Font("Arial Narrow", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.Alias.DefaultCellStyle = dataGridViewCellStyle6; + dataGridViewCellStyle2.Font = new System.Drawing.Font("Arial Narrow", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Alias.DefaultCellStyle = dataGridViewCellStyle2; this.Alias.HeaderText = "Label"; this.Alias.MaxInputLength = 60; this.Alias.Name = "Alias"; @@ -107,8 +107,8 @@ private void InitializeComponent() // // Comment // - dataGridViewCellStyle7.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.Comment.DefaultCellStyle = dataGridViewCellStyle7; + dataGridViewCellStyle3.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Comment.DefaultCellStyle = dataGridViewCellStyle3; this.Comment.HeaderText = "Comment"; this.Comment.MaxInputLength = 800; this.Comment.Name = "Comment"; diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 5385ab05..70ac9ba4 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -2,7 +2,6 @@ using System.Globalization; using System.IO; using System.Windows.Forms; -using System.Windows.Media; using Diz.Core.export; using Diz.Core.model; using Diz.Core.util; @@ -92,6 +91,7 @@ private void MainWindow_Load(object sender, EventArgs e) new object[] { true }); aliasList = new AliasList(this); + visualForm = new VisualizerForm(this); UpdatePanels(); UpdateUIFromSettings(); @@ -884,7 +884,6 @@ private void GoToUnreached(bool end, bool direction) private void visualMapToolStripMenuItem_Click(object sender, EventArgs e) { - visualForm ??= new VisualizerForm(this); visualForm.Show(); } diff --git a/DiztinGUIsh/window/VisualizerForm.Designer.cs b/DiztinGUIsh/window/VisualizerForm.Designer.cs index 450776eb..45efa576 100644 --- a/DiztinGUIsh/window/VisualizerForm.Designer.cs +++ b/DiztinGUIsh/window/VisualizerForm.Designer.cs @@ -29,36 +29,96 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.panelTop = new System.Windows.Forms.Panel(); + this.panelLegend = new System.Windows.Forms.Panel(); + this.bankLegend1 = new DiztinGUIsh.window.usercontrols.BankLegend(); + this.panelBottom = new System.Windows.Forms.Panel(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.panelTop.SuspendLayout(); + this.panelLegend.SuspendLayout(); + this.panelBottom.SuspendLayout(); this.SuspendLayout(); // // pictureBox1 // - this.pictureBox1.Dock = System.Windows.Forms.DockStyle.Fill; + this.pictureBox1.Cursor = System.Windows.Forms.Cursors.Cross; this.pictureBox1.Location = new System.Drawing.Point(0, 0); this.pictureBox1.Name = "pictureBox1"; - this.pictureBox1.Size = new System.Drawing.Size(1189, 553); - this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.pictureBox1.Size = new System.Drawing.Size(865, 562); + this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize; this.pictureBox1.TabIndex = 0; this.pictureBox1.TabStop = false; this.pictureBox1.Paint += new System.Windows.Forms.PaintEventHandler(this.pictureBox1_Paint); // + // panelTop + // + this.panelTop.Controls.Add(this.panelLegend); + this.panelTop.Dock = System.Windows.Forms.DockStyle.Top; + this.panelTop.Location = new System.Drawing.Point(0, 0); + this.panelTop.Name = "panelTop"; + this.panelTop.Size = new System.Drawing.Size(846, 123); + this.panelTop.TabIndex = 1; + // + // panelLegend + // + this.panelLegend.Controls.Add(this.bankLegend1); + this.panelLegend.Dock = System.Windows.Forms.DockStyle.Left; + this.panelLegend.Location = new System.Drawing.Point(0, 0); + this.panelLegend.Name = "panelLegend"; + this.panelLegend.Size = new System.Drawing.Size(567, 123); + this.panelLegend.TabIndex = 0; + // + // bankLegend1 + // + this.bankLegend1.AutoScroll = true; + this.bankLegend1.Dock = System.Windows.Forms.DockStyle.Fill; + this.bankLegend1.Location = new System.Drawing.Point(0, 0); + this.bankLegend1.Name = "bankLegend1"; + this.bankLegend1.Size = new System.Drawing.Size(567, 123); + this.bankLegend1.TabIndex = 0; + // + // panelBottom + // + this.panelBottom.AutoScroll = true; + this.panelBottom.AutoSize = true; + this.panelBottom.Controls.Add(this.pictureBox1); + this.panelBottom.Dock = System.Windows.Forms.DockStyle.Fill; + this.panelBottom.Location = new System.Drawing.Point(0, 123); + this.panelBottom.Name = "panelBottom"; + this.panelBottom.Size = new System.Drawing.Size(846, 401); + this.panelBottom.TabIndex = 2; + // // VisualizerForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(1189, 553); - this.Controls.Add(this.pictureBox1); + this.AutoScroll = true; + this.ClientSize = new System.Drawing.Size(846, 524); + this.Controls.Add(this.panelBottom); + this.Controls.Add(this.panelTop); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow; this.Name = "VisualizerForm"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "ROM Visualizer"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.VisualizerForm_FormClosing); this.Load += new System.EventHandler(this.VisualizerForm_Load); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.panelTop.ResumeLayout(false); + this.panelLegend.ResumeLayout(false); + this.panelBottom.ResumeLayout(false); + this.panelBottom.PerformLayout(); this.ResumeLayout(false); + this.PerformLayout(); } #endregion private System.Windows.Forms.PictureBox pictureBox1; + private System.Windows.Forms.Panel panelTop; + private System.Windows.Forms.Panel panelLegend; + private System.Windows.Forms.Panel panelBottom; + private usercontrols.BankLegend bankLegend1; } } \ No newline at end of file diff --git a/DiztinGUIsh/window/VisualizerForm.cs b/DiztinGUIsh/window/VisualizerForm.cs index d98e66b9..55996389 100644 --- a/DiztinGUIsh/window/VisualizerForm.cs +++ b/DiztinGUIsh/window/VisualizerForm.cs @@ -1,12 +1,14 @@ -using System.Drawing; +using System.Collections.Generic; using System.Windows.Forms; -using Diz.Core.model; +using Diz.Core.util; +using DiztinGUIsh.util; namespace DiztinGUIsh.window { public partial class VisualizerForm : Form { private readonly MainWindow mainWindow; + private readonly RomVisual romVisual = new RomVisual(); public VisualizerForm(MainWindow window) { @@ -14,67 +16,44 @@ public VisualizerForm(MainWindow window) InitializeComponent(); } - private Bitmap bitmap; - - private Color GetColorForFlag(Data.FlagType flag) - { - return flag switch - { - Data.FlagType.Unreached => Color.Black, - Data.FlagType.Opcode => Color.Yellow, - Data.FlagType.Operand => Color.YellowGreen, - Data.FlagType.Graphics => Color.LightPink, - Data.FlagType.Music => Color.PowderBlue, - Data.FlagType.Data8Bit => Color.NavajoWhite, - Data.FlagType.Data16Bit => Color.NavajoWhite, - Data.FlagType.Data24Bit => Color.NavajoWhite, - Data.FlagType.Data32Bit => Color.NavajoWhite, - Data.FlagType.Pointer16Bit => Color.Orchid, - Data.FlagType.Pointer24Bit => Color.Orchid, - Data.FlagType.Pointer32Bit => Color.Orchid, - Data.FlagType.Text => Color.Aquamarine, - Data.FlagType.Empty => Color.DarkSlateGray, - _ => Color.DarkSlateGray - }; - } - - void GenerateImage() + private void VisualizerForm_Load(object sender, System.EventArgs e) { - if (bitmap != null) - return; + romVisual.Project = mainWindow.Project; + pictureBox1.Image = romVisual.Bitmap; - const int pixels_per_bank = 0xFFFF; - const int bank_height = 48; - const int bank_width = pixels_per_bank / bank_height; + romVisual.ImageDataUpdated += RomVisual_ImageDataUpdated; + romVisual.MarkedDirty += RomVisual_MarkedDirty; - const int num_banks = 64; + Width = pictureBox1.Width + 40; + } - const int total_height = bank_height * num_banks; - const int total_width = bank_width; + private void RomVisual_MarkedDirty(object sender, System.EventArgs e) + { + Invalidate(); + pictureBox1.Invalidate(); + } - bitmap = new Bitmap(total_width, total_height); + private void RomVisual_ImageDataUpdated(object sender, System.EventArgs e) + { + Refresh(); + pictureBox1.Refresh(); + Application.DoEvents(); - for (var y = 0; y < bitmap.Height; y++) - { - for (var x = 0; x < bitmap.Width; x++) - { - var romOffset = y * bank_width + x; - var romFlag = mainWindow.Project.Data.RomBytes[romOffset].TypeFlag; - var color = GetColorForFlag(romFlag); - bitmap.SetPixel(x, y, color); - } - } + // ugly hack city. + pictureBox1.Image = null; + pictureBox1.Image = romVisual.Bitmap; } - private void pictureBox1_Paint(object sender, PaintEventArgs e) + private void VisualizerForm_FormClosing(object sender, FormClosingEventArgs e) { - GenerateImage(); - e.Graphics.DrawImage(bitmap, 0, 0, bitmap.Width, bitmap.Height); + if (e.CloseReason != CloseReason.UserClosing) return; + e.Cancel = true; + Hide(); } - private void VisualizerForm_Load(object sender, System.EventArgs e) + private void pictureBox1_Paint(object sender, PaintEventArgs e) { - + romVisual?.Refresh(); } } } \ No newline at end of file diff --git a/DiztinGUIsh/window/usercontrols/BankLegend.Designer.cs b/DiztinGUIsh/window/usercontrols/BankLegend.Designer.cs new file mode 100644 index 00000000..d87c5473 --- /dev/null +++ b/DiztinGUIsh/window/usercontrols/BankLegend.Designer.cs @@ -0,0 +1,59 @@ +namespace DiztinGUIsh.window.usercontrols +{ + partial class BankLegend + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); + this.SuspendLayout(); + // + // flowLayoutPanel1 + // + this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.flowLayoutPanel1.Name = "flowLayoutPanel1"; + this.flowLayoutPanel1.Size = new System.Drawing.Size(472, 180); + this.flowLayoutPanel1.TabIndex = 0; + // + // BankLegend + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoScroll = true; + this.Controls.Add(this.flowLayoutPanel1); + this.Name = "BankLegend"; + this.Size = new System.Drawing.Size(472, 180); + this.Load += new System.EventHandler(this.BankLegend_Load); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; + } +} diff --git a/DiztinGUIsh/window/usercontrols/BankLegend.cs b/DiztinGUIsh/window/usercontrols/BankLegend.cs new file mode 100644 index 00000000..c0ccccfc --- /dev/null +++ b/DiztinGUIsh/window/usercontrols/BankLegend.cs @@ -0,0 +1,31 @@ +using System.Drawing; +using System.Windows.Forms; +using Diz.Core.model; +using Diz.Core.util; + +namespace DiztinGUIsh.window.usercontrols +{ + public partial class BankLegend : UserControl + { + public BankLegend() + { + InitializeComponent(); + } + + private void AddControl(string name, Color color) + { + flowLayoutPanel1.Controls.Add( + new BankLegendItem(name, color) + ); + } + + private void BankLegend_Load(object sender, System.EventArgs e) + { + var enums = Util.GetEnumColorDescriptions(); + foreach (var en in enums) + { + AddControl(en.Key.ToString(), Util.GetColorFromFlag(en.Key)); + } + } + } +} diff --git a/DiztinGUIsh/window/usercontrols/BankLegend.resx b/DiztinGUIsh/window/usercontrols/BankLegend.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/DiztinGUIsh/window/usercontrols/BankLegend.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/DiztinGUIsh/window/usercontrols/BankLegendItem.Designer.cs b/DiztinGUIsh/window/usercontrols/BankLegendItem.Designer.cs new file mode 100644 index 00000000..8d98ba09 --- /dev/null +++ b/DiztinGUIsh/window/usercontrols/BankLegendItem.Designer.cs @@ -0,0 +1,88 @@ +namespace DiztinGUIsh.window.usercontrols +{ + partial class BankLegendItem + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label1 = new System.Windows.Forms.Label(); + this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.flowLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // pictureBox1 + // + this.pictureBox1.BackColor = System.Drawing.SystemColors.ActiveCaption; + this.pictureBox1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.pictureBox1.Location = new System.Drawing.Point(3, 3); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(29, 13); + this.pictureBox1.TabIndex = 0; + this.pictureBox1.TabStop = false; + // + // label1 + // + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(38, 3); + this.label1.Margin = new System.Windows.Forms.Padding(3); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(141, 14); + this.label1.TabIndex = 1; + this.label1.Text = "Bank Legend Item Text"; + // + // flowLayoutPanel1 + // + this.flowLayoutPanel1.Controls.Add(this.pictureBox1); + this.flowLayoutPanel1.Controls.Add(this.label1); + this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.flowLayoutPanel1.Name = "flowLayoutPanel1"; + this.flowLayoutPanel1.Size = new System.Drawing.Size(182, 17); + this.flowLayoutPanel1.TabIndex = 2; + // + // BankLegendItem + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.Controls.Add(this.flowLayoutPanel1); + this.Name = "BankLegendItem"; + this.Size = new System.Drawing.Size(182, 17); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.flowLayoutPanel1.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.PictureBox pictureBox1; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; + } +} diff --git a/DiztinGUIsh/window/usercontrols/BankLegendItem.cs b/DiztinGUIsh/window/usercontrols/BankLegendItem.cs new file mode 100644 index 00000000..d17d8158 --- /dev/null +++ b/DiztinGUIsh/window/usercontrols/BankLegendItem.cs @@ -0,0 +1,16 @@ +using System.Drawing; +using System.Windows.Forms; + +namespace DiztinGUIsh.window.usercontrols +{ + public partial class BankLegendItem : UserControl + { + public BankLegendItem(string labelText, Color color) + { + InitializeComponent(); + + label1.Text = labelText; + pictureBox1.BackColor = color; + } + } +} diff --git a/DiztinGUIsh/window/usercontrols/BankLegendItem.resx b/DiztinGUIsh/window/usercontrols/BankLegendItem.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/DiztinGUIsh/window/usercontrols/BankLegendItem.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file From 148acb6cdab23654672e0828743a84c8e2c2579a Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Fri, 23 Oct 2020 12:24:08 -0400 Subject: [PATCH 101/136] remove extra UI update calls, still works when not focused. --- DiztinGUIsh/window/VisualizerForm.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/DiztinGUIsh/window/VisualizerForm.cs b/DiztinGUIsh/window/VisualizerForm.cs index 55996389..8bcc4dcc 100644 --- a/DiztinGUIsh/window/VisualizerForm.cs +++ b/DiztinGUIsh/window/VisualizerForm.cs @@ -29,13 +29,11 @@ private void VisualizerForm_Load(object sender, System.EventArgs e) private void RomVisual_MarkedDirty(object sender, System.EventArgs e) { - Invalidate(); pictureBox1.Invalidate(); } private void RomVisual_ImageDataUpdated(object sender, System.EventArgs e) { - Refresh(); pictureBox1.Refresh(); Application.DoEvents(); From c7c3938de1fe510332f56359dad4715579a26cf6 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 24 Oct 2020 11:40:41 -0400 Subject: [PATCH 102/136] Much more stable ROM image viewer setup - put it on a timer - unscrewup the paint stuff - better multithreading support - sizing needs work but that's easy to deal with --- Diz.Core/model/Data.cs | 11 ++ Diz.Core/model/RomBytes.cs | 19 ++- Diz.Core/util/RomVisual.cs | 77 +++++++---- DiztinGUIsh/DiztinGUIsh.csproj | 9 ++ DiztinGUIsh/window/MainWindow.cs | 3 + DiztinGUIsh/window/VisualizerForm.Designer.cs | 46 +++---- DiztinGUIsh/window/VisualizerForm.cs | 47 +++---- .../BSNESTraceLogBinaryMonitorForm.UI.cs | 13 +- .../window/usercontrols/RomImage.Designer.cs | 58 +++++++++ DiztinGUIsh/window/usercontrols/RomImage.cs | 64 +++++++++ DiztinGUIsh/window/usercontrols/RomImage.resx | 123 ++++++++++++++++++ 11 files changed, 380 insertions(+), 90 deletions(-) create mode 100644 DiztinGUIsh/window/usercontrols/RomImage.Designer.cs create mode 100644 DiztinGUIsh/window/usercontrols/RomImage.cs create mode 100644 DiztinGUIsh/window/usercontrols/RomImage.resx diff --git a/Diz.Core/model/Data.cs b/Diz.Core/model/Data.cs index c47668a4..98dc4976 100644 --- a/Diz.Core/model/Data.cs +++ b/Diz.Core/model/Data.cs @@ -19,6 +19,10 @@ public Data() public void CreateRomBytesFromRom(IEnumerable actualRomBytes) { Debug.Assert(RomBytes.Count == 0); + + var previousNotificationState = RomBytes.SendNotificationChangedEvents; + RomBytes.SendNotificationChangedEvents = false; + RomBytes.Clear(); foreach (var fileByte in actualRomBytes) { @@ -27,6 +31,8 @@ public void CreateRomBytesFromRom(IEnumerable actualRomBytes) Rom = fileByte, }); } + + RomBytes.SendNotificationChangedEvents = previousNotificationState; } private byte[] GetRomBytes(int pcOffset, int count) @@ -50,12 +56,17 @@ public int GetRomCheckSumsFromRomBytes() public void CopyRomDataIn(byte[] data) { + var previousNotificationState = RomBytes.SendNotificationChangedEvents; + RomBytes.SendNotificationChangedEvents = false; + var size = data.Length; Debug.Assert(RomBytes.Count == size); for (var i = 0; i < size; i++) { RomBytes[i].Rom = data[i]; } + + RomBytes.SendNotificationChangedEvents = previousNotificationState; } public int GetROMSize() => RomBytes?.Count ?? 0; diff --git a/Diz.Core/model/RomBytes.cs b/Diz.Core/model/RomBytes.cs index fb80115b..e4714a9e 100644 --- a/Diz.Core/model/RomBytes.cs +++ b/Diz.Core/model/RomBytes.cs @@ -1,5 +1,6 @@ using System.Collections; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Linq; @@ -14,7 +15,7 @@ public class RomBytes : IEnumerable, INotifyCollectionChanged, INotifyP // This class needs to do these things that are special: // 1) Be handled specially by our custom XML serializer (compresses to save disk space) // 2) Handle Equals() by comparing each element in the list (SequenceEqual) - public ObservableList Bytes { get; } = new ObservableList(); + public ObservableCollection Bytes { get; } = new ObservableCollection(); public ROMByte this[int i] { get => Bytes[i]; @@ -23,11 +24,13 @@ public ROMByte this[int i] public RomBytes() { - Bytes.PropertyChanged += Bytes_PropertyChanged; + // Bytes.PropertyChanged += Bytes_PropertyChanged; Bytes.CollectionChanged += Bytes_CollectionChanged; } public int Count => Bytes.Count; + public bool SendNotificationChangedEvents { get; set; } = true; + public void Add(ROMByte romByte) { Bytes.Add(romByte); @@ -83,18 +86,20 @@ private void Bytes_CollectionChanged(object sender, NotifyCollectionChangedEvent { if (e.NewItems != null) foreach (ROMByte item in e.NewItems) - item.PropertyChanged += Bytes_PropertyChanged; + item.PropertyChanged += RomByteObjectChanged; if (e.OldItems != null) foreach (ROMByte item in e.OldItems) - item.PropertyChanged -= Bytes_PropertyChanged; + item.PropertyChanged -= RomByteObjectChanged; - CollectionChanged?.Invoke(sender, e); + if (SendNotificationChangedEvents) + CollectionChanged?.Invoke(sender, e); } - private void Bytes_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + private void RomByteObjectChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { - PropertyChanged?.Invoke(sender, e); + if (SendNotificationChangedEvents) + PropertyChanged?.Invoke(sender, e); } } } diff --git a/Diz.Core/util/RomVisual.cs b/Diz.Core/util/RomVisual.cs index 1418f982..2db58d79 100644 --- a/Diz.Core/util/RomVisual.cs +++ b/Diz.Core/util/RomVisual.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Drawing; using System.Linq; -using System.Security.AccessControl; using Diz.Core.model; using FastBitmapLib; @@ -51,7 +49,8 @@ public int BankWidthPixels public void ValidateHeight(int heightPixels) { if (PixelsPerBank % heightPixels != 0) - throw new ArgumentException("Selected Bank Height doesn't evenly divide. (pick a height that's a power of 2)"); + throw new ArgumentException( + "Selected Bank Height doesn't evenly divide. (pick a height that's a power of 2)"); } public Project Project @@ -70,6 +69,7 @@ public Project Project private Bitmap bitmap; private Project project; + private readonly object dirtyLock = new object(); private void RomBytes_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) @@ -81,9 +81,18 @@ private void RomBytes_CollectionChanged(object sender, public Dictionary DirtyRomBytes = new Dictionary(); private int bankHeightPixels = 64; - public bool NeedsUpdate => - AllDirty || - (AutoRefresh && DirtyRomBytes.Count > 0); + public bool IsDirty + { + get + { + lock (dirtyLock) + { + return AllDirty || + (AutoRefresh && DirtyRomBytes.Count > 0) || + bitmap == null; + } + } + } private void RomBytes_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { @@ -100,13 +109,17 @@ private void InvalidateImage() { bitmap = null; AllDirty = true; - DirtyRomBytes.Clear(); + lock (dirtyLock) + { + DirtyRomBytes.Clear(); + } + RegenerateImage(); } public void Refresh() { - if (bitmap == null || NeedsUpdate) + if (IsDirty) RegenerateImage(); } @@ -121,20 +134,16 @@ private void RegenerateImage() var totalHeight = BankHeightPixels * Data.GetNumberOfBanks(); var totalWidth = BankWidthPixels; - // requires use of the /unsafe compiler flag, because we're manipulating memory directly. - // needed because the system bitmap SetPixel() operation is super-slow. - var shouldRecreate = bitmap == null || - bitmap.Width != totalWidth || - bitmap.Height != totalHeight; + var shouldRecreateBitmap = bitmap == null || + bitmap.Width != totalWidth || + bitmap.Height != totalHeight; - if (shouldRecreate) + if (shouldRecreateBitmap) bitmap = new Bitmap(totalWidth, totalHeight); - var romBytes = AllDirty ? - Data.RomBytes.ToList() : - DirtyRomBytes.Values.Select(kvp => kvp); + var romBytes = ConsumeRomDirtyBytes(); - var fastBitmap = new FastBitmap(bitmap); + var fastBitmap = new FastBitmap(bitmap); // needs compiler flag "/unsafe" enabled using (fastBitmap.Lock()) { foreach (var romByte in romBytes) @@ -143,12 +152,29 @@ private void RegenerateImage() } } - DirtyRomBytes.Clear(); AllDirty = false; - OnBitmapUpdated(); } + // returns the RomBytes we should use to update our image + // this can either be ALL RomBytes, or, a small set of dirty RomBytes that were changed + // since our last redraw. + private IEnumerable ConsumeRomDirtyBytes() + { + if (AllDirty) + return Data.RomBytes.ToList(); + + IEnumerable romBytes; + lock (dirtyLock) + { + // make a copy so we can release the lock. + romBytes = new List(DirtyRomBytes.Values.Select(kvp => kvp)); + DirtyRomBytes.Clear(); + } + + return romBytes; + } + private static void SetPixel(ROMByte romByte, FastBitmap fastBitmap, int bankWidthPixels) { var romOffset = romByte.Offset; @@ -165,10 +191,13 @@ protected virtual void OnBitmapUpdated() protected virtual void MarkDirty(ROMByte romByte) { - if (!DirtyRomBytes.ContainsKey(romByte.Offset)) - DirtyRomBytes.Add(romByte.Offset, romByte); - else - DirtyRomBytes[romByte.Offset] = romByte; + lock (dirtyLock) + { + if (!DirtyRomBytes.ContainsKey(romByte.Offset)) + DirtyRomBytes.Add(romByte.Offset, romByte); + else + DirtyRomBytes[romByte.Offset] = romByte; + } MarkedDirty?.Invoke(this, EventArgs.Empty); } diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 1722f3c6..48a61b27 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -239,6 +239,12 @@ BankLegendItem.cs + + UserControl + + + RomImage.cs + Form @@ -298,6 +304,9 @@ BankLegendItem.cs + + RomImage.cs + VisualizerForm.cs diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 70ac9ba4..e3f8a7b7 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -197,6 +197,9 @@ private void UpdateUIFromSettings() public void OnProjectOpened(string filename) { + visualForm.Project = Project; + // TODO: do this with aliaslist too. + UpdateSaveOptionStates(true, true); RefreshUI(); diff --git a/DiztinGUIsh/window/VisualizerForm.Designer.cs b/DiztinGUIsh/window/VisualizerForm.Designer.cs index 45efa576..44a2149b 100644 --- a/DiztinGUIsh/window/VisualizerForm.Designer.cs +++ b/DiztinGUIsh/window/VisualizerForm.Designer.cs @@ -28,28 +28,16 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - this.pictureBox1 = new System.Windows.Forms.PictureBox(); this.panelTop = new System.Windows.Forms.Panel(); this.panelLegend = new System.Windows.Forms.Panel(); - this.bankLegend1 = new DiztinGUIsh.window.usercontrols.BankLegend(); this.panelBottom = new System.Windows.Forms.Panel(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.bankLegend1 = new DiztinGUIsh.window.usercontrols.BankLegend(); + this.romImage1 = new DiztinGUIsh.window.usercontrols.RomImage(); this.panelTop.SuspendLayout(); this.panelLegend.SuspendLayout(); this.panelBottom.SuspendLayout(); this.SuspendLayout(); // - // pictureBox1 - // - this.pictureBox1.Cursor = System.Windows.Forms.Cursors.Cross; - this.pictureBox1.Location = new System.Drawing.Point(0, 0); - this.pictureBox1.Name = "pictureBox1"; - this.pictureBox1.Size = new System.Drawing.Size(865, 562); - this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize; - this.pictureBox1.TabIndex = 0; - this.pictureBox1.TabStop = false; - this.pictureBox1.Paint += new System.Windows.Forms.PaintEventHandler(this.pictureBox1_Paint); - // // panelTop // this.panelTop.Controls.Add(this.panelLegend); @@ -68,6 +56,17 @@ private void InitializeComponent() this.panelLegend.Size = new System.Drawing.Size(567, 123); this.panelLegend.TabIndex = 0; // + // panelBottom + // + this.panelBottom.AutoScroll = true; + this.panelBottom.AutoSize = true; + this.panelBottom.Controls.Add(this.romImage1); + this.panelBottom.Dock = System.Windows.Forms.DockStyle.Fill; + this.panelBottom.Location = new System.Drawing.Point(0, 123); + this.panelBottom.Name = "panelBottom"; + this.panelBottom.Size = new System.Drawing.Size(846, 401); + this.panelBottom.TabIndex = 2; + // // bankLegend1 // this.bankLegend1.AutoScroll = true; @@ -77,16 +76,12 @@ private void InitializeComponent() this.bankLegend1.Size = new System.Drawing.Size(567, 123); this.bankLegend1.TabIndex = 0; // - // panelBottom + // romImage1 // - this.panelBottom.AutoScroll = true; - this.panelBottom.AutoSize = true; - this.panelBottom.Controls.Add(this.pictureBox1); - this.panelBottom.Dock = System.Windows.Forms.DockStyle.Fill; - this.panelBottom.Location = new System.Drawing.Point(0, 123); - this.panelBottom.Name = "panelBottom"; - this.panelBottom.Size = new System.Drawing.Size(846, 401); - this.panelBottom.TabIndex = 2; + this.romImage1.Location = new System.Drawing.Point(12, 6); + this.romImage1.Name = "romImage1"; + this.romImage1.Size = new System.Drawing.Size(854, 421); + this.romImage1.TabIndex = 0; // // VisualizerForm // @@ -103,22 +98,19 @@ private void InitializeComponent() this.Text = "ROM Visualizer"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.VisualizerForm_FormClosing); this.Load += new System.EventHandler(this.VisualizerForm_Load); - ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); this.panelTop.ResumeLayout(false); this.panelLegend.ResumeLayout(false); this.panelBottom.ResumeLayout(false); - this.panelBottom.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); } #endregion - - private System.Windows.Forms.PictureBox pictureBox1; private System.Windows.Forms.Panel panelTop; private System.Windows.Forms.Panel panelLegend; private System.Windows.Forms.Panel panelBottom; private usercontrols.BankLegend bankLegend1; + private usercontrols.RomImage romImage1; } } \ No newline at end of file diff --git a/DiztinGUIsh/window/VisualizerForm.cs b/DiztinGUIsh/window/VisualizerForm.cs index 8bcc4dcc..57e05a60 100644 --- a/DiztinGUIsh/window/VisualizerForm.cs +++ b/DiztinGUIsh/window/VisualizerForm.cs @@ -1,14 +1,23 @@ -using System.Collections.Generic; -using System.Windows.Forms; +using System.Windows.Forms; +using Diz.Core.model; using Diz.Core.util; -using DiztinGUIsh.util; namespace DiztinGUIsh.window { public partial class VisualizerForm : Form { private readonly MainWindow mainWindow; - private readonly RomVisual romVisual = new RomVisual(); + private Project project; + + public Project Project + { + get => project; + set + { + project = value; + romImage1.Project = project; + } + } public VisualizerForm(MainWindow window) { @@ -18,28 +27,9 @@ public VisualizerForm(MainWindow window) private void VisualizerForm_Load(object sender, System.EventArgs e) { - romVisual.Project = mainWindow.Project; - pictureBox1.Image = romVisual.Bitmap; - - romVisual.ImageDataUpdated += RomVisual_ImageDataUpdated; - romVisual.MarkedDirty += RomVisual_MarkedDirty; - - Width = pictureBox1.Width + 40; - } - - private void RomVisual_MarkedDirty(object sender, System.EventArgs e) - { - pictureBox1.Invalidate(); - } - - private void RomVisual_ImageDataUpdated(object sender, System.EventArgs e) - { - pictureBox1.Refresh(); - Application.DoEvents(); - - // ugly hack city. - pictureBox1.Image = null; - pictureBox1.Image = romVisual.Bitmap; + // hack to make room for the scrollbar + // I wish docking dealt with this, or maybe I set it up wrong... + Width = romImage1.Width + 40; } private void VisualizerForm_FormClosing(object sender, FormClosingEventArgs e) @@ -48,10 +38,5 @@ private void VisualizerForm_FormClosing(object sender, FormClosingEventArgs e) e.Cancel = true; Hide(); } - - private void pictureBox1_Paint(object sender, PaintEventArgs e) - { - romVisual?.Refresh(); - } } } \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs index 7f385e29..0b492859 100644 --- a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs @@ -15,12 +15,23 @@ public partial class BSNESTraceLogBinaryMonitorForm private readonly ChartValues chartValuesBytesModified = new ChartValues(); private long chartValueBytesModified_previous = 0; + private const int refreshGraphEveryNDataPoints = 100; + private int dataPointsIn = -1; + private void AppendToChart((BSNESTraceLogImporter.Stats stats, int bytesInQueue) currentStats) { InitChart(); + + // TODO: re-enable, it's maybe a little slow. + /*if (dataPointsIn == -1 || ++dataPointsIn >= refreshGraphEveryNDataPoints) + dataPointsIn = 0; + + if (dataPointsIn != 0) + return; + var diffBytes = currentStats.stats.numRomBytesModified - chartValueBytesModified_previous; chartValueBytesModified_previous = currentStats.stats.numRomBytesModified; - chartValuesBytesModified.Add(diffBytes); + chartValuesBytesModified.Add(diffBytes);*/ } private void InitChart() diff --git a/DiztinGUIsh/window/usercontrols/RomImage.Designer.cs b/DiztinGUIsh/window/usercontrols/RomImage.Designer.cs new file mode 100644 index 00000000..3551f867 --- /dev/null +++ b/DiztinGUIsh/window/usercontrols/RomImage.Designer.cs @@ -0,0 +1,58 @@ +namespace DiztinGUIsh.window.usercontrols +{ + partial class RomImage + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.timer1 = new System.Windows.Forms.Timer(this.components); + this.SuspendLayout(); + // + // timer1 + // + this.timer1.Enabled = true; + this.timer1.Interval = 250; + this.timer1.Tick += new System.EventHandler(this.timer1_Tick); + // + // RomImage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.DoubleBuffered = true; + this.Name = "RomImage"; + this.Size = new System.Drawing.Size(321, 255); + this.Load += new System.EventHandler(this.RomImage_Load); + this.Paint += new System.Windows.Forms.PaintEventHandler(this.RomImage_Paint); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Timer timer1; + } +} diff --git a/DiztinGUIsh/window/usercontrols/RomImage.cs b/DiztinGUIsh/window/usercontrols/RomImage.cs new file mode 100644 index 00000000..7da38a24 --- /dev/null +++ b/DiztinGUIsh/window/usercontrols/RomImage.cs @@ -0,0 +1,64 @@ +using System.Drawing; +using System.Windows.Forms; +using Diz.Core.model; +using Diz.Core.util; + +namespace DiztinGUIsh.window.usercontrols +{ + public partial class RomImage : UserControl + { + private readonly RomVisual romVisual = new RomVisual(); + private Project project; + + public Project Project + { + get => project; + set + { + project = value; + romVisual.Project = project; + } + } + + public RomImage() + { + InitializeComponent(); + } + private void RomImage_Load(object sender, System.EventArgs e) + { + // if there's a reason to track ROM byte changes, hook in here + // romVisual.MarkedDirty += RomVisual_MarkedDirty; + } + + private void RomImage_Paint(object sender, PaintEventArgs e) + { + Redraw(e.Graphics); + } + + private void Redraw(Graphics graphics = null) + { + if (romVisual?.Bitmap == null) + return; + + graphics ??= CreateGraphics(); + + var width = romVisual.Bitmap.Width; + var height = romVisual.Bitmap.Height; + graphics.DrawImage(romVisual.Bitmap, 0, 0, width, height); + } + + private void RedrawIfNeeded() + { + if (!Visible || !romVisual.IsDirty) + return; + + romVisual.Refresh(); + Redraw(); + } + + private void timer1_Tick(object sender, System.EventArgs e) + { + RedrawIfNeeded(); + } + } +} diff --git a/DiztinGUIsh/window/usercontrols/RomImage.resx b/DiztinGUIsh/window/usercontrols/RomImage.resx new file mode 100644 index 00000000..1f666f26 --- /dev/null +++ b/DiztinGUIsh/window/usercontrols/RomImage.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file From 6da5413f5f31bbc52288bf6b25b6b5091c9fba80 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 24 Oct 2020 12:06:27 -0400 Subject: [PATCH 103/136] add sizing support to visualizer, this is pretty complete now! --- DiztinGUIsh/window/VisualizerForm.cs | 12 +++++++++ DiztinGUIsh/window/usercontrols/RomImage.cs | 28 ++++++++++++++------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/DiztinGUIsh/window/VisualizerForm.cs b/DiztinGUIsh/window/VisualizerForm.cs index 57e05a60..82ec557e 100644 --- a/DiztinGUIsh/window/VisualizerForm.cs +++ b/DiztinGUIsh/window/VisualizerForm.cs @@ -1,6 +1,7 @@ using System.Windows.Forms; using Diz.Core.model; using Diz.Core.util; +using DiztinGUIsh.window.usercontrols; namespace DiztinGUIsh.window { @@ -23,6 +24,17 @@ public VisualizerForm(MainWindow window) { mainWindow = window; InitializeComponent(); + + romImage1.RedrawOccurred += RomImage1_RedrawOccurred; + } + + private void RomImage1_RedrawOccurred(object sender, System.EventArgs e) + { + if (!(sender is RomImage romImage)) + return; + + romImage1.Width = romImage.ROMVisual.Bitmap.Width; + romImage1.Height = romImage.ROMVisual.Bitmap.Height; } private void VisualizerForm_Load(object sender, System.EventArgs e) diff --git a/DiztinGUIsh/window/usercontrols/RomImage.cs b/DiztinGUIsh/window/usercontrols/RomImage.cs index 7da38a24..457075ef 100644 --- a/DiztinGUIsh/window/usercontrols/RomImage.cs +++ b/DiztinGUIsh/window/usercontrols/RomImage.cs @@ -1,4 +1,5 @@ -using System.Drawing; +using System; +using System.Drawing; using System.Windows.Forms; using Diz.Core.model; using Diz.Core.util; @@ -7,7 +8,9 @@ namespace DiztinGUIsh.window.usercontrols { public partial class RomImage : UserControl { - private readonly RomVisual romVisual = new RomVisual(); + public event EventHandler RedrawOccurred; + + public RomVisual ROMVisual { get; } = new RomVisual(); private Project project; public Project Project @@ -16,7 +19,7 @@ public Project Project set { project = value; - romVisual.Project = project; + ROMVisual.Project = project; } } @@ -37,22 +40,24 @@ private void RomImage_Paint(object sender, PaintEventArgs e) private void Redraw(Graphics graphics = null) { - if (romVisual?.Bitmap == null) + if (ROMVisual?.Bitmap == null) return; graphics ??= CreateGraphics(); - var width = romVisual.Bitmap.Width; - var height = romVisual.Bitmap.Height; - graphics.DrawImage(romVisual.Bitmap, 0, 0, width, height); + var width = ROMVisual.Bitmap.Width; + var height = ROMVisual.Bitmap.Height; + graphics.DrawImage(ROMVisual.Bitmap, 0, 0, width, height); + + OnRedrawOccurred(); } private void RedrawIfNeeded() { - if (!Visible || !romVisual.IsDirty) + if (!Visible || !ROMVisual.IsDirty) return; - romVisual.Refresh(); + ROMVisual.Refresh(); Redraw(); } @@ -60,5 +65,10 @@ private void timer1_Tick(object sender, System.EventArgs e) { RedrawIfNeeded(); } + + protected virtual void OnRedrawOccurred() + { + RedrawOccurred?.Invoke(this, EventArgs.Empty); + } } } From 1ebcdd8e7f665a46fecaec62917e015e5fce6171 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 24 Oct 2020 13:49:49 -0400 Subject: [PATCH 104/136] refactor Rom visuals class to allow arbitrary starting offsets and lengths, and allow rendering into abitrary widths --- Diz.Core/util/RomVisual.cs | 159 +++++++++++------- DiztinGUIsh/window/MainWindow.Designer.cs | 42 +++-- DiztinGUIsh/window/MainWindow.cs | 18 +- DiztinGUIsh/window/VisualizerForm.Designer.cs | 34 ++-- .../usercontrols/BankLegend.Designer.cs | 1 + 5 files changed, 156 insertions(+), 98 deletions(-) diff --git a/Diz.Core/util/RomVisual.cs b/Diz.Core/util/RomVisual.cs index 2db58d79..621a5297 100644 --- a/Diz.Core/util/RomVisual.cs +++ b/Diz.Core/util/RomVisual.cs @@ -9,12 +9,39 @@ namespace Diz.Core.util { public class RomVisual { + public event EventHandler ImageDataUpdated; + public event EventHandler MarkedDirty; + public bool AutoRefresh { get; set; } = true; public Data Data => Project?.Data; - public event EventHandler ImageDataUpdated; - public event EventHandler MarkedDirty; + public Project Project + { + get => project; + set + { + if (ReferenceEquals(project, value)) return; + project = value; + if (project?.Data == null) return; + project.Data.RomBytes.PropertyChanged += RomBytes_PropertyChanged; + project.Data.RomBytes.CollectionChanged += RomBytes_CollectionChanged; + InvalidateImage(); + } + } + + public bool IsDirty + { + get + { + lock (dirtyLock) + { + return AllDirty || + (AutoRefresh && dirtyRomBytes.Count > 0) || + bitmap == null; + } + } + } public Bitmap Bitmap { @@ -25,51 +52,57 @@ public Bitmap Bitmap } } - public int PixelsPerBank => Data.GetBankSize(); - - public int BankHeightPixels + public int RomStartingOffset { - get => bankHeightPixels; + get => romStartingOffset; set { - ValidateHeight(value); - bankHeightPixels = value; + if (value < 0 || value >= project.Data.RomBytes.Count) + throw new ArgumentOutOfRangeException(); + + romStartingOffset = value; } } - public int BankWidthPixels + public int LengthOverride { - get + get => lengthOverride; + set { - ValidateHeight(BankHeightPixels); - return PixelsPerBank / BankHeightPixels; + if (value != -1 && (value == 0 || RomStartingOffset + value >= project.Data.RomBytes.Count)) + throw new ArgumentOutOfRangeException(); + + lengthOverride = value; } } - public void ValidateHeight(int heightPixels) - { - if (PixelsPerBank % heightPixels != 0) - throw new ArgumentException( - "Selected Bank Height doesn't evenly divide. (pick a height that's a power of 2)"); - } + public int PixelCount => lengthOverride != -1 ? lengthOverride : project.Data.RomBytes.Count; - public Project Project + public int Width { - get => project; + get => width; set { - if (ReferenceEquals(project, value)) return; - project = value; - if (project?.Data == null) return; - project.Data.RomBytes.PropertyChanged += RomBytes_PropertyChanged; - project.Data.RomBytes.CollectionChanged += RomBytes_CollectionChanged; - InvalidateImage(); + if (Width <= 0) + throw new ArgumentOutOfRangeException(); + + width = value; } } + // this rounds up the height by one pixel if needed, meaning our last row can be incomplete if Width doesn't divide evenly into Length + public int Height => (int)Math.Ceiling(PixelCount / (double)Width); + + public bool AllDirty { get; set; } = true; + + private int romStartingOffset = 0; + private int lengthOverride = -1; + private int width = 1024; private Bitmap bitmap; private Project project; + private readonly object dirtyLock = new object(); + private readonly Dictionary dirtyRomBytes = new Dictionary(); private void RomBytes_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) @@ -77,21 +110,9 @@ private void RomBytes_CollectionChanged(object sender, AllDirty = true; } - public bool AllDirty { get; set; } = true; - public Dictionary DirtyRomBytes = new Dictionary(); - private int bankHeightPixels = 64; - - public bool IsDirty + private bool OffsetInRange(int offset) { - get - { - lock (dirtyLock) - { - return AllDirty || - (AutoRefresh && DirtyRomBytes.Count > 0) || - bitmap == null; - } - } + return (offset >= romStartingOffset && offset < romStartingOffset + lengthOverride); } private void RomBytes_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) @@ -102,6 +123,9 @@ private void RomBytes_PropertyChanged(object sender, System.ComponentModel.Prope if (e.PropertyName != "TypeFlag") return; + if (!OffsetInRange(romByte.Offset)) + return; + MarkDirty(romByte); } @@ -111,7 +135,7 @@ private void InvalidateImage() AllDirty = true; lock (dirtyLock) { - DirtyRomBytes.Clear(); + dirtyRomBytes.Clear(); } RegenerateImage(); @@ -131,24 +155,32 @@ private void RegenerateImage() return; } - var totalHeight = BankHeightPixels * Data.GetNumberOfBanks(); - var totalWidth = BankWidthPixels; - - var shouldRecreateBitmap = bitmap == null || - bitmap.Width != totalWidth || - bitmap.Height != totalHeight; + var h = Height; + var w = Width; + var shouldRecreateBitmap = bitmap == null || bitmap.Width != w || bitmap.Height != h; if (shouldRecreateBitmap) - bitmap = new Bitmap(totalWidth, totalHeight); + bitmap = new Bitmap(w, h); var romBytes = ConsumeRomDirtyBytes(); + var currentPixel = 0; var fastBitmap = new FastBitmap(bitmap); // needs compiler flag "/unsafe" enabled using (fastBitmap.Lock()) { foreach (var romByte in romBytes) { - SetPixel(romByte, fastBitmap, totalWidth); + SetPixel(romByte, fastBitmap); + ++currentPixel; + } + + // rom bytes may not fully fill up the last row. fill it in with + // blank pixels + while (currentPixel < w*h) + { + var (x, y) = ConvertPixelIndexToXY(currentPixel); + fastBitmap.SetPixel(x, y, Color.SlateGray); + ++currentPixel; } } @@ -168,22 +200,33 @@ private IEnumerable ConsumeRomDirtyBytes() lock (dirtyLock) { // make a copy so we can release the lock. - romBytes = new List(DirtyRomBytes.Values.Select(kvp => kvp)); - DirtyRomBytes.Clear(); + romBytes = new List(dirtyRomBytes.Values.Select(kvp => kvp)); + dirtyRomBytes.Clear(); } return romBytes; } - private static void SetPixel(ROMByte romByte, FastBitmap fastBitmap, int bankWidthPixels) + private (int x, int y) ConvertPixelIndexToXY(int offset) { - var romOffset = romByte.Offset; - var y = romOffset / bankWidthPixels; - var x = romOffset - (y * bankWidthPixels); + var y = offset / Width; + var x = offset - (y * Width); + return (x, y); + } + + private void SetPixel(ROMByte romByte, FastBitmap fastBitmap) + { + var pixelIndex = ConvertRomOffsetToPixelIndex(romByte.Offset); + var (x, y) = ConvertPixelIndexToXY(pixelIndex); var color = Util.GetColorFromFlag(romByte.TypeFlag); fastBitmap.SetPixel(x, y, color); } + private int ConvertRomOffsetToPixelIndex(int romByteOffset) + { + return romByteOffset - RomStartingOffset; + } + protected virtual void OnBitmapUpdated() { ImageDataUpdated?.Invoke(this, EventArgs.Empty); @@ -193,10 +236,10 @@ protected virtual void MarkDirty(ROMByte romByte) { lock (dirtyLock) { - if (!DirtyRomBytes.ContainsKey(romByte.Offset)) - DirtyRomBytes.Add(romByte.Offset, romByte); + if (!dirtyRomBytes.ContainsKey(romByte.Offset)) + dirtyRomBytes.Add(romByte.Offset, romByte); else - DirtyRomBytes[romByte.Offset] = romByte; + dirtyRomBytes[romByte.Offset] = romByte; } MarkedDirty?.Invoke(this, EventArgs.Empty); diff --git a/DiztinGUIsh/window/MainWindow.Designer.cs b/DiztinGUIsh/window/MainWindow.Designer.cs index 0f036084..06acf562 100644 --- a/DiztinGUIsh/window/MainWindow.Designer.cs +++ b/DiztinGUIsh/window/MainWindow.Designer.cs @@ -70,7 +70,6 @@ private void InitializeComponent() this.importCDLToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator(); this.importTraceLogText = new System.Windows.Forms.ToolStripMenuItem(); - this.importTraceLogBinary = new System.Windows.Forms.ToolStripMenuItem(); this.exportLogToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator(); this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -140,6 +139,8 @@ private void InitializeComponent() this.openUsageMapFile = new System.Windows.Forms.OpenFileDialog(); this.openTraceLogDialog = new System.Windows.Forms.OpenFileDialog(); this.openCDLDialog = new System.Windows.Forms.OpenFileDialog(); + this.importCaptureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.importTraceLogBinary = new System.Windows.Forms.ToolStripMenuItem(); ((System.ComponentModel.ISupportInitialize)(this.table)).BeginInit(); this.menuStrip1.SuspendLayout(); this.statusStrip1.SuspendLayout(); @@ -437,8 +438,7 @@ private void InitializeComponent() this.importUsageMapToolStripMenuItem, this.importCDLToolStripMenuItem, this.toolStripSeparator8, - this.importTraceLogText, - this.importTraceLogBinary}); + this.importTraceLogText}); this.toolStripMenuItem2.Name = "toolStripMenuItem2"; this.toolStripMenuItem2.Size = new System.Drawing.Size(235, 22); this.toolStripMenuItem2.Text = "Import"; @@ -447,7 +447,7 @@ private void InitializeComponent() // this.importUsageMapToolStripMenuItem.Enabled = false; this.importUsageMapToolStripMenuItem.Name = "importUsageMapToolStripMenuItem"; - this.importUsageMapToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.importUsageMapToolStripMenuItem.Size = new System.Drawing.Size(218, 22); this.importUsageMapToolStripMenuItem.Text = "Import BSNES Usage Map..."; this.importUsageMapToolStripMenuItem.Click += new System.EventHandler(this.importUsageMapToolStripMenuItem_Click_1); // @@ -456,31 +456,23 @@ private void InitializeComponent() this.importCDLToolStripMenuItem.Enabled = false; this.importCDLToolStripMenuItem.Name = "importCDLToolStripMenuItem"; this.importCDLToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.I))); - this.importCDLToolStripMenuItem.Size = new System.Drawing.Size(253, 22); + this.importCDLToolStripMenuItem.Size = new System.Drawing.Size(218, 22); this.importCDLToolStripMenuItem.Text = "Import CDL..."; this.importCDLToolStripMenuItem.Click += new System.EventHandler(this.importCDLToolStripMenuItem_Click_1); // // toolStripSeparator8 // this.toolStripSeparator8.Name = "toolStripSeparator8"; - this.toolStripSeparator8.Size = new System.Drawing.Size(250, 6); + this.toolStripSeparator8.Size = new System.Drawing.Size(215, 6); // // importTraceLogText // this.importTraceLogText.Enabled = false; this.importTraceLogText.Name = "importTraceLogText"; - this.importTraceLogText.Size = new System.Drawing.Size(253, 22); + this.importTraceLogText.Size = new System.Drawing.Size(218, 22); this.importTraceLogText.Text = "Import BSNES Trace Log..."; this.importTraceLogText.Click += new System.EventHandler(this.toolStripMenuItem3_Click); // - // importTraceLogBinary - // - this.importTraceLogBinary.Enabled = false; - this.importTraceLogBinary.Name = "importTraceLogBinary"; - this.importTraceLogBinary.Size = new System.Drawing.Size(253, 22); - this.importTraceLogBinary.Text = "Import BSNES Trace Log (Binary)..."; - this.importTraceLogBinary.Click += new System.EventHandler(this.toolStripMenuItem1_Click); - // // exportLogToolStripMenuItem // this.exportLogToolStripMenuItem.Enabled = false; @@ -843,7 +835,8 @@ private void InitializeComponent() this.graphicsWindowToolStripMenuItem, this.constantsToolStripMenuItem, this.optionsToolStripMenuItem, - this.labelListToolStripMenuItem}); + this.labelListToolStripMenuItem, + this.importCaptureToolStripMenuItem}); this.viewToolStripMenuItem.Name = "viewToolStripMenuItem"; this.viewToolStripMenuItem.Size = new System.Drawing.Size(46, 20); this.viewToolStripMenuItem.Text = "&Tools"; @@ -1034,6 +1027,22 @@ private void InitializeComponent() // this.openCDLDialog.Filter = "BizHawk Code Data Logger Files|*.cdl|All Files|*.*"; // + // importCaptureToolStripMenuItem + // + this.importCaptureToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.importTraceLogBinary}); + this.importCaptureToolStripMenuItem.Name = "importCaptureToolStripMenuItem"; + this.importCaptureToolStripMenuItem.Size = new System.Drawing.Size(212, 22); + this.importCaptureToolStripMenuItem.Text = "Live Capture"; + // + // importTraceLogBinary + // + this.importTraceLogBinary.Enabled = false; + this.importTraceLogBinary.Name = "importTraceLogBinary"; + this.importTraceLogBinary.Size = new System.Drawing.Size(207, 22); + this.importTraceLogBinary.Text = "BSNESPlus Trace Logging"; + this.importTraceLogBinary.Click += new System.EventHandler(this.importTraceLogBinary_Click); + // // MainWindow // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); @@ -1161,6 +1170,7 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem importCDLToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator8; private System.Windows.Forms.ToolStripMenuItem importTraceLogText; + private System.Windows.Forms.ToolStripMenuItem importCaptureToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem importTraceLogBinary; } } diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index e3f8a7b7..4f022cef 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -1189,6 +1189,8 @@ private void importUsageMapToolStripMenuItem_Click_1(object sender, EventArgs e) private void toolStripMenuItem3_Click(object sender, EventArgs e) { + // TODO: differentiate between binary and text format + openTraceLogDialog.Multiselect = true; if (openTraceLogDialog.ShowDialog() != DialogResult.OK) return; @@ -1199,14 +1201,6 @@ private void toolStripMenuItem3_Click(object sender, EventArgs e) MessageBoxButtons.OK, MessageBoxIcon.Information); } - private void toolStripMenuItem1_Click(object sender, EventArgs e) - { - var bsnesForm = new BSNESTraceLogBinaryMonitorForm(this); - bsnesForm.ShowDialog(); - - RefreshUI(); - } - private void importCDLToolStripMenuItem_Click_1(object sender, EventArgs e) { openCDLDialog.InitialDirectory = Project.ProjectFileName; @@ -1235,5 +1229,13 @@ private void importCDLToolStripMenuItem_Click_1(object sender, EventArgs e) UpdateWindowTitle(); InvalidateTable(); } + + private void importTraceLogBinary_Click(object sender, EventArgs e) + { + var bsnesForm = new BSNESTraceLogBinaryMonitorForm(this); + bsnesForm.ShowDialog(); + + RefreshUI(); + } } } \ No newline at end of file diff --git a/DiztinGUIsh/window/VisualizerForm.Designer.cs b/DiztinGUIsh/window/VisualizerForm.Designer.cs index 44a2149b..0f12feaf 100644 --- a/DiztinGUIsh/window/VisualizerForm.Designer.cs +++ b/DiztinGUIsh/window/VisualizerForm.Designer.cs @@ -30,8 +30,8 @@ private void InitializeComponent() { this.panelTop = new System.Windows.Forms.Panel(); this.panelLegend = new System.Windows.Forms.Panel(); - this.panelBottom = new System.Windows.Forms.Panel(); this.bankLegend1 = new DiztinGUIsh.window.usercontrols.BankLegend(); + this.panelBottom = new System.Windows.Forms.Panel(); this.romImage1 = new DiztinGUIsh.window.usercontrols.RomImage(); this.panelTop.SuspendLayout(); this.panelLegend.SuspendLayout(); @@ -40,11 +40,12 @@ private void InitializeComponent() // // panelTop // + this.panelTop.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.panelTop.Controls.Add(this.panelLegend); this.panelTop.Dock = System.Windows.Forms.DockStyle.Top; this.panelTop.Location = new System.Drawing.Point(0, 0); this.panelTop.Name = "panelTop"; - this.panelTop.Size = new System.Drawing.Size(846, 123); + this.panelTop.Size = new System.Drawing.Size(765, 154); this.panelTop.TabIndex = 1; // // panelLegend @@ -53,33 +54,34 @@ private void InitializeComponent() this.panelLegend.Dock = System.Windows.Forms.DockStyle.Left; this.panelLegend.Location = new System.Drawing.Point(0, 0); this.panelLegend.Name = "panelLegend"; - this.panelLegend.Size = new System.Drawing.Size(567, 123); + this.panelLegend.Size = new System.Drawing.Size(567, 152); this.panelLegend.TabIndex = 0; // + // bankLegend1 + // + this.bankLegend1.AutoScroll = true; + this.bankLegend1.Dock = System.Windows.Forms.DockStyle.Fill; + this.bankLegend1.Location = new System.Drawing.Point(0, 0); + this.bankLegend1.Name = "bankLegend1"; + this.bankLegend1.Size = new System.Drawing.Size(567, 152); + this.bankLegend1.TabIndex = 0; + // // panelBottom // this.panelBottom.AutoScroll = true; this.panelBottom.AutoSize = true; this.panelBottom.Controls.Add(this.romImage1); this.panelBottom.Dock = System.Windows.Forms.DockStyle.Fill; - this.panelBottom.Location = new System.Drawing.Point(0, 123); + this.panelBottom.Location = new System.Drawing.Point(0, 154); this.panelBottom.Name = "panelBottom"; - this.panelBottom.Size = new System.Drawing.Size(846, 401); + this.panelBottom.Size = new System.Drawing.Size(765, 363); this.panelBottom.TabIndex = 2; // - // bankLegend1 - // - this.bankLegend1.AutoScroll = true; - this.bankLegend1.Dock = System.Windows.Forms.DockStyle.Fill; - this.bankLegend1.Location = new System.Drawing.Point(0, 0); - this.bankLegend1.Name = "bankLegend1"; - this.bankLegend1.Size = new System.Drawing.Size(567, 123); - this.bankLegend1.TabIndex = 0; - // // romImage1 // - this.romImage1.Location = new System.Drawing.Point(12, 6); + this.romImage1.Location = new System.Drawing.Point(0, 0); this.romImage1.Name = "romImage1"; + this.romImage1.Project = null; this.romImage1.Size = new System.Drawing.Size(854, 421); this.romImage1.TabIndex = 0; // @@ -88,7 +90,7 @@ private void InitializeComponent() this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScroll = true; - this.ClientSize = new System.Drawing.Size(846, 524); + this.ClientSize = new System.Drawing.Size(765, 517); this.Controls.Add(this.panelBottom); this.Controls.Add(this.panelTop); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow; diff --git a/DiztinGUIsh/window/usercontrols/BankLegend.Designer.cs b/DiztinGUIsh/window/usercontrols/BankLegend.Designer.cs index d87c5473..d143b6a0 100644 --- a/DiztinGUIsh/window/usercontrols/BankLegend.Designer.cs +++ b/DiztinGUIsh/window/usercontrols/BankLegend.Designer.cs @@ -44,6 +44,7 @@ private void InitializeComponent() this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScroll = true; + this.AutoSize = true; this.Controls.Add(this.flowLayoutPanel1); this.Name = "BankLegend"; this.Size = new System.Drawing.Size(472, 180); From dbf9a5728133586bd801b80c84dbded8876b2e94 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 24 Oct 2020 14:38:43 -0400 Subject: [PATCH 105/136] added new rom visualizer control, about to hook it up --- Diz.Core/model/Data.cs | 13 ++ DiztinGUIsh/DiztinGUIsh.csproj | 18 +++ DiztinGUIsh/window/VisualizerForm.cs | 3 - DiztinGUIsh/window/usercontrols/BankLegend.cs | 2 + .../window/usercontrols/BankLegendItem.cs | 2 + .../RomBankVisualizer.Designer.cs | 91 +++++++++++++ .../window/usercontrols/RomBankVisualizer.cs | 24 ++++ .../usercontrols/RomBankVisualizer.resx | 120 ++++++++++++++++++ .../RomFullVisualizer.Designer.cs | 61 +++++++++ .../window/usercontrols/RomFullVisualizer.cs | 65 ++++++++++ .../usercontrols/RomFullVisualizer.resx | 120 ++++++++++++++++++ .../window/usercontrols/RomImage.Designer.cs | 2 +- DiztinGUIsh/window/usercontrols/RomImage.cs | 14 +- 13 files changed, 524 insertions(+), 11 deletions(-) create mode 100644 DiztinGUIsh/window/usercontrols/RomBankVisualizer.Designer.cs create mode 100644 DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs create mode 100644 DiztinGUIsh/window/usercontrols/RomBankVisualizer.resx create mode 100644 DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs create mode 100644 DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs create mode 100644 DiztinGUIsh/window/usercontrols/RomFullVisualizer.resx diff --git a/Diz.Core/model/Data.cs b/Diz.Core/model/Data.cs index 98dc4976..762feeff 100644 --- a/Diz.Core/model/Data.cs +++ b/Diz.Core/model/Data.cs @@ -551,5 +551,18 @@ public int GetNumberOfBanks() { return RomBytes.Count / GetBankSize(); } + + public string GetBankName(int bankIndex) + { + var bankSnesByte = GetSNESBankByte(bankIndex); + return Util.NumberToBaseString(bankSnesByte, Util.NumberBase.Hexadecimal, 2); + } + + private int GetSNESBankByte(int bankIndex) + { + var bankStartingPCOffset = bankIndex << 16; + var bankSNESNumber = ConvertPCtoSNES(bankStartingPCOffset) >> 16; + return bankSNESNumber; + } } } diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 48a61b27..2851e4bd 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -239,6 +239,18 @@ BankLegendItem.cs + + UserControl + + + RomBankVisualizer.cs + + + UserControl + + + RomFullVisualizer.cs + UserControl @@ -304,6 +316,12 @@ BankLegendItem.cs + + RomBankVisualizer.cs + + + RomFullVisualizer.cs + RomImage.cs diff --git a/DiztinGUIsh/window/VisualizerForm.cs b/DiztinGUIsh/window/VisualizerForm.cs index 82ec557e..64001819 100644 --- a/DiztinGUIsh/window/VisualizerForm.cs +++ b/DiztinGUIsh/window/VisualizerForm.cs @@ -32,9 +32,6 @@ private void RomImage1_RedrawOccurred(object sender, System.EventArgs e) { if (!(sender is RomImage romImage)) return; - - romImage1.Width = romImage.ROMVisual.Bitmap.Width; - romImage1.Height = romImage.ROMVisual.Bitmap.Height; } private void VisualizerForm_Load(object sender, System.EventArgs e) diff --git a/DiztinGUIsh/window/usercontrols/BankLegend.cs b/DiztinGUIsh/window/usercontrols/BankLegend.cs index c0ccccfc..b505714c 100644 --- a/DiztinGUIsh/window/usercontrols/BankLegend.cs +++ b/DiztinGUIsh/window/usercontrols/BankLegend.cs @@ -3,6 +3,8 @@ using Diz.Core.model; using Diz.Core.util; +// shows all the legend items in a collection + namespace DiztinGUIsh.window.usercontrols { public partial class BankLegend : UserControl diff --git a/DiztinGUIsh/window/usercontrols/BankLegendItem.cs b/DiztinGUIsh/window/usercontrols/BankLegendItem.cs index d17d8158..7889356c 100644 --- a/DiztinGUIsh/window/usercontrols/BankLegendItem.cs +++ b/DiztinGUIsh/window/usercontrols/BankLegendItem.cs @@ -1,6 +1,8 @@ using System.Drawing; using System.Windows.Forms; +// just shows one color and one label for Rom visualizer. like ("blue" = 8bit pointer) + namespace DiztinGUIsh.window.usercontrols { public partial class BankLegendItem : UserControl diff --git a/DiztinGUIsh/window/usercontrols/RomBankVisualizer.Designer.cs b/DiztinGUIsh/window/usercontrols/RomBankVisualizer.Designer.cs new file mode 100644 index 00000000..851ddd97 --- /dev/null +++ b/DiztinGUIsh/window/usercontrols/RomBankVisualizer.Designer.cs @@ -0,0 +1,91 @@ +namespace DiztinGUIsh.window.usercontrols +{ + partial class RomBankVisualizer + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.lblBankName = new System.Windows.Forms.Label(); + this.romImage1 = new DiztinGUIsh.window.usercontrols.RomImage(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // lblBankName + // + this.lblBankName.AutoSize = true; + this.lblBankName.Font = new System.Drawing.Font("Microsoft Sans Serif", 20.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblBankName.Location = new System.Drawing.Point(3, 0); + this.lblBankName.Name = "lblBankName"; + this.lblBankName.Size = new System.Drawing.Size(51, 31); + this.lblBankName.TabIndex = 0; + this.lblBankName.Text = "C0"; + // + // romImage1 + // + this.romImage1.Dock = System.Windows.Forms.DockStyle.Fill; + this.romImage1.Location = new System.Drawing.Point(60, 3); + this.romImage1.Name = "romImage1"; + this.romImage1.Project = null; + this.romImage1.Size = new System.Drawing.Size(663, 165); + this.romImage1.TabIndex = 1; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.Controls.Add(this.romImage1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.lblBankName, 0, 0); + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 1; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(726, 171); + this.tableLayoutPanel1.TabIndex = 2; + // + // RomBankVisualizer + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoSize = true; + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.Controls.Add(this.tableLayoutPanel1); + this.Name = "RomBankVisualizer"; + this.Size = new System.Drawing.Size(729, 174); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label lblBankName; + private RomImage romImage1; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + } +} diff --git a/DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs b/DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs new file mode 100644 index 00000000..63c96f6f --- /dev/null +++ b/DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs @@ -0,0 +1,24 @@ +using System.Windows.Forms; +using Diz.Core.model; + +// this usercontrol shows: +// 1) a visual of one bank of ROM data +// 2) other GUI elements (like a label for the bank name) +// +// If you create a bunch of these you can view the entire ROM as a series of banks + +namespace DiztinGUIsh.window.usercontrols +{ + public partial class RomBankVisualizer : UserControl + { + public RomBankVisualizer(Project project, int startingRomOffset, int length, string bankName) + { + InitializeComponent(); + + romImage1.Project = project; + romImage1.ROMVisual.RomStartingOffset = startingRomOffset; + romImage1.ROMVisual.LengthOverride = length; + lblBankName.Text = bankName; + } + } +} diff --git a/DiztinGUIsh/window/usercontrols/RomBankVisualizer.resx b/DiztinGUIsh/window/usercontrols/RomBankVisualizer.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/DiztinGUIsh/window/usercontrols/RomBankVisualizer.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs new file mode 100644 index 00000000..7258c388 --- /dev/null +++ b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs @@ -0,0 +1,61 @@ +namespace DiztinGUIsh.window.usercontrols +{ + partial class RomFullVisualizer + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); + this.SuspendLayout(); + // + // flowLayoutPanel1 + // + this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; + this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.flowLayoutPanel1.MinimumSize = new System.Drawing.Size(100, 100); + this.flowLayoutPanel1.Name = "flowLayoutPanel1"; + this.flowLayoutPanel1.Size = new System.Drawing.Size(100, 100); + this.flowLayoutPanel1.TabIndex = 0; + // + // RomFullVisualizer + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.Controls.Add(this.flowLayoutPanel1); + this.MaximumSize = new System.Drawing.Size(100, 100); + this.Name = "RomFullVisualizer"; + this.Size = new System.Drawing.Size(100, 100); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; + } +} diff --git a/DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs new file mode 100644 index 00000000..aff0ff1e --- /dev/null +++ b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs @@ -0,0 +1,65 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Windows.Forms; +using Diz.Core.model; + +// shows a collection of bank controls, so you can visualize the entire ROM + +namespace DiztinGUIsh.window.usercontrols +{ + public partial class RomFullVisualizer : UserControl + { + private Project project; + public Data Data => project?.Data; + public Project Project + { + get => project; + set + { + UpdateControls(); + project = value; + } + } + + private void UpdateControls() + { + foreach (var rbv in BankControls) + { + // TODO + } + } + + public RomFullVisualizer() + { + InitializeComponent(); + } + + public List BankControls = new List(); + + public void Init() + { + Debug.Assert(project != null); + + var bankSizeBytes = Data.GetBankSize(); + + for (var bank = 0; bank < Data.GetNumberOfBanks(); bank++) + { + var bankOffset = bank * bankSizeBytes; + var bankName = Data.GetBankName(bank); + + var bankControl = new RomBankVisualizer(project, bankOffset, bankSizeBytes, bankName); + + AddNewControl(bankControl); + } + } + + private void AddNewControl(RomBankVisualizer bankControl) + { + BankControls.Add(bankControl); + + flowLayoutPanel1.Controls.Add(bankControl); + flowLayoutPanel1.AutoSize = true; + flowLayoutPanel1.AutoSizeMode = AutoSizeMode.GrowAndShrink; + } + } +} diff --git a/DiztinGUIsh/window/usercontrols/RomFullVisualizer.resx b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/DiztinGUIsh/window/usercontrols/RomImage.Designer.cs b/DiztinGUIsh/window/usercontrols/RomImage.Designer.cs index 3551f867..c20aa7cc 100644 --- a/DiztinGUIsh/window/usercontrols/RomImage.Designer.cs +++ b/DiztinGUIsh/window/usercontrols/RomImage.Designer.cs @@ -44,7 +44,7 @@ private void InitializeComponent() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.DoubleBuffered = true; this.Name = "RomImage"; - this.Size = new System.Drawing.Size(321, 255); + this.Size = new System.Drawing.Size(996, 178); this.Load += new System.EventHandler(this.RomImage_Load); this.Paint += new System.Windows.Forms.PaintEventHandler(this.RomImage_Paint); this.ResumeLayout(false); diff --git a/DiztinGUIsh/window/usercontrols/RomImage.cs b/DiztinGUIsh/window/usercontrols/RomImage.cs index 457075ef..f58da1e4 100644 --- a/DiztinGUIsh/window/usercontrols/RomImage.cs +++ b/DiztinGUIsh/window/usercontrols/RomImage.cs @@ -4,6 +4,8 @@ using Diz.Core.model; using Diz.Core.util; +// this usercontrol is JUST to show the raw image data (no markup, formatting, etc) + namespace DiztinGUIsh.window.usercontrols { public partial class RomImage : UserControl @@ -11,16 +13,11 @@ public partial class RomImage : UserControl public event EventHandler RedrawOccurred; public RomVisual ROMVisual { get; } = new RomVisual(); - private Project project; public Project Project { - get => project; - set - { - project = value; - ROMVisual.Project = project; - } + get => ROMVisual.Project; + set => ROMVisual.Project = value; } public RomImage() @@ -68,6 +65,9 @@ private void timer1_Tick(object sender, System.EventArgs e) protected virtual void OnRedrawOccurred() { + Width = ROMVisual.Width; + Height = ROMVisual.Height; + RedrawOccurred?.Invoke(this, EventArgs.Empty); } } From f9cb3af6b90787b62da18b5ea6ef124956b42267 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 24 Oct 2020 15:40:27 -0400 Subject: [PATCH 106/136] shave ~2 seconds off loading --- Diz.Core/model/RomBytes.cs | 26 ++++++++++++++++--- .../xml_serializer/RomBytesXMLSerializer.cs | 19 +++++++++----- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/Diz.Core/model/RomBytes.cs b/Diz.Core/model/RomBytes.cs index e4714a9e..61c52ea7 100644 --- a/Diz.Core/model/RomBytes.cs +++ b/Diz.Core/model/RomBytes.cs @@ -10,12 +10,28 @@ namespace Diz.Core.model { public class RomBytes : IEnumerable, INotifyCollectionChanged, INotifyPropertyChanged { + private ObservableCollection bytes; + // TODO: might be able to do something more generic now that other refactorings are completed. // // This class needs to do these things that are special: // 1) Be handled specially by our custom XML serializer (compresses to save disk space) // 2) Handle Equals() by comparing each element in the list (SequenceEqual) - public ObservableCollection Bytes { get; } = new ObservableCollection(); + private ObservableCollection Bytes + { + get => bytes; + set + { + bytes = value; + + bytes.CollectionChanged += Bytes_CollectionChanged; + foreach (var romByte in bytes) + { + romByte.PropertyChanged += RomByteObjectChanged; + } + } + } + public ROMByte this[int i] { get => Bytes[i]; @@ -24,8 +40,12 @@ public ROMByte this[int i] public RomBytes() { - // Bytes.PropertyChanged += Bytes_PropertyChanged; - Bytes.CollectionChanged += Bytes_CollectionChanged; + Bytes = new ObservableCollection(); + } + + public void SetFrom(ROMByte[] romBytes) + { + Bytes = new ObservableCollection(romBytes); } public int Count => Bytes.Count; diff --git a/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs b/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs index 4212963c..9cc7ea3d 100644 --- a/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs +++ b/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs @@ -38,8 +38,6 @@ sealed class RomBytesSerializer : ISerializer public RomBytes Get(IFormatReader parameter) { - var romBytesOut = new RomBytes(); - var lines = parameter.Content().Split(new char[] { '\n' }, 3).ToList(); var options = lines[1].Split(new char[] { ',' }).ToList(); lines = lines[2].Split(new char[] { '\n' }).ToList(); @@ -55,12 +53,17 @@ public RomBytes Get(IFormatReader parameter) if (options.Exists(s => s == "compress_groupblocks")) DecodeCompression_GroupsBlocks(ref lines); - int lineNum = 0; + // perf: allocate all at once, don't use List.Add() one at a time + var capacity = lines.Count; + var romBytes = new ROMByte[capacity]; + + var lineNum = 0; try { + // TODO: romBytesOut.SendNotificationChangedEvents = false; foreach (var line in lines) { - romBytesOut.Add(DecodeRomByte(line)); + romBytes[lineNum] = DecodeRomByte(line); lineNum++; } } @@ -70,6 +73,8 @@ public RomBytes Get(IFormatReader parameter) throw; } + var romBytesOut = new RomBytes(); + romBytesOut.SetFrom(romBytes); return romBytesOut; } @@ -116,11 +121,11 @@ public void Write(IFormatWriter writer, RomBytes instance) var lines = new List(); foreach (var rb in instance) { - var encoded = EncodeByte(rb); - lines.Add(encoded); + var encodedTxt = EncodeByte(rb); + lines.Add(encodedTxt); // debug check, optional: - var decoded = DecodeRomByte(encoded); + var decoded = DecodeRomByte(encodedTxt); Debug.Assert(decoded.EqualsButNoRomByte(rb)); } From 0890539d5c47f17997c6890bf87519061d2d41f8 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 25 Oct 2020 08:29:39 -0400 Subject: [PATCH 107/136] remove dead datasources --- DiztinGUIsh/DiztinGUIsh.csproj | 7 ++--- ...UIsh.loadsave.ImportRomSettings.datasource | 21 -------------- ...og.ImportRomDialog+EnumMapper`1.datasource | 10 ------- ...ortRomDialog+ImportRomViewModel.datasource | 29 ------------------- 4 files changed, 3 insertions(+), 64 deletions(-) delete mode 100644 DiztinGUIsh/Properties/DataSources/DiztinGUIsh.loadsave.ImportRomSettings.datasource delete mode 100644 DiztinGUIsh/Properties/DataSources/DiztinGUIsh.window.dialog.ImportRomDialog+EnumMapper`1.datasource delete mode 100644 DiztinGUIsh/Properties/DataSources/DiztinGUIsh.window.dialog.ImportRomDialog+ImportRomViewModel.datasource diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 2851e4bd..174b38e3 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -350,9 +350,6 @@ - - - SettingsSingleFileGenerator Settings.Designer.cs @@ -391,7 +388,9 @@ Diz.Core
- + + + diff --git a/DiztinGUIsh/Properties/DataSources/DiztinGUIsh.loadsave.ImportRomSettings.datasource b/DiztinGUIsh/Properties/DataSources/DiztinGUIsh.loadsave.ImportRomSettings.datasource deleted file mode 100644 index 5cd28ffa..00000000 --- a/DiztinGUIsh/Properties/DataSources/DiztinGUIsh.loadsave.ImportRomSettings.datasource +++ /dev/null @@ -1,21 +0,0 @@ - - - - DiztinGUIsh.loadsave.ImportRomSettings, DiztinGUIsh, Version=1.0.69.0, Culture=neutral, PublicKeyToken=null - - - - - - - - - - - - \ No newline at end of file diff --git a/DiztinGUIsh/Properties/DataSources/DiztinGUIsh.window.dialog.ImportRomDialog+EnumMapper`1.datasource b/DiztinGUIsh/Properties/DataSources/DiztinGUIsh.window.dialog.ImportRomDialog+EnumMapper`1.datasource deleted file mode 100644 index d2491cf1..00000000 --- a/DiztinGUIsh/Properties/DataSources/DiztinGUIsh.window.dialog.ImportRomDialog+EnumMapper`1.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - DiztinGUIsh.window.dialog.ImportRomDialog+EnumMapper`1, DiztinGUIsh, Version=1.0.69.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/DiztinGUIsh/Properties/DataSources/DiztinGUIsh.window.dialog.ImportRomDialog+ImportRomViewModel.datasource b/DiztinGUIsh/Properties/DataSources/DiztinGUIsh.window.dialog.ImportRomDialog+ImportRomViewModel.datasource deleted file mode 100644 index 08e8d697..00000000 --- a/DiztinGUIsh/Properties/DataSources/DiztinGUIsh.window.dialog.ImportRomDialog+ImportRomViewModel.datasource +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - DiztinGUIsh.window.dialog.ImportRomDialog+EnumMapper`1[[DiztinGUIsh.Data+ROMMapMode, DiztinGUIsh, Version=1.0.69.0, Culture=neutral, PublicKeyToken=null]], DiztinGUIsh, Version=1.0.69.0, Culture=neutral, PublicKeyToken=null - - - - - - - - - - - - - - System.Collections.Generic.KeyValuePair`2[[DiztinGUIsh.Data+ROMMapMode, DiztinGUIsh, Version=1.0.69.0, Culture=neutral, PublicKeyToken=null],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - DiztinGUIsh.window.dialog.ImportRomDialog+ImportRomViewModel, DiztinGUIsh, Version=1.0.69.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file From 02d300ccc243b508970b8caac0c1c4c66d22e5b2 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 25 Oct 2020 08:29:59 -0400 Subject: [PATCH 108/136] remove dead code --- Diz.Core/import/BSNESTraceLogCapture.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Diz.Core/import/BSNESTraceLogCapture.cs b/Diz.Core/import/BSNESTraceLogCapture.cs index 394c45b4..96398a4a 100644 --- a/Diz.Core/import/BSNESTraceLogCapture.cs +++ b/Diz.Core/import/BSNESTraceLogCapture.cs @@ -63,8 +63,6 @@ private void Setup(Data data) private static NetworkStream Connect() { var tcpClient = new TcpClient(); - //await tcpClient.ConnectAsync(IPAddress.Loopback, 27015); - //return tcpClient.GetStream(); tcpClient.Connect(IPAddress.Loopback, 27015); return tcpClient.GetStream(); } From 6e872915fb3e9016d6ad3138685e74b0dd85303b Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 25 Oct 2020 08:31:30 -0400 Subject: [PATCH 109/136] optimization: shave ~6 seconds off project load - use multiple threads - replace a bunch of slow string manipulation - write some tests for various save/load systems --- Diz.Core/Diz.Core.csproj | 4 + Diz.Core/serialization/ProjectSerializer.cs | 2 +- .../xml_serializer/ProjectXMLSerializer.cs | 2 +- .../xml_serializer/RepeaterCompression.cs | 104 +++++ .../xml_serializer/RomByteEncoding.cs | 220 +++++++++ .../xml_serializer/RomBytesXMLSerializer.cs | 433 ++++-------------- .../xml_serializer/SubstitutionCompression.cs | 62 +++ Diz.Core/util/Fake64Encoding.cs | 87 ++++ Diz.Test/CompressionTest.cs | 45 ++ Diz.Test/Diz.Test.csproj | 5 +- Diz.Test/Fake64Test.cs | 44 ++ Diz.Test/LoadSaveTest.cs | 31 ++ ...zerTest.cs => SerializerDictionaryTest.cs} | 4 +- DiztinGUIsh/controller/ProjectController.cs | 12 +- 14 files changed, 706 insertions(+), 349 deletions(-) create mode 100644 Diz.Core/serialization/xml_serializer/RepeaterCompression.cs create mode 100644 Diz.Core/serialization/xml_serializer/RomByteEncoding.cs create mode 100644 Diz.Core/serialization/xml_serializer/SubstitutionCompression.cs create mode 100644 Diz.Core/util/Fake64Encoding.cs create mode 100644 Diz.Test/CompressionTest.cs create mode 100644 Diz.Test/Fake64Test.cs create mode 100644 Diz.Test/LoadSaveTest.cs rename Diz.Test/{SerializerTest.cs => SerializerDictionaryTest.cs} (96%) diff --git a/Diz.Core/Diz.Core.csproj b/Diz.Core/Diz.Core.csproj index 0e76a919..1f8d895d 100644 --- a/Diz.Core/Diz.Core.csproj +++ b/Diz.Core/Diz.Core.csproj @@ -126,6 +126,10 @@ + + + + diff --git a/Diz.Core/serialization/ProjectSerializer.cs b/Diz.Core/serialization/ProjectSerializer.cs index f543f890..17772d57 100644 --- a/Diz.Core/serialization/ProjectSerializer.cs +++ b/Diz.Core/serialization/ProjectSerializer.cs @@ -4,7 +4,7 @@ namespace Diz.Core.serialization { - abstract class ProjectSerializer + public abstract class ProjectSerializer { public const string Watermark = "DiztinGUIsh"; diff --git a/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs b/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs index 17a931a6..6f220f25 100644 --- a/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs +++ b/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs @@ -7,7 +7,7 @@ namespace Diz.Core.serialization.xml_serializer { - internal class ProjectXmlSerializer : ProjectSerializer + public class ProjectXmlSerializer : ProjectSerializer { // NEVER CHANGE THIS ONE. private const int FIRST_SAVE_FORMAT_VERSION = 100; diff --git a/Diz.Core/serialization/xml_serializer/RepeaterCompression.cs b/Diz.Core/serialization/xml_serializer/RepeaterCompression.cs new file mode 100644 index 00000000..12ced66e --- /dev/null +++ b/Diz.Core/serialization/xml_serializer/RepeaterCompression.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Diz.Core.serialization.xml_serializer +{ + public class RepeaterCompression + { + public static void Decompress(ref List lines) + { + var output = new List(); + + foreach (var line in lines) + { + if (!line.StartsWith("r")) + { + output.Add(line); + continue; + } + + var split = line.Split(' '); + if (split.Length != 3) + throw new InvalidDataException("Invalid repeater command"); + + var count = int.Parse(split[1]); + for (int i = 0; i < count; ++i) + { + output.Add(split[2]); + } + } + + lines = output; + } + + public static void Compress(ref List lines) + { + if (lines.Count < 8) + return; // forget it, too small to care. + + var output = new List(); + + var lastLine = lines[0]; + var consecutive = 1; + + // adjustable, just pick something > 8 or it's not worth the optimization. + // we want to catch large consecutive blocks of data. + const int min_number_repeats_before_we_bother = 8; + + int totalLinesDebug = 0; + + for (var i = 1; i < lines.Count; ++i) + { + var line = lines[i]; + Debug.Assert(!line.StartsWith("r")); + + bool different = line != lastLine; + bool finalLine = i == lines.Count - 1; + + if (!different) + { + consecutive++; + + if (!finalLine) + continue; + + // special case for the final line. + // since our loop only ever prints out the LAST line, we have to handle this separately. + consecutive++; + } + + if (consecutive >= min_number_repeats_before_we_bother) + { + // replace multiple repeated lines with one new statement + output.Add($"r {consecutive.ToString()} {lastLine}"); + } + else + { + // output 1 or more copies of the last line + // this is also how we print single lines too + output.AddRange(Enumerable.Repeat(lastLine, consecutive).ToList()); + } + + if (finalLine && different) + { + output.Add(line); + totalLinesDebug++; + } + + totalLinesDebug += consecutive; + + lastLine = line; + consecutive = 1; + } + + Debug.Assert(totalLinesDebug == lines.Count); + + lines = output; + } + } +} diff --git a/Diz.Core/serialization/xml_serializer/RomByteEncoding.cs b/Diz.Core/serialization/xml_serializer/RomByteEncoding.cs new file mode 100644 index 00000000..62a9dcbd --- /dev/null +++ b/Diz.Core/serialization/xml_serializer/RomByteEncoding.cs @@ -0,0 +1,220 @@ +// #define EXTRA_DEBUG_CHECKS + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using Diz.Core.model; +using Diz.Core.util; + +namespace Diz.Core.serialization.xml_serializer +{ + public class RomByteEncoding + { + public class FlagEncodeEntry + { + public char c; + public Data.FlagType f; + }; + + // totally dumb but saves time vs slow Byte.Parse(x, isHex) + // idea credit: Daniel-Lemire + public static readonly int[] hexAsciiToDigit = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}; + + public static byte ByteParseHex1(char hexChar) + { + var result = hexAsciiToDigit[hexChar]; + if (result == -1) + throw new InvalidDataException("Invalid hex digit"); + + return (byte)result; + } + + public static byte ByteParseHex2(char hexChar1, char hexChar2) + { + var result = ByteParseHex1(hexChar1) * 0x10 + ByteParseHex1(hexChar2); + return (byte)result; + } + + public static int ByteParseHex4(char hexChar1, char hexChar2, char hexChar3, char hexChar4) + { + return + ByteParseHex1(hexChar1) * 0x1000 + + ByteParseHex1(hexChar2) * 0x100 + + ByteParseHex1(hexChar3) * 0x10 + + ByteParseHex1(hexChar4); + } + + private static readonly List flagEncodeTable = new List { + new FlagEncodeEntry() {f = Data.FlagType.Unreached, c = 'U'}, + + new FlagEncodeEntry() {f = Data.FlagType.Opcode, c = '+'}, + new FlagEncodeEntry() {f = Data.FlagType.Operand, c = '.'}, + + new FlagEncodeEntry() {f = Data.FlagType.Graphics, c = 'G'}, + new FlagEncodeEntry() {f = Data.FlagType.Music, c = 'M'}, + new FlagEncodeEntry() {f = Data.FlagType.Empty, c = 'X'}, + new FlagEncodeEntry() {f = Data.FlagType.Text, c = 'T'}, + + new FlagEncodeEntry() {f = Data.FlagType.Data8Bit, c = 'A'}, + new FlagEncodeEntry() {f = Data.FlagType.Data16Bit, c = 'B'}, + new FlagEncodeEntry() {f = Data.FlagType.Data24Bit, c = 'C'}, + new FlagEncodeEntry() {f = Data.FlagType.Data32Bit, c = 'D'}, + + new FlagEncodeEntry() {f = Data.FlagType.Pointer16Bit, c = 'E'}, + new FlagEncodeEntry() {f = Data.FlagType.Pointer24Bit, c = 'F'}, + new FlagEncodeEntry() {f = Data.FlagType.Pointer32Bit, c = 'G'}, + }; + + private readonly StringBuilder cachedPadSb = new StringBuilder(LineMaxLen); + + private const int LineMaxLen = 9; + + // note: performance-intensive function. be really careful when adding stuff here. + public ROMByte DecodeRomByte(string line) + { + var input = PrepLine(line); + + var newByte = new ROMByte(); + + var flagTxt = input[0]; + var otherFlags1 = Fake64Encoding.DecodeHackyBase64(input[1]); + newByte.DataBank = ByteParseHex2(input[2], input[3]); + newByte.DirectPage = ByteParseHex4(input[4], input[5], input[6], input[7]); + newByte.Arch = (Data.Architecture)(ByteParseHex1(input[8]) & 0x3); + + #if EXTRA_DEBUG_CHECKS + Debug.Assert(Fake64Encoding.EncodeHackyBase64(otherFlags1) == o1_str); + #endif + + newByte.XFlag = ((otherFlags1 >> 2) & 0x1) != 0; + newByte.MFlag = ((otherFlags1 >> 3) & 0x1) != 0; + newByte.Point = (Data.InOutPoint)((otherFlags1 >> 4) & 0xF); + + var found = false; + foreach (var e in flagEncodeTable) + { + if (e.c != flagTxt) + continue; + + newByte.TypeFlag = e.f; + found = true; + break; + } + if (!found) + throw new InvalidDataException("Unknown FlagType"); + + return newByte; + } + + // perf note: re-uses a cached StringBuilder for subsequent runs + private StringBuilder PrepLine(string line) + { + if (cachedPadSb.Length == 0) + cachedPadSb.Append("000000000"); // any 9 chars + + // light decompression. ensure our line is always 9 chars long. + // if any characters are missing, pad them with zeroes + // + // perf: string.PadRight() is simpler but too slow, so do it by hand + var inSize = line.Length; + for (var i = 0; i < LineMaxLen; ++i) + { + cachedPadSb[i] = i < inSize ? line[i] : '0'; + } + + Debug.Assert(cachedPadSb.Length == LineMaxLen); + + return cachedPadSb; + } + + public string EncodeByte(ROMByte instance) + { + // use a custom formatter here to save space. there are a LOT of ROMBytes. + // despite that we're still going for: + // 1) text only for slightly human readability + // 2) mergability in git/etc + // + // some of this can be unpacked further to increase readability without + // hurting the filesize too much. figure out what's useful. + // + // sorry, I know the encoding looks insane and weird and specific. this reduced my + // save file size from 42MB to less than 13MB + + // NOTE: must be uppercase letter or "=" or "-" + // if you add things here, make sure you understand the compression settings above. + var flagTxt = ' '; + foreach (var e in flagEncodeTable) + { + if (e.f == instance.TypeFlag) + { + flagTxt = e.c; + break; + } + } + + if (flagTxt == ' ') + throw new InvalidDataException("Unknown FlagType"); + + // max 6 bits if we want to fit in 1 base64 ASCII digit + byte otherFlags1 = (byte)( + (instance.XFlag ? 1 : 0) << 2 | // 1 bit + (instance.MFlag ? 1 : 0) << 3 | // 1 bit + (byte)instance.Point << 4 // 4 bits + // LEAVE OFF THE LAST 2 BITS. it'll mess with the base64 below + ); + // reminder: when decoding, have to cut off all but the first 6 bits + var o1_str = Fake64Encoding.EncodeHackyBase64(otherFlags1); + Debug.Assert(Fake64Encoding.DecodeHackyBase64(o1_str) == otherFlags1); + + if (!instance.XFlag && !instance.MFlag && instance.Point == 0) + { + Debug.Assert(o1_str == '0'); // sanity + } + + // this is basically going to be "0" almost 100% of the time. + // we'll put it on the end of the string so it's most likely not output + byte otherFlags2 = (byte)( + (byte)instance.Arch << 0 // 2 bits + ); + var o2_str = otherFlags2.ToString("X1"); Debug.Assert(o2_str.Length == 1); + + // ordering: put DB and D on the end, they're likely to be zero and compressible + var sb = new StringBuilder(9); + sb.Append(flagTxt); + sb.Append(o1_str); + sb.Append(instance.DataBank.ToString("X2")); + sb.Append(instance.DirectPage.ToString("X4")); + sb.Append(o2_str); + + Debug.Assert(sb.Length == 9); + var data = sb.ToString(); + + // light compression: chop off any trailing zeroes. + // this alone saves a giant amount of space. + data = data.TrimEnd(new char[] { '0' }); + + // future compression but dilutes readability: + // if type is opcode or operand with same flags, combine those into 1 type. + // i.e. take an opcode with 3 operands, represent it using one digit in the file. + // instead of "=---", we swap with "+" or something. small optimization. + + return data; + } + } +} diff --git a/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs b/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs index 9cc7ea3d..69c5faaa 100644 --- a/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs +++ b/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs @@ -1,8 +1,12 @@ -using System; +// define to do some extra checking as we save the data out +// #define EXTRA_DEBUG_CHECKS + +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; +using System.Threading.Tasks; using Diz.Core.model; using ExtendedXmlSerializer.ContentModel; using ExtendedXmlSerializer.ContentModel.Format; @@ -31,53 +35,112 @@ sealed class RomBytesSerializer : ISerializer public static RomBytesSerializer Default { get; } = new RomBytesSerializer(); - RomBytesSerializer() { } - public bool compress_groupblock = true; public bool compress_using_table_1 = true; + public int numTasksToUse = 10; public RomBytes Get(IFormatReader parameter) { - var lines = parameter.Content().Split(new char[] { '\n' }, 3).ToList(); - var options = lines[1].Split(new char[] { ',' }).ToList(); - lines = lines[2].Split(new char[] { '\n' }).ToList(); - if (lines[lines.Count - 1] == "") - lines.RemoveAt(lines.Count - 1); + var allLines = ReadMainDataRaw(parameter.Content()); + var romBytes = DecodeAllBytes(allLines); + return FinishRead(romBytes); + } - CheckForCompatibleVersion(options); + private ROMByte[] DecodeAllBytes(List allLines) + { + if (numTasksToUse == 1) + return DecodeRomBytes(allLines, 0); - // always apply options in same order here and in saving function - if (options.Exists(s => s == "compress_table_1")) - DecodeCompression_Table1(ref lines); + var nextIndex = 0; + var workListCount = allLines.Count / numTasksToUse; - if (options.Exists(s => s == "compress_groupblocks")) - DecodeCompression_GroupsBlocks(ref lines); + var tasks = new List>(numTasksToUse); + + for (var t = 0; t < numTasksToUse; ++t) + { + var lastThread = t == numTasksToUse - 1; + if (lastThread) + workListCount = allLines.Count - nextIndex; + + var workList = new List(workListCount); + for (var i = 0; i < workListCount; ++i) + { + workList.Add(allLines[nextIndex + i]); + } + + // ReSharper disable once AccessToStaticMemberViaDerivedType + var index = nextIndex; + var task = Task.Run(() => DecodeRomBytes(workList, index)); + tasks.Add(task); + + nextIndex += workListCount; + } + + var continuation = Task.WhenAll(tasks); + continuation.Wait(); + return continuation.Result.SelectMany(i => i).ToArray(); + } + + private static ROMByte[] DecodeRomBytes(List lines, int startingLineNum) + { // perf: allocate all at once, don't use List.Add() one at a time - var capacity = lines.Count; - var romBytes = new ROMByte[capacity]; + var romBytes = new ROMByte[lines.Count]; + var currentLineNum = startingLineNum; + + var romByteEncoding = new RomByteEncoding(); - var lineNum = 0; try { - // TODO: romBytesOut.SendNotificationChangedEvents = false; + var i = 0; foreach (var line in lines) { - romBytes[lineNum] = DecodeRomByte(line); - lineNum++; + romBytes[i] = romByteEncoding.DecodeRomByte(line); + currentLineNum++; + i++; } } catch (Exception ex) { - ex.Data.Add("ParseLineNum", "Near line#" + lineNum); + ex.Data.Add("ParseLineNum", "Near line# " + currentLineNum); throw; } + return romBytes; + } + + private static RomBytes FinishRead(ROMByte[] romBytes) + { var romBytesOut = new RomBytes(); romBytesOut.SetFrom(romBytes); return romBytesOut; } + private static List ReadMainDataRaw(string allLines) + { + var (lines, options) = ReadHeader(allLines); + + CheckForCompatibleVersion(options); + + // always apply options in same order here and in saving function + if (options.Exists(s => s == "compress_table_1")) + SubstitutionCompression.DecodeCompression_Table1(ref lines); + + if (options.Exists(s => s == "compress_groupblocks")) + RepeaterCompression.Decompress(ref lines); + return lines; + } + + private static (List lines, List options) ReadHeader(string allLines) + { + var lines = allLines.Split(new char[] {'\n'}, 3).ToList(); + var options = lines[1].Split(new char[] {','}).ToList(); + lines = lines[2].Split(new char[] {'\n'}).ToList(); + if (lines[lines.Count - 1] == "") + lines.RemoveAt(lines.Count - 1); + return (lines, options); + } + private static void CheckForCompatibleVersion(IEnumerable options) { try @@ -118,27 +181,31 @@ public void Write(IFormatWriter writer, RomBytes instance) $"version:{CURRENT_DATA_FORMAT_VERSION}", }; + var romByteEncoding = new RomByteEncoding(); + var lines = new List(); foreach (var rb in instance) { - var encodedTxt = EncodeByte(rb); + var encodedTxt = romByteEncoding.EncodeByte(rb); lines.Add(encodedTxt); // debug check, optional: - var decoded = DecodeRomByte(encodedTxt); +#if EXTRA_DEBUG_CHECKS + var decoded = romByteEncoding.DecodeRomByte(encodedTxt); Debug.Assert(decoded.EqualsButNoRomByte(rb)); +#endif } if (compress_groupblock) { options.Add("compress_groupblocks"); - ApplyCompression_GroupsBlocks(ref lines); + RepeaterCompression.Compress(ref lines); } if (compress_using_table_1) { options.Add("compress_table_1"); - EncodeCompression_Table1(ref lines); + SubstitutionCompression.EncodeCompression_Table1(ref lines); } writer.Content($"\n{string.Join(",", options)}\n"); @@ -148,321 +215,5 @@ public void Write(IFormatWriter writer, RomBytes instance) writer.Content(line + "\n"); } } - - class CompressionEntry - { - public string LongTextPattern; - public string ShortTextToEncode; - } - private static List table1 = new List - { - new CompressionEntry() {LongTextPattern = "0001E", ShortTextToEncode="ZQ"}, - new CompressionEntry() {LongTextPattern = "B0001", ShortTextToEncode="Zq"}, - new CompressionEntry() {LongTextPattern = "C0001", ShortTextToEncode="ZX"}, - new CompressionEntry() {LongTextPattern = "B7E", ShortTextToEncode="Zx"}, - new CompressionEntry() {LongTextPattern = "07F01", ShortTextToEncode="ZY"}, - new CompressionEntry() {LongTextPattern = "0001D", ShortTextToEncode="Zy"}, - new CompressionEntry() {LongTextPattern = "C7E", ShortTextToEncode="ZZ"}, - new CompressionEntry() {LongTextPattern = "07E", ShortTextToEncode="Zz"}, - new CompressionEntry() {LongTextPattern = "00001", ShortTextToEncode="ZS"}, - new CompressionEntry() {LongTextPattern = "0001", ShortTextToEncode="Zs"}, - }; - - private void DecodeCompression_Table1(ref List lines) - { - for (int i = 0; i < lines.Count; ++i) - { - // shouldn't matter much but, apply in reverse to ensure it's done the same - // way as the encoding process - foreach (var e in table1.Reverse()) - { - lines[i] = lines[i].Replace(e.ShortTextToEncode, e.LongTextPattern); - } - } - } - - private void EncodeCompression_Table1(ref List lines) - { - // kind of a manually made / crappy huffman table encoding type thing. - // this is no great work of genius, more just some cheap hacks to reduce filesize. - // these are based on one half-assembled ROM i was using and probably don't - // universally work perfectly. I expect at some point we could collect a bunch of projects - // and make a Table2, add that here without having to bump the file version. - for (int i = 0; i < lines.Count; ++i) - { - foreach (var e in table1) - { - Debug.Assert(!lines[i].Contains(e.ShortTextToEncode)); - lines[i] = lines[i].Replace(e.LongTextPattern, e.ShortTextToEncode); - } - } - } - - private void DecodeCompression_GroupsBlocks(ref List lines) - { - var output = new List(); - - foreach (var line in lines) - { - if (!line.StartsWith("r")) - { - output.Add(line); - continue; - } - - var split = line.Split(' '); - if (split.Length != 3) - throw new InvalidDataException("Invalid repeater command"); - - var count = int.Parse(split[1]); - for (int i = 0; i < count; ++i) - { - output.Add(split[2]); - } - } - - lines = output; - } - - private void ApplyCompression_GroupsBlocks(ref List lines) - { - if (lines.Count < 8) - return; // forget it, too small to care. - - var output = new List(); - - var lastline = lines[0]; - var consecutive = 1; - - // adjustable, just pick something > 8 or it's not worth the optimization. - // we want to catch large consecutive blocks of data. - const int min_number_repeats_before_we_bother = 8; - - int totalLinesDebug = 0; - - for (var i = 1; i < lines.Count; ++i) - { - var line = lines[i]; - Debug.Assert(!line.StartsWith("r")); - - bool different = line != lastline; - bool finalLine = i == lines.Count-1; - - if (!different) { - consecutive++; - - if (!finalLine) - continue; - - // special case for the final line. - // since our loop only ever prints out the LAST line, we have to handle this separately. - consecutive++; - } - - if (consecutive >= min_number_repeats_before_we_bother) - { - // replace multiple repeated lines with one new statement - output.Add($"r {consecutive.ToString()} {lastline}"); - } - else - { - // output 1 or more copies of the last line - // this is also how we print single lines too - output.AddRange(Enumerable.Repeat(lastline, consecutive).ToList()); - } - - if (finalLine && different) { - output.Add(line); - totalLinesDebug++; - } - - totalLinesDebug += consecutive; - - lastline = line; - consecutive = 1; - } - - Debug.Assert(totalLinesDebug == lines.Count); - - lines = output; - } - - public class FlagEncodeEntry - { - public string c; - public Data.FlagType f; - }; - - private static readonly List flagEncodeTable = new List { - new FlagEncodeEntry() {f = Data.FlagType.Unreached, c = "U"}, - - new FlagEncodeEntry() {f = Data.FlagType.Opcode, c = "+"}, - new FlagEncodeEntry() {f = Data.FlagType.Operand, c = "."}, - - new FlagEncodeEntry() {f = Data.FlagType.Graphics, c = "G"}, - new FlagEncodeEntry() {f = Data.FlagType.Music, c = "M"}, - new FlagEncodeEntry() {f = Data.FlagType.Empty, c = "X"}, - new FlagEncodeEntry() {f = Data.FlagType.Text, c = "T"}, - - new FlagEncodeEntry() {f = Data.FlagType.Data8Bit, c = "A"}, - new FlagEncodeEntry() {f = Data.FlagType.Data16Bit, c = "B"}, - new FlagEncodeEntry() {f = Data.FlagType.Data24Bit, c = "C"}, - new FlagEncodeEntry() {f = Data.FlagType.Data32Bit, c = "D"}, - - new FlagEncodeEntry() {f = Data.FlagType.Pointer16Bit, c = "E"}, - new FlagEncodeEntry() {f = Data.FlagType.Pointer24Bit, c = "F"}, - new FlagEncodeEntry() {f = Data.FlagType.Pointer32Bit, c = "G"}, - }; - - private ROMByte DecodeRomByte(string line) - { - var newByte = new ROMByte(); - - // light decompression. always 9 chars long - line = line.PadRight(9, '0'); - Debug.Assert(line.Length == 9); - - var asHex = System.Globalization.NumberStyles.HexNumber; - - var flagTxt = line.Substring(0, 1); - var o1_str = line.Substring(1, 1); - newByte.DataBank = byte.Parse(line.Substring(2, 2), asHex); - newByte.DirectPage = int.Parse(line.Substring(4, 4), asHex); - var o2_str = byte.Parse(line.Substring(8, 1), asHex); - - newByte.Arch = (Data.Architecture)((o2_str >> 0) & 0x3); - - var otherFlags1 = DecodeHackyBase64(o1_str); - Debug.Assert(EncodeHackyBase64(otherFlags1) == o1_str); - - newByte.XFlag = ((otherFlags1 >> 2) & 0x1) != 0; - newByte.MFlag = ((otherFlags1 >> 3) & 0x1) != 0; - newByte.Point = (Data.InOutPoint)((otherFlags1 >> 4) & 0xF); - - bool found = false; - foreach (var e in flagEncodeTable) - { - if (e.c == flagTxt) - { - newByte.TypeFlag = e.f; - found = true; - break; - } - } - if (!found) - throw new InvalidDataException("Unknown FlagType"); - - return newByte; - } - - private string EncodeByte(ROMByte instance) - { - // use a custom formatter here to save space. there are a LOT of ROMBytes. - // despite that we're still going for: - // 1) text only for slightly human readability - // 2) mergability in git/etc - // - // some of this can be unpacked further to increase readability without - // hurting the filesize too much. figure out what's useful. - // - // sorry, I know the encoding looks insane and weird and specific. this reduced my - // save file size from 42MB to less than 13MB - - // NOTE: must be uppercase letter or "=" or "-" - // if you add things here, make sure you understand the compression settings above. - string flagTxt = ""; - foreach (var e in flagEncodeTable) - { - if (e.f == instance.TypeFlag) - { - flagTxt = e.c; - break; - } - } - - if (flagTxt == "") - throw new InvalidDataException("Unknown FlagType"); - - // max 6 bits if we want to fit in 1 base64 ASCII digit - byte otherFlags1 = (byte)( - (instance.XFlag ? 1 : 0) << 2 | // 1 bit - (instance.MFlag ? 1 : 0) << 3 | // 1 bit - (byte)instance.Point << 4 // 4 bits - // LEAVE OFF THE LAST 2 BITS. it'll mess with the base64 below - ); - // reminder: when decoding, have to cut off all but the first 6 bits - var o1_str = EncodeHackyBase64(otherFlags1); - Debug.Assert(DecodeHackyBase64(o1_str) == otherFlags1); - - if (!instance.XFlag && !instance.MFlag && instance.Point == 0) - Debug.Assert(o1_str == "0"); // sanity - - // this is basically going to be "0" almost 100% of the time. - // we'll put it on the end of the string so it's most likely not output - byte otherFlags2 = (byte)( - (byte)instance.Arch << 0 // 2 bits - ); - var o2_str = otherFlags2.ToString("X1"); Debug.Assert(o2_str.Length == 1); - - // ordering: put DB and D on the end, they're likely to be zero and compressible - string data = - flagTxt + // 1 - o1_str + // 1 - instance.DataBank.ToString("X2") + // 2 - instance.DirectPage.ToString("X4") + // 4 - o2_str; // 1 - - Debug.Assert(data.Length == 9); - - // light compression: chop off any trailing zeroes. - // this alone saves a giant amount of space. - data = data.TrimEnd(new char[] { '0' }); - - // future compression but dilutes readability: - // if type is opcode or operand with same flags, combine those into 1 type. - // i.e. take an opcode with 3 operands, represent it using one digit in the file. - // instead of "=---", we swap with "+" or something. small optimization. - - return data; - } - - private static void Swap0forA(ref string input) - { - // *****dumbest thing in the entire world***** - // - // the more zeroes our ouput text has, the more compressed we get later. - // so, let's swap base64's "A" (index 0) for "0" (index 52). - // - // if you got here after being really fucking confused about why - // your Base64 encoding algo wasn't working, then I owe you a beer. super-sorry. - // - // you are now allowed to flip your desk over. say it with me - // "Damnit Dom!!! Y U DO THIS" - if (input == "A") - input = "0"; - else if (input == "0") - input = "A"; - } - - // base64 decode, but we swap "0" for "A" - private static byte DecodeHackyBase64(string input) - { - Swap0forA(ref input); - var superHackyBase64 = input + "A=="; // we dont care about > 6 bits, so we can fake this. - var result = Convert.FromBase64CharArray(superHackyBase64.ToCharArray(), 0, superHackyBase64.Length); - Debug.Assert(result.Length == 1); - return result[0]; - } - - // base64 encode, but we swap "0" for "A" - private static string EncodeHackyBase64(byte input) - { - var output = System.Convert.ToBase64String(new byte[] {input}); - Debug.Assert(output.Length == 4); - Debug.Assert(output.Substring(1) == "A=="); - output = output.Remove(1); - Swap0forA(ref output); - return output; - } } } \ No newline at end of file diff --git a/Diz.Core/serialization/xml_serializer/SubstitutionCompression.cs b/Diz.Core/serialization/xml_serializer/SubstitutionCompression.cs new file mode 100644 index 00000000..26524661 --- /dev/null +++ b/Diz.Core/serialization/xml_serializer/SubstitutionCompression.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Diz.Core.serialization.xml_serializer +{ + public static class SubstitutionCompression + { + private class CompressionEntry + { + public string LongTextPattern; + public string ShortTextToEncode; + } + + private static readonly List table1 = new List + { + new CompressionEntry() {LongTextPattern = "0001E", ShortTextToEncode="ZQ"}, + new CompressionEntry() {LongTextPattern = "B0001", ShortTextToEncode="Zq"}, + new CompressionEntry() {LongTextPattern = "C0001", ShortTextToEncode="ZX"}, + new CompressionEntry() {LongTextPattern = "B7E", ShortTextToEncode="Zx"}, + new CompressionEntry() {LongTextPattern = "07F01", ShortTextToEncode="ZY"}, + new CompressionEntry() {LongTextPattern = "0001D", ShortTextToEncode="Zy"}, + new CompressionEntry() {LongTextPattern = "C7E", ShortTextToEncode="ZZ"}, + new CompressionEntry() {LongTextPattern = "07E", ShortTextToEncode="Zz"}, + new CompressionEntry() {LongTextPattern = "00001", ShortTextToEncode="ZS"}, + new CompressionEntry() {LongTextPattern = "0001", ShortTextToEncode="Zs"}, + }; + + public static void DecodeCompression_Table1(ref List lines) + { + for (int i = 0; i < lines.Count; ++i) + { + // shouldn't matter much but, apply in reverse to ensure it's done the same + // way as the encoding process + foreach (var e in table1.Reverse()) + { + lines[i] = lines[i].Replace(e.ShortTextToEncode, e.LongTextPattern); + } + } + } + + public static void EncodeCompression_Table1(ref List lines) + { + // kind of a manually made / crappy huffman table encoding type thing. + // this is no great work of genius, more just some cheap hacks to reduce filesize. + // these are based on one half-assembled ROM i was using and probably don't + // universally work perfectly. I expect at some point we could collect a bunch of projects + // and make a Table2, add that here without having to bump the file version. + for (var i = 0; i < lines.Count; ++i) + { + foreach (var e in table1) + { + Debug.Assert(!lines[i].Contains(e.ShortTextToEncode)); + lines[i] = lines[i].Replace(e.LongTextPattern, e.ShortTextToEncode); + } + } + } + } +} diff --git a/Diz.Core/util/Fake64Encoding.cs b/Diz.Core/util/Fake64Encoding.cs new file mode 100644 index 00000000..525ab730 --- /dev/null +++ b/Diz.Core/util/Fake64Encoding.cs @@ -0,0 +1,87 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Diz.Core.util +{ + public static class Fake64Encoding + { + // this is base64 EXCEPT: + // 1) char "A" and "0" swapped (my data format compresses things with "0" better) + // 2) only supports 6 bits of input data to encode + // DONT BE FOOLED :) + public const string Fake64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + "abcdefghijklmnopqrstuvwxyz" + + "0123456789" + + "+/"; + + public static readonly byte[] Fake64Values = + { + 208, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, + 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, + 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, + 148, 152, 156, 160, 164, 168, 172, 176, 180, 184, + 188, 192, 196, 200, 204, 0, 212, 216, 220, 224, 228, + 232, 236, 240, 244, 248, 252 + }; + + private static readonly object InitLock = new object(); + + public static IEnumerable CharToByte => + Fake64Chars.Zip( + Fake64Values, (c, b) => new object[] { c, b }); + + private static Dictionary _fake64CharToByte; + public static Dictionary Fake64CharToByte + { + get + { + lock (InitLock) + { + if (_fake64CharToByte != null) + return _fake64CharToByte; + + _fake64CharToByte = new Dictionary(); + foreach (var kvp in CharToByte) + { + _fake64CharToByte[(char) kvp[0]] = (byte) kvp[1]; + } + + return _fake64CharToByte; + } + } + } + + private static Dictionary _fake64ByteToChar; + public static Dictionary Fake64ByteToChar + { + get + { + lock (InitLock) + { + if (_fake64ByteToChar != null) + return _fake64ByteToChar; + + _fake64ByteToChar = new Dictionary(); + foreach (var kvp in CharToByte) + { + _fake64ByteToChar[(byte) kvp[1]] = (char) kvp[0]; + } + + return _fake64ByteToChar; + } + } + } + + // we could use the system base64 stuff but, this is faster. + + public static byte DecodeHackyBase64(char input) + { + return Fake64CharToByte[input]; + } + + public static char EncodeHackyBase64(byte input) + { + return Fake64ByteToChar[input]; + } + } +} diff --git a/Diz.Test/CompressionTest.cs b/Diz.Test/CompressionTest.cs new file mode 100644 index 00000000..cfb8dee4 --- /dev/null +++ b/Diz.Test/CompressionTest.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Diz.Core.serialization.xml_serializer; +using Diz.Core.util; +using IX.System.Collections.Generic; +using Xunit; + +namespace Diz.Test +{ + public static class CompressionTest + { + public static IEnumerable Repeat(TOut toRepeat, int times) + { + for (var i = 0; i < times; ++i) + { + yield return toRepeat; + } + } + + public static TheoryData, IEnumerable> ValidCompressionData => + new TheoryData, IEnumerable> + { + { + Repeat("YO", 3), + Repeat("YO", 3) + }, + { + Repeat("YO", 20), + new[] {"r YO"} + } + }; + + [Theory] + [MemberData(nameof(ValidCompressionData))] + public static void TestCompressionsValid(IEnumerable input, IEnumerable output) + { + //var serializer = new RomBytesSerializer(); + //RomBytesXMLSerializer.ApplyCompression_GroupsBlocks() + Assert.Equal(input.ToList(), output.ToList()); + } + } +} \ No newline at end of file diff --git a/Diz.Test/Diz.Test.csproj b/Diz.Test/Diz.Test.csproj index ad2f4dfb..51a2f328 100644 --- a/Diz.Test/Diz.Test.csproj +++ b/Diz.Test/Diz.Test.csproj @@ -136,10 +136,13 @@ + + - + + diff --git a/Diz.Test/Fake64Test.cs b/Diz.Test/Fake64Test.cs new file mode 100644 index 00000000..8bdb0178 --- /dev/null +++ b/Diz.Test/Fake64Test.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using System.Linq; +using Diz.Core.serialization.xml_serializer; +using Diz.Core.util; +using Xunit; + +namespace Diz.Test +{ + public static class Fake64Test + { + public class Fake64Tests + { + public static IEnumerable CharToByte => + Fake64Encoding.Fake64Chars.Zip( + Fake64Encoding.Fake64Values, (c, b) => new object[] { c, b }); + + [Theory] + [MemberData(nameof(CharToByte))] + public static void TestDecodeFake64(char c, byte b) + { + Assert.Equal(b, Fake64Encoding.DecodeHackyBase64(c)); + } + + [Theory] + [MemberData(nameof(CharToByte))] + public static void TestEncodeFake64(char c, byte b) + { + Assert.Equal(c, Fake64Encoding.EncodeHackyBase64(b)); + } + + [Fact] + public static void TestHex() + { + Assert.Equal(0xF0, RomByteEncoding.ByteParseHex2('F', '0')); + } + + [Fact] + public static void TestHex4() + { + Assert.Equal(0xF029, RomByteEncoding.ByteParseHex4('F', '0', '2', '9')); + } + } + } +} \ No newline at end of file diff --git a/Diz.Test/LoadSaveTest.cs b/Diz.Test/LoadSaveTest.cs new file mode 100644 index 00000000..20c38cef --- /dev/null +++ b/Diz.Test/LoadSaveTest.cs @@ -0,0 +1,31 @@ +using System.Xml; +using Diz.Core; +using Diz.Core.model; +using Diz.Core.serialization.xml_serializer; +using ExtendedXmlSerializer; +using ExtendedXmlSerializer.Configuration; +using IX.Observable; +using Xunit; +using Xunit.Abstractions; + +namespace Diz.Test +{ + public class LoadSaveTest + { + [Fact] + private void SerializeAndDeserialize() + { + var sampleProject = new Project {Data = SampleRomData.SampleData}; + + var serializer = new ProjectXmlSerializer(); + var outputBytes = serializer.Save(sampleProject); + + var (deserializedProject, warning) = serializer.Load(outputBytes); + + Assert.True(warning == ""); + Assert.True(sampleProject.Equals(deserializedProject)); + + // todo: run a couple tests where we mess with the end repeater bytes + } + } +} \ No newline at end of file diff --git a/Diz.Test/SerializerTest.cs b/Diz.Test/SerializerDictionaryTest.cs similarity index 96% rename from Diz.Test/SerializerTest.cs rename to Diz.Test/SerializerDictionaryTest.cs index c3ada6b2..180877ac 100644 --- a/Diz.Test/SerializerTest.cs +++ b/Diz.Test/SerializerDictionaryTest.cs @@ -11,11 +11,11 @@ namespace Diz.Test { - public class SerializerTest + public class SerializerDictionaryTest { private readonly ITestOutputHelper testOutputHelper; - public SerializerTest(ITestOutputHelper testOutputHelper) + public SerializerDictionaryTest(ITestOutputHelper testOutputHelper) { this.testOutputHelper = testOutputHelper; } diff --git a/DiztinGUIsh/controller/ProjectController.cs b/DiztinGUIsh/controller/ProjectController.cs index 8deed28e..78cd9f9f 100644 --- a/DiztinGUIsh/controller/ProjectController.cs +++ b/DiztinGUIsh/controller/ProjectController.cs @@ -2,6 +2,7 @@ using System.ComponentModel; using System.Diagnostics; using System.IO; +using System.Linq; using System.Security.Policy; using Diz.Core.export; using Diz.Core.import; @@ -78,9 +79,14 @@ public bool OpenProject(string filename) { try { - var result = ProjectFileManager.Open(filename, AskToSelectNewRomFilename); - project = result.project; - warningMsg = result.warning; + var (project1, warning) = ProjectFileManager.Open(filename, AskToSelectNewRomFilename); + project = project1; + warningMsg = warning; + } + catch (AggregateException ex) + { + project = null; + errorMsg = ex.InnerExceptions.Select(e => e.Message).Aggregate((line, val) => line += val + "\n"); } catch (Exception ex) { From a28608e7a3dd665408239ccb4a7f7e8d9c4bf09f Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 25 Oct 2020 08:45:41 -0400 Subject: [PATCH 110/136] WIP improving visuals --- DiztinGUIsh/window/VisualizerForm.Designer.cs | 46 +++---- DiztinGUIsh/window/VisualizerForm.cs | 12 +- .../BSNESTraceLogBinaryMonitorForm.UI.cs | 6 +- .../window/usercontrols/RomBankVisualizer.cs | 17 ++- .../RomFullVisualizer.Designer.cs | 119 +++++++++++++----- .../window/usercontrols/RomFullVisualizer.cs | 17 ++- 6 files changed, 152 insertions(+), 65 deletions(-) diff --git a/DiztinGUIsh/window/VisualizerForm.Designer.cs b/DiztinGUIsh/window/VisualizerForm.Designer.cs index 0f12feaf..859b9ebf 100644 --- a/DiztinGUIsh/window/VisualizerForm.Designer.cs +++ b/DiztinGUIsh/window/VisualizerForm.Designer.cs @@ -32,14 +32,14 @@ private void InitializeComponent() this.panelLegend = new System.Windows.Forms.Panel(); this.bankLegend1 = new DiztinGUIsh.window.usercontrols.BankLegend(); this.panelBottom = new System.Windows.Forms.Panel(); - this.romImage1 = new DiztinGUIsh.window.usercontrols.RomImage(); + this.romFullVisualizer1 = new DiztinGUIsh.window.usercontrols.RomFullVisualizer(); this.panelTop.SuspendLayout(); this.panelLegend.SuspendLayout(); this.panelBottom.SuspendLayout(); this.SuspendLayout(); - // + // // panelTop - // + // this.panelTop.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.panelTop.Controls.Add(this.panelLegend); this.panelTop.Dock = System.Windows.Forms.DockStyle.Top; @@ -47,46 +47,49 @@ private void InitializeComponent() this.panelTop.Name = "panelTop"; this.panelTop.Size = new System.Drawing.Size(765, 154); this.panelTop.TabIndex = 1; - // + // // panelLegend - // + // this.panelLegend.Controls.Add(this.bankLegend1); this.panelLegend.Dock = System.Windows.Forms.DockStyle.Left; this.panelLegend.Location = new System.Drawing.Point(0, 0); this.panelLegend.Name = "panelLegend"; this.panelLegend.Size = new System.Drawing.Size(567, 152); this.panelLegend.TabIndex = 0; - // + // // bankLegend1 - // + // this.bankLegend1.AutoScroll = true; + this.bankLegend1.AutoSize = true; this.bankLegend1.Dock = System.Windows.Forms.DockStyle.Fill; this.bankLegend1.Location = new System.Drawing.Point(0, 0); this.bankLegend1.Name = "bankLegend1"; this.bankLegend1.Size = new System.Drawing.Size(567, 152); this.bankLegend1.TabIndex = 0; - // + // // panelBottom - // + // this.panelBottom.AutoScroll = true; this.panelBottom.AutoSize = true; - this.panelBottom.Controls.Add(this.romImage1); + this.panelBottom.Controls.Add(this.romFullVisualizer1); this.panelBottom.Dock = System.Windows.Forms.DockStyle.Fill; this.panelBottom.Location = new System.Drawing.Point(0, 154); this.panelBottom.Name = "panelBottom"; this.panelBottom.Size = new System.Drawing.Size(765, 363); this.panelBottom.TabIndex = 2; - // - // romImage1 - // - this.romImage1.Location = new System.Drawing.Point(0, 0); - this.romImage1.Name = "romImage1"; - this.romImage1.Project = null; - this.romImage1.Size = new System.Drawing.Size(854, 421); - this.romImage1.TabIndex = 0; - // + // + // romFullVisualizer1 + // + this.romFullVisualizer1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.romFullVisualizer1.Location = new System.Drawing.Point(3, 3); + this.romFullVisualizer1.MaximumSize = new System.Drawing.Size(100, 100); + this.romFullVisualizer1.Name = "romFullVisualizer1"; + this.romFullVisualizer1.Project = null; + this.romFullVisualizer1.Size = new System.Drawing.Size(100, 100); + this.romFullVisualizer1.TabIndex = 0; + // // VisualizerForm - // + // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScroll = true; @@ -102,6 +105,7 @@ private void InitializeComponent() this.Load += new System.EventHandler(this.VisualizerForm_Load); this.panelTop.ResumeLayout(false); this.panelLegend.ResumeLayout(false); + this.panelLegend.PerformLayout(); this.panelBottom.ResumeLayout(false); this.ResumeLayout(false); this.PerformLayout(); @@ -113,6 +117,6 @@ private void InitializeComponent() private System.Windows.Forms.Panel panelLegend; private System.Windows.Forms.Panel panelBottom; private usercontrols.BankLegend bankLegend1; - private usercontrols.RomImage romImage1; + private usercontrols.RomFullVisualizer romFullVisualizer1; } } \ No newline at end of file diff --git a/DiztinGUIsh/window/VisualizerForm.cs b/DiztinGUIsh/window/VisualizerForm.cs index 64001819..80b6ddc4 100644 --- a/DiztinGUIsh/window/VisualizerForm.cs +++ b/DiztinGUIsh/window/VisualizerForm.cs @@ -16,7 +16,7 @@ public Project Project set { project = value; - romImage1.Project = project; + romFullVisualizer1.Project = project; } } @@ -24,21 +24,13 @@ public VisualizerForm(MainWindow window) { mainWindow = window; InitializeComponent(); - - romImage1.RedrawOccurred += RomImage1_RedrawOccurred; - } - - private void RomImage1_RedrawOccurred(object sender, System.EventArgs e) - { - if (!(sender is RomImage romImage)) - return; } private void VisualizerForm_Load(object sender, System.EventArgs e) { // hack to make room for the scrollbar // I wish docking dealt with this, or maybe I set it up wrong... - Width = romImage1.Width + 40; + Width = romFullVisualizer1.Width + 40; } private void VisualizerForm_FormClosing(object sender, FormClosingEventArgs e) diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs index 0b492859..ca267454 100644 --- a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs @@ -13,10 +13,10 @@ public partial class BSNESTraceLogBinaryMonitorForm { private bool initializedChart; private readonly ChartValues chartValuesBytesModified = new ChartValues(); - private long chartValueBytesModified_previous = 0; + // private long chartValueBytesModified_previous = 0; - private const int refreshGraphEveryNDataPoints = 100; - private int dataPointsIn = -1; + //private const int refreshGraphEveryNDataPoints = 100; + //private int dataPointsIn = -1; private void AppendToChart((BSNESTraceLogImporter.Stats stats, int bytesInQueue) currentStats) { diff --git a/DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs b/DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs index 63c96f6f..4c829446 100644 --- a/DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs +++ b/DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs @@ -1,4 +1,5 @@ -using System.Windows.Forms; +using System; +using System.Windows.Forms; using Diz.Core.model; // this usercontrol shows: @@ -11,6 +12,8 @@ namespace DiztinGUIsh.window.usercontrols { public partial class RomBankVisualizer : UserControl { + public event EventHandler RedrawOccurred; + public RomBankVisualizer(Project project, int startingRomOffset, int length, string bankName) { InitializeComponent(); @@ -19,6 +22,18 @@ public RomBankVisualizer(Project project, int startingRomOffset, int length, str romImage1.ROMVisual.RomStartingOffset = startingRomOffset; romImage1.ROMVisual.LengthOverride = length; lblBankName.Text = bankName; + + romImage1.RedrawOccurred += RomImage1_RedrawOccurred; + } + + private void RomImage1_RedrawOccurred(object sender, System.EventArgs e) + { + OnRedrawOccurred(); + } + + protected virtual void OnRedrawOccurred() + { + RedrawOccurred?.Invoke(this, EventArgs.Empty); } } } diff --git a/DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs index 7258c388..859b9ebf 100644 --- a/DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs +++ b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs @@ -1,13 +1,13 @@ -namespace DiztinGUIsh.window.usercontrols +namespace DiztinGUIsh.window { - partial class RomFullVisualizer + partial class VisualizerForm { - /// + /// /// Required designer variable. /// private System.ComponentModel.IContainer components = null; - /// + /// /// Clean up any resources being used. /// /// true if managed resources should be disposed; otherwise, false. @@ -20,42 +20,103 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } - #region Component Designer generated code + #region Windows Form Designer generated code - /// - /// Required method for Designer support - do not modify + /// + /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { - this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); + this.panelTop = new System.Windows.Forms.Panel(); + this.panelLegend = new System.Windows.Forms.Panel(); + this.bankLegend1 = new DiztinGUIsh.window.usercontrols.BankLegend(); + this.panelBottom = new System.Windows.Forms.Panel(); + this.romFullVisualizer1 = new DiztinGUIsh.window.usercontrols.RomFullVisualizer(); + this.panelTop.SuspendLayout(); + this.panelLegend.SuspendLayout(); + this.panelBottom.SuspendLayout(); this.SuspendLayout(); - // - // flowLayoutPanel1 - // - this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; - this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; - this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0); - this.flowLayoutPanel1.MinimumSize = new System.Drawing.Size(100, 100); - this.flowLayoutPanel1.Name = "flowLayoutPanel1"; - this.flowLayoutPanel1.Size = new System.Drawing.Size(100, 100); - this.flowLayoutPanel1.TabIndex = 0; - // - // RomFullVisualizer - // + // + // panelTop + // + this.panelTop.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.panelTop.Controls.Add(this.panelLegend); + this.panelTop.Dock = System.Windows.Forms.DockStyle.Top; + this.panelTop.Location = new System.Drawing.Point(0, 0); + this.panelTop.Name = "panelTop"; + this.panelTop.Size = new System.Drawing.Size(765, 154); + this.panelTop.TabIndex = 1; + // + // panelLegend + // + this.panelLegend.Controls.Add(this.bankLegend1); + this.panelLegend.Dock = System.Windows.Forms.DockStyle.Left; + this.panelLegend.Location = new System.Drawing.Point(0, 0); + this.panelLegend.Name = "panelLegend"; + this.panelLegend.Size = new System.Drawing.Size(567, 152); + this.panelLegend.TabIndex = 0; + // + // bankLegend1 + // + this.bankLegend1.AutoScroll = true; + this.bankLegend1.AutoSize = true; + this.bankLegend1.Dock = System.Windows.Forms.DockStyle.Fill; + this.bankLegend1.Location = new System.Drawing.Point(0, 0); + this.bankLegend1.Name = "bankLegend1"; + this.bankLegend1.Size = new System.Drawing.Size(567, 152); + this.bankLegend1.TabIndex = 0; + // + // panelBottom + // + this.panelBottom.AutoScroll = true; + this.panelBottom.AutoSize = true; + this.panelBottom.Controls.Add(this.romFullVisualizer1); + this.panelBottom.Dock = System.Windows.Forms.DockStyle.Fill; + this.panelBottom.Location = new System.Drawing.Point(0, 154); + this.panelBottom.Name = "panelBottom"; + this.panelBottom.Size = new System.Drawing.Size(765, 363); + this.panelBottom.TabIndex = 2; + // + // romFullVisualizer1 + // + this.romFullVisualizer1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.romFullVisualizer1.Location = new System.Drawing.Point(3, 3); + this.romFullVisualizer1.MaximumSize = new System.Drawing.Size(100, 100); + this.romFullVisualizer1.Name = "romFullVisualizer1"; + this.romFullVisualizer1.Project = null; + this.romFullVisualizer1.Size = new System.Drawing.Size(100, 100); + this.romFullVisualizer1.TabIndex = 0; + // + // VisualizerForm + // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.Controls.Add(this.flowLayoutPanel1); - this.MaximumSize = new System.Drawing.Size(100, 100); - this.Name = "RomFullVisualizer"; - this.Size = new System.Drawing.Size(100, 100); + this.AutoScroll = true; + this.ClientSize = new System.Drawing.Size(765, 517); + this.Controls.Add(this.panelBottom); + this.Controls.Add(this.panelTop); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow; + this.Name = "VisualizerForm"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "ROM Visualizer"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.VisualizerForm_FormClosing); + this.Load += new System.EventHandler(this.VisualizerForm_Load); + this.panelTop.ResumeLayout(false); + this.panelLegend.ResumeLayout(false); + this.panelLegend.PerformLayout(); + this.panelBottom.ResumeLayout(false); this.ResumeLayout(false); + this.PerformLayout(); } #endregion - - private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; + private System.Windows.Forms.Panel panelTop; + private System.Windows.Forms.Panel panelLegend; + private System.Windows.Forms.Panel panelBottom; + private usercontrols.BankLegend bankLegend1; + private usercontrols.RomFullVisualizer romFullVisualizer1; } -} +} \ No newline at end of file diff --git a/DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs index aff0ff1e..6032c129 100644 --- a/DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs +++ b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Diagnostics; using System.Windows.Forms; using Diz.Core.model; @@ -55,11 +56,25 @@ public void Init() private void AddNewControl(RomBankVisualizer bankControl) { + // bankControl.RedrawOccurred += BankControl_RedrawOccurred; + BankControls.Add(bankControl); flowLayoutPanel1.Controls.Add(bankControl); flowLayoutPanel1.AutoSize = true; flowLayoutPanel1.AutoSizeMode = AutoSizeMode.GrowAndShrink; } + + /*private void BankControl_RedrawOccurred(object sender, EventArgs e) + { + OnRedrawOccurred(); + } + + public event EventHandler RedrawOccurred; + + protected virtual void OnRedrawOccurred() + { + RedrawOccurred?.Invoke(this, EventArgs.Empty); + }*/ } } From 06445862a54164b918a4bdf08dd77d248609598b Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 25 Oct 2020 11:31:48 -0400 Subject: [PATCH 111/136] temp disable currently unused visuals code --- .../window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs index 0b492859..5614dfbf 100644 --- a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs @@ -13,10 +13,10 @@ public partial class BSNESTraceLogBinaryMonitorForm { private bool initializedChart; private readonly ChartValues chartValuesBytesModified = new ChartValues(); - private long chartValueBytesModified_previous = 0; + //private long chartValueBytesModified_previous = 0; - private const int refreshGraphEveryNDataPoints = 100; - private int dataPointsIn = -1; + //private const int refreshGraphEveryNDataPoints = 100; + //private int dataPointsIn = -1; private void AppendToChart((BSNESTraceLogImporter.Stats stats, int bytesInQueue) currentStats) { From 1b81e641ca281a2e0595effed4cb0c5669f6857e Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 25 Oct 2020 11:32:21 -0400 Subject: [PATCH 112/136] better lazy loading for visuals form --- DiztinGUIsh/window/MainWindow.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 4f022cef..de02ecca 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -91,7 +91,6 @@ private void MainWindow_Load(object sender, EventArgs e) new object[] { true }); aliasList = new AliasList(this); - visualForm = new VisualizerForm(this); UpdatePanels(); UpdateUIFromSettings(); @@ -197,7 +196,9 @@ private void UpdateUIFromSettings() public void OnProjectOpened(string filename) { - visualForm.Project = Project; + if (visualForm != null) + visualForm.Project = Project; + // TODO: do this with aliaslist too. UpdateSaveOptionStates(true, true); @@ -883,10 +884,9 @@ private void GoToUnreached(bool end, bool direction) if (Project.Data.GetFlag(unreached) == Data.FlagType.Unreached) SelectOffset(unreached, 1); } - private VisualizerForm visualForm; - private void visualMapToolStripMenuItem_Click(object sender, EventArgs e) { + visualForm ??= new VisualizerForm(this); visualForm.Show(); } @@ -1135,6 +1135,7 @@ private void moveWithStepToolStripMenuItem_Click(object sender, EventArgs e) // sub windows public AliasList aliasList; + private VisualizerForm visualForm; private void EnableSubWindows() { From 38ed2db0383a1be5673e6b9688e559425ea09d36 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 25 Oct 2020 11:32:38 -0400 Subject: [PATCH 113/136] breakup main function so we can add some command line args --- DiztinGUIsh/Program.cs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/DiztinGUIsh/Program.cs b/DiztinGUIsh/Program.cs index 9ec2dff4..9bcf24c3 100644 --- a/DiztinGUIsh/Program.cs +++ b/DiztinGUIsh/Program.cs @@ -1,16 +1,26 @@ using System; +using System.Diagnostics; using System.Windows.Forms; using DiztinGUIsh.window; namespace DiztinGUIsh { - static class Program + internal static class Program { - /// - /// The main entry point for the application. - /// + [System.Runtime.InteropServices.DllImport("user32.dll")] + private static extern bool SetProcessDPIAware(); + [STAThread] static void Main(string[] args) + { + var openFile = ""; + if (args.Length > 0) + openFile = args[0]; + + RunNormally(openFile); + } + + private static void RunNormally(string openFile = "") { if (Environment.OSVersion.Version.Major >= 6) { @@ -21,13 +31,10 @@ static void Main(string[] args) Application.SetCompatibleTextRenderingDefault(false); var window = new MainWindow(); - if (args.Length > 0) - window.OpenProject(args[0]); + if (openFile != "") + window.OpenProject(""); Application.Run(window); } - - [System.Runtime.InteropServices.DllImport("user32.dll")] - private static extern bool SetProcessDPIAware(); } } \ No newline at end of file From 49284cf08d77e727d16de4d0b9404818c970966f Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 25 Oct 2020 11:33:02 -0400 Subject: [PATCH 114/136] add tracing for project loading [light diagnostics] --- Diz.Core/serialization/ProjectFileManager.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Diz.Core/serialization/ProjectFileManager.cs b/Diz.Core/serialization/ProjectFileManager.cs index 9031d8fa..d7668dbc 100644 --- a/Diz.Core/serialization/ProjectFileManager.cs +++ b/Diz.Core/serialization/ProjectFileManager.cs @@ -12,6 +12,8 @@ public static class ProjectFileManager { public static (Project project, string warning) Open(string filename, Func romPromptFn) { + Trace.WriteLine("Opening Project START"); + var data = File.ReadAllBytes(filename); if (!IsUncompressedProject(filename)) @@ -24,6 +26,7 @@ public static (Project project, string warning) Open(string filename, Func Date: Sun, 25 Oct 2020 11:34:41 -0400 Subject: [PATCH 115/136] auto-remove lots of unused 'using' directives --- Diz.Core/Properties/AssemblyInfo.cs | 1 - Diz.Core/SampleRomData.cs | 1 - Diz.Core/import/BSNESTraceLogCapture.cs | 4 +--- Diz.Core/import/BSNESUsageMapImporter.cs | 1 - Diz.Core/model/Data.Properties.cs | 1 - Diz.Core/model/ROMByte.cs | 3 +-- Diz.Core/model/RomBytes.cs | 1 - .../xml_serializer/ProjectXMLSerializer.cs | 1 - .../xml_serializer/RepeaterCompression.cs | 5 +---- .../serialization/xml_serializer/RomByteEncoding.cs | 1 - .../xml_serializer/SubstitutionCompression.cs | 5 +---- .../xml_serializer/XMLSerializerSupport.cs | 1 - Diz.Core/util/RomUtil.cs | 1 - Diz.Test/CompressionTest.cs | 8 +------- Diz.Test/LoadSaveTest.cs | 7 +------ Diz.Test/LogCreator.cs | 1 - Diz.Test/Properties/AssemblyInfo.cs | 1 - Diz.Test/SerializerDictionaryTest.cs | 2 -- DiztinGUIsh/Program.cs | 1 - DiztinGUIsh/controller/ProjectController.cs | 1 - DiztinGUIsh/window/VisualizerForm.cs | 1 - .../window/dialog/BSNESTraceLogBinaryMonitorForm.cs | 2 -- DiztinGUIsh/window/dialog/ExportDisassembly.cs | 2 -- DiztinGUIsh/window/dialog/InOutPointChecker.cs | 7 ------- DiztinGUIsh/window/dialog/ProgressDialog.cs | 10 +--------- 25 files changed, 7 insertions(+), 62 deletions(-) diff --git a/Diz.Core/Properties/AssemblyInfo.cs b/Diz.Core/Properties/AssemblyInfo.cs index 505f44b1..49e87f75 100644 --- a/Diz.Core/Properties/AssemblyInfo.cs +++ b/Diz.Core/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/Diz.Core/SampleRomData.cs b/Diz.Core/SampleRomData.cs index d85ab9cc..3e743d0b 100644 --- a/Diz.Core/SampleRomData.cs +++ b/Diz.Core/SampleRomData.cs @@ -1,5 +1,4 @@ using Diz.Core.model; -using Diz.Core.util; using IX.Observable; namespace Diz.Core diff --git a/Diz.Core/import/BSNESTraceLogCapture.cs b/Diz.Core/import/BSNESTraceLogCapture.cs index 96398a4a..80d9e5e1 100644 --- a/Diz.Core/import/BSNESTraceLogCapture.cs +++ b/Diz.Core/import/BSNESTraceLogCapture.cs @@ -1,7 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; -using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading; diff --git a/Diz.Core/import/BSNESUsageMapImporter.cs b/Diz.Core/import/BSNESUsageMapImporter.cs index e3c5f279..d347f03f 100644 --- a/Diz.Core/import/BSNESUsageMapImporter.cs +++ b/Diz.Core/import/BSNESUsageMapImporter.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.ExceptionServices; using Diz.Core.model; namespace Diz.Core.import diff --git a/Diz.Core/model/Data.Properties.cs b/Diz.Core/model/Data.Properties.cs index 478bf047..dc0ab2b0 100644 --- a/Diz.Core/model/Data.Properties.cs +++ b/Diz.Core/model/Data.Properties.cs @@ -1,5 +1,4 @@ using System.Linq; -using Diz.Core.arch; using IX.Observable; namespace Diz.Core.model diff --git a/Diz.Core/model/ROMByte.cs b/Diz.Core/model/ROMByte.cs index 9483b6c4..f2963c84 100644 --- a/Diz.Core/model/ROMByte.cs +++ b/Diz.Core/model/ROMByte.cs @@ -1,5 +1,4 @@ -using System.ComponentModel; -using DiztinGUIsh; +using DiztinGUIsh; namespace Diz.Core.model { diff --git a/Diz.Core/model/RomBytes.cs b/Diz.Core/model/RomBytes.cs index 61c52ea7..ae930e46 100644 --- a/Diz.Core/model/RomBytes.cs +++ b/Diz.Core/model/RomBytes.cs @@ -4,7 +4,6 @@ using System.Collections.Specialized; using System.ComponentModel; using System.Linq; -using IX.Observable; namespace Diz.Core.model { diff --git a/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs b/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs index 6f220f25..e6716b5e 100644 --- a/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs +++ b/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs @@ -2,7 +2,6 @@ using System.Text; using System.Xml; using Diz.Core.model; -using DiztinGUIsh; using ExtendedXmlSerializer; namespace Diz.Core.serialization.xml_serializer diff --git a/Diz.Core/serialization/xml_serializer/RepeaterCompression.cs b/Diz.Core/serialization/xml_serializer/RepeaterCompression.cs index 12ced66e..5f3998f5 100644 --- a/Diz.Core/serialization/xml_serializer/RepeaterCompression.cs +++ b/Diz.Core/serialization/xml_serializer/RepeaterCompression.cs @@ -1,10 +1,7 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Diz.Core.serialization.xml_serializer { diff --git a/Diz.Core/serialization/xml_serializer/RomByteEncoding.cs b/Diz.Core/serialization/xml_serializer/RomByteEncoding.cs index 62a9dcbd..02524887 100644 --- a/Diz.Core/serialization/xml_serializer/RomByteEncoding.cs +++ b/Diz.Core/serialization/xml_serializer/RomByteEncoding.cs @@ -1,6 +1,5 @@ // #define EXTRA_DEBUG_CHECKS -using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; diff --git a/Diz.Core/serialization/xml_serializer/SubstitutionCompression.cs b/Diz.Core/serialization/xml_serializer/SubstitutionCompression.cs index 26524661..72988374 100644 --- a/Diz.Core/serialization/xml_serializer/SubstitutionCompression.cs +++ b/Diz.Core/serialization/xml_serializer/SubstitutionCompression.cs @@ -1,9 +1,6 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Diz.Core.serialization.xml_serializer { diff --git a/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs b/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs index 9e367de8..7d184116 100644 --- a/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs +++ b/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs @@ -1,5 +1,4 @@ using Diz.Core.model; -using Diz.Core.util; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; diff --git a/Diz.Core/util/RomUtil.cs b/Diz.Core/util/RomUtil.cs index 317f397a..be2182c0 100644 --- a/Diz.Core/util/RomUtil.cs +++ b/Diz.Core/util/RomUtil.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Text; using Diz.Core.export; using Diz.Core.model; diff --git a/Diz.Test/CompressionTest.cs b/Diz.Test/CompressionTest.cs index cfb8dee4..d8ab8480 100644 --- a/Diz.Test/CompressionTest.cs +++ b/Diz.Test/CompressionTest.cs @@ -1,11 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Diz.Core.serialization.xml_serializer; -using Diz.Core.util; -using IX.System.Collections.Generic; using Xunit; namespace Diz.Test diff --git a/Diz.Test/LoadSaveTest.cs b/Diz.Test/LoadSaveTest.cs index 20c38cef..750e4775 100644 --- a/Diz.Test/LoadSaveTest.cs +++ b/Diz.Test/LoadSaveTest.cs @@ -1,12 +1,7 @@ -using System.Xml; -using Diz.Core; +using Diz.Core; using Diz.Core.model; using Diz.Core.serialization.xml_serializer; -using ExtendedXmlSerializer; -using ExtendedXmlSerializer.Configuration; -using IX.Observable; using Xunit; -using Xunit.Abstractions; namespace Diz.Test { diff --git a/Diz.Test/LogCreator.cs b/Diz.Test/LogCreator.cs index e01297cd..4062cd48 100644 --- a/Diz.Test/LogCreator.cs +++ b/Diz.Test/LogCreator.cs @@ -3,7 +3,6 @@ using System.Linq; using Diz.Core.export; using Diz.Core.model; -using Diz.Core.util; using IX.Observable; using Xunit; diff --git a/Diz.Test/Properties/AssemblyInfo.cs b/Diz.Test/Properties/AssemblyInfo.cs index 9260ec1f..84fa07a0 100644 --- a/Diz.Test/Properties/AssemblyInfo.cs +++ b/Diz.Test/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/Diz.Test/SerializerDictionaryTest.cs b/Diz.Test/SerializerDictionaryTest.cs index 180877ac..a7a09881 100644 --- a/Diz.Test/SerializerDictionaryTest.cs +++ b/Diz.Test/SerializerDictionaryTest.cs @@ -1,11 +1,9 @@ using System.Xml; using Diz.Core.model; using Diz.Core.serialization.xml_serializer; -using Diz.Core.util; using ExtendedXmlSerializer; using ExtendedXmlSerializer.Configuration; using IX.Observable; -using IX.StandardExtensions; using Xunit; using Xunit.Abstractions; diff --git a/DiztinGUIsh/Program.cs b/DiztinGUIsh/Program.cs index 9bcf24c3..cb5bd135 100644 --- a/DiztinGUIsh/Program.cs +++ b/DiztinGUIsh/Program.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using System.Windows.Forms; using DiztinGUIsh.window; diff --git a/DiztinGUIsh/controller/ProjectController.cs b/DiztinGUIsh/controller/ProjectController.cs index 78cd9f9f..fc2a60b6 100644 --- a/DiztinGUIsh/controller/ProjectController.cs +++ b/DiztinGUIsh/controller/ProjectController.cs @@ -3,7 +3,6 @@ using System.Diagnostics; using System.IO; using System.Linq; -using System.Security.Policy; using Diz.Core.export; using Diz.Core.import; using Diz.Core.model; diff --git a/DiztinGUIsh/window/VisualizerForm.cs b/DiztinGUIsh/window/VisualizerForm.cs index 64001819..1c994896 100644 --- a/DiztinGUIsh/window/VisualizerForm.cs +++ b/DiztinGUIsh/window/VisualizerForm.cs @@ -1,6 +1,5 @@ using System.Windows.Forms; using Diz.Core.model; -using Diz.Core.util; using DiztinGUIsh.window.usercontrols; namespace DiztinGUIsh.window diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs index 6b365ea3..9a838b0d 100644 --- a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs @@ -1,9 +1,7 @@ using System; -using System.Drawing; using System.Linq; using System.Threading.Tasks; using System.Windows.Forms; -using ByteSizeLib; using Diz.Core.import; namespace DiztinGUIsh.window.dialog diff --git a/DiztinGUIsh/window/dialog/ExportDisassembly.cs b/DiztinGUIsh/window/dialog/ExportDisassembly.cs index 1a19c15b..4226e7f6 100644 --- a/DiztinGUIsh/window/dialog/ExportDisassembly.cs +++ b/DiztinGUIsh/window/dialog/ExportDisassembly.cs @@ -1,8 +1,6 @@ using System; using System.IO; -using System.Text; using System.Windows.Forms; -using Diz.Core; using Diz.Core.export; using Diz.Core.model; using Diz.Core.util; diff --git a/DiztinGUIsh/window/dialog/InOutPointChecker.cs b/DiztinGUIsh/window/dialog/InOutPointChecker.cs index 20e636bd..79484e8d 100644 --- a/DiztinGUIsh/window/dialog/InOutPointChecker.cs +++ b/DiztinGUIsh/window/dialog/InOutPointChecker.cs @@ -1,11 +1,4 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; namespace DiztinGUIsh diff --git a/DiztinGUIsh/window/dialog/ProgressDialog.cs b/DiztinGUIsh/window/dialog/ProgressDialog.cs index b2987735..a3e73e9b 100644 --- a/DiztinGUIsh/window/dialog/ProgressDialog.cs +++ b/DiztinGUIsh/window/dialog/ProgressDialog.cs @@ -1,12 +1,4 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Drawing; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; -using System.Windows.Forms; +using System.Windows.Forms; namespace DiztinGUIsh.window.dialog { From 39623dc65e74b1847110f84a6dcf829e4349f14b Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 25 Oct 2020 14:49:21 -0400 Subject: [PATCH 116/136] lint: I let Jetbrains rename everything to be consistent with its access level - also, move RomMapMode and RomSpeed out of Data --- Diz.Core/SampleRomData.cs | 273 +++++----- Diz.Core/arch/CPU65C816.cs | 490 +++++++++--------- Diz.Core/export/LogCreator.ErrorChecking.cs | 10 +- Diz.Core/export/LogCreator.Setup.cs | 40 +- Diz.Core/export/LogCreator.cs | 186 +++---- Diz.Core/export/LogOutput.cs | 60 +-- Diz.Core/export/LogWriterSettings.cs | 58 +-- Diz.Core/import/BSNESImportStreamProcessor.cs | 2 +- Diz.Core/import/BSNESTraceLogCapture.cs | 30 +- Diz.Core/import/BSNESTraceLogImporter.cs | 140 ++--- Diz.Core/import/BSNESUsageMapImporter.cs | 8 +- Diz.Core/import/BizHawkCdlImporter.cs | 20 +- Diz.Core/model/Data.Constants.cs | 43 +- Diz.Core/model/Data.Properties.cs | 9 +- Diz.Core/model/Data.cs | 158 +++--- Diz.Core/model/Label.cs | 12 +- Diz.Core/model/ROMByte.cs | 10 +- Diz.Core/model/RomBytes.cs | 24 +- Diz.Core/serialization/ImportSettings.cs | 9 +- Diz.Core/serialization/ProjectFileManager.cs | 4 +- .../binary_serializer_old/BinarySerializer.cs | 52 +- .../xml_serializer/ProjectXMLSerializer.cs | 35 +- .../xml_serializer/RepeaterCompression.cs | 4 +- .../xml_serializer/RomByteEncoding.cs | 68 +-- .../xml_serializer/RomBytesXMLSerializer.cs | 45 +- .../xml_serializer/SubstitutionCompression.cs | 6 +- .../xml_serializer/XMLSerializerSupport.cs | 10 +- Diz.Core/util/ByteUtil.cs | 16 +- Diz.Core/util/RomUtil.cs | 154 +++--- Diz.Core/util/RomVisual.cs | 20 +- Diz.Core/util/Util.cs | 6 +- Diz.Test/LogCreator.cs | 81 +-- Diz.Test/RomByteTests.cs | 8 +- Diz.Test/SerializerDictionaryTest.cs | 16 +- DiztinGUIsh/controller/ProjectController.cs | 24 +- DiztinGUIsh/util/ProgressBarWorker.cs | 20 +- DiztinGUIsh/window/AliasList.cs | 36 +- DiztinGUIsh/window/MainWindow.cs | 134 ++--- ...BSNESTraceLogBinaryMonitorForm.Designer.cs | 4 +- .../BSNESTraceLogBinaryMonitorForm.UI.cs | 20 +- .../dialog/BSNESTraceLogBinaryMonitorForm.cs | 20 +- .../window/dialog/ExportDisassembly.cs | 38 +- DiztinGUIsh/window/dialog/GotoDialog.cs | 26 +- DiztinGUIsh/window/dialog/HarshAutoStep.cs | 18 +- DiztinGUIsh/window/dialog/ImportROMDialog.cs | 26 +- .../dialog/ImportROMDialogController.cs | 14 +- DiztinGUIsh/window/dialog/MarkManyDialog.cs | 24 +- .../window/dialog/MisalignmentChecker.cs | 6 +- .../window/usercontrols/RomBankVisualizer.cs | 4 +- DiztinGUIsh/window/usercontrols/RomImage.cs | 22 +- 50 files changed, 1274 insertions(+), 1269 deletions(-) diff --git a/Diz.Core/SampleRomData.cs b/Diz.Core/SampleRomData.cs index 3e743d0b..7d866f1d 100644 --- a/Diz.Core/SampleRomData.cs +++ b/Diz.Core/SampleRomData.cs @@ -1,4 +1,5 @@ using Diz.Core.model; +using Diz.Core.util; using IX.Observable; namespace Diz.Core @@ -12,8 +13,8 @@ public static SampleRomData SampleData // one-time: take our sample data from below and bolt some extra stuff on top of it. // then, cache all this in a static read-only property - if (finalSampleData != null) - return finalSampleData; + if (_finalSampleData != null) + return _finalSampleData; // tricky: this sample data can be used to populate the "sample assembly output" // window to demo some features. One thing we'd like to demo is showing generated @@ -24,165 +25,165 @@ public static SampleRomData SampleData // only assembling bytes up to BaseSampleData.SizeOverride. BaseSampleData.OriginalRomSizeBeforePadding = BaseSampleData.RomBytes.Count; while (BaseSampleData.RomBytes.Count < 0x8000) - BaseSampleData.RomBytes.Add(new ROMByte()); + BaseSampleData.RomBytes.Add(new RomByte()); - finalSampleData = BaseSampleData; + _finalSampleData = BaseSampleData; return BaseSampleData; } } public int OriginalRomSizeBeforePadding { get; set; } - private static SampleRomData finalSampleData; + private static SampleRomData _finalSampleData; private static readonly SampleRomData BaseSampleData = new SampleRomData { // random sample code I made up; hopefully it shows a little bit of // everything so you can see how the settings will effect the output - RomMapMode = ROMMapMode.LoROM, - RomSpeed = ROMSpeed.FastROM, + RomMapMode = RomMapMode.LoRom, + RomSpeed = RomSpeed.FastRom, RomBytes = new RomBytes { - new ROMByte {Rom = 0x78, TypeFlag = FlagType.Opcode, MFlag = true, XFlag = true, Point = InOutPoint.InPoint}, - new ROMByte {Rom = 0xA9, TypeFlag = FlagType.Opcode, MFlag = true, XFlag = true}, - new ROMByte {Rom = 0x01, TypeFlag = FlagType.Operand}, - new ROMByte {Rom = 0x8D, TypeFlag = FlagType.Opcode, MFlag = true, XFlag = true}, - new ROMByte {Rom = 0x0D, TypeFlag = FlagType.Operand}, - new ROMByte {Rom = 0x42, TypeFlag = FlagType.Operand}, - new ROMByte {Rom = 0x5C, TypeFlag = FlagType.Opcode, MFlag = true, XFlag = true, Point = InOutPoint.EndPoint}, - new ROMByte {Rom = 0x0A, TypeFlag = FlagType.Operand}, - new ROMByte {Rom = 0x80, TypeFlag = FlagType.Operand}, - new ROMByte {Rom = 0x80, TypeFlag = FlagType.Operand}, - new ROMByte {Rom = 0xC2, TypeFlag = FlagType.Opcode, MFlag = true, XFlag = true, Point = InOutPoint.InPoint}, - new ROMByte {Rom = 0x30, TypeFlag = FlagType.Operand}, - new ROMByte {Rom = 0xA9, TypeFlag = FlagType.Opcode}, - new ROMByte {Rom = 0x00, TypeFlag = FlagType.Operand}, - new ROMByte {Rom = 0x21, TypeFlag = FlagType.Operand}, - new ROMByte {Rom = 0x5B, TypeFlag = FlagType.Opcode}, - new ROMByte {Rom = 0x4B, TypeFlag = FlagType.Opcode, DirectPage = 0x2100}, - new ROMByte {Rom = 0xAB, TypeFlag = FlagType.Opcode, DirectPage = 0x2100}, - new ROMByte {Rom = 0xA2, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x07, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xBF, TypeFlag = FlagType.Opcode, Point = InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x32, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x80, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x80, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x9F, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x7E, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xCA, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xCA, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x10, TypeFlag = FlagType.Opcode, Point = InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xF4, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x64, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x40, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x64, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x41, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x64, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x42, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x64, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x43, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xAE, TypeFlag = FlagType.Opcode, Point = InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xFC, TypeFlag = FlagType.Opcode, Point = InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x3A, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x80, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x4C, TypeFlag = FlagType.Opcode, Point = InOutPoint.EndPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xC0, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = FlagType.Data16Bit, Point = InOutPoint.ReadPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x08, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x10, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x20, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x44, TypeFlag = FlagType.Pointer16Bit, Point = InOutPoint.ReadPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x80, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x7B, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x80, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x44, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x81, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xC4, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x81, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x0A, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x82, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x08, TypeFlag = FlagType.Opcode, Point = InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x8B, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x4B, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xAB, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xE2, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x20, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xC2, TypeFlag = FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x10, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xA2, TypeFlag = FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x1F, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x78, TypeFlag = FlagType.Opcode, MFlag = true, XFlag = true, Point = InOutPoint.InPoint}, + new RomByte {Rom = 0xA9, TypeFlag = FlagType.Opcode, MFlag = true, XFlag = true}, + new RomByte {Rom = 0x01, TypeFlag = FlagType.Operand}, + new RomByte {Rom = 0x8D, TypeFlag = FlagType.Opcode, MFlag = true, XFlag = true}, + new RomByte {Rom = 0x0D, TypeFlag = FlagType.Operand}, + new RomByte {Rom = 0x42, TypeFlag = FlagType.Operand}, + new RomByte {Rom = 0x5C, TypeFlag = FlagType.Opcode, MFlag = true, XFlag = true, Point = InOutPoint.EndPoint}, + new RomByte {Rom = 0x0A, TypeFlag = FlagType.Operand}, + new RomByte {Rom = 0x80, TypeFlag = FlagType.Operand}, + new RomByte {Rom = 0x80, TypeFlag = FlagType.Operand}, + new RomByte {Rom = 0xC2, TypeFlag = FlagType.Opcode, MFlag = true, XFlag = true, Point = InOutPoint.InPoint}, + new RomByte {Rom = 0x30, TypeFlag = FlagType.Operand}, + new RomByte {Rom = 0xA9, TypeFlag = FlagType.Opcode}, + new RomByte {Rom = 0x00, TypeFlag = FlagType.Operand}, + new RomByte {Rom = 0x21, TypeFlag = FlagType.Operand}, + new RomByte {Rom = 0x5B, TypeFlag = FlagType.Opcode}, + new RomByte {Rom = 0x4B, TypeFlag = FlagType.Opcode, DirectPage = 0x2100}, + new RomByte {Rom = 0xAB, TypeFlag = FlagType.Opcode, DirectPage = 0x2100}, + new RomByte {Rom = 0xA2, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x07, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xBF, TypeFlag = FlagType.Opcode, Point = InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x32, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x80, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x80, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x9F, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x7E, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xCA, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xCA, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x10, TypeFlag = FlagType.Opcode, Point = InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xF4, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x64, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x40, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x64, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x41, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x64, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x42, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x64, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x43, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xAE, TypeFlag = FlagType.Opcode, Point = InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xFC, TypeFlag = FlagType.Opcode, Point = InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x3A, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x80, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x4C, TypeFlag = FlagType.Opcode, Point = InOutPoint.EndPoint, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xC0, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x00, TypeFlag = FlagType.Data16Bit, Point = InOutPoint.ReadPoint, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x00, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x08, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x00, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x10, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x00, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x20, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x00, TypeFlag = FlagType.Data16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x44, TypeFlag = FlagType.Pointer16Bit, Point = InOutPoint.ReadPoint, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x80, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x7B, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x80, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x44, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x81, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xC4, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x81, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x0A, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x82, TypeFlag = FlagType.Pointer16Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x08, TypeFlag = FlagType.Opcode, Point = InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x8B, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x4B, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xAB, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xE2, TypeFlag = FlagType.Opcode, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x20, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xC2, TypeFlag = FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x10, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xA2, TypeFlag = FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x1F, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, // -------------------------- // highlighting a particular section here // we will use this for unit tests as well. // LDA.W Test_Data,X - new ROMByte {Rom = 0xBD, TypeFlag = FlagType.Opcode, MFlag = true, Point = InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x5B, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, // Test_Data - new ROMByte {Rom = 0x80, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, // Test_Data + new RomByte {Rom = 0xBD, TypeFlag = FlagType.Opcode, MFlag = true, Point = InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x5B, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, // Test_Data + new RomByte {Rom = 0x80, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, // Test_Data // STA.W $0100,X - new ROMByte {Rom = 0x9D, TypeFlag = FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x01, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x9D, TypeFlag = FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x00, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x01, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, // DEX - new ROMByte {Rom = 0xCA, TypeFlag = FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xCA, TypeFlag = FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, // BPL CODE_80804F - new ROMByte {Rom = 0x10, TypeFlag = FlagType.Opcode, MFlag = true, Point = InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xF7, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x10, TypeFlag = FlagType.Opcode, MFlag = true, Point = InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xF7, TypeFlag = FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, // ------------------------------------ - new ROMByte {Rom = 0xAB, TypeFlag = FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x28, TypeFlag = FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x60, TypeFlag = FlagType.Opcode, Point = InOutPoint.EndPoint, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xAB, TypeFlag = FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x28, TypeFlag = FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x60, TypeFlag = FlagType.Opcode, Point = InOutPoint.EndPoint, DataBank = 0x80, DirectPage = 0x2100}, // -------------------------- - new ROMByte {Rom = 0x45, TypeFlag = FlagType.Data8Bit, Point = InOutPoint.ReadPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x8D, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x69, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x83, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xB2, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x99, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x23, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x01, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xA3, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xF8, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x52, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x08, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xBB, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x29, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x5C, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x32, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xE7, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x88, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x3C, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x30, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x18, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x9A, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xB0, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x34, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x8C, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xDD, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x05, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xB7, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x83, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x34, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x6D, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x45, TypeFlag = FlagType.Data8Bit, Point = InOutPoint.ReadPoint, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x8D, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x69, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x83, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xB2, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x99, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x00, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x23, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x01, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xA3, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xF8, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x52, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x08, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xBB, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x29, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x5C, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x32, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xE7, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x88, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x3C, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x30, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x18, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x9A, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xB0, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x34, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x8C, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xDD, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x05, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xB7, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x83, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x34, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x6D, TypeFlag = FlagType.Data8Bit, DataBank = 0x80, DirectPage = 0x2100}, }, Comments = new ObservableDictionary() { @@ -193,12 +194,12 @@ public static SampleRomData SampleData }, Labels = new ObservableDictionary() { - {0x808000 + 0x00, new Label {name = "Emulation_RESET", comment = "Sample emulation reset location"}}, - {0x808000 + 0x0A, new Label {name = "FastRESET", comment = "Sample label"}}, - {0x808000 + 0x32, new Label {name = "Test_Indices"}}, - {0x808000 + 0x3A, new Label {name = "Pointer_Table"}}, - {0x808000 + 0x44, new Label {name = "First_Routine"}}, - {0x808000 + 0x5B, new Label {name = "Test_Data", comment = "Pretty cool huh?"}} + {0x808000 + 0x00, new Label {Name = "Emulation_RESET", Comment = "Sample emulation reset location"}}, + {0x808000 + 0x0A, new Label {Name = "FastRESET", Comment = "Sample label"}}, + {0x808000 + 0x32, new Label {Name = "Test_Indices"}}, + {0x808000 + 0x3A, new Label {Name = "Pointer_Table"}}, + {0x808000 + 0x44, new Label {Name = "First_Routine"}}, + {0x808000 + 0x5B, new Label {Name = "Test_Data", Comment = "Pretty cool huh?"}} }, }; } diff --git a/Diz.Core/arch/CPU65C816.cs b/Diz.Core/arch/CPU65C816.cs index 78430c4b..396955b2 100644 --- a/Diz.Core/arch/CPU65C816.cs +++ b/Diz.Core/arch/CPU65C816.cs @@ -3,41 +3,41 @@ namespace Diz.Core.arch { - public class CPU65C816 + public class Cpu65C816 { - private readonly Data Data; - public CPU65C816(Data data) + private readonly Data data; + public Cpu65C816(Data data) { - Data = data; + this.data = data; } public int Step(int offset, bool branch, bool force, int prevOffset) { - var opcode = Data.GetROMByte(offset); - var prevDirectPage = Data.GetDirectPage(offset); - var prevDataBank = Data.GetDataBank(offset); - bool prevX = Data.GetXFlag(offset), prevM = Data.GetMFlag(offset); + var opcode = data.GetRomByte(offset); + var prevDirectPage = data.GetDirectPage(offset); + var prevDataBank = data.GetDataBank(offset); + bool prevX = data.GetXFlag(offset), prevM = data.GetMFlag(offset); - while (prevOffset >= 0 && Data.GetFlag(prevOffset) == Data.FlagType.Operand) prevOffset--; - if (prevOffset >= 0 && Data.GetFlag(prevOffset) == Data.FlagType.Opcode) + while (prevOffset >= 0 && data.GetFlag(prevOffset) == Data.FlagType.Operand) prevOffset--; + if (prevOffset >= 0 && data.GetFlag(prevOffset) == Data.FlagType.Opcode) { - prevDirectPage = Data.GetDirectPage(prevOffset); - prevDataBank = Data.GetDataBank(prevOffset); - prevX = Data.GetXFlag(prevOffset); - prevM = Data.GetMFlag(prevOffset); + prevDirectPage = data.GetDirectPage(prevOffset); + prevDataBank = data.GetDataBank(prevOffset); + prevX = data.GetXFlag(prevOffset); + prevM = data.GetMFlag(prevOffset); } if (opcode == 0xC2 || opcode == 0xE2) // REP SEP { - prevX = (Data.GetROMByte(offset + 1) & 0x10) != 0 ? opcode == 0xE2 : prevX; - prevM = (Data.GetROMByte(offset + 1) & 0x20) != 0 ? opcode == 0xE2 : prevM; + prevX = (data.GetRomByte(offset + 1) & 0x10) != 0 ? opcode == 0xE2 : prevX; + prevM = (data.GetRomByte(offset + 1) & 0x20) != 0 ? opcode == 0xE2 : prevM; } // set first byte first, so the instruction length is correct - Data.SetFlag(offset, Data.FlagType.Opcode); - Data.SetDataBank(offset, prevDataBank); - Data.SetDirectPage(offset, prevDirectPage); - Data.SetXFlag(offset, prevX); - Data.SetMFlag(offset, prevM); + data.SetFlag(offset, Data.FlagType.Opcode); + data.SetDataBank(offset, prevDataBank); + data.SetDirectPage(offset, prevDirectPage); + data.SetXFlag(offset, prevX); + data.SetMFlag(offset, prevM); var length = GetInstructionLength(offset); @@ -54,11 +54,11 @@ public int Step(int offset, bool branch, bool force, int prevOffset) // in most situations. for (var i = 1; i < length; i++) { - Data.SetFlag(offset + i, Data.FlagType.Operand); - Data.SetDataBank(offset + i, prevDataBank); - Data.SetDirectPage(offset + i, prevDirectPage); - Data.SetXFlag(offset + i, prevX); - Data.SetMFlag(offset + i, prevM); + data.SetFlag(offset + i, Data.FlagType.Operand); + data.SetDataBank(offset + i, prevDataBank); + data.SetDirectPage(offset + i, prevDirectPage); + data.SetXFlag(offset + i, prevX); + data.SetMFlag(offset + i, prevM); } MarkInOutPoints(offset); @@ -71,7 +71,7 @@ public int Step(int offset, bool branch, bool force, int prevOffset) opcode != 0x22)))) return nextOffset; - var iaNextOffsetPc = Data.ConvertSNEStoPC(GetIntermediateAddress(offset, true)); + var iaNextOffsetPc = data.ConvertSnesToPc(GetIntermediateAddress(offset, true)); if (iaNextOffsetPc >= 0) nextOffset = iaNextOffsetPc; @@ -83,58 +83,58 @@ public int Step(int offset, bool branch, bool force, int prevOffset) public int GetIntermediateAddress(int offset, bool resolve) { int bank, directPage, operand, programCounter; - var opcode = Data.GetROMByte(offset); + var opcode = data.GetRomByte(offset); var mode = GetAddressMode(offset); switch (mode) { - case AddressMode.DIRECT_PAGE: - case AddressMode.DIRECT_PAGE_X_INDEX: - case AddressMode.DIRECT_PAGE_Y_INDEX: - case AddressMode.DIRECT_PAGE_INDIRECT: - case AddressMode.DIRECT_PAGE_X_INDEX_INDIRECT: - case AddressMode.DIRECT_PAGE_INDIRECT_Y_INDEX: - case AddressMode.DIRECT_PAGE_LONG_INDIRECT: - case AddressMode.DIRECT_PAGE_LONG_INDIRECT_Y_INDEX: + case AddressMode.DirectPage: + case AddressMode.DirectPageXIndex: + case AddressMode.DirectPageYIndex: + case AddressMode.DirectPageIndirect: + case AddressMode.DirectPageXIndexIndirect: + case AddressMode.DirectPageIndirectYIndex: + case AddressMode.DirectPageLongIndirect: + case AddressMode.DirectPageLongIndirectYIndex: if (resolve) { - directPage = Data.GetDirectPage(offset); - operand = Data.GetROMByte(offset + 1); + directPage = data.GetDirectPage(offset); + operand = data.GetRomByte(offset + 1); return (directPage + operand) & 0xFFFF; } else { - goto case AddressMode.DIRECT_PAGE_S_INDEX; + goto case AddressMode.DirectPageSIndex; } - case AddressMode.DIRECT_PAGE_S_INDEX: - case AddressMode.DIRECT_PAGE_S_INDEX_INDIRECT_Y_INDEX: - return Data.GetROMByte(offset + 1); - case AddressMode.ADDRESS: - case AddressMode.ADDRESS_X_INDEX: - case AddressMode.ADDRESS_Y_INDEX: - case AddressMode.ADDRESS_X_INDEX_INDIRECT: + case AddressMode.DirectPageSIndex: + case AddressMode.DirectPageSIndexIndirectYIndex: + return data.GetRomByte(offset + 1); + case AddressMode.Address: + case AddressMode.AddressXIndex: + case AddressMode.AddressYIndex: + case AddressMode.AddressXIndexIndirect: bank = (opcode == 0x20 || opcode == 0x4C || opcode == 0x7C || opcode == 0xFC) ? - Data.ConvertPCtoSNES(offset) >> 16 : - Data.GetDataBank(offset); - operand = Data.GetROMWord(offset + 1); + data.ConvertPCtoSnes(offset) >> 16 : + data.GetDataBank(offset); + operand = data.GetRomWord(offset + 1); return (bank << 16) | operand; - case AddressMode.ADDRESS_INDIRECT: - case AddressMode.ADDRESS_LONG_INDIRECT: - operand = Data.GetROMWord(offset + 1); + case AddressMode.AddressIndirect: + case AddressMode.AddressLongIndirect: + operand = data.GetRomWord(offset + 1); return operand; - case AddressMode.LONG: - case AddressMode.LONG_X_INDEX: - operand = Data.GetROMLong(offset + 1); + case AddressMode.Long: + case AddressMode.LongXIndex: + operand = data.GetRomLong(offset + 1); return operand; - case AddressMode.RELATIVE_8: - programCounter = Data.ConvertPCtoSNES(offset + 2); + case AddressMode.Relative8: + programCounter = data.ConvertPCtoSnes(offset + 2); bank = programCounter >> 16; - offset = (sbyte)Data.GetROMByte(offset + 1); + offset = (sbyte)data.GetRomByte(offset + 1); return (bank << 16) | ((programCounter + offset) & 0xFFFF); - case AddressMode.RELATIVE_16: - programCounter = Data.ConvertPCtoSNES(offset + 3); + case AddressMode.Relative16: + programCounter = data.ConvertPCtoSnes(offset + 3); bank = programCounter >> 16; - offset = (short)Data.GetROMWord(offset + 1); + offset = (short)data.GetRomWord(offset + 1); return (bank << 16) | ((programCounter + offset) & 0xFFFF); } return -1; @@ -146,18 +146,18 @@ public string GetInstruction(int offset) string format = GetInstructionFormatString(offset); string mnemonic = GetMnemonic(offset); string op1 = "", op2 = ""; - if (mode == AddressMode.BLOCK_MOVE) + if (mode == AddressMode.BlockMove) { - op1 = Util.NumberToBaseString(Data.GetROMByte(offset + 1), Util.NumberBase.Hexadecimal, 2, true); - op2 = Util.NumberToBaseString(Data.GetROMByte(offset + 2), Util.NumberBase.Hexadecimal, 2, true); + op1 = Util.NumberToBaseString(data.GetRomByte(offset + 1), Util.NumberBase.Hexadecimal, 2, true); + op2 = Util.NumberToBaseString(data.GetRomByte(offset + 2), Util.NumberBase.Hexadecimal, 2, true); } - else if (mode == AddressMode.CONSTANT_8 || mode == AddressMode.IMMEDIATE_8) + else if (mode == AddressMode.Constant8 || mode == AddressMode.Immediate8) { - op1 = Util.NumberToBaseString(Data.GetROMByte(offset + 1), Util.NumberBase.Hexadecimal, 2, true); + op1 = Util.NumberToBaseString(data.GetRomByte(offset + 1), Util.NumberBase.Hexadecimal, 2, true); } - else if (mode == AddressMode.IMMEDIATE_16) + else if (mode == AddressMode.Immediate16) { - op1 = Util.NumberToBaseString(Data.GetROMWord(offset + 1), Util.NumberBase.Hexadecimal, 4, true); + op1 = Util.NumberToBaseString(data.GetRomWord(offset + 1), Util.NumberBase.Hexadecimal, 4, true); } else { @@ -179,35 +179,35 @@ public static int InstructionLength(AddressMode mode) { switch (mode) { - case AddressMode.IMPLIED: - case AddressMode.ACCUMULATOR: + case AddressMode.Implied: + case AddressMode.Accumulator: return 1; - case AddressMode.CONSTANT_8: - case AddressMode.IMMEDIATE_8: - case AddressMode.DIRECT_PAGE: - case AddressMode.DIRECT_PAGE_X_INDEX: - case AddressMode.DIRECT_PAGE_Y_INDEX: - case AddressMode.DIRECT_PAGE_S_INDEX: - case AddressMode.DIRECT_PAGE_INDIRECT: - case AddressMode.DIRECT_PAGE_X_INDEX_INDIRECT: - case AddressMode.DIRECT_PAGE_INDIRECT_Y_INDEX: - case AddressMode.DIRECT_PAGE_S_INDEX_INDIRECT_Y_INDEX: - case AddressMode.DIRECT_PAGE_LONG_INDIRECT: - case AddressMode.DIRECT_PAGE_LONG_INDIRECT_Y_INDEX: - case AddressMode.RELATIVE_8: + case AddressMode.Constant8: + case AddressMode.Immediate8: + case AddressMode.DirectPage: + case AddressMode.DirectPageXIndex: + case AddressMode.DirectPageYIndex: + case AddressMode.DirectPageSIndex: + case AddressMode.DirectPageIndirect: + case AddressMode.DirectPageXIndexIndirect: + case AddressMode.DirectPageIndirectYIndex: + case AddressMode.DirectPageSIndexIndirectYIndex: + case AddressMode.DirectPageLongIndirect: + case AddressMode.DirectPageLongIndirectYIndex: + case AddressMode.Relative8: return 2; - case AddressMode.IMMEDIATE_16: - case AddressMode.ADDRESS: - case AddressMode.ADDRESS_X_INDEX: - case AddressMode.ADDRESS_Y_INDEX: - case AddressMode.ADDRESS_INDIRECT: - case AddressMode.ADDRESS_X_INDEX_INDIRECT: - case AddressMode.ADDRESS_LONG_INDIRECT: - case AddressMode.BLOCK_MOVE: - case AddressMode.RELATIVE_16: + case AddressMode.Immediate16: + case AddressMode.Address: + case AddressMode.AddressXIndex: + case AddressMode.AddressYIndex: + case AddressMode.AddressIndirect: + case AddressMode.AddressXIndexIndirect: + case AddressMode.AddressLongIndirect: + case AddressMode.BlockMove: + case AddressMode.Relative16: return 3; - case AddressMode.LONG: - case AddressMode.LONG_X_INDEX: + case AddressMode.Long: + case AddressMode.LongXIndex: return 4; } @@ -216,62 +216,62 @@ public static int InstructionLength(AddressMode mode) public void MarkInOutPoints(int offset) { - int opcode = Data.GetROMByte(offset); - int iaOffsetPC = Data.ConvertSNEStoPC(Data.GetIntermediateAddress(offset, true)); + int opcode = data.GetRomByte(offset); + int iaOffsetPc = data.ConvertSnesToPc(data.GetIntermediateAddress(offset, true)); // set read point on EA - if (iaOffsetPC >= 0 && ( // these are all read/write/math instructions + if (iaOffsetPc >= 0 && ( // these are all read/write/math instructions ((opcode & 0x04) != 0) || ((opcode & 0x0F) == 0x01) || ((opcode & 0x0F) == 0x03) || ((opcode & 0x1F) == 0x12) || ((opcode & 0x1F) == 0x19)) && (opcode != 0x45) && (opcode != 0x55) && (opcode != 0xF5) && (opcode != 0x4C) && (opcode != 0x5C) && (opcode != 0x6C) && (opcode != 0x7C) && (opcode != 0xDC) && (opcode != 0xFC) - ) Data.SetInOutPoint(iaOffsetPC, Data.InOutPoint.ReadPoint); + ) data.SetInOutPoint(iaOffsetPc, Data.InOutPoint.ReadPoint); // set end point on offset if (opcode == 0x40 || opcode == 0x4C || opcode == 0x5C || opcode == 0x60 // RTI JMP JML RTS || opcode == 0x6B || opcode == 0x6C || opcode == 0x7C || opcode == 0x80 // RTL JMP JMP BRA || opcode == 0x82 || opcode == 0xDB || opcode == 0xDC // BRL STP JML - ) Data.SetInOutPoint(offset, Data.InOutPoint.EndPoint); + ) data.SetInOutPoint(offset, Data.InOutPoint.EndPoint); // set out point on offset // set in point on EA - if (iaOffsetPC >= 0 && ( + if (iaOffsetPc >= 0 && ( opcode == 0x4C || opcode == 0x5C || opcode == 0x80 || opcode == 0x82 // JMP JML BRA BRL || opcode == 0x10 || opcode == 0x30 || opcode == 0x50 || opcode == 0x70 // BPL BMI BVC BVS || opcode == 0x90 || opcode == 0xB0 || opcode == 0xD0 || opcode == 0xF0 // BCC BCS BNE BEQ || opcode == 0x20 || opcode == 0x22)) // JSR JSL { - Data.SetInOutPoint(offset, Data.InOutPoint.OutPoint); - Data.SetInOutPoint(iaOffsetPC, Data.InOutPoint.InPoint); + data.SetInOutPoint(offset, Data.InOutPoint.OutPoint); + data.SetInOutPoint(iaOffsetPc, Data.InOutPoint.InPoint); } } private string FormatOperandAddress(int offset, AddressMode mode) { - int address = Data.GetIntermediateAddress(offset); + int address = data.GetIntermediateAddress(offset); if (address < 0) return ""; - var label = Data.GetLabelName(address); + var label = data.GetLabelName(address); if (label != "") return label; var count = BytesToShow(mode); - if (mode == AddressMode.RELATIVE_8 || mode == AddressMode.RELATIVE_16) address = Data.GetROMWord(offset + 1); + if (mode == AddressMode.Relative8 || mode == AddressMode.Relative16) address = data.GetRomWord(offset + 1); address &= ~(-1 << (8 * count)); return Util.NumberToBaseString(address, Util.NumberBase.Hexadecimal, 2 * count, true); } private string GetMnemonic(int offset, bool showHint = true) { - var mn = mnemonics[Data.GetROMByte(offset)]; + var mn = Mnemonics[data.GetRomByte(offset)]; if (!showHint) return mn; var mode = GetAddressMode(offset); var count = BytesToShow(mode); - if (mode == AddressMode.CONSTANT_8 || mode == AddressMode.RELATIVE_16 || mode == AddressMode.RELATIVE_8) return mn; + if (mode == AddressMode.Constant8 || mode == AddressMode.Relative16 || mode == AddressMode.Relative8) return mn; return count switch { @@ -286,31 +286,31 @@ private static int BytesToShow(AddressMode mode) { switch (mode) { - case AddressMode.CONSTANT_8: - case AddressMode.IMMEDIATE_8: - case AddressMode.DIRECT_PAGE: - case AddressMode.DIRECT_PAGE_X_INDEX: - case AddressMode.DIRECT_PAGE_Y_INDEX: - case AddressMode.DIRECT_PAGE_S_INDEX: - case AddressMode.DIRECT_PAGE_INDIRECT: - case AddressMode.DIRECT_PAGE_X_INDEX_INDIRECT: - case AddressMode.DIRECT_PAGE_INDIRECT_Y_INDEX: - case AddressMode.DIRECT_PAGE_S_INDEX_INDIRECT_Y_INDEX: - case AddressMode.DIRECT_PAGE_LONG_INDIRECT: - case AddressMode.DIRECT_PAGE_LONG_INDIRECT_Y_INDEX: - case AddressMode.RELATIVE_8: + case AddressMode.Constant8: + case AddressMode.Immediate8: + case AddressMode.DirectPage: + case AddressMode.DirectPageXIndex: + case AddressMode.DirectPageYIndex: + case AddressMode.DirectPageSIndex: + case AddressMode.DirectPageIndirect: + case AddressMode.DirectPageXIndexIndirect: + case AddressMode.DirectPageIndirectYIndex: + case AddressMode.DirectPageSIndexIndirectYIndex: + case AddressMode.DirectPageLongIndirect: + case AddressMode.DirectPageLongIndirectYIndex: + case AddressMode.Relative8: return 1; - case AddressMode.IMMEDIATE_16: - case AddressMode.ADDRESS: - case AddressMode.ADDRESS_X_INDEX: - case AddressMode.ADDRESS_Y_INDEX: - case AddressMode.ADDRESS_INDIRECT: - case AddressMode.ADDRESS_X_INDEX_INDIRECT: - case AddressMode.ADDRESS_LONG_INDIRECT: - case AddressMode.RELATIVE_16: + case AddressMode.Immediate16: + case AddressMode.Address: + case AddressMode.AddressXIndex: + case AddressMode.AddressYIndex: + case AddressMode.AddressIndirect: + case AddressMode.AddressXIndexIndirect: + case AddressMode.AddressLongIndirect: + case AddressMode.Relative16: return 2; - case AddressMode.LONG: - case AddressMode.LONG_X_INDEX: + case AddressMode.Long: + case AddressMode.LongXIndex: return 3; } return 0; @@ -324,45 +324,45 @@ private string GetInstructionFormatString(int offset) var mode = GetAddressMode(offset); switch (mode) { - case AddressMode.IMPLIED: + case AddressMode.Implied: return "{0}"; - case AddressMode.ACCUMULATOR: + case AddressMode.Accumulator: return "{0} A"; - case AddressMode.CONSTANT_8: - case AddressMode.IMMEDIATE_8: - case AddressMode.IMMEDIATE_16: + case AddressMode.Constant8: + case AddressMode.Immediate8: + case AddressMode.Immediate16: return "{0} #{1}"; - case AddressMode.DIRECT_PAGE: - case AddressMode.ADDRESS: - case AddressMode.LONG: - case AddressMode.RELATIVE_8: - case AddressMode.RELATIVE_16: + case AddressMode.DirectPage: + case AddressMode.Address: + case AddressMode.Long: + case AddressMode.Relative8: + case AddressMode.Relative16: return "{0} {1}"; - case AddressMode.DIRECT_PAGE_X_INDEX: - case AddressMode.ADDRESS_X_INDEX: - case AddressMode.LONG_X_INDEX: + case AddressMode.DirectPageXIndex: + case AddressMode.AddressXIndex: + case AddressMode.LongXIndex: return "{0} {1},X"; - case AddressMode.DIRECT_PAGE_Y_INDEX: - case AddressMode.ADDRESS_Y_INDEX: + case AddressMode.DirectPageYIndex: + case AddressMode.AddressYIndex: return "{0} {1},Y"; - case AddressMode.DIRECT_PAGE_S_INDEX: + case AddressMode.DirectPageSIndex: return "{0} {1},S"; - case AddressMode.DIRECT_PAGE_INDIRECT: - case AddressMode.ADDRESS_INDIRECT: + case AddressMode.DirectPageIndirect: + case AddressMode.AddressIndirect: return "{0} ({1})"; - case AddressMode.DIRECT_PAGE_X_INDEX_INDIRECT: - case AddressMode.ADDRESS_X_INDEX_INDIRECT: + case AddressMode.DirectPageXIndexIndirect: + case AddressMode.AddressXIndexIndirect: return "{0} ({1},X)"; - case AddressMode.DIRECT_PAGE_INDIRECT_Y_INDEX: + case AddressMode.DirectPageIndirectYIndex: return "{0} ({1}),Y"; - case AddressMode.DIRECT_PAGE_S_INDEX_INDIRECT_Y_INDEX: + case AddressMode.DirectPageSIndexIndirectYIndex: return "{0} ({1},S),Y"; - case AddressMode.DIRECT_PAGE_LONG_INDIRECT: - case AddressMode.ADDRESS_LONG_INDIRECT: + case AddressMode.DirectPageLongIndirect: + case AddressMode.AddressLongIndirect: return "{0} [{1}]"; - case AddressMode.DIRECT_PAGE_LONG_INDIRECT_Y_INDEX: + case AddressMode.DirectPageLongIndirectYIndex: return "{0} [{1}],Y"; - case AddressMode.BLOCK_MOVE: + case AddressMode.BlockMove: return "{0} {1},{2}"; } return ""; @@ -370,33 +370,33 @@ private string GetInstructionFormatString(int offset) private AddressMode GetAddressMode(int offset) { - var mode = addressingModes[Data.GetROMByte(offset)]; + var mode = AddressingModes[data.GetRomByte(offset)]; return mode switch { - AddressMode.IMMEDIATE_M_FLAG_DEPENDENT => Data.GetMFlag(offset) - ? AddressMode.IMMEDIATE_8 - : AddressMode.IMMEDIATE_16, - AddressMode.IMMEDIATE_X_FLAG_DEPENDENT => Data.GetXFlag(offset) - ? AddressMode.IMMEDIATE_8 - : AddressMode.IMMEDIATE_16, + AddressMode.ImmediateMFlagDependent => data.GetMFlag(offset) + ? AddressMode.Immediate8 + : AddressMode.Immediate16, + AddressMode.ImmediateXFlagDependent => data.GetXFlag(offset) + ? AddressMode.Immediate8 + : AddressMode.Immediate16, _ => mode }; } public enum AddressMode : byte { - IMPLIED, ACCUMULATOR, CONSTANT_8, IMMEDIATE_8, IMMEDIATE_16, - IMMEDIATE_X_FLAG_DEPENDENT, IMMEDIATE_M_FLAG_DEPENDENT, - DIRECT_PAGE, DIRECT_PAGE_X_INDEX, DIRECT_PAGE_Y_INDEX, - DIRECT_PAGE_S_INDEX, DIRECT_PAGE_INDIRECT, DIRECT_PAGE_X_INDEX_INDIRECT, - DIRECT_PAGE_INDIRECT_Y_INDEX, DIRECT_PAGE_S_INDEX_INDIRECT_Y_INDEX, - DIRECT_PAGE_LONG_INDIRECT, DIRECT_PAGE_LONG_INDIRECT_Y_INDEX, - ADDRESS, ADDRESS_X_INDEX, ADDRESS_Y_INDEX, ADDRESS_INDIRECT, - ADDRESS_X_INDEX_INDIRECT, ADDRESS_LONG_INDIRECT, - LONG, LONG_X_INDEX, BLOCK_MOVE, RELATIVE_8, RELATIVE_16 + Implied, Accumulator, Constant8, Immediate8, Immediate16, + ImmediateXFlagDependent, ImmediateMFlagDependent, + DirectPage, DirectPageXIndex, DirectPageYIndex, + DirectPageSIndex, DirectPageIndirect, DirectPageXIndexIndirect, + DirectPageIndirectYIndex, DirectPageSIndexIndirectYIndex, + DirectPageLongIndirect, DirectPageLongIndirectYIndex, + Address, AddressXIndex, AddressYIndex, AddressIndirect, + AddressXIndexIndirect, AddressLongIndirect, + Long, LongXIndex, BlockMove, Relative8, Relative16 } - private static readonly string[] mnemonics = + private static readonly string[] Mnemonics = { "BRK", "ORA", "COP", "ORA", "TSB", "ORA", "ASL", "ORA", "PHP", "ORA", "ASL", "PHD", "TSB", "ORA", "ASL", "ORA", "BPL", "ORA", "ORA", "ORA", "TRB", "ORA", "ASL", "ORA", "CLC", "ORA", "INC", "TCS", "TRB", "ORA", "ASL", "ORA", @@ -416,79 +416,79 @@ public enum AddressMode : byte "BEQ", "SBC", "SBC", "SBC", "PEA", "SBC", "INC", "SBC", "SED", "SBC", "PLX", "XCE", "JSR", "SBC", "INC", "SBC" }; - private static readonly AddressMode[] addressingModes = + private static readonly AddressMode[] AddressingModes = { - AddressMode.CONSTANT_8, AddressMode.DIRECT_PAGE_X_INDEX_INDIRECT, AddressMode.CONSTANT_8, AddressMode.DIRECT_PAGE_S_INDEX, - AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE_LONG_INDIRECT, - AddressMode.IMPLIED, AddressMode.IMMEDIATE_M_FLAG_DEPENDENT, AddressMode.ACCUMULATOR, AddressMode.IMPLIED, - AddressMode.ADDRESS, AddressMode.ADDRESS, AddressMode.ADDRESS, AddressMode.LONG, - AddressMode.RELATIVE_8, AddressMode.DIRECT_PAGE_INDIRECT_Y_INDEX, AddressMode.DIRECT_PAGE_INDIRECT, AddressMode.DIRECT_PAGE_S_INDEX_INDIRECT_Y_INDEX, - AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE_X_INDEX, AddressMode.DIRECT_PAGE_X_INDEX, AddressMode.DIRECT_PAGE_LONG_INDIRECT_Y_INDEX, - AddressMode.IMPLIED, AddressMode.ADDRESS_Y_INDEX, AddressMode.ACCUMULATOR, AddressMode.IMPLIED, - AddressMode.ADDRESS, AddressMode.ADDRESS_X_INDEX, AddressMode.ADDRESS_X_INDEX, AddressMode.LONG_X_INDEX, - - AddressMode.ADDRESS, AddressMode.DIRECT_PAGE_X_INDEX_INDIRECT, AddressMode.LONG, AddressMode.DIRECT_PAGE_S_INDEX, - AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE_LONG_INDIRECT, - AddressMode.IMPLIED, AddressMode.IMMEDIATE_M_FLAG_DEPENDENT, AddressMode.ACCUMULATOR, AddressMode.IMPLIED, - AddressMode.ADDRESS, AddressMode.ADDRESS, AddressMode.ADDRESS, AddressMode.LONG, - AddressMode.RELATIVE_8, AddressMode.DIRECT_PAGE_INDIRECT_Y_INDEX, AddressMode.DIRECT_PAGE_INDIRECT, AddressMode.DIRECT_PAGE_S_INDEX_INDIRECT_Y_INDEX, - AddressMode.DIRECT_PAGE_X_INDEX, AddressMode.DIRECT_PAGE_X_INDEX, AddressMode.DIRECT_PAGE_X_INDEX, AddressMode.DIRECT_PAGE_LONG_INDIRECT_Y_INDEX, - AddressMode.IMPLIED, AddressMode.ADDRESS_Y_INDEX, AddressMode.ACCUMULATOR, AddressMode.IMPLIED, - AddressMode.ADDRESS_X_INDEX, AddressMode.ADDRESS_X_INDEX, AddressMode.ADDRESS_X_INDEX, AddressMode.LONG_X_INDEX, - - AddressMode.IMPLIED, AddressMode.DIRECT_PAGE_X_INDEX_INDIRECT, AddressMode.CONSTANT_8, AddressMode.DIRECT_PAGE_S_INDEX, - AddressMode.BLOCK_MOVE, AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE_LONG_INDIRECT, - AddressMode.IMPLIED, AddressMode.IMMEDIATE_M_FLAG_DEPENDENT, AddressMode.ACCUMULATOR, AddressMode.IMPLIED, - AddressMode.ADDRESS, AddressMode.ADDRESS, AddressMode.ADDRESS, AddressMode.LONG, - AddressMode.RELATIVE_8, AddressMode.DIRECT_PAGE_INDIRECT_Y_INDEX, AddressMode.DIRECT_PAGE_INDIRECT, AddressMode.DIRECT_PAGE_S_INDEX_INDIRECT_Y_INDEX, - AddressMode.BLOCK_MOVE, AddressMode.DIRECT_PAGE_X_INDEX, AddressMode.DIRECT_PAGE_X_INDEX, AddressMode.DIRECT_PAGE_LONG_INDIRECT_Y_INDEX, - AddressMode.IMPLIED, AddressMode.ADDRESS_Y_INDEX, AddressMode.IMPLIED, AddressMode.IMPLIED, - AddressMode.LONG, AddressMode.ADDRESS_X_INDEX, AddressMode.ADDRESS_X_INDEX, AddressMode.LONG_X_INDEX, - - AddressMode.IMPLIED, AddressMode.DIRECT_PAGE_X_INDEX_INDIRECT, AddressMode.RELATIVE_16, AddressMode.DIRECT_PAGE_S_INDEX, - AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE_LONG_INDIRECT, - AddressMode.IMPLIED, AddressMode.IMMEDIATE_M_FLAG_DEPENDENT, AddressMode.ACCUMULATOR, AddressMode.IMPLIED, - AddressMode.ADDRESS_INDIRECT, AddressMode.ADDRESS, AddressMode.ADDRESS, AddressMode.LONG, - AddressMode.RELATIVE_8, AddressMode.DIRECT_PAGE_INDIRECT_Y_INDEX, AddressMode.DIRECT_PAGE_INDIRECT, AddressMode.DIRECT_PAGE_S_INDEX_INDIRECT_Y_INDEX, - AddressMode.DIRECT_PAGE_X_INDEX, AddressMode.DIRECT_PAGE_X_INDEX, AddressMode.DIRECT_PAGE_X_INDEX, AddressMode.DIRECT_PAGE_LONG_INDIRECT_Y_INDEX, - AddressMode.IMPLIED, AddressMode.ADDRESS_Y_INDEX, AddressMode.IMPLIED, AddressMode.IMPLIED, - AddressMode.ADDRESS_X_INDEX_INDIRECT, AddressMode.ADDRESS_X_INDEX, AddressMode.ADDRESS_X_INDEX, AddressMode.LONG_X_INDEX, - - AddressMode.RELATIVE_8, AddressMode.DIRECT_PAGE_X_INDEX_INDIRECT, AddressMode.RELATIVE_16, AddressMode.DIRECT_PAGE_S_INDEX, - AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE_LONG_INDIRECT, - AddressMode.IMPLIED, AddressMode.IMMEDIATE_M_FLAG_DEPENDENT, AddressMode.IMPLIED, AddressMode.IMPLIED, - AddressMode.ADDRESS, AddressMode.ADDRESS, AddressMode.ADDRESS, AddressMode.LONG, - AddressMode.RELATIVE_8, AddressMode.DIRECT_PAGE_INDIRECT_Y_INDEX, AddressMode.DIRECT_PAGE_INDIRECT, AddressMode.DIRECT_PAGE_S_INDEX_INDIRECT_Y_INDEX, - AddressMode.DIRECT_PAGE_X_INDEX, AddressMode.DIRECT_PAGE_X_INDEX, AddressMode.DIRECT_PAGE_Y_INDEX, AddressMode.DIRECT_PAGE_LONG_INDIRECT_Y_INDEX, - AddressMode.IMPLIED, AddressMode.ADDRESS_Y_INDEX, AddressMode.IMPLIED, AddressMode.IMPLIED, - AddressMode.ADDRESS, AddressMode.ADDRESS_X_INDEX, AddressMode.ADDRESS_X_INDEX, AddressMode.LONG_X_INDEX, - - AddressMode.IMMEDIATE_X_FLAG_DEPENDENT, AddressMode.DIRECT_PAGE_X_INDEX_INDIRECT, AddressMode.IMMEDIATE_X_FLAG_DEPENDENT, AddressMode.DIRECT_PAGE_S_INDEX, - AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE_LONG_INDIRECT, - AddressMode.IMPLIED, AddressMode.IMMEDIATE_M_FLAG_DEPENDENT, AddressMode.IMPLIED, AddressMode.IMPLIED, - AddressMode.ADDRESS, AddressMode.ADDRESS, AddressMode.ADDRESS, AddressMode.LONG, - AddressMode.RELATIVE_8, AddressMode.DIRECT_PAGE_INDIRECT_Y_INDEX, AddressMode.DIRECT_PAGE_INDIRECT, AddressMode.DIRECT_PAGE_S_INDEX_INDIRECT_Y_INDEX, - AddressMode.DIRECT_PAGE_X_INDEX, AddressMode.DIRECT_PAGE_X_INDEX, AddressMode.DIRECT_PAGE_Y_INDEX, AddressMode.DIRECT_PAGE_LONG_INDIRECT_Y_INDEX, - AddressMode.IMPLIED, AddressMode.ADDRESS_Y_INDEX, AddressMode.IMPLIED, AddressMode.IMPLIED, - AddressMode.ADDRESS_X_INDEX, AddressMode.ADDRESS_X_INDEX, AddressMode.ADDRESS_Y_INDEX, AddressMode.LONG_X_INDEX, - - AddressMode.IMMEDIATE_X_FLAG_DEPENDENT, AddressMode.DIRECT_PAGE_X_INDEX_INDIRECT, AddressMode.CONSTANT_8, AddressMode.DIRECT_PAGE_S_INDEX, - AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE_LONG_INDIRECT, - AddressMode.IMPLIED, AddressMode.IMMEDIATE_M_FLAG_DEPENDENT, AddressMode.IMPLIED, AddressMode.IMPLIED, - AddressMode.ADDRESS, AddressMode.ADDRESS, AddressMode.ADDRESS, AddressMode.LONG, - AddressMode.RELATIVE_8, AddressMode.DIRECT_PAGE_INDIRECT_Y_INDEX, AddressMode.DIRECT_PAGE_INDIRECT, AddressMode.DIRECT_PAGE_S_INDEX_INDIRECT_Y_INDEX, - AddressMode.DIRECT_PAGE_INDIRECT, AddressMode.DIRECT_PAGE_X_INDEX, AddressMode.DIRECT_PAGE_X_INDEX, AddressMode.DIRECT_PAGE_LONG_INDIRECT_Y_INDEX, - AddressMode.IMPLIED, AddressMode.ADDRESS_Y_INDEX, AddressMode.IMPLIED, AddressMode.IMPLIED, - AddressMode.ADDRESS_LONG_INDIRECT, AddressMode.ADDRESS_X_INDEX, AddressMode.ADDRESS_X_INDEX, AddressMode.LONG_X_INDEX, - - AddressMode.IMMEDIATE_X_FLAG_DEPENDENT, AddressMode.DIRECT_PAGE_X_INDEX_INDIRECT, AddressMode.CONSTANT_8, AddressMode.DIRECT_PAGE_S_INDEX, - AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE, AddressMode.DIRECT_PAGE_LONG_INDIRECT, - AddressMode.IMPLIED, AddressMode.IMMEDIATE_M_FLAG_DEPENDENT, AddressMode.IMPLIED, AddressMode.IMPLIED, - AddressMode.ADDRESS, AddressMode.ADDRESS, AddressMode.ADDRESS, AddressMode.LONG, - AddressMode.RELATIVE_8, AddressMode.DIRECT_PAGE_INDIRECT_Y_INDEX, AddressMode.DIRECT_PAGE_INDIRECT, AddressMode.DIRECT_PAGE_S_INDEX_INDIRECT_Y_INDEX, - AddressMode.ADDRESS, AddressMode.DIRECT_PAGE_X_INDEX, AddressMode.DIRECT_PAGE_X_INDEX, AddressMode.DIRECT_PAGE_LONG_INDIRECT_Y_INDEX, - AddressMode.IMPLIED, AddressMode.ADDRESS_Y_INDEX, AddressMode.IMPLIED, AddressMode.IMPLIED, - AddressMode.ADDRESS_X_INDEX_INDIRECT, AddressMode.ADDRESS_X_INDEX, AddressMode.ADDRESS_X_INDEX, AddressMode.LONG_X_INDEX, + AddressMode.Constant8, AddressMode.DirectPageXIndexIndirect, AddressMode.Constant8, AddressMode.DirectPageSIndex, + AddressMode.DirectPage, AddressMode.DirectPage, AddressMode.DirectPage, AddressMode.DirectPageLongIndirect, + AddressMode.Implied, AddressMode.ImmediateMFlagDependent, AddressMode.Accumulator, AddressMode.Implied, + AddressMode.Address, AddressMode.Address, AddressMode.Address, AddressMode.Long, + AddressMode.Relative8, AddressMode.DirectPageIndirectYIndex, AddressMode.DirectPageIndirect, AddressMode.DirectPageSIndexIndirectYIndex, + AddressMode.DirectPage, AddressMode.DirectPageXIndex, AddressMode.DirectPageXIndex, AddressMode.DirectPageLongIndirectYIndex, + AddressMode.Implied, AddressMode.AddressYIndex, AddressMode.Accumulator, AddressMode.Implied, + AddressMode.Address, AddressMode.AddressXIndex, AddressMode.AddressXIndex, AddressMode.LongXIndex, + + AddressMode.Address, AddressMode.DirectPageXIndexIndirect, AddressMode.Long, AddressMode.DirectPageSIndex, + AddressMode.DirectPage, AddressMode.DirectPage, AddressMode.DirectPage, AddressMode.DirectPageLongIndirect, + AddressMode.Implied, AddressMode.ImmediateMFlagDependent, AddressMode.Accumulator, AddressMode.Implied, + AddressMode.Address, AddressMode.Address, AddressMode.Address, AddressMode.Long, + AddressMode.Relative8, AddressMode.DirectPageIndirectYIndex, AddressMode.DirectPageIndirect, AddressMode.DirectPageSIndexIndirectYIndex, + AddressMode.DirectPageXIndex, AddressMode.DirectPageXIndex, AddressMode.DirectPageXIndex, AddressMode.DirectPageLongIndirectYIndex, + AddressMode.Implied, AddressMode.AddressYIndex, AddressMode.Accumulator, AddressMode.Implied, + AddressMode.AddressXIndex, AddressMode.AddressXIndex, AddressMode.AddressXIndex, AddressMode.LongXIndex, + + AddressMode.Implied, AddressMode.DirectPageXIndexIndirect, AddressMode.Constant8, AddressMode.DirectPageSIndex, + AddressMode.BlockMove, AddressMode.DirectPage, AddressMode.DirectPage, AddressMode.DirectPageLongIndirect, + AddressMode.Implied, AddressMode.ImmediateMFlagDependent, AddressMode.Accumulator, AddressMode.Implied, + AddressMode.Address, AddressMode.Address, AddressMode.Address, AddressMode.Long, + AddressMode.Relative8, AddressMode.DirectPageIndirectYIndex, AddressMode.DirectPageIndirect, AddressMode.DirectPageSIndexIndirectYIndex, + AddressMode.BlockMove, AddressMode.DirectPageXIndex, AddressMode.DirectPageXIndex, AddressMode.DirectPageLongIndirectYIndex, + AddressMode.Implied, AddressMode.AddressYIndex, AddressMode.Implied, AddressMode.Implied, + AddressMode.Long, AddressMode.AddressXIndex, AddressMode.AddressXIndex, AddressMode.LongXIndex, + + AddressMode.Implied, AddressMode.DirectPageXIndexIndirect, AddressMode.Relative16, AddressMode.DirectPageSIndex, + AddressMode.DirectPage, AddressMode.DirectPage, AddressMode.DirectPage, AddressMode.DirectPageLongIndirect, + AddressMode.Implied, AddressMode.ImmediateMFlagDependent, AddressMode.Accumulator, AddressMode.Implied, + AddressMode.AddressIndirect, AddressMode.Address, AddressMode.Address, AddressMode.Long, + AddressMode.Relative8, AddressMode.DirectPageIndirectYIndex, AddressMode.DirectPageIndirect, AddressMode.DirectPageSIndexIndirectYIndex, + AddressMode.DirectPageXIndex, AddressMode.DirectPageXIndex, AddressMode.DirectPageXIndex, AddressMode.DirectPageLongIndirectYIndex, + AddressMode.Implied, AddressMode.AddressYIndex, AddressMode.Implied, AddressMode.Implied, + AddressMode.AddressXIndexIndirect, AddressMode.AddressXIndex, AddressMode.AddressXIndex, AddressMode.LongXIndex, + + AddressMode.Relative8, AddressMode.DirectPageXIndexIndirect, AddressMode.Relative16, AddressMode.DirectPageSIndex, + AddressMode.DirectPage, AddressMode.DirectPage, AddressMode.DirectPage, AddressMode.DirectPageLongIndirect, + AddressMode.Implied, AddressMode.ImmediateMFlagDependent, AddressMode.Implied, AddressMode.Implied, + AddressMode.Address, AddressMode.Address, AddressMode.Address, AddressMode.Long, + AddressMode.Relative8, AddressMode.DirectPageIndirectYIndex, AddressMode.DirectPageIndirect, AddressMode.DirectPageSIndexIndirectYIndex, + AddressMode.DirectPageXIndex, AddressMode.DirectPageXIndex, AddressMode.DirectPageYIndex, AddressMode.DirectPageLongIndirectYIndex, + AddressMode.Implied, AddressMode.AddressYIndex, AddressMode.Implied, AddressMode.Implied, + AddressMode.Address, AddressMode.AddressXIndex, AddressMode.AddressXIndex, AddressMode.LongXIndex, + + AddressMode.ImmediateXFlagDependent, AddressMode.DirectPageXIndexIndirect, AddressMode.ImmediateXFlagDependent, AddressMode.DirectPageSIndex, + AddressMode.DirectPage, AddressMode.DirectPage, AddressMode.DirectPage, AddressMode.DirectPageLongIndirect, + AddressMode.Implied, AddressMode.ImmediateMFlagDependent, AddressMode.Implied, AddressMode.Implied, + AddressMode.Address, AddressMode.Address, AddressMode.Address, AddressMode.Long, + AddressMode.Relative8, AddressMode.DirectPageIndirectYIndex, AddressMode.DirectPageIndirect, AddressMode.DirectPageSIndexIndirectYIndex, + AddressMode.DirectPageXIndex, AddressMode.DirectPageXIndex, AddressMode.DirectPageYIndex, AddressMode.DirectPageLongIndirectYIndex, + AddressMode.Implied, AddressMode.AddressYIndex, AddressMode.Implied, AddressMode.Implied, + AddressMode.AddressXIndex, AddressMode.AddressXIndex, AddressMode.AddressYIndex, AddressMode.LongXIndex, + + AddressMode.ImmediateXFlagDependent, AddressMode.DirectPageXIndexIndirect, AddressMode.Constant8, AddressMode.DirectPageSIndex, + AddressMode.DirectPage, AddressMode.DirectPage, AddressMode.DirectPage, AddressMode.DirectPageLongIndirect, + AddressMode.Implied, AddressMode.ImmediateMFlagDependent, AddressMode.Implied, AddressMode.Implied, + AddressMode.Address, AddressMode.Address, AddressMode.Address, AddressMode.Long, + AddressMode.Relative8, AddressMode.DirectPageIndirectYIndex, AddressMode.DirectPageIndirect, AddressMode.DirectPageSIndexIndirectYIndex, + AddressMode.DirectPageIndirect, AddressMode.DirectPageXIndex, AddressMode.DirectPageXIndex, AddressMode.DirectPageLongIndirectYIndex, + AddressMode.Implied, AddressMode.AddressYIndex, AddressMode.Implied, AddressMode.Implied, + AddressMode.AddressLongIndirect, AddressMode.AddressXIndex, AddressMode.AddressXIndex, AddressMode.LongXIndex, + + AddressMode.ImmediateXFlagDependent, AddressMode.DirectPageXIndexIndirect, AddressMode.Constant8, AddressMode.DirectPageSIndex, + AddressMode.DirectPage, AddressMode.DirectPage, AddressMode.DirectPage, AddressMode.DirectPageLongIndirect, + AddressMode.Implied, AddressMode.ImmediateMFlagDependent, AddressMode.Implied, AddressMode.Implied, + AddressMode.Address, AddressMode.Address, AddressMode.Address, AddressMode.Long, + AddressMode.Relative8, AddressMode.DirectPageIndirectYIndex, AddressMode.DirectPageIndirect, AddressMode.DirectPageSIndexIndirectYIndex, + AddressMode.Address, AddressMode.DirectPageXIndex, AddressMode.DirectPageXIndex, AddressMode.DirectPageLongIndirectYIndex, + AddressMode.Implied, AddressMode.AddressYIndex, AddressMode.Implied, AddressMode.Implied, + AddressMode.AddressXIndexIndirect, AddressMode.AddressXIndex, AddressMode.AddressXIndex, AddressMode.LongXIndex, }; } } diff --git a/Diz.Core/export/LogCreator.ErrorChecking.cs b/Diz.Core/export/LogCreator.ErrorChecking.cs index 4fd883cd..c4d85365 100644 --- a/Diz.Core/export/LogCreator.ErrorChecking.cs +++ b/Diz.Core/export/LogCreator.ErrorChecking.cs @@ -5,13 +5,13 @@ namespace Diz.Core.export { public partial class LogCreator { - protected int errorCount; + protected int ErrorCount; private void ReportError(int offset, string msg) { - ++errorCount; + ++ErrorCount; var offsetMsg = offset >= 0 ? $" Offset 0x{offset:X}" : ""; - output.WriteErrorLine($"({errorCount}){offsetMsg}: {msg}"); + Output.WriteErrorLine($"({ErrorCount}){offsetMsg}: {msg}"); } private void ErrorIfOperand(int offset) @@ -72,7 +72,7 @@ private bool ErrorIfUnexpectedFlagAt(int nextOffset, Data.FlagType expectedFlag) private bool DoesIndirectAddressPointToOpcode(int ia) { - return Data.GetFlag(Data.ConvertSNEStoPC(ia)) == Data.FlagType.Opcode; + return Data.GetFlag(Data.ConvertSnesToPc(ia)) == Data.FlagType.Opcode; } private bool IsOpcodeOutboundJump(int offset) @@ -83,7 +83,7 @@ private bool IsOpcodeOutboundJump(int offset) private bool IsOffsetInRange(int offset) { - return offset >= 0 && offset < Data.GetROMSize(); + return offset >= 0 && offset < Data.GetRomSize(); } private int GetByteLengthFollowing(int offset) diff --git a/Diz.Core/export/LogCreator.Setup.cs b/Diz.Core/export/LogCreator.Setup.cs index a908dd6a..579b596d 100644 --- a/Diz.Core/export/LogCreator.Setup.cs +++ b/Diz.Core/export/LogCreator.Setup.cs @@ -14,21 +14,21 @@ public partial class LogCreator { protected class AssemblerHandler : Attribute { - public string token; - public int length; + public string Token; + public int Length; } public class OutputResult { - public bool success; - public int error_count = -1; - public LogCreator logCreator; - public string outputStr = ""; // only set if outputString=true + public bool Success; + public int ErrorCount = -1; + public LogCreator LogCreator; + public string OutputStr = ""; // only set if outputString=true } // DONT use directly [except to setup the caching] - protected static Dictionary> parameters; + protected static Dictionary> parametersCache; // SAFE to use directly. protected static Dictionary> Parameters @@ -36,16 +36,16 @@ protected static Dictionary> Parameters get { CacheAssemblerAttributeInfo(); - return parameters; + return parametersCache; } } protected static void CacheAssemblerAttributeInfo() { - if (parameters != null) + if (parametersCache != null) return; - parameters = new Dictionary>(); + parametersCache = new Dictionary>(); var methodsWithAttributes = typeof(LogCreator) .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance) @@ -56,8 +56,8 @@ protected static void CacheAssemblerAttributeInfo() foreach (var method in methodsWithAttributes) { var assemblerHandler = method.GetCustomAttribute(); - var token = assemblerHandler.token; - var length = assemblerHandler.length; + var token = assemblerHandler.Token; + var length = assemblerHandler.Length; // check your method signature if you hit this stuff. Debug.Assert(method.GetParameters().Length == 2); @@ -70,10 +70,10 @@ protected static void CacheAssemblerAttributeInfo() Debug.Assert(method.ReturnType == typeof(string)); - parameters.Add(token, (new Tuple(method, length))); + parametersCache.Add(token, (new Tuple(method, length))); } - Debug.Assert(parameters.Count != 0); + Debug.Assert(parametersCache.Count != 0); } protected string GetParameter(int offset, string parameter, int length) @@ -110,10 +110,10 @@ public void AddExtraLabel(int i, Label v) // TODO: generate some nice looking "+"/"-" labels here. protected void GenerateAdditionalExtraLabels() { - if (Settings.unlabeled == FormatUnlabeled.ShowNone) + if (Settings.Unlabeled == FormatUnlabeled.ShowNone) return; - for (var pointer = 0; pointer < Data.GetROMSize(); pointer += GetLineByteLength(pointer)) + for (var pointer = 0; pointer < Data.GetRomSize(); pointer += GetLineByteLength(pointer)) { GenerateLabelIfNeededAt(pointer); } @@ -127,14 +127,14 @@ private void GenerateLabelIfNeededAt(int pcoffset) var labelName = Data.GetDefaultLabel(snes); AddExtraLabel(snes, new Label() { - name = labelName, + Name = labelName, }); } protected int GetAddressOfAnyUsefulLabelsAt(int pcoffset) { - if (Settings.unlabeled == FormatUnlabeled.ShowAll) - return Data.ConvertPCtoSNES(pcoffset); // this may not be right either... + if (Settings.Unlabeled == FormatUnlabeled.ShowAll) + return Data.ConvertPCtoSnes(pcoffset); // this may not be right either... var flag = Data.GetFlag(pcoffset); var usefulToCreateLabelFrom = @@ -145,7 +145,7 @@ protected int GetAddressOfAnyUsefulLabelsAt(int pcoffset) return -1; var snesIa = Data.GetIntermediateAddressOrPointer(pcoffset); - var pc = Data.ConvertSNEStoPC(snesIa); + var pc = Data.ConvertSnesToPc(snesIa); return pc >= 0 ? snesIa : -1; } diff --git a/Diz.Core/export/LogCreator.cs b/Diz.Core/export/LogCreator.cs index 0555da16..be340c78 100644 --- a/Diz.Core/export/LogCreator.cs +++ b/Diz.Core/export/LogCreator.cs @@ -24,12 +24,12 @@ public enum FormatStructure public LogWriterSettings Settings { get; set; } public Data Data { get; set; } - protected LogCreatorOutput output; + protected LogCreatorOutput Output; protected Dictionary ExtraLabels { get; set; } = new Dictionary(); - protected List> parseList; - protected List labelsWeVisited; - protected int bankSize; - protected ObservableDictionary backupOfOriginalLabelsBeforeModifying; + protected List> ParseList; + protected List LabelsWeVisited; + protected int BankSize; + protected ObservableDictionary BackupOfOriginalLabelsBeforeModifying; public virtual OutputResult CreateLog() { @@ -55,9 +55,9 @@ protected virtual void Init() InitOutput(); SetupParseList(); - bankSize = RomUtil.GetBankSize(Data.RomMapMode); - errorCount = 0; - labelsWeVisited = new List(); + BankSize = RomUtil.GetBankSize(Data.RomMapMode); + ErrorCount = 0; + LabelsWeVisited = new List(); GenerateAdditionalExtraLabels(); WriteGeneratedLabelsIntoUnderlyingData(); // MODIFIES DATA. MAKE SURE TO UNDO THIS. @@ -65,12 +65,12 @@ protected virtual void Init() private void InitOutput() { - if (Settings.outputToString) - output = new LogCreatorStringOutput(); + if (Settings.OutputToString) + Output = new LogCreatorStringOutput(); else - output = new LogCreatorStreamOutput(); + Output = new LogCreatorStreamOutput(); - output.Init(this); + Output.Init(this); } protected virtual void Cleanup() @@ -84,30 +84,30 @@ protected void RestoreUnderlyingDataLabels() { // SUPER IMPORTANT. THIS MUST GET DONE, ALWAYS. PROTECT THIS WITH TRY/CATCH - if (backupOfOriginalLabelsBeforeModifying != null) - Data.Labels = backupOfOriginalLabelsBeforeModifying; + if (BackupOfOriginalLabelsBeforeModifying != null) + Data.Labels = BackupOfOriginalLabelsBeforeModifying; - backupOfOriginalLabelsBeforeModifying = null; + BackupOfOriginalLabelsBeforeModifying = null; } private void CloseOutput(OutputResult result) { - output?.Finish(result); - output = null; + Output?.Finish(result); + Output = null; } private OutputResult GetResult() { var result = new OutputResult() { - error_count = errorCount, - success = true, - logCreator = this + ErrorCount = ErrorCount, + Success = true, + LogCreator = this }; - if (Settings.outputToString) - result.outputStr = ((LogCreatorStringOutput)output)?.OutputString; + if (Settings.OutputToString) + result.OutputStr = ((LogCreatorStringOutput)Output)?.OutputString; return result; } @@ -121,7 +121,7 @@ protected void WriteGeneratedLabelsIntoUnderlyingData() // TODO: I really don't like us modifying and restoring the // underlying labels or anything in Data. Data should ideally be immutable by us. // we should either clone all of Data before modifying, or generate these labels on the fly. - backupOfOriginalLabelsBeforeModifying = Data.Labels; + BackupOfOriginalLabelsBeforeModifying = Data.Labels; Data.Labels = new ObservableDictionary(Data.Labels); // write the new generated labels in, don't let them overwrite any real labels @@ -136,7 +136,7 @@ protected void WriteGeneratedLabelsIntoUnderlyingData() public int GetRomSize() { - return Settings.romSizeOverride != -1 ? Settings.romSizeOverride : Data.GetROMSize(); + return Settings.RomSizeOverride != -1 ? Settings.RomSizeOverride : Data.GetRomSize(); } protected virtual void WriteLog() @@ -164,7 +164,7 @@ protected void WriteSpecial(string special) { const int doesntMatter = 0; var line = GetLine(doesntMatter, special); - output.WriteLine(line); + Output.WriteLine(line); } protected void WriteMainIncludes(int size) @@ -176,22 +176,22 @@ protected void WriteMainIncludes(int size) private void WriteMainBankIncludes(int size) { - if (Settings.structure != FormatStructure.OneBankPerFile) + if (Settings.Structure != FormatStructure.OneBankPerFile) return; - for (var i = 0; i < size; i += bankSize) - output.WriteLine(GetLine(i, "incsrc")); + for (var i = 0; i < size; i += BankSize) + Output.WriteLine(GetLine(i, "incsrc")); - output.WriteLine(GetLine(-1, "incsrc")); + Output.WriteLine(GetLine(-1, "incsrc")); } protected void SetupParseList() { - var split = Settings.format.Split('%'); - parseList = new List>(); + var split = Settings.Format.Split('%'); + ParseList = new List>(); for (var i = 0; i < split.Length; i++) { - if (i % 2 == 0) parseList.Add(Tuple.Create(split[i], int.MaxValue)); + if (i % 2 == 0) ParseList.Add(Tuple.Create(split[i], int.MaxValue)); else { var colon = split[i].IndexOf(':'); @@ -209,7 +209,7 @@ protected void SetupParseList() tuple = Tuple.Create(split[i].Substring(0, colon), int.Parse(split[i].Substring(colon + 1))); } - parseList.Add(tuple); + ParseList.Add(tuple); } } } @@ -227,27 +227,27 @@ protected void WriteAddress(ref int pointer, ref int currentBank) private void WriteTheRealLine(int pointer) { - output.WriteLine(GetLine(pointer, null)); + Output.WriteLine(GetLine(pointer, null)); } private void WriteBlankLineIfEndPoint(int pointer) { if ((Data.GetInOutPoint(pointer) & Data.InOutPoint.EndPoint) != 0) - output.WriteLine(GetLine(pointer, "empty")); + Output.WriteLine(GetLine(pointer, "empty")); } private void WriteBlankLineIfStartingNewParagraph(int pointer) { var isLocationAReadPoint = (Data.GetInOutPoint(pointer) & Data.InOutPoint.ReadPoint) != 0; - var anyLabelsPresent = Data.Labels.TryGetValue(pointer, out var label) && label.name.Length > 0; + var anyLabelsPresent = Data.Labels.TryGetValue(pointer, out var label) && label.Name.Length > 0; if (isLocationAReadPoint || anyLabelsPresent) - output.WriteLine(GetLine(pointer, "empty")); + Output.WriteLine(GetLine(pointer, "empty")); } private void SwitchBanksIfNeeded(int pointer, ref int currentBank) { - var snesAddress = Data.ConvertPCtoSNES(pointer); + var snesAddress = Data.ConvertPCtoSnes(pointer); var thisBank = snesAddress >> 16; @@ -257,7 +257,7 @@ private void SwitchBanksIfNeeded(int pointer, ref int currentBank) OpenNewBank(pointer, thisBank); currentBank = thisBank; - if (snesAddress % bankSize == 0) + if (snesAddress % BankSize == 0) return; ReportError(pointer, "An instruction crossed a bank boundary."); @@ -265,11 +265,11 @@ private void SwitchBanksIfNeeded(int pointer, ref int currentBank) private void OpenNewBank(int pointer, int thisBank) { - output.SwitchToBank(thisBank); + Output.SwitchToBank(thisBank); - output.WriteLine(GetLine(pointer, "empty")); - output.WriteLine(GetLine(pointer, "org")); - output.WriteLine(GetLine(pointer, "empty")); + Output.WriteLine(GetLine(pointer, "empty")); + Output.WriteLine(GetLine(pointer, "org")); + Output.WriteLine(GetLine(pointer, "empty")); } protected void WriteLabels(int pointer) @@ -286,7 +286,7 @@ private Dictionary GetUnvisitedLabels() // part 1: important: include all labels we aren't defining somewhere else. needed for disassembly foreach (var pair in Data.Labels) { - if (labelsWeVisited.Contains(pair.Key)) + if (LabelsWeVisited.Contains(pair.Key)) continue; // this label was not defined elsewhere in our disassembly, so we need to include it in labels.asm @@ -301,7 +301,7 @@ private void WriteAnyUnivisitedLabels(int pointer, Dictionary unvisi SwitchOutputStream(pointer, "labels"); foreach (var pair in unvisitedLabels) - output.WriteLine(GetLine(pair.Key, "labelassign")); + Output.WriteLine(GetLine(pair.Key, "labelassign")); } private void PrintAllLabelsIfRequested(int pointer, Dictionary unvisitedLabels) @@ -310,7 +310,7 @@ private void PrintAllLabelsIfRequested(int pointer, Dictionary unvis // Useful for debugging, documentation, or reverse engineering workflow. // this file shouldn't need to be included in the build, it's just reference documentation - if (!Settings.includeUnusedLabels) + if (!Settings.IncludeUnusedLabels) return; SwitchOutputStream(pointer, "all-labels.txt"); // TODO: csv in the future. escape commas @@ -318,17 +318,17 @@ private void PrintAllLabelsIfRequested(int pointer, Dictionary unvis { // not the best place to add formatting, TODO: cleanup var category = unvisitedLabels.ContainsKey(pair.Key) ? "UNUSED" : "USED"; - output.WriteLine($";!^!-{category}-! " + GetLine(pair.Key, "labelassign")); + Output.WriteLine($";!^!-{category}-! " + GetLine(pair.Key, "labelassign")); } } protected void SwitchOutputStream(int pointer, string streamName) { - output.SwitchToStream(streamName); + Output.SwitchToStream(streamName); // write an extra blank line if we would normally switch files here - if (Settings.structure == FormatStructure.SingleFile) - output.WriteLine(GetLine(pointer, "empty")); + if (Settings.Structure == FormatStructure.SingleFile) + Output.WriteLine(GetLine(pointer, "empty")); } // -------------------------- @@ -339,7 +339,7 @@ protected string GetLine(int offset, string special) var isSpecial = special != null; var line = ""; - foreach (var t in parseList) + foreach (var t in ParseList) { if (t.Item2 == int.MaxValue) // string literal { @@ -382,7 +382,7 @@ private Data.FlagType GetFlagButSwapOpcodeForOperand(int offset) protected int GetLineByteLength(int offset) { int max = 1, step = 1; - var size = Data.GetROMSize(); + var size = Data.GetRomSize(); switch (Data.GetFlag(offset)) { @@ -394,22 +394,22 @@ protected int GetLineByteLength(int offset) case Data.FlagType.Graphics: case Data.FlagType.Music: case Data.FlagType.Empty: - max = Settings.dataPerLine; + max = Settings.DataPerLine; break; case Data.FlagType.Text: max = 21; break; case Data.FlagType.Data16Bit: step = 2; - max = Settings.dataPerLine; + max = Settings.DataPerLine; break; case Data.FlagType.Data24Bit: step = 3; - max = Settings.dataPerLine; + max = Settings.DataPerLine; break; case Data.FlagType.Data32Bit: step = 4; - max = Settings.dataPerLine; + max = Settings.DataPerLine; break; case Data.FlagType.Pointer16Bit: step = 2; @@ -425,26 +425,26 @@ protected int GetLineByteLength(int offset) break; } - int min = step, myBank = offset / bankSize; + int min = step, myBank = offset / BankSize; while ( min < max && offset + min < size && Data.GetFlag(offset + min) == Data.GetFlag(offset) && - Data.GetLabelName(Data.ConvertPCtoSNES(offset + min)) == "" && - (offset + min) / bankSize == myBank + Data.GetLabelName(Data.ConvertPCtoSnes(offset + min)) == "" && + (offset + min) / BankSize == myBank ) min += step; return min; } // just a % - [AssemblerHandler(token = "", length = 1)] + [AssemblerHandler(Token = "", Length = 1)] protected string GetPercent(int offset, int length) { return "%"; } // all spaces - [AssemblerHandler(token = "%empty", length = 1)] + [AssemblerHandler(Token = "%empty", Length = 1)] protected string GetEmpty(int offset, int length) { return string.Format("{0," + length + "}", ""); @@ -452,7 +452,7 @@ protected string GetEmpty(int offset, int length) // trim to length // negative length = right justified - [AssemblerHandler(token = "label", length = -22)] + [AssemblerHandler(Token = "label", Length = -22)] protected string GetLabel(int offset, int length) { // what we're given: a PC offset in ROM. @@ -464,19 +464,19 @@ protected string GetLabel(int offset, int length) // TODO: we need to deal with that mirroring here // TODO: eventually, support multiple labels tagging the same address, it may not always be just one. - var snesOffset = Data.ConvertPCtoSNES(offset); + var snesOffset = Data.ConvertPCtoSnes(offset); var label = Data.GetLabelName(snesOffset); if (label == null) return ""; - labelsWeVisited.Add(snesOffset); + LabelsWeVisited.Add(snesOffset); var noColon = label.Length == 0 || label[0] == '-' || label[0] == '+'; return string.Format("{0," + (length * -1) + "}", label + (noColon ? "" : ":")); } // trim to length - [AssemblerHandler(token = "code", length = 37)] + [AssemblerHandler(Token = "code", Length = 37)] protected string GetCode(int offset, int length) { var bytes = GetLineByteLength(offset); @@ -521,44 +521,44 @@ protected string GetCode(int offset, int length) return string.Format("{0," + (length * -1) + "}", code); } - [AssemblerHandler(token = "%org", length = 37)] - protected string GetORG(int offset, int length) + [AssemblerHandler(Token = "%org", Length = 37)] + protected string GetOrg(int offset, int length) { - string org = "ORG " + Util.NumberToBaseString(Data.ConvertPCtoSNES(offset), Util.NumberBase.Hexadecimal, 6, true); + string org = "ORG " + Util.NumberToBaseString(Data.ConvertPCtoSnes(offset), Util.NumberBase.Hexadecimal, 6, true); return string.Format("{0," + (length * -1) + "}", org); } - [AssemblerHandler(token = "%map", length = 37)] + [AssemblerHandler(Token = "%map", Length = 37)] protected string GetMap(int offset, int length) { string s = ""; switch (Data.RomMapMode) { - case Data.ROMMapMode.LoROM: s = "lorom"; break; - case Data.ROMMapMode.HiROM: s = "hirom"; break; - case Data.ROMMapMode.SA1ROM: s = "sa1rom"; break; // todo - case Data.ROMMapMode.ExSA1ROM: s = "exsa1rom"; break; // todo - case Data.ROMMapMode.SuperFX: s = "sfxrom"; break; // todo - case Data.ROMMapMode.ExHiROM: s = "exhirom"; break; - case Data.ROMMapMode.ExLoROM: s = "exlorom"; break; + case RomMapMode.LoRom: s = "lorom"; break; + case RomMapMode.HiRom: s = "hirom"; break; + case RomMapMode.Sa1Rom: s = "sa1rom"; break; // todo + case RomMapMode.ExSa1Rom: s = "exsa1rom"; break; // todo + case RomMapMode.SuperFx: s = "sfxrom"; break; // todo + case RomMapMode.ExHiRom: s = "exhirom"; break; + case RomMapMode.ExLoRom: s = "exlorom"; break; } return string.Format("{0," + (length * -1) + "}", s); } // 0+ = bank_xx.asm, -1 = labels.asm - [AssemblerHandler(token = "%incsrc", length = 1)] + [AssemblerHandler(Token = "%incsrc", Length = 1)] protected string GetIncSrc(int offset, int length) { string s = "incsrc \"labels.asm\""; if (offset >= 0) { - int bank = Data.ConvertPCtoSNES(offset) >> 16; + int bank = Data.ConvertPCtoSnes(offset) >> 16; s = string.Format("incsrc \"bank_{0}.asm\"", Util.NumberToBaseString(bank, Util.NumberBase.Hexadecimal, 2)); } return string.Format("{0," + (length * -1) + "}", s); } - [AssemblerHandler(token = "%bankcross", length = 1)] + [AssemblerHandler(Token = "%bankcross", Length = 1)] protected string GetBankCross(int offset, int length) { string s = "check bankcross off"; @@ -566,7 +566,7 @@ protected string GetBankCross(int offset, int length) } // length forced to 6 - [AssemblerHandler(token = "ia", length = 6)] + [AssemblerHandler(Token = "ia", Length = 6)] protected string GetIntermediateAddress(int offset, int length) { int ia = Data.GetIntermediateAddressOrPointer(offset); @@ -574,21 +574,21 @@ protected string GetIntermediateAddress(int offset, int length) } // length forced to 6 - [AssemblerHandler(token = "pc", length = 6)] + [AssemblerHandler(Token = "pc", Length = 6)] protected string GetProgramCounter(int offset, int length) { - return Util.NumberToBaseString(Data.ConvertPCtoSNES(offset), Util.NumberBase.Hexadecimal, 6); + return Util.NumberToBaseString(Data.ConvertPCtoSnes(offset), Util.NumberBase.Hexadecimal, 6); } // trim to length - [AssemblerHandler(token = "offset", length = -6)] + [AssemblerHandler(Token = "offset", Length = -6)] protected string GetOffset(int offset, int length) { return string.Format("{0," + (length * -1) + "}", Util.NumberToBaseString(offset, Util.NumberBase.Hexadecimal, 0)); } // length forced to 8 - [AssemblerHandler(token = "bytes", length = 8)] + [AssemblerHandler(Token = "bytes", Length = 8)] protected string GetRawBytes(int offset, int length) { string bytes = ""; @@ -596,36 +596,36 @@ protected string GetRawBytes(int offset, int length) { for (var i = 0; i < Data.GetInstructionLength(offset); i++) { - bytes += Util.NumberToBaseString(Data.GetROMByte(offset + i), Util.NumberBase.Hexadecimal); + bytes += Util.NumberToBaseString(Data.GetRomByte(offset + i), Util.NumberBase.Hexadecimal); } } return $"{bytes,-8}"; } // trim to length - [AssemblerHandler(token = "comment", length = 1)] + [AssemblerHandler(Token = "comment", Length = 1)] protected string GetComment(int offset, int length) { - var snesOffset = Data.ConvertPCtoSNES(offset); + var snesOffset = Data.ConvertPCtoSnes(offset); return string.Format("{0," + (length * -1) + "}", Data.GetComment(snesOffset)); } // length forced to 2 - [AssemblerHandler(token = "b", length = 2)] + [AssemblerHandler(Token = "b", Length = 2)] protected string GetDataBank(int offset, int length) { return Util.NumberToBaseString(Data.GetDataBank(offset), Util.NumberBase.Hexadecimal, 2); } // length forced to 4 - [AssemblerHandler(token = "d", length = 4)] + [AssemblerHandler(Token = "d", Length = 4)] protected string GetDirectPage(int offset, int length) { return Util.NumberToBaseString(Data.GetDirectPage(offset), Util.NumberBase.Hexadecimal, 4); } // if length == 1, M/m, else 08/16 - [AssemblerHandler(token = "m", length = 1)] + [AssemblerHandler(Token = "m", Length = 1)] protected string GetMFlag(int offset, int length) { var m = Data.GetMFlag(offset); @@ -634,7 +634,7 @@ protected string GetMFlag(int offset, int length) } // if length == 1, X/x, else 08/16 - [AssemblerHandler(token = "x", length = 1)] + [AssemblerHandler(Token = "x", Length = 1)] protected string GetXFlag(int offset, int length) { var x = Data.GetXFlag(offset); @@ -643,7 +643,7 @@ protected string GetXFlag(int offset, int length) } // output label at snes offset, and its value - [AssemblerHandler(token = "%labelassign", length = 1)] + [AssemblerHandler(Token = "%labelassign", Length = 1)] protected string GetLabelAssign(int offset, int length) { var labelName = Data.GetLabelName(offset); @@ -658,7 +658,7 @@ protected string GetLabelAssign(int offset, int length) var finalCommentText = ""; // TODO: sorry, probably not the best way to stuff this in here, consider putting it in the %comment% section in the future. -Dom - if (Settings.printLabelSpecificComments && labelComment != "") + if (Settings.PrintLabelSpecificComments && labelComment != "") finalCommentText = $"; !^ {labelComment} ^!"; string s = $"{labelName} = {offsetStr}{finalCommentText}"; diff --git a/Diz.Core/export/LogOutput.cs b/Diz.Core/export/LogOutput.cs index 1e811215..76ae5c4e 100644 --- a/Diz.Core/export/LogOutput.cs +++ b/Diz.Core/export/LogOutput.cs @@ -26,74 +26,74 @@ public virtual void SwitchToStream(string streamName, bool isErrorStream = false public class LogCreatorStringOutput : LogCreatorOutput { - protected StringBuilder outputBuilder = new StringBuilder(); - protected StringBuilder errorBuilder = new StringBuilder(); + protected StringBuilder OutputBuilder = new StringBuilder(); + protected StringBuilder ErrorBuilder = new StringBuilder(); - public string OutputString => outputBuilder.ToString(); - public string ErrorString => errorBuilder.ToString(); + public string OutputString => OutputBuilder.ToString(); + public string ErrorString => ErrorBuilder.ToString(); protected override void Init() { - Debug.Assert(LogCreator.Settings.outputToString && LogCreator.Settings.structure == LogCreator.FormatStructure.SingleFile); + Debug.Assert(LogCreator.Settings.OutputToString && LogCreator.Settings.Structure == LogCreator.FormatStructure.SingleFile); } - public override void WriteLine(string line) => outputBuilder.AppendLine(line); - public override void WriteErrorLine(string line) => errorBuilder.AppendLine(line); + public override void WriteLine(string line) => OutputBuilder.AppendLine(line); + public override void WriteErrorLine(string line) => ErrorBuilder.AppendLine(line); public override void Finish(LogCreator.OutputResult result) { - result.outputStr = OutputString; + result.OutputStr = OutputString; } } public class LogCreatorStreamOutput : LogCreatorOutput { - protected Dictionary outputStreams = new Dictionary(); - protected StreamWriter errorOutputStream; + protected Dictionary OutputStreams = new Dictionary(); + protected StreamWriter ErrorOutputStream; // references to stuff in outputStreams private string activeStreamName; private StreamWriter activeOutputStream; - protected string folder; - protected string filename; // if set to single file output moe. + protected string Folder; + protected string Filename; // if set to single file output moe. protected override void Init() { - var basePath = LogCreator.Settings.fileOrFolderOutPath; + var basePath = LogCreator.Settings.FileOrFolderOutPath; - if (LogCreator.Settings.structure == LogCreator.FormatStructure.OneBankPerFile) + if (LogCreator.Settings.Structure == LogCreator.FormatStructure.OneBankPerFile) basePath += "\\"; // force it to treat it as a path. not the best way. - folder = Path.GetDirectoryName(basePath); + Folder = Path.GetDirectoryName(basePath); - if (LogCreator.Settings.structure == LogCreator.FormatStructure.SingleFile) + if (LogCreator.Settings.Structure == LogCreator.FormatStructure.SingleFile) { - filename = Path.GetFileName(LogCreator.Settings.fileOrFolderOutPath); - SwitchToStream(filename); + Filename = Path.GetFileName(LogCreator.Settings.FileOrFolderOutPath); + SwitchToStream(Filename); } else { SwitchToStream("main"); } - SwitchToStream(LogCreator.Settings.errorFilename, isErrorStream: true); + SwitchToStream(LogCreator.Settings.ErrorFilename, isErrorStream: true); } public override void Finish(LogCreator.OutputResult result) { - foreach (var stream in outputStreams) + foreach (var stream in OutputStreams) { stream.Value.Close(); } - outputStreams.Clear(); + OutputStreams.Clear(); activeOutputStream = null; - errorOutputStream = null; + ErrorOutputStream = null; activeStreamName = ""; - if (result.error_count == 0) - File.Delete(BuildStreamPath(LogCreator.Settings.errorFilename)); + if (result.ErrorCount == 0) + File.Delete(BuildStreamPath(LogCreator.Settings.ErrorFilename)); } public override void SwitchToBank(int bankNum) @@ -105,18 +105,18 @@ public override void SwitchToBank(int bankNum) public override void SwitchToStream(string streamName, bool isErrorStream = false) { // don't switch off the main file IF we're only supposed to be outputting one file - if (LogCreator.Settings.structure == LogCreator.FormatStructure.SingleFile && + if (LogCreator.Settings.Structure == LogCreator.FormatStructure.SingleFile && !string.IsNullOrEmpty(activeStreamName)) return; - var whichStream = outputStreams.TryGetValue(streamName, out var outputStream) + var whichStream = OutputStreams.TryGetValue(streamName, out var outputStream) ? outputStream : OpenNewStream(streamName); if (!isErrorStream) SetActiveStream(streamName, whichStream); else - errorOutputStream = whichStream; + ErrorOutputStream = whichStream; } public void SetActiveStream(string streamName, StreamWriter streamWriter) @@ -128,13 +128,13 @@ public void SetActiveStream(string streamName, StreamWriter streamWriter) protected virtual StreamWriter OpenNewStream(string streamName) { var streamWriter = new StreamWriter(BuildStreamPath(streamName)); - outputStreams.Add(streamName, streamWriter); + OutputStreams.Add(streamName, streamWriter); return streamWriter; } private string BuildStreamPath(string streamName) { - var fullOutputPath = Path.Combine(folder, streamName); + var fullOutputPath = Path.Combine(Folder, streamName); if (!Path.HasExtension(fullOutputPath)) fullOutputPath += ".asm"; @@ -149,7 +149,7 @@ public override void WriteLine(string line) public override void WriteErrorLine(string line) { - errorOutputStream?.WriteLine(line); + ErrorOutputStream?.WriteLine(line); } } } diff --git a/Diz.Core/export/LogWriterSettings.cs b/Diz.Core/export/LogWriterSettings.cs index db2af028..da8677dc 100644 --- a/Diz.Core/export/LogWriterSettings.cs +++ b/Diz.Core/export/LogWriterSettings.cs @@ -8,64 +8,64 @@ public struct LogWriterSettings // The plumbing could use a pass of something like 'ref readonly' because: // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#reference-return-values - public string format; - public int dataPerLine; - public LogCreator.FormatUnlabeled unlabeled; - public LogCreator.FormatStructure structure; - public bool includeUnusedLabels; - public bool printLabelSpecificComments; + public string Format; + public int DataPerLine; + public LogCreator.FormatUnlabeled Unlabeled; + public LogCreator.FormatStructure Structure; + public bool IncludeUnusedLabels; + public bool PrintLabelSpecificComments; - public bool wasInitialized; - public int romSizeOverride; // specify an override for the # of bytes to assemble. default is the entire ROM + public bool WasInitialized; + public int RomSizeOverride; // specify an override for the # of bytes to assemble. default is the entire ROM - public string fileOrFolderOutPath; - public bool outputToString; - public string errorFilename; + public string FileOrFolderOutPath; + public bool OutputToString; + public string ErrorFilename; public void SetDefaults() { - format = "%label:-22% %code:37%;%pc%|%bytes%|%ia%; %comment%"; - dataPerLine = 8; - unlabeled = LogCreator.FormatUnlabeled.ShowInPoints; - structure = LogCreator.FormatStructure.OneBankPerFile; - includeUnusedLabels = false; - printLabelSpecificComments = false; - fileOrFolderOutPath = ""; // path to output file or folder - wasInitialized = true; - romSizeOverride = -1; - errorFilename = "errors.txt"; + Format = "%label:-22% %code:37%;%pc%|%bytes%|%ia%; %comment%"; + DataPerLine = 8; + Unlabeled = LogCreator.FormatUnlabeled.ShowInPoints; + Structure = LogCreator.FormatStructure.OneBankPerFile; + IncludeUnusedLabels = false; + PrintLabelSpecificComments = false; + FileOrFolderOutPath = ""; // path to output file or folder + WasInitialized = true; + RomSizeOverride = -1; + ErrorFilename = "errors.txt"; } // return null if no error, or message if there is public string Validate() { // for now, just make sure it was initialized somewhere by someone - if (!wasInitialized) + if (!WasInitialized) return "Not initialized"; // TODO: add more validation. - if (outputToString) + if (OutputToString) { - if (structure == LogCreator.FormatStructure.OneBankPerFile) + if (Structure == LogCreator.FormatStructure.OneBankPerFile) return "Can't use one-bank-per-file output with string output"; - if (fileOrFolderOutPath != "") + if (FileOrFolderOutPath != "") return "Can't use one-bank-per-file output with file output"; } else { - if (fileOrFolderOutPath == "") + if (FileOrFolderOutPath == "") return "No file path set"; - if (!Directory.Exists(Path.GetDirectoryName(fileOrFolderOutPath))) + if (!Directory.Exists(Path.GetDirectoryName(FileOrFolderOutPath))) return "File or folder output directory doesn't exist"; - if (structure == LogCreator.FormatStructure.SingleFile) + if (Structure == LogCreator.FormatStructure.SingleFile) { // don't check for existence, just that what we have appears to be a filename and // not a directory. - if (Path.GetFileName(fileOrFolderOutPath) == string.Empty) + if (Path.GetFileName(FileOrFolderOutPath) == string.Empty) return "Output path doesn't appear to be a valid file selection"; } } diff --git a/Diz.Core/import/BSNESImportStreamProcessor.cs b/Diz.Core/import/BSNESImportStreamProcessor.cs index eb702c61..fad35ec9 100644 --- a/Diz.Core/import/BSNESImportStreamProcessor.cs +++ b/Diz.Core/import/BSNESImportStreamProcessor.cs @@ -6,7 +6,7 @@ namespace Diz.Core.import { - public class BSNESImportStreamProcessor + public class BsnesImportStreamProcessor { public struct CompressedWorkItems { diff --git a/Diz.Core/import/BSNESTraceLogCapture.cs b/Diz.Core/import/BSNESTraceLogCapture.cs index 80d9e5e1..28f41637 100644 --- a/Diz.Core/import/BSNESTraceLogCapture.cs +++ b/Diz.Core/import/BSNESTraceLogCapture.cs @@ -11,16 +11,16 @@ namespace Diz.Core.import { // TODO: can probably replace this better with Dataflow TPL, investigate - public class BSNESTraceLogCapture + public class BsnesTraceLogCapture { private WorkerTaskManager taskManager; - private BSNESImportStreamProcessor streamProcessor; + private BsnesImportStreamProcessor streamProcessor; private readonly ReaderWriterLockSlim importerLock = new ReaderWriterLockSlim(); - private BSNESTraceLogImporter importer; + private BsnesTraceLogImporter importer; private int bytesToProcess = 0; private int compressedBlocksToProcess = 0; - private BSNESTraceLogImporter.Stats cachedStats; + private BsnesTraceLogImporter.Stats cachedStats; public bool Running { get; protected set; } @@ -53,8 +53,8 @@ private void Shutdown() private void Setup(Data data) { Running = true; - importer = new BSNESTraceLogImporter(data); - streamProcessor = new BSNESImportStreamProcessor(); + importer = new BsnesTraceLogImporter(data); + streamProcessor = new BsnesImportStreamProcessor(); taskManager = new WorkerTaskManager(); } @@ -82,19 +82,19 @@ private void ProcessStreamData(Stream networkStream) } } - private async void ProcessCompressedWorkItem(BSNESImportStreamProcessor.CompressedWorkItems compressedItems) + private async void ProcessCompressedWorkItem(BsnesImportStreamProcessor.CompressedWorkItems compressedItems) { // tune this as needed. // we want parallel jobs going, but, we don't want too many of them at once. // average # workItems per CompressedWorkItem is like 12K currently. const int numItemsPerTask = 6000; - using var enumerator = BSNESImportStreamProcessor.ProcessCompressedWorkItems(compressedItems).GetEnumerator(); + using var enumerator = BsnesImportStreamProcessor.ProcessCompressedWorkItems(compressedItems).GetEnumerator(); bool keepGoing; var itemsRemainingBeforeSend = numItemsPerTask; var subTasks = new List(); - var workItemsForThisTask = new List(); + var workItemsForThisTask = new List(); do { @@ -111,7 +111,7 @@ private async void ProcessCompressedWorkItem(BSNESImportStreamProcessor.Compress if (!shouldSendNow) continue; - var workItemsCopy = new List(workItemsForThisTask); + var workItemsCopy = new List(workItemsForThisTask); subTasks.Add(taskManager.Run(() => { ProcessWorkItems(workItemsCopy); @@ -125,7 +125,7 @@ private async void ProcessCompressedWorkItem(BSNESImportStreamProcessor.Compress Stats_MarkCompleted(compressedItems); } - private void ProcessWorkItems(IEnumerable workItemsForThisTask) + private void ProcessWorkItems(IEnumerable workItemsForThisTask) { foreach (var workItem in workItemsForThisTask) { @@ -134,7 +134,7 @@ private void ProcessWorkItems(IEnumerable w } // this is just neat stats. it's optional, remove if performance becomes an issue (seems unlikely) - private void States_MarkQueued(BSNESImportStreamProcessor.CompressedWorkItems compressedItems) + private void States_MarkQueued(BsnesImportStreamProcessor.CompressedWorkItems compressedItems) { try { @@ -148,7 +148,7 @@ private void States_MarkQueued(BSNESImportStreamProcessor.CompressedWorkItems co } } - private void Stats_MarkCompleted(BSNESImportStreamProcessor.CompressedWorkItems compressedItems) + private void Stats_MarkCompleted(BsnesImportStreamProcessor.CompressedWorkItems compressedItems) { try { @@ -162,7 +162,7 @@ private void Stats_MarkCompleted(BSNESImportStreamProcessor.CompressedWorkItems } } - private void ProcessWorkItem(BSNESImportStreamProcessor.WorkItem workItem) + private void ProcessWorkItem(BsnesImportStreamProcessor.WorkItem workItem) { try { @@ -182,7 +182,7 @@ public void SignalToStop() taskManager.StartFinishing(); } - public (BSNESTraceLogImporter.Stats stats, int bytesToProcess) GetStats() + public (BsnesTraceLogImporter.Stats stats, int bytesToProcess) GetStats() { if (importer == null) return (cachedStats, 0); diff --git a/Diz.Core/import/BSNESTraceLogImporter.cs b/Diz.Core/import/BSNESTraceLogImporter.cs index 336d42c0..7be516e8 100644 --- a/Diz.Core/import/BSNESTraceLogImporter.cs +++ b/Diz.Core/import/BSNESTraceLogImporter.cs @@ -6,41 +6,41 @@ namespace Diz.Core.import { - public class BSNESTraceLogImporter + public class BsnesTraceLogImporter { - private Data Data; + private Data data; int romSize; public struct Stats { - public long numRomBytesAnalyzed; - public long numRomBytesModified; - - public long numXFlagsModified; - public long numMFlagsModified; - public long numDBModified; - public long numDpModified; - public long numMarksModified; + public long NumRomBytesAnalyzed; + public long NumRomBytesModified; + + public long NumXFlagsModified; + public long NumMFlagsModified; + public long NumDbModified; + public long NumDpModified; + public long NumMarksModified; } public Stats CurrentStats; public Data GetData() { - return Data; + return data; } - public BSNESTraceLogImporter(Data data) + public BsnesTraceLogImporter(Data data) { - Data = data; - romSize = Data.GetROMSize(); - - CurrentStats.numRomBytesAnalyzed = 0; - CurrentStats.numRomBytesModified = 0; - CurrentStats.numXFlagsModified = 0; - CurrentStats.numMFlagsModified = 0; - CurrentStats.numDBModified = 0; - CurrentStats.numDpModified = 0; - CurrentStats.numMarksModified = 0; + this.data = data; + romSize = this.data.GetRomSize(); + + CurrentStats.NumRomBytesAnalyzed = 0; + CurrentStats.NumRomBytesModified = 0; + CurrentStats.NumXFlagsModified = 0; + CurrentStats.NumMFlagsModified = 0; + CurrentStats.NumDbModified = 0; + CurrentStats.NumDpModified = 0; + CurrentStats.NumMarksModified = 0; } // this class exists for performance optimization ONLY. @@ -54,18 +54,18 @@ private class CachedTraceLineIndex // index of the start of the info public readonly int - addr, + Addr, D, - DB, - flags, - f_N, - f_V, - f_M, - f_X, - f_D, - f_I, - f_Z, - f_C; + Db, + Flags, + FN, + FV, + FM, + FX, + FD, + FI, + FZ, + FC; public CachedTraceLineIndex() { @@ -74,20 +74,20 @@ int SkipToken(string token) return sample.IndexOf(token) + token.Length; } - addr = 0; + Addr = 0; D = SkipToken("D:"); - DB = SkipToken("DB:"); - flags = DB + 3; + Db = SkipToken("DB:"); + Flags = Db + 3; // flags: nvmxdizc - f_N = flags + 0; - f_V = flags + 1; - f_M = flags + 2; - f_X = flags + 3; - f_D = flags + 4; - f_I = flags + 5; - f_Z = flags + 6; - f_C = flags + 7; + FN = Flags + 0; + FV = Flags + 1; + FM = Flags + 2; + FX = Flags + 3; + FD = Flags + 4; + FI = Flags + 5; + FZ = Flags + 6; + FC = Flags + 7; } } @@ -113,15 +113,15 @@ int GetHexValueAt(int startIndex, int length) // TODO: error treatment / validation var directPage = GetHexValueAt(CachedIdx.D, 4); - var dataBank = GetHexValueAt(CachedIdx.DB, 2); + var dataBank = GetHexValueAt(CachedIdx.Db, 2); // 'X' = unchecked in bsnesplus debugger UI = (8bit), 'x' or '.' = checked (16bit) - var xflag_set = line[CachedIdx.f_X] == 'X'; + var xflagSet = line[CachedIdx.FX] == 'X'; // 'M' = unchecked in bsnesplus debugger UI = (8bit), 'm' or '.' = checked (16bit) - var mflag_set = line[CachedIdx.f_M] == 'M'; + var mflagSet = line[CachedIdx.FM] == 'M'; - SetOpcodeAndOperandsFromTraceData(snesAddress, dataBank, directPage, xflag_set, mflag_set); + SetOpcodeAndOperandsFromTraceData(snesAddress, dataBank, directPage, xflagSet, mflagSet); } // this is same as above but, reads the same data from a binary format. this is for @@ -208,7 +208,7 @@ private void SetOpcodeAndOperandsFromTraceData( if (!SetOneRomByteFromTraceData(snesAddress, dataBank, directPage, xflagSet, mflagSet, opcodeLen, currentIndex)) break; - snesAddress = RomUtil.CalculateSNESOffsetWithWrap(snesAddress, 1); + snesAddress = RomUtil.CalculateSnesOffsetWithWrap(snesAddress, 1); currentIndex++; } } @@ -216,10 +216,10 @@ private void SetOpcodeAndOperandsFromTraceData( private bool SetOneRomByteFromTraceData(int snesAddress, int dataBank, int directPage, bool xflagSet, bool mflagSet, int opcodeLen, int currentIndex) { - CurrentStats.numRomBytesAnalyzed++; + CurrentStats.NumRomBytesAnalyzed++; - var pc = Data.ConvertSNEStoPC(snesAddress); - if (!IsOKToSetThisRomByte(pc, currentIndex, opcodeLen)) + var pc = data.ConvertSnesToPc(snesAddress); + if (!IsOkToSetThisRomByte(pc, currentIndex, opcodeLen)) return false; var flagType = currentIndex == 0 ? Data.FlagType.Opcode : Data.FlagType.Operand; @@ -231,16 +231,16 @@ private bool SetOneRomByteFromTraceData(int snesAddress, int dataBank, int direc // flipping and re-flipping bytes, but still maintain correctness with the game itself. // actually do the update - Data.SetFlag(pc, flagType); - Data.SetDataBank(pc, dataBank); - Data.SetDirectPage(pc, directPage); - Data.SetXFlag(pc, xflagSet); - Data.SetMFlag(pc, mflagSet); + data.SetFlag(pc, flagType); + data.SetDataBank(pc, dataBank); + data.SetDirectPage(pc, directPage); + data.SetXFlag(pc, xflagSet); + data.SetMFlag(pc, mflagSet); return true; } - private bool IsOKToSetThisRomByte(int pc, int opIndex, int instructionByteLen) + private bool IsOkToSetThisRomByte(int pc, int opIndex, int instructionByteLen) { if (pc < 0 || pc >= romSize) return false; @@ -275,26 +275,26 @@ private bool IsOKToSetThisRomByte(int pc, int opIndex, int instructionByteLen) // just play it safe and stop at the first thing that's NOT an Operand. // // Calling code should ideally not let us get to here, and instead supply us with a valid instructionByteLen - return Data.GetFlag(pc) == Data.FlagType.Operand; + return data.GetFlag(pc) == Data.FlagType.Operand; } } private void LogStats(int pc, int dataBank, int directPage, bool xflagSet, bool mflagSet, Data.FlagType flagType) { - var mMarks = Data.GetFlag(pc) != flagType; - var mDb = Data.GetDataBank(pc) != dataBank; - var mDp = Data.GetDirectPage(pc) != directPage; - var mX = Data.GetXFlag(pc) != xflagSet; - var mM = Data.GetMFlag(pc) != mflagSet; + var mMarks = data.GetFlag(pc) != flagType; + var mDb = data.GetDataBank(pc) != dataBank; + var mDp = data.GetDirectPage(pc) != directPage; + var mX = data.GetXFlag(pc) != xflagSet; + var mM = data.GetMFlag(pc) != mflagSet; if (mMarks || mDb || mDp || mX || mM) - CurrentStats.numRomBytesModified++; + CurrentStats.NumRomBytesModified++; - CurrentStats.numMarksModified += mMarks ? 1 : 0; - CurrentStats.numDBModified += mDb ? 1 : 0; - CurrentStats.numDpModified += mDp ? 1 : 0; - CurrentStats.numXFlagsModified += mX ? 1 : 0; - CurrentStats.numMFlagsModified += mM ? 1 : 0; + CurrentStats.NumMarksModified += mMarks ? 1 : 0; + CurrentStats.NumDbModified += mDb ? 1 : 0; + CurrentStats.NumDpModified += mDp ? 1 : 0; + CurrentStats.NumXFlagsModified += mX ? 1 : 0; + CurrentStats.NumMFlagsModified += mM ? 1 : 0; } } } \ No newline at end of file diff --git a/Diz.Core/import/BSNESUsageMapImporter.cs b/Diz.Core/import/BSNESUsageMapImporter.cs index d347f03f..cf084152 100644 --- a/Diz.Core/import/BSNESUsageMapImporter.cs +++ b/Diz.Core/import/BSNESUsageMapImporter.cs @@ -3,7 +3,7 @@ namespace Diz.Core.import { - public class BSNESUsageMapImporter + public class BsnesUsageMapImporter { // TODO: move BsnesPlusUsage stuff to its own class outside of Data [Flags] @@ -20,13 +20,13 @@ public enum BsnesPlusUsage : byte // move out of here to extension method or just external method public int ImportUsageMap(byte[] usageMap, Data data) { - int size = data.GetROMSize(); + int size = data.GetRomSize(); int modified = 0; int prevFlags = 0; for (int map = 0; map <= 0xFFFFFF; map++) { - var i = data.ConvertSNEStoPC(map); + var i = data.ConvertSnesToPc(map); if (i == -1 || i >= size) { @@ -59,7 +59,7 @@ public int ImportUsageMap(byte[] usageMap, Data data) data.SetFlag(i, Data.FlagType.Opcode); } - data.SetMXFlags(i, prevFlags); + data.SetMxFlags(i, prevFlags); modified++; } else if (flags.HasFlag(BsnesPlusUsage.UsageRead)) diff --git a/Diz.Core/import/BizHawkCdlImporter.cs b/Diz.Core/import/BizHawkCdlImporter.cs index c4d1cb07..88428c81 100644 --- a/Diz.Core/import/BizHawkCdlImporter.cs +++ b/Diz.Core/import/BizHawkCdlImporter.cs @@ -16,11 +16,11 @@ public enum Flag : byte None = 0x00, ExecFirst = 0x01, ExecOperand = 0x02, - CPUData = 0x04, - DMAData = 0x08, - CPUXFlag = 0x10, - CPUMFlag = 0x20, - BRR = 0x80 + CpuData = 0x04, + DmaData = 0x08, + CpuxFlag = 0x10, + CpumFlag = 0x20, + Brr = 0x80 } public static void Import(string filename, Data data) @@ -69,7 +69,7 @@ private void CopyInto(Data data) throw new InvalidDataException("The CDL file does not contain CARTROM block."); } - var size = Math.Min(cdlRomFlags.Count, data.GetROMSize()); + var size = Math.Min(cdlRomFlags.Count, data.GetRomSize()); bool m = false; bool x = false; for (var offset = 0; offset < size; offset++) @@ -82,14 +82,14 @@ private void CopyInto(Data data) if ((cdlFlag & BizHawkCdlImporter.Flag.ExecFirst) != 0) { type = Data.FlagType.Opcode; - m = (cdlFlag & BizHawkCdlImporter.Flag.CPUMFlag) != 0; - x = (cdlFlag & BizHawkCdlImporter.Flag.CPUXFlag) != 0; + m = (cdlFlag & BizHawkCdlImporter.Flag.CpumFlag) != 0; + x = (cdlFlag & BizHawkCdlImporter.Flag.CpuxFlag) != 0; } else if ((cdlFlag & BizHawkCdlImporter.Flag.ExecOperand) != 0) type = Data.FlagType.Operand; - else if ((cdlFlag & BizHawkCdlImporter.Flag.CPUData) != 0) + else if ((cdlFlag & BizHawkCdlImporter.Flag.CpuData) != 0) type = Data.FlagType.Data8Bit; - else if ((cdlFlag & BizHawkCdlImporter.Flag.DMAData) != 0) + else if ((cdlFlag & BizHawkCdlImporter.Flag.DmaData) != 0) type = Data.FlagType.Data8Bit; data.Mark(offset, type, 1); diff --git a/Diz.Core/model/Data.Constants.cs b/Diz.Core/model/Data.Constants.cs index 06dd905f..ad112d79 100644 --- a/Diz.Core/model/Data.Constants.cs +++ b/Diz.Core/model/Data.Constants.cs @@ -62,9 +62,9 @@ public enum FlagType : byte public enum Architecture : byte { - [Description("65C816")] CPU65C816 = 0x00, - [Description("SPC700")] APUSPC700 = 0x01, - [Description("SuperFX")] GPUSuperFX = 0x02 + [Description("65C816")] Cpu65C816 = 0x00, + [Description("SPC700")] Apuspc700 = 0x01, + [Description("SuperFX")] GpuSuperFx = 0x02 } [Flags] @@ -75,37 +75,10 @@ public enum InOutPoint : byte EndPoint = 0x04, ReadPoint = 0x08 } - - public enum ROMMapMode : byte - { - LoROM, - - HiROM, - - ExHiROM, - - [Description("SA - 1 ROM")] SA1ROM, - - [Description("SA-1 ROM (FuSoYa's 8MB mapper)")] - ExSA1ROM, - - SuperFX, - - [Description("Super MMC")] SuperMMC, - - ExLoROM - } - - public enum ROMSpeed : byte - { - SlowROM, - FastROM, - Unknown - } - - public const int LOROM_SETTING_OFFSET = 0x7FD5; - public const int HIROM_SETTING_OFFSET = 0xFFD5; - public const int EXHIROM_SETTING_OFFSET = 0x40FFD5; - public const int EXLOROM_SETTING_OFFSET = 0x407FD5; + + public const int LoromSettingOffset = 0x7FD5; + public const int HiromSettingOffset = 0xFFD5; + public const int ExhiromSettingOffset = 0x40FFD5; + public const int ExloromSettingOffset = 0x407FD5; } } \ No newline at end of file diff --git a/Diz.Core/model/Data.Properties.cs b/Diz.Core/model/Data.Properties.cs index dc0ab2b0..bcb88527 100644 --- a/Diz.Core/model/Data.Properties.cs +++ b/Diz.Core/model/Data.Properties.cs @@ -1,4 +1,5 @@ using System.Linq; +using Diz.Core.util; using IX.Observable; namespace Diz.Core.model @@ -7,8 +8,8 @@ public partial class Data { // don't modify these directly, always go through the public properties so // other objects can subscribe to modification notifications - private ROMMapMode romMapMode; - private ROMSpeed romSpeed = ROMSpeed.Unknown; + private RomMapMode romMapMode; + private RomSpeed romSpeed = RomSpeed.Unknown; private ObservableDictionary comments = new ObservableDictionary(); private ObservableDictionary labels = new ObservableDictionary(); private RomBytes romBytes = new RomBytes(); @@ -16,13 +17,13 @@ public partial class Data // Note: order of these public properties matters for the load/save process. Keep 'RomBytes' LAST // TODO: should be a way in the XML serializer to control the order, remove this comment // when we figure it out. - public ROMMapMode RomMapMode + public RomMapMode RomMapMode { get => romMapMode; set => SetField(ref romMapMode, value); } - public ROMSpeed RomSpeed + public RomSpeed RomSpeed { get => romSpeed; set => SetField(ref romSpeed, value); diff --git a/Diz.Core/model/Data.cs b/Diz.Core/model/Data.cs index 762feeff..2b53cf1f 100644 --- a/Diz.Core/model/Data.cs +++ b/Diz.Core/model/Data.cs @@ -9,11 +9,11 @@ namespace Diz.Core.model { public partial class Data : DizDataModel { - private readonly CPU65C816 cpu65C816; // TODO: this really shouldn't be in Data, move to an outside 'SNESSystem' class or something + private readonly Cpu65C816 cpu65C816; // TODO: this really shouldn't be in Data, move to an outside 'SNESSystem' class or something public Data() { - cpu65C816 = new CPU65C816(this); + cpu65C816 = new Cpu65C816(this); } public void CreateRomBytesFromRom(IEnumerable actualRomBytes) @@ -26,7 +26,7 @@ public void CreateRomBytesFromRom(IEnumerable actualRomBytes) RomBytes.Clear(); foreach (var fileByte in actualRomBytes) { - RomBytes.Add(new ROMByte + RomBytes.Add(new RomByte { Rom = fileByte, }); @@ -39,7 +39,7 @@ private byte[] GetRomBytes(int pcOffset, int count) { byte[] output = new byte[count]; for (int i = 0; i < output.Length; i++) - output[i] = (byte)GetROMByte(ConvertSNEStoPC(pcOffset + i)); + output[i] = (byte)GetRomByte(ConvertSnesToPc(pcOffset + i)); return output; } @@ -69,9 +69,7 @@ public void CopyRomDataIn(byte[] data) RomBytes.SendNotificationChangedEvents = previousNotificationState; } - public int GetROMSize() => RomBytes?.Count ?? 0; - public ROMMapMode GetROMMapMode() => RomMapMode; - public ROMSpeed GetROMSpeed() => RomSpeed; + public int GetRomSize() => RomBytes?.Count ?? 0; public FlagType GetFlag(int i) => RomBytes[i].TypeFlag; public void SetFlag(int i, FlagType flag) => RomBytes[i].TypeFlag = flag; public Architecture GetArchitecture(int i) => RomBytes[i].Arch; @@ -87,11 +85,11 @@ public void CopyRomDataIn(byte[] data) public void SetXFlag(int i, bool x) => RomBytes[i].XFlag = x; public bool GetMFlag(int i) => RomBytes[i].MFlag; public void SetMFlag(int i, bool m) => RomBytes[i].MFlag = m; - public int GetMXFlags(int i) + public int GetMxFlags(int i) { return (RomBytes[i].MFlag ? 0x20 : 0) | (RomBytes[i].XFlag ? 0x10 : 0); } - public void SetMXFlags(int i, int mx) + public void SetMxFlags(int i, int mx) { RomBytes[i].MFlag = ((mx & 0x20) != 0); RomBytes[i].XFlag = ((mx & 0x10) != 0); @@ -99,14 +97,14 @@ public void SetMXFlags(int i, int mx) public string GetLabelName(int i) { if (Labels.TryGetValue(i, out var val)) - return val?.name ?? ""; + return val?.Name ?? ""; return ""; } public string GetLabelComment(int i) { if (Labels.TryGetValue(i, out var val)) - return val?.comment ?? ""; + return val?.Comment ?? ""; return ""; } @@ -153,27 +151,27 @@ public void AddComment(int i, string v, bool overwrite) } } - public int ConvertPCtoSNES(int offset) + public int ConvertPCtoSnes(int offset) { - return RomUtil.ConvertPCtoSNES(offset, RomMapMode, GetROMSpeed()); + return RomUtil.ConvertPCtoSnes(offset, RomMapMode, RomSpeed); } - public int GetROMByte(int i) => RomBytes[i].Rom; - public int GetROMWord(int offset) + public int GetRomByte(int i) => RomBytes[i].Rom; + public int GetRomWord(int offset) { - if (offset + 1 < GetROMSize()) - return GetROMByte(offset) + (GetROMByte(offset + 1) << 8); + if (offset + 1 < GetRomSize()) + return GetRomByte(offset) + (GetRomByte(offset + 1) << 8); return -1; } - public int GetROMLong(int offset) + public int GetRomLong(int offset) { - if (offset + 2 < GetROMSize()) - return GetROMByte(offset) + (GetROMByte(offset + 1) << 8) + (GetROMByte(offset + 2) << 16); + if (offset + 2 < GetRomSize()) + return GetRomByte(offset) + (GetRomByte(offset + 1) << 8) + (GetRomByte(offset + 2) << 16); return -1; } - public int GetROMDoubleWord(int offset) + public int GetRomDoubleWord(int offset) { - if (offset + 3 < GetROMSize()) - return GetROMByte(offset) + (GetROMByte(offset + 1) << 8) + (GetROMByte(offset + 2) << 16) + (GetROMByte(offset + 3) << 24); + if (offset + 3 < GetRomSize()) + return GetRomByte(offset) + (GetRomByte(offset + 1) << 8) + (GetRomByte(offset + 2) << 16) + (GetRomByte(offset + 3) << 24); return -1; } public int GetIntermediateAddressOrPointer(int offset) @@ -185,10 +183,10 @@ public int GetIntermediateAddressOrPointer(int offset) return GetIntermediateAddress(offset, true); case FlagType.Pointer16Bit: int bank = GetDataBank(offset); - return (bank << 16) | GetROMWord(offset); + return (bank << 16) | GetRomWord(offset); case FlagType.Pointer24Bit: case FlagType.Pointer32Bit: - return GetROMLong(offset); + return GetRomLong(offset); } return -1; } @@ -202,16 +200,16 @@ public int OpcodeByteLength(int offset) { return GetArchitecture(offset) switch { - Architecture.CPU65C816 => cpu65C816.GetInstructionLength(offset), - Architecture.APUSPC700 => 1, - Architecture.GPUSuperFX => 1, + Architecture.Cpu65C816 => cpu65C816.GetInstructionLength(offset), + Architecture.Apuspc700 => 1, + Architecture.GpuSuperFx => 1, _ => 1 }; } private int UnmirroredOffset(int offset) { - return RomUtil.UnmirroredOffset(offset, GetROMSize()); + return RomUtil.UnmirroredOffset(offset, GetRomSize()); } public string GetFormattedBytes(int offset, int step, int bytes) @@ -231,19 +229,19 @@ public string GetFormattedBytes(int offset, int step, int bytes) switch (step) { - case 1: res += Util.NumberToBaseString(GetROMByte(offset + i), Util.NumberBase.Hexadecimal, 2, true); break; - case 2: res += Util.NumberToBaseString(GetROMWord(offset + i), Util.NumberBase.Hexadecimal, 4, true); break; - case 3: res += Util.NumberToBaseString(GetROMLong(offset + i), Util.NumberBase.Hexadecimal, 6, true); break; - case 4: res += Util.NumberToBaseString(GetROMDoubleWord(offset + i), Util.NumberBase.Hexadecimal, 8, true); break; + case 1: res += Util.NumberToBaseString(GetRomByte(offset + i), Util.NumberBase.Hexadecimal, 2, true); break; + case 2: res += Util.NumberToBaseString(GetRomWord(offset + i), Util.NumberBase.Hexadecimal, 4, true); break; + case 3: res += Util.NumberToBaseString(GetRomLong(offset + i), Util.NumberBase.Hexadecimal, 6, true); break; + case 4: res += Util.NumberToBaseString(GetRomDoubleWord(offset + i), Util.NumberBase.Hexadecimal, 8, true); break; } } return res; } - public int ConvertSNEStoPC(int address) + public int ConvertSnesToPc(int address) { - return RomUtil.ConvertSNESToPC(address, RomMapMode, GetROMSize()); + return RomUtil.ConvertSnesToPc(address, RomMapMode, GetRomSize()); } public string GetPointer(int offset, int bytes) @@ -253,24 +251,24 @@ public string GetPointer(int offset, int bytes) switch (bytes) { case 2: - ia = (GetDataBank(offset) << 16) | GetROMWord(offset); + ia = (GetDataBank(offset) << 16) | GetRomWord(offset); format = "dw {0}"; - param = Util.NumberToBaseString(GetROMWord(offset), Util.NumberBase.Hexadecimal, 4, true); + param = Util.NumberToBaseString(GetRomWord(offset), Util.NumberBase.Hexadecimal, 4, true); break; case 3: - ia = GetROMLong(offset); + ia = GetRomLong(offset); format = "dl {0}"; - param = Util.NumberToBaseString(GetROMLong(offset), Util.NumberBase.Hexadecimal, 6, true); + param = Util.NumberToBaseString(GetRomLong(offset), Util.NumberBase.Hexadecimal, 6, true); break; case 4: - ia = GetROMLong(offset); + ia = GetRomLong(offset); format = "dl {0}" + - $" : db {Util.NumberToBaseString(GetROMByte(offset + 3), Util.NumberBase.Hexadecimal, 2, true)}"; - param = Util.NumberToBaseString(GetROMLong(offset), Util.NumberBase.Hexadecimal, 6, true); + $" : db {Util.NumberToBaseString(GetRomByte(offset + 3), Util.NumberBase.Hexadecimal, 2, true)}"; + param = Util.NumberToBaseString(GetRomLong(offset), Util.NumberBase.Hexadecimal, 6, true); break; } - var pc = ConvertSNEStoPC(ia); + var pc = ConvertSnesToPc(ia); if (pc >= 0 && GetLabelName(ia) != "") param = GetLabelName(ia); return string.Format(format, param); } @@ -278,13 +276,13 @@ public string GetPointer(int offset, int bytes) public string GetFormattedText(int offset, int bytes) { var text = "db \""; - for (var i = 0; i < bytes; i++) text += (char)GetROMByte(offset + i); + for (var i = 0; i < bytes; i++) text += (char)GetRomByte(offset + i); return text + "\""; } public string GetDefaultLabel(int snes) { - var pcoffset = ConvertSNEStoPC(snes); + var pcoffset = ConvertSnesToPc(snes); var prefix = RomUtil.TypeToLabel(GetFlag(pcoffset)); var labelAddress = Util.NumberToBaseString(snes, Util.NumberBase.Hexadecimal, 6); return $"{prefix}_{labelAddress}"; @@ -294,9 +292,9 @@ public int Step(int offset, bool branch, bool force, int prevOffset) { return GetArchitecture(offset) switch { - Architecture.CPU65C816 => cpu65C816.Step(offset, branch, force, prevOffset), - Architecture.APUSPC700 => offset, - Architecture.GPUSuperFX => offset, + Architecture.Cpu65C816 => cpu65C816.Step(offset, branch, force, prevOffset), + Architecture.Apuspc700 => offset, + Architecture.GpuSuperFx => offset, _ => offset }; } @@ -323,14 +321,14 @@ public int AutoStep(int offset, bool harsh, int amount) { switch (GetArchitecture(newOffset)) { - case Architecture.CPU65C816: + case Architecture.Cpu65C816: if (seenBranches.Contains(newOffset)) { keepGoing = false; break; } - var opcode = GetROMByte(newOffset); + var opcode = GetRomByte(newOffset); nextOffset = Step(newOffset, false, false, prevOffset); var jumpOffset = Step(newOffset, true, false, prevOffset); @@ -347,7 +345,7 @@ public int AutoStep(int offset, bool harsh, int amount) if (opcode == 0x08) // PHP { - stack.Push(GetMXFlags(newOffset)); + stack.Push(GetMxFlags(newOffset)); } else if (opcode == 0x28) // PLP { @@ -357,7 +355,7 @@ public int AutoStep(int offset, bool harsh, int amount) } else { - SetMXFlags(newOffset, stack.Pop()); + SetMxFlags(newOffset, stack.Pop()); } } @@ -386,8 +384,8 @@ public int AutoStep(int offset, bool harsh, int amount) newOffset = nextOffset; } break; - case Architecture.APUSPC700: - case Architecture.GPUSuperFX: + case Architecture.Apuspc700: + case Architecture.GpuSuperFx: nextOffset = Step(newOffset, false, true, prevOffset); prevOffset = newOffset; newOffset = nextOffset; @@ -403,42 +401,42 @@ public int AutoStep(int offset, bool harsh, int amount) public int Mark(int offset, FlagType type, int count) { - int i, size = GetROMSize(); + int i, size = GetRomSize(); for (i = 0; i < count && offset + i < size; i++) SetFlag(offset + i, type); return offset + i < size ? offset + i : size - 1; } public int MarkDataBank(int offset, int db, int count) { - int i, size = GetROMSize(); + int i, size = GetRomSize(); for (i = 0; i < count && offset + i < size; i++) SetDataBank(offset + i, db); return offset + i < size ? offset + i : size - 1; } public int MarkDirectPage(int offset, int dp, int count) { - int i, size = GetROMSize(); + int i, size = GetRomSize(); for (i = 0; i < count && offset + i < size; i++) SetDirectPage(offset + i, dp); return offset + i < size ? offset + i : size - 1; } public int MarkXFlag(int offset, bool x, int count) { - int i, size = GetROMSize(); + int i, size = GetRomSize(); for (i = 0; i < count && offset + i < size; i++) SetXFlag(offset + i, x); return offset + i < size ? offset + i : size - 1; } public int MarkMFlag(int offset, bool m, int count) { - int i, size = GetROMSize(); + int i, size = GetRomSize(); for (i = 0; i < count && offset + i < size; i++) SetMFlag(offset + i, m); return offset + i < size ? offset + i : size - 1; } public int MarkArchitechture(int offset, Architecture arch, int count) { - int i, size = GetROMSize(); + int i, size = GetRomSize(); for (i = 0; i < count && offset + i < size; i++) SetArchitechture(offset + i, arch); return offset + i < size ? offset + i : size - 1; } @@ -447,16 +445,16 @@ public int GetInstructionLength(int offset) { return GetArchitecture(offset) switch { - Architecture.CPU65C816 => cpu65C816.GetInstructionLength(offset), - Architecture.APUSPC700 => 1, - Architecture.GPUSuperFX => 1, + Architecture.Cpu65C816 => cpu65C816.GetInstructionLength(offset), + Architecture.Apuspc700 => 1, + Architecture.GpuSuperFx => 1, _ => 1 }; } public int FixMisalignedFlags() { - int count = 0, size = GetROMSize(); + int count = 0, size = GetRomSize(); for (var i = 0; i < size; i++) { @@ -508,17 +506,17 @@ public int FixMisalignedFlags() public void RescanInOutPoints() { - for (var i = 0; i < GetROMSize(); i++) ClearInOutPoint(i); + for (var i = 0; i < GetRomSize(); i++) ClearInOutPoint(i); - for (var i = 0; i < GetROMSize(); i++) + for (var i = 0; i < GetRomSize(); i++) { if (GetFlag(i) == FlagType.Opcode) { switch (GetArchitecture(i)) { - case Architecture.CPU65C816: cpu65C816.MarkInOutPoints(i); break; - case Architecture.APUSPC700: break; - case Architecture.GPUSuperFX: break; + case Architecture.Cpu65C816: cpu65C816.MarkInOutPoints(i); break; + case Architecture.Apuspc700: break; + case Architecture.GpuSuperFx: break; } } } @@ -529,9 +527,9 @@ public int GetIntermediateAddress(int offset, bool resolve = false) // FIX ME: log and generation of dp opcodes. search references return GetArchitecture(offset) switch { - Architecture.CPU65C816 => cpu65C816.GetIntermediateAddress(offset, resolve), - Architecture.APUSPC700 => -1, - Architecture.GPUSuperFX => -1, + Architecture.Cpu65C816 => cpu65C816.GetIntermediateAddress(offset, resolve), + Architecture.Apuspc700 => -1, + Architecture.GpuSuperFx => -1, _ => -1 }; } @@ -540,9 +538,9 @@ public string GetInstruction(int offset) { return GetArchitecture(offset) switch { - Architecture.CPU65C816 => cpu65C816.GetInstruction(offset), - Architecture.APUSPC700 => "", - Architecture.GPUSuperFX => "", + Architecture.Cpu65C816 => cpu65C816.GetInstruction(offset), + Architecture.Apuspc700 => "", + Architecture.GpuSuperFx => "", _ => "" }; } @@ -554,15 +552,15 @@ public int GetNumberOfBanks() public string GetBankName(int bankIndex) { - var bankSnesByte = GetSNESBankByte(bankIndex); + var bankSnesByte = GetSnesBankByte(bankIndex); return Util.NumberToBaseString(bankSnesByte, Util.NumberBase.Hexadecimal, 2); } - private int GetSNESBankByte(int bankIndex) + private int GetSnesBankByte(int bankIndex) { - var bankStartingPCOffset = bankIndex << 16; - var bankSNESNumber = ConvertPCtoSNES(bankStartingPCOffset) >> 16; - return bankSNESNumber; + var bankStartingPcOffset = bankIndex << 16; + var bankSnesNumber = ConvertPCtoSnes(bankStartingPcOffset) >> 16; + return bankSnesNumber; } } } diff --git a/Diz.Core/model/Label.cs b/Diz.Core/model/Label.cs index 9710f227..a51d3fd6 100644 --- a/Diz.Core/model/Label.cs +++ b/Diz.Core/model/Label.cs @@ -14,19 +14,19 @@ public class Label { - public string name = ""; // name of the label - public string comment = ""; // user-generated text, comment only + public string Name = ""; // name of the label + public string Comment = ""; // user-generated text, comment only public void CleanUp() { - comment ??= ""; - name ??= ""; + Comment ??= ""; + Name ??= ""; } #region Equality protected bool Equals(Label other) { - return name == other.name && comment == other.comment; + return Name == other.Name && Comment == other.Comment; } public override bool Equals(object obj) @@ -40,7 +40,7 @@ public override int GetHashCode() { unchecked { - return ((name != null ? name.GetHashCode() : 0) * 397) ^ (comment != null ? comment.GetHashCode() : 0); + return ((Name != null ? Name.GetHashCode() : 0) * 397) ^ (Comment != null ? Comment.GetHashCode() : 0); } } diff --git a/Diz.Core/model/ROMByte.cs b/Diz.Core/model/ROMByte.cs index f2963c84..9bef9d9a 100644 --- a/Diz.Core/model/ROMByte.cs +++ b/Diz.Core/model/ROMByte.cs @@ -2,7 +2,7 @@ namespace Diz.Core.model { - public class ROMByte : DizDataModel + public class RomByte : DizDataModel { // never modify directly. only go through the public fields private byte rom; @@ -11,7 +11,7 @@ public class ROMByte : DizDataModel private bool xFlag; private bool mFlag; private Data.FlagType typeFlag = Data.FlagType.Unreached; - private Data.Architecture arch = Data.Architecture.CPU65C816; + private Data.Architecture arch = Data.Architecture.Cpu65C816; private Data.InOutPoint point = 0; // holds the original byte from the source ROM @@ -76,12 +76,12 @@ public void SetCachedOffset(int offset) #region Equality - protected bool Equals(ROMByte other) + protected bool Equals(RomByte other) { return Rom == other.Rom && EqualsButNoRomByte(other); } - public bool EqualsButNoRomByte(ROMByte other) + public bool EqualsButNoRomByte(RomByte other) { return DataBank == other.DataBank && DirectPage == other.DirectPage && XFlag == other.XFlag && MFlag == other.MFlag && TypeFlag == other.TypeFlag && Arch == other.Arch && Point == other.Point; } @@ -90,7 +90,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == this.GetType() && Equals((ROMByte)obj); + return obj.GetType() == this.GetType() && Equals((RomByte)obj); } public override int GetHashCode() diff --git a/Diz.Core/model/RomBytes.cs b/Diz.Core/model/RomBytes.cs index ae930e46..63cbd99f 100644 --- a/Diz.Core/model/RomBytes.cs +++ b/Diz.Core/model/RomBytes.cs @@ -7,16 +7,16 @@ namespace Diz.Core.model { - public class RomBytes : IEnumerable, INotifyCollectionChanged, INotifyPropertyChanged + public class RomBytes : IEnumerable, INotifyCollectionChanged, INotifyPropertyChanged { - private ObservableCollection bytes; + private ObservableCollection bytes; // TODO: might be able to do something more generic now that other refactorings are completed. // // This class needs to do these things that are special: // 1) Be handled specially by our custom XML serializer (compresses to save disk space) // 2) Handle Equals() by comparing each element in the list (SequenceEqual) - private ObservableCollection Bytes + private ObservableCollection Bytes { get => bytes; set @@ -31,7 +31,7 @@ private ObservableCollection Bytes } } - public ROMByte this[int i] + public RomByte this[int i] { get => Bytes[i]; set => Bytes[i] = value; @@ -39,18 +39,18 @@ public ROMByte this[int i] public RomBytes() { - Bytes = new ObservableCollection(); + Bytes = new ObservableCollection(); } - public void SetFrom(ROMByte[] romBytes) + public void SetFrom(RomByte[] romBytes) { - Bytes = new ObservableCollection(romBytes); + Bytes = new ObservableCollection(romBytes); } public int Count => Bytes.Count; public bool SendNotificationChangedEvents { get; set; } = true; - public void Add(ROMByte romByte) + public void Add(RomByte romByte) { Bytes.Add(romByte); romByte.SetCachedOffset(Bytes.Count - 1); // I don't love this.... @@ -59,7 +59,7 @@ public void Add(ROMByte romByte) public void Create(int size) { for (var i = 0; i < size; ++i) - Add(new ROMByte()); + Add(new RomByte()); } public void Clear() { @@ -87,7 +87,7 @@ public override int GetHashCode() #endregion #region Enumerator - public IEnumerator GetEnumerator() + public IEnumerator GetEnumerator() { return Bytes.GetEnumerator(); } @@ -104,11 +104,11 @@ IEnumerator IEnumerable.GetEnumerator() private void Bytes_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.NewItems != null) - foreach (ROMByte item in e.NewItems) + foreach (RomByte item in e.NewItems) item.PropertyChanged += RomByteObjectChanged; if (e.OldItems != null) - foreach (ROMByte item in e.OldItems) + foreach (RomByte item in e.OldItems) item.PropertyChanged -= RomByteObjectChanged; if (SendNotificationChangedEvents) diff --git a/Diz.Core/serialization/ImportSettings.cs b/Diz.Core/serialization/ImportSettings.cs index 27f65d48..9f22e6ad 100644 --- a/Diz.Core/serialization/ImportSettings.cs +++ b/Diz.Core/serialization/ImportSettings.cs @@ -1,23 +1,24 @@ using System.Collections.Generic; using Diz.Core.model; +using Diz.Core.util; using DiztinGUIsh; namespace Diz.Core.serialization { public class ImportRomSettings : PropertyNotifyChanged { - private Data.ROMMapMode mode; - private Data.ROMSpeed romSpeed; + private RomMapMode mode; + private RomSpeed romSpeed; private byte[] romBytes; private string romFilename; - public Data.ROMMapMode ROMMapMode + public RomMapMode RomMapMode { get => mode; set => SetField(ref mode, value); } - public Data.ROMSpeed ROMSpeed + public RomSpeed RomSpeed { get => romSpeed; set => SetField(ref romSpeed, value); diff --git a/Diz.Core/serialization/ProjectFileManager.cs b/Diz.Core/serialization/ProjectFileManager.cs index d7668dbc..d4732d9c 100644 --- a/Diz.Core/serialization/ProjectFileManager.cs +++ b/Diz.Core/serialization/ProjectFileManager.cs @@ -130,8 +130,8 @@ public static Project ImportRomAndCreateNewProject(ImportRomSettings importSetti Data = new Data() }; - project.Data.RomMapMode = importSettings.ROMMapMode; - project.Data.RomSpeed = importSettings.ROMSpeed; + project.Data.RomMapMode = importSettings.RomMapMode; + project.Data.RomSpeed = importSettings.RomSpeed; project.Data.CreateRomBytesFromRom(importSettings.RomBytes); foreach (var pair in importSettings.InitialLabels) diff --git a/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs b/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs index 24701471..1935902d 100644 --- a/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs +++ b/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs @@ -10,8 +10,8 @@ namespace Diz.Core.serialization.binary_serializer_old { internal class BinarySerializer : ProjectSerializer { - public const int HEADER_SIZE = 0x100; - private const int LATEST_FILE_FORMAT_VERSION = 2; + public const int HeaderSize = 0x100; + private const int LatestFileFormatVersion = 2; public static bool IsBinaryFileFormat(byte[] data) { @@ -24,13 +24,13 @@ public static bool IsBinaryFileFormat(byte[] data) public override byte[] Save(Project project) { - const int versionToSave = LATEST_FILE_FORMAT_VERSION; + const int versionToSave = LatestFileFormatVersion; var data = SaveVersion(project, versionToSave); - var everything = new byte[HEADER_SIZE + data.Length]; + var everything = new byte[HeaderSize + data.Length]; everything[0] = versionToSave; ByteUtil.StringToByteArray(Watermark).CopyTo(everything, 1); - data.CopyTo(everything, HEADER_SIZE); + data.CopyTo(everything, HeaderSize); return data; } @@ -51,15 +51,15 @@ public override (Project project, string warning) Load(byte[] data) // version 0 needs to convert PC to SNES for some addresses ByteUtil.AddressConverter converter = address => address; if (version == 0) - converter = project.Data.ConvertPCtoSNES; + converter = project.Data.ConvertPCtoSnes; // read mode, speed, size - project.Data.RomMapMode = (Data.ROMMapMode)data[HEADER_SIZE]; - project.Data.RomSpeed = (Data.ROMSpeed)data[HEADER_SIZE + 1]; - var size = ByteUtil.ByteArrayToInt32(data, HEADER_SIZE + 2); + project.Data.RomMapMode = (RomMapMode)data[HeaderSize]; + project.Data.RomSpeed = (RomSpeed)data[HeaderSize + 1]; + var size = ByteUtil.ByteArrayToInt32(data, HeaderSize + 2); // read internal title - var pointer = HEADER_SIZE + 6; + var pointer = HeaderSize + 6; project.InternalRomGameName = RomUtil.ReadStringFromByteArray(data, RomUtil.LengthOfTitleName, pointer); pointer += RomUtil.LengthOfTitleName; @@ -89,7 +89,7 @@ public override (Project project, string warning) Load(byte[] data) project.UnsavedChanges = false; var warning = ""; - if (version != LATEST_FILE_FORMAT_VERSION) + if (version != LatestFileFormatVersion) { warning = "This project file is in an older format.\n" + "You may want to back up your work or 'Save As' in case the conversion goes wrong.\n" + @@ -114,12 +114,12 @@ private byte[] SaveVersion(Project project, int version) { ValidateSaveVersion(version); - int size = project.Data.GetROMSize(); + int size = project.Data.GetRomSize(); byte[] romSettings = new byte[31]; // save these two - romSettings[0] = (byte)project.Data.GetROMMapMode(); - romSettings[1] = (byte)project.Data.GetROMSpeed(); + romSettings[0] = (byte)project.Data.RomMapMode; + romSettings[1] = (byte)project.Data.RomSpeed; // save the size, 4 bytes ByteUtil.IntegerIntoByteArray(size, romSettings, 2); @@ -134,23 +134,23 @@ private byte[] SaveVersion(Project project, int version) // save all labels ad comments List label = new List(), comment = new List(); - var all_labels = project.Data.Labels; - var all_comments = project.Data.Comments; + var allLabels = project.Data.Labels; + var allComments = project.Data.Comments; - ByteUtil.IntegerIntoByteList(all_labels.Count, label); - foreach (var pair in all_labels) + ByteUtil.IntegerIntoByteList(allLabels.Count, label); + foreach (var pair in allLabels) { ByteUtil.IntegerIntoByteList(pair.Key, label); - SaveStringToBytes(pair.Value.name, label); + SaveStringToBytes(pair.Value.Name, label); if (version >= 2) { - SaveStringToBytes(pair.Value.comment, label); + SaveStringToBytes(pair.Value.Comment, label); } } - ByteUtil.IntegerIntoByteList(all_comments.Count, comment); - foreach (KeyValuePair pair in all_comments) + ByteUtil.IntegerIntoByteList(allComments.Count, comment); + foreach (KeyValuePair pair in allComments) { ByteUtil.IntegerIntoByteList(pair.Key, comment); SaveStringToBytes(pair.Value, comment); @@ -204,14 +204,14 @@ void ReadOperation(int startIdx, int whichOp) } private static void ValidateSaveVersion(int version) { - if (version < 1 || version > LATEST_FILE_FORMAT_VERSION) { + if (version < 1 || version > LatestFileFormatVersion) { throw new ArgumentException($"Saving: Invalid save version requested for saving: {version}."); } } private static void ValidateProjectFileVersion(int version) { - if (version > LATEST_FILE_FORMAT_VERSION) + if (version > LatestFileFormatVersion) { throw new ArgumentException( "This DiztinGUIsh file uses a newer file format! You'll need to download the newest version of DiztinGUIsh to open it."); @@ -243,8 +243,8 @@ private void ReadLabels(Project project, byte[] bytes, ref int pointer, ByteUtil Debug.Assert(strings.Length == stringsPerEntry); var label = new Label { - name = strings[0], - comment = strings.ElementAtOrDefault(1) + Name = strings[0], + Comment = strings.ElementAtOrDefault(1) }; label.CleanUp(); project.Data.AddLabel(offset, label, true); diff --git a/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs b/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs index e6716b5e..6c7ea4d9 100644 --- a/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs +++ b/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs @@ -9,15 +9,15 @@ namespace Diz.Core.serialization.xml_serializer public class ProjectXmlSerializer : ProjectSerializer { // NEVER CHANGE THIS ONE. - private const int FIRST_SAVE_FORMAT_VERSION = 100; + private const int FirstSaveFormatVersion = 100; - // increment this if you change the XML file format - private const int CURRENT_SAVE_FORMAT_VERSION = FIRST_SAVE_FORMAT_VERSION; + // increment this if you change the XML file format + private const int CurrentSaveFormatVersion = FirstSaveFormatVersion; - // update this if we are dropped support for really old save formats. - private const int EARLIEST_SUPPORTED_SAVE_FORMAT_VERSION = FIRST_SAVE_FORMAT_VERSION; + // update this if we are dropped support for really old save formats. + private const int EarliestSupportedSaveFormatVersion = FirstSaveFormatVersion; - internal class Root + private class Root { // XML serializer specific metadata, top-level deserializer. // This is unique to JUST the XML serializer, doesn't affect any other types of serializers. @@ -40,13 +40,13 @@ public override byte[] Save(Project project) // format version. Note that each serializer has its own implementation of storing this metadata var rootElement = new Root() { - SaveVersion = CURRENT_SAVE_FORMAT_VERSION, + SaveVersion = CurrentSaveFormatVersion, Watermark = ProjectSerializer.Watermark, Project = project, }; var xmlStr = XmlSerializerSupport.GetSerializer().Create().Serialize( - new XmlWriterSettings { Indent = true }, + new XmlWriterSettings {Indent = true}, rootElement); var finalBytes = Encoding.UTF8.GetBytes(xmlStr); @@ -60,9 +60,9 @@ public override byte[] Save(Project project) // just for debugging purposes, compare two projects together to make sure they serialize/deserialize // correctly. - private void DebugVerifyProjectEquality(Project project1, byte[] finalBytes_project2) + private void DebugVerifyProjectEquality(Project project1, byte[] finalBytesProject2) { - var result = Load(finalBytes_project2); + var result = Load(finalBytesProject2); var project2 = result.project; ProjectFileManager.PostSerialize(project2, null); @@ -81,18 +81,21 @@ public override (Project project, string warning) Load(byte[] data) var root = XmlSerializerSupport.GetSerializer().Create().Deserialize(text); if (root.Watermark != Watermark) - throw new InvalidDataException("This file doesn't appear to be a valid DiztinGUIsh XML file (missing/invalid watermark element in XML)"); + throw new InvalidDataException( + "This file doesn't appear to be a valid DiztinGUIsh XML file (missing/invalid watermark element in XML)"); - if (root.SaveVersion > CURRENT_SAVE_FORMAT_VERSION) - throw new InvalidDataException($"Save file version is newer than this version of DiztinGUIsh, likely can't be opened safely. This save file version = '{root.SaveVersion}', our highest supported version is {CURRENT_SAVE_FORMAT_VERSION}"); + if (root.SaveVersion > CurrentSaveFormatVersion) + throw new InvalidDataException( + $"Save file version is newer than this version of DiztinGUIsh, likely can't be opened safely. This save file version = '{root.SaveVersion}', our highest supported version is {CurrentSaveFormatVersion}"); // Apply any migrations here for older save file formats. Right now, // there aren't any because we're on the first revision. // The XML serialization might be fairly forgiving of most kinds of changes, // so you may not have to write migrations unless properties are renamed or deleted. - if (root.SaveVersion < CURRENT_SAVE_FORMAT_VERSION) + if (root.SaveVersion < CurrentSaveFormatVersion) { - throw new InvalidDataException($"Save file version is newer than this version of DiztinGUIsh, likely can't be opened safely. This save file version = '{root.SaveVersion}', our highest supported version is {CURRENT_SAVE_FORMAT_VERSION}"); + throw new InvalidDataException( + $"Save file version is newer than this version of DiztinGUIsh, likely can't be opened safely. This save file version = '{root.SaveVersion}', our highest supported version is {CurrentSaveFormatVersion}"); } var project = root.Project; @@ -101,4 +104,4 @@ public override (Project project, string warning) Load(byte[] data) return (project, warning); } } -} +} \ No newline at end of file diff --git a/Diz.Core/serialization/xml_serializer/RepeaterCompression.cs b/Diz.Core/serialization/xml_serializer/RepeaterCompression.cs index 5f3998f5..6726be9a 100644 --- a/Diz.Core/serialization/xml_serializer/RepeaterCompression.cs +++ b/Diz.Core/serialization/xml_serializer/RepeaterCompression.cs @@ -45,7 +45,7 @@ public static void Compress(ref List lines) // adjustable, just pick something > 8 or it's not worth the optimization. // we want to catch large consecutive blocks of data. - const int min_number_repeats_before_we_bother = 8; + const int minNumberRepeatsBeforeWeBother = 8; int totalLinesDebug = 0; @@ -69,7 +69,7 @@ public static void Compress(ref List lines) consecutive++; } - if (consecutive >= min_number_repeats_before_we_bother) + if (consecutive >= minNumberRepeatsBeforeWeBother) { // replace multiple repeated lines with one new statement output.Add($"r {consecutive.ToString()} {lastLine}"); diff --git a/Diz.Core/serialization/xml_serializer/RomByteEncoding.cs b/Diz.Core/serialization/xml_serializer/RomByteEncoding.cs index 02524887..41d3872a 100644 --- a/Diz.Core/serialization/xml_serializer/RomByteEncoding.cs +++ b/Diz.Core/serialization/xml_serializer/RomByteEncoding.cs @@ -13,13 +13,13 @@ public class RomByteEncoding { public class FlagEncodeEntry { - public char c; - public Data.FlagType f; + public char C; + public Data.FlagType F; }; // totally dumb but saves time vs slow Byte.Parse(x, isHex) // idea credit: Daniel-Lemire - public static readonly int[] hexAsciiToDigit = { + public static readonly int[] HexAsciiToDigit = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, @@ -37,7 +37,7 @@ public class FlagEncodeEntry public static byte ByteParseHex1(char hexChar) { - var result = hexAsciiToDigit[hexChar]; + var result = HexAsciiToDigit[hexChar]; if (result == -1) throw new InvalidDataException("Invalid hex digit"); @@ -59,25 +59,25 @@ public static int ByteParseHex4(char hexChar1, char hexChar2, char hexChar3, cha ByteParseHex1(hexChar4); } - private static readonly List flagEncodeTable = new List { - new FlagEncodeEntry() {f = Data.FlagType.Unreached, c = 'U'}, + private static readonly List FlagEncodeTable = new List { + new FlagEncodeEntry() {F = Data.FlagType.Unreached, C = 'U'}, - new FlagEncodeEntry() {f = Data.FlagType.Opcode, c = '+'}, - new FlagEncodeEntry() {f = Data.FlagType.Operand, c = '.'}, + new FlagEncodeEntry() {F = Data.FlagType.Opcode, C = '+'}, + new FlagEncodeEntry() {F = Data.FlagType.Operand, C = '.'}, - new FlagEncodeEntry() {f = Data.FlagType.Graphics, c = 'G'}, - new FlagEncodeEntry() {f = Data.FlagType.Music, c = 'M'}, - new FlagEncodeEntry() {f = Data.FlagType.Empty, c = 'X'}, - new FlagEncodeEntry() {f = Data.FlagType.Text, c = 'T'}, + new FlagEncodeEntry() {F = Data.FlagType.Graphics, C = 'G'}, + new FlagEncodeEntry() {F = Data.FlagType.Music, C = 'M'}, + new FlagEncodeEntry() {F = Data.FlagType.Empty, C = 'X'}, + new FlagEncodeEntry() {F = Data.FlagType.Text, C = 'T'}, - new FlagEncodeEntry() {f = Data.FlagType.Data8Bit, c = 'A'}, - new FlagEncodeEntry() {f = Data.FlagType.Data16Bit, c = 'B'}, - new FlagEncodeEntry() {f = Data.FlagType.Data24Bit, c = 'C'}, - new FlagEncodeEntry() {f = Data.FlagType.Data32Bit, c = 'D'}, + new FlagEncodeEntry() {F = Data.FlagType.Data8Bit, C = 'A'}, + new FlagEncodeEntry() {F = Data.FlagType.Data16Bit, C = 'B'}, + new FlagEncodeEntry() {F = Data.FlagType.Data24Bit, C = 'C'}, + new FlagEncodeEntry() {F = Data.FlagType.Data32Bit, C = 'D'}, - new FlagEncodeEntry() {f = Data.FlagType.Pointer16Bit, c = 'E'}, - new FlagEncodeEntry() {f = Data.FlagType.Pointer24Bit, c = 'F'}, - new FlagEncodeEntry() {f = Data.FlagType.Pointer32Bit, c = 'G'}, + new FlagEncodeEntry() {F = Data.FlagType.Pointer16Bit, C = 'E'}, + new FlagEncodeEntry() {F = Data.FlagType.Pointer24Bit, C = 'F'}, + new FlagEncodeEntry() {F = Data.FlagType.Pointer32Bit, C = 'G'}, }; private readonly StringBuilder cachedPadSb = new StringBuilder(LineMaxLen); @@ -85,11 +85,11 @@ public static int ByteParseHex4(char hexChar1, char hexChar2, char hexChar3, cha private const int LineMaxLen = 9; // note: performance-intensive function. be really careful when adding stuff here. - public ROMByte DecodeRomByte(string line) + public RomByte DecodeRomByte(string line) { var input = PrepLine(line); - var newByte = new ROMByte(); + var newByte = new RomByte(); var flagTxt = input[0]; var otherFlags1 = Fake64Encoding.DecodeHackyBase64(input[1]); @@ -106,12 +106,12 @@ public ROMByte DecodeRomByte(string line) newByte.Point = (Data.InOutPoint)((otherFlags1 >> 4) & 0xF); var found = false; - foreach (var e in flagEncodeTable) + foreach (var e in FlagEncodeTable) { - if (e.c != flagTxt) + if (e.C != flagTxt) continue; - newByte.TypeFlag = e.f; + newByte.TypeFlag = e.F; found = true; break; } @@ -142,7 +142,7 @@ private StringBuilder PrepLine(string line) return cachedPadSb; } - public string EncodeByte(ROMByte instance) + public string EncodeByte(RomByte instance) { // use a custom formatter here to save space. there are a LOT of ROMBytes. // despite that we're still going for: @@ -158,11 +158,11 @@ public string EncodeByte(ROMByte instance) // NOTE: must be uppercase letter or "=" or "-" // if you add things here, make sure you understand the compression settings above. var flagTxt = ' '; - foreach (var e in flagEncodeTable) + foreach (var e in FlagEncodeTable) { - if (e.f == instance.TypeFlag) + if (e.F == instance.TypeFlag) { - flagTxt = e.c; + flagTxt = e.C; break; } } @@ -178,12 +178,12 @@ public string EncodeByte(ROMByte instance) // LEAVE OFF THE LAST 2 BITS. it'll mess with the base64 below ); // reminder: when decoding, have to cut off all but the first 6 bits - var o1_str = Fake64Encoding.EncodeHackyBase64(otherFlags1); - Debug.Assert(Fake64Encoding.DecodeHackyBase64(o1_str) == otherFlags1); + var o1Str = Fake64Encoding.EncodeHackyBase64(otherFlags1); + Debug.Assert(Fake64Encoding.DecodeHackyBase64(o1Str) == otherFlags1); if (!instance.XFlag && !instance.MFlag && instance.Point == 0) { - Debug.Assert(o1_str == '0'); // sanity + Debug.Assert(o1Str == '0'); // sanity } // this is basically going to be "0" almost 100% of the time. @@ -191,15 +191,15 @@ public string EncodeByte(ROMByte instance) byte otherFlags2 = (byte)( (byte)instance.Arch << 0 // 2 bits ); - var o2_str = otherFlags2.ToString("X1"); Debug.Assert(o2_str.Length == 1); + var o2Str = otherFlags2.ToString("X1"); Debug.Assert(o2Str.Length == 1); // ordering: put DB and D on the end, they're likely to be zero and compressible var sb = new StringBuilder(9); sb.Append(flagTxt); - sb.Append(o1_str); + sb.Append(o1Str); sb.Append(instance.DataBank.ToString("X2")); sb.Append(instance.DirectPage.ToString("X4")); - sb.Append(o2_str); + sb.Append(o2Str); Debug.Assert(sb.Length == 9); var data = sb.ToString(); diff --git a/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs b/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs index 69c5faaa..314962d6 100644 --- a/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs +++ b/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs @@ -31,13 +31,14 @@ sealed class RomBytesSerializer : ISerializer { // let the outer XML class do the heavy lifting on versioning. // but, let's add one here just because this specific class is complex. - private const int CURRENT_DATA_FORMAT_VERSION = 200; + private const int CurrentDataFormatVersion = 200; public static RomBytesSerializer Default { get; } = new RomBytesSerializer(); - public bool compress_groupblock = true; - public bool compress_using_table_1 = true; - public int numTasksToUse = 10; + private const bool CompressGroupBlock = true; + private const bool CompressUsingTable1 = true; + private const int NumTasksToUse = 10; + public RomBytes Get(IFormatReader parameter) { @@ -46,19 +47,19 @@ public RomBytes Get(IFormatReader parameter) return FinishRead(romBytes); } - private ROMByte[] DecodeAllBytes(List allLines) + private RomByte[] DecodeAllBytes(List allLines) { - if (numTasksToUse == 1) + if (NumTasksToUse == 1) return DecodeRomBytes(allLines, 0); var nextIndex = 0; - var workListCount = allLines.Count / numTasksToUse; + var workListCount = allLines.Count / NumTasksToUse; - var tasks = new List>(numTasksToUse); + var tasks = new List>(NumTasksToUse); - for (var t = 0; t < numTasksToUse; ++t) + for (var t = 0; t < NumTasksToUse; ++t) { - var lastThread = t == numTasksToUse - 1; + var lastThread = t == NumTasksToUse - 1; if (lastThread) workListCount = allLines.Count - nextIndex; @@ -71,7 +72,7 @@ private ROMByte[] DecodeAllBytes(List allLines) // ReSharper disable once AccessToStaticMemberViaDerivedType var index = nextIndex; - var task = Task.Run(() => DecodeRomBytes(workList, index)); + var task = Task.Run(() => DecodeRomBytes(workList, index)); tasks.Add(task); nextIndex += workListCount; @@ -82,10 +83,10 @@ private ROMByte[] DecodeAllBytes(List allLines) return continuation.Result.SelectMany(i => i).ToArray(); } - private static ROMByte[] DecodeRomBytes(List lines, int startingLineNum) + private static RomByte[] DecodeRomBytes(List lines, int startingLineNum) { // perf: allocate all at once, don't use List.Add() one at a time - var romBytes = new ROMByte[lines.Count]; + var romBytes = new RomByte[lines.Count]; var currentLineNum = startingLineNum; var romByteEncoding = new RomByteEncoding(); @@ -109,7 +110,7 @@ private static ROMByte[] DecodeRomBytes(List lines, int startingLineNum) return romBytes; } - private static RomBytes FinishRead(ROMByte[] romBytes) + private static RomBytes FinishRead(RomByte[] romBytes) { var romBytesOut = new RomBytes(); romBytesOut.SetFrom(romBytes); @@ -155,18 +156,18 @@ private static void CheckForCompatibleVersion(IEnumerable options) var split = versionOption.Split(':'); Debug.Assert(split.Length == 2); - if (!int.TryParse(split[1], out var version_num)) + if (!int.TryParse(split[1], out var versionNum)) throw new InvalidDataException( $"Couldn't parse version # from version tag"); - if (version_num > CURRENT_DATA_FORMAT_VERSION) + if (versionNum > CurrentDataFormatVersion) throw new InvalidDataException( - $"Newer file format detected: {version_num}. This version of distinguish only supports data table formats up to {CURRENT_DATA_FORMAT_VERSION}."); + $"Newer file format detected: {versionNum}. This version of distinguish only supports data table formats up to {CurrentDataFormatVersion}."); // In the future, we can add migrations here for older version. For now, just reject it. - if (version_num < CURRENT_DATA_FORMAT_VERSION) + if (versionNum < CurrentDataFormatVersion) throw new InvalidDataException( - $"Newer file format detected: {version_num}. This version of distinguish only supports data table formats up to {CURRENT_DATA_FORMAT_VERSION}."); + $"Newer file format detected: {versionNum}. This version of distinguish only supports data table formats up to {CurrentDataFormatVersion}."); } catch (Exception ex) { @@ -178,7 +179,7 @@ public void Write(IFormatWriter writer, RomBytes instance) { var options = new List { - $"version:{CURRENT_DATA_FORMAT_VERSION}", + $"version:{CurrentDataFormatVersion}", }; var romByteEncoding = new RomByteEncoding(); @@ -196,13 +197,13 @@ public void Write(IFormatWriter writer, RomBytes instance) #endif } - if (compress_groupblock) + if (CompressGroupBlock) { options.Add("compress_groupblocks"); RepeaterCompression.Compress(ref lines); } - if (compress_using_table_1) + if (CompressUsingTable1) { options.Add("compress_table_1"); SubstitutionCompression.EncodeCompression_Table1(ref lines); diff --git a/Diz.Core/serialization/xml_serializer/SubstitutionCompression.cs b/Diz.Core/serialization/xml_serializer/SubstitutionCompression.cs index 72988374..50621f00 100644 --- a/Diz.Core/serialization/xml_serializer/SubstitutionCompression.cs +++ b/Diz.Core/serialization/xml_serializer/SubstitutionCompression.cs @@ -12,7 +12,7 @@ private class CompressionEntry public string ShortTextToEncode; } - private static readonly List table1 = new List + private static readonly List Table1 = new List { new CompressionEntry() {LongTextPattern = "0001E", ShortTextToEncode="ZQ"}, new CompressionEntry() {LongTextPattern = "B0001", ShortTextToEncode="Zq"}, @@ -32,7 +32,7 @@ public static void DecodeCompression_Table1(ref List lines) { // shouldn't matter much but, apply in reverse to ensure it's done the same // way as the encoding process - foreach (var e in table1.Reverse()) + foreach (var e in Table1.Reverse()) { lines[i] = lines[i].Replace(e.ShortTextToEncode, e.LongTextPattern); } @@ -48,7 +48,7 @@ public static void EncodeCompression_Table1(ref List lines) // and make a Table2, add that here without having to bump the file version. for (var i = 0; i < lines.Count; ++i) { - foreach (var e in table1) + foreach (var e in Table1) { Debug.Assert(!lines[i].Contains(e.ShortTextToEncode)); lines[i] = lines[i].Replace(e.LongTextPattern, e.ShortTextToEncode); diff --git a/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs b/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs index 7d184116..4e0595e8 100644 --- a/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs +++ b/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs @@ -11,20 +11,18 @@ public static IConfigurationContainer GetSerializer() // This configuration changes how parts of the data structures are serialized back/forth to XML. // This is using the ExtendedXmlSerializer library, which has a zillion config options and is // awesome. - - // TODO: doesn't work for saving ObservableDictionary related stuff yet. we are working - // around it with a wrapper, but, it's clumsy. Somewhere in these options is a way to fix it, - // just gotta figure it out. - return new ConfigurationContainer() + .Type() .Member(x => x.UnsavedChanges).Ignore() + .Type() .Register().Serializer().Using(RomBytesSerializer.Default) + .Type() - .UseOptimizedNamespaces() .UseAutoFormatting() + .EnableImplicitTyping(typeof(Data)) .EnableImplicitTyping(typeof(Label)); } diff --git a/Diz.Core/util/ByteUtil.cs b/Diz.Core/util/ByteUtil.cs index 408640d9..3e2ef166 100644 --- a/Diz.Core/util/ByteUtil.cs +++ b/Diz.Core/util/ByteUtil.cs @@ -32,15 +32,15 @@ public static bool StripFormattedAddress(ref string addressTxt, NumberStyles sty public delegate int AddressConverter(int address); - public static int ReadStringsTable(byte[] bytes, int starting_index, int stringsPerEntry, AddressConverter converter, Action processTableEntry) + public static int ReadStringsTable(byte[] bytes, int startingIndex, int stringsPerEntry, AddressConverter converter, Action processTableEntry) { var strings = new List(); - var pos = starting_index; - var num_table_entries = ByteArrayToInt32(bytes, pos); + var pos = startingIndex; + var numTableEntries = ByteArrayToInt32(bytes, pos); pos += 4; - for (var entry = 0; entry < num_table_entries; ++entry) + for (var entry = 0; entry < numTableEntries; ++entry) { var offset = converter(ByteArrayToInt32(bytes, pos)); pos += 4; @@ -54,17 +54,17 @@ public static int ReadStringsTable(byte[] bytes, int starting_index, int strings processTableEntry(offset, strings.ToArray()); } - return pos - starting_index; + return pos - startingIndex; } - public static int ReadNullTerminatedString(byte[] bytes, int starting_offset, out string str) + public static int ReadNullTerminatedString(byte[] bytes, int startingOffset, out string str) { str = ""; - var pos = starting_offset; + var pos = startingOffset; while (bytes[pos] != 0) str += (char)bytes[pos++]; pos++; - return pos - starting_offset; + return pos - startingOffset; } public static byte[] IntegerToByteArray(int a) diff --git a/Diz.Core/util/RomUtil.cs b/Diz.Core/util/RomUtil.cs index be2182c0..a721103a 100644 --- a/Diz.Core/util/RomUtil.cs +++ b/Diz.Core/util/RomUtil.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.IO; using Diz.Core.export; @@ -6,33 +7,60 @@ namespace Diz.Core.util { + public enum RomSpeed : byte + { + SlowRom, + FastRom, + Unknown + } + + public enum RomMapMode : byte + { + LoRom, + + HiRom, + + ExHiRom, + + [Description("SA - 1 ROM")] Sa1Rom, + + [Description("SA-1 ROM (FuSoYa's 8MB mapper)")] + ExSa1Rom, + + SuperFx, + + [Description("Super MMC")] SuperMmc, + + ExLoRom + } + public static class RomUtil { - public static int CalculateSNESOffsetWithWrap(int snesAddress, int offset) + public static int CalculateSnesOffsetWithWrap(int snesAddress, int offset) { - return (GetBankFromSNESAddress(snesAddress) << 16) + ((snesAddress + offset) & 0xFFFF); + return (GetBankFromSnesAddress(snesAddress) << 16) + ((snesAddress + offset) & 0xFFFF); } - private static int GetBankFromSNESAddress(int snesAddress) + private static int GetBankFromSnesAddress(int snesAddress) { return (snesAddress >> 16) & 0xFF; } - public static int GetBankSize(Data.ROMMapMode mode) + public static int GetBankSize(RomMapMode mode) { // todo - return mode == Data.ROMMapMode.LoROM ? 0x8000 : 0x10000; + return mode == RomMapMode.LoRom ? 0x8000 : 0x10000; } - public static Data.ROMSpeed GetRomSpeed(int offset, IReadOnlyList romBytes) => + public static RomSpeed GetRomSpeed(int offset, IReadOnlyList romBytes) => offset < romBytes.Count - ? (romBytes[offset] & 0x10) != 0 ? Data.ROMSpeed.FastROM : Data.ROMSpeed.SlowROM - : Data.ROMSpeed.Unknown; + ? (romBytes[offset] & 0x10) != 0 ? RomSpeed.FastRom : RomSpeed.SlowRom + : RomSpeed.Unknown; // verify the data in the provided ROM bytes matches the data we expect it to have. // returns error message if it's not identical, or null if everything is OK. public static string IsThisRomIsIdenticalToUs(byte[] rom, - Data.ROMMapMode mode, string requiredGameNameMatch, int requiredRomChecksumMatch) + RomMapMode mode, string requiredGameNameMatch, int requiredRomChecksumMatch) { var romSettingsOffset = GetRomSettingOffset(mode); if (rom.Length <= romSettingsOffset + 10) @@ -59,9 +87,9 @@ public static string GetRomTitleName(byte[] rom, int romSettingOffset) return internalGameNameToVerify; } - public static int ConvertSNESToPC(int address, Data.ROMMapMode mode, int size) + public static int ConvertSnesToPc(int address, RomMapMode mode, int size) { - int _UnmirroredOffset(int offset) => UnmirroredOffset(offset, size); + int UnmirroredOffset(int offset) => RomUtil.UnmirroredOffset(offset, size); // WRAM is N/A to PC addressing if ((address & 0xFE0000) == 0x7E0000) return -1; @@ -71,66 +99,66 @@ public static int ConvertSNESToPC(int address, Data.ROMMapMode mode, int size) switch (mode) { - case Data.ROMMapMode.LoROM: + case RomMapMode.LoRom: { // SRAM is N/A to PC addressing if (((address & 0x700000) == 0x700000) && ((address & 0x8000) == 0)) return -1; - return _UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); + return UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); } - case Data.ROMMapMode.HiROM: + case RomMapMode.HiRom: { - return _UnmirroredOffset(address & 0x3FFFFF); + return UnmirroredOffset(address & 0x3FFFFF); } - case Data.ROMMapMode.SuperMMC: + case RomMapMode.SuperMmc: { - return _UnmirroredOffset(address & 0x3FFFFF); // todo, treated as hirom atm + return UnmirroredOffset(address & 0x3FFFFF); // todo, treated as hirom atm } - case Data.ROMMapMode.SA1ROM: - case Data.ROMMapMode.ExSA1ROM: + case RomMapMode.Sa1Rom: + case RomMapMode.ExSa1Rom: { // BW-RAM is N/A to PC addressing if (address >= 0x400000 && address <= 0x7FFFFF) return -1; if (address >= 0xC00000) - return mode == Data.ROMMapMode.ExSA1ROM ? _UnmirroredOffset(address & 0x7FFFFF) : _UnmirroredOffset(address & 0x3FFFFF); + return mode == RomMapMode.ExSa1Rom ? UnmirroredOffset(address & 0x7FFFFF) : UnmirroredOffset(address & 0x3FFFFF); if (address >= 0x800000) address -= 0x400000; // SRAM is N/A to PC addressing if (((address & 0x8000) == 0)) return -1; - return _UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); + return UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); } - case Data.ROMMapMode.SuperFX: + case RomMapMode.SuperFx: { // BW-RAM is N/A to PC addressing if (address >= 0x600000 && address <= 0x7FFFFF) return -1; if (address < 0x400000) - return _UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); + return UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); if (address < 0x600000) - return _UnmirroredOffset(address & 0x3FFFFF); + return UnmirroredOffset(address & 0x3FFFFF); if (address < 0xC00000) - return 0x200000 + _UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); + return 0x200000 + UnmirroredOffset(((address & 0x7F0000) >> 1) | (address & 0x7FFF)); - return 0x400000 + _UnmirroredOffset(address & 0x3FFFFF); + return 0x400000 + UnmirroredOffset(address & 0x3FFFFF); } - case Data.ROMMapMode.ExHiROM: + case RomMapMode.ExHiRom: { - return _UnmirroredOffset(((~address & 0x800000) >> 1) | (address & 0x3FFFFF)); + return UnmirroredOffset(((~address & 0x800000) >> 1) | (address & 0x3FFFFF)); } - case Data.ROMMapMode.ExLoROM: + case RomMapMode.ExLoRom: { // SRAM is N/A to PC addressing if (((address & 0x700000) == 0x700000) && ((address & 0x8000) == 0)) return -1; - return _UnmirroredOffset((((address ^ 0x800000) & 0xFF0000) >> 1) | (address & 0x7FFF)); + return UnmirroredOffset((((address ^ 0x800000) & 0xFF0000) >> 1) | (address & 0x7FFF)); } default: { @@ -139,25 +167,25 @@ public static int ConvertSNESToPC(int address, Data.ROMMapMode mode, int size) } } - public static int ConvertPCtoSNES(int offset, Data.ROMMapMode romMapMode, Data.ROMSpeed romSpeed) + public static int ConvertPCtoSnes(int offset, RomMapMode romMapMode, RomSpeed romSpeed) { switch (romMapMode) { - case Data.ROMMapMode.LoROM: + case RomMapMode.LoRom: offset = ((offset & 0x3F8000) << 1) | 0x8000 | (offset & 0x7FFF); - if (romSpeed == Data.ROMSpeed.FastROM || offset >= 0x7E0000) offset |= 0x800000; + if (romSpeed == RomSpeed.FastRom || offset >= 0x7E0000) offset |= 0x800000; return offset; - case Data.ROMMapMode.HiROM: + case RomMapMode.HiRom: offset |= 0x400000; - if (romSpeed == Data.ROMSpeed.FastROM || offset >= 0x7E0000) offset |= 0x800000; + if (romSpeed == RomSpeed.FastRom || offset >= 0x7E0000) offset |= 0x800000; return offset; - case Data.ROMMapMode.ExHiROM when offset < 0x40000: + case RomMapMode.ExHiRom when offset < 0x40000: offset |= 0xC00000; return offset; - case Data.ROMMapMode.ExHiROM: + case RomMapMode.ExHiRom: if (offset >= 0x7E0000) offset &= 0x3FFFFF; return offset; - case Data.ROMMapMode.ExSA1ROM when offset >= 0x400000: + case RomMapMode.ExSa1Rom when offset >= 0x400000: offset += 0x800000; return offset; } @@ -239,39 +267,39 @@ public static int GetByteLengthForFlag(Data.FlagType flag) return 0; } - public static Data.ROMMapMode DetectROMMapMode(IReadOnlyList romBytes, out bool detectedValidRomMapType) + public static RomMapMode DetectRomMapMode(IReadOnlyList romBytes, out bool detectedValidRomMapType) { detectedValidRomMapType = true; - if ((romBytes[Data.LOROM_SETTING_OFFSET] & 0xEF) == 0x23) - return romBytes.Count > 0x400000 ? Data.ROMMapMode.ExSA1ROM : Data.ROMMapMode.SA1ROM; + if ((romBytes[Data.LoromSettingOffset] & 0xEF) == 0x23) + return romBytes.Count > 0x400000 ? RomMapMode.ExSa1Rom : RomMapMode.Sa1Rom; - if ((romBytes[Data.LOROM_SETTING_OFFSET] & 0xEC) == 0x20) - return (romBytes[Data.LOROM_SETTING_OFFSET + 1] & 0xF0) == 0x10 ? Data.ROMMapMode.SuperFX : Data.ROMMapMode.LoROM; + if ((romBytes[Data.LoromSettingOffset] & 0xEC) == 0x20) + return (romBytes[Data.LoromSettingOffset + 1] & 0xF0) == 0x10 ? RomMapMode.SuperFx : RomMapMode.LoRom; - if (romBytes.Count >= 0x10000 && (romBytes[Data.HIROM_SETTING_OFFSET] & 0xEF) == 0x21) - return Data.ROMMapMode.HiROM; + if (romBytes.Count >= 0x10000 && (romBytes[Data.HiromSettingOffset] & 0xEF) == 0x21) + return RomMapMode.HiRom; - if (romBytes.Count >= 0x10000 && (romBytes[Data.HIROM_SETTING_OFFSET] & 0xE7) == 0x22) - return Data.ROMMapMode.SuperMMC; + if (romBytes.Count >= 0x10000 && (romBytes[Data.HiromSettingOffset] & 0xE7) == 0x22) + return RomMapMode.SuperMmc; - if (romBytes.Count >= 0x410000 && (romBytes[Data.EXHIROM_SETTING_OFFSET] & 0xEF) == 0x25) - return Data.ROMMapMode.ExHiROM; + if (romBytes.Count >= 0x410000 && (romBytes[Data.ExhiromSettingOffset] & 0xEF) == 0x25) + return RomMapMode.ExHiRom; // detection failed. take our best guess..... detectedValidRomMapType = false; - return romBytes.Count > 0x40000 ? Data.ROMMapMode.ExLoROM : Data.ROMMapMode.LoROM; + return romBytes.Count > 0x40000 ? RomMapMode.ExLoRom : RomMapMode.LoRom; } - public static int GetRomSettingOffset(Data.ROMMapMode mode) + public static int GetRomSettingOffset(RomMapMode mode) { return mode switch { - Data.ROMMapMode.LoROM => Data.LOROM_SETTING_OFFSET, - Data.ROMMapMode.HiROM => Data.HIROM_SETTING_OFFSET, - Data.ROMMapMode.ExHiROM => Data.EXHIROM_SETTING_OFFSET, - Data.ROMMapMode.ExLoROM => Data.EXLOROM_SETTING_OFFSET, - _ => Data.LOROM_SETTING_OFFSET + RomMapMode.LoRom => Data.LoromSettingOffset, + RomMapMode.HiRom => Data.HiromSettingOffset, + RomMapMode.ExHiRom => Data.ExhiromSettingOffset, + RomMapMode.ExLoRom => Data.ExloromSettingOffset, + _ => Data.LoromSettingOffset }; } @@ -356,7 +384,7 @@ public static void GenerateHeaderFlags(int romSettingsOffset, IDictionary GenerateVectorLabels(Dictionary vectorNames, int romSettingsOffset, IReadOnlyList romBytes, Data.ROMMapMode mode) + public static Dictionary GenerateVectorLabels(Dictionary vectorNames, int romSettingsOffset, IReadOnlyList romBytes, RomMapMode mode) { // TODO: probably better to just use a data structure for this instead of generating the // offsets with table/entry vars @@ -378,9 +406,9 @@ public static Dictionary GenerateVectorLabels(Dictionary= 0 && pc < romBytes.Count && !labels.ContainsKey(offset)) - labels.Add(offset, new Label() { name = vectorEntry.Key }); + labels.Add(offset, new Label() { Name = vectorEntry.Key }); if (++entry < entryCount) continue; @@ -398,10 +426,10 @@ public static Dictionary GenerateVectorLabels(Dictionary dirtyRomBytes = new Dictionary(); + private readonly Dictionary dirtyRomBytes = new Dictionary(); private void RomBytes_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) @@ -117,7 +117,7 @@ private bool OffsetInRange(int offset) private void RomBytes_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { - if (!(sender is ROMByte romByte)) + if (!(sender is RomByte romByte)) return; if (e.PropertyName != "TypeFlag") @@ -178,7 +178,7 @@ private void RegenerateImage() // blank pixels while (currentPixel < w*h) { - var (x, y) = ConvertPixelIndexToXY(currentPixel); + var (x, y) = ConvertPixelIndexToXy(currentPixel); fastBitmap.SetPixel(x, y, Color.SlateGray); ++currentPixel; } @@ -191,33 +191,33 @@ private void RegenerateImage() // returns the RomBytes we should use to update our image // this can either be ALL RomBytes, or, a small set of dirty RomBytes that were changed // since our last redraw. - private IEnumerable ConsumeRomDirtyBytes() + private IEnumerable ConsumeRomDirtyBytes() { if (AllDirty) return Data.RomBytes.ToList(); - IEnumerable romBytes; + IEnumerable romBytes; lock (dirtyLock) { // make a copy so we can release the lock. - romBytes = new List(dirtyRomBytes.Values.Select(kvp => kvp)); + romBytes = new List(dirtyRomBytes.Values.Select(kvp => kvp)); dirtyRomBytes.Clear(); } return romBytes; } - private (int x, int y) ConvertPixelIndexToXY(int offset) + private (int x, int y) ConvertPixelIndexToXy(int offset) { var y = offset / Width; var x = offset - (y * Width); return (x, y); } - private void SetPixel(ROMByte romByte, FastBitmap fastBitmap) + private void SetPixel(RomByte romByte, FastBitmap fastBitmap) { var pixelIndex = ConvertRomOffsetToPixelIndex(romByte.Offset); - var (x, y) = ConvertPixelIndexToXY(pixelIndex); + var (x, y) = ConvertPixelIndexToXy(pixelIndex); var color = Util.GetColorFromFlag(romByte.TypeFlag); fastBitmap.SetPixel(x, y, color); } @@ -232,7 +232,7 @@ protected virtual void OnBitmapUpdated() ImageDataUpdated?.Invoke(this, EventArgs.Empty); } - protected virtual void MarkDirty(ROMByte romByte) + protected virtual void MarkDirty(RomByte romByte) { lock (dirtyLock) { diff --git a/Diz.Core/util/Util.cs b/Diz.Core/util/Util.cs index 72ed99a6..3292b746 100644 --- a/Diz.Core/util/Util.cs +++ b/Diz.Core/util/Util.cs @@ -168,16 +168,16 @@ public static List> GetEnumInfo(Func CachedROMFlagColors = + private static readonly Dictionary CachedRomFlagColors = new Dictionary(); public static Color GetColorFromFlag(Data.FlagType romFlag) { - if (CachedROMFlagColors.TryGetValue(romFlag, out var color)) + if (CachedRomFlagColors.TryGetValue(romFlag, out var color)) return color; color = Color.FromKnownColor(GetEnumColor(romFlag)); // slow (comparatively) - CachedROMFlagColors[romFlag] = color; + CachedRomFlagColors[romFlag] = color; return color; } diff --git a/Diz.Test/LogCreator.cs b/Diz.Test/LogCreator.cs index 4062cd48..8b2eb145 100644 --- a/Diz.Test/LogCreator.cs +++ b/Diz.Test/LogCreator.cs @@ -3,6 +3,7 @@ using System.Linq; using Diz.Core.export; using Diz.Core.model; +using Diz.Core.util; using IX.Observable; using Xunit; @@ -14,7 +15,7 @@ public class ParsedOutput { protected bool Equals(ParsedOutput other) { - return label == other.label && instr == other.instr && pc == other.pc && rawbytes == other.rawbytes && ia == other.ia && realcomment == other.realcomment; + return Label == other.Label && Instr == other.Instr && Pc == other.Pc && Rawbytes == other.Rawbytes && Ia == other.Ia && Realcomment == other.Realcomment; } public override bool Equals(object obj) @@ -29,24 +30,24 @@ public override int GetHashCode() { unchecked { - var hashCode = label.GetHashCode(); - hashCode = (hashCode * 397) ^ instr.GetHashCode(); - hashCode = (hashCode * 397) ^ pc.GetHashCode(); - hashCode = (hashCode * 397) ^ rawbytes.GetHashCode(); - hashCode = (hashCode * 397) ^ ia.GetHashCode(); - hashCode = (hashCode * 397) ^ realcomment.GetHashCode(); + var hashCode = Label.GetHashCode(); + hashCode = (hashCode * 397) ^ Instr.GetHashCode(); + hashCode = (hashCode * 397) ^ Pc.GetHashCode(); + hashCode = (hashCode * 397) ^ Rawbytes.GetHashCode(); + hashCode = (hashCode * 397) ^ Ia.GetHashCode(); + hashCode = (hashCode * 397) ^ Realcomment.GetHashCode(); return hashCode; } } - public string label; - public string instr; + public string Label; + public string Instr; - public string pc; - public string rawbytes; - public string ia; + public string Pc; + public string Rawbytes; + public string Ia; - public string realcomment; + public string Realcomment; } public static ParsedOutput ParseLine(string line) @@ -61,12 +62,12 @@ public static ParsedOutput ParseLine(string line) var comment = split[1].Trim(); var csplit = comment.Split(new[] { '|' }, 3, options: StringSplitOptions.None); - output.pc = csplit[0].Trim(); - output.rawbytes = csplit[1].Trim(); + output.Pc = csplit[0].Trim(); + output.Rawbytes = csplit[1].Trim(); var iasplit = csplit[2].Split(new[] { ';' }, 2, options: StringSplitOptions.None); - output.ia = iasplit[0].Trim(); - output.realcomment = iasplit[1].Trim(); + output.Ia = iasplit[0].Trim(); + output.Realcomment = iasplit[1].Trim(); var msplit = main.Split(new[] { ':' }, 2, options: StringSplitOptions.None); var m1 = msplit[0].Trim(); @@ -74,13 +75,13 @@ public static ParsedOutput ParseLine(string line) if (m2 != "") { - output.label = m1; - output.instr = m2; + output.Label = m1; + output.Instr = m2; } else { - output.label = ""; - output.instr = m1; + output.Label = ""; + output.Instr = m1; } return output; @@ -114,12 +115,12 @@ public void TestAFewLines() { Labels = new ObservableDictionary { - {0x808000 + 0x06, new Label {name = "Test22"}}, - {0x808000 + 0x5B, new Label {name = "Test_Data", comment = "Pretty cool huh?"}}, + {0x808000 + 0x06, new Label {Name = "Test22"}}, + {0x808000 + 0x5B, new Label {Name = "Test_Data", Comment = "Pretty cool huh?"}}, // the CODE_XXXXXX labels are autogenerated }, - RomMapMode = Data.ROMMapMode.LoROM, - RomSpeed = Data.ROMSpeed.FastROM, + RomMapMode = RomMapMode.LoRom, + RomSpeed = RomSpeed.FastRom, RomBytes = { // -------------------------- @@ -127,21 +128,21 @@ public void TestAFewLines() // we will use this for unit tests as well. // CODE_808000: LDA.W Test_Data,X - new ROMByte {Rom = 0xBD, TypeFlag = Data.FlagType.Opcode, MFlag = true, Point = Data.InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x5B, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, // Test_Data - new ROMByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, // Test_Data + new RomByte {Rom = 0xBD, TypeFlag = Data.FlagType.Opcode, MFlag = true, Point = Data.InOutPoint.InPoint, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x5B, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, // Test_Data + new RomByte {Rom = 0x80, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, // Test_Data // STA.W $0100,X - new ROMByte {Rom = 0x9D, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0x01, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x9D, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x00, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x01, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, // DEX - new ROMByte {Rom = 0xCA, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xCA, TypeFlag = Data.FlagType.Opcode, MFlag = true, DataBank = 0x80, DirectPage = 0x2100}, // BPL CODE_808000 - new ROMByte {Rom = 0x10, TypeFlag = Data.FlagType.Opcode, MFlag = true, Point = Data.InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, - new ROMByte {Rom = 0xF7, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0x10, TypeFlag = Data.FlagType.Opcode, MFlag = true, Point = Data.InOutPoint.OutPoint, DataBank = 0x80, DirectPage = 0x2100}, + new RomByte {Rom = 0xF7, TypeFlag = Data.FlagType.Operand, DataBank = 0x80, DirectPage = 0x2100}, // ------------------------------------ } @@ -149,8 +150,8 @@ public void TestAFewLines() var settings = new LogWriterSettings(); settings.SetDefaults(); - settings.outputToString = true; - settings.structure = LogCreator.FormatStructure.SingleFile; + settings.OutputToString = true; + settings.Structure = LogCreator.FormatStructure.SingleFile; var lc = new LogCreator() { @@ -160,11 +161,11 @@ public void TestAFewLines() var result = lc.CreateLog(); - Assert.True(result.logCreator != null); - Assert.True(result.outputStr != null); - Assert.True(result.error_count == 0); + Assert.True(result.LogCreator != null); + Assert.True(result.OutputStr != null); + Assert.True(result.ErrorCount == 0); - var actualOut = ParseAll(result.outputStr); + var actualOut = ParseAll(result.OutputStr); Assert.Equal(expectedOut.Count, actualOut.Count); diff --git a/Diz.Test/RomByteTests.cs b/Diz.Test/RomByteTests.cs index 7b0674a4..65ab97c3 100644 --- a/Diz.Test/RomByteTests.cs +++ b/Diz.Test/RomByteTests.cs @@ -5,10 +5,10 @@ namespace Diz.Test { public sealed class RomByteTests { - private static ROMByte SampleRomByte1() + private static RomByte SampleRomByte1() { - return new ROMByte() { - Arch = Data.Architecture.APUSPC700, + return new RomByte() { + Arch = Data.Architecture.Apuspc700, DataBank = 90, DirectPage = 3, MFlag = true, @@ -19,7 +19,7 @@ private static ROMByte SampleRomByte1() }; } - private static ROMByte SampleRomByte2() + private static RomByte SampleRomByte2() { // same as above, but just change .Rom var rb = SampleRomByte1(); diff --git a/Diz.Test/SerializerDictionaryTest.cs b/Diz.Test/SerializerDictionaryTest.cs index a7a09881..7375b6d4 100644 --- a/Diz.Test/SerializerDictionaryTest.cs +++ b/Diz.Test/SerializerDictionaryTest.cs @@ -20,21 +20,21 @@ public SerializerDictionaryTest(ITestOutputHelper testOutputHelper) public class TestRoot { - public ObservableDictionary ODW { get; set; } = new ObservableDictionary() { + public ObservableDictionary Odw { get; set; } = new ObservableDictionary() { {1, "Z test1"}, {2, "Z test3"}, }; - public ObservableDictionary ODW2 { get; set; } = new ObservableDictionary() { - {100, new Label {comment = "c1", name = "location1"}}, - {200, new Label {comment = "c2", name = "location2"}}, + public ObservableDictionary Odw2 { get; set; } = new ObservableDictionary() { + {100, new Label {Comment = "c1", Name = "location1"}}, + {200, new Label {Comment = "c2", Name = "location2"}}, }; #region Equality protected bool Equals(TestRoot other) { return - System.Linq.Enumerable.SequenceEqual(ODW, other.ODW) && - System.Linq.Enumerable.SequenceEqual(ODW2, other.ODW2); + System.Linq.Enumerable.SequenceEqual(Odw, other.Odw) && + System.Linq.Enumerable.SequenceEqual(Odw2, other.Odw2); } public override bool Equals(object obj) @@ -49,7 +49,7 @@ public override int GetHashCode() { unchecked { - return ((ODW != null ? ODW.GetHashCode() : 0) * 397) ^ (ODW2 != null ? ODW2.GetHashCode() : 0); + return ((Odw != null ? Odw.GetHashCode() : 0) * 397) ^ (Odw2 != null ? Odw2.GetHashCode() : 0); } } #endregion @@ -86,6 +86,6 @@ private void DeSerialize() private readonly TestRoot testRootElementGood = new TestRoot(); - string xmlShouldBe = ""; + string xmlShouldBe = ""; } } \ No newline at end of file diff --git a/DiztinGUIsh/controller/ProjectController.cs b/DiztinGUIsh/controller/ProjectController.cs index fc2a60b6..6cc91fa2 100644 --- a/DiztinGUIsh/controller/ProjectController.cs +++ b/DiztinGUIsh/controller/ProjectController.cs @@ -133,7 +133,7 @@ public void SaveProject(string filename) ProjectView.OnProjectSaved(); } - public void ImportBizHawkCDL(string filename) + public void ImportBizHawkCdl(string filename) { BizHawkCdlImporter.Import(filename, Project.Data); @@ -145,12 +145,12 @@ public void ImportBizHawkCDL(string filename) }); } - public bool ImportRomAndCreateNewProject(string ROMFilename) + public bool ImportRomAndCreateNewProject(string romFilename) { // let the user select settings on the GUI - var importController = new ImportROMDialogController {View = ProjectView.GetImportView()}; + var importController = new ImportRomDialogController {View = ProjectView.GetImportView()}; importController.View.Controller = importController; - var importSettings = importController.PromptUserForRomSettings(ROMFilename); + var importSettings = importController.PromptUserForRomSettings(romFilename); if (importSettings == null) return false; @@ -207,9 +207,9 @@ public void SelectOffset(int offset, int column = -1) ProjectView.SelectOffset(offset, column); } - public long ImportBSNESUsageMap(string fileName) + public long ImportBsnesUsageMap(string fileName) { - var importer = new BSNESUsageMapImporter(); + var importer = new BsnesUsageMapImporter(); var linesModified = importer.ImportUsageMap(File.ReadAllBytes(fileName), Project.Data); @@ -219,9 +219,9 @@ public long ImportBSNESUsageMap(string fileName) return linesModified; } - public long ImportBSNESTraceLogs(string[] fileNames) + public long ImportBsnesTraceLogs(string[] fileNames) { - var importer = new BSNESTraceLogImporter(Project.Data); + var importer = new BsnesTraceLogImporter(Project.Data); // caution: trace logs can be gigantic, even a few seconds can be > 1GB // inside here, performance becomes critical. @@ -231,15 +231,15 @@ public long ImportBSNESTraceLogs(string[] fileNames) importer.ImportTraceLogLine(line); }); - if (importer.CurrentStats.numRomBytesModified > 0) + if (importer.CurrentStats.NumRomBytesModified > 0) MarkChanged(); - return importer.CurrentStats.numRomBytesModified; + return importer.CurrentStats.NumRomBytesModified; } public long ImportBsnesTraceLogsBinary(string[] filenames) { - var importer = new BSNESTraceLogImporter(Project.Data); + var importer = new BsnesTraceLogImporter(Project.Data); foreach (var file in filenames) { @@ -254,7 +254,7 @@ public long ImportBsnesTraceLogsBinary(string[] filenames) } } - return importer.CurrentStats.numRomBytesModified; + return importer.CurrentStats.NumRomBytesModified; } } } diff --git a/DiztinGUIsh/util/ProgressBarWorker.cs b/DiztinGUIsh/util/ProgressBarWorker.cs index e35f416d..b9bfc757 100644 --- a/DiztinGUIsh/util/ProgressBarWorker.cs +++ b/DiztinGUIsh/util/ProgressBarWorker.cs @@ -7,8 +7,8 @@ namespace DiztinGUIsh // TODO: use https://www.wpf-tutorial.com/misc/multi-threading-with-the-backgroundworker/ backgroundworker public abstract class ProgressBarWorker { - private ProgressDialog Dialog; - private bool IsRunning; + private ProgressDialog dialog; + private bool isRunning; private Thread backgroundThread; public bool IsMarquee { get; set; } public string TextOverride { get; set; } @@ -16,7 +16,7 @@ public abstract class ProgressBarWorker protected void UpdateProgress(int i) { // i must be in range of 0 to 100 - Dialog.UpdateProgress(i); + dialog.UpdateProgress(i); } protected abstract void Thread_DoWork(); @@ -36,13 +36,13 @@ public void Run() protected virtual void Setup() { - if (IsRunning) + if (isRunning) throw new InvalidOperationException( "Progress bar already running, existing job must finish first"); - IsRunning = true; + isRunning = true; - Dialog = new ProgressDialog(IsMarquee, TextOverride); + dialog = new ProgressDialog(IsMarquee, TextOverride); // setup, but don't start, the new thread backgroundThread = new Thread(Thread_Main); @@ -55,7 +55,7 @@ protected virtual void Setup() private void WaitForJobToFinish() { // blocks til worker thread closes this dialog box - Dialog.ShowDialog(); + dialog.ShowDialog(); } // called from a new worker thread @@ -65,14 +65,14 @@ private void Thread_Main() { // BAD APPROACH. we should instead get an event // I'm too lazy right now. TODO FIXME - while (!Dialog.Visible) + while (!dialog.Visible) Thread.Sleep(50); Thread_DoWork(); } finally { - IsRunning = false; + isRunning = false; SignalJobIsDone(); } } @@ -80,7 +80,7 @@ private void Thread_Main() private void SignalJobIsDone() { // unblock the main thread from ShowDialog() - Dialog?.BeginInvoke(new Action(() => Dialog.Close())); + dialog?.BeginInvoke(new Action(() => dialog.Close())); } } } diff --git a/DiztinGUIsh/window/AliasList.cs b/DiztinGUIsh/window/AliasList.cs index dd3bce5f..d73e27e7 100644 --- a/DiztinGUIsh/window/AliasList.cs +++ b/DiztinGUIsh/window/AliasList.cs @@ -20,7 +20,7 @@ public partial class AliasList : Form private ProjectController ProjectController => parentWindow?.ProjectController; private Data Data => ProjectController?.Project?.Data; - public bool locked; + public bool Locked; private int currentlyEditing = -1; public AliasList(MainWindow main) @@ -47,7 +47,7 @@ private void jump_Click(object sender, EventArgs e) if (!int.TryParse((string) dataGridView1.SelectedRows[0].Cells[0].Value, NumberStyles.HexNumber, null, out var val)) return; - var offset = Data.ConvertSNEStoPC(val); + var offset = Data.ConvertSnesToPc(val); if (offset >= 0) { ProjectController.SelectOffset(offset); @@ -90,13 +90,13 @@ private void ImportLabelsFromCsv(bool replaceAll) errLine = i + 1; SplitOnFirstComma(lines[i], out var labelAddress, out var remainder); - SplitOnFirstComma(remainder, out label.name, out label.comment); + SplitOnFirstComma(remainder, out label.Name, out label.Comment); label.CleanUp(); - label.name = label.name.Trim(); - if (!validLabelChars.Match(label.name).Success) - throw new InvalidDataException("invalid label name: " + label.name); + label.Name = label.Name.Trim(); + if (!validLabelChars.Match(label.Name).Success) + throw new InvalidDataException("invalid label name: " + label.Name); newValues.Add(int.Parse(labelAddress, NumberStyles.HexNumber, null), label); } @@ -133,7 +133,7 @@ private void export_Click(object sender, EventArgs e) foreach (var pair in Data.Labels) { sw.WriteLine( - $"{Util.NumberToBaseString(pair.Key, Util.NumberBase.Hexadecimal, 6)},{pair.Value.name},{pair.Value.comment}"); + $"{Util.NumberToBaseString(pair.Key, Util.NumberBase.Hexadecimal, 6)},{pair.Value.Name},{pair.Value.Comment}"); } } catch (Exception) { @@ -145,9 +145,9 @@ private void dataGridView1_UserDeletingRow(object sender, DataGridViewRowCancelE { if (!int.TryParse((string) dataGridView1.Rows[e.Row.Index].Cells[0].Value, NumberStyles.HexNumber, null, out var val)) return; - locked = true; + Locked = true; Data.AddLabel(val, null, true); - locked = false; + Locked = false; parentWindow.InvalidateTable(); // TODO: move to mainwindow, use notifychanged in mainwindow for this } @@ -170,8 +170,8 @@ private void dataGridView1_CellValidating(object sender, DataGridViewCellValidat var labelLabel = new Label { - name = (string) dataGridView1.Rows[e.RowIndex].Cells[1].Value, - comment = (string)dataGridView1.Rows[e.RowIndex].Cells[2].Value, + Name = (string) dataGridView1.Rows[e.RowIndex].Cells[1].Value, + Comment = (string)dataGridView1.Rows[e.RowIndex].Cells[2].Value, }; toolStripStatusLabel1.Text = ""; @@ -199,26 +199,26 @@ private void dataGridView1_CellValidating(object sender, DataGridViewCellValidat case 1: { val = oldAddress; - labelLabel.name = e.FormattedValue.ToString(); + labelLabel.Name = e.FormattedValue.ToString(); // todo (validate for valid label characters) break; } case 2: { val = oldAddress; - labelLabel.comment = e.FormattedValue.ToString(); + labelLabel.Comment = e.FormattedValue.ToString(); // todo (validate for valid comment characters, if any) break; } } - locked = true; + Locked = true; if (currentlyEditing >= 0) { if (val >= 0) Data.AddLabel(oldAddress, null, true); Data.AddLabel(val, labelLabel, true); } - locked = false; + Locked = false; currentlyEditing = -1; parentWindow.InvalidateTable(); // TODO: move to mainwindow, use notifychanged in mainwindow for this @@ -226,7 +226,7 @@ private void dataGridView1_CellValidating(object sender, DataGridViewCellValidat public void AddRow(int address, Label alias) { - if (locked) + if (Locked) return; RawAdd(address, alias); dataGridView1.Invalidate(); @@ -234,12 +234,12 @@ public void AddRow(int address, Label alias) private void RawAdd(int address, Label alias) { - dataGridView1.Rows.Add(Util.NumberToBaseString(address, Util.NumberBase.Hexadecimal, 6), alias.name, alias.comment); + dataGridView1.Rows.Add(Util.NumberToBaseString(address, Util.NumberBase.Hexadecimal, 6), alias.Name, alias.Comment); } public void RemoveRow(int address) { - if (locked) + if (Locked) return; for (var index = 0; index < dataGridView1.Rows.Count; index++) diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index de02ecca..046c6b1e 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -47,7 +47,7 @@ private void ProjectController_ProjectChanged(object sender, ProjectController.P private void RebindProject() { - aliasList.RebindProject(); + AliasList.RebindProject(); } private void MainWindow_FormClosing(object sender, FormClosingEventArgs e) @@ -90,10 +90,10 @@ private void MainWindow_Load(object sender, EventArgs e) table, new object[] { true }); - aliasList = new AliasList(this); + AliasList = new AliasList(this); UpdatePanels(); - UpdateUIFromSettings(); + UpdateUiFromSettings(); if (Settings.Default.OpenLastFileAutomatically) OpenLastProject(); @@ -179,11 +179,11 @@ public string LastProjectFilename Settings.Default.LastOpenedFile = value; Settings.Default.Save(); - UpdateUIFromSettings(); + UpdateUiFromSettings(); } } - private void UpdateUIFromSettings() + private void UpdateUiFromSettings() { var lastOpenedFilePresent = Settings.Default.LastOpenedFile != ""; toolStripOpenLast.Enabled = lastOpenedFilePresent; @@ -202,7 +202,7 @@ public void OnProjectOpened(string filename) // TODO: do this with aliaslist too. UpdateSaveOptionStates(true, true); - RefreshUI(); + RefreshUi(); LastProjectFilename = filename; // do this last. } @@ -210,10 +210,10 @@ public void OnProjectOpened(string filename) private void OnImportedProjectSuccess() { UpdateSaveOptionStates(false, true); - RefreshUI(); + RefreshUi(); } - private void RefreshUI() + private void RefreshUi() { importCDLToolStripMenuItem.Enabled = true; UpdateWindowTitle(); @@ -252,7 +252,7 @@ public void OnProjectSaved() public void OnExportFinished(LogCreator.OutputResult result) { - if (result.error_count > 0) + if (result.ErrorCount > 0) MessageBox.Show("Disassembly created with errors. See errors.txt for details.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); else @@ -329,9 +329,9 @@ private void exitToolStripMenuItem_Click(object sender, EventArgs e) Application.Exit(); } - private Util.NumberBase DisplayBase = Util.NumberBase.Hexadecimal; + private Util.NumberBase displayBase = Util.NumberBase.Hexadecimal; private Data.FlagType markFlag = Data.FlagType.Data8Bit; - private bool MoveWithStep = true; + private bool moveWithStep = true; private void decimalToolStripMenuItem_Click(object sender, EventArgs e) { @@ -350,7 +350,7 @@ private void binaryToolStripMenuItem_Click(object sender, EventArgs e) private void UpdateBase(Util.NumberBase noBase) { - DisplayBase = noBase; + displayBase = noBase; decimalToolStripMenuItem.Checked = noBase == Util.NumberBase.Decimal; hexadecimalToolStripMenuItem.Checked = noBase == Util.NumberBase.Hexadecimal; binaryToolStripMenuItem.Checked = noBase == Util.NumberBase.Binary; @@ -359,10 +359,10 @@ private void UpdateBase(Util.NumberBase noBase) public void UpdatePercent() { - if (Project?.Data == null || Project.Data.GetROMSize() <= 0) + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; - int totalUnreached = 0, size = Project.Data.GetROMSize(); + int totalUnreached = 0, size = Project.Data.GetRomSize(); for (int i = 0; i < size; i++) if (Project.Data.GetFlag(i) == Data.FlagType.Unreached) totalUnreached++; @@ -401,19 +401,19 @@ private int ViewOffset private void UpdateDataGridView() { - if (Project?.Data == null || Project.Data.GetROMSize() <= 0) + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; rowsToShow = ((table.Height - table.ColumnHeadersHeight) / table.RowTemplate.Height); - if (ViewOffset + rowsToShow > Project.Data.GetROMSize()) - ViewOffset = Project.Data.GetROMSize() - rowsToShow; + if (ViewOffset + rowsToShow > Project.Data.GetRomSize()) + ViewOffset = Project.Data.GetRomSize() - rowsToShow; if (ViewOffset < 0) ViewOffset = 0; vScrollBar1.Enabled = true; - vScrollBar1.Maximum = Project.Data.GetROMSize() - rowsToShow; + vScrollBar1.Maximum = Project.Data.GetRomSize() - rowsToShow; vScrollBar1.Value = ViewOffset; table.RowCount = rowsToShow; @@ -431,7 +431,7 @@ private void UpdateImporterEnabledStatus() private void table_MouseWheel(object sender, MouseEventArgs e) { - if (Project?.Data == null || Project.Data.GetROMSize() <= 0) + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; int selRow = table.CurrentCell.RowIndex + ViewOffset, selCol = table.CurrentCell.ColumnIndex; var amount = e.Delta / 0x18; @@ -467,7 +467,7 @@ private void table_MouseDown(object sender, MouseEventArgs e) private void table_KeyDown(object sender, KeyEventArgs e) { - if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; int offset = table.CurrentCell.RowIndex + ViewOffset; int newOffset = offset; @@ -489,7 +489,7 @@ private void table_KeyDown(object sender, KeyEventArgs e) case Keys.Down: amount = e.KeyCode == Keys.Down ? 0x01 : e.KeyCode == Keys.PageDown ? 0x10 : 0x100; newOffset = offset + amount; - if (newOffset >= Project.Data.GetROMSize()) newOffset = Project.Data.GetROMSize() - 1; + if (newOffset >= Project.Data.GetRomSize()) newOffset = Project.Data.GetRomSize() - 1; SelectOffset(newOffset); break; case Keys.Left: @@ -557,27 +557,27 @@ private void table_KeyDown(object sender, KeyEventArgs e) private void table_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) { int row = e.RowIndex + ViewOffset; - if (row >= Project.Data.GetROMSize()) return; + if (row >= Project.Data.GetRomSize()) return; switch (e.ColumnIndex) { case 0: - e.Value = Project.Data.GetLabelName(Project.Data.ConvertPCtoSNES(row)); + e.Value = Project.Data.GetLabelName(Project.Data.ConvertPCtoSnes(row)); break; case 1: - e.Value = Util.NumberToBaseString(Project.Data.ConvertPCtoSNES(row), Util.NumberBase.Hexadecimal, 6); + e.Value = Util.NumberToBaseString(Project.Data.ConvertPCtoSnes(row), Util.NumberBase.Hexadecimal, 6); break; case 2: - e.Value = (char) Project.Data.GetROMByte(row); + e.Value = (char) Project.Data.GetRomByte(row); break; case 3: - e.Value = Util.NumberToBaseString(Project.Data.GetROMByte(row), DisplayBase); + e.Value = Util.NumberToBaseString(Project.Data.GetRomByte(row), displayBase); break; case 4: e.Value = RomUtil.PointToString(Project.Data.GetInOutPoint(row)); break; case 5: var len = Project.Data.GetInstructionLength(row); - e.Value = row + len <= Project.Data.GetROMSize() ? Project.Data.GetInstruction(row) : ""; + e.Value = row + len <= Project.Data.GetRomSize() ? Project.Data.GetInstruction(row) : ""; break; case 6: var ia = Project.Data.GetIntermediateAddressOrPointer(row); @@ -599,7 +599,7 @@ private void table_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e.Value = RomUtil.BoolToSize(Project.Data.GetXFlag(row)); break; case 12: - e.Value = Project.Data.GetComment(Project.Data.ConvertPCtoSNES(row)); + e.Value = Project.Data.GetComment(Project.Data.ConvertPCtoSnes(row)); break; } } @@ -609,11 +609,11 @@ private void table_CellValuePushed(object sender, DataGridViewCellValueEventArgs string value = e.Value as string; int result; int row = e.RowIndex + ViewOffset; - if (row >= Project.Data.GetROMSize()) return; + if (row >= Project.Data.GetRomSize()) return; switch (e.ColumnIndex) { case 0: - Project.Data.AddLabel(Project.Data.ConvertPCtoSNES(row), new Label() {name = value}, true); + Project.Data.AddLabel(Project.Data.ConvertPCtoSnes(row), new Label() {Name = value}, true); break; // todo (validate for valid label characters) case 8: if (int.TryParse(value, NumberStyles.HexNumber, null, out result)) Project.Data.SetDataBank(row, result); @@ -628,7 +628,7 @@ private void table_CellValuePushed(object sender, DataGridViewCellValueEventArgs Project.Data.SetXFlag(row, (value == "8" || value == "X")); break; case 12: - Project.Data.AddComment(Project.Data.ConvertPCtoSNES(row), value, true); + Project.Data.AddComment(Project.Data.ConvertPCtoSnes(row), value, true); break; } @@ -647,7 +647,7 @@ public void PaintCell(int offset, DataGridViewCellStyle style, int column, int s style.ForeColor = Color.DarkSlateGray; break; case Data.FlagType.Opcode: - int opcode = Project.Data.GetROMByte(offset); + int opcode = Project.Data.GetRomByte(offset); switch (column) { case 4: // <*> @@ -679,7 +679,7 @@ public void PaintCell(int offset, DataGridViewCellStyle style, int column, int s case 11: // X Flag int mask = column == 10 ? 0x20 : 0x10; if (opcode == 0x28 || ((opcode == 0xC2 || opcode == 0xE2) // PLP SEP REP - && (Project.Data.GetROMByte(offset + 1) & mask) != 0)) // relevant bit set + && (Project.Data.GetRomByte(offset + 1) & mask) != 0)) // relevant bit set style.BackColor = Color.OrangeRed; if (opcode == 0x08) // PHP style.BackColor = Color.Yellow; @@ -715,16 +715,16 @@ public void PaintCell(int offset, DataGridViewCellStyle style, int column, int s break; } - if (selOffset >= 0 && selOffset < Project.Data.GetROMSize()) + if (selOffset >= 0 && selOffset < Project.Data.GetRomSize()) { if (column == 1 //&& (Project.Data.GetFlag(selOffset) == Data.FlagType.Opcode || Project.Data.GetFlag(selOffset) == Data.FlagType.Unreached) - && Project.Data.ConvertSNEStoPC(Project.Data.GetIntermediateAddressOrPointer(selOffset)) == offset + && Project.Data.ConvertSnesToPc(Project.Data.GetIntermediateAddressOrPointer(selOffset)) == offset ) style.BackColor = Color.DeepPink; if (column == 6 //&& (Project.Data.GetFlag(offset) == Data.FlagType.Opcode || Project.Data.GetFlag(offset) == Data.FlagType.Unreached) - && Project.Data.ConvertSNEStoPC(Project.Data.GetIntermediateAddressOrPointer(offset)) == selOffset + && Project.Data.ConvertSnesToPc(Project.Data.GetIntermediateAddressOrPointer(offset)) == selOffset ) style.BackColor = Color.DeepPink; } } @@ -732,7 +732,7 @@ public void PaintCell(int offset, DataGridViewCellStyle style, int column, int s private void table_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) { int row = e.RowIndex + ViewOffset; - if (row < 0 || row >= Project.Data.GetROMSize()) return; + if (row < 0 || row >= Project.Data.GetRomSize()) return; PaintCell(row, e.CellStyle, e.ColumnIndex, table.CurrentCell.RowIndex + ViewOffset); } @@ -777,7 +777,7 @@ private void AutoStepSafe(int offset) { ProjectController.MarkChanged(); var destination = Project.Data.AutoStep(offset, false, 0); - if (MoveWithStep) + if (moveWithStep) SelectOffset(destination); UpdatePercent(); UpdateWindowTitle(); @@ -791,7 +791,7 @@ private void AutoStepHarsh(int offset) { ProjectController.MarkChanged(); int destination = Project.Data.AutoStep(harsh.GetOffset(), true, harsh.GetCount()); - if (MoveWithStep) SelectOffset(destination); + if (moveWithStep) SelectOffset(destination); UpdatePercent(); UpdateWindowTitle(); } @@ -839,7 +839,7 @@ private void MarkMany(int offset, int column) break; } - if (MoveWithStep) + if (moveWithStep) SelectOffset(destination); UpdatePercent(); @@ -853,7 +853,7 @@ private void GoToIntermediateAddress(int offset) if (ia < 0) return; - var pc = Project.Data.ConvertSNEStoPC(ia); + var pc = Project.Data.ConvertSnesToPc(ia); if (pc < 0) return; @@ -863,7 +863,7 @@ private void GoToIntermediateAddress(int offset) private void GoToUnreached(bool end, bool direction) { int offset = table.CurrentCell.RowIndex + ViewOffset; - int size = Project.Data.GetROMSize(); + int size = Project.Data.GetRomSize(); int unreached = end ? (direction ? 0 : size - 1) : offset; if (direction) @@ -898,31 +898,31 @@ private void graphicsWindowToolStripMenuItem_Click(object sender, EventArgs e) private void stepOverToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; Step(table.CurrentCell.RowIndex + ViewOffset); } private void stepInToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; StepIn(table.CurrentCell.RowIndex + ViewOffset); } private void autoStepSafeToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; AutoStepSafe(table.CurrentCell.RowIndex + ViewOffset); } private void autoStepHarshToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; AutoStepHarsh(table.CurrentCell.RowIndex + ViewOffset); } private void gotoToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project?.Data == null || Project.Data.GetROMSize() <= 0) + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; var go = new GotoDialog(ViewOffset + table.CurrentCell.RowIndex, Project.Data); @@ -931,7 +931,7 @@ private void gotoToolStripMenuItem_Click(object sender, EventArgs e) return; var offset = go.GetPcOffset(); - if (offset >= 0 && offset < Project.Data.GetROMSize()) + if (offset >= 0 && offset < Project.Data.GetRomSize()) SelectOffset(offset); else MessageBox.Show("That offset is out of range.", "Error", MessageBoxButtons.OK, @@ -940,7 +940,7 @@ private void gotoToolStripMenuItem_Click(object sender, EventArgs e) private void gotoIntermediateAddressToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; GoToIntermediateAddress(table.CurrentCell.RowIndex + ViewOffset); } @@ -961,13 +961,13 @@ private void gotoNextUnreachedToolStripMenuItem_Click(object sender, EventArgs e private void markOneToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; Mark(table.CurrentCell.RowIndex + ViewOffset); } private void markManyToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; MarkMany(table.CurrentCell.RowIndex + ViewOffset, 7); } @@ -979,25 +979,25 @@ private void addLabelToolStripMenuItem_Click(object sender, EventArgs e) private void setDataBankToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; MarkMany(table.CurrentCell.RowIndex + ViewOffset, 8); } private void setDirectPageToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; MarkMany(table.CurrentCell.RowIndex + ViewOffset, 9); } private void toggleAccumulatorSizeMToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; MarkMany(table.CurrentCell.RowIndex + ViewOffset, 10); } private void toggleIndexSizeToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project?.Data == null || Project.Data.GetROMSize() <= 0) return; + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; MarkMany(table.CurrentCell.RowIndex + ViewOffset, 11); } @@ -1009,7 +1009,7 @@ private void addCommentToolStripMenuItem_Click(object sender, EventArgs e) private void fixMisalignedInstructionsToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project?.Data == null || Project.Data.GetROMSize() <= 0) + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; var mis = new MisalignmentChecker(Project.Data); @@ -1030,7 +1030,7 @@ private void fixMisalignedInstructionsToolStripMenuItem_Click(object sender, Eve private void rescanForInOutPointsToolStripMenuItem_Click(object sender, EventArgs e) { - if (Project?.Data == null || Project.Data.GetROMSize() <= 0) + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; var point = new InOutPointChecker(); @@ -1129,12 +1129,12 @@ private void textToolStripMenuItem_Click(object sender, EventArgs e) private void moveWithStepToolStripMenuItem_Click(object sender, EventArgs e) { - MoveWithStep = !MoveWithStep; - moveWithStepToolStripMenuItem.Checked = MoveWithStep; + moveWithStep = !moveWithStep; + moveWithStepToolStripMenuItem.Checked = moveWithStep; } // sub windows - public AliasList aliasList; + public AliasList AliasList; private VisualizerForm visualForm; private void EnableSubWindows() @@ -1144,14 +1144,14 @@ private void EnableSubWindows() private void labelListToolStripMenuItem_Click(object sender, EventArgs e) { - aliasList.Show(); + AliasList.Show(); } private void openLastProjectAutomaticallyToolStripMenuItem_Click(object sender, EventArgs e) { Settings.Default.OpenLastFileAutomatically = openLastProjectAutomaticallyToolStripMenuItem.Checked; Settings.Default.Save(); - UpdateUIFromSettings(); + UpdateUiFromSettings(); } private void toolStripOpenLast_Click(object sender, EventArgs e) @@ -1182,7 +1182,7 @@ private void importUsageMapToolStripMenuItem_Click_1(object sender, EventArgs e) if (openUsageMapFile.ShowDialog() != DialogResult.OK) return; - var numModifiedFlags = ProjectController.ImportBSNESUsageMap(openUsageMapFile.FileName); + var numModifiedFlags = ProjectController.ImportBsnesUsageMap(openUsageMapFile.FileName); MessageBox.Show($"Modified total {numModifiedFlags} flags!", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information); @@ -1196,7 +1196,7 @@ private void toolStripMenuItem3_Click(object sender, EventArgs e) if (openTraceLogDialog.ShowDialog() != DialogResult.OK) return; - var numModifiedFlags = ProjectController.ImportBSNESTraceLogs(openTraceLogDialog.FileNames); + var numModifiedFlags = ProjectController.ImportBsnesTraceLogs(openTraceLogDialog.FileNames); MessageBox.Show($"Modified total {numModifiedFlags} flags from {openTraceLogDialog.FileNames.Length} files!", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information); @@ -1215,7 +1215,7 @@ private void importCDLToolStripMenuItem_Click_1(object sender, EventArgs e) try { - ProjectController.ImportBizHawkCDL(filename); + ProjectController.ImportBizHawkCdl(filename); } catch (InvalidDataException ex) { @@ -1233,10 +1233,10 @@ private void importCDLToolStripMenuItem_Click_1(object sender, EventArgs e) private void importTraceLogBinary_Click(object sender, EventArgs e) { - var bsnesForm = new BSNESTraceLogBinaryMonitorForm(this); + var bsnesForm = new BsnesTraceLogBinaryMonitorForm(this); bsnesForm.ShowDialog(); - RefreshUI(); + RefreshUi(); } } } \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.Designer.cs b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.Designer.cs index 115bc713..aecd202b 100644 --- a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.Designer.cs +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.Designer.cs @@ -1,6 +1,6 @@ namespace DiztinGUIsh.window.dialog { - partial class BSNESTraceLogBinaryMonitorForm + partial class BsnesTraceLogBinaryMonitorForm { /// /// Required designer variable. @@ -362,7 +362,7 @@ private void InitializeComponent() this.Controls.Add(this.label1); this.Controls.Add(this.btnStart); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; - this.Name = "BSNESTraceLogBinaryMonitorForm"; + this.Name = "BsnesTraceLogBinaryMonitorForm"; this.Text = "BSNES Live Tracelog Capture"; this.Load += new System.EventHandler(this.BSNESTraceLogBinaryMonitorForm_Load); this.Shown += new System.EventHandler(this.BSNESTraceLogBinaryMonitorForm_Shown); diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs index 5614dfbf..1c508806 100644 --- a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.UI.cs @@ -9,7 +9,7 @@ namespace DiztinGUIsh.window.dialog { - public partial class BSNESTraceLogBinaryMonitorForm + public partial class BsnesTraceLogBinaryMonitorForm { private bool initializedChart; private readonly ChartValues chartValuesBytesModified = new ChartValues(); @@ -18,7 +18,7 @@ public partial class BSNESTraceLogBinaryMonitorForm //private const int refreshGraphEveryNDataPoints = 100; //private int dataPointsIn = -1; - private void AppendToChart((BSNESTraceLogImporter.Stats stats, int bytesInQueue) currentStats) + private void AppendToChart((BsnesTraceLogImporter.Stats stats, int bytesInQueue) currentStats) { InitChart(); @@ -54,7 +54,7 @@ private void InitChart() initializedChart = true; } - private void UpdateUI() + private void UpdateUi() { var running = capturing?.Running ?? false; var finishing = capturing?.Finishing ?? false; @@ -96,13 +96,13 @@ private void UpdateUI() // TODO: use databinding - lblTotalProcessed.Text = ByteSize.FromBytes(stats.numRomBytesAnalyzed).ToString("0.00"); - lblNumberModified.Text = ByteSize.FromBytes(stats.numRomBytesModified).ToString("0.00"); - lblModifiedDBs.Text = ByteSize.FromBytes(stats.numDBModified).ToString("0.00"); - lblModifiedDPs.Text = ByteSize.FromBytes(stats.numDpModified).ToString("0.00"); - lblModifiedFlags.Text = ByteSize.FromBytes(stats.numMarksModified).ToString("0.00"); - lblModifiedXFlags.Text = ByteSize.FromBytes(stats.numXFlagsModified).ToString("0.00"); - lblModifiedMFlags.Text = ByteSize.FromBytes(stats.numMFlagsModified).ToString("0.00"); + lblTotalProcessed.Text = ByteSize.FromBytes(stats.NumRomBytesAnalyzed).ToString("0.00"); + lblNumberModified.Text = ByteSize.FromBytes(stats.NumRomBytesModified).ToString("0.00"); + lblModifiedDBs.Text = ByteSize.FromBytes(stats.NumDbModified).ToString("0.00"); + lblModifiedDPs.Text = ByteSize.FromBytes(stats.NumDpModified).ToString("0.00"); + lblModifiedFlags.Text = ByteSize.FromBytes(stats.NumMarksModified).ToString("0.00"); + lblModifiedXFlags.Text = ByteSize.FromBytes(stats.NumXFlagsModified).ToString("0.00"); + lblModifiedMFlags.Text = ByteSize.FromBytes(stats.NumMFlagsModified).ToString("0.00"); } private void button1_Click(object sender, EventArgs e) diff --git a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs index 9a838b0d..b7681860 100644 --- a/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs +++ b/DiztinGUIsh/window/dialog/BSNESTraceLogBinaryMonitorForm.cs @@ -11,13 +11,13 @@ namespace DiztinGUIsh.window.dialog // TODO: BSNESTraceLogCapture does a lot of threading. It's decently protected but, // while that stuff is running, try and avoid using 'Data' anywhere outside BSNESTraceLogCapture. // eventually, if we want to do that we need to retrofit the rest of the app to take advantage of that. - public partial class BSNESTraceLogBinaryMonitorForm : Form + public partial class BsnesTraceLogBinaryMonitorForm : Form { private readonly MainWindow mainWindow; - private BSNESTraceLogCapture capturing; + private BsnesTraceLogCapture capturing; private string lastError; - public BSNESTraceLogBinaryMonitorForm(MainWindow window) + public BsnesTraceLogBinaryMonitorForm(MainWindow window) { mainWindow = window; InitializeComponent(); @@ -29,7 +29,7 @@ private void btnStart_Click(object sender, EventArgs e) btnFinish.Enabled = true; btnStart.Enabled = false; - capturing = new BSNESTraceLogCapture(); + capturing = new BsnesTraceLogCapture(); Start(); } @@ -42,13 +42,13 @@ await Task.Run(() => { }).ContinueWith(task => { this.InvokeIfRequired(() => CapturingFinished(task.Exception)); }); - UpdateUI(); + UpdateUi(); } private void btnFinish_Click(object sender, EventArgs e) { capturing?.SignalToStop(); - UpdateUI(); + UpdateUi(); } private void CapturingFinished(AggregateException ex) @@ -59,10 +59,10 @@ private void CapturingFinished(AggregateException ex) timer1.Enabled = false; capturing = null; - UpdateUI(); + UpdateUi(); } - private void timer1_Tick(object sender, EventArgs e) => UpdateUI(); + private void timer1_Tick(object sender, EventArgs e) => UpdateUi(); private void OnError(AggregateException e) { @@ -70,7 +70,7 @@ private void OnError(AggregateException e) lastError = e.InnerExceptions.Select(ex => ex.Message).Aggregate((line, val) => line += val + "\n"); } - private void BSNESTraceLogBinaryMonitorForm_Load(object sender, EventArgs e) => UpdateUI(); - private void BSNESTraceLogBinaryMonitorForm_Shown(object sender, EventArgs e) => UpdateUI(); + private void BSNESTraceLogBinaryMonitorForm_Load(object sender, EventArgs e) => UpdateUi(); + private void BSNESTraceLogBinaryMonitorForm_Shown(object sender, EventArgs e) => UpdateUi(); } } \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/ExportDisassembly.cs b/DiztinGUIsh/window/dialog/ExportDisassembly.cs index 4226e7f6..f0a0d8de 100644 --- a/DiztinGUIsh/window/dialog/ExportDisassembly.cs +++ b/DiztinGUIsh/window/dialog/ExportDisassembly.cs @@ -11,7 +11,7 @@ namespace DiztinGUIsh // end. public partial class ExportDisassembly : Form { - private readonly Project Project; + private readonly Project project; // Our copy. At the end, if everything is correct, we'll return this. private LogWriterSettings settings; @@ -29,7 +29,7 @@ public partial class ExportDisassembly : Form public ExportDisassembly(Project project) { - Project = project; + this.project = project; settings = project.LogWriterSettings; // copy if (settings.Validate() != "") @@ -43,12 +43,12 @@ public ExportDisassembly(Project project) public void UpdateUiFromProjectSettings() { // TODO: in the future, replace this with databinding so we don't have to do it manually - numData.Value = settings.dataPerLine; - textFormat.Text = settings.format; - comboUnlabeled.SelectedIndex = (int)settings.unlabeled; - comboStructure.SelectedIndex = (int)settings.structure; - chkIncludeUnusedLabels.Checked = settings.includeUnusedLabels; - chkPrintLabelSpecificComments.Checked = settings.printLabelSpecificComments; + numData.Value = settings.DataPerLine; + textFormat.Text = settings.Format; + comboUnlabeled.SelectedIndex = (int)settings.Unlabeled; + comboStructure.SelectedIndex = (int)settings.Structure; + chkIncludeUnusedLabels.Checked = settings.IncludeUnusedLabels; + chkPrintLabelSpecificComments.Checked = settings.PrintLabelSpecificComments; } private void cancel_Click(object sender, EventArgs e) @@ -72,27 +72,27 @@ private string PromptForLogPathFromFileOrFolderDialog(bool askForFile) private string PromptSaveLogPath() { - chooseLogFolder.SelectedPath = Path.GetDirectoryName(Project.ProjectFileName); + chooseLogFolder.SelectedPath = Path.GetDirectoryName(project.ProjectFileName); return chooseLogFolder.ShowDialog() == DialogResult.OK && chooseLogFolder.SelectedPath != "" ? chooseLogFolder.SelectedPath : null; } private string PromptSaveLogFile() { - saveLogSingleFile.InitialDirectory = Project.ProjectFileName; + saveLogSingleFile.InitialDirectory = project.ProjectFileName; return saveLogSingleFile.ShowDialog() == DialogResult.OK && saveLogSingleFile.FileName != "" ? saveLogSingleFile.FileName : null; } private bool PromptForPath() { - var singleFile = settings.structure == LogCreator.FormatStructure.SingleFile; + var singleFile = settings.Structure == LogCreator.FormatStructure.SingleFile; var fileOrFolderPath = PromptForLogPathFromFileOrFolderDialog(singleFile); if (string.IsNullOrEmpty(fileOrFolderPath)) return false; - settings.fileOrFolderOutPath = fileOrFolderPath; + settings.FileOrFolderOutPath = fileOrFolderPath; return true; } @@ -101,7 +101,7 @@ private void textFormat_TextChanged(object sender, EventArgs e) { if (ValidateFormat()) { - settings.format = textFormat.Text.ToLower(); + settings.Format = textFormat.Text.ToLower(); RegenerateSampleOutput(); button2.Enabled = true; } else { @@ -112,19 +112,19 @@ private void textFormat_TextChanged(object sender, EventArgs e) private void numData_ValueChanged(object sender, EventArgs e) { - settings.dataPerLine = (int)numData.Value; + settings.DataPerLine = (int)numData.Value; RegenerateSampleOutput(); } private void comboUnlabeled_SelectedIndexChanged(object sender, EventArgs e) { - settings.unlabeled = (LogCreator.FormatUnlabeled)comboUnlabeled.SelectedIndex; + settings.Unlabeled = (LogCreator.FormatUnlabeled)comboUnlabeled.SelectedIndex; RegenerateSampleOutput(); } private void comboStructure_SelectedIndexChanged(object sender, EventArgs e) { - settings.structure = (LogCreator.FormatStructure)comboStructure.SelectedIndex; + settings.Structure = (LogCreator.FormatStructure)comboStructure.SelectedIndex; } private bool ValidateFormat() @@ -135,17 +135,17 @@ private bool ValidateFormat() private void RegenerateSampleOutput() { var result = RomUtil.GetSampleAssemblyOutput(settings); - textSample.Text = result.outputStr; + textSample.Text = result.OutputStr; } private void chkPrintLabelSpecificComments_CheckedChanged(object sender, EventArgs e) { - settings.printLabelSpecificComments = chkPrintLabelSpecificComments.Checked; + settings.PrintLabelSpecificComments = chkPrintLabelSpecificComments.Checked; } private void chkIncludeUnusedLabels_CheckedChanged(object sender, EventArgs e) { - settings.includeUnusedLabels = chkIncludeUnusedLabels.Checked; + settings.IncludeUnusedLabels = chkIncludeUnusedLabels.Checked; } } } diff --git a/DiztinGUIsh/window/dialog/GotoDialog.cs b/DiztinGUIsh/window/dialog/GotoDialog.cs index 45c5095d..bd6e82cb 100644 --- a/DiztinGUIsh/window/dialog/GotoDialog.cs +++ b/DiztinGUIsh/window/dialog/GotoDialog.cs @@ -13,14 +13,14 @@ public GotoDialog(int offset, Data data) { InitializeComponent(); Data = data; - textROM.Text = Util.NumberToBaseString(Data.ConvertPCtoSNES(offset), Util.NumberBase.Hexadecimal, 6); + textROM.Text = Util.NumberToBaseString(Data.ConvertPCtoSnes(offset), Util.NumberBase.Hexadecimal, 6); textPC.Text = Util.NumberToBaseString(offset, Util.NumberBase.Hexadecimal, 0); } private void GotoDialog_Load(object sender, EventArgs e) { textROM.SelectAll(); - UpdateUI(); + UpdateUi(); } private int ParseOffset(string text) @@ -67,12 +67,12 @@ private bool UpdateTextChanged(string txtChanged, Action= 0 && pc < Data.GetROMSize(); + return pc >= 0 && pc < Data.GetRomSize(); } - private bool IsPCOffsetValid() + private bool IsPcOffsetValid() { var offset = GetPcOffset(); - return IsValidPCAddress(offset); + return IsValidPcAddress(offset); } private bool IsRomAddressValid() @@ -104,33 +104,33 @@ private bool IsRomAddressValid() if (address < 0) return false; - return IsValidPCAddress(Data.ConvertSNEStoPC(address)); + return IsValidPcAddress(Data.ConvertSnesToPc(address)); } private void textROM_TextChanged(object sender, EventArgs e) { UpdateTextChanged(textROM.Text,(finaltext, address, noBase) => { - int pc = Data.ConvertSNEStoPC(address); + int pc = Data.ConvertSnesToPc(address); textROM.Text = finaltext; textPC.Text = Util.NumberToBaseString(pc, noBase, 0); }); - UpdateUI(); + UpdateUi(); } private void textPC_TextChanged(object sender, EventArgs e) { UpdateTextChanged(textPC.Text, (finaltext, offset, noBase) => { - int addr = Data.ConvertPCtoSNES(offset); + int addr = Data.ConvertPCtoSnes(offset); textPC.Text = finaltext; textROM.Text = Util.NumberToBaseString(addr, noBase, 6); }); - UpdateUI(); + UpdateUi(); } private void go_Click(object sender, EventArgs e) diff --git a/DiztinGUIsh/window/dialog/HarshAutoStep.cs b/DiztinGUIsh/window/dialog/HarshAutoStep.cs index 27b44f4c..80a34077 100644 --- a/DiztinGUIsh/window/dialog/HarshAutoStep.cs +++ b/DiztinGUIsh/window/dialog/HarshAutoStep.cs @@ -11,17 +11,17 @@ public partial class HarshAutoStep : Form { private int start, end, count; - private readonly Data Data; + private readonly Data data; public HarshAutoStep(int offset, Data data) { - Debug.Assert(Data!=null); - Data = data; + Debug.Assert(this.data!=null); + this.data = data; InitializeComponent(); start = offset; - var rest = data.GetROMSize() - start; + var rest = data.GetRomSize() - start; count = rest < 0x100 ? rest : 0x100; end = start + count; @@ -46,13 +46,13 @@ private void UpdateText(TextBox selected) int digits = noBase == Util.NumberBase.Hexadecimal && radioROM.Checked ? 6 : 0; if (start < 0) start = 0; - if (end >= Data.GetROMSize()) end = Data.GetROMSize() - 1; + if (end >= data.GetRomSize()) end = data.GetRomSize() - 1; count = end - start; if (count < 0) count = 0; updatingText = true; - if (selected != textStart) textStart.Text = Util.NumberToBaseString(radioROM.Checked ? Data.ConvertPCtoSNES(start) : start, noBase, digits); - if (selected != textEnd) textEnd.Text = Util.NumberToBaseString(radioROM.Checked ? Data.ConvertPCtoSNES(end) : end, noBase, digits); + if (selected != textStart) textStart.Text = Util.NumberToBaseString(radioROM.Checked ? data.ConvertPCtoSnes(start) : start, noBase, digits); + if (selected != textEnd) textEnd.Text = Util.NumberToBaseString(radioROM.Checked ? data.ConvertPCtoSnes(end) : end, noBase, digits); if (selected != textCount) textCount.Text = Util.NumberToBaseString(count, noBase, 0); updatingText = false; } @@ -95,7 +95,7 @@ private void textEnd_TextChanged(object sender, EventArgs e) if (int.TryParse(textEnd.Text, style, null, out var result)) { if (radioROM.Checked) - result = Data.ConvertSNEStoPC(result); + result = data.ConvertSnesToPc(result); end = result; count = end - start; @@ -115,7 +115,7 @@ private void textStart_TextChanged(object sender, EventArgs e) if (int.TryParse(textStart.Text, style, null, out var result)) { if (radioROM.Checked) - result = Data.ConvertSNEStoPC(result); + result = data.ConvertSnesToPc(result); start = result; count = end - start; } diff --git a/DiztinGUIsh/window/dialog/ImportROMDialog.cs b/DiztinGUIsh/window/dialog/ImportROMDialog.cs index 5c3951bc..2c4a653c 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialog.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialog.cs @@ -25,8 +25,8 @@ public partial class ImportRomDialog : Form, IImportRomDialogView private readonly TextBox[,] vectors; private readonly CheckBox[,] checkboxes; - private ImportROMDialogController controller; - public ImportROMDialogController Controller + private ImportRomDialogController controller; + public ImportRomDialogController Controller { get => controller; set @@ -53,7 +53,7 @@ public ImportRomDialog() private void DataBind() { Debug.Assert(ImportSettings != null); - GuiUtil.BindListControlToEnum(cmbRomMapMode, ImportSettings, "ROMMapMode"); + GuiUtil.BindListControlToEnum(cmbRomMapMode, ImportSettings, "ROMMapMode"); checkHeader.Checked = Controller.ShouldCheckHeader; // todo: databind this instead. ImportSettings.PropertyChanged += ImportSettingsOnPropertyChanged; @@ -67,15 +67,15 @@ public bool ShowAndWaitForUserToConfirmSettings() private void Controller_SettingsCreated() { DataBind(); - RefreshUI(); + RefreshUi(); } private void ImportSettingsOnPropertyChanged(object sender, PropertyChangedEventArgs e) { - RefreshUI(); + RefreshUi(); } - private void RefreshUI() + private void RefreshUi() { UpdateOffsetAndSpeed(); UpdateTextboxes(); @@ -85,7 +85,7 @@ private void RefreshUI() } private string GetDetectionMessage() => - Controller.DetectedMapMode.HasValue ? Util.GetEnumDescription(ImportSettings.ROMMapMode) : "Couldn't auto detect ROM Map Mode!"; + Controller.DetectedMapMode.HasValue ? Util.GetEnumDescription(ImportSettings.RomMapMode) : "Couldn't auto detect ROM Map Mode!"; public void UpdateVectorTable() { @@ -111,13 +111,13 @@ public void UpdateVectorTable() private void UpdateOffsetAndSpeed() { - Controller.RomSettingsOffset = RomUtil.GetRomSettingOffset(ImportSettings.ROMMapMode); - ImportSettings.ROMSpeed = RomUtil.GetRomSpeed(Controller.RomSettingsOffset, ImportSettings.RomBytes); + Controller.RomSettingsOffset = RomUtil.GetRomSettingOffset(ImportSettings.RomMapMode); + ImportSettings.RomSpeed = RomUtil.GetRomSpeed(Controller.RomSettingsOffset, ImportSettings.RomBytes); } private void UpdateOkayButtonEnabled() { - okay.Enabled = ImportSettings.ROMSpeed != Data.ROMSpeed.Unknown; + okay.Enabled = ImportSettings.RomSpeed != RomSpeed.Unknown; } private void UpdateTextboxes() @@ -142,7 +142,7 @@ private bool IsOffsetInRange(int offset) => offset > 0 && offset <= ImportSettings.RomBytes.Length; private bool IsProbablyValidDetection() => - ImportSettings.ROMSpeed != Data.ROMSpeed.Unknown && IsOffsetInRange(Controller.RomSettingsOffset); + ImportSettings.RomSpeed != RomSpeed.Unknown && IsOffsetInRange(Controller.RomSettingsOffset); private void SetDefaultsIfDetectionFailed() { @@ -176,14 +176,14 @@ private void UpdateDetectedValues() } } } - var romSpeedStr = Util.GetEnumDescription(ImportSettings.ROMSpeed); + var romSpeedStr = Util.GetEnumDescription(ImportSettings.RomSpeed); var romTitleName = RomUtil.GetRomTitleName(ImportSettings.RomBytes, Controller.RomSettingsOffset); romspeed.Text = romSpeedStr; romtitle.Text = romTitleName; } - private void ImportROMDialog_Load(object sender, EventArgs e) => RefreshUI(); + private void ImportROMDialog_Load(object sender, EventArgs e) => RefreshUi(); private void okay_Click(object sender, EventArgs e) { diff --git a/DiztinGUIsh/window/dialog/ImportROMDialogController.cs b/DiztinGUIsh/window/dialog/ImportROMDialogController.cs index 50916ee3..1767c4a3 100644 --- a/DiztinGUIsh/window/dialog/ImportROMDialogController.cs +++ b/DiztinGUIsh/window/dialog/ImportROMDialogController.cs @@ -9,14 +9,14 @@ public interface IImportRomDialogView { bool PromptToConfirmAction(string msg); bool ShowAndWaitForUserToConfirmSettings(); - ImportROMDialogController Controller { get; set; } + ImportRomDialogController Controller { get; set; } } - public class ImportROMDialogController + public class ImportRomDialogController { public IImportRomDialogView View { get; set; } public ImportRomSettings ImportSettings { get; protected set; } - public Data.ROMMapMode? DetectedMapMode { get; protected set; } + public RomMapMode? DetectedMapMode { get; protected set; } public int RomSettingsOffset { get; set; }= -1; public bool ShouldCheckHeader { get; set; } = true; @@ -46,11 +46,11 @@ public void CreateSettingsFromRom(string filename) { RomFilename = filename, RomBytes = romBytes, - ROMMapMode = RomUtil.DetectROMMapMode(romBytes, out var detectedMapModeSuccess) + RomMapMode = RomUtil.DetectRomMapMode(romBytes, out var detectedMapModeSuccess) }; if (detectedMapModeSuccess) - DetectedMapMode = ImportSettings.ROMMapMode; + DetectedMapMode = ImportSettings.RomMapMode; OnSettingsCreated(); } @@ -74,7 +74,7 @@ public bool Submit() if (!Warn("ROM Map type couldn't be detected.")) return false; } - else if (DetectedMapMode.Value != ImportSettings.ROMMapMode) + else if (DetectedMapMode.Value != ImportSettings.RomMapMode) { if (!Warn("The ROM map type selected is different than what was detected.")) return false; @@ -85,7 +85,7 @@ public bool Submit() private Dictionary GenerateVectorLabels() => RomUtil.GenerateVectorLabels( - VectorTableEntriesEnabled, RomSettingsOffset, ImportSettings.RomBytes, ImportSettings.ROMMapMode); + VectorTableEntriesEnabled, RomSettingsOffset, ImportSettings.RomBytes, ImportSettings.RomMapMode); public Dictionary GenerateHeaderFlags() { diff --git a/DiztinGUIsh/window/dialog/MarkManyDialog.cs b/DiztinGUIsh/window/dialog/MarkManyDialog.cs index 0edff915..ee62a657 100644 --- a/DiztinGUIsh/window/dialog/MarkManyDialog.cs +++ b/DiztinGUIsh/window/dialog/MarkManyDialog.cs @@ -10,12 +10,12 @@ public partial class MarkManyDialog : Form { private int start, end, count, value; - private Data Data; + private Data data; public MarkManyDialog(int offset, int column, Data data) { InitializeComponent(); - Data = data; + this.data = data; switch (column) { @@ -26,7 +26,7 @@ public MarkManyDialog(int offset, int column, Data data) default: property.SelectedIndex = 0; break; } start = offset; - int rest = Data.GetROMSize() - start; + int rest = this.data.GetRomSize() - start; count = rest < 0x10 ? rest : 0x10; end = start + count; @@ -85,9 +85,9 @@ public object GetValue() case 5: switch (archCombo.SelectedIndex) { - case 0: return Data.Architecture.CPU65C816; - case 1: return Data.Architecture.APUSPC700; - case 2: return Data.Architecture.GPUSuperFX; + case 0: return Data.Architecture.Cpu65C816; + case 1: return Data.Architecture.Apuspc700; + case 2: return Data.Architecture.GpuSuperFx; } break; } @@ -101,7 +101,7 @@ private void UpdateGroup() mxCombo.Visible = (property.SelectedIndex == 3 || property.SelectedIndex == 4); archCombo.Visible = (property.SelectedIndex == 5); regValue.MaxLength = (property.SelectedIndex == 1 ? 3 : 5); - value = property.SelectedIndex == 1 ? Data.GetDataBank(start) : Data.GetDirectPage(start); + value = property.SelectedIndex == 1 ? data.GetDataBank(start) : data.GetDirectPage(start); } private bool updatingText; @@ -110,7 +110,7 @@ private void UpdateText(TextBox selected) { Util.NumberBase noBase = radioDec.Checked ? Util.NumberBase.Decimal : Util.NumberBase.Hexadecimal; int digits = noBase == Util.NumberBase.Hexadecimal && radioROM.Checked ? 6 : 0; - int size = Data.GetROMSize(); + int size = data.GetRomSize(); int maxValue = property.SelectedIndex == 1 ? 0x100 : 0x10000; if (start < 0) start = 0; @@ -121,8 +121,8 @@ private void UpdateText(TextBox selected) if (value >= maxValue) value = maxValue - 1; updatingText = true; - if (selected != textStart) textStart.Text = Util.NumberToBaseString(radioROM.Checked ? Data.ConvertPCtoSNES(start) : start, noBase, digits); - if (selected != textEnd) textEnd.Text = Util.NumberToBaseString(radioROM.Checked ? Data.ConvertPCtoSNES(end) : end, noBase, digits); + if (selected != textStart) textStart.Text = Util.NumberToBaseString(radioROM.Checked ? data.ConvertPCtoSnes(start) : start, noBase, digits); + if (selected != textEnd) textEnd.Text = Util.NumberToBaseString(radioROM.Checked ? data.ConvertPCtoSnes(end) : end, noBase, digits); if (selected != textCount) textCount.Text = Util.NumberToBaseString(count, noBase, 0); if (selected != regValue) regValue.Text = Util.NumberToBaseString(value, noBase, 0); updatingText = false; @@ -151,7 +151,7 @@ private void textEnd_TextChanged(object sender, EventArgs e) if (int.TryParse(textEnd.Text, style, null, out var result)) { - if (radioROM.Checked) result = Data.ConvertSNEStoPC(result); + if (radioROM.Checked) result = data.ConvertSnesToPc(result); end = result; count = end - start; } @@ -192,7 +192,7 @@ private void textStart_TextChanged(object sender, EventArgs e) if (int.TryParse(textStart.Text, style, null, out var result)) { - if (radioROM.Checked) result = Data.ConvertSNEStoPC(result); + if (radioROM.Checked) result = data.ConvertSnesToPc(result); start = result; count = end - start; } diff --git a/DiztinGUIsh/window/dialog/MisalignmentChecker.cs b/DiztinGUIsh/window/dialog/MisalignmentChecker.cs index ae444d42..0b062b27 100644 --- a/DiztinGUIsh/window/dialog/MisalignmentChecker.cs +++ b/DiztinGUIsh/window/dialog/MisalignmentChecker.cs @@ -24,7 +24,7 @@ private void buttonScan_Click(object sender, EventArgs e) textLog.Text = ""; int found = 0, offset = 0; - while (found < 500 && offset < Data.GetROMSize()) + while (found < 500 && offset < Data.GetRomSize()) { Data.FlagType flag = Data.GetFlag(offset), check = flag == Data.FlagType.Opcode ? Data.FlagType.Operand : flag; var step = flag == Data.FlagType.Opcode ? Data.GetInstructionLength(offset) : RomUtil.GetByteLengthForFlag(flag); @@ -33,7 +33,7 @@ private void buttonScan_Click(object sender, EventArgs e) { found++; textLog.Text += - $"{Util.NumberToBaseString(Data.ConvertPCtoSNES(offset), Util.NumberBase.Hexadecimal, 6, true)} (0x{Util.NumberToBaseString(offset, Util.NumberBase.Hexadecimal, 0)}): Operand without Opcode\r\n"; + $"{Util.NumberToBaseString(Data.ConvertPCtoSnes(offset), Util.NumberBase.Hexadecimal, 6, true)} (0x{Util.NumberToBaseString(offset, Util.NumberBase.Hexadecimal, 0)}): Operand without Opcode\r\n"; } else if (step > 1) { for (var i = 1; i < step; i++) @@ -41,7 +41,7 @@ private void buttonScan_Click(object sender, EventArgs e) if (Data.GetFlag(offset + i) == check) continue; found++; textLog.Text += - $"{Util.NumberToBaseString(Data.ConvertPCtoSNES(offset + i), Util.NumberBase.Hexadecimal, 6, true)} (0x{Util.NumberToBaseString(offset + i, Util.NumberBase.Hexadecimal, 0)}): {Util.GetEnumDescription(Data.GetFlag(offset + i))} is not {Util.GetEnumDescription(check)}\r\n"; + $"{Util.NumberToBaseString(Data.ConvertPCtoSnes(offset + i), Util.NumberBase.Hexadecimal, 6, true)} (0x{Util.NumberToBaseString(offset + i, Util.NumberBase.Hexadecimal, 0)}): {Util.GetEnumDescription(Data.GetFlag(offset + i))} is not {Util.GetEnumDescription(check)}\r\n"; } } diff --git a/DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs b/DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs index 63c96f6f..668f8c0d 100644 --- a/DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs +++ b/DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs @@ -16,8 +16,8 @@ public RomBankVisualizer(Project project, int startingRomOffset, int length, str InitializeComponent(); romImage1.Project = project; - romImage1.ROMVisual.RomStartingOffset = startingRomOffset; - romImage1.ROMVisual.LengthOverride = length; + romImage1.RomVisual.RomStartingOffset = startingRomOffset; + romImage1.RomVisual.LengthOverride = length; lblBankName.Text = bankName; } } diff --git a/DiztinGUIsh/window/usercontrols/RomImage.cs b/DiztinGUIsh/window/usercontrols/RomImage.cs index f58da1e4..ae3133dc 100644 --- a/DiztinGUIsh/window/usercontrols/RomImage.cs +++ b/DiztinGUIsh/window/usercontrols/RomImage.cs @@ -12,12 +12,12 @@ public partial class RomImage : UserControl { public event EventHandler RedrawOccurred; - public RomVisual ROMVisual { get; } = new RomVisual(); + public RomVisual RomVisual { get; } = new RomVisual(); public Project Project { - get => ROMVisual.Project; - set => ROMVisual.Project = value; + get => RomVisual.Project; + set => RomVisual.Project = value; } public RomImage() @@ -37,24 +37,24 @@ private void RomImage_Paint(object sender, PaintEventArgs e) private void Redraw(Graphics graphics = null) { - if (ROMVisual?.Bitmap == null) + if (RomVisual?.Bitmap == null) return; graphics ??= CreateGraphics(); - var width = ROMVisual.Bitmap.Width; - var height = ROMVisual.Bitmap.Height; - graphics.DrawImage(ROMVisual.Bitmap, 0, 0, width, height); + var width = RomVisual.Bitmap.Width; + var height = RomVisual.Bitmap.Height; + graphics.DrawImage(RomVisual.Bitmap, 0, 0, width, height); OnRedrawOccurred(); } private void RedrawIfNeeded() { - if (!Visible || !ROMVisual.IsDirty) + if (!Visible || !RomVisual.IsDirty) return; - ROMVisual.Refresh(); + RomVisual.Refresh(); Redraw(); } @@ -65,8 +65,8 @@ private void timer1_Tick(object sender, System.EventArgs e) protected virtual void OnRedrawOccurred() { - Width = ROMVisual.Width; - Height = ROMVisual.Height; + Width = RomVisual.Width; + Height = RomVisual.Height; RedrawOccurred?.Invoke(this, EventArgs.Empty); } From 10c6408050217323b93d3747be5d8f966d504504 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 25 Oct 2020 16:28:29 -0400 Subject: [PATCH 117/136] fix bug with compression routine - was incorrectly adding an extra line add unit tests! --- .../xml_serializer/RepeaterCompression.cs | 14 ++-- Diz.Test/CompressionTest.cs | 81 +++++++++++++++---- 2 files changed, 69 insertions(+), 26 deletions(-) diff --git a/Diz.Core/serialization/xml_serializer/RepeaterCompression.cs b/Diz.Core/serialization/xml_serializer/RepeaterCompression.cs index 6726be9a..eee3b4ac 100644 --- a/Diz.Core/serialization/xml_serializer/RepeaterCompression.cs +++ b/Diz.Core/serialization/xml_serializer/RepeaterCompression.cs @@ -5,7 +5,7 @@ namespace Diz.Core.serialization.xml_serializer { - public class RepeaterCompression + public static class RepeaterCompression { public static void Decompress(ref List lines) { @@ -24,7 +24,7 @@ public static void Decompress(ref List lines) throw new InvalidDataException("Invalid repeater command"); var count = int.Parse(split[1]); - for (int i = 0; i < count; ++i) + for (var i = 0; i < count; ++i) { output.Add(split[2]); } @@ -47,15 +47,15 @@ public static void Compress(ref List lines) // we want to catch large consecutive blocks of data. const int minNumberRepeatsBeforeWeBother = 8; - int totalLinesDebug = 0; + var totalLinesDebug = 0; for (var i = 1; i < lines.Count; ++i) { var line = lines[i]; Debug.Assert(!line.StartsWith("r")); - bool different = line != lastLine; - bool finalLine = i == lines.Count - 1; + var different = line != lastLine; + var finalLine = i == lines.Count - 1; if (!different) { @@ -63,10 +63,6 @@ public static void Compress(ref List lines) if (!finalLine) continue; - - // special case for the final line. - // since our loop only ever prints out the LAST line, we have to handle this separately. - consecutive++; } if (consecutive >= minNumberRepeatsBeforeWeBother) diff --git a/Diz.Test/CompressionTest.cs b/Diz.Test/CompressionTest.cs index d8ab8480..1dce203e 100644 --- a/Diz.Test/CompressionTest.cs +++ b/Diz.Test/CompressionTest.cs @@ -1,39 +1,86 @@ using System.Collections.Generic; using System.Linq; +using Diz.Core.serialization.xml_serializer; using Xunit; namespace Diz.Test { public static class CompressionTest { - public static IEnumerable Repeat(TOut toRepeat, int times) + private static IEnumerable Repeat(TOut toRepeat, int times) { + for (var i = 0; i < times; ++i) { + yield return toRepeat; + } + } + + private static (IEnumerable, IEnumerable) GenerateRepeat(string toRepeat, int times) { - for (var i = 0; i < times; ++i) + var repeated = Repeat($"{toRepeat}", times); + return (repeated.ToList(), + times >= 8 + ? new List(new[] {$"r {times} {toRepeat}"}) + : repeated.ToList() + ); + } + + public static TheoryData, IEnumerable> ValidCompressionData + { + get { - yield return toRepeat; + // TODO: probably a way simpler way to do this. works ok. + var p = ValidDataReal(); + var xx = new TheoryData, IEnumerable>(); + p.ForEach(i => xx.Add(i.Item1, i.Item2)); + return xx; } } - public static TheoryData, IEnumerable> ValidCompressionData => - new TheoryData, IEnumerable> + private static List<(IEnumerable, IEnumerable)> ValidDataReal() => + new List<(IEnumerable, IEnumerable)> { - { - Repeat("YO", 3), - Repeat("YO", 3) - }, - { - Repeat("YO", 20), - new[] {"r YO"} - } + GenerateRepeat("TestItem", 20), + GenerateRepeat("TestItem", 30), + ( + Repeat("YO", 20).Concat(new[] { + "different @ end" + }), + new List(new[] { + "r 20 YO", + "different @ end" + }) + ), + ( + new List() + { + "start", + "start2", + } + .Concat( + Repeat("YO1", 22).Concat( + Repeat("YO2", 20).Concat( + new[] { + "different @ end" + }))), + new List(new[] { + "start", + "start2", + "r 22 YO1", + "r 20 YO2", + "different @ end" + }) + ) }; [Theory] [MemberData(nameof(ValidCompressionData))] - public static void TestCompressionsValid(IEnumerable input, IEnumerable output) + public static void TestCompressionsValid(IEnumerable input, IEnumerable expected) { - //var serializer = new RomBytesSerializer(); - //RomBytesXMLSerializer.ApplyCompression_GroupsBlocks() - Assert.Equal(input.ToList(), output.ToList()); + var inputListCopy = new List(input); + RepeaterCompression.Compress(ref inputListCopy); + Assert.Equal(expected, inputListCopy); + + RepeaterCompression.Decompress(ref inputListCopy); + Assert.Equal(inputListCopy, input); } } } \ No newline at end of file From 0f9f827639a6b18f701474fe2e1601c828dcfc7b Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 25 Oct 2020 17:13:14 -0400 Subject: [PATCH 118/136] refactor: - make ProjectFileManager.cs not reliant on having a rom prompt function (easier to test or handle differently now) - add function to get true SMC ROM bytes - add working full load/save cycle unit tests - fix existing tests --- Diz.Core/model/Data.cs | 21 +++-- Diz.Core/serialization/ProjectFileManager.cs | 77 ++++++++++--------- .../xml_serializer/ProjectXMLSerializer.cs | 10 +-- .../xml_serializer/RomBytesXMLSerializer.cs | 13 ++-- Diz.Test/LoadSaveTest.cs | 16 +++- Diz.Test/SerializerDictionaryTest.cs | 12 +-- DiztinGUIsh/controller/ProjectController.cs | 10 ++- 7 files changed, 94 insertions(+), 65 deletions(-) diff --git a/Diz.Core/model/Data.cs b/Diz.Core/model/Data.cs index 2b53cf1f..69220c75 100644 --- a/Diz.Core/model/Data.cs +++ b/Diz.Core/model/Data.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Text; using Diz.Core.arch; using Diz.Core.util; @@ -54,17 +55,18 @@ public int GetRomCheckSumsFromRomBytes() return ByteUtil.ByteArrayToInt32(GetRomBytes(0xFFDC, 4)); } - public void CopyRomDataIn(byte[] data) + public void CopyRomDataIn(IEnumerable trueRomBytes) { var previousNotificationState = RomBytes.SendNotificationChangedEvents; RomBytes.SendNotificationChangedEvents = false; - - var size = data.Length; - Debug.Assert(RomBytes.Count == size); - for (var i = 0; i < size; i++) + + var i = 0; + foreach (var b in trueRomBytes) { - RomBytes[i].Rom = data[i]; + RomBytes[i].Rom = b; + ++i; } + Debug.Assert(RomBytes.Count == i); RomBytes.SendNotificationChangedEvents = previousNotificationState; } @@ -562,5 +564,12 @@ private int GetSnesBankByte(int bankIndex) var bankSnesNumber = ConvertPCtoSnes(bankStartingPcOffset) >> 16; return bankSnesNumber; } + + // get the actual ROM file bytes (i.e. the contents of the SMC file on the disk) + // note: don't save these anywhere because the data is copyrighted. + public IEnumerable GetFileBytes() + { + return RomBytes.Select(b => b.Rom); + } } } diff --git a/Diz.Core/serialization/ProjectFileManager.cs b/Diz.Core/serialization/ProjectFileManager.cs index d4732d9c..591b57e7 100644 --- a/Diz.Core/serialization/ProjectFileManager.cs +++ b/Diz.Core/serialization/ProjectFileManager.cs @@ -8,9 +8,41 @@ namespace Diz.Core.serialization { - public static class ProjectFileManager + public class ProjectFileManager : BaseProjectFileManager { - public static (Project project, string warning) Open(string filename, Func romPromptFn) + public Func RomPromptFn { get; set; } + + // TODO: move romPromptFn to be a field instead of a param passed around. + protected override byte[] ReadFromOriginalRom(Project project) + { + string firstRomFileWeTried; + var nextFileToTry = firstRomFileWeTried = project.AttachedRomFilename; + byte[] rom; + + // try to open a ROM that matches us, if not, ask the user until they give up + do + { + var error = project.ReadRomIfMatchesProject(nextFileToTry, out rom); + if (error == null) + break; + + nextFileToTry = RomPromptFn(error); + if (nextFileToTry == null) + return null; + } while (true); + + project.AttachedRomFilename = nextFileToTry; + + if (project.AttachedRomFilename != firstRomFileWeTried) + project.UnsavedChanges = true; + + return rom; + } + } + + public abstract class BaseProjectFileManager + { + public (Project project, string warning) Open(string filename) { Trace.WriteLine("Opening Project START"); @@ -24,13 +56,13 @@ public static (Project project, string warning) Open(string filename, Func romPromptFn) + public bool PostSerialize(Project project) { // at this stage, 'Data' is populated with everything EXCEPT the actual ROM bytes. // It would be easy to store the ROM bytes in the save file, but, for copyright reasons, @@ -44,7 +76,7 @@ public static bool PostSerialize(Project project, Func romPrompt Debug.Assert(data.Labels != null && data.Comments != null); Debug.Assert(data.RomBytes != null && data.RomBytes.Count > 0); - var rom = ReadFromOriginalRom(project, romPromptFn); + var rom = ReadFromOriginalRom(project); if (rom == null) return false; @@ -52,33 +84,6 @@ public static bool PostSerialize(Project project, Func romPrompt return true; } - public static byte[] ReadFromOriginalRom(Project project, Func romPromptFn) - { - string firstRomFileWeTried; - var nextFileToTry = firstRomFileWeTried = project.AttachedRomFilename; - byte[] rom; - - // try to open a ROM that matches us, if not, ask the user until they give up - do - { - var error = project.ReadRomIfMatchesProject(nextFileToTry, out rom); - if (error == null) - break; - - nextFileToTry = romPromptFn(error); - if (nextFileToTry == null) - return null; - } while (true); - - project.AttachedRomFilename = nextFileToTry; - - if (project.AttachedRomFilename != firstRomFileWeTried) - project.UnsavedChanges = true; - - return rom; - } - - private static ProjectSerializer GetSerializerForFormat(byte[] data) { if (BinarySerializer.IsBinaryFileFormat(data)) @@ -92,7 +97,7 @@ private static bool IsUncompressedProject(string filename) return Path.GetExtension(filename).Equals(".dizraw", StringComparison.InvariantCultureIgnoreCase); } - public static void Save(Project project, string filename) + public void Save(Project project, string filename) { // Everything saves in XML format from here on out. // Binary format is deprecated. @@ -101,7 +106,7 @@ public static void Save(Project project, string filename) Save(project, filename, defaultSerializer); } - private static void Save(Project project, string filename, ProjectSerializer serializer) + private void Save(Project project, string filename, ProjectSerializer serializer) { var data = DoSave(project, filename, serializer); @@ -110,7 +115,7 @@ private static void Save(Project project, string filename, ProjectSerializer ser project.ProjectFileName = filename; } - private static byte[] DoSave(Project project, string filename, ProjectSerializer serializer) + private byte[] DoSave(Project project, string filename, ProjectSerializer serializer) { var data = serializer.Save(project); @@ -149,5 +154,7 @@ public static Project ImportRomAndCreateNewProject(ImportRomSettings importSetti return project; } + + protected abstract byte[] ReadFromOriginalRom(Project project); } } diff --git a/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs b/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs index 6c7ea4d9..cb2aaaf2 100644 --- a/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs +++ b/Diz.Core/serialization/xml_serializer/ProjectXMLSerializer.cs @@ -52,7 +52,7 @@ public override byte[] Save(Project project) var finalBytes = Encoding.UTF8.GetBytes(xmlStr); // if you want some sanity checking, run this to verify everything saved correctly - DebugVerifyProjectEquality(project, finalBytes); + // DebugVerifyProjectEquality(project, finalBytes); // end debug return finalBytes; @@ -60,13 +60,13 @@ public override byte[] Save(Project project) // just for debugging purposes, compare two projects together to make sure they serialize/deserialize // correctly. - private void DebugVerifyProjectEquality(Project project1, byte[] finalBytesProject2) + private void DebugVerifyProjectEquality(Project originalProjectWeJustSaved, byte[] projectBytesWeJustSerialized) { - var result = Load(finalBytesProject2); + var result = Load(projectBytesWeJustSerialized); var project2 = result.project; - ProjectFileManager.PostSerialize(project2, null); - DebugVerifyProjectEquality(project1, project2); + new ProjectFileManager().PostSerialize(project2); + DebugVerifyProjectEquality(originalProjectWeJustSaved, project2); } public override (Project project, string warning) Load(byte[] data) diff --git a/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs b/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs index 314962d6..af691fb8 100644 --- a/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs +++ b/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs @@ -37,8 +37,7 @@ sealed class RomBytesSerializer : ISerializer private const bool CompressGroupBlock = true; private const bool CompressUsingTable1 = true; - private const int NumTasksToUse = 10; - + private readonly int numTasksToUse = 10; public RomBytes Get(IFormatReader parameter) { @@ -49,17 +48,17 @@ public RomBytes Get(IFormatReader parameter) private RomByte[] DecodeAllBytes(List allLines) { - if (NumTasksToUse == 1) + if (numTasksToUse == 1) return DecodeRomBytes(allLines, 0); var nextIndex = 0; - var workListCount = allLines.Count / NumTasksToUse; + var workListCount = allLines.Count / numTasksToUse; - var tasks = new List>(NumTasksToUse); + var tasks = new List>(numTasksToUse); - for (var t = 0; t < NumTasksToUse; ++t) + for (var t = 0; t < numTasksToUse; ++t) { - var lastThread = t == NumTasksToUse - 1; + var lastThread = t == numTasksToUse - 1; if (lastThread) workListCount = allLines.Count - nextIndex; diff --git a/Diz.Test/LoadSaveTest.cs b/Diz.Test/LoadSaveTest.cs index 750e4775..c5fbeb52 100644 --- a/Diz.Test/LoadSaveTest.cs +++ b/Diz.Test/LoadSaveTest.cs @@ -1,4 +1,5 @@ -using Diz.Core; +using System.Linq; +using Diz.Core; using Diz.Core.model; using Diz.Core.serialization.xml_serializer; using Xunit; @@ -10,17 +11,26 @@ public class LoadSaveTest [Fact] private void SerializeAndDeserialize() { + // use the sample data to fake a project var sampleProject = new Project {Data = SampleRomData.SampleData}; + + // extract the bytes that would normally be in the SMC file (they only exist in code for this sample data) + var romFileBytes = sampleProject.Data.GetFileBytes(); + // save it to create an output byte stream, we'd normally write this to the disk var serializer = new ProjectXmlSerializer(); var outputBytes = serializer.Save(sampleProject); + // now do the reverse and load our output back as the input var (deserializedProject, warning) = serializer.Load(outputBytes); + + // final step, the loading process doesn't save the actual SMC file bytes, so we do it ourselves here + deserializedProject.Data.CopyRomDataIn(romFileBytes); + // now we can do a full compare between the original project, and the project which has been cycled through + // serialization and deserialization Assert.True(warning == ""); Assert.True(sampleProject.Equals(deserializedProject)); - - // todo: run a couple tests where we mess with the end repeater bytes } } } \ No newline at end of file diff --git a/Diz.Test/SerializerDictionaryTest.cs b/Diz.Test/SerializerDictionaryTest.cs index 7375b6d4..9cf36e14 100644 --- a/Diz.Test/SerializerDictionaryTest.cs +++ b/Diz.Test/SerializerDictionaryTest.cs @@ -20,11 +20,11 @@ public SerializerDictionaryTest(ITestOutputHelper testOutputHelper) public class TestRoot { - public ObservableDictionary Odw { get; set; } = new ObservableDictionary() { + public ObservableDictionary ODW { get; set; } = new ObservableDictionary() { {1, "Z test1"}, {2, "Z test3"}, }; - public ObservableDictionary Odw2 { get; set; } = new ObservableDictionary() { + public ObservableDictionary ODW2 { get; set; } = new ObservableDictionary() { {100, new Label {Comment = "c1", Name = "location1"}}, {200, new Label {Comment = "c2", Name = "location2"}}, }; @@ -33,8 +33,8 @@ public class TestRoot protected bool Equals(TestRoot other) { return - System.Linq.Enumerable.SequenceEqual(Odw, other.Odw) && - System.Linq.Enumerable.SequenceEqual(Odw2, other.Odw2); + System.Linq.Enumerable.SequenceEqual(ODW, other.ODW) && + System.Linq.Enumerable.SequenceEqual(ODW2, other.ODW2); } public override bool Equals(object obj) @@ -49,7 +49,7 @@ public override int GetHashCode() { unchecked { - return ((Odw != null ? Odw.GetHashCode() : 0) * 397) ^ (Odw2 != null ? Odw2.GetHashCode() : 0); + return ((ODW != null ? ODW.GetHashCode() : 0) * 397) ^ (ODW2 != null ? ODW2.GetHashCode() : 0); } } #endregion @@ -86,6 +86,6 @@ private void DeSerialize() private readonly TestRoot testRootElementGood = new TestRoot(); - string xmlShouldBe = ""; + string xmlShouldBe = ""; } } \ No newline at end of file diff --git a/DiztinGUIsh/controller/ProjectController.cs b/DiztinGUIsh/controller/ProjectController.cs index 6cc91fa2..d7aee609 100644 --- a/DiztinGUIsh/controller/ProjectController.cs +++ b/DiztinGUIsh/controller/ProjectController.cs @@ -78,7 +78,11 @@ public bool OpenProject(string filename) { try { - var (project1, warning) = ProjectFileManager.Open(filename, AskToSelectNewRomFilename); + var (project1, warning) = new ProjectFileManager() + { + RomPromptFn = AskToSelectNewRomFilename + }.Open(filename); + project = project1; warningMsg = warning; } @@ -128,7 +132,7 @@ private void Project_PropertyChanged(object sender, PropertyChangedEventArgs e) public void SaveProject(string filename) { - DoLongRunningTask(delegate { ProjectFileManager.Save(Project, filename); }, + DoLongRunningTask(delegate { new ProjectFileManager().Save(Project, filename); }, $"Saving {Path.GetFileName(filename)}..."); ProjectView.OnProjectSaved(); } @@ -161,7 +165,7 @@ public bool ImportRomAndCreateNewProject(string romFilename) public void ImportRomAndCreateNewProject(ImportRomSettings importSettings) { - var project = ProjectFileManager.ImportRomAndCreateNewProject(importSettings); + var project = BaseProjectFileManager.ImportRomAndCreateNewProject(importSettings); OnProjectOpenSuccess(project.ProjectFileName, project); } From 039f851b4efbbd1292d9910e3ece70c6380ebe4e Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 25 Oct 2020 18:13:41 -0400 Subject: [PATCH 119/136] optimize: make fake64 be ultra-bare-metal, hardcore the crap out of it --- Diz.Core/util/Fake64Encoding.cs | 217 ++++++++++++++++++++++---------- Diz.Test/Diz.Test.csproj | 2 +- Diz.Test/Fake64Test.cs | 44 ------- Diz.Test/MiscTests.cs | 23 ++++ 4 files changed, 172 insertions(+), 114 deletions(-) delete mode 100644 Diz.Test/Fake64Test.cs create mode 100644 Diz.Test/MiscTests.cs diff --git a/Diz.Core/util/Fake64Encoding.cs b/Diz.Core/util/Fake64Encoding.cs index 525ab730..f1d71b1f 100644 --- a/Diz.Core/util/Fake64Encoding.cs +++ b/Diz.Core/util/Fake64Encoding.cs @@ -3,77 +3,19 @@ namespace Diz.Core.util { + // this is base64 EXCEPT: + // 1) char "A" and "0" swapped (my data format compresses things with "0" better) + // 2) only supports 6 bits of input data to encode on ONE BYTE. + // + // there's better ways to do this but I'm going for blinding speed for multi-threaded access. + // just, hardcode it. there are system Base64 functions we could use but, they're also way too slow. + // + // This is ... kind of a silly implementation... but, it's fast and works well with our compression so... + // if you don't like it that's just like... your opinion and stuff. man.♦ + // + // [don't judge me] -Dom public static class Fake64Encoding { - // this is base64 EXCEPT: - // 1) char "A" and "0" swapped (my data format compresses things with "0" better) - // 2) only supports 6 bits of input data to encode - // DONT BE FOOLED :) - public const string Fake64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + - "abcdefghijklmnopqrstuvwxyz" + - "0123456789" + - "+/"; - - public static readonly byte[] Fake64Values = - { - 208, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, - 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, - 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, - 148, 152, 156, 160, 164, 168, 172, 176, 180, 184, - 188, 192, 196, 200, 204, 0, 212, 216, 220, 224, 228, - 232, 236, 240, 244, 248, 252 - }; - - private static readonly object InitLock = new object(); - - public static IEnumerable CharToByte => - Fake64Chars.Zip( - Fake64Values, (c, b) => new object[] { c, b }); - - private static Dictionary _fake64CharToByte; - public static Dictionary Fake64CharToByte - { - get - { - lock (InitLock) - { - if (_fake64CharToByte != null) - return _fake64CharToByte; - - _fake64CharToByte = new Dictionary(); - foreach (var kvp in CharToByte) - { - _fake64CharToByte[(char) kvp[0]] = (byte) kvp[1]; - } - - return _fake64CharToByte; - } - } - } - - private static Dictionary _fake64ByteToChar; - public static Dictionary Fake64ByteToChar - { - get - { - lock (InitLock) - { - if (_fake64ByteToChar != null) - return _fake64ByteToChar; - - _fake64ByteToChar = new Dictionary(); - foreach (var kvp in CharToByte) - { - _fake64ByteToChar[(byte) kvp[1]] = (char) kvp[0]; - } - - return _fake64ByteToChar; - } - } - } - - // we could use the system base64 stuff but, this is faster. - public static byte DecodeHackyBase64(char input) { return Fake64CharToByte[input]; @@ -83,5 +25,142 @@ public static char EncodeHackyBase64(byte input) { return Fake64ByteToChar[input]; } + + // char to byte + private static readonly Dictionary Fake64CharToByte = new Dictionary() + { + {'A', 208}, + {'B', 4}, + {'C', 8}, + {'D', 12}, + {'E', 16}, + {'F', 20}, + {'G', 24}, + {'H', 28}, + {'I', 32}, + {'J', 36}, + {'K', 40}, + {'L', 44}, + {'M', 48}, + {'N', 52}, + {'O', 56}, + {'P', 60}, + {'Q', 64}, + {'R', 68}, + {'S', 72}, + {'T', 76}, + {'U', 80}, + {'V', 84}, + {'W', 88}, + {'X', 92}, + {'Y', 96}, + {'Z', 100}, + {'a', 104}, + {'b', 108}, + {'c', 112}, + {'d', 116}, + {'e', 120}, + {'f', 124}, + {'g', 128}, + {'h', 132}, + {'i', 136}, + {'j', 140}, + {'k', 144}, + {'l', 148}, + {'m', 152}, + {'n', 156}, + {'o', 160}, + {'p', 164}, + {'q', 168}, + {'r', 172}, + {'s', 176}, + {'t', 180}, + {'u', 184}, + {'v', 188}, + {'w', 192}, + {'x', 196}, + {'y', 200}, + {'z', 204}, + {'0', 0}, + {'1', 212}, + {'2', 216}, + {'3', 220}, + {'4', 224}, + {'5', 228}, + {'6', 232}, + {'7', 236}, + {'8', 240}, + {'9', 244}, + {'+', 248}, + {'/', 252}, + }; + + private static readonly Dictionary Fake64ByteToChar = new Dictionary() + { + {208, 'A'}, + {4, 'B'}, + {8, 'C'}, + {12, 'D'}, + {16, 'E'}, + {20, 'F'}, + {24, 'G'}, + {28, 'H'}, + {32, 'I'}, + {36, 'J'}, + {40, 'K'}, + {44, 'L'}, + {48, 'M'}, + {52, 'N'}, + {56, 'O'}, + {60, 'P'}, + {64, 'Q'}, + {68, 'R'}, + {72, 'S'}, + {76, 'T'}, + {80, 'U'}, + {84, 'V'}, + {88, 'W'}, + {92, 'X'}, + {96, 'Y'}, + {100, 'Z'}, + {104, 'a'}, + {108, 'b'}, + {112, 'c'}, + {116, 'd'}, + {120, 'e'}, + {124, 'f'}, + {128, 'g'}, + {132, 'h'}, + {136, 'i'}, + {140, 'j'}, + {144, 'k'}, + {148, 'l'}, + {152, 'm'}, + {156, 'n'}, + {160, 'o'}, + {164, 'p'}, + {168, 'q'}, + {172, 'r'}, + {176, 's'}, + {180, 't'}, + {184, 'u'}, + {188, 'v'}, + {192, 'w'}, + {196, 'x'}, + {200, 'y'}, + {204, 'z'}, + {0, '0'}, + {212, '1'}, + {216, '2'}, + {220, '3'}, + {224, '4'}, + {228, '5'}, + {232, '6'}, + {236, '7'}, + {240, '8'}, + {244, '9'}, + {248, '+'}, + {252, '/'}, + }; } } diff --git a/Diz.Test/Diz.Test.csproj b/Diz.Test/Diz.Test.csproj index 51a2f328..f5d12f0d 100644 --- a/Diz.Test/Diz.Test.csproj +++ b/Diz.Test/Diz.Test.csproj @@ -137,7 +137,7 @@ - + diff --git a/Diz.Test/Fake64Test.cs b/Diz.Test/Fake64Test.cs deleted file mode 100644 index 8bdb0178..00000000 --- a/Diz.Test/Fake64Test.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Diz.Core.serialization.xml_serializer; -using Diz.Core.util; -using Xunit; - -namespace Diz.Test -{ - public static class Fake64Test - { - public class Fake64Tests - { - public static IEnumerable CharToByte => - Fake64Encoding.Fake64Chars.Zip( - Fake64Encoding.Fake64Values, (c, b) => new object[] { c, b }); - - [Theory] - [MemberData(nameof(CharToByte))] - public static void TestDecodeFake64(char c, byte b) - { - Assert.Equal(b, Fake64Encoding.DecodeHackyBase64(c)); - } - - [Theory] - [MemberData(nameof(CharToByte))] - public static void TestEncodeFake64(char c, byte b) - { - Assert.Equal(c, Fake64Encoding.EncodeHackyBase64(b)); - } - - [Fact] - public static void TestHex() - { - Assert.Equal(0xF0, RomByteEncoding.ByteParseHex2('F', '0')); - } - - [Fact] - public static void TestHex4() - { - Assert.Equal(0xF029, RomByteEncoding.ByteParseHex4('F', '0', '2', '9')); - } - } - } -} \ No newline at end of file diff --git a/Diz.Test/MiscTests.cs b/Diz.Test/MiscTests.cs new file mode 100644 index 00000000..925b937a --- /dev/null +++ b/Diz.Test/MiscTests.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Linq; +using Diz.Core.serialization.xml_serializer; +using Diz.Core.util; +using Xunit; + +namespace Diz.Test +{ + public static class MiscTests + { + [Fact] + public static void TestHex() + { + Assert.Equal(0xF0, RomByteEncoding.ByteParseHex2('F', '0')); + } + + [Fact] + public static void TestHex4() + { + Assert.Equal(0xF029, RomByteEncoding.ByteParseHex4('F', '0', '2', '9')); + } + } +} \ No newline at end of file From fbf59f296ecaadf13fd49f1b486959427432a3a3 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 25 Oct 2020 21:40:22 -0400 Subject: [PATCH 120/136] optimize: tried a strategy with less memory copying for opening. kind of a wash for optimization but a little neater, so leaving it. - add unit tests for performance testing load/save --- .../xml_serializer/RomBytesXMLSerializer.cs | 45 +++++++-------- Diz.Test/LoadSaveTest.cs | 55 ++++++++++++++++++- 2 files changed, 73 insertions(+), 27 deletions(-) diff --git a/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs b/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs index af691fb8..27a8806d 100644 --- a/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs +++ b/Diz.Core/serialization/xml_serializer/RomBytesXMLSerializer.cs @@ -37,7 +37,7 @@ sealed class RomBytesSerializer : ISerializer private const bool CompressGroupBlock = true; private const bool CompressUsingTable1 = true; - private readonly int numTasksToUse = 10; + public int numTasksToUse = 5; // seems like the sweet spot public RomBytes Get(IFormatReader parameter) { @@ -49,30 +49,19 @@ public RomBytes Get(IFormatReader parameter) private RomByte[] DecodeAllBytes(List allLines) { if (numTasksToUse == 1) - return DecodeRomBytes(allLines, 0); + return DecodeRomBytes(allLines, 0, allLines.Count); + + var tasks = new List>(numTasksToUse); var nextIndex = 0; var workListCount = allLines.Count / numTasksToUse; - var tasks = new List>(numTasksToUse); - for (var t = 0; t < numTasksToUse; ++t) { - var lastThread = t == numTasksToUse - 1; - - if (lastThread) + if (t == numTasksToUse - 1) workListCount = allLines.Count - nextIndex; - var workList = new List(workListCount); - for (var i = 0; i < workListCount; ++i) - { - workList.Add(allLines[nextIndex + i]); - } - - // ReSharper disable once AccessToStaticMemberViaDerivedType - var index = nextIndex; - var task = Task.Run(() => DecodeRomBytes(workList, index)); - tasks.Add(task); + tasks.Add(CreateDecodeRomBytesTask(allLines, nextIndex, workListCount)); nextIndex += workListCount; } @@ -82,27 +71,31 @@ private RomByte[] DecodeAllBytes(List allLines) return continuation.Result.SelectMany(i => i).ToArray(); } - private static RomByte[] DecodeRomBytes(List lines, int startingLineNum) + private static Task CreateDecodeRomBytesTask(List allLines, int nextIndex, int workListCount) { - // perf: allocate all at once, don't use List.Add() one at a time - var romBytes = new RomByte[lines.Count]; - var currentLineNum = startingLineNum; + // ReSharper disable once AccessToStaticMemberViaDerivedType + return Task.Run(() => DecodeRomBytes(allLines, nextIndex, workListCount)); + } + private static RomByte[] DecodeRomBytes(IReadOnlyList allLines, int startIndex, int count) + { + // perf: allocate all at once, don't use List.Add() one at a time + var romBytes = new RomByte[count]; var romByteEncoding = new RomByteEncoding(); + var i = 0; try { - var i = 0; - foreach (var line in lines) + while (i < count) { + var line = allLines[startIndex + i]; romBytes[i] = romByteEncoding.DecodeRomByte(line); - currentLineNum++; - i++; + ++i; } } catch (Exception ex) { - ex.Data.Add("ParseLineNum", "Near line# " + currentLineNum); + ex.Data.Add("ParseLineNum", "Near line# " + (startIndex + i)); throw; } diff --git a/Diz.Test/LoadSaveTest.cs b/Diz.Test/LoadSaveTest.cs index c5fbeb52..cb2e011f 100644 --- a/Diz.Test/LoadSaveTest.cs +++ b/Diz.Test/LoadSaveTest.cs @@ -1,8 +1,10 @@ -using System.Linq; +using System.Diagnostics; using Diz.Core; using Diz.Core.model; +using Diz.Core.serialization; using Diz.Core.serialization.xml_serializer; using Xunit; +using Xunit.Abstractions; namespace Diz.Test { @@ -32,5 +34,56 @@ private void SerializeAndDeserialize() Assert.True(warning == ""); Assert.True(sampleProject.Equals(deserializedProject)); } + + private readonly ITestOutputHelper output; + + public LoadSaveTest(ITestOutputHelper output) + { + this.output = output; + } + + private static Project OpenProject(string openFile) + { + var projectFileManager = new ProjectFileManager(); + var (project, warning) = projectFileManager.Open(openFile); + + Assert.Equal(warning, ""); + Assert.True(project.Data.RomBytes.Count >= 0x1000 * 64); + + return project; + } + + [Fact(Skip = "Performance Test")] + private void OpenFilePerformanceTest() + { + var s = Stopwatch.StartNew(); + s.Start(); + + var openFile = "D:\\projects\\cthack\\src\\rom\\Chrono Trigger - CTHACKv3 - master copy.xml.dizraw"; + var project = OpenProject(openFile); + + s.Stop(); + + output.WriteLine($"runtime: {s.ElapsedMilliseconds:N0}, #bytes={project.Data.RomBytes.Count}"); + } + + + [Fact(Skip = "Performance Test")] + private void SaveFilePerformanceTest() + { + var openFile = "INSERT YOUR FILE HERE BEFORE RUNNING THIS TEST"; + var project = OpenProject(openFile); + + var s = Stopwatch.StartNew(); + s.Start(); + + var data = new ProjectXmlSerializer().Save(project); + + s.Stop(); + + Assert.True(data.Length != 0); + + output.WriteLine($"runtime: {s.ElapsedMilliseconds:N0}"); + } } } \ No newline at end of file From d9465da51926c3b11d15016c5705cd34594bd160 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 25 Oct 2020 22:05:14 -0400 Subject: [PATCH 121/136] fix test --- Diz.Test/LoadSaveTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Diz.Test/LoadSaveTest.cs b/Diz.Test/LoadSaveTest.cs index cb2e011f..0e7c2a4f 100644 --- a/Diz.Test/LoadSaveTest.cs +++ b/Diz.Test/LoadSaveTest.cs @@ -47,7 +47,7 @@ private static Project OpenProject(string openFile) var projectFileManager = new ProjectFileManager(); var (project, warning) = projectFileManager.Open(openFile); - Assert.Equal(warning, ""); + Assert.Equal("", warning); Assert.True(project.Data.RomBytes.Count >= 0x1000 * 64); return project; From dfa071a0869bac0dcf3752d5a4db6cbdb701dcc9 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sun, 25 Oct 2020 22:14:41 -0400 Subject: [PATCH 122/136] fix recursive issue w/visuals forms (merge error) --- .../RomFullVisualizer.Designer.cs | 119 +++++------------- 1 file changed, 29 insertions(+), 90 deletions(-) diff --git a/DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs index 859b9ebf..7258c388 100644 --- a/DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs +++ b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs @@ -1,13 +1,13 @@ -namespace DiztinGUIsh.window +namespace DiztinGUIsh.window.usercontrols { - partial class VisualizerForm + partial class RomFullVisualizer { - /// + /// /// Required designer variable. /// private System.ComponentModel.IContainer components = null; - /// + /// /// Clean up any resources being used. /// /// true if managed resources should be disposed; otherwise, false. @@ -20,103 +20,42 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } - #region Windows Form Designer generated code + #region Component Designer generated code - /// - /// Required method for Designer support - do not modify + /// + /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { - this.panelTop = new System.Windows.Forms.Panel(); - this.panelLegend = new System.Windows.Forms.Panel(); - this.bankLegend1 = new DiztinGUIsh.window.usercontrols.BankLegend(); - this.panelBottom = new System.Windows.Forms.Panel(); - this.romFullVisualizer1 = new DiztinGUIsh.window.usercontrols.RomFullVisualizer(); - this.panelTop.SuspendLayout(); - this.panelLegend.SuspendLayout(); - this.panelBottom.SuspendLayout(); + this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); this.SuspendLayout(); - // - // panelTop - // - this.panelTop.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.panelTop.Controls.Add(this.panelLegend); - this.panelTop.Dock = System.Windows.Forms.DockStyle.Top; - this.panelTop.Location = new System.Drawing.Point(0, 0); - this.panelTop.Name = "panelTop"; - this.panelTop.Size = new System.Drawing.Size(765, 154); - this.panelTop.TabIndex = 1; - // - // panelLegend - // - this.panelLegend.Controls.Add(this.bankLegend1); - this.panelLegend.Dock = System.Windows.Forms.DockStyle.Left; - this.panelLegend.Location = new System.Drawing.Point(0, 0); - this.panelLegend.Name = "panelLegend"; - this.panelLegend.Size = new System.Drawing.Size(567, 152); - this.panelLegend.TabIndex = 0; - // - // bankLegend1 - // - this.bankLegend1.AutoScroll = true; - this.bankLegend1.AutoSize = true; - this.bankLegend1.Dock = System.Windows.Forms.DockStyle.Fill; - this.bankLegend1.Location = new System.Drawing.Point(0, 0); - this.bankLegend1.Name = "bankLegend1"; - this.bankLegend1.Size = new System.Drawing.Size(567, 152); - this.bankLegend1.TabIndex = 0; - // - // panelBottom - // - this.panelBottom.AutoScroll = true; - this.panelBottom.AutoSize = true; - this.panelBottom.Controls.Add(this.romFullVisualizer1); - this.panelBottom.Dock = System.Windows.Forms.DockStyle.Fill; - this.panelBottom.Location = new System.Drawing.Point(0, 154); - this.panelBottom.Name = "panelBottom"; - this.panelBottom.Size = new System.Drawing.Size(765, 363); - this.panelBottom.TabIndex = 2; - // - // romFullVisualizer1 - // - this.romFullVisualizer1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.romFullVisualizer1.Location = new System.Drawing.Point(3, 3); - this.romFullVisualizer1.MaximumSize = new System.Drawing.Size(100, 100); - this.romFullVisualizer1.Name = "romFullVisualizer1"; - this.romFullVisualizer1.Project = null; - this.romFullVisualizer1.Size = new System.Drawing.Size(100, 100); - this.romFullVisualizer1.TabIndex = 0; - // - // VisualizerForm - // + // + // flowLayoutPanel1 + // + this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; + this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.flowLayoutPanel1.MinimumSize = new System.Drawing.Size(100, 100); + this.flowLayoutPanel1.Name = "flowLayoutPanel1"; + this.flowLayoutPanel1.Size = new System.Drawing.Size(100, 100); + this.flowLayoutPanel1.TabIndex = 0; + // + // RomFullVisualizer + // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.AutoScroll = true; - this.ClientSize = new System.Drawing.Size(765, 517); - this.Controls.Add(this.panelBottom); - this.Controls.Add(this.panelTop); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow; - this.Name = "VisualizerForm"; - this.ShowIcon = false; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "ROM Visualizer"; - this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.VisualizerForm_FormClosing); - this.Load += new System.EventHandler(this.VisualizerForm_Load); - this.panelTop.ResumeLayout(false); - this.panelLegend.ResumeLayout(false); - this.panelLegend.PerformLayout(); - this.panelBottom.ResumeLayout(false); + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.Controls.Add(this.flowLayoutPanel1); + this.MaximumSize = new System.Drawing.Size(100, 100); + this.Name = "RomFullVisualizer"; + this.Size = new System.Drawing.Size(100, 100); this.ResumeLayout(false); - this.PerformLayout(); } #endregion - private System.Windows.Forms.Panel panelTop; - private System.Windows.Forms.Panel panelLegend; - private System.Windows.Forms.Panel panelBottom; - private usercontrols.BankLegend bankLegend1; - private usercontrols.RomFullVisualizer romFullVisualizer1; + + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; } -} \ No newline at end of file +} From 3b3c59fd94c08f03d8790afecc232f0489b8c48d Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Mon, 26 Oct 2020 00:04:37 -0400 Subject: [PATCH 123/136] visualizer solid pogress, WIP --- Diz.Core/model/RomBytes.cs | 4 + Diz.Core/util/RomVisual.cs | 12 +- DiztinGUIsh/window/VisualizerForm.Designer.cs | 31 ++-- DiztinGUIsh/window/VisualizerForm.cs | 2 + .../RomBankVisualizer.Designer.cs | 46 +++--- .../window/usercontrols/RomBankVisualizer.cs | 10 +- .../RomFullVisualizer.Designer.cs | 151 +++++++++++++++++- .../window/usercontrols/RomFullVisualizer.cs | 15 +- .../window/usercontrols/RomImage.Designer.cs | 5 +- DiztinGUIsh/window/usercontrols/RomImage.cs | 8 +- 10 files changed, 220 insertions(+), 64 deletions(-) diff --git a/Diz.Core/model/RomBytes.cs b/Diz.Core/model/RomBytes.cs index 63cbd99f..368b0f2a 100644 --- a/Diz.Core/model/RomBytes.cs +++ b/Diz.Core/model/RomBytes.cs @@ -45,6 +45,10 @@ public RomBytes() public void SetFrom(RomByte[] romBytes) { Bytes = new ObservableCollection(romBytes); + for (var i = 0; i < romBytes.Length; ++i) + { + romBytes[i].SetCachedOffset(i); + } } public int Count => Bytes.Count; diff --git a/Diz.Core/util/RomVisual.cs b/Diz.Core/util/RomVisual.cs index 4c04be67..1f5735fd 100644 --- a/Diz.Core/util/RomVisual.cs +++ b/Diz.Core/util/RomVisual.cs @@ -26,7 +26,7 @@ public Project Project if (project?.Data == null) return; project.Data.RomBytes.PropertyChanged += RomBytes_PropertyChanged; project.Data.RomBytes.CollectionChanged += RomBytes_CollectionChanged; - InvalidateImage(); + // InvalidateImage(); } } @@ -69,7 +69,7 @@ public int LengthOverride get => lengthOverride; set { - if (value != -1 && (value == 0 || RomStartingOffset + value >= project.Data.RomBytes.Count)) + if (value != -1 && (value == 0 || RomStartingOffset + value > project.Data.RomBytes.Count)) throw new ArgumentOutOfRangeException(); lengthOverride = value; @@ -78,6 +78,8 @@ public int LengthOverride public int PixelCount => lengthOverride != -1 ? lengthOverride : project.Data.RomBytes.Count; + private int RomMaxOffsetAllowed => RomStartingOffset + PixelCount - 1; + public int Width { get => width; @@ -194,7 +196,11 @@ private void RegenerateImage() private IEnumerable ConsumeRomDirtyBytes() { if (AllDirty) - return Data.RomBytes.ToList(); + return Data.RomBytes + .Where(rb => + rb.Offset >= RomStartingOffset && rb.Offset <= RomMaxOffsetAllowed + ) + .ToList(); IEnumerable romBytes; lock (dirtyLock) diff --git a/DiztinGUIsh/window/VisualizerForm.Designer.cs b/DiztinGUIsh/window/VisualizerForm.Designer.cs index 859b9ebf..34a16095 100644 --- a/DiztinGUIsh/window/VisualizerForm.Designer.cs +++ b/DiztinGUIsh/window/VisualizerForm.Designer.cs @@ -37,9 +37,9 @@ private void InitializeComponent() this.panelLegend.SuspendLayout(); this.panelBottom.SuspendLayout(); this.SuspendLayout(); - // + // // panelTop - // + // this.panelTop.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.panelTop.Controls.Add(this.panelLegend); this.panelTop.Dock = System.Windows.Forms.DockStyle.Top; @@ -47,18 +47,18 @@ private void InitializeComponent() this.panelTop.Name = "panelTop"; this.panelTop.Size = new System.Drawing.Size(765, 154); this.panelTop.TabIndex = 1; - // + // // panelLegend - // + // this.panelLegend.Controls.Add(this.bankLegend1); this.panelLegend.Dock = System.Windows.Forms.DockStyle.Left; this.panelLegend.Location = new System.Drawing.Point(0, 0); this.panelLegend.Name = "panelLegend"; this.panelLegend.Size = new System.Drawing.Size(567, 152); this.panelLegend.TabIndex = 0; - // + // // bankLegend1 - // + // this.bankLegend1.AutoScroll = true; this.bankLegend1.AutoSize = true; this.bankLegend1.Dock = System.Windows.Forms.DockStyle.Fill; @@ -66,9 +66,9 @@ private void InitializeComponent() this.bankLegend1.Name = "bankLegend1"; this.bankLegend1.Size = new System.Drawing.Size(567, 152); this.bankLegend1.TabIndex = 0; - // + // // panelBottom - // + // this.panelBottom.AutoScroll = true; this.panelBottom.AutoSize = true; this.panelBottom.Controls.Add(this.romFullVisualizer1); @@ -77,19 +77,18 @@ private void InitializeComponent() this.panelBottom.Name = "panelBottom"; this.panelBottom.Size = new System.Drawing.Size(765, 363); this.panelBottom.TabIndex = 2; - // + // // romFullVisualizer1 - // - this.romFullVisualizer1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.romFullVisualizer1.Location = new System.Drawing.Point(3, 3); - this.romFullVisualizer1.MaximumSize = new System.Drawing.Size(100, 100); + // + this.romFullVisualizer1.Location = new System.Drawing.Point(3, 0); + this.romFullVisualizer1.MinimumSize = new System.Drawing.Size(100, 100); this.romFullVisualizer1.Name = "romFullVisualizer1"; this.romFullVisualizer1.Project = null; - this.romFullVisualizer1.Size = new System.Drawing.Size(100, 100); + this.romFullVisualizer1.Size = new System.Drawing.Size(666, 335); this.romFullVisualizer1.TabIndex = 0; - // + // // VisualizerForm - // + // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScroll = true; diff --git a/DiztinGUIsh/window/VisualizerForm.cs b/DiztinGUIsh/window/VisualizerForm.cs index 11196aab..9b3a9726 100644 --- a/DiztinGUIsh/window/VisualizerForm.cs +++ b/DiztinGUIsh/window/VisualizerForm.cs @@ -30,6 +30,8 @@ private void VisualizerForm_Load(object sender, System.EventArgs e) // hack to make room for the scrollbar // I wish docking dealt with this, or maybe I set it up wrong... Width = romFullVisualizer1.Width + 40; + + romFullVisualizer1.Project = mainWindow.Project; } private void VisualizerForm_FormClosing(object sender, FormClosingEventArgs e) diff --git a/DiztinGUIsh/window/usercontrols/RomBankVisualizer.Designer.cs b/DiztinGUIsh/window/usercontrols/RomBankVisualizer.Designer.cs index 851ddd97..4b99791f 100644 --- a/DiztinGUIsh/window/usercontrols/RomBankVisualizer.Designer.cs +++ b/DiztinGUIsh/window/usercontrols/RomBankVisualizer.Designer.cs @@ -30,8 +30,8 @@ private void InitializeComponent() { this.lblBankName = new System.Windows.Forms.Label(); this.romImage1 = new DiztinGUIsh.window.usercontrols.RomImage(); - this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); - this.tableLayoutPanel1.SuspendLayout(); + this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); + this.flowLayoutPanel1.SuspendLayout(); this.SuspendLayout(); // // lblBankName @@ -46,26 +46,26 @@ private void InitializeComponent() // // romImage1 // - this.romImage1.Dock = System.Windows.Forms.DockStyle.Fill; - this.romImage1.Location = new System.Drawing.Point(60, 3); + this.romImage1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(128))))); + this.romImage1.Dock = System.Windows.Forms.DockStyle.Bottom; + this.romImage1.Location = new System.Drawing.Point(60, 18); + this.romImage1.MinimumSize = new System.Drawing.Size(400, 10); this.romImage1.Name = "romImage1"; this.romImage1.Project = null; - this.romImage1.Size = new System.Drawing.Size(663, 165); + this.romImage1.Size = new System.Drawing.Size(500, 10); this.romImage1.TabIndex = 1; // - // tableLayoutPanel1 + // flowLayoutPanel1 // - this.tableLayoutPanel1.ColumnCount = 2; - this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel1.Controls.Add(this.romImage1, 0, 0); - this.tableLayoutPanel1.Controls.Add(this.lblBankName, 0, 0); - this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); - this.tableLayoutPanel1.Name = "tableLayoutPanel1"; - this.tableLayoutPanel1.RowCount = 1; - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel1.Size = new System.Drawing.Size(726, 171); - this.tableLayoutPanel1.TabIndex = 2; + this.flowLayoutPanel1.AutoSize = true; + this.flowLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.flowLayoutPanel1.Controls.Add(this.lblBankName); + this.flowLayoutPanel1.Controls.Add(this.romImage1); + this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.flowLayoutPanel1.Name = "flowLayoutPanel1"; + this.flowLayoutPanel1.Size = new System.Drawing.Size(563, 31); + this.flowLayoutPanel1.TabIndex = 2; // // RomBankVisualizer // @@ -73,12 +73,14 @@ private void InitializeComponent() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoSize = true; this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.Controls.Add(this.tableLayoutPanel1); + this.BackColor = System.Drawing.Color.SeaGreen; + this.Controls.Add(this.flowLayoutPanel1); this.Name = "RomBankVisualizer"; - this.Size = new System.Drawing.Size(729, 174); - this.tableLayoutPanel1.ResumeLayout(false); - this.tableLayoutPanel1.PerformLayout(); + this.Size = new System.Drawing.Size(563, 31); + this.flowLayoutPanel1.ResumeLayout(false); + this.flowLayoutPanel1.PerformLayout(); this.ResumeLayout(false); + this.PerformLayout(); } @@ -86,6 +88,6 @@ private void InitializeComponent() private System.Windows.Forms.Label lblBankName; private RomImage romImage1; - private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; } } diff --git a/DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs b/DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs index 60a147e9..73c6bc24 100644 --- a/DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs +++ b/DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs @@ -12,7 +12,7 @@ namespace DiztinGUIsh.window.usercontrols { public partial class RomBankVisualizer : UserControl { - public event EventHandler RedrawOccurred; + //public event EventHandler RedrawOccurred; public RomBankVisualizer(Project project, int startingRomOffset, int length, string bankName) { @@ -23,17 +23,17 @@ public RomBankVisualizer(Project project, int startingRomOffset, int length, str romImage1.RomVisual.LengthOverride = length; lblBankName.Text = bankName; - romImage1.RedrawOccurred += RomImage1_RedrawOccurred; + //romImage1.RedrawOccurred += RomImage1_RedrawOccurred; } private void RomImage1_RedrawOccurred(object sender, System.EventArgs e) { - OnRedrawOccurred(); + //OnRedrawOccurred(); } - protected virtual void OnRedrawOccurred() + private void OnRedrawOccurred() { - RedrawOccurred?.Invoke(this, EventArgs.Empty); + //RedrawOccurred?.Invoke(this, EventArgs.Empty); } } } diff --git a/DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs index 7258c388..3e1c13a2 100644 --- a/DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs +++ b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs @@ -22,40 +22,177 @@ protected override void Dispose(bool disposing) #region Component Designer generated code - /// - /// Required method for Designer support - do not modify + /// + /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); + this.button1 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); + this.button3 = new System.Windows.Forms.Button(); + this.button4 = new System.Windows.Forms.Button(); + this.button5 = new System.Windows.Forms.Button(); + this.button6 = new System.Windows.Forms.Button(); + this.button7 = new System.Windows.Forms.Button(); + this.button8 = new System.Windows.Forms.Button(); + this.button9 = new System.Windows.Forms.Button(); + this.button10 = new System.Windows.Forms.Button(); + this.button11 = new System.Windows.Forms.Button(); + this.flowLayoutPanel1.SuspendLayout(); this.SuspendLayout(); // // flowLayoutPanel1 // - this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.flowLayoutPanel1.AutoSize = true; + this.flowLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.flowLayoutPanel1.BackColor = System.Drawing.SystemColors.AppWorkspace; + this.flowLayoutPanel1.Controls.Add(this.button1); + this.flowLayoutPanel1.Controls.Add(this.button2); + this.flowLayoutPanel1.Controls.Add(this.button3); + this.flowLayoutPanel1.Controls.Add(this.button4); + this.flowLayoutPanel1.Controls.Add(this.button5); + this.flowLayoutPanel1.Controls.Add(this.button6); + this.flowLayoutPanel1.Controls.Add(this.button7); + this.flowLayoutPanel1.Controls.Add(this.button8); + this.flowLayoutPanel1.Controls.Add(this.button9); + this.flowLayoutPanel1.Controls.Add(this.button10); + this.flowLayoutPanel1.Controls.Add(this.button11); this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0); this.flowLayoutPanel1.MinimumSize = new System.Drawing.Size(100, 100); this.flowLayoutPanel1.Name = "flowLayoutPanel1"; - this.flowLayoutPanel1.Size = new System.Drawing.Size(100, 100); + this.flowLayoutPanel1.Size = new System.Drawing.Size(376, 968); this.flowLayoutPanel1.TabIndex = 0; // + // button1 + // + this.button1.Location = new System.Drawing.Point(3, 3); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(370, 82); + this.button1.TabIndex = 0; + this.button1.Text = "button1"; + this.button1.UseVisualStyleBackColor = true; + // + // button2 + // + this.button2.Location = new System.Drawing.Point(3, 91); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(370, 82); + this.button2.TabIndex = 1; + this.button2.Text = "button2"; + this.button2.UseVisualStyleBackColor = true; + // + // button3 + // + this.button3.Location = new System.Drawing.Point(3, 179); + this.button3.Name = "button3"; + this.button3.Size = new System.Drawing.Size(370, 82); + this.button3.TabIndex = 2; + this.button3.Text = "button3"; + this.button3.UseVisualStyleBackColor = true; + // + // button4 + // + this.button4.Location = new System.Drawing.Point(3, 267); + this.button4.Name = "button4"; + this.button4.Size = new System.Drawing.Size(370, 82); + this.button4.TabIndex = 3; + this.button4.Text = "button4"; + this.button4.UseVisualStyleBackColor = true; + // + // button5 + // + this.button5.Location = new System.Drawing.Point(3, 355); + this.button5.Name = "button5"; + this.button5.Size = new System.Drawing.Size(370, 82); + this.button5.TabIndex = 4; + this.button5.Text = "button5"; + this.button5.UseVisualStyleBackColor = true; + // + // button6 + // + this.button6.Location = new System.Drawing.Point(3, 443); + this.button6.Name = "button6"; + this.button6.Size = new System.Drawing.Size(370, 82); + this.button6.TabIndex = 5; + this.button6.Text = "button6"; + this.button6.UseVisualStyleBackColor = true; + // + // button7 + // + this.button7.Location = new System.Drawing.Point(3, 531); + this.button7.Name = "button7"; + this.button7.Size = new System.Drawing.Size(370, 82); + this.button7.TabIndex = 6; + this.button7.Text = "button7"; + this.button7.UseVisualStyleBackColor = true; + // + // button8 + // + this.button8.Location = new System.Drawing.Point(3, 619); + this.button8.Name = "button8"; + this.button8.Size = new System.Drawing.Size(370, 82); + this.button8.TabIndex = 7; + this.button8.Text = "button8"; + this.button8.UseVisualStyleBackColor = true; + // + // button9 + // + this.button9.Location = new System.Drawing.Point(3, 707); + this.button9.Name = "button9"; + this.button9.Size = new System.Drawing.Size(370, 82); + this.button9.TabIndex = 8; + this.button9.Text = "button9"; + this.button9.UseVisualStyleBackColor = true; + // + // button10 + // + this.button10.Location = new System.Drawing.Point(3, 795); + this.button10.Name = "button10"; + this.button10.Size = new System.Drawing.Size(370, 82); + this.button10.TabIndex = 9; + this.button10.Text = "button10"; + this.button10.UseVisualStyleBackColor = true; + // + // button11 + // + this.button11.Location = new System.Drawing.Point(3, 883); + this.button11.Name = "button11"; + this.button11.Size = new System.Drawing.Size(370, 82); + this.button11.TabIndex = 10; + this.button11.Text = "button11"; + this.button11.UseVisualStyleBackColor = true; + // // RomFullVisualizer // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.AutoSize = true; this.Controls.Add(this.flowLayoutPanel1); - this.MaximumSize = new System.Drawing.Size(100, 100); + this.MinimumSize = new System.Drawing.Size(100, 100); this.Name = "RomFullVisualizer"; - this.Size = new System.Drawing.Size(100, 100); + this.Size = new System.Drawing.Size(379, 971); + this.flowLayoutPanel1.ResumeLayout(false); this.ResumeLayout(false); + this.PerformLayout(); } #endregion private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.Button button3; + private System.Windows.Forms.Button button4; + private System.Windows.Forms.Button button5; + private System.Windows.Forms.Button button6; + private System.Windows.Forms.Button button7; + private System.Windows.Forms.Button button8; + private System.Windows.Forms.Button button9; + private System.Windows.Forms.Button button10; + private System.Windows.Forms.Button button11; } } diff --git a/DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs index 6032c129..a5e78d8f 100644 --- a/DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs +++ b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Windows.Forms; using Diz.Core.model; @@ -17,16 +18,18 @@ public Project Project get => project; set { - UpdateControls(); + DeleteControls(); project = value; + if (project != null) + Init(); } } - private void UpdateControls() + private void DeleteControls() { - foreach (var rbv in BankControls) + foreach (var rbv in BankControls.Where(rbv => Controls.Contains(rbv))) { - // TODO + Controls.Remove(rbv); } } @@ -61,8 +64,8 @@ private void AddNewControl(RomBankVisualizer bankControl) BankControls.Add(bankControl); flowLayoutPanel1.Controls.Add(bankControl); - flowLayoutPanel1.AutoSize = true; - flowLayoutPanel1.AutoSizeMode = AutoSizeMode.GrowAndShrink; + //flowLayoutPanel1.AutoSize = true; + //flowLayoutPanel1.AutoSizeMode = AutoSizeMode.GrowAndShrink; } /*private void BankControl_RedrawOccurred(object sender, EventArgs e) diff --git a/DiztinGUIsh/window/usercontrols/RomImage.Designer.cs b/DiztinGUIsh/window/usercontrols/RomImage.Designer.cs index c20aa7cc..2b889aa6 100644 --- a/DiztinGUIsh/window/usercontrols/RomImage.Designer.cs +++ b/DiztinGUIsh/window/usercontrols/RomImage.Designer.cs @@ -42,9 +42,12 @@ private void InitializeComponent() // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoSize = true; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(128))))); this.DoubleBuffered = true; + this.MinimumSize = new System.Drawing.Size(1024, 100); this.Name = "RomImage"; - this.Size = new System.Drawing.Size(996, 178); + this.Size = new System.Drawing.Size(1142, 202); this.Load += new System.EventHandler(this.RomImage_Load); this.Paint += new System.Windows.Forms.PaintEventHandler(this.RomImage_Paint); this.ResumeLayout(false); diff --git a/DiztinGUIsh/window/usercontrols/RomImage.cs b/DiztinGUIsh/window/usercontrols/RomImage.cs index ae3133dc..9ae9106d 100644 --- a/DiztinGUIsh/window/usercontrols/RomImage.cs +++ b/DiztinGUIsh/window/usercontrols/RomImage.cs @@ -32,7 +32,7 @@ private void RomImage_Load(object sender, System.EventArgs e) private void RomImage_Paint(object sender, PaintEventArgs e) { - Redraw(e.Graphics); + // Redraw(e.Graphics); } private void Redraw(Graphics graphics = null) @@ -65,10 +65,10 @@ private void timer1_Tick(object sender, System.EventArgs e) protected virtual void OnRedrawOccurred() { - Width = RomVisual.Width; - Height = RomVisual.Height; + //Width = RomVisual.Width; + //Height = RomVisual.Height; - RedrawOccurred?.Invoke(this, EventArgs.Empty); + // RedrawOccurred?.Invoke(this, EventArgs.Empty); } } } From e996c54734be7a0c3c40496efa274f18dbb351e5 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Mon, 26 Oct 2020 00:20:44 -0400 Subject: [PATCH 124/136] fully working visualizer --- .../RomBankVisualizer.Designer.cs | 18 ++- .../RomFullVisualizer.Designer.cs | 140 +----------------- .../window/usercontrols/RomImage.Designer.cs | 2 - DiztinGUIsh/window/usercontrols/RomImage.cs | 20 ++- 4 files changed, 23 insertions(+), 157 deletions(-) diff --git a/DiztinGUIsh/window/usercontrols/RomBankVisualizer.Designer.cs b/DiztinGUIsh/window/usercontrols/RomBankVisualizer.Designer.cs index 4b99791f..41d8a67b 100644 --- a/DiztinGUIsh/window/usercontrols/RomBankVisualizer.Designer.cs +++ b/DiztinGUIsh/window/usercontrols/RomBankVisualizer.Designer.cs @@ -39,20 +39,22 @@ private void InitializeComponent() this.lblBankName.AutoSize = true; this.lblBankName.Font = new System.Drawing.Font("Microsoft Sans Serif", 20.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lblBankName.Location = new System.Drawing.Point(3, 0); + this.lblBankName.MinimumSize = new System.Drawing.Size(60, 0); this.lblBankName.Name = "lblBankName"; - this.lblBankName.Size = new System.Drawing.Size(51, 31); + this.lblBankName.Size = new System.Drawing.Size(60, 31); this.lblBankName.TabIndex = 0; this.lblBankName.Text = "C0"; // // romImage1 // + this.romImage1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.romImage1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(128))))); - this.romImage1.Dock = System.Windows.Forms.DockStyle.Bottom; - this.romImage1.Location = new System.Drawing.Point(60, 18); + this.romImage1.Location = new System.Drawing.Point(66, 0); + this.romImage1.Margin = new System.Windows.Forms.Padding(0); this.romImage1.MinimumSize = new System.Drawing.Size(400, 10); this.romImage1.Name = "romImage1"; this.romImage1.Project = null; - this.romImage1.Size = new System.Drawing.Size(500, 10); + this.romImage1.Size = new System.Drawing.Size(400, 42); this.romImage1.TabIndex = 1; // // flowLayoutPanel1 @@ -63,8 +65,9 @@ private void InitializeComponent() this.flowLayoutPanel1.Controls.Add(this.romImage1); this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.flowLayoutPanel1.Margin = new System.Windows.Forms.Padding(0); this.flowLayoutPanel1.Name = "flowLayoutPanel1"; - this.flowLayoutPanel1.Size = new System.Drawing.Size(563, 31); + this.flowLayoutPanel1.Size = new System.Drawing.Size(466, 42); this.flowLayoutPanel1.TabIndex = 2; // // RomBankVisualizer @@ -73,10 +76,11 @@ private void InitializeComponent() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoSize = true; this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.BackColor = System.Drawing.Color.SeaGreen; + this.BackColor = System.Drawing.SystemColors.Control; + this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.Controls.Add(this.flowLayoutPanel1); this.Name = "RomBankVisualizer"; - this.Size = new System.Drawing.Size(563, 31); + this.Size = new System.Drawing.Size(466, 42); this.flowLayoutPanel1.ResumeLayout(false); this.flowLayoutPanel1.PerformLayout(); this.ResumeLayout(false); diff --git a/DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs index 3e1c13a2..3f882658 100644 --- a/DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs +++ b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.Designer.cs @@ -29,142 +29,20 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); - this.button1 = new System.Windows.Forms.Button(); - this.button2 = new System.Windows.Forms.Button(); - this.button3 = new System.Windows.Forms.Button(); - this.button4 = new System.Windows.Forms.Button(); - this.button5 = new System.Windows.Forms.Button(); - this.button6 = new System.Windows.Forms.Button(); - this.button7 = new System.Windows.Forms.Button(); - this.button8 = new System.Windows.Forms.Button(); - this.button9 = new System.Windows.Forms.Button(); - this.button10 = new System.Windows.Forms.Button(); - this.button11 = new System.Windows.Forms.Button(); - this.flowLayoutPanel1.SuspendLayout(); this.SuspendLayout(); // // flowLayoutPanel1 // this.flowLayoutPanel1.AutoSize = true; this.flowLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.flowLayoutPanel1.BackColor = System.Drawing.SystemColors.AppWorkspace; - this.flowLayoutPanel1.Controls.Add(this.button1); - this.flowLayoutPanel1.Controls.Add(this.button2); - this.flowLayoutPanel1.Controls.Add(this.button3); - this.flowLayoutPanel1.Controls.Add(this.button4); - this.flowLayoutPanel1.Controls.Add(this.button5); - this.flowLayoutPanel1.Controls.Add(this.button6); - this.flowLayoutPanel1.Controls.Add(this.button7); - this.flowLayoutPanel1.Controls.Add(this.button8); - this.flowLayoutPanel1.Controls.Add(this.button9); - this.flowLayoutPanel1.Controls.Add(this.button10); - this.flowLayoutPanel1.Controls.Add(this.button11); + this.flowLayoutPanel1.BackColor = System.Drawing.SystemColors.Control; this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0); this.flowLayoutPanel1.MinimumSize = new System.Drawing.Size(100, 100); this.flowLayoutPanel1.Name = "flowLayoutPanel1"; - this.flowLayoutPanel1.Size = new System.Drawing.Size(376, 968); + this.flowLayoutPanel1.Size = new System.Drawing.Size(100, 100); this.flowLayoutPanel1.TabIndex = 0; // - // button1 - // - this.button1.Location = new System.Drawing.Point(3, 3); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(370, 82); - this.button1.TabIndex = 0; - this.button1.Text = "button1"; - this.button1.UseVisualStyleBackColor = true; - // - // button2 - // - this.button2.Location = new System.Drawing.Point(3, 91); - this.button2.Name = "button2"; - this.button2.Size = new System.Drawing.Size(370, 82); - this.button2.TabIndex = 1; - this.button2.Text = "button2"; - this.button2.UseVisualStyleBackColor = true; - // - // button3 - // - this.button3.Location = new System.Drawing.Point(3, 179); - this.button3.Name = "button3"; - this.button3.Size = new System.Drawing.Size(370, 82); - this.button3.TabIndex = 2; - this.button3.Text = "button3"; - this.button3.UseVisualStyleBackColor = true; - // - // button4 - // - this.button4.Location = new System.Drawing.Point(3, 267); - this.button4.Name = "button4"; - this.button4.Size = new System.Drawing.Size(370, 82); - this.button4.TabIndex = 3; - this.button4.Text = "button4"; - this.button4.UseVisualStyleBackColor = true; - // - // button5 - // - this.button5.Location = new System.Drawing.Point(3, 355); - this.button5.Name = "button5"; - this.button5.Size = new System.Drawing.Size(370, 82); - this.button5.TabIndex = 4; - this.button5.Text = "button5"; - this.button5.UseVisualStyleBackColor = true; - // - // button6 - // - this.button6.Location = new System.Drawing.Point(3, 443); - this.button6.Name = "button6"; - this.button6.Size = new System.Drawing.Size(370, 82); - this.button6.TabIndex = 5; - this.button6.Text = "button6"; - this.button6.UseVisualStyleBackColor = true; - // - // button7 - // - this.button7.Location = new System.Drawing.Point(3, 531); - this.button7.Name = "button7"; - this.button7.Size = new System.Drawing.Size(370, 82); - this.button7.TabIndex = 6; - this.button7.Text = "button7"; - this.button7.UseVisualStyleBackColor = true; - // - // button8 - // - this.button8.Location = new System.Drawing.Point(3, 619); - this.button8.Name = "button8"; - this.button8.Size = new System.Drawing.Size(370, 82); - this.button8.TabIndex = 7; - this.button8.Text = "button8"; - this.button8.UseVisualStyleBackColor = true; - // - // button9 - // - this.button9.Location = new System.Drawing.Point(3, 707); - this.button9.Name = "button9"; - this.button9.Size = new System.Drawing.Size(370, 82); - this.button9.TabIndex = 8; - this.button9.Text = "button9"; - this.button9.UseVisualStyleBackColor = true; - // - // button10 - // - this.button10.Location = new System.Drawing.Point(3, 795); - this.button10.Name = "button10"; - this.button10.Size = new System.Drawing.Size(370, 82); - this.button10.TabIndex = 9; - this.button10.Text = "button10"; - this.button10.UseVisualStyleBackColor = true; - // - // button11 - // - this.button11.Location = new System.Drawing.Point(3, 883); - this.button11.Name = "button11"; - this.button11.Size = new System.Drawing.Size(370, 82); - this.button11.TabIndex = 10; - this.button11.Text = "button11"; - this.button11.UseVisualStyleBackColor = true; - // // RomFullVisualizer // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -173,8 +51,7 @@ private void InitializeComponent() this.Controls.Add(this.flowLayoutPanel1); this.MinimumSize = new System.Drawing.Size(100, 100); this.Name = "RomFullVisualizer"; - this.Size = new System.Drawing.Size(379, 971); - this.flowLayoutPanel1.ResumeLayout(false); + this.Size = new System.Drawing.Size(103, 103); this.ResumeLayout(false); this.PerformLayout(); @@ -183,16 +60,5 @@ private void InitializeComponent() #endregion private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; - private System.Windows.Forms.Button button1; - private System.Windows.Forms.Button button2; - private System.Windows.Forms.Button button3; - private System.Windows.Forms.Button button4; - private System.Windows.Forms.Button button5; - private System.Windows.Forms.Button button6; - private System.Windows.Forms.Button button7; - private System.Windows.Forms.Button button8; - private System.Windows.Forms.Button button9; - private System.Windows.Forms.Button button10; - private System.Windows.Forms.Button button11; } } diff --git a/DiztinGUIsh/window/usercontrols/RomImage.Designer.cs b/DiztinGUIsh/window/usercontrols/RomImage.Designer.cs index 2b889aa6..b6726163 100644 --- a/DiztinGUIsh/window/usercontrols/RomImage.Designer.cs +++ b/DiztinGUIsh/window/usercontrols/RomImage.Designer.cs @@ -42,10 +42,8 @@ private void InitializeComponent() // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.AutoSize = true; this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(128))))); this.DoubleBuffered = true; - this.MinimumSize = new System.Drawing.Size(1024, 100); this.Name = "RomImage"; this.Size = new System.Drawing.Size(1142, 202); this.Load += new System.EventHandler(this.RomImage_Load); diff --git a/DiztinGUIsh/window/usercontrols/RomImage.cs b/DiztinGUIsh/window/usercontrols/RomImage.cs index 9ae9106d..32b4823d 100644 --- a/DiztinGUIsh/window/usercontrols/RomImage.cs +++ b/DiztinGUIsh/window/usercontrols/RomImage.cs @@ -10,8 +10,6 @@ namespace DiztinGUIsh.window.usercontrols { public partial class RomImage : UserControl { - public event EventHandler RedrawOccurred; - public RomVisual RomVisual { get; } = new RomVisual(); public Project Project @@ -28,16 +26,18 @@ private void RomImage_Load(object sender, System.EventArgs e) { // if there's a reason to track ROM byte changes, hook in here // romVisual.MarkedDirty += RomVisual_MarkedDirty; + + UpdateDimensions(); } private void RomImage_Paint(object sender, PaintEventArgs e) { - // Redraw(e.Graphics); + Redraw(e.Graphics); } private void Redraw(Graphics graphics = null) { - if (RomVisual?.Bitmap == null) + if (RomVisual?.Bitmap == null || updatingDimensions) return; graphics ??= CreateGraphics(); @@ -45,8 +45,6 @@ private void Redraw(Graphics graphics = null) var width = RomVisual.Bitmap.Width; var height = RomVisual.Bitmap.Height; graphics.DrawImage(RomVisual.Bitmap, 0, 0, width, height); - - OnRedrawOccurred(); } private void RedrawIfNeeded() @@ -63,12 +61,12 @@ private void timer1_Tick(object sender, System.EventArgs e) RedrawIfNeeded(); } - protected virtual void OnRedrawOccurred() - { - //Width = RomVisual.Width; - //Height = RomVisual.Height; + private bool updatingDimensions = false; - // RedrawOccurred?.Invoke(this, EventArgs.Empty); + private void UpdateDimensions() + { + Width = RomVisual.Width; + Height = RomVisual.Height; } } } From 809e6d8d8696ae8f1bda27d25cb0194f82f9fe11 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Mon, 26 Oct 2020 00:22:40 -0400 Subject: [PATCH 125/136] remove some unused visuals code --- .../window/usercontrols/RomBankVisualizer.cs | 14 -------------- .../window/usercontrols/RomFullVisualizer.cs | 17 ----------------- DiztinGUIsh/window/usercontrols/RomImage.cs | 7 ++----- 3 files changed, 2 insertions(+), 36 deletions(-) diff --git a/DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs b/DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs index 73c6bc24..d060b176 100644 --- a/DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs +++ b/DiztinGUIsh/window/usercontrols/RomBankVisualizer.cs @@ -12,8 +12,6 @@ namespace DiztinGUIsh.window.usercontrols { public partial class RomBankVisualizer : UserControl { - //public event EventHandler RedrawOccurred; - public RomBankVisualizer(Project project, int startingRomOffset, int length, string bankName) { InitializeComponent(); @@ -22,18 +20,6 @@ public RomBankVisualizer(Project project, int startingRomOffset, int length, str romImage1.RomVisual.RomStartingOffset = startingRomOffset; romImage1.RomVisual.LengthOverride = length; lblBankName.Text = bankName; - - //romImage1.RedrawOccurred += RomImage1_RedrawOccurred; - } - - private void RomImage1_RedrawOccurred(object sender, System.EventArgs e) - { - //OnRedrawOccurred(); - } - - private void OnRedrawOccurred() - { - //RedrawOccurred?.Invoke(this, EventArgs.Empty); } } } diff --git a/DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs index a5e78d8f..8ac71b07 100644 --- a/DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs +++ b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs @@ -59,25 +59,8 @@ public void Init() private void AddNewControl(RomBankVisualizer bankControl) { - // bankControl.RedrawOccurred += BankControl_RedrawOccurred; - BankControls.Add(bankControl); - flowLayoutPanel1.Controls.Add(bankControl); - //flowLayoutPanel1.AutoSize = true; - //flowLayoutPanel1.AutoSizeMode = AutoSizeMode.GrowAndShrink; - } - - /*private void BankControl_RedrawOccurred(object sender, EventArgs e) - { - OnRedrawOccurred(); } - - public event EventHandler RedrawOccurred; - - protected virtual void OnRedrawOccurred() - { - RedrawOccurred?.Invoke(this, EventArgs.Empty); - }*/ } } diff --git a/DiztinGUIsh/window/usercontrols/RomImage.cs b/DiztinGUIsh/window/usercontrols/RomImage.cs index 32b4823d..fb0ec214 100644 --- a/DiztinGUIsh/window/usercontrols/RomImage.cs +++ b/DiztinGUIsh/window/usercontrols/RomImage.cs @@ -1,5 +1,4 @@ -using System; -using System.Drawing; +using System.Drawing; using System.Windows.Forms; using Diz.Core.model; using Diz.Core.util; @@ -37,7 +36,7 @@ private void RomImage_Paint(object sender, PaintEventArgs e) private void Redraw(Graphics graphics = null) { - if (RomVisual?.Bitmap == null || updatingDimensions) + if (RomVisual?.Bitmap == null) return; graphics ??= CreateGraphics(); @@ -61,8 +60,6 @@ private void timer1_Tick(object sender, System.EventArgs e) RedrawIfNeeded(); } - private bool updatingDimensions = false; - private void UpdateDimensions() { Width = RomVisual.Width; From 505a169875a009a8cea3802e23408fe52a7beea6 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Mon, 26 Oct 2020 00:47:56 -0400 Subject: [PATCH 126/136] bugfix: dont pad empty row pixels when using the dirty list --- Diz.Core/util/RomVisual.cs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Diz.Core/util/RomVisual.cs b/Diz.Core/util/RomVisual.cs index 1f5735fd..4252d672 100644 --- a/Diz.Core/util/RomVisual.cs +++ b/Diz.Core/util/RomVisual.cs @@ -164,7 +164,7 @@ private void RegenerateImage() if (shouldRecreateBitmap) bitmap = new Bitmap(w, h); - var romBytes = ConsumeRomDirtyBytes(); + var romBytes = ConsumeRomDirtyBytes(out var usedDirtyList); var currentPixel = 0; var fastBitmap = new FastBitmap(bitmap); // needs compiler flag "/unsafe" enabled @@ -176,13 +176,16 @@ private void RegenerateImage() ++currentPixel; } - // rom bytes may not fully fill up the last row. fill it in with - // blank pixels - while (currentPixel < w*h) + if (!usedDirtyList) { - var (x, y) = ConvertPixelIndexToXy(currentPixel); - fastBitmap.SetPixel(x, y, Color.SlateGray); - ++currentPixel; + // rom bytes may not fully fill up the last row. fill it in with + // blank pixels + while (currentPixel < w * h) + { + var (x, y) = ConvertPixelIndexToXy(currentPixel); + fastBitmap.SetPixel(x, y, Color.SlateGray); + ++currentPixel; + } } } @@ -193,8 +196,10 @@ private void RegenerateImage() // returns the RomBytes we should use to update our image // this can either be ALL RomBytes, or, a small set of dirty RomBytes that were changed // since our last redraw. - private IEnumerable ConsumeRomDirtyBytes() + private IEnumerable ConsumeRomDirtyBytes(out bool usedDirtyList) { + usedDirtyList = false; + if (AllDirty) return Data.RomBytes .Where(rb => @@ -202,6 +207,7 @@ private IEnumerable ConsumeRomDirtyBytes() ) .ToList(); + usedDirtyList = true; IEnumerable romBytes; lock (dirtyLock) { From 43f475e58437984f352221edc3e1e1fcbd25b607 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 27 Oct 2020 05:44:26 -0400 Subject: [PATCH 127/136] rename test --- Diz.Test/LoadSaveTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Diz.Test/LoadSaveTest.cs b/Diz.Test/LoadSaveTest.cs index 0e7c2a4f..31e7b32c 100644 --- a/Diz.Test/LoadSaveTest.cs +++ b/Diz.Test/LoadSaveTest.cs @@ -11,7 +11,7 @@ namespace Diz.Test public class LoadSaveTest { [Fact] - private void SerializeAndDeserialize() + private void FullSerializeAndDeserialize() { // use the sample data to fake a project var sampleProject = new Project {Data = SampleRomData.SampleData}; From 037546beab77f843d0f60b8b5bece8476db9e82d Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 27 Oct 2020 11:36:27 -0400 Subject: [PATCH 128/136] add licensing info for included libraries (not sure we exactly have to do this but, doesn't hurt) --- .../licensing/Library Licenses.dist.txt | 61 ++++++++++++++++++ DiztinGUIsh/licensing/Library Licenses.xlsx | Bin 0 -> 12438 bytes 2 files changed, 61 insertions(+) create mode 100644 DiztinGUIsh/licensing/Library Licenses.dist.txt create mode 100644 DiztinGUIsh/licensing/Library Licenses.xlsx diff --git a/DiztinGUIsh/licensing/Library Licenses.dist.txt b/DiztinGUIsh/licensing/Library Licenses.dist.txt new file mode 100644 index 00000000..1eb3460b --- /dev/null +++ b/DiztinGUIsh/licensing/Library Licenses.dist.txt @@ -0,0 +1,61 @@ +Castle.Core http://www.apache.org/licenses/LICENSE-2.0.html Apache 2.0 +xunit https://raw.githubusercontent.com/xunit/xunit/master/license.txt Apache 2.0 +xunit.abstractions https://raw.githubusercontent.com/xunit/xunit/master/license.txt Apache 2.0 +xunit.analyzers https://raw.githubusercontent.com/xunit/xunit.analyzers/master/LICENSE Apache 2.0 +xunit.assert https://raw.githubusercontent.com/xunit/xunit/master/license.txt Apache 2.0 +xunit.core https://raw.githubusercontent.com/xunit/xunit/master/license.txt Apache 2.0 +xunit.extensibility.core https://raw.githubusercontent.com/xunit/xunit/master/license.txt Apache 2.0 +xunit.extensibility.execution https://raw.githubusercontent.com/xunit/xunit/master/license.txt Apache 2.0 +xunit.runner.console https://raw.githubusercontent.com/xunit/xunit/master/license.txt Apache 2.0 +Moq https://raw.githubusercontent.com/moq/moq4/master/License.txt BSD 3clause +ByteSize https://github.com/omar/ByteSize/blob/master/LICENSE MIT +ExtendedXmlSerializer https://github.com/ExtendedXmlSerializer/home/blob/master/LICENSE MIT +FastBitmapLib https://licenses.nuget.org/MIT MIT +GitInfo https://licenses.nuget.org/MIT MIT +IX.Abstractions https://licenses.nuget.org/MIT MIT +IX.Abstractions.Collections https://licenses.nuget.org/MIT MIT +IX.Abstractions.Threading https://licenses.nuget.org/MIT MIT +IX.Observable https://licenses.nuget.org/MIT MIT +IX.StandardExtensions https://licenses.nuget.org/MIT MIT +IX.StandardExtensions.ComponentModel https://licenses.nuget.org/MIT MIT +IX.StandardExtensions.Threading https://licenses.nuget.org/MIT MIT +IX.Undoable https://licenses.nuget.org/MIT MIT +JetBrains.Annotations https://licenses.nuget.org/MIT MIT +LightInject https://licenses.nuget.org/MIT MIT +LiveCharts https://github.com/beto-rodriguez/Live-Charts/blob/master/LICENSE.TXT MIT +NReco.LambdaParser https://raw.githubusercontent.com/nreco/lambdaparser/master/LICENSE MIT +SharpZipLib https://licenses.nuget.org/MIT MIT +Sprache https://github.com/sprache/Sprache/blob/master/licence.txt MIT +xunit.runner.visualstudio https://licenses.nuget.org/MIT MIT +-------------------------------------------------- +"MOQ +BSD 3-Clause License + +Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD, +and Contributors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +-------------------------------------------------- diff --git a/DiztinGUIsh/licensing/Library Licenses.xlsx b/DiztinGUIsh/licensing/Library Licenses.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..5655cb9ebe042e788bc3928c3681efc2343b9a50 GIT binary patch literal 12438 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 literal 0 HcmV?d00001 From 4dd75196c257619ae3818a9604dc72ea4bd56d0d Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Tue, 27 Oct 2020 12:17:44 -0400 Subject: [PATCH 129/136] don't save the project filename in XML --- .../serialization/xml_serializer/XMLSerializerSupport.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs b/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs index 4e0595e8..d7f091d2 100644 --- a/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs +++ b/Diz.Core/serialization/xml_serializer/XMLSerializerSupport.cs @@ -11,11 +11,14 @@ public static IConfigurationContainer GetSerializer() // This configuration changes how parts of the data structures are serialized back/forth to XML. // This is using the ExtendedXmlSerializer library, which has a zillion config options and is // awesome. + // + // TODO: would be cool if these were stored as attributes on the classes themselves return new ConfigurationContainer() .Type() .Member(x => x.UnsavedChanges).Ignore() - + .Member(x => x.ProjectFileName).Ignore() + .Type() .Register().Serializer().Using(RomBytesSerializer.Default) From b7da7b68a12e6dcea7c4270bb292da48d3dc8c46 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Thu, 29 Oct 2020 00:00:59 -0400 Subject: [PATCH 130/136] denote certain properties as not being saved in XML --- Diz.Core/model/Project.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Diz.Core/model/Project.cs b/Diz.Core/model/Project.cs index 13faf790..9b5a4d5c 100644 --- a/Diz.Core/model/Project.cs +++ b/Diz.Core/model/Project.cs @@ -7,14 +7,18 @@ namespace Diz.Core.model { public class Project : DizDataModel { - // Any public properties will be automatically serialized to XML. - // They require a get AND set. Order is important. + // Any public properties will be automatically serialized to XML unless noted. + // They will require a get AND set. + // Order is important. + + // not saved in XML public string ProjectFileName { get => projectFileName; set => SetField(ref projectFileName, value); } + // not saved in XML public string AttachedRomFilename { get => attachedRomFilename; @@ -81,7 +85,7 @@ public Project() LogWriterSettings.SetDefaults(); } - + // don't access these backing fields directly, instead, always use the properties private string projectFileName; private string attachedRomFilename; private bool unsavedChanges; From 720d2c57826a6b57959f54a1a08df151948b63a9 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Thu, 29 Oct 2020 00:01:38 -0400 Subject: [PATCH 131/136] add new "closeproject" support --- DiztinGUIsh/controller/ProjectController.cs | 22 ++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/DiztinGUIsh/controller/ProjectController.cs b/DiztinGUIsh/controller/ProjectController.cs index d7aee609..5c88fb6c 100644 --- a/DiztinGUIsh/controller/ProjectController.cs +++ b/DiztinGUIsh/controller/ProjectController.cs @@ -49,7 +49,8 @@ public enum ProjectChangedType Invalid, Saved, Opened, - Imported + Imported, + Closing } public ProjectChangedType ChangeType; @@ -157,6 +158,8 @@ public bool ImportRomAndCreateNewProject(string romFilename) var importSettings = importController.PromptUserForRomSettings(romFilename); if (importSettings == null) return false; + + CloseProject(); // actually do the import ImportRomAndCreateNewProject(importSettings); @@ -227,6 +230,10 @@ public long ImportBsnesTraceLogs(string[] fileNames) { var importer = new BsnesTraceLogImporter(Project.Data); + // TODO: differentiate between binary-formatted and text-formatted files + // probably look for a newline within 80 characters + // call importer.ImportTraceLogLineBinary() + // caution: trace logs can be gigantic, even a few seconds can be > 1GB // inside here, performance becomes critical. LargeFilesReader.ReadFilesLines(fileNames, @@ -260,5 +267,18 @@ public long ImportBsnesTraceLogsBinary(string[] filenames) return importer.CurrentStats.NumRomBytesModified; } + + public void CloseProject() + { + if (Project == null) + return; + + ProjectChanged?.Invoke(this, new ProjectChangedEventArgs() + { + ChangeType = ProjectChangedEventArgs.ProjectChangedType.Closing + }); + + Project = null; + } } } From 7d2f07c34163aa60f30c0a85c7a4f596b4aef6ed Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Thu, 29 Oct 2020 00:02:32 -0400 Subject: [PATCH 132/136] simplify "mark" operations --- Diz.Core/model/Data.cs | 60 +++++++++++++----------------------------- 1 file changed, 18 insertions(+), 42 deletions(-) diff --git a/Diz.Core/model/Data.cs b/Diz.Core/model/Data.cs index 69220c75..73f9b6db 100644 --- a/Diz.Core/model/Data.cs +++ b/Diz.Core/model/Data.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; @@ -10,7 +11,8 @@ namespace Diz.Core.model { public partial class Data : DizDataModel { - private readonly Cpu65C816 cpu65C816; // TODO: this really shouldn't be in Data, move to an outside 'SNESSystem' class or something + // TODO: this really shouldn't be in Data, move to an outside 'SNESSystem' class or something that operates on Data + private readonly Cpu65C816 cpu65C816; public Data() { @@ -38,8 +40,8 @@ public void CreateRomBytesFromRom(IEnumerable actualRomBytes) private byte[] GetRomBytes(int pcOffset, int count) { - byte[] output = new byte[count]; - for (int i = 0; i < output.Length; i++) + var output = new byte[count]; + for (var i = 0; i < output.Length; i++) output[i] = (byte)GetRomByte(ConvertSnesToPc(pcOffset + i)); return output; @@ -75,7 +77,7 @@ public void CopyRomDataIn(IEnumerable trueRomBytes) public FlagType GetFlag(int i) => RomBytes[i].TypeFlag; public void SetFlag(int i, FlagType flag) => RomBytes[i].TypeFlag = flag; public Architecture GetArchitecture(int i) => RomBytes[i].Arch; - public void SetArchitechture(int i, Architecture arch) => RomBytes[i].Arch = arch; + public void SetArchitecture(int i, Architecture arch) => RomBytes[i].Arch = arch; public InOutPoint GetInOutPoint(int i) => RomBytes[i].Point; public void SetInOutPoint(int i, InOutPoint point) => RomBytes[i].Point |= point; public void ClearInOutPoint(int i) => RomBytes[i].Point = 0; @@ -401,47 +403,21 @@ public int AutoStep(int offset, bool harsh, int amount) return newOffset; } - public int Mark(int offset, FlagType type, int count) + public int Mark(Action MarkAction, int offset, int count) { int i, size = GetRomSize(); - for (i = 0; i < count && offset + i < size; i++) SetFlag(offset + i, type); - return offset + i < size ? offset + i : size - 1; - } - - public int MarkDataBank(int offset, int db, int count) - { - int i, size = GetRomSize(); - for (i = 0; i < count && offset + i < size; i++) SetDataBank(offset + i, db); - return offset + i < size ? offset + i : size - 1; - } - - public int MarkDirectPage(int offset, int dp, int count) - { - int i, size = GetRomSize(); - for (i = 0; i < count && offset + i < size; i++) SetDirectPage(offset + i, dp); - return offset + i < size ? offset + i : size - 1; - } - - public int MarkXFlag(int offset, bool x, int count) - { - int i, size = GetRomSize(); - for (i = 0; i < count && offset + i < size; i++) SetXFlag(offset + i, x); - return offset + i < size ? offset + i : size - 1; - } - - public int MarkMFlag(int offset, bool m, int count) - { - int i, size = GetRomSize(); - for (i = 0; i < count && offset + i < size; i++) SetMFlag(offset + i, m); + for (i = 0; i < count && offset + i < size; i++) + MarkAction(offset + i); + return offset + i < size ? offset + i : size - 1; } - public int MarkArchitechture(int offset, Architecture arch, int count) - { - int i, size = GetRomSize(); - for (i = 0; i < count && offset + i < size; i++) SetArchitechture(offset + i, arch); - return offset + i < size ? offset + i : size - 1; - } + public int MarkTypeFlag(int offset, FlagType type, int count) => Mark(i => SetFlag(i, type), offset, count); + public int MarkDataBank(int offset, int db, int count) => Mark(i => SetDataBank(i, db), offset, count); + public int MarkDirectPage(int offset, int dp, int count) => Mark(i => SetDirectPage(i, dp), offset, count); + public int MarkXFlag(int offset, bool x, int count) => Mark(i => SetXFlag(i, x), offset, count); + public int MarkMFlag(int offset, bool m, int count) => Mark(i => SetMFlag(i, m), offset, count); + public int MarkArchitecture(int offset, Architecture arch, int count) => Mark(i => SetArchitecture(i, arch), offset, count); public int GetInstructionLength(int offset) { @@ -566,7 +542,7 @@ private int GetSnesBankByte(int bankIndex) } // get the actual ROM file bytes (i.e. the contents of the SMC file on the disk) - // note: don't save these anywhere because the data is copyrighted. + // note: don't save these anywhere permanent because ROM data is usually copyrighted. public IEnumerable GetFileBytes() { return RomBytes.Select(b => b.Rom); From 0c9e86c916f3b710c0f877b427d225787326fe49 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Thu, 29 Oct 2020 00:04:11 -0400 Subject: [PATCH 133/136] allow property notification change events to look at just the ref type instead of a full compare --- Diz.Core/model/Model.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Diz.Core/model/Model.cs b/Diz.Core/model/Model.cs index 46d69983..b385d606 100644 --- a/Diz.Core/model/Model.cs +++ b/Diz.Core/model/Model.cs @@ -17,9 +17,18 @@ public class PropertyNotifyChanged : INotifyPropertyChanged // Just hook up SetField() to the 'set' param of any property you would like to // expose to outside classes. public event PropertyChangedEventHandler PropertyChanged; - protected bool SetField(ref T field, T value, [CallerMemberName] string propertyName = null) + protected bool SetField(ref T field, T value, bool compareRefOnly = false, [CallerMemberName] string propertyName = null) { - if (EqualityComparer.Default.Equals(field, value)) return false; + if (compareRefOnly) + { + if (ReferenceEquals(field, value)) + return false; + } + else if (EqualityComparer.Default.Equals(field, value)) + { + return false; + } + field = value; OnPropertyChanged(propertyName); return true; From 3b6af2e02faff3807e6613af901b7e9d645ec80e Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Thu, 29 Oct 2020 00:04:29 -0400 Subject: [PATCH 134/136] add new DizDocument, for better managing changes of Project's. this class is NEVER serialized --- DiztinGUIsh/window/DizDocument.cs | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 DiztinGUIsh/window/DizDocument.cs diff --git a/DiztinGUIsh/window/DizDocument.cs b/DiztinGUIsh/window/DizDocument.cs new file mode 100644 index 00000000..e9669543 --- /dev/null +++ b/DiztinGUIsh/window/DizDocument.cs @@ -0,0 +1,36 @@ +using Diz.Core.model; +using DiztinGUIsh.Properties; + +namespace DiztinGUIsh.window +{ + // This class is for GUI internal use only, it should never be serialized. + // It represents the current "open document" (usually a thin wrapper around a Project) + // Anything that should persist should go inside Project instead. + // + // This can store some per-user settings that get saved locally. + // Don't save anything important here though. + public class DizDocument : DizDataModel + { + private Project project; + + public Project Project + { + get => project; + set => SetField(ref project, value, compareRefOnly: true); + } + + public string LastProjectFilename + { + get => Settings.Default.LastOpenedFile; + set + { + var lastOpenFile = Settings.Default.LastOpenedFile; + if (!SetField(ref lastOpenFile, value)) + return; + + Settings.Default.LastOpenedFile = lastOpenFile; + Settings.Default.Save(); + } + } + } +} \ No newline at end of file From 681305b040ff23272b297d7b1afe1b9bf02797b3 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Thu, 29 Oct 2020 00:05:13 -0400 Subject: [PATCH 135/136] fixup visual form handling of project open/close/new events --- Diz.Core/util/RomVisual.cs | 18 +++++++++++++----- DiztinGUIsh/window/VisualizerForm.cs | 7 +++++++ .../window/usercontrols/RomFullVisualizer.cs | 7 +++++-- DiztinGUIsh/window/usercontrols/RomImage.cs | 18 ++++++++++++------ 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/Diz.Core/util/RomVisual.cs b/Diz.Core/util/RomVisual.cs index 4252d672..bf253099 100644 --- a/Diz.Core/util/RomVisual.cs +++ b/Diz.Core/util/RomVisual.cs @@ -22,14 +22,22 @@ public Project Project set { if (ReferenceEquals(project, value)) return; - project = value; - if (project?.Data == null) return; - project.Data.RomBytes.PropertyChanged += RomBytes_PropertyChanged; - project.Data.RomBytes.CollectionChanged += RomBytes_CollectionChanged; - // InvalidateImage(); + SwitchProject(value); } } + private void SwitchProject(Project value) + { + bitmap = null; + + project = value; + if (project?.Data == null) + return; + + project.Data.RomBytes.PropertyChanged += RomBytes_PropertyChanged; + project.Data.RomBytes.CollectionChanged += RomBytes_CollectionChanged; + } + public bool IsDirty { get diff --git a/DiztinGUIsh/window/VisualizerForm.cs b/DiztinGUIsh/window/VisualizerForm.cs index 9b3a9726..11d18c66 100644 --- a/DiztinGUIsh/window/VisualizerForm.cs +++ b/DiztinGUIsh/window/VisualizerForm.cs @@ -27,6 +27,8 @@ public VisualizerForm(MainWindow window) private void VisualizerForm_Load(object sender, System.EventArgs e) { + mainWindow.ProjectController.ProjectChanged += ProjectController_ProjectChanged; + // hack to make room for the scrollbar // I wish docking dealt with this, or maybe I set it up wrong... Width = romFullVisualizer1.Width + 40; @@ -34,6 +36,11 @@ private void VisualizerForm_Load(object sender, System.EventArgs e) romFullVisualizer1.Project = mainWindow.Project; } + private void ProjectController_ProjectChanged(object sender, controller.ProjectController.ProjectChangedEventArgs e) + { + this.Project = e.Project; + } + private void VisualizerForm_FormClosing(object sender, FormClosingEventArgs e) { if (e.CloseReason != CloseReason.UserClosing) return; diff --git a/DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs index 8ac71b07..b17375fc 100644 --- a/DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs +++ b/DiztinGUIsh/window/usercontrols/RomFullVisualizer.cs @@ -13,6 +13,8 @@ public partial class RomFullVisualizer : UserControl { private Project project; public Data Data => project?.Data; + + private ControlCollection FormControls => flowLayoutPanel1.Controls; public Project Project { get => project; @@ -27,10 +29,11 @@ public Project Project private void DeleteControls() { - foreach (var rbv in BankControls.Where(rbv => Controls.Contains(rbv))) + foreach (var rbv in BankControls.Where(rbv => FormControls.Contains(rbv))) { - Controls.Remove(rbv); + FormControls.Remove(rbv); } + BankControls.Clear(); } public RomFullVisualizer() diff --git a/DiztinGUIsh/window/usercontrols/RomImage.cs b/DiztinGUIsh/window/usercontrols/RomImage.cs index fb0ec214..9c5235e5 100644 --- a/DiztinGUIsh/window/usercontrols/RomImage.cs +++ b/DiztinGUIsh/window/usercontrols/RomImage.cs @@ -9,23 +9,29 @@ namespace DiztinGUIsh.window.usercontrols { public partial class RomImage : UserControl { - public RomVisual RomVisual { get; } = new RomVisual(); - + public RomVisual RomVisual { get; protected set; } = new RomVisual(); public Project Project { get => RomVisual.Project; - set => RomVisual.Project = value; + set + { + RomVisual = new RomVisual + { + Project = value + }; + + // if there's a reason to track ROM byte changes, hook in here + // romVisual.MarkedDirty += RomVisual_MarkedDirty; + } } public RomImage() { InitializeComponent(); } + private void RomImage_Load(object sender, System.EventArgs e) { - // if there's a reason to track ROM byte changes, hook in here - // romVisual.MarkedDirty += RomVisual_MarkedDirty; - UpdateDimensions(); } From ab5236b70efb0136465be90cbe81aa7aefb9c508 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Thu, 29 Oct 2020 00:06:43 -0400 Subject: [PATCH 136/136] massive overhaul of main form - attempted to divide and conquer lots of form elements here into 7 partial classes - mostly for organizing, lays the groundwork for future refactoring - makes it easier to mentally digest the important bits separate from the glue --- Diz.Core/import/BizHawkCdlImporter.cs | 2 +- .../binary_serializer_old/BinarySerializer.cs | 2 +- DiztinGUIsh/DiztinGUIsh.csproj | 17 + DiztinGUIsh/Program.cs | 2 +- DiztinGUIsh/window/MainWindow.Actions.cs | 237 ++++ DiztinGUIsh/window/MainWindow.Designer.cs | 44 +- DiztinGUIsh/window/MainWindow.Importers.cs | 69 + DiztinGUIsh/window/MainWindow.MainTable.cs | 380 ++++++ DiztinGUIsh/window/MainWindow.Prompts.cs | 172 +++ DiztinGUIsh/window/MainWindow.Properties.cs | 47 + .../window/MainWindow.ReadOnlyHelpers.cs | 68 + DiztinGUIsh/window/MainWindow.SimpleUI.cs | 137 ++ DiztinGUIsh/window/MainWindow.StateUpdate.cs | 146 ++ DiztinGUIsh/window/MainWindow.cs | 1194 +---------------- DiztinGUIsh/window/dialog/HarshAutoStep.cs | 110 +- .../window/dialog/MarkManyDialog.Designer.cs | 2 +- DiztinGUIsh/window/dialog/MarkManyDialog.cs | 229 ++-- 17 files changed, 1499 insertions(+), 1359 deletions(-) create mode 100644 DiztinGUIsh/window/MainWindow.Actions.cs create mode 100644 DiztinGUIsh/window/MainWindow.Importers.cs create mode 100644 DiztinGUIsh/window/MainWindow.MainTable.cs create mode 100644 DiztinGUIsh/window/MainWindow.Prompts.cs create mode 100644 DiztinGUIsh/window/MainWindow.Properties.cs create mode 100644 DiztinGUIsh/window/MainWindow.ReadOnlyHelpers.cs create mode 100644 DiztinGUIsh/window/MainWindow.SimpleUI.cs create mode 100644 DiztinGUIsh/window/MainWindow.StateUpdate.cs diff --git a/Diz.Core/import/BizHawkCdlImporter.cs b/Diz.Core/import/BizHawkCdlImporter.cs index 88428c81..091d6a26 100644 --- a/Diz.Core/import/BizHawkCdlImporter.cs +++ b/Diz.Core/import/BizHawkCdlImporter.cs @@ -91,7 +91,7 @@ private void CopyInto(Data data) type = Data.FlagType.Data8Bit; else if ((cdlFlag & BizHawkCdlImporter.Flag.DmaData) != 0) type = Data.FlagType.Data8Bit; - data.Mark(offset, type, 1); + data.MarkTypeFlag(offset, type, 1); if (type != Data.FlagType.Opcode && type != Data.FlagType.Operand) continue; diff --git a/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs b/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs index 1935902d..d25c7392 100644 --- a/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs +++ b/Diz.Core/serialization/binary_serializer_old/BinarySerializer.cs @@ -79,7 +79,7 @@ public override (Project project, string warning) Load(byte[] data) for (int i = 0; i < size; i++) project.Data.SetXFlag(i, data[pointer + 3 * size + i] != 0); for (int i = 0; i < size; i++) project.Data.SetMFlag(i, data[pointer + 4 * size + i] != 0); for (int i = 0; i < size; i++) project.Data.SetFlag(i, (Data.FlagType)data[pointer + 5 * size + i]); - for (int i = 0; i < size; i++) project.Data.SetArchitechture(i, (Data.Architecture)data[pointer + 6 * size + i]); + for (int i = 0; i < size; i++) project.Data.SetArchitecture(i, (Data.Architecture)data[pointer + 6 * size + i]); for (int i = 0; i < size; i++) project.Data.SetInOutPoint(i, (Data.InOutPoint)data[pointer + 7 * size + i]); pointer += 8 * size; diff --git a/DiztinGUIsh/DiztinGUIsh.csproj b/DiztinGUIsh/DiztinGUIsh.csproj index 174b38e3..be72361a 100644 --- a/DiztinGUIsh/DiztinGUIsh.csproj +++ b/DiztinGUIsh/DiztinGUIsh.csproj @@ -227,6 +227,23 @@ AliasList.cs + + + + + Form + + + + + Form + + + Form + + + Form + UserControl diff --git a/DiztinGUIsh/Program.cs b/DiztinGUIsh/Program.cs index cb5bd135..d35856df 100644 --- a/DiztinGUIsh/Program.cs +++ b/DiztinGUIsh/Program.cs @@ -31,7 +31,7 @@ private static void RunNormally(string openFile = "") var window = new MainWindow(); if (openFile != "") - window.OpenProject(""); + window.ProjectController.OpenProject(""); Application.Run(window); } diff --git a/DiztinGUIsh/window/MainWindow.Actions.cs b/DiztinGUIsh/window/MainWindow.Actions.cs new file mode 100644 index 00000000..69f0d701 --- /dev/null +++ b/DiztinGUIsh/window/MainWindow.Actions.cs @@ -0,0 +1,237 @@ +using Diz.Core.model; +using Diz.Core.util; +using DiztinGUIsh.Properties; + +namespace DiztinGUIsh.window +{ + public partial class MainWindow + { + private void OpenLastProject() + { + if (Document.LastProjectFilename == "") + return; + + // safeguard: if we crash opening this project, + // then next time we load make sure we don't try it again. + // this will be reset later + var projectToOpen = Document.LastProjectFilename; + Document.LastProjectFilename = ""; + + ProjectController.OpenProject(projectToOpen); + } + + private void OpenProject() + { + if (!PromptForOpenProjectFilename()) + return; + + ProjectController.OpenProject(openProjectFile.FileName); + } + + private void CreateNewProject() + { + if (!PromptContinueEvenIfUnsavedChanges()) + return; + + var romFilename = PromptForOpenFilename(); + if (romFilename == "") + return; + + ProjectController.ImportRomAndCreateNewProject(openFileDialog.FileName); + } + + private void ExportAssembly() + { + var adjustedSettings = PromptForExportSettingsAndConfirmation(); + if (!adjustedSettings.HasValue) + return; + + ProjectController.UpdateExportSettings(adjustedSettings.Value); + ProjectController.WriteAssemblyOutput(); + } + + + private void Step(int offset) + { + if (!RomDataPresent()) + return; + + ProjectController.MarkChanged(); + SelectOffset(Project.Data.Step(offset, false, false, offset - 1)); + UpdateUI_Tmp3(); + } + + private void StepIn(int offset) + { + if (!RomDataPresent()) + return; + + ProjectController.MarkChanged(); + SelectOffset(Project.Data.Step(offset, true, false, offset - 1)); + UpdateUI_Tmp3(); + } + + private void AutoStepSafe(int offset) + { + if (!RomDataPresent()) + return; + + ProjectController.MarkChanged(); + var destination = Project.Data.AutoStep(offset, false, 0); + if (moveWithStep) + SelectOffset(destination); + + UpdateUI_Tmp3(); + } + + private void AutoStepHarsh(int offset) + { + if (!RomDataPresent()) + return; + + if (!PromptHarshAutoStep(offset, out var newOffset, out var count)) + return; + + ProjectController.MarkChanged(); + var destination = Project.Data.AutoStep(newOffset, true, count); + + if (moveWithStep) + SelectOffset(destination); + + UpdateUI_Tmp3(); + } + + private void Mark(int offset) + { + if (!RomDataPresent()) + return; + + ProjectController.MarkChanged(); + var newOffset = Project.Data.MarkTypeFlag(offset, markFlag, RomUtil.GetByteLengthForFlag(markFlag)); + + SelectOffset(newOffset); + + UpdateUI_Tmp3(); + } + + private void MarkMany(int offset, int column) + { + if (!RomDataPresent()) + return; + + var mark = PromptMarkMany(offset, column); + if (mark == null) + return; + + MarkMany(mark.Property, mark.Start, mark.Value, mark.Count); + + UpdateSomeUI2(); + } + + private void MarkMany(int markProperty, int markStart, object markValue, int markCount) + { + var destination = markProperty switch + { + 0 => Project.Data.MarkTypeFlag(markStart, (Data.FlagType) markValue, markCount), + 1 => Project.Data.MarkDataBank(markStart, (int) markValue, markCount), + 2 => Project.Data.MarkDirectPage(markStart, (int) markValue, markCount), + 3 => Project.Data.MarkMFlag(markStart, (bool) markValue, markCount), + 4 => Project.Data.MarkXFlag(markStart, (bool) markValue, markCount), + 5 => Project.Data.MarkArchitecture(markStart, (Data.Architecture) markValue, markCount), + _ => 0 + }; + + ProjectController.MarkChanged(); + + if (moveWithStep) + SelectOffset(destination); + } + + private void GoToIntermediateAddress(int offset) + { + var snesOffset = FindIntermediateAddress(offset); + if (snesOffset == -1) + return; + + SelectOffset(snesOffset, 1); + } + + private void GoTo(int offset) + { + if (IsOffsetInRange(offset)) + SelectOffset(offset); + else + ShowOffsetOutOfRangeMsg(); + } + + private void GoToUnreached(bool end, bool direction) + { + if (!FindUnreached(SelectedOffset, end, direction, out var unreached)) + return; + + SelectOffset(unreached, 1); + } + + + private void FixMisalignedInstructions() + { + if (!PromptForMisalignmentCheck()) + return; + + var count = Project.Data.FixMisalignedFlags(); + + if (count > 0) + ProjectController.MarkChanged(); + InvalidateTable(); + + ShowInfo($"Modified {count} flags!", "Done!"); + } + + private void RescanForInOut() + { + if (!PromptForInOutChecking()) + return; + + Project.Data.RescanInOutPoints(); + ProjectController.MarkChanged(); + + InvalidateTable(); + ShowInfo("Scan complete!", "Done!"); + } + + private void SaveProject() + { + ProjectController.SaveProject(Project.ProjectFileName); + } + + private void ShowVisualizerForm() + { + visualForm ??= new VisualizerForm(this); + visualForm.Show(); + } + + private void ShowCommentList() + { + AliasList.Show(); + } + + private void SetMarkerLabel(Data.FlagType flagType) + { + markFlag = flagType; + UpdateMarkerLabel(); + } + + private void ToggleMoveWithStep() + { + moveWithStep = !moveWithStep; + moveWithStepToolStripMenuItem.Checked = moveWithStep; + } + + private void ToggleOpenLastProjectEnabled() + { + Settings.Default.OpenLastFileAutomatically = openLastProjectAutomaticallyToolStripMenuItem.Checked; + Settings.Default.Save(); + UpdateUiFromSettings(); + } + } +} \ No newline at end of file diff --git a/DiztinGUIsh/window/MainWindow.Designer.cs b/DiztinGUIsh/window/MainWindow.Designer.cs index 06acf562..293ee1c9 100644 --- a/DiztinGUIsh/window/MainWindow.Designer.cs +++ b/DiztinGUIsh/window/MainWindow.Designer.cs @@ -124,6 +124,8 @@ private void InitializeComponent() this.moveWithStepToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.openLastProjectAutomaticallyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.labelListToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.importCaptureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.importTraceLogBinary = new System.Windows.Forms.ToolStripMenuItem(); this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.viewHelpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.githubToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -139,8 +141,7 @@ private void InitializeComponent() this.openUsageMapFile = new System.Windows.Forms.OpenFileDialog(); this.openTraceLogDialog = new System.Windows.Forms.OpenFileDialog(); this.openCDLDialog = new System.Windows.Forms.OpenFileDialog(); - this.importCaptureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.importTraceLogBinary = new System.Windows.Forms.ToolStripMenuItem(); + this.closeProjectToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); ((System.ComponentModel.ISupportInitialize)(this.table)).BeginInit(); this.menuStrip1.SuspendLayout(); this.statusStrip1.SuspendLayout(); @@ -374,6 +375,7 @@ private void InitializeComponent() this.newProjectToolStripMenuItem, this.openProjectToolStripMenuItem, this.toolStripOpenLast, + this.closeProjectToolStripMenuItem, this.saveProjectToolStripMenuItem, this.saveProjectAsToolStripMenuItem, this.toolStripSeparator1, @@ -471,7 +473,7 @@ private void InitializeComponent() this.importTraceLogText.Name = "importTraceLogText"; this.importTraceLogText.Size = new System.Drawing.Size(218, 22); this.importTraceLogText.Text = "Import BSNES Trace Log..."; - this.importTraceLogText.Click += new System.EventHandler(this.toolStripMenuItem3_Click); + this.importTraceLogText.Click += new System.EventHandler(this.importBsnesTracelogText_Click); // // exportLogToolStripMenuItem // @@ -927,6 +929,22 @@ private void InitializeComponent() this.labelListToolStripMenuItem.Text = "Label List"; this.labelListToolStripMenuItem.Click += new System.EventHandler(this.labelListToolStripMenuItem_Click); // + // importCaptureToolStripMenuItem + // + this.importCaptureToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.importTraceLogBinary}); + this.importCaptureToolStripMenuItem.Name = "importCaptureToolStripMenuItem"; + this.importCaptureToolStripMenuItem.Size = new System.Drawing.Size(212, 22); + this.importCaptureToolStripMenuItem.Text = "Live Capture"; + // + // importTraceLogBinary + // + this.importTraceLogBinary.Enabled = false; + this.importTraceLogBinary.Name = "importTraceLogBinary"; + this.importTraceLogBinary.Size = new System.Drawing.Size(207, 22); + this.importTraceLogBinary.Text = "BSNESPlus Trace Logging"; + this.importTraceLogBinary.Click += new System.EventHandler(this.importTraceLogBinary_Click); + // // helpToolStripMenuItem // this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -1027,21 +1045,12 @@ private void InitializeComponent() // this.openCDLDialog.Filter = "BizHawk Code Data Logger Files|*.cdl|All Files|*.*"; // - // importCaptureToolStripMenuItem + // closeProjectToolStripMenuItem // - this.importCaptureToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.importTraceLogBinary}); - this.importCaptureToolStripMenuItem.Name = "importCaptureToolStripMenuItem"; - this.importCaptureToolStripMenuItem.Size = new System.Drawing.Size(212, 22); - this.importCaptureToolStripMenuItem.Text = "Live Capture"; - // - // importTraceLogBinary - // - this.importTraceLogBinary.Enabled = false; - this.importTraceLogBinary.Name = "importTraceLogBinary"; - this.importTraceLogBinary.Size = new System.Drawing.Size(207, 22); - this.importTraceLogBinary.Text = "BSNESPlus Trace Logging"; - this.importTraceLogBinary.Click += new System.EventHandler(this.importTraceLogBinary_Click); + this.closeProjectToolStripMenuItem.Name = "closeProjectToolStripMenuItem"; + this.closeProjectToolStripMenuItem.Size = new System.Drawing.Size(235, 22); + this.closeProjectToolStripMenuItem.Text = "Close Project"; + this.closeProjectToolStripMenuItem.Click += new System.EventHandler(this.closeProjectToolStripMenuItem_Click); // // MainWindow // @@ -1172,6 +1181,7 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem importTraceLogText; private System.Windows.Forms.ToolStripMenuItem importCaptureToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem importTraceLogBinary; + private System.Windows.Forms.ToolStripMenuItem closeProjectToolStripMenuItem; } } diff --git a/DiztinGUIsh/window/MainWindow.Importers.cs b/DiztinGUIsh/window/MainWindow.Importers.cs new file mode 100644 index 00000000..28df36bc --- /dev/null +++ b/DiztinGUIsh/window/MainWindow.Importers.cs @@ -0,0 +1,69 @@ +using System; +using System.Windows.Forms; +using DiztinGUIsh.window.dialog; + +namespace DiztinGUIsh.window +{ + public partial class MainWindow + { + public IImportRomDialogView GetImportView() + { + return new ImportRomDialog(); + } + + private void ImportBizhawkCDL() + { + var filename = PromptOpenBizhawkCDLFile(); + if (filename != null && filename == "") return; + ImportBizHawkCdl(filename); + UpdateSomeUI2(); + } + + private void ImportBizHawkCdl(string filename) + { + try + { + ProjectController.ImportBizHawkCdl(filename); + } + catch (Exception ex) + { + ShowError(ex.Message, "Error"); + } + } + + private void ImportBsnesTraceLogText() + { + if (!PromptForImportBSNESTraceLogFile()) return; + var (numModifiedFlags, numFiles) = ImportBSNESTraceLogs(); + ReportNumberFlagsModified(numModifiedFlags, numFiles); + } + + private void ImportBSNESUsageMap() + { + if (openUsageMapFile.ShowDialog() != DialogResult.OK) + return; + + var numModifiedFlags = ProjectController.ImportBsnesUsageMap(openUsageMapFile.FileName); + + ShowInfo($"Modified total {numModifiedFlags} flags!", "Done"); + } + + private (long numBytesModified, int numFiles) ImportBSNESTraceLogs() + { + var numBytesModified = ProjectController.ImportBsnesTraceLogs(openTraceLogDialog.FileNames); + return (numBytesModified, openTraceLogDialog.FileNames.Length); + } + + private void ImportBsnesBinaryTraceLog() + { + new BsnesTraceLogBinaryMonitorForm(this).ShowDialog(); + RefreshUi(); + } + + private void OnImportedProjectSuccess() + { + UpdateSaveOptionStates(saveEnabled: false, saveAsEnabled: true, closeEnabled: true); + RefreshUi(); + } + } +} \ No newline at end of file diff --git a/DiztinGUIsh/window/MainWindow.MainTable.cs b/DiztinGUIsh/window/MainWindow.MainTable.cs new file mode 100644 index 00000000..f35de76c --- /dev/null +++ b/DiztinGUIsh/window/MainWindow.MainTable.cs @@ -0,0 +1,380 @@ +using System; +using System.Drawing; +using System.Globalization; +using System.Windows.Forms; +using Diz.Core.model; +using Diz.Core.util; + +namespace DiztinGUIsh.window +{ + // Everything in here should probably go in its own usercontrol for JUST the table. + // It's a complicated little beast. + public partial class MainWindow + { + // Data offset of the selected row + public int SelectedOffset => table.CurrentCell.RowIndex + ViewOffset; + + private int rowsToShow; + private bool moveWithStep = true; + + public void InvalidateTable() => table.Invalidate(); + + private void ScrollTableBy(int delta) + { + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) + return; + int selRow = table.CurrentCell.RowIndex + ViewOffset, selCol = table.CurrentCell.ColumnIndex; + var amount = delta / 0x18; + ViewOffset -= amount; + UpdateDataGridView(); + if (selRow < ViewOffset) selRow = ViewOffset; + else if (selRow >= ViewOffset + rowsToShow) selRow = ViewOffset + rowsToShow - 1; + table.CurrentCell = table.Rows[selRow - ViewOffset].Cells[selCol]; + InvalidateTable(); + } + + private void vScrollBar1_ValueChanged(object sender, EventArgs e) + { + if (table.CurrentCell == null) + return; + + int selOffset = table.CurrentCell.RowIndex + ViewOffset; + ViewOffset = vScrollBar1.Value; + UpdateDataGridView(); + + if (selOffset < ViewOffset) table.CurrentCell = table.Rows[0].Cells[table.CurrentCell.ColumnIndex]; + else if (selOffset >= ViewOffset + rowsToShow) + table.CurrentCell = table.Rows[rowsToShow - 1].Cells[table.CurrentCell.ColumnIndex]; + else table.CurrentCell = table.Rows[selOffset - ViewOffset].Cells[table.CurrentCell.ColumnIndex]; + + InvalidateTable(); + } + + private void table_MouseDown(object sender, MouseEventArgs e) + { + InvalidateTable(); + } + + private void table_KeyDown(object sender, KeyEventArgs e) + { + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; + + var offset = table.CurrentCell.RowIndex + ViewOffset; + var newOffset = offset; + var amount = 0x01; + + Console.WriteLine(e.KeyCode); + switch (e.KeyCode) + { + case Keys.Home: + case Keys.PageUp: + case Keys.Up: + amount = e.KeyCode == Keys.Up ? 0x01 : e.KeyCode == Keys.PageUp ? 0x10 : 0x100; + newOffset = offset - amount; + if (newOffset < 0) newOffset = 0; + SelectOffset(newOffset); + break; + case Keys.End: + case Keys.PageDown: + case Keys.Down: + amount = e.KeyCode == Keys.Down ? 0x01 : e.KeyCode == Keys.PageDown ? 0x10 : 0x100; + newOffset = offset + amount; + if (newOffset >= Project.Data.GetRomSize()) newOffset = Project.Data.GetRomSize() - 1; + SelectOffset(newOffset); + break; + case Keys.Left: + amount = table.CurrentCell.ColumnIndex; + amount = amount - 1 < 0 ? 0 : amount - 1; + table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[amount]; + break; + case Keys.Right: + amount = table.CurrentCell.ColumnIndex; + amount = amount + 1 >= table.ColumnCount ? table.ColumnCount - 1 : amount + 1; + table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[amount]; + break; + case Keys.S: + Step(offset); + break; + case Keys.I: + StepIn(offset); + break; + case Keys.A: + AutoStepSafe(offset); + break; + case Keys.T: + GoToIntermediateAddress(offset); + break; + case Keys.U: + GoToUnreached(true, true); + break; + case Keys.H: + GoToUnreached(false, false); + break; + case Keys.N: + GoToUnreached(false, true); + break; + case Keys.K: + Mark(offset); + break; + case Keys.L: + table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[0]; + table.BeginEdit(true); + break; + case Keys.B: + table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[8]; + table.BeginEdit(true); + break; + case Keys.D: + table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[9]; + table.BeginEdit(true); + break; + case Keys.M: + Project.Data.SetMFlag(offset, !Project.Data.GetMFlag(offset)); + break; + case Keys.X: + Project.Data.SetXFlag(offset, !Project.Data.GetXFlag(offset)); + break; + case Keys.C: + table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[12]; + table.BeginEdit(true); + break; + } + + e.Handled = true; + InvalidateTable(); + } + + private void table_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) + { + var row = e.RowIndex + ViewOffset; + if (row >= Project.Data.GetRomSize()) return; + switch (e.ColumnIndex) + { + case 0: + e.Value = Project.Data.GetLabelName(Project.Data.ConvertPCtoSnes(row)); + break; + case 1: + e.Value = Util.NumberToBaseString(Project.Data.ConvertPCtoSnes(row), Util.NumberBase.Hexadecimal, 6); + break; + case 2: + e.Value = (char)Project.Data.GetRomByte(row); + break; + case 3: + e.Value = Util.NumberToBaseString(Project.Data.GetRomByte(row), displayBase); + break; + case 4: + e.Value = RomUtil.PointToString(Project.Data.GetInOutPoint(row)); + break; + case 5: + var len = Project.Data.GetInstructionLength(row); + e.Value = row + len <= Project.Data.GetRomSize() ? Project.Data.GetInstruction(row) : ""; + break; + case 6: + var ia = Project.Data.GetIntermediateAddressOrPointer(row); + e.Value = ia >= 0 ? Util.NumberToBaseString(ia, Util.NumberBase.Hexadecimal, 6) : ""; + break; + case 7: + e.Value = Util.GetEnumDescription(Project.Data.GetFlag(row)); + break; + case 8: + e.Value = Util.NumberToBaseString(Project.Data.GetDataBank(row), Util.NumberBase.Hexadecimal, 2); + break; + case 9: + e.Value = Util.NumberToBaseString(Project.Data.GetDirectPage(row), Util.NumberBase.Hexadecimal, 4); + break; + case 10: + e.Value = RomUtil.BoolToSize(Project.Data.GetMFlag(row)); + break; + case 11: + e.Value = RomUtil.BoolToSize(Project.Data.GetXFlag(row)); + break; + case 12: + e.Value = Project.Data.GetComment(Project.Data.ConvertPCtoSnes(row)); + break; + } + } + + private void table_CellValuePushed(object sender, DataGridViewCellValueEventArgs e) + { + string value = e.Value as string; + int result; + int row = e.RowIndex + ViewOffset; + if (row >= Project.Data.GetRomSize()) return; + switch (e.ColumnIndex) + { + case 0: + Project.Data.AddLabel(Project.Data.ConvertPCtoSnes(row), new Diz.Core.model.Label() { Name = value }, true); + break; // todo (validate for valid label characters) + case 8: + if (int.TryParse(value, NumberStyles.HexNumber, null, out result)) Project.Data.SetDataBank(row, result); + break; + case 9: + if (int.TryParse(value, NumberStyles.HexNumber, null, out result)) Project.Data.SetDirectPage(row, result); + break; + case 10: + Project.Data.SetMFlag(row, (value == "8" || value == "M")); + break; + case 11: + Project.Data.SetXFlag(row, (value == "8" || value == "X")); + break; + case 12: + Project.Data.AddComment(Project.Data.ConvertPCtoSnes(row), value, true); + break; + } + + table.InvalidateRow(e.RowIndex); + } + + public void PaintCell(int offset, DataGridViewCellStyle style, int column, int selOffset) + { + // editable cells show up green + if (column == 0 || column == 8 || column == 9 || column == 12) style.SelectionBackColor = Color.Chartreuse; + + switch (Project.Data.GetFlag(offset)) + { + case Data.FlagType.Unreached: + style.BackColor = Color.LightGray; + style.ForeColor = Color.DarkSlateGray; + break; + case Data.FlagType.Opcode: + int opcode = Project.Data.GetRomByte(offset); + switch (column) + { + case 4: // <*> + Data.InOutPoint point = Project.Data.GetInOutPoint(offset); + int r = 255, g = 255, b = 255; + if ((point & (Data.InOutPoint.EndPoint | Data.InOutPoint.OutPoint)) != 0) g -= 50; + if ((point & (Data.InOutPoint.InPoint)) != 0) r -= 50; + if ((point & (Data.InOutPoint.ReadPoint)) != 0) b -= 50; + style.BackColor = Color.FromArgb(r, g, b); + break; + case 5: // Instruction + if (opcode == 0x40 || opcode == 0xCB || opcode == 0xDB || opcode == 0xF8 // RTI WAI STP SED + || opcode == 0xFB || opcode == 0x00 || opcode == 0x02 || opcode == 0x42 // XCE BRK COP WDM + ) style.BackColor = Color.Yellow; + break; + case 8: // Data Bank + if (opcode == 0xAB || opcode == 0x44 || opcode == 0x54) // PLB MVP MVN + style.BackColor = Color.OrangeRed; + else if (opcode == 0x8B) // PHB + style.BackColor = Color.Yellow; + break; + case 9: // Direct Page + if (opcode == 0x2B || opcode == 0x5B) // PLD TCD + style.BackColor = Color.OrangeRed; + if (opcode == 0x0B || opcode == 0x7B) // PHD TDC + style.BackColor = Color.Yellow; + break; + case 10: // M Flag + case 11: // X Flag + int mask = column == 10 ? 0x20 : 0x10; + if (opcode == 0x28 || ((opcode == 0xC2 || opcode == 0xE2) // PLP SEP REP + && (Project.Data.GetRomByte(offset + 1) & mask) != 0)) // relevant bit set + style.BackColor = Color.OrangeRed; + if (opcode == 0x08) // PHP + style.BackColor = Color.Yellow; + break; + } + break; + case Data.FlagType.Operand: + style.ForeColor = Color.LightGray; + break; + case Data.FlagType.Graphics: + style.BackColor = Color.LightPink; + break; + case Data.FlagType.Music: + style.BackColor = Color.PowderBlue; + break; + case Data.FlagType.Data8Bit: + case Data.FlagType.Data16Bit: + case Data.FlagType.Data24Bit: + case Data.FlagType.Data32Bit: + style.BackColor = Color.NavajoWhite; + break; + case Data.FlagType.Pointer16Bit: + case Data.FlagType.Pointer24Bit: + case Data.FlagType.Pointer32Bit: + style.BackColor = Color.Orchid; + break; + case Data.FlagType.Text: + style.BackColor = Color.Aquamarine; + break; + case Data.FlagType.Empty: + style.BackColor = Color.DarkSlateGray; + style.ForeColor = Color.LightGray; + break; + } + + if (selOffset >= 0 && selOffset < Project.Data.GetRomSize()) + { + if (column == 1 + //&& (Project.Data.GetFlag(selOffset) == Data.FlagType.Opcode || Project.Data.GetFlag(selOffset) == Data.FlagType.Unreached) + && Project.Data.ConvertSnesToPc(Project.Data.GetIntermediateAddressOrPointer(selOffset)) == offset + ) style.BackColor = Color.DeepPink; + + if (column == 6 + //&& (Project.Data.GetFlag(offset) == Data.FlagType.Opcode || Project.Data.GetFlag(offset) == Data.FlagType.Unreached) + && Project.Data.ConvertSnesToPc(Project.Data.GetIntermediateAddressOrPointer(offset)) == selOffset + ) style.BackColor = Color.DeepPink; + } + } + + private void table_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) + { + int row = e.RowIndex + ViewOffset; + if (row < 0 || row >= Project.Data.GetRomSize()) return; + PaintCell(row, e.CellStyle, e.ColumnIndex, table.CurrentCell.RowIndex + ViewOffset); + } + + public void SelectOffset(int offset, int column = -1) + { + var col = column == -1 ? table.CurrentCell.ColumnIndex : column; + if (offset < ViewOffset) + { + ViewOffset = offset; + UpdateDataGridView(); + table.CurrentCell = table.Rows[0].Cells[col]; + } + else if (offset >= ViewOffset + rowsToShow) + { + ViewOffset = offset - rowsToShow + 1; + UpdateDataGridView(); + table.CurrentCell = table.Rows[rowsToShow - 1].Cells[col]; + } + else + { + table.CurrentCell = table.Rows[offset - ViewOffset].Cells[col]; + } + } + + private void InitMainTable() + { + table.CellValueNeeded += new DataGridViewCellValueEventHandler(table_CellValueNeeded); + table.CellValuePushed += new DataGridViewCellValueEventHandler(table_CellValuePushed); + table.CellPainting += new DataGridViewCellPaintingEventHandler(table_CellPainting); + + rowsToShow = ((table.Height - table.ColumnHeadersHeight) / table.RowTemplate.Height); + + // https://stackoverflow.com/a/1506066 + typeof(DataGridView).InvokeMember( + "DoubleBuffered", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | + System.Reflection.BindingFlags.SetProperty, + null, + table, + new object[] {true}); + } + + private void BeginEditingComment() + { + table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[12]; + table.BeginEdit(true); + } + + private void BeginAddingLabel() + { + table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[0]; + table.BeginEdit(true); + } + } +} \ No newline at end of file diff --git a/DiztinGUIsh/window/MainWindow.Prompts.cs b/DiztinGUIsh/window/MainWindow.Prompts.cs new file mode 100644 index 00000000..c75ccb13 --- /dev/null +++ b/DiztinGUIsh/window/MainWindow.Prompts.cs @@ -0,0 +1,172 @@ +using System; +using System.IO; +using System.Windows.Forms; +using Diz.Core.export; +using DiztinGUIsh.window.dialog; + +namespace DiztinGUIsh.window +{ + public partial class MainWindow + { + private bool PromptContinueEvenIfUnsavedChanges() + { + if (Project == null || !Project.UnsavedChanges) + return true; + + return DialogResult.OK == MessageBox.Show( + "You have unsaved changes. They will be lost if you continue.", + "Unsaved Changes", MessageBoxButtons.OKCancel); + } + + private string PromptForOpenFilename() + { + // TODO: combine with another function here that does similar + openFileDialog.InitialDirectory = Project?.ProjectFileName ?? ""; + return openFileDialog.ShowDialog() == DialogResult.OK ? openFileDialog.FileName : ""; + } + + private static void ShowExportResults(LogCreator.OutputResult result) + { + if (result.ErrorCount > 0) + MessageBox.Show("Disassembly created with errors. See errors.txt for details.", "Warning", + MessageBoxButtons.OK, MessageBoxIcon.Warning); + else + MessageBox.Show("Disassembly created successfully!", "Complete", MessageBoxButtons.OK, + MessageBoxIcon.Asterisk); + } + + private void PromptForFilenameToSave() + { + saveProjectFile.InitialDirectory = Project.AttachedRomFilename; + if (saveProjectFile.ShowDialog() == DialogResult.OK && saveProjectFile.FileName != "") + { + ProjectController.SaveProject(saveProjectFile.FileName); + } + } + + private bool PromptForOpenProjectFilename() + { + if (!PromptContinueEvenIfUnsavedChanges()) + return false; + + openProjectFile.InitialDirectory = Project?.ProjectFileName; + return openProjectFile.ShowDialog() == DialogResult.OK; + } + + private void viewHelpToolStripMenuItem_Click(object sender, EventArgs e) + { + try + { + System.Diagnostics.Process.Start(Directory.GetCurrentDirectory() + "/help.html"); + } + catch (Exception) + { + MessageBox.Show("Can't find the help file.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private void githubToolStripMenuItem_Click(object sender, EventArgs e) + { + System.Diagnostics.Process.Start("https://github.com/Dotsarecool/DiztinGUIsh"); + } + + private string PromptOpenBizhawkCDLFile() + { + openCDLDialog.InitialDirectory = Project.ProjectFileName; + if (openCDLDialog.ShowDialog() != DialogResult.OK) + return ""; + + return !PromptContinueEvenIfUnsavedChanges() ? "" : openCDLDialog.FileName; + } + + private static void ReportNumberFlagsModified(long numModifiedFlags, int numFiles = 1) + { + MessageBox.Show($"Modified total {numModifiedFlags} flags from {numFiles} files!", + "Done", + MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + private bool PromptForImportBSNESTraceLogFile() + { + openTraceLogDialog.Multiselect = true; + return openTraceLogDialog.ShowDialog() == DialogResult.OK; + } + + private static void ShowOffsetOutOfRangeMsg() + { + ShowError("That offset is out of range.", "Error"); + } + + private int PromptForGotoOffset() + { + if (!RomDataPresent()) + return -1; + + var go = new GotoDialog(ViewOffset + table.CurrentCell.RowIndex, Project.Data); + var result = go.ShowDialog(); + if (result != DialogResult.OK) + return -1; + + return go.GetPcOffset(); + } + + private static void ShowError(string errorMsg, string caption = "Error") + { + MessageBox.Show(errorMsg, caption, MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + private bool PromptHarshAutoStep(int offset, out int newOffset, out int count) + { + newOffset = count = -1; + + var harsh = new HarshAutoStep(offset, Project.Data); + if (harsh.ShowDialog() != DialogResult.OK) + return false; + + newOffset = harsh.Start; + count = harsh.Count; + return true; + } + + private MarkManyDialog PromptMarkMany(int offset, int column) + { + var mark = new MarkManyDialog(offset, column, Project.Data); + return mark.ShowDialog() == DialogResult.OK ? mark : null; + } + + private bool PromptForMisalignmentCheck() + { + if (!RomDataPresent()) + return false; + + return new MisalignmentChecker(Project.Data).ShowDialog() == DialogResult.OK; + } + + private static void ShowInfo(string s, string caption) + { + MessageBox.Show(s, caption, + MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + private bool PromptForInOutChecking() + { + if (!RomDataPresent()) + return false; + + return new InOutPointChecker().ShowDialog() == DialogResult.OK; + } + + public string AskToSelectNewRomFilename(string promptSubject, string promptText) + { + string initialDir = null; // TODO: Project.ProjectFileName + return GuiUtil.PromptToConfirmAction(promptSubject, promptText, + () => GuiUtil.PromptToSelectFile(initialDir) + ); + } + + public void OnProjectOpenWarning(string warningMsg) + { + MessageBox.Show(warningMsg, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + } +} \ No newline at end of file diff --git a/DiztinGUIsh/window/MainWindow.Properties.cs b/DiztinGUIsh/window/MainWindow.Properties.cs new file mode 100644 index 00000000..e1f01de0 --- /dev/null +++ b/DiztinGUIsh/window/MainWindow.Properties.cs @@ -0,0 +1,47 @@ +using Diz.Core.model; +using Diz.Core.util; +using DiztinGUIsh.controller; + +namespace DiztinGUIsh.window +{ + public partial class MainWindow + { + public DizDocument Document { get; } = new DizDocument(); + + public Project Project + { + get => Document.Project; + set => Document.Project = value; + } + + // not sure if this will be the final place this lives. OK for now. -Dom + public ProjectController ProjectController { get; protected set; } + + IProjectView.LongRunningTaskHandler IProjectView.TaskHandler => + ProgressBarJob.RunAndWaitForCompletion; + + // sub windows + public AliasList AliasList; + private VisualizerForm visualForm; + + // TODO: add a handler so we get notified when CurrentViewOffset changes. + // then, we split most of our functions up into + // 1. things that change ViewOffset + // 2. things that react to ViewOffset changes. + // + // This will allow more flexibility and synchronizing different views (i.e. main table, graphics, layout, etc) + // and this lets us save this value with the project file itself. + + // Data offset of the "view" i.e. the top of the table + private int ViewOffset + { + get => Project?.CurrentViewOffset ?? 0; + set => Project.CurrentViewOffset = value; + } + + private bool importerMenuItemsEnabled; + + private Util.NumberBase displayBase = Util.NumberBase.Hexadecimal; + private Data.FlagType markFlag = Data.FlagType.Data8Bit; + } +} \ No newline at end of file diff --git a/DiztinGUIsh/window/MainWindow.ReadOnlyHelpers.cs b/DiztinGUIsh/window/MainWindow.ReadOnlyHelpers.cs new file mode 100644 index 00000000..b5cb3542 --- /dev/null +++ b/DiztinGUIsh/window/MainWindow.ReadOnlyHelpers.cs @@ -0,0 +1,68 @@ +using Diz.Core.model; + +namespace DiztinGUIsh.window +{ + public partial class MainWindow + { + private int FindIntermediateAddress(int offset) + { + if (!RomDataPresent()) + return -1; + + var ia = Project.Data.GetIntermediateAddressOrPointer(offset); + if (ia < 0) + return -1; + + return Project.Data.ConvertSnesToPc(ia); + } + + private bool FindUnreached(int offset, bool end, bool direction, out int unreached) + { + var size = Project.Data.GetRomSize(); + unreached = end ? (direction ? 0 : size - 1) : offset; + + if (direction) + { + if (!end) + while (unreached < size - 1 && IsUnreached(unreached)) + unreached++; + + while (unreached < size - 1 && IsReached(unreached)) + unreached++; + } + else + { + if (unreached > 0) + unreached--; + + while (unreached > 0 && IsReached(unreached)) + unreached--; + } + + while (unreached > 0 && IsUnreached(unreached - 1)) + unreached--; + + return IsUnreached(unreached); + } + + private bool IsReached(int offset) + { + return Project.Data.GetFlag(offset) != Data.FlagType.Unreached; + } + + private bool IsUnreached(int offset) + { + return Project.Data.GetFlag(offset) == Data.FlagType.Unreached; + } + + private bool RomDataPresent() + { + return Project?.Data?.GetRomSize() > 0; + } + + private bool IsOffsetInRange(int offset) + { + return offset >= 0 && offset < Project.Data.GetRomSize(); + } + } +} \ No newline at end of file diff --git a/DiztinGUIsh/window/MainWindow.SimpleUI.cs b/DiztinGUIsh/window/MainWindow.SimpleUI.cs new file mode 100644 index 00000000..e9aa1914 --- /dev/null +++ b/DiztinGUIsh/window/MainWindow.SimpleUI.cs @@ -0,0 +1,137 @@ +using System; +using System.Windows.Forms; +using Diz.Core.model; +using Diz.Core.util; +using DiztinGUIsh.window.dialog; + +namespace DiztinGUIsh.window +{ + public partial class MainWindow + { + private void MainWindow_FormClosing(object sender, FormClosingEventArgs e) => + e.Cancel = !PromptContinueEvenIfUnsavedChanges(); + + private void MainWindow_SizeChanged(object sender, EventArgs e) => UpdatePanels(); + private void MainWindow_ResizeEnd(object sender, EventArgs e) => UpdateDataGridView(); + private void MainWindow_Load(object sender, EventArgs e) => Init(); + private void newProjectToolStripMenuItem_Click(object sender, EventArgs e) => CreateNewProject(); + private void openProjectToolStripMenuItem_Click(object sender, EventArgs e) => OpenProject(); + + private void saveProjectToolStripMenuItem_Click(object sender, EventArgs e) => SaveProject(); + + private void saveProjectAsToolStripMenuItem_Click(object sender, EventArgs e) => PromptForFilenameToSave(); + private void exportLogToolStripMenuItem_Click(object sender, EventArgs e) => ExportAssembly(); + private void aboutToolStripMenuItem_Click(object sender, EventArgs e) => new About().ShowDialog(); + private void exitToolStripMenuItem_Click(object sender, EventArgs e) => Application.Exit(); + + private void decimalToolStripMenuItem_Click(object sender, EventArgs e) => + UpdateBase(Util.NumberBase.Decimal); + + private void hexadecimalToolStripMenuItem_Click(object sender, EventArgs e) => + UpdateBase(Util.NumberBase.Hexadecimal); + + private void binaryToolStripMenuItem_Click(object sender, EventArgs e) => + UpdateBase(Util.NumberBase.Binary); + + private void importTraceLogBinary_Click(object sender, EventArgs e) => ImportBsnesBinaryTraceLog(); + private void addLabelToolStripMenuItem_Click(object sender, EventArgs e) => BeginAddingLabel(); + private void visualMapToolStripMenuItem_Click(object sender, EventArgs e) => ShowVisualizerForm(); + private void stepOverToolStripMenuItem_Click(object sender, EventArgs e) => Step(SelectedOffset); + private void stepInToolStripMenuItem_Click(object sender, EventArgs e) => StepIn(SelectedOffset); + private void autoStepSafeToolStripMenuItem_Click(object sender, EventArgs e) => AutoStepSafe(SelectedOffset); + private void autoStepHarshToolStripMenuItem_Click(object sender, EventArgs e) => AutoStepHarsh(SelectedOffset); + private void gotoToolStripMenuItem_Click(object sender, EventArgs e) => GoTo(PromptForGotoOffset()); + + private void gotoIntermediateAddressToolStripMenuItem_Click(object sender, EventArgs e) => + GoToIntermediateAddress(SelectedOffset); + + private void gotoFirstUnreachedToolStripMenuItem_Click(object sender, EventArgs e) => + GoToUnreached(true, true); + + private void gotoNearUnreachedToolStripMenuItem_Click(object sender, EventArgs e) => + GoToUnreached(false, false); + + private void gotoNextUnreachedToolStripMenuItem_Click(object sender, EventArgs e) => + GoToUnreached(false, true); + + private void markOneToolStripMenuItem_Click(object sender, EventArgs e) => Mark(SelectedOffset); + private void markManyToolStripMenuItem_Click(object sender, EventArgs e) => MarkMany(SelectedOffset, 7); + private void setDataBankToolStripMenuItem_Click(object sender, EventArgs e) => MarkMany(SelectedOffset, 8); + private void setDirectPageToolStripMenuItem_Click(object sender, EventArgs e) => MarkMany(SelectedOffset, 9); + + private void toggleAccumulatorSizeMToolStripMenuItem_Click(object sender, EventArgs e) => MarkMany(SelectedOffset, 10); + + private void toggleIndexSizeToolStripMenuItem_Click(object sender, EventArgs e) => MarkMany(SelectedOffset, 11); + private void addCommentToolStripMenuItem_Click(object sender, EventArgs e) => BeginEditingComment(); + + private void unreachedToolStripMenuItem_Click(object sender, EventArgs e) => + SetMarkerLabel(Data.FlagType.Unreached); + + private void opcodeToolStripMenuItem_Click(object sender, EventArgs e) => SetMarkerLabel(Data.FlagType.Opcode); + + private void operandToolStripMenuItem_Click(object sender, EventArgs e) => + SetMarkerLabel(Data.FlagType.Operand); + + private void bitDataToolStripMenuItem_Click(object sender, EventArgs e) => + SetMarkerLabel(Data.FlagType.Data8Bit); + + private void graphicsToolStripMenuItem_Click(object sender, EventArgs e) => + SetMarkerLabel(Data.FlagType.Graphics); + + private void musicToolStripMenuItem_Click(object sender, EventArgs e) => SetMarkerLabel(Data.FlagType.Music); + private void emptyToolStripMenuItem_Click(object sender, EventArgs e) => SetMarkerLabel(Data.FlagType.Empty); + + private void bitDataToolStripMenuItem1_Click(object sender, EventArgs e) => + SetMarkerLabel(Data.FlagType.Data16Bit); + + private void wordPointerToolStripMenuItem_Click(object sender, EventArgs e) => + SetMarkerLabel(Data.FlagType.Pointer16Bit); + + private void bitDataToolStripMenuItem2_Click(object sender, EventArgs e) => + SetMarkerLabel(Data.FlagType.Data24Bit); + + private void longPointerToolStripMenuItem_Click(object sender, EventArgs e) => + SetMarkerLabel(Data.FlagType.Pointer24Bit); + + private void bitDataToolStripMenuItem3_Click(object sender, EventArgs e) => + SetMarkerLabel(Data.FlagType.Data32Bit); + + private void dWordPointerToolStripMenuItem_Click(object sender, EventArgs e) => + SetMarkerLabel(Data.FlagType.Pointer32Bit); + + private void textToolStripMenuItem_Click(object sender, EventArgs e) => SetMarkerLabel(Data.FlagType.Text); + + private void fixMisalignedInstructionsToolStripMenuItem_Click(object sender, EventArgs e) => + FixMisalignedInstructions(); + + private void moveWithStepToolStripMenuItem_Click(object sender, EventArgs e) => ToggleMoveWithStep(); + private void labelListToolStripMenuItem_Click(object sender, EventArgs e) => ShowCommentList(); + + private void openLastProjectAutomaticallyToolStripMenuItem_Click(object sender, EventArgs e) => + ToggleOpenLastProjectEnabled(); + + private void closeProjectToolStripMenuItem_Click(object sender, EventArgs e) + { + // TODO + } + + private void importCDLToolStripMenuItem_Click_1(object sender, EventArgs e) => ImportBizhawkCDL(); + + private void importBsnesTracelogText_Click(object sender, EventArgs e) => ImportBsnesTraceLogText(); + + private void graphicsWindowToolStripMenuItem_Click(object sender, EventArgs e) + { + // TODO + // graphics view window + } + + private void toolStripOpenLast_Click(object sender, EventArgs e) + { + OpenLastProject(); + } + + private void rescanForInOutPointsToolStripMenuItem_Click(object sender, EventArgs e) => RescanForInOut(); + private void importUsageMapToolStripMenuItem_Click_1(object sender, EventArgs e) => ImportBSNESUsageMap(); + private void table_MouseWheel(object sender, MouseEventArgs e) => ScrollTableBy(e.Delta); + } +} \ No newline at end of file diff --git a/DiztinGUIsh/window/MainWindow.StateUpdate.cs b/DiztinGUIsh/window/MainWindow.StateUpdate.cs new file mode 100644 index 00000000..d0f1f5fc --- /dev/null +++ b/DiztinGUIsh/window/MainWindow.StateUpdate.cs @@ -0,0 +1,146 @@ +using System.IO; +using System.Windows.Forms; +using Diz.Core.model; +using Diz.Core.util; +using DiztinGUIsh.Properties; + +namespace DiztinGUIsh.window +{ + // This file is mostly about various controls reacting to state changes + // + // The direction we need to take this is being driven almost 100% by INotifyChanged events coming off + // DizDocument, Data, and Project classes --- instead of being explicitly pushed. + public partial class MainWindow + { + private void RebindProject() + { + AliasList?.RebindProject(); + if (visualForm != null) + visualForm.Project = Project; + } + + private void UpdatePanels() + { + table.Height = this.Height - 85; + table.Width = this.Width - 33; + vScrollBar1.Height = this.Height - 85; + vScrollBar1.Left = this.Width - 33; + if (WindowState == FormWindowState.Maximized) UpdateDataGridView(); + } + + public void UpdateWindowTitle() + { + Text = + (Project.UnsavedChanges ? "*" : "") + + (Project.ProjectFileName ?? "New Project") + + " - DiztinGUIsh"; + } + + private void UpdateUiFromSettings() + { + var lastOpenedFilePresent = Settings.Default.LastOpenedFile != ""; + + toolStripOpenLast.Enabled = lastOpenedFilePresent; + toolStripOpenLast.Text = "Open Last File"; + if (lastOpenedFilePresent) + toolStripOpenLast.Text += $" ({Path.GetFileNameWithoutExtension(Settings.Default.LastOpenedFile)})"; + + openLastProjectAutomaticallyToolStripMenuItem.Checked = Settings.Default.OpenLastFileAutomatically; + } + + private void RefreshUi() + { + importCDLToolStripMenuItem.Enabled = true; + UpdateWindowTitle(); + UpdateDataGridView(); + UpdatePercent(); + table.Invalidate(); + EnableSubWindows(); + } + + private void UpdateBase(Util.NumberBase noBase) + { + displayBase = noBase; + decimalToolStripMenuItem.Checked = noBase == Util.NumberBase.Decimal; + hexadecimalToolStripMenuItem.Checked = noBase == Util.NumberBase.Hexadecimal; + binaryToolStripMenuItem.Checked = noBase == Util.NumberBase.Binary; + InvalidateTable(); + } + + public void UpdatePercent() + { + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) + return; + + int totalUnreached = 0, size = Project.Data.GetRomSize(); + for (int i = 0; i < size; i++) + if (Project.Data.GetFlag(i) == Data.FlagType.Unreached) + totalUnreached++; + int reached = size - totalUnreached; + percentComplete.Text = $"{reached * 100.0 / size:N3}% ({reached:D}/{size:D})"; + } + + public void UpdateMarkerLabel() + { + currentMarker.Text = $"Marker: {markFlag.ToString()}"; + } + + private void UpdateDataGridView() + { + if (Project?.Data == null || Project.Data.GetRomSize() <= 0) + return; + + rowsToShow = ((table.Height - table.ColumnHeadersHeight) / table.RowTemplate.Height); + + if (ViewOffset + rowsToShow > Project.Data.GetRomSize()) + ViewOffset = Project.Data.GetRomSize() - rowsToShow; + + if (ViewOffset < 0) + ViewOffset = 0; + + vScrollBar1.Enabled = true; + vScrollBar1.Maximum = Project.Data.GetRomSize() - rowsToShow; + vScrollBar1.Value = ViewOffset; + table.RowCount = rowsToShow; + + importerMenuItemsEnabled = true; + UpdateImporterEnabledStatus(); + } + + private void UpdateImporterEnabledStatus() + { + importUsageMapToolStripMenuItem.Enabled = importerMenuItemsEnabled; + importCDLToolStripMenuItem.Enabled = importerMenuItemsEnabled; + importTraceLogBinary.Enabled = importerMenuItemsEnabled; + importTraceLogText.Enabled = importerMenuItemsEnabled; + } + + private void EnableSubWindows() + { + labelListToolStripMenuItem.Enabled = true; + } + + public void UpdateSaveOptionStates(bool saveEnabled, bool saveAsEnabled, bool closeEnabled) + { + saveProjectToolStripMenuItem.Enabled = saveEnabled; + saveProjectAsToolStripMenuItem.Enabled = saveAsEnabled; + closeProjectToolStripMenuItem.Enabled = closeEnabled; + + exportLogToolStripMenuItem.Enabled = true; + } + + private void UpdateSomeUI2() + { + // refactor this somewhere else + UpdateUI_Tmp3(); + InvalidateTable(); + } + + private void UpdateUI_Tmp3() + { + // refactor this somewhere else + UpdatePercent(); + UpdateWindowTitle(); + } + } +} \ No newline at end of file diff --git a/DiztinGUIsh/window/MainWindow.cs b/DiztinGUIsh/window/MainWindow.cs index 046c6b1e..cec65b2c 100644 --- a/DiztinGUIsh/window/MainWindow.cs +++ b/DiztinGUIsh/window/MainWindow.cs @@ -1,94 +1,28 @@ -using System; -using System.Globalization; -using System.IO; -using System.Windows.Forms; +using System.Windows.Forms; using Diz.Core.export; using Diz.Core.model; -using Diz.Core.util; using DiztinGUIsh.controller; using DiztinGUIsh.Properties; -using DiztinGUIsh.window.dialog; -using Color = System.Drawing.Color; -using Label = Diz.Core.model.Label; namespace DiztinGUIsh.window { public partial class MainWindow : Form, IProjectView { - public Project Project { get; set; } - public MainWindow() { ProjectController = new ProjectController { ProjectView = this, }; + + Document.PropertyChanged += Document_PropertyChanged; ProjectController.ProjectChanged += ProjectController_ProjectChanged; InitializeComponent(); } - - private void ProjectController_ProjectChanged(object sender, ProjectController.ProjectChangedEventArgs e) + + private void Init() { - RebindProject(); - - switch (e.ChangeType) - { - case ProjectController.ProjectChangedEventArgs.ProjectChangedType.Saved: - OnProjectSaved(); - break; - case ProjectController.ProjectChangedEventArgs.ProjectChangedType.Opened: - OnProjectOpened(e.Filename); - break; - case ProjectController.ProjectChangedEventArgs.ProjectChangedType.Imported: - OnImportedProjectSuccess(); - break; - } - } - - private void RebindProject() - { - AliasList.RebindProject(); - } - - private void MainWindow_FormClosing(object sender, FormClosingEventArgs e) - { - e.Cancel = !ContinueUnsavedChanges(); - } - - private void MainWindow_SizeChanged(object sender, EventArgs e) - { - UpdatePanels(); - } - - private void UpdatePanels() - { - table.Height = this.Height - 85; - table.Width = this.Width - 33; - vScrollBar1.Height = this.Height - 85; - vScrollBar1.Left = this.Width - 33; - if (WindowState == FormWindowState.Maximized) UpdateDataGridView(); - } - - private void MainWindow_ResizeEnd(object sender, EventArgs e) - { - UpdateDataGridView(); - } - - private void MainWindow_Load(object sender, EventArgs e) - { - table.CellValueNeeded += new DataGridViewCellValueEventHandler(table_CellValueNeeded); - table.CellValuePushed += new DataGridViewCellValueEventHandler(table_CellValuePushed); - table.CellPainting += new DataGridViewCellPaintingEventHandler(table_CellPainting); - - rowsToShow = ((table.Height - table.ColumnHeadersHeight) / table.RowTemplate.Height); - - // https://stackoverflow.com/a/1506066 - typeof(DataGridView).InvokeMember( - "DoubleBuffered", - System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.SetProperty, - null, - table, - new object[] { true }); + InitMainTable(); AliasList = new AliasList(this); @@ -99,99 +33,39 @@ private void MainWindow_Load(object sender, EventArgs e) OpenLastProject(); } - private void OpenLastProject() - { - if (LastProjectFilename == "") - return; - - // safeguard: if we crash opening this project, - // then next time we load make sure we don't try it again. - // this will be reset later - var projectToOpen = LastProjectFilename; - LastProjectFilename = ""; - - OpenProject(projectToOpen); - } - - public void UpdateWindowTitle() - { - this.Text = - (Project.UnsavedChanges ? "*" : "") + - (Project.ProjectFileName ?? "New Project") + - " - DiztinGUIsh"; - } - - private bool ContinueUnsavedChanges() - { - if (Project == null || !Project.UnsavedChanges) - return true; - - return DialogResult.OK == MessageBox.Show( - "You have unsaved changes. They will be lost if you continue.", - "Unsaved Changes", MessageBoxButtons.OKCancel); - - } - - public void UpdateSaveOptionStates(bool saveEnabled, bool saveAsEnabled) - { - saveProjectToolStripMenuItem.Enabled = saveEnabled; - saveProjectAsToolStripMenuItem.Enabled = saveAsEnabled; - exportLogToolStripMenuItem.Enabled = true; - } - private void newProjectToolStripMenuItem_Click(object sender, EventArgs e) + private void Document_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { - if (!ContinueUnsavedChanges()) - return; - - var romFilename = PromptForOpenFilename(); - if (string.IsNullOrEmpty(romFilename)) - return; - - ProjectController.ImportRomAndCreateNewProject(openFileDialog.FileName); - } - - private string PromptForOpenFilename() - { - // TODO: combine with another function in Project that feels similar to this - openFileDialog.InitialDirectory = Project?.ProjectFileName ?? ""; - return openFileDialog.ShowDialog() == DialogResult.OK ? openFileDialog.FileName : null; - } - - private void openProjectToolStripMenuItem_Click(object sender, EventArgs e) - { - if (!ContinueUnsavedChanges()) - return; - - openProjectFile.InitialDirectory = Project?.ProjectFileName; - if (openProjectFile.ShowDialog() != DialogResult.OK) - return; - - OpenProject(openProjectFile.FileName); + if (e.PropertyName == nameof(DizDocument.LastProjectFilename)) + { + UpdateUiFromSettings(); + } } - // TODO: state change should be moved into the controller - public string LastProjectFilename + private void ProjectController_ProjectChanged(object sender, ProjectController.ProjectChangedEventArgs e) { - get => Settings.Default.LastOpenedFile; - set + switch (e.ChangeType) { - Settings.Default.LastOpenedFile = value; - Settings.Default.Save(); - - UpdateUiFromSettings(); + case ProjectController.ProjectChangedEventArgs.ProjectChangedType.Saved: + OnProjectSaved(); + break; + case ProjectController.ProjectChangedEventArgs.ProjectChangedType.Opened: + OnProjectOpened(e.Filename); + break; + case ProjectController.ProjectChangedEventArgs.ProjectChangedType.Imported: + OnImportedProjectSuccess(); + break; + case ProjectController.ProjectChangedEventArgs.ProjectChangedType.Closing: + OnProjectClosing(); + break; } + + RebindProject(); } - private void UpdateUiFromSettings() + private void OnProjectClosing() { - var lastOpenedFilePresent = Settings.Default.LastOpenedFile != ""; - toolStripOpenLast.Enabled = lastOpenedFilePresent; - toolStripOpenLast.Text = "Open Last File"; - if (lastOpenedFilePresent) - toolStripOpenLast.Text += $" ({Path.GetFileNameWithoutExtension(Settings.Default.LastOpenedFile)})"; - - openLastProjectAutomaticallyToolStripMenuItem.Checked = Settings.Default.OpenLastFileAutomatically; + UpdateSaveOptionStates(saveEnabled: false, saveAsEnabled: false, closeEnabled: false); } public void OnProjectOpened(string filename) @@ -201,87 +75,27 @@ public void OnProjectOpened(string filename) // TODO: do this with aliaslist too. - UpdateSaveOptionStates(true, true); + UpdateSaveOptionStates(saveEnabled: true, saveAsEnabled: true, closeEnabled: true); RefreshUi(); - LastProjectFilename = filename; // do this last. - } - - private void OnImportedProjectSuccess() - { - UpdateSaveOptionStates(false, true); - RefreshUi(); - } - - private void RefreshUi() - { - importCDLToolStripMenuItem.Enabled = true; - UpdateWindowTitle(); - UpdateDataGridView(); - UpdatePercent(); - table.Invalidate(); - EnableSubWindows(); + Document.LastProjectFilename = filename; // do this last. } public void OnProjectOpenFail(string errorMsg) { - LastProjectFilename = ""; - MessageBox.Show(errorMsg, "Error opening project", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - - public void OpenProject(string filename) - { - ProjectController.OpenProject(filename); - } - - private void saveProjectToolStripMenuItem_Click(object sender, EventArgs e) - { - SaveProject(Project.ProjectFileName); - } - - public void SaveProject(string filename) - { - ProjectController.SaveProject(filename); + Document.LastProjectFilename = ""; + ShowError(errorMsg, "Error opening project"); } public void OnProjectSaved() { - UpdateSaveOptionStates(true, true); + UpdateSaveOptionStates(saveEnabled: true, saveAsEnabled: true, closeEnabled: true); UpdateWindowTitle(); } public void OnExportFinished(LogCreator.OutputResult result) { - if (result.ErrorCount > 0) - MessageBox.Show("Disassembly created with errors. See errors.txt for details.", "Warning", - MessageBoxButtons.OK, MessageBoxIcon.Warning); - else - MessageBox.Show("Disassembly created successfully!", "Complete", MessageBoxButtons.OK, - MessageBoxIcon.Asterisk); - } - - IProjectView.LongRunningTaskHandler IProjectView.TaskHandler => - ProgressBarJob.RunAndWaitForCompletion; - - private void saveProjectAsToolStripMenuItem_Click(object sender, EventArgs e) - { - saveProjectFile.InitialDirectory = Project.AttachedRomFilename; - if (saveProjectFile.ShowDialog() == DialogResult.OK && saveProjectFile.FileName != "") - { - SaveProject(saveProjectFile.FileName); - } - } - - public ProjectController ProjectController { get; protected set; } - - private void exportLogToolStripMenuItem_Click(object sender, EventArgs e) - { - var adjustedSettings = PromptForExportSettingsAndConfirmation(); - if (!adjustedSettings.HasValue) - return; - - ProjectController.UpdateExportSettings(adjustedSettings.Value); - ProjectController.WriteAssemblyOutput(); + ShowExportResults(result); } private LogWriterSettings? PromptForExportSettingsAndConfirmation() @@ -300,943 +114,5 @@ private void exportLogToolStripMenuItem_Click(object sender, EventArgs e) return settings; } - - private void viewHelpToolStripMenuItem_Click(object sender, EventArgs e) - { - try - { - System.Diagnostics.Process.Start(Directory.GetCurrentDirectory() + "/help.html"); - } - catch (Exception) - { - MessageBox.Show("Can't find the help file.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - - private void githubToolStripMenuItem_Click(object sender, EventArgs e) - { - System.Diagnostics.Process.Start("https://github.com/Dotsarecool/DiztinGUIsh"); - } - - private void aboutToolStripMenuItem_Click(object sender, EventArgs e) - { - var about = new About(); - about.ShowDialog(); - } - - private void exitToolStripMenuItem_Click(object sender, EventArgs e) - { - Application.Exit(); - } - - private Util.NumberBase displayBase = Util.NumberBase.Hexadecimal; - private Data.FlagType markFlag = Data.FlagType.Data8Bit; - private bool moveWithStep = true; - - private void decimalToolStripMenuItem_Click(object sender, EventArgs e) - { - UpdateBase(Util.NumberBase.Decimal); - } - - private void hexadecimalToolStripMenuItem_Click(object sender, EventArgs e) - { - UpdateBase(Util.NumberBase.Hexadecimal); - } - - private void binaryToolStripMenuItem_Click(object sender, EventArgs e) - { - UpdateBase(Util.NumberBase.Binary); - } - - private void UpdateBase(Util.NumberBase noBase) - { - displayBase = noBase; - decimalToolStripMenuItem.Checked = noBase == Util.NumberBase.Decimal; - hexadecimalToolStripMenuItem.Checked = noBase == Util.NumberBase.Hexadecimal; - binaryToolStripMenuItem.Checked = noBase == Util.NumberBase.Binary; - InvalidateTable(); - } - - public void UpdatePercent() - { - if (Project?.Data == null || Project.Data.GetRomSize() <= 0) - return; - - int totalUnreached = 0, size = Project.Data.GetRomSize(); - for (int i = 0; i < size; i++) - if (Project.Data.GetFlag(i) == Data.FlagType.Unreached) - totalUnreached++; - int reached = size - totalUnreached; - percentComplete.Text = $"{reached * 100.0 / size:N3}% ({reached:D}/{size:D})"; - } - - public void UpdateMarkerLabel() - { - currentMarker.Text = $"Marker: {markFlag.ToString()}"; - } - - public void InvalidateTable() - { - table.Invalidate(); - } - - // DataGridView - - // TODO: add a handler so we get notified when CurrentViewOffset changes. - // then, we split most of our functions up into - // 1. things that change ViewOffset - // 2. things that react to ViewOffset changes. - // - // This will allow more flexibility and synchronizing different views (i.e. main table, graphics, layout, etc) - // and this lets us save this value with the project file itself. - private int ViewOffset - { - get => Project?.CurrentViewOffset ?? 0; - set => Project.CurrentViewOffset = value; - } - - private int rowsToShow; - - private bool importerMenuItemsEnabled; - - private void UpdateDataGridView() - { - if (Project?.Data == null || Project.Data.GetRomSize() <= 0) - return; - - rowsToShow = ((table.Height - table.ColumnHeadersHeight) / table.RowTemplate.Height); - - if (ViewOffset + rowsToShow > Project.Data.GetRomSize()) - ViewOffset = Project.Data.GetRomSize() - rowsToShow; - - if (ViewOffset < 0) - ViewOffset = 0; - - vScrollBar1.Enabled = true; - vScrollBar1.Maximum = Project.Data.GetRomSize() - rowsToShow; - vScrollBar1.Value = ViewOffset; - table.RowCount = rowsToShow; - - importerMenuItemsEnabled = true; - UpdateImporterEnabledStatus(); - } - - private void UpdateImporterEnabledStatus() - { - importUsageMapToolStripMenuItem.Enabled = importerMenuItemsEnabled; - importCDLToolStripMenuItem.Enabled = importerMenuItemsEnabled; - importTraceLogBinary.Enabled = importerMenuItemsEnabled; - importTraceLogText.Enabled = importerMenuItemsEnabled; - } - - private void table_MouseWheel(object sender, MouseEventArgs e) - { - if (Project?.Data == null || Project.Data.GetRomSize() <= 0) - return; - int selRow = table.CurrentCell.RowIndex + ViewOffset, selCol = table.CurrentCell.ColumnIndex; - var amount = e.Delta / 0x18; - ViewOffset -= amount; - UpdateDataGridView(); - if (selRow < ViewOffset) selRow = ViewOffset; - else if (selRow >= ViewOffset + rowsToShow) selRow = ViewOffset + rowsToShow - 1; - table.CurrentCell = table.Rows[selRow - ViewOffset].Cells[selCol]; - InvalidateTable(); - } - - private void vScrollBar1_ValueChanged(object sender, EventArgs e) - { - if (table.CurrentCell == null) - return; - - int selOffset = table.CurrentCell.RowIndex + ViewOffset; - ViewOffset = vScrollBar1.Value; - UpdateDataGridView(); - - if (selOffset < ViewOffset) table.CurrentCell = table.Rows[0].Cells[table.CurrentCell.ColumnIndex]; - else if (selOffset >= ViewOffset + rowsToShow) - table.CurrentCell = table.Rows[rowsToShow - 1].Cells[table.CurrentCell.ColumnIndex]; - else table.CurrentCell = table.Rows[selOffset - ViewOffset].Cells[table.CurrentCell.ColumnIndex]; - - InvalidateTable(); - } - - private void table_MouseDown(object sender, MouseEventArgs e) - { - InvalidateTable(); - } - - private void table_KeyDown(object sender, KeyEventArgs e) - { - if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; - - int offset = table.CurrentCell.RowIndex + ViewOffset; - int newOffset = offset; - int amount = 0x01; - - Console.WriteLine(e.KeyCode); - switch (e.KeyCode) - { - case Keys.Home: - case Keys.PageUp: - case Keys.Up: - amount = e.KeyCode == Keys.Up ? 0x01 : e.KeyCode == Keys.PageUp ? 0x10 : 0x100; - newOffset = offset - amount; - if (newOffset < 0) newOffset = 0; - SelectOffset(newOffset); - break; - case Keys.End: - case Keys.PageDown: - case Keys.Down: - amount = e.KeyCode == Keys.Down ? 0x01 : e.KeyCode == Keys.PageDown ? 0x10 : 0x100; - newOffset = offset + amount; - if (newOffset >= Project.Data.GetRomSize()) newOffset = Project.Data.GetRomSize() - 1; - SelectOffset(newOffset); - break; - case Keys.Left: - amount = table.CurrentCell.ColumnIndex; - amount = amount - 1 < 0 ? 0 : amount - 1; - table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[amount]; - break; - case Keys.Right: - amount = table.CurrentCell.ColumnIndex; - amount = amount + 1 >= table.ColumnCount ? table.ColumnCount - 1 : amount + 1; - table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[amount]; - break; - case Keys.S: - Step(offset); - break; - case Keys.I: - StepIn(offset); - break; - case Keys.A: - AutoStepSafe(offset); - break; - case Keys.T: - GoToIntermediateAddress(offset); - break; - case Keys.U: - GoToUnreached(true, true); - break; - case Keys.H: - GoToUnreached(false, false); - break; - case Keys.N: - GoToUnreached(false, true); - break; - case Keys.K: - Mark(offset); - break; - case Keys.L: - table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[0]; - table.BeginEdit(true); - break; - case Keys.B: - table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[8]; - table.BeginEdit(true); - break; - case Keys.D: - table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[9]; - table.BeginEdit(true); - break; - case Keys.M: - Project.Data.SetMFlag(offset, !Project.Data.GetMFlag(offset)); - break; - case Keys.X: - Project.Data.SetXFlag(offset, !Project.Data.GetXFlag(offset)); - break; - case Keys.C: - table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[12]; - table.BeginEdit(true); - break; - } - - e.Handled = true; - InvalidateTable(); - } - - private void table_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) - { - int row = e.RowIndex + ViewOffset; - if (row >= Project.Data.GetRomSize()) return; - switch (e.ColumnIndex) - { - case 0: - e.Value = Project.Data.GetLabelName(Project.Data.ConvertPCtoSnes(row)); - break; - case 1: - e.Value = Util.NumberToBaseString(Project.Data.ConvertPCtoSnes(row), Util.NumberBase.Hexadecimal, 6); - break; - case 2: - e.Value = (char) Project.Data.GetRomByte(row); - break; - case 3: - e.Value = Util.NumberToBaseString(Project.Data.GetRomByte(row), displayBase); - break; - case 4: - e.Value = RomUtil.PointToString(Project.Data.GetInOutPoint(row)); - break; - case 5: - var len = Project.Data.GetInstructionLength(row); - e.Value = row + len <= Project.Data.GetRomSize() ? Project.Data.GetInstruction(row) : ""; - break; - case 6: - var ia = Project.Data.GetIntermediateAddressOrPointer(row); - e.Value = ia >= 0 ? Util.NumberToBaseString(ia, Util.NumberBase.Hexadecimal, 6) : ""; - break; - case 7: - e.Value = Util.GetEnumDescription(Project.Data.GetFlag(row)); - break; - case 8: - e.Value = Util.NumberToBaseString(Project.Data.GetDataBank(row), Util.NumberBase.Hexadecimal, 2); - break; - case 9: - e.Value = Util.NumberToBaseString(Project.Data.GetDirectPage(row), Util.NumberBase.Hexadecimal, 4); - break; - case 10: - e.Value = RomUtil.BoolToSize(Project.Data.GetMFlag(row)); - break; - case 11: - e.Value = RomUtil.BoolToSize(Project.Data.GetXFlag(row)); - break; - case 12: - e.Value = Project.Data.GetComment(Project.Data.ConvertPCtoSnes(row)); - break; - } - } - - private void table_CellValuePushed(object sender, DataGridViewCellValueEventArgs e) - { - string value = e.Value as string; - int result; - int row = e.RowIndex + ViewOffset; - if (row >= Project.Data.GetRomSize()) return; - switch (e.ColumnIndex) - { - case 0: - Project.Data.AddLabel(Project.Data.ConvertPCtoSnes(row), new Label() {Name = value}, true); - break; // todo (validate for valid label characters) - case 8: - if (int.TryParse(value, NumberStyles.HexNumber, null, out result)) Project.Data.SetDataBank(row, result); - break; - case 9: - if (int.TryParse(value, NumberStyles.HexNumber, null, out result)) Project.Data.SetDirectPage(row, result); - break; - case 10: - Project.Data.SetMFlag(row, (value == "8" || value == "M")); - break; - case 11: - Project.Data.SetXFlag(row, (value == "8" || value == "X")); - break; - case 12: - Project.Data.AddComment(Project.Data.ConvertPCtoSnes(row), value, true); - break; - } - - table.InvalidateRow(e.RowIndex); - } - - public void PaintCell(int offset, DataGridViewCellStyle style, int column, int selOffset) - { - // editable cells show up green - if (column == 0 || column == 8 || column == 9 || column == 12) style.SelectionBackColor = Color.Chartreuse; - - switch (Project.Data.GetFlag(offset)) - { - case Data.FlagType.Unreached: - style.BackColor = Color.LightGray; - style.ForeColor = Color.DarkSlateGray; - break; - case Data.FlagType.Opcode: - int opcode = Project.Data.GetRomByte(offset); - switch (column) - { - case 4: // <*> - Data.InOutPoint point = Project.Data.GetInOutPoint(offset); - int r = 255, g = 255, b = 255; - if ((point & (Data.InOutPoint.EndPoint | Data.InOutPoint.OutPoint)) != 0) g -= 50; - if ((point & (Data.InOutPoint.InPoint)) != 0) r -= 50; - if ((point & (Data.InOutPoint.ReadPoint)) != 0) b -= 50; - style.BackColor = Color.FromArgb(r, g, b); - break; - case 5: // Instruction - if (opcode == 0x40 || opcode == 0xCB || opcode == 0xDB || opcode == 0xF8 // RTI WAI STP SED - || opcode == 0xFB || opcode == 0x00 || opcode == 0x02 || opcode == 0x42 // XCE BRK COP WDM - ) style.BackColor = Color.Yellow; - break; - case 8: // Data Bank - if (opcode == 0xAB || opcode == 0x44 || opcode == 0x54) // PLB MVP MVN - style.BackColor = Color.OrangeRed; - else if (opcode == 0x8B) // PHB - style.BackColor = Color.Yellow; - break; - case 9: // Direct Page - if (opcode == 0x2B || opcode == 0x5B) // PLD TCD - style.BackColor = Color.OrangeRed; - if (opcode == 0x0B || opcode == 0x7B) // PHD TDC - style.BackColor = Color.Yellow; - break; - case 10: // M Flag - case 11: // X Flag - int mask = column == 10 ? 0x20 : 0x10; - if (opcode == 0x28 || ((opcode == 0xC2 || opcode == 0xE2) // PLP SEP REP - && (Project.Data.GetRomByte(offset + 1) & mask) != 0)) // relevant bit set - style.BackColor = Color.OrangeRed; - if (opcode == 0x08) // PHP - style.BackColor = Color.Yellow; - break; - } - break; - case Data.FlagType.Operand: - style.ForeColor = Color.LightGray; - break; - case Data.FlagType.Graphics: - style.BackColor = Color.LightPink; - break; - case Data.FlagType.Music: - style.BackColor = Color.PowderBlue; - break; - case Data.FlagType.Data8Bit: - case Data.FlagType.Data16Bit: - case Data.FlagType.Data24Bit: - case Data.FlagType.Data32Bit: - style.BackColor = Color.NavajoWhite; - break; - case Data.FlagType.Pointer16Bit: - case Data.FlagType.Pointer24Bit: - case Data.FlagType.Pointer32Bit: - style.BackColor = Color.Orchid; - break; - case Data.FlagType.Text: - style.BackColor = Color.Aquamarine; - break; - case Data.FlagType.Empty: - style.BackColor = Color.DarkSlateGray; - style.ForeColor = Color.LightGray; - break; - } - - if (selOffset >= 0 && selOffset < Project.Data.GetRomSize()) - { - if (column == 1 - //&& (Project.Data.GetFlag(selOffset) == Data.FlagType.Opcode || Project.Data.GetFlag(selOffset) == Data.FlagType.Unreached) - && Project.Data.ConvertSnesToPc(Project.Data.GetIntermediateAddressOrPointer(selOffset)) == offset - ) style.BackColor = Color.DeepPink; - - if (column == 6 - //&& (Project.Data.GetFlag(offset) == Data.FlagType.Opcode || Project.Data.GetFlag(offset) == Data.FlagType.Unreached) - && Project.Data.ConvertSnesToPc(Project.Data.GetIntermediateAddressOrPointer(offset)) == selOffset - ) style.BackColor = Color.DeepPink; - } - } - - private void table_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) - { - int row = e.RowIndex + ViewOffset; - if (row < 0 || row >= Project.Data.GetRomSize()) return; - PaintCell(row, e.CellStyle, e.ColumnIndex, table.CurrentCell.RowIndex + ViewOffset); - } - - public void SelectOffset(int offset, int column = -1) - { - var col = column == -1 ? table.CurrentCell.ColumnIndex : column; - if (offset < ViewOffset) - { - ViewOffset = offset; - UpdateDataGridView(); - table.CurrentCell = table.Rows[0].Cells[col]; - } - else if (offset >= ViewOffset + rowsToShow) - { - ViewOffset = offset - rowsToShow + 1; - UpdateDataGridView(); - table.CurrentCell = table.Rows[rowsToShow - 1].Cells[col]; - } - else - { - table.CurrentCell = table.Rows[offset - ViewOffset].Cells[col]; - } - } - - private void Step(int offset) - { - ProjectController.MarkChanged();; - SelectOffset(Project.Data.Step(offset, false, false, offset - 1)); - UpdatePercent(); - UpdateWindowTitle(); - } - - private void StepIn(int offset) - { - ProjectController.MarkChanged(); - SelectOffset(Project.Data.Step(offset, true, false, offset - 1)); - UpdatePercent(); - UpdateWindowTitle(); - } - - private void AutoStepSafe(int offset) - { - ProjectController.MarkChanged(); - var destination = Project.Data.AutoStep(offset, false, 0); - if (moveWithStep) - SelectOffset(destination); - UpdatePercent(); - UpdateWindowTitle(); - } - - private void AutoStepHarsh(int offset) - { - HarshAutoStep harsh = new HarshAutoStep(offset, Project.Data); - DialogResult result = harsh.ShowDialog(); - if (result == DialogResult.OK) - { - ProjectController.MarkChanged(); - int destination = Project.Data.AutoStep(harsh.GetOffset(), true, harsh.GetCount()); - if (moveWithStep) SelectOffset(destination); - UpdatePercent(); - UpdateWindowTitle(); - } - } - - private void Mark(int offset) - { - ProjectController.MarkChanged(); - SelectOffset(Project.Data.Mark(offset, markFlag, RomUtil.GetByteLengthForFlag(markFlag))); - UpdatePercent(); - UpdateWindowTitle(); - } - - private void MarkMany(int offset, int column) - { - var mark = new MarkManyDialog(offset, column, Project.Data); - var result = mark.ShowDialog(); - if (result != DialogResult.OK) - return; - - ProjectController.MarkChanged(); - - var destination = 0; - var col = mark.GetProperty(); - switch (col) - { - case 0: - destination = Project.Data.Mark(mark.GetOffset(), (Data.FlagType) mark.GetValue(), mark.GetCount()); - break; - case 1: - destination = Project.Data.MarkDataBank(mark.GetOffset(), (int) mark.GetValue(), mark.GetCount()); - break; - case 2: - destination = Project.Data.MarkDirectPage(mark.GetOffset(), (int) mark.GetValue(), mark.GetCount()); - break; - case 3: - destination = Project.Data.MarkMFlag(mark.GetOffset(), (bool) mark.GetValue(), mark.GetCount()); - break; - case 4: - destination = Project.Data.MarkXFlag(mark.GetOffset(), (bool) mark.GetValue(), mark.GetCount()); - break; - case 5: - destination = Project.Data.MarkArchitechture(mark.GetOffset(), (Data.Architecture) mark.GetValue(), - mark.GetCount()); - break; - } - - if (moveWithStep) - SelectOffset(destination); - - UpdatePercent(); - UpdateWindowTitle(); - InvalidateTable(); - } - - private void GoToIntermediateAddress(int offset) - { - var ia = Project.Data.GetIntermediateAddressOrPointer(offset); - if (ia < 0) - return; - - var pc = Project.Data.ConvertSnesToPc(ia); - if (pc < 0) - return; - - SelectOffset(pc, 1); - } - - private void GoToUnreached(bool end, bool direction) - { - int offset = table.CurrentCell.RowIndex + ViewOffset; - int size = Project.Data.GetRomSize(); - int unreached = end ? (direction ? 0 : size - 1) : offset; - - if (direction) - { - if (!end) - while (unreached < size - 1 && Project.Data.GetFlag(unreached) == Data.FlagType.Unreached) - unreached++; - while (unreached < size - 1 && Project.Data.GetFlag(unreached) != Data.FlagType.Unreached) unreached++; - } - else - { - if (unreached > 0) unreached--; - while (unreached > 0 && Project.Data.GetFlag(unreached) != Data.FlagType.Unreached) unreached--; - } - - while (unreached > 0 && Project.Data.GetFlag(unreached - 1) == Data.FlagType.Unreached) unreached--; - - if (Project.Data.GetFlag(unreached) == Data.FlagType.Unreached) SelectOffset(unreached, 1); - } - - private void visualMapToolStripMenuItem_Click(object sender, EventArgs e) - { - visualForm ??= new VisualizerForm(this); - visualForm.Show(); - } - - private void graphicsWindowToolStripMenuItem_Click(object sender, EventArgs e) - { - // TODO - // graphics view window - } - - private void stepOverToolStripMenuItem_Click(object sender, EventArgs e) - { - if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; - Step(table.CurrentCell.RowIndex + ViewOffset); - } - - private void stepInToolStripMenuItem_Click(object sender, EventArgs e) - { - if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; - StepIn(table.CurrentCell.RowIndex + ViewOffset); - } - - private void autoStepSafeToolStripMenuItem_Click(object sender, EventArgs e) - { - if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; - AutoStepSafe(table.CurrentCell.RowIndex + ViewOffset); - } - - private void autoStepHarshToolStripMenuItem_Click(object sender, EventArgs e) - { - if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; - AutoStepHarsh(table.CurrentCell.RowIndex + ViewOffset); - } - - private void gotoToolStripMenuItem_Click(object sender, EventArgs e) - { - if (Project?.Data == null || Project.Data.GetRomSize() <= 0) - return; - - var go = new GotoDialog(ViewOffset + table.CurrentCell.RowIndex, Project.Data); - var result = go.ShowDialog(); - if (result != DialogResult.OK) - return; - - var offset = go.GetPcOffset(); - if (offset >= 0 && offset < Project.Data.GetRomSize()) - SelectOffset(offset); - else - MessageBox.Show("That offset is out of range.", "Error", MessageBoxButtons.OK, - MessageBoxIcon.Error); - } - - private void gotoIntermediateAddressToolStripMenuItem_Click(object sender, EventArgs e) - { - if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; - GoToIntermediateAddress(table.CurrentCell.RowIndex + ViewOffset); - } - - private void gotoFirstUnreachedToolStripMenuItem_Click(object sender, EventArgs e) - { - GoToUnreached(true, true); - } - - private void gotoNearUnreachedToolStripMenuItem_Click(object sender, EventArgs e) - { - GoToUnreached(false, false); - } - - private void gotoNextUnreachedToolStripMenuItem_Click(object sender, EventArgs e) - { - GoToUnreached(false, true); - } - - private void markOneToolStripMenuItem_Click(object sender, EventArgs e) - { - if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; - Mark(table.CurrentCell.RowIndex + ViewOffset); - } - - private void markManyToolStripMenuItem_Click(object sender, EventArgs e) - { - if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; - MarkMany(table.CurrentCell.RowIndex + ViewOffset, 7); - } - - private void addLabelToolStripMenuItem_Click(object sender, EventArgs e) - { - table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[0]; - table.BeginEdit(true); - } - - private void setDataBankToolStripMenuItem_Click(object sender, EventArgs e) - { - if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; - MarkMany(table.CurrentCell.RowIndex + ViewOffset, 8); - } - - private void setDirectPageToolStripMenuItem_Click(object sender, EventArgs e) - { - if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; - MarkMany(table.CurrentCell.RowIndex + ViewOffset, 9); - } - - private void toggleAccumulatorSizeMToolStripMenuItem_Click(object sender, EventArgs e) - { - if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; - MarkMany(table.CurrentCell.RowIndex + ViewOffset, 10); - } - - private void toggleIndexSizeToolStripMenuItem_Click(object sender, EventArgs e) - { - if (Project?.Data == null || Project.Data.GetRomSize() <= 0) return; - MarkMany(table.CurrentCell.RowIndex + ViewOffset, 11); - } - - private void addCommentToolStripMenuItem_Click(object sender, EventArgs e) - { - table.CurrentCell = table.Rows[table.CurrentCell.RowIndex].Cells[12]; - table.BeginEdit(true); - } - - private void fixMisalignedInstructionsToolStripMenuItem_Click(object sender, EventArgs e) - { - if (Project?.Data == null || Project.Data.GetRomSize() <= 0) - return; - - var mis = new MisalignmentChecker(Project.Data); - var result = mis.ShowDialog(); - - if (result != DialogResult.OK) - return; - - int count = Project.Data.FixMisalignedFlags(); - - if (count > 0) - ProjectController.MarkChanged(); - - InvalidateTable(); - MessageBox.Show($"Modified {count} flags!", "Done!", - MessageBoxButtons.OK, MessageBoxIcon.Information); - } - - private void rescanForInOutPointsToolStripMenuItem_Click(object sender, EventArgs e) - { - if (Project?.Data == null || Project.Data.GetRomSize() <= 0) - return; - - var point = new InOutPointChecker(); - if (point.ShowDialog() != DialogResult.OK) - return; - - Project.Data.RescanInOutPoints(); - ProjectController.MarkChanged(); - InvalidateTable(); - MessageBox.Show("Scan complete!", "Done!", MessageBoxButtons.OK, MessageBoxIcon.Information); - } - - private void unreachedToolStripMenuItem_Click(object sender, EventArgs e) - { - markFlag = Data.FlagType.Unreached; - UpdateMarkerLabel(); - } - - private void opcodeToolStripMenuItem_Click(object sender, EventArgs e) - { - markFlag = Data.FlagType.Opcode; - UpdateMarkerLabel(); - } - - private void operandToolStripMenuItem_Click(object sender, EventArgs e) - { - markFlag = Data.FlagType.Operand; - UpdateMarkerLabel(); - } - - private void bitDataToolStripMenuItem_Click(object sender, EventArgs e) - { - markFlag = Data.FlagType.Data8Bit; - UpdateMarkerLabel(); - } - - private void graphicsToolStripMenuItem_Click(object sender, EventArgs e) - { - markFlag = Data.FlagType.Graphics; - UpdateMarkerLabel(); - } - - private void musicToolStripMenuItem_Click(object sender, EventArgs e) - { - markFlag = Data.FlagType.Music; - UpdateMarkerLabel(); - } - - private void emptyToolStripMenuItem_Click(object sender, EventArgs e) - { - markFlag = Data.FlagType.Empty; - UpdateMarkerLabel(); - } - - private void bitDataToolStripMenuItem1_Click(object sender, EventArgs e) - { - markFlag = Data.FlagType.Data16Bit; - UpdateMarkerLabel(); - } - - private void wordPointerToolStripMenuItem_Click(object sender, EventArgs e) - { - markFlag = Data.FlagType.Pointer16Bit; - UpdateMarkerLabel(); - } - - private void bitDataToolStripMenuItem2_Click(object sender, EventArgs e) - { - markFlag = Data.FlagType.Data24Bit; - UpdateMarkerLabel(); - } - - private void longPointerToolStripMenuItem_Click(object sender, EventArgs e) - { - markFlag = Data.FlagType.Pointer24Bit; - UpdateMarkerLabel(); - } - - private void bitDataToolStripMenuItem3_Click(object sender, EventArgs e) - { - markFlag = Data.FlagType.Data32Bit; - UpdateMarkerLabel(); - } - - private void dWordPointerToolStripMenuItem_Click(object sender, EventArgs e) - { - markFlag = Data.FlagType.Pointer32Bit; - UpdateMarkerLabel(); - } - - private void textToolStripMenuItem_Click(object sender, EventArgs e) - { - markFlag = Data.FlagType.Text; - UpdateMarkerLabel(); - } - - private void moveWithStepToolStripMenuItem_Click(object sender, EventArgs e) - { - moveWithStep = !moveWithStep; - moveWithStepToolStripMenuItem.Checked = moveWithStep; - } - - // sub windows - public AliasList AliasList; - private VisualizerForm visualForm; - - private void EnableSubWindows() - { - labelListToolStripMenuItem.Enabled = true; - } - - private void labelListToolStripMenuItem_Click(object sender, EventArgs e) - { - AliasList.Show(); - } - - private void openLastProjectAutomaticallyToolStripMenuItem_Click(object sender, EventArgs e) - { - Settings.Default.OpenLastFileAutomatically = openLastProjectAutomaticallyToolStripMenuItem.Checked; - Settings.Default.Save(); - UpdateUiFromSettings(); - } - - private void toolStripOpenLast_Click(object sender, EventArgs e) - { - OpenLastProject(); - } - - public string AskToSelectNewRomFilename(string promptSubject, string promptText) - { - string initialDir = null; // TODO: Project.ProjectFileName - return GuiUtil.PromptToConfirmAction(promptSubject, promptText, - () => GuiUtil.PromptToSelectFile(initialDir) - ); - } - - public IImportRomDialogView GetImportView() - { - return new ImportRomDialog(); - } - - public void OnProjectOpenWarning(string warningMsg) - { - MessageBox.Show(warningMsg, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - } - - private void importUsageMapToolStripMenuItem_Click_1(object sender, EventArgs e) - { - if (openUsageMapFile.ShowDialog() != DialogResult.OK) - return; - - var numModifiedFlags = ProjectController.ImportBsnesUsageMap(openUsageMapFile.FileName); - - MessageBox.Show($"Modified total {numModifiedFlags} flags!", "Done", - MessageBoxButtons.OK, MessageBoxIcon.Information); - } - - private void toolStripMenuItem3_Click(object sender, EventArgs e) - { - // TODO: differentiate between binary and text format - - openTraceLogDialog.Multiselect = true; - if (openTraceLogDialog.ShowDialog() != DialogResult.OK) - return; - - var numModifiedFlags = ProjectController.ImportBsnesTraceLogs(openTraceLogDialog.FileNames); - - MessageBox.Show($"Modified total {numModifiedFlags} flags from {openTraceLogDialog.FileNames.Length} files!", "Done", - MessageBoxButtons.OK, MessageBoxIcon.Information); - } - - private void importCDLToolStripMenuItem_Click_1(object sender, EventArgs e) - { - openCDLDialog.InitialDirectory = Project.ProjectFileName; - if (openCDLDialog.ShowDialog() != DialogResult.OK) - return; - - if (!ContinueUnsavedChanges()) - return; - - var filename = openCDLDialog.FileName; - - try - { - ProjectController.ImportBizHawkCdl(filename); - } - catch (InvalidDataException ex) - { - MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - catch (EndOfStreamException ex) - { - MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - - UpdatePercent(); - UpdateWindowTitle(); - InvalidateTable(); - } - - private void importTraceLogBinary_Click(object sender, EventArgs e) - { - var bsnesForm = new BsnesTraceLogBinaryMonitorForm(this); - bsnesForm.ShowDialog(); - - RefreshUi(); - } } } \ No newline at end of file diff --git a/DiztinGUIsh/window/dialog/HarshAutoStep.cs b/DiztinGUIsh/window/dialog/HarshAutoStep.cs index 80a34077..a9fac3e0 100644 --- a/DiztinGUIsh/window/dialog/HarshAutoStep.cs +++ b/DiztinGUIsh/window/dialog/HarshAutoStep.cs @@ -9,51 +9,42 @@ namespace DiztinGUIsh { public partial class HarshAutoStep : Form { - private int start, end, count; - + public int Start { get; private set; } + public int End { get; private set; } + public int Count { get; private set; } + private readonly Data data; + private bool updatingText; public HarshAutoStep(int offset, Data data) { - Debug.Assert(this.data!=null); + Debug.Assert(data != null); this.data = data; InitializeComponent(); - start = offset; - var rest = data.GetRomSize() - start; - count = rest < 0x100 ? rest : 0x100; - end = start + count; + Start = offset; + var rest = data.GetRomSize() - Start; + Count = rest < 0x100 ? rest : 0x100; + End = Start + Count; UpdateText(null); } - public int GetOffset() - { - return start; - } - - public int GetCount() - { - return count; - } - - private bool updatingText; - private void UpdateText(TextBox selected) { - Util.NumberBase noBase = radioDec.Checked ? Util.NumberBase.Decimal : Util.NumberBase.Hexadecimal; - int digits = noBase == Util.NumberBase.Hexadecimal && radioROM.Checked ? 6 : 0; + var noBase = radioDec.Checked ? Util.NumberBase.Decimal : Util.NumberBase.Hexadecimal; + var digits = noBase == Util.NumberBase.Hexadecimal && radioROM.Checked ? 6 : 0; - if (start < 0) start = 0; - if (end >= data.GetRomSize()) end = data.GetRomSize() - 1; - count = end - start; - if (count < 0) count = 0; + if (Start < 0) Start = 0; + if (End >= data.GetRomSize()) End = data.GetRomSize() - 1; + Count = End - Start; + if (Count < 0) Count = 0; updatingText = true; - if (selected != textStart) textStart.Text = Util.NumberToBaseString(radioROM.Checked ? data.ConvertPCtoSnes(start) : start, noBase, digits); - if (selected != textEnd) textEnd.Text = Util.NumberToBaseString(radioROM.Checked ? data.ConvertPCtoSnes(end) : end, noBase, digits); - if (selected != textCount) textCount.Text = Util.NumberToBaseString(count, noBase, 0); + if (selected != textStart) textStart.Text = Util.NumberToBaseString(radioROM.Checked ? data.ConvertPCtoSnes(Start) : Start, noBase, digits); + if (selected != textEnd) textEnd.Text = Util.NumberToBaseString(radioROM.Checked ? data.ConvertPCtoSnes(End) : End, noBase, digits); + if (selected != textCount) textCount.Text = Util.NumberToBaseString(Count, noBase, 0); updatingText = false; } @@ -69,68 +60,59 @@ private void radioROM_CheckedChanged(object sender, EventArgs e) private void textCount_TextChanged(object sender, EventArgs e) { - if (!updatingText) + OnTextChanged(textCount, value => { - updatingText = true; - var style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; - - if (int.TryParse(textCount.Text, style, null, out var result)) - { - count = result; - end = start + count; - } - - UpdateText(textCount); - } + Count = value; + End = Start + Count; + }); } private void textEnd_TextChanged(object sender, EventArgs e) { - if (updatingText) - return; + OnTextChanged(textEnd, value => + { + if (radioROM.Checked) + value = data.ConvertSnesToPc(value); - updatingText = true; - var style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; + End = value; + Count = End - Start; + }); + } - if (int.TryParse(textEnd.Text, style, null, out var result)) + private void textStart_TextChanged(object sender, EventArgs e) + { + OnTextChanged(textStart, value => { - if (radioROM.Checked) - result = data.ConvertSnesToPc(result); - - end = result; - count = end - start; - } + if (radioROM.Checked) + value = data.ConvertSnesToPc(value); - UpdateText(textEnd); + Start = value; + Count = End - Start; + }); } - private void textStart_TextChanged(object sender, EventArgs e) + private void OnTextChanged(TextBox textBox, Action OnResult) { - if (updatingText) + if (updatingText) return; updatingText = true; var style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; - if (int.TryParse(textStart.Text, style, null, out var result)) - { - if (radioROM.Checked) - result = data.ConvertSnesToPc(result); - start = result; - count = end - start; - } + if (int.TryParse(textBox.Text, style, null, out var result)) + OnResult(result); - UpdateText(textStart); + UpdateText(textBox); } private void go_Click(object sender, EventArgs e) { - this.DialogResult = DialogResult.OK; + DialogResult = DialogResult.OK; } private void cancel_Click(object sender, EventArgs e) { - this.Close(); + Close(); } } } diff --git a/DiztinGUIsh/window/dialog/MarkManyDialog.Designer.cs b/DiztinGUIsh/window/dialog/MarkManyDialog.Designer.cs index 9e682419..bcfdaf76 100644 --- a/DiztinGUIsh/window/dialog/MarkManyDialog.Designer.cs +++ b/DiztinGUIsh/window/dialog/MarkManyDialog.Designer.cs @@ -1,4 +1,4 @@ -namespace DiztinGUIsh +namespace DiztinGUIsh.window.dialog { partial class MarkManyDialog { diff --git a/DiztinGUIsh/window/dialog/MarkManyDialog.cs b/DiztinGUIsh/window/dialog/MarkManyDialog.cs index ee62a657..a78e6550 100644 --- a/DiztinGUIsh/window/dialog/MarkManyDialog.cs +++ b/DiztinGUIsh/window/dialog/MarkManyDialog.cs @@ -4,31 +4,36 @@ using Diz.Core.model; using Diz.Core.util; -namespace DiztinGUIsh +namespace DiztinGUIsh.window.dialog { public partial class MarkManyDialog : Form { - private int start, end, count, value; + public int Start { get; private set; } + public int End { get; private set; } + public int Count { get; private set; } + + private int value; - private Data data; + private readonly Data data; public MarkManyDialog(int offset, int column, Data data) { InitializeComponent(); this.data = data; - switch (column) + property.SelectedIndex = column switch { - case 8: property.SelectedIndex = 1; break; - case 9: property.SelectedIndex = 2; break; - case 10: property.SelectedIndex = 3; break; - case 11: property.SelectedIndex = 4; break; - default: property.SelectedIndex = 0; break; - } - start = offset; - int rest = this.data.GetRomSize() - start; - count = rest < 0x10 ? rest : 0x10; - end = start + count; + 8 => 1, + 9 => 2, + 10 => 3, + 11 => 4, + _ => 0 + }; + + Start = offset; + var rest = this.data.GetRomSize() - Start; + Count = rest < 0x10 ? rest : 0x10; + End = Start + Count; flagCombo.SelectedIndex = 3; archCombo.SelectedIndex = 0; @@ -37,61 +42,55 @@ public MarkManyDialog(int offset, int column, Data data) UpdateGroup(); UpdateText(null); } + + public int Property => property.SelectedIndex; - public int GetOffset() - { - return start; - } - - public int GetCount() - { - return count; - } - - public int GetProperty() - { - return property.SelectedIndex; - } - - public object GetValue() - { - switch (property.SelectedIndex) + public object Value { + get { - case 0: - switch (flagCombo.SelectedIndex) - { - case 0: return Data.FlagType.Unreached; - case 1: return Data.FlagType.Opcode; - case 2: return Data.FlagType.Operand; - case 3: return Data.FlagType.Data8Bit; - case 4: return Data.FlagType.Graphics; - case 5: return Data.FlagType.Music; - case 6: return Data.FlagType.Empty; - case 7: return Data.FlagType.Data16Bit; - case 8: return Data.FlagType.Pointer16Bit; - case 9: return Data.FlagType.Data24Bit; - case 10: return Data.FlagType.Pointer24Bit; - case 11: return Data.FlagType.Data32Bit; - case 12: return Data.FlagType.Pointer32Bit; - case 13: return Data.FlagType.Text; - } - break; - case 1: - case 2: - return value; - case 3: - case 4: - return mxCombo.SelectedIndex != 0; - case 5: - switch (archCombo.SelectedIndex) - { - case 0: return Data.Architecture.Cpu65C816; - case 1: return Data.Architecture.Apuspc700; - case 2: return Data.Architecture.GpuSuperFx; - } - break; + switch (property.SelectedIndex) + { + case 0: + switch (flagCombo.SelectedIndex) + { + case 0: return Data.FlagType.Unreached; + case 1: return Data.FlagType.Opcode; + case 2: return Data.FlagType.Operand; + case 3: return Data.FlagType.Data8Bit; + case 4: return Data.FlagType.Graphics; + case 5: return Data.FlagType.Music; + case 6: return Data.FlagType.Empty; + case 7: return Data.FlagType.Data16Bit; + case 8: return Data.FlagType.Pointer16Bit; + case 9: return Data.FlagType.Data24Bit; + case 10: return Data.FlagType.Pointer24Bit; + case 11: return Data.FlagType.Data32Bit; + case 12: return Data.FlagType.Pointer32Bit; + case 13: return Data.FlagType.Text; + } + + break; + case 1: + case 2: + return value; + case 3: + case 4: + return mxCombo.SelectedIndex != 0; + case 5: + switch (archCombo.SelectedIndex) + { + case 0: return Data.Architecture.Cpu65C816; + case 1: return Data.Architecture.Apuspc700; + case 2: return Data.Architecture.GpuSuperFx; + } + + break; + default: + return 0; + } + + return 0; } - return 0; } private void UpdateGroup() @@ -101,7 +100,7 @@ private void UpdateGroup() mxCombo.Visible = (property.SelectedIndex == 3 || property.SelectedIndex == 4); archCombo.Visible = (property.SelectedIndex == 5); regValue.MaxLength = (property.SelectedIndex == 1 ? 3 : 5); - value = property.SelectedIndex == 1 ? data.GetDataBank(start) : data.GetDirectPage(start); + value = property.SelectedIndex == 1 ? data.GetDataBank(Start) : data.GetDirectPage(Start); } private bool updatingText; @@ -113,57 +112,26 @@ private void UpdateText(TextBox selected) int size = data.GetRomSize(); int maxValue = property.SelectedIndex == 1 ? 0x100 : 0x10000; - if (start < 0) start = 0; - if (end >= size) end = size - 1; - count = end - start; - if (count < 0) count = 0; + if (Start < 0) Start = 0; + if (End >= size) End = size - 1; + Count = End - Start; + if (Count < 0) Count = 0; if (value < 0) value = 0; if (value >= maxValue) value = maxValue - 1; updatingText = true; - if (selected != textStart) textStart.Text = Util.NumberToBaseString(radioROM.Checked ? data.ConvertPCtoSnes(start) : start, noBase, digits); - if (selected != textEnd) textEnd.Text = Util.NumberToBaseString(radioROM.Checked ? data.ConvertPCtoSnes(end) : end, noBase, digits); - if (selected != textCount) textCount.Text = Util.NumberToBaseString(count, noBase, 0); + if (selected != textStart) textStart.Text = Util.NumberToBaseString(radioROM.Checked ? data.ConvertPCtoSnes(Start) : Start, noBase, digits); + if (selected != textEnd) textEnd.Text = Util.NumberToBaseString(radioROM.Checked ? data.ConvertPCtoSnes(End) : End, noBase, digits); + if (selected != textCount) textCount.Text = Util.NumberToBaseString(Count, noBase, 0); if (selected != regValue) regValue.Text = Util.NumberToBaseString(value, noBase, 0); updatingText = false; } - - private void textCount_TextChanged(object sender, EventArgs e) - { - if (updatingText) return; - updatingText = true; - var style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; - - if (int.TryParse(textCount.Text, style, null, out var result)) - { - count = result; - end = start + count; - } - - UpdateText(textCount); - } - - private void textEnd_TextChanged(object sender, EventArgs e) - { - if (updatingText) return; - updatingText = true; - var style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; - - if (int.TryParse(textEnd.Text, style, null, out var result)) - { - if (radioROM.Checked) result = data.ConvertSnesToPc(result); - end = result; - count = end - start; - } - - UpdateText(textEnd); - } - + private void property_SelectedIndexChanged(object sender, EventArgs e) { UpdateGroup(); } - + private void regValue_TextChanged(object sender, EventArgs e) { var style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; @@ -184,20 +152,51 @@ private void cancel_Click(object sender, EventArgs e) Close(); } + private void textCount_TextChanged(object sender, EventArgs e) + { + OnTextChanged(textCount, value => + { + Count = value; + End = Start + Count; + }); + } + + private void textEnd_TextChanged(object sender, EventArgs e) + { + OnTextChanged(textEnd, value => + { + if (radioROM.Checked) + value = data.ConvertSnesToPc(value); + + End = value; + Count = End - Start; + }); + } + private void textStart_TextChanged(object sender, EventArgs e) { - if (updatingText) return; + OnTextChanged(textStart, value => + { + if (radioROM.Checked) + value = data.ConvertSnesToPc(value); + + Start = value; + Count = End - Start; + }); + } + + private void OnTextChanged(TextBox textBox, Action OnResult) + { + if (updatingText) + return; + updatingText = true; var style = radioDec.Checked ? NumberStyles.Number : NumberStyles.HexNumber; - if (int.TryParse(textStart.Text, style, null, out var result)) - { - if (radioROM.Checked) result = data.ConvertSnesToPc(result); - start = result; - count = end - start; - } + if (int.TryParse(textBox.Text, style, null, out var result)) + OnResult(result); - UpdateText(textStart); + UpdateText(textBox); } private void radioHex_CheckedChanged(object sender, EventArgs e)