BizHawk/BizHawk.MultiClient/tools/RamSearch.cs

1212 lines
43 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Globalization;
namespace BizHawk.MultiClient
{
/// <summary>
/// A winform designed to search through ram values
/// </summary>
public partial class RamSearch : Form
{
//TODO:
//Window position gets saved but doesn't load properly
//Add to Ram watch fails to open ram watch if it has neve been opened
//Doesnt' release handle after saving file, Ram Watch too?
//Implement Preview search
//Implement definitions of Previous value
string systemID = "NULL";
List<Watch> searchList = new List<Watch>();
List<Watch> undoList = new List<Watch>();
List<Watch> weededList = new List<Watch>(); //When addresses are weeded out, the new list goes here, before going into searchList
public enum SCompareTo { PREV, VALUE, ADDRESS, CHANGES };
public enum SOperator { LESS, GREATER, LESSEQUAL, GREATEREQUAL, EQUAL, NOTEQUAL, DIFFBY };
public enum SSigned { SIGNED, UNSIGNED, HEX };
//Reset window position item
int defaultWidth; //For saving the default size of the dialog, so the user can restore if desired
int defaultHeight;
string currentSearchFile = "";
public RamSearch()
{
InitializeComponent();
}
public void UpdateValues()
{
for (int x = 0; x < searchList.Count; x++)
{
searchList[x].prev = searchList[x].value;
searchList[x].PeekAddress(Global.Emulator.MainMemory);
if (searchList[x].prev != searchList[x].value)
searchList[x].changecount++;
}
if (AutoSearchCheckBox.Checked)
DoSearch();
SearchListView.Refresh();
}
private void RamSearch_Load(object sender, EventArgs e)
{
defaultWidth = this.Size.Width; //Save these first so that the user can restore to its original size
defaultHeight = this.Size.Height;
if (Global.Emulator.MainMemory.Endian == Endian.Big)
{
bigEndianToolStripMenuItem.Checked = true;
littleEndianToolStripMenuItem.Checked = false;
}
else
{
bigEndianToolStripMenuItem.Checked = false;
littleEndianToolStripMenuItem.Checked = true;
}
StartNewSearch();
if (Global.Config.RamSearchWndx >= 0 && Global.Config.RamSearchWndy >= 0)
this.Location = new Point(Global.Config.RamSearchWndx, Global.Config.RamSearchWndy);
if (Global.Config.RamSearchWidth >= 0 && Global.Config.RamSearchHeight >= 0)
{
this.Size = new System.Drawing.Size(Global.Config.RamSearchWidth, Global.Config.RamSearchHeight);
}
}
private void SetTotal()
{
int x = searchList.Count;
string str;
if (x == 1)
str = " address";
else
str = " addresses";
TotalSearchLabel.Text = x.ToString() + str;
}
private void OpenSearchFile()
{
var file = GetFileFromUser();
if (file != null)
{
LoadSearchFile(file.FullName, false);
DisplaySearchList();
}
}
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenSearchFile();
}
private void openToolStripButton_Click(object sender, EventArgs e)
{
OpenSearchFile();
}
private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
{
SaveAs();
}
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Hide();
}
private void SpecificValueRadio_CheckedChanged(object sender, EventArgs e)
{
if (SpecificValueRadio.Checked)
{
SpecificValueBox.Enabled = true;
SpecificAddressBox.Enabled = false;
NumberOfChangesBox.Enabled = false;
SpecificValueBox.Focus();
SpecificValueBox.SelectAll();
}
}
private void PreviousValueRadio_CheckedChanged(object sender, EventArgs e)
{
if (PreviousValueRadio.Checked)
{
SpecificValueBox.Enabled = false;
SpecificAddressBox.Enabled = false;
NumberOfChangesBox.Enabled = false;
}
}
private void SpecificAddressRadio_CheckedChanged(object sender, EventArgs e)
{
if (SpecificAddressRadio.Checked)
{
SpecificValueBox.Enabled = false;
SpecificAddressBox.Enabled = true;
NumberOfChangesBox.Enabled = false;
SpecificAddressBox.Focus();
SpecificAddressBox.SelectAll();
}
}
private void NumberOfChangesRadio_CheckedChanged(object sender, EventArgs e)
{
if (NumberOfChangesRadio.Checked)
{
SpecificValueBox.Enabled = false;
SpecificAddressBox.Enabled = false;
NumberOfChangesBox.Enabled = true;
NumberOfChangesBox.Focus();
NumberOfChangesBox.SelectAll();
}
}
private void DifferentByRadio_CheckedChanged(object sender, EventArgs e)
{
if (DifferentByRadio.Checked)
DifferentByBox.Enabled = true;
else
DifferentByBox.Enabled = false;
DifferentByBox.Focus();
DifferentByBox.SelectAll();
}
private void AddToRamWatch()
{
ListView.SelectedIndexCollection indexes = SearchListView.SelectedIndices;
if (indexes.Count > 0)
{
if (!Global.MainForm.RamWatch1.IsDisposed)
{
Global.MainForm.RamWatch1.Focus();
}
else
{
Global.MainForm.RamWatch1 = new RamWatch();
Global.MainForm.RamWatch1.Show();
}
for (int x = 0; x < indexes.Count; x++)
Global.MainForm.RamWatch1.AddWatch(searchList[indexes[x]]);
}
}
private void WatchtoolStripButton1_Click(object sender, EventArgs e)
{
AddToRamWatch();
}
private void RamSearch_LocationChanged(object sender, EventArgs e)
{
Global.Config.RamSearchWndx = this.Location.X;
Global.Config.RamSearchWndy = this.Location.Y;
}
private void RamSearch_Resize(object sender, EventArgs e)
{
Global.Config.RamSearchWidth = this.Right - this.Left;
Global.Config.RamSearchHeight = this.Bottom - this.Top;
}
private void restoreOriginalWindowSizeToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Size = new System.Drawing.Size(defaultWidth, defaultHeight);
}
private void NewSearchtoolStripButton_Click(object sender, EventArgs e)
{
StartNewSearch();
}
private asigned GetDataType()
{
if (unsignedToolStripMenuItem.Checked)
return asigned.UNSIGNED;
if (signedToolStripMenuItem.Checked)
return asigned.SIGNED;
if (hexadecimalToolStripMenuItem.Checked)
return asigned.HEX;
return asigned.UNSIGNED; //Just in case
}
private atype GetDataSize()
{
if (byteToolStripMenuItem.Checked)
return atype.BYTE;
if (bytesToolStripMenuItem.Checked)
return atype.WORD;
if (dWordToolStripMenuItem1.Checked)
return atype.DWORD;
return atype.BYTE;
}
private bool GetBigEndian()
{
if (bigEndianToolStripMenuItem.Checked)
return true;
else
return false;
}
private void StartNewSearch()
{
searchList.Clear();
undoList.Clear();
GetMemoryDomain();
int startaddress = 0;
if (Global.Emulator.SystemId == "PCE")
startaddress = 0x1F0000; //For now, until Emulator core functionality can better handle a prefix
int count = 0;
int divisor = 1;
if (!includeMisalignedToolStripMenuItem.Checked)
{
switch (GetDataSize())
{
case atype.WORD:
divisor = 2;
break;
case atype.DWORD:
divisor = 4;
break;
default:
divisor = 1;
break;
}
}
for (int x = 0; x < ((Global.Emulator.MainMemory.Size / divisor)-1); x++)
{
searchList.Add(new Watch());
searchList[x].address = count + startaddress;
searchList[x].type = GetDataSize();
searchList[x].bigendian = GetBigEndian();
searchList[x].signed = GetDataType();
searchList[x].PeekAddress(Global.Emulator.MainMemory);
searchList[x].prev = searchList[x].value;
if (includeMisalignedToolStripMenuItem.Checked)
count++;
else
{
switch (GetDataSize())
{
case atype.BYTE: //TODO: misaligned option
count++;
break;
case atype.WORD:
count += 2;
break;
case atype.DWORD:
count += 4;
break;
}
}
}
OutputLabel.Text = "New search started";
DisplaySearchList();
}
private void DisplaySearchList()
{
SearchListView.ItemCount = searchList.Count;
SetTotal();
}
private void newSearchToolStripMenuItem_Click(object sender, EventArgs e)
{
StartNewSearch();
}
private void GetMemoryDomain()
{
string memoryDomain = "Main memory"; //TODO: multiple memory domains
systemID = Global.Emulator.SystemId;
MemDomainLabel.Text = systemID + " " + memoryDomain;
}
private Point GetPromptPoint()
{
Point p = new Point(SearchListView.Location.X, SearchListView.Location.Y);
Point q = new Point();
q = PointToScreen(p);
return q;
}
private void PokeAddress()
{
ListView.SelectedIndexCollection indexes = SearchListView.SelectedIndices;
RamPoke p = new RamPoke();
if (indexes.Count > 0)
p.SetWatchObject(searchList[indexes[0]]);
p.location = GetPromptPoint();
p.ShowDialog();
}
private void PoketoolStripButton1_Click(object sender, EventArgs e)
{
PokeAddress();
}
private void RemoveAddresses()
{
ListView.SelectedIndexCollection indexes = SearchListView.SelectedIndices;
if (indexes.Count > 0)
{
SaveUndo();
for (int x = 0; x < indexes.Count; x++)
{
searchList.Remove(searchList[indexes[x]-x]);
}
DisplaySearchList();
}
}
private void cutToolStripButton_Click(object sender, EventArgs e)
{
RemoveAddresses();
}
/// <summary>
/// Saves the current search list to the undo list
/// This function should be called before any destructive operation to the list!
/// </summary>
private void SaveUndo()
{
undoList = new List<Watch>(searchList);
}
private void DoUndo()
{
if (undoList.Count > 0)
{
searchList = new List<Watch>(undoList);
undoList.Clear();
DisplaySearchList();
}
}
private void UndotoolStripButton_Click(object sender, EventArgs e)
{
DoUndo();
}
private void SearchListView_QueryItemBkColor(int index, int column, ref Color color)
{
//TODO: make background pink on items that would be removed if search button were clicked
}
private void SearchListView_QueryItemText(int index, int column, out string text)
{
text = "";
if (column == 0)
{
text = searchList[index].address.ToString("X");
}
if (column == 1)
{
if (searchList[index].signed == asigned.UNSIGNED)
text = searchList[index].value.ToString();
else if (searchList[index].signed == asigned.SIGNED)
text = ((sbyte)searchList[index].value).ToString();
else if (searchList[index].signed == asigned.HEX)
text = searchList[index].value.ToString("X");
}
if (column == 2)
{
if (searchList[index].signed == asigned.UNSIGNED) //TODO: only use .prev if that is the definition of prev set by user, else use PrevList
text = searchList[index].prev.ToString();
else if (searchList[index].signed == asigned.SIGNED)
text = ((sbyte)searchList[index].prev).ToString();
else if (searchList[index].signed == asigned.HEX)
text = searchList[index].prev.ToString("X");
}
if (column == 3)
{
text = searchList[index].changecount.ToString();
}
}
private void SearchListView_QueryItemIndent(int index, out int itemIndent)
{
itemIndent = 0;
}
private void SearchListView_QueryItemImage(int index, int column, out int imageIndex)
{
imageIndex = -1;
}
private void ClearChangeCounts()
{
SaveUndo();
for (int x = 0; x < searchList.Count; x++)
searchList[x].changecount = 0;
DisplaySearchList();
}
private void ClearChangeCountstoolStripButton_Click(object sender, EventArgs e)
{
ClearChangeCounts();
}
private void UndotoolStripButton_Click_1(object sender, EventArgs e)
{
DoUndo();
}
private void ReplaceSearchListWithWeedOutList()
{
searchList = new List<Watch>(weededList);
weededList.Clear();
}
private void DoSearch()
{
if (GenerateWeedOutList())
{
SaveUndo();
OutputLabel.Text = (searchList.Count - weededList.Count).ToString() + " addresses removed"; //TODO: address if only 1
ReplaceSearchListWithWeedOutList();
DisplaySearchList();
}
//TODO: else notify the user something went wrong?
}
private void toolStripButton1_Click(object sender, EventArgs e)
{
DoSearch();
}
private SCompareTo GetCompareTo()
{
if (PreviousValueRadio.Checked)
return SCompareTo.PREV;
if (SpecificValueRadio.Checked)
return SCompareTo.VALUE;
if (SpecificAddressRadio.Checked)
return SCompareTo.ADDRESS;
if (NumberOfChangesRadio.Checked)
return SCompareTo.CHANGES;
return SCompareTo.PREV; //Just in case
}
private SOperator GetOperator()
{
if (LessThanRadio.Checked)
return SOperator.LESS;
if (GreaterThanRadio.Checked)
return SOperator.GREATER;
if (LessThanOrEqualToRadio.Checked)
return SOperator.LESSEQUAL;
if (GreaterThanOrEqualToRadio.Checked)
return SOperator.GREATEREQUAL;
if (EqualToRadio.Checked)
return SOperator.EQUAL;
if (NotEqualToRadio.Checked)
return SOperator.NOTEQUAL;
if (DifferentByRadio.Checked)
return SOperator.DIFFBY;
return SOperator.LESS; //Just in case
}
private bool GenerateWeedOutList()
{
//Switch based on user criteria
//Generate search list
//Use search list to generate a list of flagged address (for displaying pink)
switch (GetCompareTo())
{
case SCompareTo.PREV:
return DoPreviousValue();
case SCompareTo.VALUE:
return DoSpecificValue();
case SCompareTo.ADDRESS:
return DoSpecificAddress();
case SCompareTo.CHANGES:
return DoNumberOfChanges();
default:
return false;
}
}
private int GetPreviousValue(int pos)
{
return searchList[pos].prev; //TODO: return value based on user choice
}
private bool DoPreviousValue()
{
switch (GetOperator())
{
case SOperator.LESS:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].value < GetPreviousValue(x))
weededList.Add(searchList[x]);
}
break;
case SOperator.GREATER:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].value > GetPreviousValue(x))
weededList.Add(searchList[x]);
}
break;
case SOperator.LESSEQUAL:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].value <= GetPreviousValue(x))
weededList.Add(searchList[x]);
}
break;
case SOperator.GREATEREQUAL:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].value >= GetPreviousValue(x))
weededList.Add(searchList[x]);
}
break;
case SOperator.EQUAL:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].value == GetPreviousValue(x))
weededList.Add(searchList[x]);
}
break;
case SOperator.NOTEQUAL:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].value != GetPreviousValue(x))
weededList.Add(searchList[x]);
}
break;
case SOperator.DIFFBY:
int diff = GetDifferentBy();
if (diff < 0) return false;
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].value == GetPreviousValue(x) + diff || searchList[x].value == GetPreviousValue(x) - diff)
weededList.Add(searchList[x]);
}
break;
}
return true;
}
private bool DoSpecificValue()
{
int value = GetSpecificValue();
if (value < 0)
{
MessageBox.Show("Missing or invalid value", "Invalid value", MessageBoxButtons.OK, MessageBoxIcon.Error);
SpecificValueBox.Focus();
SpecificValueBox.SelectAll();
return false;
}
switch (GetOperator())
{
case SOperator.LESS:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].value < value)
weededList.Add(searchList[x]);
}
break;
case SOperator.GREATER:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].value > value)
weededList.Add(searchList[x]);
}
break;
case SOperator.LESSEQUAL:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].value <= value)
weededList.Add(searchList[x]);
}
break;
case SOperator.GREATEREQUAL:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].value >= value)
weededList.Add(searchList[x]);
}
break;
case SOperator.EQUAL:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].value == value)
weededList.Add(searchList[x]);
}
break;
case SOperator.NOTEQUAL:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].value != value)
weededList.Add(searchList[x]);
}
break;
case SOperator.DIFFBY:
int diff = GetDifferentBy();
if (diff < 0) return false;
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].value == value + diff || searchList[x].value == value - diff)
weededList.Add(searchList[x]);
}
break;
}
return true;
}
private int GetSpecificValue()
{
bool i = InputValidate.IsValidSignedNumber(SpecificValueBox.Text);
if (!i) return -1;
return int.Parse(SpecificValueBox.Text);
}
private int GetSpecificAddress()
{
bool i = InputValidate.IsValidHexNumber(SpecificAddressBox.Text);
if (!i) return -1;
return int.Parse(SpecificAddressBox.Text, NumberStyles.HexNumber);
}
private int GetDifferentBy()
{
bool i = InputValidate.IsValidUnsignedNumber(DifferentByBox.Text);
if (!i)
{
MessageBox.Show("Missing or invalid Different By value", "Invalid value", MessageBoxButtons.OK, MessageBoxIcon.Error);
DifferentByBox.Focus();
DifferentByBox.SelectAll();
return -1;
}
else
return int.Parse(DifferentByBox.Text);
}
private bool DoSpecificAddress()
{
int address = GetSpecificAddress();
if (address < 0)
{
MessageBox.Show("Missing or invalid address", "Invalid address", MessageBoxButtons.OK, MessageBoxIcon.Error);
SpecificAddressBox.Focus();
SpecificAddressBox.SelectAll();
return false;
}
switch (GetOperator())
{
case SOperator.LESS:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].address < address)
weededList.Add(searchList[x]);
}
break;
case SOperator.GREATER:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].address > address)
weededList.Add(searchList[x]);
}
break;
case SOperator.LESSEQUAL:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].address <= address)
weededList.Add(searchList[x]);
}
break;
case SOperator.GREATEREQUAL:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].address >= address)
weededList.Add(searchList[x]);
}
break;
case SOperator.EQUAL:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].address == address)
weededList.Add(searchList[x]);
}
break;
case SOperator.NOTEQUAL:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].address != address)
weededList.Add(searchList[x]);
}
break;
case SOperator.DIFFBY:
{
int diff = GetDifferentBy();
if (diff < 0) return false;
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].address == address + diff || searchList[x].address == address - diff)
weededList.Add(searchList[x]);
}
}
break;
}
return true;
}
private int GetSpecificChanges()
{
bool i = InputValidate.IsValidUnsignedNumber(NumberOfChangesBox.Text);
if (!i) return -1;
return int.Parse(NumberOfChangesBox.Text);
}
private bool DoNumberOfChanges()
{
int changes = GetSpecificChanges();
if (changes < 0)
{
MessageBox.Show("Missing or invalid number of changes", "Invalid number", MessageBoxButtons.OK, MessageBoxIcon.Error);
NumberOfChangesBox.Focus();
NumberOfChangesBox.SelectAll();
return false;
}
switch (GetOperator())
{
case SOperator.LESS:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].changecount < changes)
weededList.Add(searchList[x]);
}
break;
case SOperator.GREATER:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].changecount > changes)
weededList.Add(searchList[x]);
}
break;
case SOperator.LESSEQUAL:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].changecount <= changes)
weededList.Add(searchList[x]);
}
break;
case SOperator.GREATEREQUAL:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].changecount >= changes)
weededList.Add(searchList[x]);
}
break;
case SOperator.EQUAL:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].changecount == changes)
weededList.Add(searchList[x]);
}
break;
case SOperator.NOTEQUAL:
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].changecount != changes)
weededList.Add(searchList[x]);
}
break;
case SOperator.DIFFBY:
int diff = GetDifferentBy();
if (diff < 0) return false;
for (int x = 0; x < searchList.Count; x++)
{
if (searchList[x].address == changes + diff || searchList[x].address == changes - diff)
weededList.Add(searchList[x]);
}
break;
}
return true;
}
private void ConvertListDataType(asigned s)
{
for (int x = 0; x < searchList.Count; x++)
searchList[x].signed = s;
}
private void signedToolStripMenuItem_Click(object sender, EventArgs e)
{
unsignedToolStripMenuItem.Checked = false;
signedToolStripMenuItem.Checked = true;
hexadecimalToolStripMenuItem.Checked = false;
ConvertListDataType(asigned.SIGNED);
DisplaySearchList();
}
private void unsignedToolStripMenuItem_Click(object sender, EventArgs e)
{
unsignedToolStripMenuItem.Checked = true;
signedToolStripMenuItem.Checked = false;
hexadecimalToolStripMenuItem.Checked = false;
ConvertListDataType(asigned.UNSIGNED);
DisplaySearchList();
}
private void hexadecimalToolStripMenuItem_Click(object sender, EventArgs e)
{
unsignedToolStripMenuItem.Checked = false;
signedToolStripMenuItem.Checked = false;
hexadecimalToolStripMenuItem.Checked = true;
ConvertListDataType(asigned.HEX);
DisplaySearchList();
}
private void SearchListView_MouseDoubleClick(object sender, MouseEventArgs e)
{
ListView.SelectedIndexCollection indexes = SearchListView.SelectedIndices;
if (indexes.Count > 0)
{
AddToRamWatch();
}
}
private void byteToolStripMenuItem_Click(object sender, EventArgs e)
{
byteToolStripMenuItem.Checked = true;
bytesToolStripMenuItem.Checked = false;
dWordToolStripMenuItem1.Checked = false;
}
private void bytesToolStripMenuItem_Click(object sender, EventArgs e)
{
byteToolStripMenuItem.Checked = false;
bytesToolStripMenuItem.Checked = true;
dWordToolStripMenuItem1.Checked = false;
}
private void dWordToolStripMenuItem1_Click(object sender, EventArgs e)
{
byteToolStripMenuItem.Checked = false;
bytesToolStripMenuItem.Checked = false;
dWordToolStripMenuItem1.Checked = true;
}
private void bigEndianToolStripMenuItem_Click(object sender, EventArgs e)
{
bigEndianToolStripMenuItem.Checked = true;
littleEndianToolStripMenuItem.Checked = false;
}
private void littleEndianToolStripMenuItem_Click(object sender, EventArgs e)
{
bigEndianToolStripMenuItem.Checked = false;
littleEndianToolStripMenuItem.Checked = true;
}
private void AutoSearchCheckBox_CheckedChanged(object sender, EventArgs e)
{
if (AutoSearchCheckBox.Checked)
AutoSearchCheckBox.BackColor = Color.Pink;
else
AutoSearchCheckBox.BackColor = this.BackColor;
}
private void SpecificValueBox_Leave(object sender, EventArgs e)
{
SpecificValueBox.Text = SpecificValueBox.Text.Replace(" ", "");
if (!InputValidate.IsValidSignedNumber(SpecificValueBox.Text))
{
SpecificValueBox.Focus();
SpecificValueBox.SelectAll();
ToolTip t = new ToolTip();
t.Show("Must be a valid decimal value", SpecificValueBox, 5000);
}
}
private void SpecificAddressBox_Leave(object sender, EventArgs e)
{
SpecificAddressBox.Text = SpecificAddressBox.Text.Replace(" ", "");
if (!InputValidate.IsValidHexNumber(SpecificAddressBox.Text))
{
SpecificAddressBox.Focus();
SpecificAddressBox.SelectAll();
ToolTip t = new ToolTip();
t.Show("Must be a valid hexadecimal value", SpecificAddressBox, 5000);
}
}
private void NumberOfChangesBox_Leave(object sender, EventArgs e)
{
NumberOfChangesBox.Text = NumberOfChangesBox.Text.Replace(" ", "");
if (!InputValidate.IsValidUnsignedNumber(NumberOfChangesBox.Text))
{
NumberOfChangesBox.Focus();
NumberOfChangesBox.SelectAll();
ToolTip t = new ToolTip();
t.Show("Must be a valid unsigned decimal value", NumberOfChangesBox, 5000);
}
}
private void DifferentByBox_Leave(object sender, EventArgs e)
{
DifferentByBox.Text = DifferentByBox.Text.Replace(" ", "");
if (!InputValidate.IsValidUnsignedNumber(DifferentByBox.Text))
{
DifferentByBox.Focus();
DifferentByBox.SelectAll();
ToolTip t = new ToolTip();
t.Show("Must be a valid unsigned decimal value", DifferentByBox, 5000);
}
}
private bool SaveSearchFile(string path)
{
var file = new FileInfo(path);
using (StreamWriter sw = new StreamWriter(path))
{
string str = "";
for (int x = 0; x < searchList.Count; x++)
{
str += string.Format("{0:X4}", searchList[x].address) + "\t";
str += searchList[x].GetTypeByChar().ToString() + "\t";
str += searchList[x].GetSignedByChar().ToString() + "\t";
if (searchList[x].bigendian == true)
str += "1\t";
else
str += "0\t";
str += searchList[x].notes + "\n";
}
sw.WriteLine(str);
}
return true;
}
private FileInfo GetSaveFileFromUser()
{
var sfd = new SaveFileDialog();
sfd.InitialDirectory = Global.Config.LastRomPath;
sfd.Filter = "Watch Files (*.wch)|*.wch|All Files|*.*";
sfd.RestoreDirectory = true;
Global.Sound.StopSound();
var result = sfd.ShowDialog();
Global.Sound.StartSound();
if (result != DialogResult.OK)
return null;
var file = new FileInfo(sfd.FileName);
Global.Config.LastRomPath = file.DirectoryName;
return file;
}
public void SaveAs()
{
var file = GetSaveFileFromUser();
if (file != null)
{
SaveSearchFile(file.FullName);
currentSearchFile = file.FullName;
}
OutputLabel.Text = Path.GetFileName(currentSearchFile) + " saved.";
}
private void LoadSearchFromRecent(string file)
{
bool r = LoadSearchFile(file, false);
if (!r)
{
DialogResult result = MessageBox.Show("Could not open " + file + "\nRemove from list?", "File not found", MessageBoxButtons.YesNo, MessageBoxIcon.Error);
if (result == DialogResult.Yes)
Global.Config.RecentSearches.Remove(file);
}
DisplaySearchList();
}
public int HowMany(string str, char c)
{
int count = 0;
for (int x = 0; x < str.Length; x++)
{
if (str[x] == c)
count++;
}
return count;
}
bool LoadSearchFile(string path, bool append)
{
int y, z;
var file = new FileInfo(path);
if (file.Exists == false) return false;
using (StreamReader sr = file.OpenText())
{
if (!append)
currentSearchFile = path;
int count = 0;
string s = "";
string temp = "";
if (append == false)
searchList.Clear(); //Wipe existing list and read from file
while ((s = sr.ReadLine()) != null)
{
//parse each line and add to watchList
//.wch files from other emulators start with a number representing the number of watch, that line can be discarded here
//Any properly formatted line couldn't possibly be this short anyway, this also takes care of any garbage lines that might be in a file
if (s.Length < 5) continue;
z = HowMany(s, '\t');
if (z == 5)
{
//If 5, then this is a .wch file format made from another emulator, the first column (watch position) is not needed here
y = s.IndexOf('\t') + 1;
s = s.Substring(y, s.Length - y); //5 digit value representing the watch position number
}
else if (z != 4)
continue; //If not 4, something is wrong with this line, ignore it
count++;
Watch w = new Watch();
temp = s.Substring(0, s.IndexOf('\t'));
w.address = int.Parse(temp, NumberStyles.HexNumber);
y = s.IndexOf('\t') + 1;
s = s.Substring(y, s.Length - y); //Type
w.SetTypeByChar(s[0]);
y = s.IndexOf('\t') + 1;
s = s.Substring(y, s.Length - y); //Signed
w.SetSignedByChar(s[0]);
y = s.IndexOf('\t') + 1;
s = s.Substring(y, s.Length - y); //Endian
y = Int16.Parse(s[0].ToString());
if (y == 0)
w.bigendian = false;
else
w.bigendian = true;
//w.notes = s.Substring(2, s.Length - 2); //User notes
searchList.Add(w);
}
Global.Config.RecentSearches.Add(file.FullName);
OutputLabel.Text = Path.GetFileName(file.FullName);
//Update the number of watches
SetTotal();
}
return true;
}
private void recentToolStripMenuItem_DropDownOpened(object sender, EventArgs e)
{
//Clear out recent Roms list
//repopulate it with an up to date list
recentToolStripMenuItem.DropDownItems.Clear();
if (Global.Config.RecentSearches.IsEmpty())
{
recentToolStripMenuItem.DropDownItems.Add("None");
}
else
{
for (int x = 0; x < Global.Config.RecentSearches.Length(); x++)
{
string path = Global.Config.RecentSearches.GetRecentFileByPosition(x);
var item = new ToolStripMenuItem();
item.Text = path;
item.Click += (o, ev) => LoadSearchFromRecent(path);
recentToolStripMenuItem.DropDownItems.Add(item);
}
}
recentToolStripMenuItem.DropDownItems.Add("-");
var clearitem = new ToolStripMenuItem();
clearitem.Text = "&Clear";
clearitem.Click += (o, ev) => Global.Config.RecentSearches.Clear();
recentToolStripMenuItem.DropDownItems.Add(clearitem);
var auto = new ToolStripMenuItem();
auto.Text = "&Auto-Load";
auto.Click += (o, ev) => UpdateAutoLoadRamSearch();
if (Global.Config.AutoLoadRamSearch == true)
auto.Checked = true;
else
auto.Checked = false;
recentToolStripMenuItem.DropDownItems.Add(auto);
}
private void UpdateAutoLoadRamSearch()
{
autoLoadToolStripMenuItem.Checked = Global.Config.AutoLoadRamSearch ^= true;
}
private void appendFileToolStripMenuItem_Click(object sender, EventArgs e)
{
var file = GetFileFromUser();
if (file != null)
LoadSearchFile(file.FullName, true);
DisplaySearchList();
}
private FileInfo GetFileFromUser()
{
var ofd = new OpenFileDialog();
ofd.InitialDirectory = Global.Config.LastRomPath;
ofd.Filter = "Watch Files (*.wch)|*.wch|All Files|*.*";
ofd.RestoreDirectory = true;
Global.Sound.StopSound();
var result = ofd.ShowDialog();
Global.Sound.StartSound();
if (result != DialogResult.OK)
return null;
var file = new FileInfo(ofd.FileName);
Global.Config.LastRomPath = file.DirectoryName;
return file;
}
private void includeMisalignedToolStripMenuItem_Click(object sender, EventArgs e)
{
includeMisalignedToolStripMenuItem.Checked ^= true;
}
}
}