mirror of
https://github.com/fadden/6502bench.git
synced 2024-11-29 10:50:28 +00:00
Add file slicer tool
The tool allows you to cut a piece out of a file by specifying an offset and a length. A pair of hex dumps helps you verify that the positions are correct. Also, minor cleanups elsewhere.
This commit is contained in:
parent
89413d11e4
commit
1373ffd8e3
@ -985,7 +985,8 @@ namespace Asm65 {
|
||||
/// <param name="offset">Start offset.</param>
|
||||
/// <returns>Formatted string.</returns>
|
||||
public string FormatHexDump(byte[] data, int offset) {
|
||||
FormatHexDumpCommon(data, offset);
|
||||
int length = Math.Min(16, data.Length - offset);
|
||||
FormatHexDumpCommon(data, offset, offset, length);
|
||||
// this is the only allocation
|
||||
return new string(mHexDumpBuffer);
|
||||
}
|
||||
@ -998,14 +999,21 @@ namespace Asm65 {
|
||||
/// <param name="offset">Start offset.</param>
|
||||
/// <param name="sb">StringBuilder that receives output.</param>
|
||||
public void FormatHexDump(byte[] data, int offset, StringBuilder sb) {
|
||||
FormatHexDumpCommon(data, offset);
|
||||
int length = Math.Min(16, data.Length - offset);
|
||||
FormatHexDumpCommon(data, offset, offset, length);
|
||||
sb.Append(mHexDumpBuffer);
|
||||
}
|
||||
|
||||
public void FormatHexDump(byte[] data, int offset, int addr, int length,
|
||||
StringBuilder sb) {
|
||||
FormatHexDumpCommon(data, offset, addr, length);
|
||||
sb.Append(mHexDumpBuffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats up to 16 bytes of data into mHexDumpBuffer.
|
||||
/// </summary>
|
||||
private void FormatHexDumpCommon(byte[] data, int offset) {
|
||||
private void FormatHexDumpCommon(byte[] data, int offset, int addr, int length) {
|
||||
Debug.Assert(offset >= 0 && offset < data.Length);
|
||||
Debug.Assert(data.Length < (1 << 24));
|
||||
const int dataCol = 8;
|
||||
@ -1014,21 +1022,30 @@ namespace Asm65 {
|
||||
char[] hexChars = mFormatConfig.mUpperHexDigits ? sHexCharsUpper : sHexCharsLower;
|
||||
char[] outBuf = mHexDumpBuffer;
|
||||
|
||||
int skip = addr & 0x0f; // we skip this many entries...
|
||||
offset -= skip; // ...so adjust offset to balance it
|
||||
addr &= ~0x0f;
|
||||
|
||||
// address field
|
||||
int addr = offset;
|
||||
for (int i = 5; i >= 0; i--) {
|
||||
outBuf[i] = hexChars[addr & 0x0f];
|
||||
addr >>= 4;
|
||||
}
|
||||
|
||||
// hex digits and characters
|
||||
int length = Math.Min(16, data.Length - offset);
|
||||
// If addr doesn't start at xxx0, pad it.
|
||||
int index;
|
||||
for (index = 0; index < length; index++) {
|
||||
for (index = 0; index < skip; index++) {
|
||||
outBuf[dataCol + index * 3] = outBuf[dataCol + index * 3 + 1] =
|
||||
outBuf[asciiCol + index] = ' ';
|
||||
}
|
||||
|
||||
// hex digits and characters
|
||||
for (int i = 0; i < length; i++) {
|
||||
byte val = data[offset + index];
|
||||
outBuf[dataCol + index * 3] = hexChars[val >> 4];
|
||||
outBuf[dataCol + index * 3 + 1] = hexChars[val & 0x0f];
|
||||
outBuf[asciiCol + index] = CharConv(val);
|
||||
index++;
|
||||
}
|
||||
|
||||
// for partial line, clear out previous contents
|
||||
|
@ -21,7 +21,7 @@ namespace Asm65 {
|
||||
/// <summary>
|
||||
/// Parses an integer in a variety of formats (hex, decimal, binary). We allow
|
||||
/// hex to be identified with a leading '$' as well as "0x".
|
||||
///
|
||||
///
|
||||
/// Trim whitespace before calling here.
|
||||
/// </summary>
|
||||
/// <param name="str">String to parse.</param>
|
||||
@ -57,5 +57,45 @@ namespace Asm65 {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a long integer in a variety of formats (hex, decimal, binary). We allow
|
||||
/// hex to be identified with a leading '$' as well as "0x".
|
||||
///
|
||||
/// Trim whitespace before calling here.
|
||||
/// </summary>
|
||||
/// <param name="str">String to parse.</param>
|
||||
/// <param name="val">Integer value of string.</param>
|
||||
/// <param name="intBase">What base the string was in (2, 10, or 16).</param>
|
||||
/// <returns>True if the parsing was successful.</returns>
|
||||
public static bool TryParseLong(string str, out long val, out int intBase) {
|
||||
if (string.IsNullOrEmpty(str)) {
|
||||
val = intBase = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (str[0] == '$') {
|
||||
intBase = 16;
|
||||
str = str.Substring(1); // Convert functions don't like '$'
|
||||
} else if (str.Length > 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
|
||||
intBase = 16;
|
||||
} else if (str[0] == '%') {
|
||||
intBase = 2;
|
||||
str = str.Substring(1); // Convert functions don't like '%'
|
||||
} else {
|
||||
intBase = 10; // try it as decimal
|
||||
}
|
||||
|
||||
try {
|
||||
val = Convert.ToInt64(str, intBase);
|
||||
//Debug.WriteLine("GOT " + val + " - " + intBase);
|
||||
} catch (Exception) {
|
||||
//Debug.WriteLine("TryParseInt failed on '" + str + "': " + ex.Message);
|
||||
val = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ namespace SourceGen {
|
||||
///
|
||||
/// This is shared with the DisplayList.
|
||||
/// </summary>
|
||||
private Formatter mOutputFormatter;
|
||||
private Formatter mFormatter;
|
||||
|
||||
/// <summary>
|
||||
/// Pseudo-op names.
|
||||
@ -180,7 +180,7 @@ namespace SourceGen {
|
||||
/// CPU definition used when the Formatter was created. If the CPU choice or
|
||||
/// inclusion of undocumented opcodes changes, we need to wipe the formatter.
|
||||
/// </summary>
|
||||
private CpuDef mOutputFormatterCpuDef;
|
||||
private CpuDef mFormatterCpuDef;
|
||||
|
||||
/// <summary>
|
||||
/// Instruction description object. Used for Info window.
|
||||
@ -486,10 +486,10 @@ namespace SourceGen {
|
||||
}
|
||||
|
||||
|
||||
// Update the formatter, and null out mOutputFormatterCpuDef to force a refresh
|
||||
// Update the formatter, and null out mFormatterCpuDef to force a refresh
|
||||
// of related items.
|
||||
mOutputFormatter = new Formatter(mFormatterConfig);
|
||||
mOutputFormatterCpuDef = null;
|
||||
mFormatter = new Formatter(mFormatterConfig);
|
||||
mFormatterCpuDef = null;
|
||||
|
||||
// Set pseudo-op names. Entries aren't allowed to be blank, so we start with the
|
||||
// default values and merge in whatever the user has configured.
|
||||
@ -737,7 +737,7 @@ namespace SourceGen {
|
||||
|
||||
private void FinishPrep() {
|
||||
CodeLineList = new LineListGen(mProject, mMainWin.CodeDisplayList,
|
||||
mOutputFormatter, mPseudoOpNames);
|
||||
mFormatter, mPseudoOpNames);
|
||||
SetCodeLineListColorMultiplier();
|
||||
|
||||
string messages = mProject.LoadExternalFiles();
|
||||
@ -959,13 +959,13 @@ namespace SourceGen {
|
||||
// Changing the CPU type or whether undocumented instructions are supported
|
||||
// invalidates the Formatter's mnemonic cache. We can change these values
|
||||
// through undo/redo, so we need to check it here.
|
||||
if (mOutputFormatterCpuDef != mProject.CpuDef) { // reference equality is fine
|
||||
if (mFormatterCpuDef != mProject.CpuDef) { // reference equality is fine
|
||||
Debug.WriteLine("CpuDef has changed, resetting formatter (now " +
|
||||
mProject.CpuDef + ")");
|
||||
mOutputFormatter = new Formatter(mFormatterConfig);
|
||||
CodeLineList.SetFormatter(mOutputFormatter);
|
||||
mFormatter = new Formatter(mFormatterConfig);
|
||||
CodeLineList.SetFormatter(mFormatter);
|
||||
CodeLineList.SetPseudoOpNames(mPseudoOpNames);
|
||||
mOutputFormatterCpuDef = mProject.CpuDef;
|
||||
mFormatterCpuDef = mProject.CpuDef;
|
||||
}
|
||||
|
||||
if (reanalysisRequired != UndoableChange.ReanalysisScope.DisplayOnly) {
|
||||
@ -978,7 +978,7 @@ namespace SourceGen {
|
||||
mReanalysisTimer.EndTask("Call DisasmProject.Analyze()");
|
||||
|
||||
mReanalysisTimer.StartTask("Update message list");
|
||||
mMainWin.UpdateMessageList(mProject.Messages, mOutputFormatter);
|
||||
mMainWin.UpdateMessageList(mProject.Messages, mFormatter);
|
||||
mReanalysisTimer.EndTask("Update message list");
|
||||
}
|
||||
|
||||
@ -1410,7 +1410,7 @@ namespace SourceGen {
|
||||
} else if (format == ClipLineFormat.AllColumns) {
|
||||
colFlags = Exporter.ActiveColumnFlags.ALL;
|
||||
}
|
||||
Exporter eport = new Exporter(mProject, CodeLineList, mOutputFormatter,
|
||||
Exporter eport = new Exporter(mProject, CodeLineList, mFormatter,
|
||||
colFlags, rightWidths);
|
||||
eport.Selection = selection;
|
||||
|
||||
@ -1727,7 +1727,7 @@ namespace SourceGen {
|
||||
}
|
||||
|
||||
EditAddress dlg = new EditAddress(mMainWin, firstOffset, nextOffset, nextAddr,
|
||||
mProject, mOutputFormatter);
|
||||
mProject, mFormatter);
|
||||
if (dlg.ShowDialog() != true) {
|
||||
return;
|
||||
}
|
||||
@ -1826,7 +1826,7 @@ namespace SourceGen {
|
||||
|
||||
Anattrib attr = mProject.GetAnattrib(offset);
|
||||
EditLabel dlg = new EditLabel(mMainWin, attr.Symbol, attr.Address, offset,
|
||||
mProject.SymbolTable, mOutputFormatter);
|
||||
mProject.SymbolTable, mFormatter);
|
||||
if (dlg.ShowDialog() != true) {
|
||||
return;
|
||||
}
|
||||
@ -1907,7 +1907,7 @@ namespace SourceGen {
|
||||
mProject.LvTables.TryGetValue(offset, out LocalVariableTable oldLvt);
|
||||
|
||||
EditLocalVariableTable dlg = new EditLocalVariableTable(mMainWin, mProject,
|
||||
mOutputFormatter, oldLvt, offset);
|
||||
mFormatter, oldLvt, offset);
|
||||
if (dlg.ShowDialog() != true) {
|
||||
return;
|
||||
}
|
||||
@ -1953,7 +1953,7 @@ namespace SourceGen {
|
||||
}
|
||||
|
||||
private void EditLongComment(int offset) {
|
||||
EditLongComment dlg = new EditLongComment(mMainWin, mOutputFormatter);
|
||||
EditLongComment dlg = new EditLongComment(mMainWin, mFormatter);
|
||||
if (mProject.LongComments.TryGetValue(offset, out MultiLineComment oldComment)) {
|
||||
dlg.LongComment = oldComment;
|
||||
}
|
||||
@ -2042,7 +2042,7 @@ namespace SourceGen {
|
||||
|
||||
private void EditInstructionOperand(int offset) {
|
||||
EditInstructionOperand dlg = new EditInstructionOperand(mMainWin, mProject,
|
||||
offset, mOutputFormatter);
|
||||
offset, mFormatter);
|
||||
if (dlg.ShowDialog() != true) {
|
||||
return;
|
||||
}
|
||||
@ -2130,7 +2130,7 @@ namespace SourceGen {
|
||||
mProject.OperandFormats.TryGetValue(firstOffset.Value, out FormatDescriptor dfd);
|
||||
|
||||
EditDataOperand dlg =
|
||||
new EditDataOperand(mMainWin, mProject, mOutputFormatter, trs, dfd);
|
||||
new EditDataOperand(mMainWin, mProject, mFormatter, trs, dfd);
|
||||
if (dlg.ShowDialog() == true) {
|
||||
// Merge the changes into the OperandFormats list. We need to remove all
|
||||
// FormatDescriptors that overlap the selected region. We don't need to
|
||||
@ -2153,7 +2153,7 @@ namespace SourceGen {
|
||||
projectDir = Path.GetDirectoryName(mProjectPathName);
|
||||
}
|
||||
EditProjectProperties dlg = new EditProjectProperties(mMainWin, mProject.ProjectProps,
|
||||
projectDir, mOutputFormatter, initialTab);
|
||||
projectDir, mFormatter, initialTab);
|
||||
dlg.ShowDialog();
|
||||
ProjectProperties newProps = dlg.NewProps;
|
||||
|
||||
@ -2185,7 +2185,7 @@ namespace SourceGen {
|
||||
DefSymbol origDefSym = mProject.ActiveDefSymbolList[symIndex];
|
||||
Debug.Assert(origDefSym.SymbolSource == Symbol.Source.Project);
|
||||
|
||||
EditDefSymbol dlg = new EditDefSymbol(mMainWin, mOutputFormatter,
|
||||
EditDefSymbol dlg = new EditDefSymbol(mMainWin, mFormatter,
|
||||
mProject.ProjectProps.ProjectSyms, origDefSym, null);
|
||||
if (dlg.ShowDialog() == true) {
|
||||
ProjectProperties newProps = new ProjectProperties(mProject.ProjectProps);
|
||||
@ -2245,7 +2245,7 @@ namespace SourceGen {
|
||||
mProject.VisualizationSets.TryGetValue(offset, out VisualizationSet curVisSet);
|
||||
|
||||
EditVisualizationSet dlg = new EditVisualizationSet(mMainWin, mProject,
|
||||
mOutputFormatter, curVisSet, offset);
|
||||
mFormatter, curVisSet, offset);
|
||||
if (dlg.ShowDialog() != true) {
|
||||
return;
|
||||
}
|
||||
@ -2307,7 +2307,7 @@ namespace SourceGen {
|
||||
dlg.AsmLabelColWidth, dlg.AsmOpcodeColWidth,
|
||||
dlg.AsmOperandColWidth, dlg.AsmCommentColWidth
|
||||
};
|
||||
Exporter eport = new Exporter(mProject, CodeLineList, mOutputFormatter,
|
||||
Exporter eport = new Exporter(mProject, CodeLineList, mFormatter,
|
||||
dlg.ColFlags, rightWidths);
|
||||
eport.IncludeNotes = dlg.IncludeNotes;
|
||||
eport.GenerateImageFiles = dlg.GenerateImageFiles;
|
||||
@ -2526,7 +2526,7 @@ namespace SourceGen {
|
||||
}
|
||||
|
||||
FormatAddressTable dlg = new FormatAddressTable(mMainWin, mProject, trs,
|
||||
mOutputFormatter);
|
||||
mFormatter);
|
||||
|
||||
dlg.ShowDialog();
|
||||
if (dlg.DialogResult != true) {
|
||||
@ -2583,7 +2583,7 @@ namespace SourceGen {
|
||||
}
|
||||
int offset = CodeLineList[index].FileOffset;
|
||||
|
||||
GotoBox dlg = new GotoBox(mMainWin, mProject, offset, mOutputFormatter);
|
||||
GotoBox dlg = new GotoBox(mMainWin, mProject, offset, mFormatter);
|
||||
if (dlg.ShowDialog() == true) {
|
||||
GoToLocation(new NavStack.Location(dlg.TargetOffset, 0, false),
|
||||
GoToMode.JumpToCodeData, true);
|
||||
@ -2696,7 +2696,7 @@ namespace SourceGen {
|
||||
// We're comparing to the formatted strings -- safer than trying to find the symbol
|
||||
// in the table and then guess at how the table arranges itself for display -- so we
|
||||
// need to compare the formatted form of the label.
|
||||
string cmpStr = mOutputFormatter.FormatVariableLabel(symRef.Label);
|
||||
string cmpStr = mFormatter.FormatVariableLabel(symRef.Label);
|
||||
int lineIndex = CodeLineList.FindLineIndexByOffset(varOffset);
|
||||
while (lineIndex < mProject.FileDataLength) {
|
||||
LineListGen.Line line = CodeLineList[lineIndex];
|
||||
@ -3125,7 +3125,7 @@ namespace SourceGen {
|
||||
// when it's not on top, it can sit behind the main app window until you
|
||||
// double-click something else.
|
||||
mHexDumpDialog = new Tools.WpfGui.HexDumpViewer(null,
|
||||
mProject.FileData, mOutputFormatter);
|
||||
mProject.FileData, mFormatter);
|
||||
mHexDumpDialog.Closing += (sender, e) => {
|
||||
Debug.WriteLine("Hex dump dialog closed");
|
||||
//showHexDumpToolStripMenuItem.Checked = false;
|
||||
@ -3448,7 +3448,7 @@ namespace SourceGen {
|
||||
}
|
||||
|
||||
// TODO(someday): localization
|
||||
Asm65.Formatter formatter = mOutputFormatter;
|
||||
Asm65.Formatter formatter = mFormatter;
|
||||
bool showBank = !mProject.CpuDef.HasAddr16;
|
||||
for (int i = 0; i < xrefs.Count; i++) {
|
||||
XrefSet.Xref xr = xrefs[i];
|
||||
@ -3565,7 +3565,7 @@ namespace SourceGen {
|
||||
}
|
||||
|
||||
MainWindow.NotesListItem nli = new MainWindow.NotesListItem(offset,
|
||||
mOutputFormatter.FormatOffset24(offset),
|
||||
mFormatter.FormatOffset24(offset),
|
||||
nocrlfStr,
|
||||
mlc.BackgroundColor);
|
||||
mMainWin.NotesList.Add(nli);
|
||||
@ -3583,13 +3583,13 @@ namespace SourceGen {
|
||||
private void PopulateSymbolsList() {
|
||||
mMainWin.SymbolsList.Clear();
|
||||
foreach (Symbol sym in mProject.SymbolTable) {
|
||||
string valueStr = mOutputFormatter.FormatHexValue(sym.Value, 0);
|
||||
string valueStr = mFormatter.FormatHexValue(sym.Value, 0);
|
||||
string sourceTypeStr = sym.SourceTypeString;
|
||||
if (sym is DefSymbol) {
|
||||
DefSymbol defSym = (DefSymbol)sym;
|
||||
if (defSym.MultiMask != null) {
|
||||
valueStr += " & " +
|
||||
mOutputFormatter.FormatHexValue(defSym.MultiMask.AddressMask, 4);
|
||||
mFormatter.FormatHexValue(defSym.MultiMask.AddressMask, 4);
|
||||
}
|
||||
if (defSym.Direction == DefSymbol.DirectionFlags.Read) {
|
||||
sourceTypeStr += '<';
|
||||
@ -3599,7 +3599,7 @@ namespace SourceGen {
|
||||
}
|
||||
|
||||
MainWindow.SymbolsListItem sli = new MainWindow.SymbolsListItem(sym,
|
||||
sourceTypeStr, valueStr, sym.GenerateDisplayLabel(mOutputFormatter));
|
||||
sourceTypeStr, valueStr, sym.GenerateDisplayLabel(mFormatter));
|
||||
mMainWin.SymbolsList.Add(sli);
|
||||
}
|
||||
}
|
||||
@ -3970,7 +3970,7 @@ namespace SourceGen {
|
||||
public void ToggleInstructionChart() {
|
||||
if (mInstructionChartDialog == null) {
|
||||
// Create without owner so it doesn't have to be in front of main window.
|
||||
mInstructionChartDialog = new Tools.WpfGui.InstructionChart(null, mOutputFormatter);
|
||||
mInstructionChartDialog = new Tools.WpfGui.InstructionChart(null, mFormatter);
|
||||
mInstructionChartDialog.Closing += (sender, e) => {
|
||||
Debug.WriteLine("Instruction chart closed");
|
||||
mInstructionChartDialog = null;
|
||||
@ -4009,7 +4009,7 @@ namespace SourceGen {
|
||||
|
||||
// Create the dialog without an owner, and add it to the "unowned" list.
|
||||
Tools.WpfGui.HexDumpViewer dlg = new Tools.WpfGui.HexDumpViewer(null,
|
||||
data, mOutputFormatter);
|
||||
data, mFormatter);
|
||||
dlg.SetFileName(Path.GetFileName(fileName));
|
||||
dlg.Closing += (sender, e) => {
|
||||
Debug.WriteLine("Window " + dlg + " closed, removing from unowned list");
|
||||
@ -4025,6 +4025,21 @@ namespace SourceGen {
|
||||
concat.ShowDialog();
|
||||
}
|
||||
|
||||
public void SliceFiles() {
|
||||
OpenFileDialog fileDlg = new OpenFileDialog() {
|
||||
Filter = Res.Strings.FILE_FILTER_ALL,
|
||||
FilterIndex = 1
|
||||
};
|
||||
if (fileDlg.ShowDialog() != true) {
|
||||
return;
|
||||
}
|
||||
string pathName = Path.GetFullPath(fileDlg.FileName);
|
||||
|
||||
Tools.WpfGui.FileSlicer slicer = new Tools.WpfGui.FileSlicer(this.mMainWin, pathName,
|
||||
mFormatter);
|
||||
slicer.ShowDialog();
|
||||
}
|
||||
|
||||
#endregion Tools
|
||||
|
||||
#region Debug features
|
||||
|
@ -12,6 +12,23 @@
|
||||
<div id="content">
|
||||
<h1>6502bench SourceGen: Tools</h1>
|
||||
|
||||
<h2><a name="instruction-chart">Instruction Chart</a></h2>
|
||||
<p>This opens a window with a summary of all 256 opcodes. The CPU can
|
||||
be chosen from the pop-up list at the bottom. Undocumented opcodes are
|
||||
shown in italics.</p>
|
||||
<p>The status flags affected by each instruction reflect their behavior
|
||||
on the 65816. The only significant difference between 65816 and
|
||||
6502/65C02 is the way the BRK instruction affects the D and B/X flags.</p>
|
||||
|
||||
|
||||
<h2><a name="ascii-chart">ASCII Chart</a></h2>
|
||||
|
||||
<p>This opens a window with the ASCII character set. Each character is
|
||||
displayed next to its numeric value in decimal and hexadecimal. The
|
||||
pop-up list at the bottom allows you to flip between standard and "high"
|
||||
ASCII.</p>
|
||||
|
||||
|
||||
<h2><a name="hexdump">Hex Dump Viewer</a></h2>
|
||||
|
||||
<p>You can use this to view the contents of the project data file
|
||||
@ -53,25 +70,19 @@ external files.</p>
|
||||
|
||||
<p>The File Concatenator combines multiple files into a single file.
|
||||
Select the files to add, arrange them in the proper order, then hit
|
||||
"Save".</p>
|
||||
"Save". CRC-32 values are shown for reference.</p>
|
||||
|
||||
|
||||
<h2><a name="ascii-chart">ASCII Chart</a></h2>
|
||||
<h2><a name="file-slicer">File Slicer</a></h2>
|
||||
|
||||
<p>This opens a window with the ASCII character set. Each character is
|
||||
displayed next to its numeric value in decimal and hexadecimal. The
|
||||
pop-up list at the bottom allows you to flip between standard and "high"
|
||||
ASCII.</p>
|
||||
<p>The File Slicer allows you to "slice" a piece out of a file, saving
|
||||
it to a new file. Specify the start and length in decimal or hex. If
|
||||
you leave a field blank, they will default to offset 0 and the remaining
|
||||
length of the file, respectively.</p>
|
||||
<p>The hex dumps show the area just before and after the chunk to be
|
||||
sliced, allowing you to confirm the placement.</p>
|
||||
|
||||
|
||||
<h2><a name="instruction-chart">Instruction Chart</a></h2>
|
||||
<p>This opens a window with a summary of all 256 opcodes. The CPU can
|
||||
be chosen from the pop-up list at the bottom. Undocumented opcodes are
|
||||
shown in italics.</p>
|
||||
<p>The status flags affected by each instruction are shown for the 65816
|
||||
implementation. The only significant difference vs. 6502/65C02
|
||||
is in the way the BRK instruction affects the D and B/X flags.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="footer">
|
||||
|
@ -89,6 +89,9 @@
|
||||
<Compile Include="Tools\WpfGui\FileConcatenator.xaml.cs">
|
||||
<DependentUpon>FileConcatenator.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Tools\WpfGui\FileSlicer.xaml.cs">
|
||||
<DependentUpon>FileSlicer.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Tools\WpfGui\InstructionChart.xaml.cs">
|
||||
<DependentUpon>InstructionChart.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@ -269,6 +272,10 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Tools\WpfGui\FileSlicer.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Tools\WpfGui\InstructionChart.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
|
@ -47,7 +47,7 @@ limitations under the License.
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Text="Select files:"/>
|
||||
<TextBlock Grid.Row="0" Text="Select files:" Margin="0,0,0,4"/>
|
||||
|
||||
<DataGrid Name="concatGrid" Grid.Row="1" Height="300" Width="480"
|
||||
IsReadOnly="True"
|
||||
@ -95,6 +95,5 @@ limitations under the License.
|
||||
IsEnabled="{Binding IsSaveEnabled}" Click="SaveButton_Click"/>
|
||||
<Button Content="Cancel" IsCancel="True" Width="70" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</Window>
|
||||
|
@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
@ -21,6 +20,7 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
using Microsoft.Win32;
|
||||
|
||||
using CommonUtil;
|
||||
using System.Windows.Controls;
|
||||
|
93
SourceGen/Tools/WpfGui/FileSlicer.xaml
Normal file
93
SourceGen/Tools/WpfGui/FileSlicer.xaml
Normal file
@ -0,0 +1,93 @@
|
||||
<!--
|
||||
Copyright 2019 faddenSoft
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<Window x:Class="SourceGen.Tools.WpfGui.FileSlicer"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:SourceGen.Tools.WpfGui"
|
||||
xmlns:system="clr-namespace:System;assembly=mscorlib"
|
||||
mc:Ignorable="d"
|
||||
Title="File Slicer"
|
||||
SizeToContent="WidthAndHeight" ResizeMode="NoResize"
|
||||
ShowInTaskbar="False" WindowStartupLocation="CenterOwner"
|
||||
Closing="Window_Closing">
|
||||
|
||||
<Window.Resources>
|
||||
<system:String x:Key="str_LastByteAt" xml:space="preserve"> - last byte at </system:String>
|
||||
<system:String x:Key="str_SuccessCaption">Success</system:String>
|
||||
<system:String x:Key="str_SuccessMsg">File created.</system:String>
|
||||
<system:String x:Key="str_FileAccessFailedCaption">File Access Error</system:String>
|
||||
<system:String x:Key="str_FileAccessFailedFmt">Unable to access file: {0}</system:String>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Margin="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Text="Select region to extract:"/>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="1" HorizontalAlignment="Right" Margin="0,8,4,0"
|
||||
Text="File size:"/>
|
||||
<TextBlock Grid.Column="1" Grid.Row="1" Margin="0,8,0,0"
|
||||
Text="{Binding FileLengthStr, FallbackValue=12345 ($abcd)}"/>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="2" HorizontalAlignment="Right" Margin="0,5,4,0"
|
||||
Foreground="{Binding SliceStartBrush}" Text="Slice start:"/>
|
||||
<StackPanel Grid.Column="1" Grid.Row="2" Orientation="Horizontal" Margin="0,4,0,0">
|
||||
<TextBox HorizontalAlignment="Left" Width="80"
|
||||
Text="{Binding SliceStart, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<TextBlock Margin="8,0,0,0" Text="{Binding SliceStartDesc, FallbackValue=12345 ($abcd)}"/>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="3" HorizontalAlignment="Right" Margin="0,5,4,0"
|
||||
Foreground="{Binding SliceLengthBrush}" Text="Slice length:"/>
|
||||
<StackPanel Grid.Column="1" Grid.Row="3" Orientation="Horizontal" Margin="0,4,0,0">
|
||||
<TextBox HorizontalAlignment="Left" Width="80"
|
||||
Text="{Binding SliceLength, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<TextBlock Margin="8,0,0,0" Text="{Binding SliceLengthDesc, FallbackValue=12345 ($abcd)}"/>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="4" HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,4,4,0" Text="Start"/>
|
||||
<TextBox Grid.Column="1" Grid.Row="4" Grid.ColumnSpan="2" Margin="0,8,0,0" Width="491" Height="74"
|
||||
IsReadOnly="True" FontFamily="{StaticResource GeneralMonoFont}" Text="{Binding StartHexDump}"/>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="5" HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,4,4,0" Text="End"/>
|
||||
<TextBox Grid.Column="1" Grid.Row="5" Grid.ColumnSpan="2" Margin="0,8,0,0" Width="491" Height="74"
|
||||
IsReadOnly="True" FontFamily="{StaticResource GeneralMonoFont}" Text="{Binding EndHexDump}"/>
|
||||
|
||||
<StackPanel Grid.Column="0" Grid.Row="6" Grid.ColumnSpan="3"
|
||||
Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,10,0,0">
|
||||
<Button Content="Save..." IsDefault="True" Width="70"
|
||||
IsEnabled="{Binding IsSaveEnabled}" Click="SaveButton_Click"/>
|
||||
<Button Content="Cancel" IsCancel="True" Width="70" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
364
SourceGen/Tools/WpfGui/FileSlicer.xaml.cs
Normal file
364
SourceGen/Tools/WpfGui/FileSlicer.xaml.cs
Normal file
@ -0,0 +1,364 @@
|
||||
/*
|
||||
* Copyright 2019 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using Microsoft.Win32;
|
||||
|
||||
using Asm65;
|
||||
using System.Text;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace SourceGen.Tools.WpfGui {
|
||||
/// <summary>
|
||||
/// File slicer tool.
|
||||
/// </summary>
|
||||
public partial class FileSlicer : Window, INotifyPropertyChanged {
|
||||
/// <summary>
|
||||
/// Path to file to slice.
|
||||
/// </summary>
|
||||
private string mPathName;
|
||||
|
||||
/// <summary>
|
||||
/// Text formatter.
|
||||
/// </summary>
|
||||
private Formatter mFormatter;
|
||||
|
||||
/// <summary>
|
||||
/// Length of file to slice.
|
||||
/// </summary>
|
||||
private long mFileLength;
|
||||
|
||||
/// <summary>
|
||||
/// Open file.
|
||||
/// </summary>
|
||||
private FileStream mFileStream;
|
||||
|
||||
private bool mIsSaveEnabled;
|
||||
public bool IsSaveEnabled {
|
||||
get { return mIsSaveEnabled; }
|
||||
set { mIsSaveEnabled = value; OnPropertyChanged(); }
|
||||
}
|
||||
|
||||
public string FileLengthStr {
|
||||
get { return FormatDecAndHex(mFileLength); }
|
||||
}
|
||||
|
||||
// Start/length entry fields and dec+hex display.
|
||||
private string mSliceStart;
|
||||
public string SliceStart {
|
||||
get { return mSliceStart; }
|
||||
set { mSliceStart = value; OnPropertyChanged(); UpdateControls(); }
|
||||
}
|
||||
private string mSliceStartDesc;
|
||||
public string SliceStartDesc {
|
||||
get { return mSliceStartDesc; }
|
||||
set { mSliceStartDesc = value; OnPropertyChanged(); }
|
||||
}
|
||||
private string mSliceLength;
|
||||
public string SliceLength {
|
||||
get { return mSliceLength; }
|
||||
set { mSliceLength = value; OnPropertyChanged(); UpdateControls(); }
|
||||
}
|
||||
private string mSliceLengthDesc;
|
||||
public string SliceLengthDesc {
|
||||
get { return mSliceLengthDesc; }
|
||||
set { mSliceLengthDesc = value; OnPropertyChanged(); }
|
||||
}
|
||||
|
||||
private string mStartHexDump;
|
||||
public string StartHexDump {
|
||||
get { return mStartHexDump; }
|
||||
set { mStartHexDump = value; OnPropertyChanged(); }
|
||||
}
|
||||
private string mEndHexDump;
|
||||
public string EndHexDump {
|
||||
get { return mEndHexDump; }
|
||||
set { mEndHexDump = value; OnPropertyChanged(); }
|
||||
}
|
||||
|
||||
// Text turns red on error.
|
||||
private Brush mSliceStartBrush;
|
||||
public Brush SliceStartBrush {
|
||||
get { return mSliceStartBrush; }
|
||||
set { mSliceStartBrush = value; OnPropertyChanged(); }
|
||||
}
|
||||
private Brush mSliceLengthBrush;
|
||||
public Brush SliceLengthBrush {
|
||||
get { return mSliceLengthBrush; }
|
||||
set { mSliceLengthBrush = value; OnPropertyChanged(); }
|
||||
}
|
||||
|
||||
private Brush mDefaultLabelColor = SystemColors.WindowTextBrush;
|
||||
private Brush mErrorLabelColor = Brushes.Red;
|
||||
|
||||
// INotifyPropertyChanged implementation
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
private void OnPropertyChanged([CallerMemberName] string propertyName = "") {
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public FileSlicer(Window owner, string pathName, Formatter formatter) {
|
||||
InitializeComponent();
|
||||
Owner = owner;
|
||||
DataContext = this;
|
||||
|
||||
mPathName = pathName;
|
||||
mFormatter = formatter;
|
||||
|
||||
mFileLength = new FileInfo(pathName).Length;
|
||||
mFileStream = new FileStream(pathName, FileMode.Open, FileAccess.Read);
|
||||
|
||||
mSliceStart = mSliceLength = string.Empty;
|
||||
UpdateControls();
|
||||
}
|
||||
|
||||
private void Window_Closing(object sender, CancelEventArgs e) {
|
||||
mFileStream.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a value in decimal and hex.
|
||||
/// </summary>
|
||||
/// <param name="val">Value to format.</param>
|
||||
/// <returns>Formatted string.</returns>
|
||||
private string FormatDecAndHex(long val) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append(val.ToString());
|
||||
sb.Append(" (");
|
||||
sb.Append(mFormatter.FormatHexValue((int)val, 4));
|
||||
sb.Append(")");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the state of the controls after something changed.
|
||||
/// </summary>
|
||||
private void UpdateControls() {
|
||||
ParseStartLength(out bool isStartValid, out long sliceStart,
|
||||
out bool isLengthValid, out long sliceLength);
|
||||
|
||||
SliceStartDesc = FormatDecAndHex(sliceStart);
|
||||
SliceLengthDesc = FormatDecAndHex(sliceLength) +
|
||||
(string)FindResource("str_LastByteAt") +
|
||||
mFormatter.FormatOffset24((int)(sliceStart + sliceLength - 1));
|
||||
|
||||
if (isStartValid && isLengthValid) {
|
||||
// anchor is first byte in slice
|
||||
StartHexDump = CreateSplitHexDump(0, sliceStart, sliceStart + sliceLength - 1);
|
||||
// anchor is first byte after slice (may be off end)
|
||||
EndHexDump = CreateSplitHexDump(sliceStart, sliceStart + sliceLength,
|
||||
mFileLength - 1);
|
||||
} else {
|
||||
StartHexDump = EndHexDump = string.Empty;
|
||||
}
|
||||
|
||||
SliceStartBrush = isStartValid ? mDefaultLabelColor : mErrorLabelColor;
|
||||
SliceLengthBrush = isLengthValid ? mDefaultLabelColor : mErrorLabelColor;
|
||||
|
||||
IsSaveEnabled = isStartValid && isLengthValid;
|
||||
}
|
||||
|
||||
private void ParseStartLength(out bool startOk, out long sliceStart,
|
||||
out bool lengthOk, out long sliceLength) {
|
||||
startOk = lengthOk = true;
|
||||
|
||||
if (string.IsNullOrEmpty(SliceStart)) {
|
||||
sliceStart = 0;
|
||||
} else if (Number.TryParseLong(SliceStart.Trim(), out sliceStart, out int unused1)) {
|
||||
if (sliceStart < 0 || sliceStart >= mFileLength) {
|
||||
startOk = false;
|
||||
}
|
||||
} else {
|
||||
startOk = false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(SliceLength)) {
|
||||
sliceLength = mFileLength - sliceStart;
|
||||
if (sliceLength < 0) {
|
||||
sliceLength = 0;
|
||||
}
|
||||
} else if (Number.TryParseLong(SliceLength.Trim(), out sliceLength, out int unused2)) {
|
||||
if (sliceLength <= 0 || sliceLength > mFileLength ||
|
||||
sliceStart + sliceLength > mFileLength) {
|
||||
lengthOk = false;
|
||||
}
|
||||
} else {
|
||||
lengthOk = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a hex dump with up to 5 lines. Two lines before the anchor point, then
|
||||
/// a gap, then two lines that start with the anchor.
|
||||
/// </summary>
|
||||
/// <param name="minFirst">Earliest position we're allowed to include.</param>
|
||||
/// <param name="anchorPos">Anchor point.</param>
|
||||
/// <param name="maxLast">Last position we're allowed to show (inclusive end).</param>
|
||||
/// <returns>Multi-line formatted string.</returns>
|
||||
private string CreateSplitHexDump(long minFirst, long anchorPos, long maxLast) {
|
||||
const long AND_16_MASK = ~0x0f;
|
||||
|
||||
Debug.Assert(minFirst <= anchorPos && anchorPos <= maxLast + 1 && minFirst <= maxLast);
|
||||
Debug.Assert(minFirst >= 0);
|
||||
Debug.Assert(maxLast < mFileLength);
|
||||
|
||||
StringBuilder sb = new StringBuilder(5 * 64);
|
||||
byte[] dataBuf = new byte[32];
|
||||
|
||||
// We show two lines of hex dump before the anchor, so we need up to 32 bytes.
|
||||
long firstPos = Math.Max(anchorPos - 32, minFirst);
|
||||
firstPos = (firstPos + 15) & AND_16_MASK;
|
||||
long chunkLen = anchorPos - firstPos;
|
||||
|
||||
mFileStream.Seek(firstPos, SeekOrigin.Begin);
|
||||
int actual = mFileStream.Read(dataBuf, 0, dataBuf.Length);
|
||||
Debug.Assert(chunkLen <= actual);
|
||||
|
||||
if (chunkLen <= 0) {
|
||||
// no pre-anchor data
|
||||
sb.AppendLine(string.Empty);
|
||||
sb.AppendLine(string.Empty);
|
||||
} else {
|
||||
long pos = firstPos;
|
||||
long lineLen = 16 - (pos & 0x0f);
|
||||
if (lineLen >= chunkLen) {
|
||||
// top part fits on a single line; do it on the next one
|
||||
lineLen = chunkLen;
|
||||
sb.AppendLine(string.Empty);
|
||||
} else {
|
||||
mFormatter.FormatHexDump(dataBuf, (int)(pos - firstPos), (int)pos,
|
||||
(int)lineLen, sb);
|
||||
sb.Append("\r\n");
|
||||
//sb.AppendLine(pos.ToString("x4") + ": " + lineLen);
|
||||
pos += lineLen;
|
||||
lineLen = chunkLen - lineLen;
|
||||
}
|
||||
|
||||
mFormatter.FormatHexDump(dataBuf, (int)(pos - firstPos), (int)pos,
|
||||
(int)lineLen, sb);
|
||||
sb.Append("\r\n");
|
||||
//sb.AppendLine(pos.ToString("x4") + ": " + lineLen);
|
||||
}
|
||||
|
||||
sb.AppendLine("------");
|
||||
|
||||
// We show two lines of hex dump with the anchor, so we need up to 31 bytes
|
||||
// following it.
|
||||
//
|
||||
// NOTE: anchorPos is inclusive and represents the first byte contained in the
|
||||
// range. If we're doing the hex dump for the end of the file, the value can be
|
||||
// one greater than maxLast if the pre-anchor range runs to EOF.
|
||||
long lastPos = ((anchorPos + 32) & AND_16_MASK) - 1; // inclusive end
|
||||
lastPos = Math.Min(lastPos, maxLast);
|
||||
chunkLen = lastPos - anchorPos + 1;
|
||||
|
||||
mFileStream.Seek(anchorPos, SeekOrigin.Begin);
|
||||
actual = mFileStream.Read(dataBuf, 0, dataBuf.Length);
|
||||
Debug.Assert(chunkLen <= actual);
|
||||
|
||||
if (chunkLen <= 0) {
|
||||
// anchor not visible
|
||||
sb.AppendLine(string.Empty);
|
||||
sb.AppendLine(string.Empty);
|
||||
} else {
|
||||
long pos = anchorPos;
|
||||
long lineLen = 16 - (pos & 0x0f);
|
||||
if (lineLen > chunkLen) {
|
||||
lineLen = chunkLen;
|
||||
}
|
||||
mFormatter.FormatHexDump(dataBuf, (int)(pos - anchorPos), (int)pos,
|
||||
(int)lineLen, sb);
|
||||
sb.Append("\r\n");
|
||||
//sb.AppendLine(pos.ToString("x4") + ": " + lineLen);
|
||||
pos += lineLen;
|
||||
lineLen = chunkLen - lineLen;
|
||||
|
||||
if (lineLen <= 0) {
|
||||
sb.AppendLine(string.Empty);
|
||||
} else {
|
||||
mFormatter.FormatHexDump(dataBuf, (int)(pos - anchorPos), (int)pos,
|
||||
(int)lineLen, sb);
|
||||
sb.Append("\r\n");
|
||||
//sb.AppendLine(pos.ToString("x4") + ": " + lineLen);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private void SaveButton_Click(object sender, RoutedEventArgs e) {
|
||||
SaveFileDialog fileDlg = new SaveFileDialog() {
|
||||
Filter = Res.Strings.FILE_FILTER_ALL,
|
||||
FilterIndex = 0,
|
||||
ValidateNames = true,
|
||||
FileName = "slice.bin"
|
||||
};
|
||||
if (fileDlg.ShowDialog() != true) {
|
||||
return;
|
||||
}
|
||||
string pathName = Path.GetFullPath(fileDlg.FileName);
|
||||
Debug.WriteLine("OUTPUT TO " + pathName);
|
||||
|
||||
try {
|
||||
ParseStartLength(out bool startOk, out long sliceStart,
|
||||
out bool lengthOk, out long sliceLength);
|
||||
if (!(startOk && lengthOk)) {
|
||||
throw new Exception("Internal error: start/length invalid");
|
||||
}
|
||||
|
||||
using (FileStream outStream = new FileStream(pathName, FileMode.Create)) {
|
||||
mFileStream.Seek(sliceStart, SeekOrigin.Begin);
|
||||
CopyStreamToStream(mFileStream, outStream, sliceLength);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
string ecaption = (string)FindResource("str_FileAccessFailedCaption");
|
||||
string efmt = (string)FindResource("str_FileAccessFailedFmt");
|
||||
MessageBox.Show(string.Format(efmt, ex.Message), ecaption,
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
string caption = (string)FindResource("str_SuccessCaption");
|
||||
string msg = (string)FindResource("str_SuccessMsg");
|
||||
MessageBox.Show(msg, caption, MessageBoxButton.OK, MessageBoxImage.None);
|
||||
}
|
||||
|
||||
private static void CopyStreamToStream(Stream inStream, Stream outStream, long length) {
|
||||
byte[] buffer = new byte[256 * 1024];
|
||||
|
||||
while (length > 0) {
|
||||
int getLen = (int)Math.Min(length, buffer.Length);
|
||||
|
||||
int actual = inStream.Read(buffer, 0, getLen);
|
||||
if (actual != getLen) {
|
||||
throw new IOException("Read failed: requested " + getLen + ", got " + actual);
|
||||
}
|
||||
outStream.Write(buffer, 0, getLen);
|
||||
|
||||
length -= getLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -32,6 +32,7 @@ limitations under the License.
|
||||
<system:String x:Key="str_LowHighAscii">Low/High ASCII</system:String>
|
||||
<system:String x:Key="str_C64Petscii">C64 PETSCII</system:String>
|
||||
<system:String x:Key="str_C64ScreenCode">C64 Screen Code</system:String>
|
||||
<system:String x:Key="str_TitleAddon" xml:space="preserve"> - Hex Dump Viewer</system:String>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Margin="8">
|
||||
|
@ -126,7 +126,7 @@ namespace SourceGen.Tools.WpfGui {
|
||||
/// Sets the filename associated with the data. This is for display purposes only.
|
||||
/// </summary>
|
||||
public void SetFileName(string fileName) {
|
||||
Title = fileName;
|
||||
Title = fileName + (string)FindResource("str_TitleAddon");
|
||||
}
|
||||
|
||||
private void CharConvComboBox_SelectionChanged(object sender,
|
||||
|
@ -40,7 +40,7 @@ namespace SourceGen.WpfGui {
|
||||
}
|
||||
private string mCommentText;
|
||||
|
||||
private Brush mDefaultLabelColor;
|
||||
private Brush mDefaultLabelColor = SystemColors.WindowTextBrush;
|
||||
|
||||
// INotifyPropertyChanged implementation
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
@ -54,7 +54,6 @@ namespace SourceGen.WpfGui {
|
||||
DataContext = this;
|
||||
|
||||
CommentText = comment;
|
||||
mDefaultLabelColor = asciiOnlyLabel.Foreground;
|
||||
}
|
||||
|
||||
public void Window_ContentRendered(object sender, EventArgs e) {
|
||||
|
@ -149,8 +149,7 @@ namespace SourceGen.WpfGui {
|
||||
/// </summary>
|
||||
private bool mIsWidthOptional;
|
||||
|
||||
// Saved off at dialog load time.
|
||||
private Brush mDefaultLabelColor;
|
||||
private Brush mDefaultLabelColor = SystemColors.WindowTextBrush;
|
||||
|
||||
// INotifyPropertyChanged implementation
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
@ -205,8 +204,6 @@ namespace SourceGen.WpfGui {
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e) {
|
||||
mDefaultLabelColor = labelNotesLabel.Foreground;
|
||||
|
||||
if (mOldSym != null) {
|
||||
Label = mOldSym.GenerateDisplayLabel(mNumFormatter);
|
||||
Value = mNumFormatter.FormatValueInBase(mOldSym.Value,
|
||||
|
@ -53,8 +53,7 @@ namespace SourceGen.WpfGui {
|
||||
/// </summary>
|
||||
private Formatter mFormatter;
|
||||
|
||||
// Dialog label text color, saved off at dialog load time.
|
||||
private Brush mDefaultLabelColor;
|
||||
private Brush mDefaultLabelColor = SystemColors.WindowTextBrush;
|
||||
|
||||
/// <summary>
|
||||
/// Recursion guard.
|
||||
@ -146,8 +145,6 @@ namespace SourceGen.WpfGui {
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e) {
|
||||
mDefaultLabelColor = maxLengthLabel.Foreground;
|
||||
|
||||
IsNonUniqueEnabled = IsLocalEnabled = IsGlobalEnabled = IsExportedEnabled = true;
|
||||
|
||||
if (LabelSym == null) {
|
||||
|
@ -164,13 +164,14 @@ limitations under the License.
|
||||
</RoutedUICommand>
|
||||
<RoutedUICommand x:Key="ShowFileHexDumpCmd" Text="File Hex Dump..."/>
|
||||
<RoutedUICommand x:Key="ShowHexDumpCmd" Text="Show Hex Dump"/>
|
||||
<RoutedUICommand x:Key="SliceFilesCmd" Text="Slice Files..."/>
|
||||
<RoutedUICommand x:Key="ToggleAsciiChartCmd" Text="ASCII Chart"/>
|
||||
<RoutedUICommand x:Key="ToggleDataScanCmd" Text="Toggle Data Scan">
|
||||
<RoutedUICommand.InputGestures>
|
||||
<KeyGesture>Ctrl+D</KeyGesture>
|
||||
</RoutedUICommand.InputGestures>
|
||||
</RoutedUICommand>
|
||||
<RoutedUICommand x:Key="ToggleInstructionChartCmd" Text="Instruction Chart"/>
|
||||
<RoutedUICommand x:Key="ToggleInstructionChartCmd" Text="65xx Instruction Chart"/>
|
||||
<RoutedUICommand x:Key="ToggleSingleByteFormatCmd" Text="Toggle Single-Byte Format">
|
||||
<RoutedUICommand.InputGestures>
|
||||
<KeyGesture>Ctrl+B</KeyGesture>
|
||||
@ -291,6 +292,8 @@ limitations under the License.
|
||||
Executed="ShowFileHexDumpCmd_Executed"/>
|
||||
<CommandBinding Command="{StaticResource ShowHexDumpCmd}"
|
||||
CanExecute="IsProjectOpen" Executed="ShowHexDumpCmd_Executed"/>
|
||||
<CommandBinding Command="{StaticResource SliceFilesCmd}"
|
||||
Executed="SliceFilesCmd_Executed"/>
|
||||
<CommandBinding Command="{StaticResource ToggleAsciiChartCmd}"
|
||||
Executed="ToggleAsciiChartCmd_Executed"/>
|
||||
<CommandBinding Command="{StaticResource ToggleDataScanCmd}"
|
||||
@ -400,8 +403,10 @@ limitations under the License.
|
||||
Command="{StaticResource ToggleInstructionChartCmd}" IsCheckable="True"/>
|
||||
<MenuItem Name="toggleAsciiChartMenuItem"
|
||||
Command="{StaticResource ToggleAsciiChartCmd}" IsCheckable="True"/>
|
||||
<Separator/>
|
||||
<MenuItem Command="{StaticResource ShowFileHexDumpCmd}"/>
|
||||
<MenuItem Command="{StaticResource ConcatenateFilesCmd}"/>
|
||||
<MenuItem Command="{StaticResource SliceFilesCmd}"/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="_Help">
|
||||
<MenuItem Command="Help"/>
|
||||
|
@ -1334,6 +1334,10 @@ namespace SourceGen.WpfGui {
|
||||
mMainCtrl.ShowHexDump();
|
||||
}
|
||||
|
||||
private void SliceFilesCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
|
||||
mMainCtrl.SliceFiles();
|
||||
}
|
||||
|
||||
private void ToggleAsciiChartCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
|
||||
mMainCtrl.ToggleAsciiChart();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user