mirror of
https://github.com/fadden/6502bench.git
synced 2024-12-28 01:29:29 +00:00
Progress toward OMF file handling
Added generation of info/error messages to segment parser, which are displayed in the main OMF viewer window. Added segment viewer window, which opens when a segment entry in the viewer list is double-clicked. Currently shows the "raw" header fields, with place-holder UI for additional stuff.
This commit is contained in:
parent
b77d9ba4c8
commit
d1526e5f25
@ -54,6 +54,7 @@
|
|||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Helper.cs" />
|
<Compile Include="Helper.cs" />
|
||||||
<Compile Include="InverseBooleanConverter.cs" />
|
<Compile Include="InverseBooleanConverter.cs" />
|
||||||
|
<Compile Include="ListToStringConverter.cs" />
|
||||||
<Compile Include="MultiKeyInputGesture.cs" />
|
<Compile Include="MultiKeyInputGesture.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs">
|
<Compile Include="Properties\AssemblyInfo.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
|
50
CommonWPF/ListToStringConverter.cs
Normal file
50
CommonWPF/ListToStringConverter.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
namespace CommonWPF {
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a List<string> to a multi-line string, suitable for presentation
|
||||||
|
/// in a TextBlock or other UI element.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// https://stackoverflow.com/a/345515/294248
|
||||||
|
///
|
||||||
|
/// In XAML, reference with:
|
||||||
|
/// xmlns:common="clr-namespace:CommonWPF;assembly=CommonWPF"
|
||||||
|
/// </remarks>
|
||||||
|
[ValueConversion(typeof(List<string>), typeof(string))]
|
||||||
|
public class ListToStringConverter : IValueConverter {
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||||
|
if (targetType != typeof(string)) {
|
||||||
|
Debug.WriteLine("Invalid targetType for string conversion");
|
||||||
|
return DependencyProperty.UnsetValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Join("\r\n", ((List<string>)value).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter,
|
||||||
|
CultureInfo culture) {
|
||||||
|
return DependencyProperty.UnsetValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4177,7 +4177,7 @@ namespace SourceGen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Tools.Omf.WpfGui.OmfViewer ov =
|
Tools.Omf.WpfGui.OmfViewer ov =
|
||||||
new Tools.Omf.WpfGui.OmfViewer(this.mMainWin, pathName, fileData);
|
new Tools.Omf.WpfGui.OmfViewer(this.mMainWin, pathName, fileData, mFormatter);
|
||||||
ov.ShowDialog();
|
ov.ShowDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +87,9 @@
|
|||||||
<Compile Include="Tools\ApplesoftToHtml.cs" />
|
<Compile Include="Tools\ApplesoftToHtml.cs" />
|
||||||
<Compile Include="Tools\Omf\OmfFile.cs" />
|
<Compile Include="Tools\Omf\OmfFile.cs" />
|
||||||
<Compile Include="Tools\Omf\OmfSegment.cs" />
|
<Compile Include="Tools\Omf\OmfSegment.cs" />
|
||||||
|
<Compile Include="Tools\Omf\WpfGui\OmfSegmentViewer.xaml.cs">
|
||||||
|
<DependentUpon>OmfSegmentViewer.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Tools\Omf\WpfGui\OmfViewer.xaml.cs">
|
<Compile Include="Tools\Omf\WpfGui\OmfViewer.xaml.cs">
|
||||||
<DependentUpon>OmfViewer.xaml</DependentUpon>
|
<DependentUpon>OmfViewer.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
@ -281,6 +284,10 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="Tools\Omf\WpfGui\OmfSegmentViewer.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
<Page Include="Tools\Omf\WpfGui\OmfViewer.xaml">
|
<Page Include="Tools\Omf\WpfGui\OmfViewer.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
@ -38,8 +38,8 @@ namespace SourceGen.Tools.Omf {
|
|||||||
/// Appendix F describes OMF v2.1, and Chapter 8 has some useful information about
|
/// Appendix F describes OMF v2.1, and Chapter 8 has some useful information about
|
||||||
/// how the loader works (e.g. page 205).
|
/// how the loader works (e.g. page 205).
|
||||||
/// - "Undocumented Secrets of the Apple IIGS System Loader" by Neil Parker,
|
/// - "Undocumented Secrets of the Apple IIGS System Loader" by Neil Parker,
|
||||||
/// http://nparker.llx.com/a2/loader.html . Among other things it documents ExpressLoad
|
/// http://nparker.llx.com/a2/loader.html . Among other things it documents the
|
||||||
/// segments, something Apple apparently never did.
|
/// contents of ExpressLoad segments, which I haven't found in an official reference.
|
||||||
/// - Apple IIgs Tech Note #66, "ExpressLoad Philosophy".
|
/// - Apple IIgs Tech Note #66, "ExpressLoad Philosophy".
|
||||||
///
|
///
|
||||||
/// Related:
|
/// Related:
|
||||||
@ -76,19 +76,20 @@ namespace SourceGen.Tools.Omf {
|
|||||||
Object, // output of assembler/compiler, before linking
|
Object, // output of assembler/compiler, before linking
|
||||||
Library, // static code library
|
Library, // static code library
|
||||||
RunTimeLibrary, // dynamic shared library
|
RunTimeLibrary, // dynamic shared library
|
||||||
|
Indeterminate, // valid OMF, but type is indeterminate
|
||||||
Foreign // not OMF, or not IIgs OMF
|
Foreign // not OMF, or not IIgs OMF
|
||||||
}
|
}
|
||||||
public FileKind OmfFileKind { get; private set; }
|
public FileKind OmfFileKind { get; private set; }
|
||||||
|
|
||||||
private bool mIsDamaged;
|
private bool mIsDamaged;
|
||||||
|
|
||||||
private string mDamageMsg = string.Empty;
|
|
||||||
|
|
||||||
private List<OmfSegment> mSegmentList = new List<OmfSegment>();
|
private List<OmfSegment> mSegmentList = new List<OmfSegment>();
|
||||||
public List<OmfSegment> SegmentList {
|
public List<OmfSegment> SegmentList {
|
||||||
get { return mSegmentList; }
|
get { return mSegmentList; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<string> MessageList { get; private set; } = new List<string>();
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructor.
|
/// Constructor.
|
||||||
@ -105,7 +106,13 @@ namespace SourceGen.Tools.Omf {
|
|||||||
OmfSegment.ParseResult result = DoAnalyze(false);
|
OmfSegment.ParseResult result = DoAnalyze(false);
|
||||||
if (result == OmfSegment.ParseResult.IsLibrary ||
|
if (result == OmfSegment.ParseResult.IsLibrary ||
|
||||||
result == OmfSegment.ParseResult.Failure) {
|
result == OmfSegment.ParseResult.Failure) {
|
||||||
DoAnalyze(true);
|
// Failed; try again as a library.
|
||||||
|
List<string> firstFail = new List<string>(MessageList);
|
||||||
|
result = DoAnalyze(true);
|
||||||
|
if (result == OmfSegment.ParseResult.Failure) {
|
||||||
|
// Failed both ways. Report the failures from the non-library attempt.
|
||||||
|
MessageList = firstFail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,24 +121,32 @@ namespace SourceGen.Tools.Omf {
|
|||||||
int offset = 0;
|
int offset = 0;
|
||||||
int len = mFileData.Length;
|
int len = mFileData.Length;
|
||||||
|
|
||||||
|
List<string> msgs = new List<string>();
|
||||||
|
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
OmfSegment.ParseResult result =
|
OmfSegment.ParseResult result = OmfSegment.ParseSegment(mFileData, offset,
|
||||||
OmfSegment.ParseSegment(mFileData, offset, parseAsLibrary, out OmfSegment seg);
|
parseAsLibrary, msgs, out OmfSegment seg);
|
||||||
if (result == OmfSegment.ParseResult.Failure) {
|
|
||||||
// parsing failed; reject file or stop early
|
MessageList.Clear();
|
||||||
if (first) {
|
foreach (string str in msgs) {
|
||||||
OmfFileKind = FileKind.Foreign;
|
MessageList.Add(str);
|
||||||
} else {
|
}
|
||||||
mIsDamaged = true;
|
|
||||||
mDamageMsg = string.Format("File may be damaged; ignoring last {0} bytes",
|
if (result == OmfSegment.ParseResult.IsLibrary) {
|
||||||
mFileData.Length - offset);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} else if (result == OmfSegment.ParseResult.IsLibrary) {
|
|
||||||
// Need to start over in library mode.
|
// Need to start over in library mode.
|
||||||
Debug.WriteLine("Restarting in library mode");
|
Debug.WriteLine("Restarting in library mode");
|
||||||
return result;
|
return result;
|
||||||
|
} else if (result == OmfSegment.ParseResult.Failure) {
|
||||||
|
// Could be a library we failed to parse, could be a totally bad file.
|
||||||
|
// If we were on the first segment, fail immediately so we can retry as
|
||||||
|
// library. If not, it's probably not a library (assuming the Library
|
||||||
|
// Dictionary segment appears first), but rather a partially-bad OMF.
|
||||||
|
if (first) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
first = false;
|
||||||
|
|
||||||
Debug.Assert(seg.FileLength > 0);
|
Debug.Assert(seg.FileLength > 0);
|
||||||
mSegmentList.Add(seg);
|
mSegmentList.Add(seg);
|
||||||
|
@ -76,15 +76,23 @@ namespace SourceGen.Tools.Omf {
|
|||||||
private const int LOAD_NAME_LEN = 10;
|
private const int LOAD_NAME_LEN = 10;
|
||||||
|
|
||||||
public class NameValueNote {
|
public class NameValueNote {
|
||||||
public string Name { get; set; }
|
public string Name { get; private set; }
|
||||||
public object Value { get; set; }
|
public object Value { get; private set; }
|
||||||
public string Note { get; set; }
|
public int Width { get; private set; }
|
||||||
|
public string Note { get; private set; }
|
||||||
|
|
||||||
|
public NameValueNote(string name, object value, int width, string note) {
|
||||||
|
Name = name;
|
||||||
|
Value = value;
|
||||||
|
Width = width;
|
||||||
|
Note = note;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Values pulled from file header. Useful for display.
|
/// Values pulled from file header. Useful for display.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
List<NameValueNote> RawValues = new List<NameValueNote>();
|
public List<NameValueNote> RawValues = new List<NameValueNote>();
|
||||||
|
|
||||||
public enum SegmentVersion { v0_0, v1_0, v2_0, v2_1 }
|
public enum SegmentVersion { v0_0, v1_0, v2_0, v2_1 }
|
||||||
|
|
||||||
@ -107,9 +115,9 @@ namespace SourceGen.Tools.Omf {
|
|||||||
BankRel = 0x0100, // v2.1
|
BankRel = 0x0100, // v2.1
|
||||||
Skip = 0x0200, // v2.1
|
Skip = 0x0200, // v2.1
|
||||||
Reloadable = 0x0400, // v2.0
|
Reloadable = 0x0400, // v2.0
|
||||||
AbsoluteBank = 0x0800, // v2.0
|
AbsBank = 0x0800, // v2.0
|
||||||
NoSpecial = 0x1000, // v2.0
|
NoSpecial = 0x1000, // v2.0
|
||||||
PositionIndep = 0x2000, //
|
PosnIndep = 0x2000, //
|
||||||
Private = 0x4000, //
|
Private = 0x4000, //
|
||||||
Dynamic = 0x8000 //
|
Dynamic = 0x8000 //
|
||||||
}
|
}
|
||||||
@ -118,6 +126,7 @@ namespace SourceGen.Tools.Omf {
|
|||||||
// Header fields.
|
// Header fields.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
public int FileOffset { get; private set; }
|
||||||
public int FileLength { get; private set; } // from BLKCNT or BYTECNT
|
public int FileLength { get; private set; } // from BLKCNT or BYTECNT
|
||||||
public int ResSpc { get; private set; }
|
public int ResSpc { get; private set; }
|
||||||
public int Length { get; private set; }
|
public int Length { get; private set; }
|
||||||
@ -155,19 +164,31 @@ namespace SourceGen.Tools.Omf {
|
|||||||
IsLibrary
|
IsLibrary
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses an OMF segment header.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">File data.</param>
|
||||||
|
/// <param name="offset">Offset at which to start parsing.</param>
|
||||||
|
/// <param name="parseAsLibrary">Set to true to parse the header as if it were part
|
||||||
|
/// of a library file. Affects parsing of v1 headers.</param>
|
||||||
|
/// <param name="msgs">Notes and errors generated by the parser.</param>
|
||||||
|
/// <param name="segResult">Completed object, or null on failure.</param>
|
||||||
|
/// <returns>Result code.</returns>
|
||||||
public static ParseResult ParseSegment(byte[] data, int offset, bool parseAsLibrary,
|
public static ParseResult ParseSegment(byte[] data, int offset, bool parseAsLibrary,
|
||||||
out OmfSegment segResult) {
|
List<string> msgs, out OmfSegment segResult) {
|
||||||
segResult = null;
|
segResult = null;
|
||||||
|
|
||||||
|
//Debug.WriteLine("PARSE offset=" + offset);
|
||||||
|
|
||||||
Debug.Assert(offset < data.Length);
|
Debug.Assert(offset < data.Length);
|
||||||
if (data.Length - offset < MIN_HEADER_V0) {
|
if (data.Length - offset < MIN_HEADER_V0) {
|
||||||
// Definitely too small.
|
// Definitely too small.
|
||||||
|
AddErrorMsg(msgs, offset, "remaining file space too small to hold segment");
|
||||||
return ParseResult.Failure;
|
return ParseResult.Failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Debug.WriteLine("PARSE offset=" + offset);
|
|
||||||
|
|
||||||
OmfSegment newSeg = new OmfSegment();
|
OmfSegment newSeg = new OmfSegment();
|
||||||
|
newSeg.FileOffset = offset;
|
||||||
|
|
||||||
// Start with the version number. The meaning of everything else depends on this.
|
// Start with the version number. The meaning of everything else depends on this.
|
||||||
int minLen, expectedDispName;
|
int minLen, expectedDispName;
|
||||||
@ -189,10 +210,13 @@ namespace SourceGen.Tools.Omf {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// invalid version, this is probably not OMF
|
// invalid version, this is probably not OMF
|
||||||
|
AddErrorMsg(msgs, offset, "invalid segment type " + data[offset + 0x0f]);
|
||||||
return ParseResult.Failure;
|
return ParseResult.Failure;
|
||||||
}
|
}
|
||||||
if (data.Length - offset < minLen) {
|
if (data.Length - offset < minLen) {
|
||||||
// Too small for this version of the header.
|
// Too small for this version of the header.
|
||||||
|
AddErrorMsg(msgs, offset, "remaining file space too small to hold " +
|
||||||
|
newSeg.Version + " segment");
|
||||||
return ParseResult.Failure;
|
return ParseResult.Failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,6 +251,8 @@ namespace SourceGen.Tools.Omf {
|
|||||||
expectedDispName += 4;
|
expectedDispName += 4;
|
||||||
|
|
||||||
if (data.Length - offset < minLen + 4) {
|
if (data.Length - offset < minLen + 4) {
|
||||||
|
AddErrorMsg(msgs, offset, "remaining file space too small to hold " +
|
||||||
|
newSeg.Version + " segment");
|
||||||
return ParseResult.Failure;
|
return ParseResult.Failure;
|
||||||
}
|
}
|
||||||
newSeg.TempOrg = RawData.GetWord(data, offset + 0x2c, 4, false);
|
newSeg.TempOrg = RawData.GetWord(data, offset + 0x2c, 4, false);
|
||||||
@ -238,14 +264,14 @@ namespace SourceGen.Tools.Omf {
|
|||||||
kindByte = data[offset + 0x0c];
|
kindByte = data[offset + 0x0c];
|
||||||
if (!Enum.IsDefined(typeof(SegmentKind), kindByte & 0x1f)) {
|
if (!Enum.IsDefined(typeof(SegmentKind), kindByte & 0x1f)) {
|
||||||
// Example: Moria GS has a kind of $1F for its GLOBALS segment.
|
// Example: Moria GS has a kind of $1F for its GLOBALS segment.
|
||||||
Debug.WriteLine("Invalid segment kind $" + kindByte.ToString("x2"));
|
AddErrorMsg(msgs, offset, "invalid segment kind $" + kindByte.ToString("x2"));
|
||||||
return ParseResult.Failure;
|
return ParseResult.Failure;
|
||||||
}
|
}
|
||||||
newSeg.Kind = (SegmentKind)(kindByte & 0x1f);
|
newSeg.Kind = (SegmentKind)(kindByte & 0x1f);
|
||||||
|
|
||||||
int kindAttrs = 0;
|
int kindAttrs = 0;
|
||||||
if ((kindByte & 0x20) != 0) {
|
if ((kindByte & 0x20) != 0) {
|
||||||
kindAttrs |= (int)SegmentAttribute.PositionIndep;
|
kindAttrs |= (int)SegmentAttribute.PosnIndep;
|
||||||
}
|
}
|
||||||
if ((kindByte & 0x40) != 0) {
|
if ((kindByte & 0x40) != 0) {
|
||||||
kindAttrs |= (int)SegmentAttribute.Private;
|
kindAttrs |= (int)SegmentAttribute.Private;
|
||||||
@ -258,7 +284,7 @@ namespace SourceGen.Tools.Omf {
|
|||||||
// Yank all the attribute bits out at once. Don't worry about v2.0 vs. v2.1.
|
// Yank all the attribute bits out at once. Don't worry about v2.0 vs. v2.1.
|
||||||
kindWord = RawData.GetWord(data, offset + 0x14, 2, false);
|
kindWord = RawData.GetWord(data, offset + 0x14, 2, false);
|
||||||
if (!Enum.IsDefined(typeof(SegmentKind), kindWord & 0x001f)) {
|
if (!Enum.IsDefined(typeof(SegmentKind), kindWord & 0x001f)) {
|
||||||
Debug.WriteLine("Invalid segment kind $" + kindWord.ToString("x4"));
|
AddErrorMsg(msgs, offset, "invalid segment kind $" + kindWord.ToString("x4"));
|
||||||
return ParseResult.Failure;
|
return ParseResult.Failure;
|
||||||
}
|
}
|
||||||
newSeg.Kind = (SegmentKind)(kindWord & 0x001f);
|
newSeg.Kind = (SegmentKind)(kindWord & 0x001f);
|
||||||
@ -268,6 +294,7 @@ namespace SourceGen.Tools.Omf {
|
|||||||
// If we found a library dictionary segment, and we're not currently handling the
|
// If we found a library dictionary segment, and we're not currently handling the
|
||||||
// file as a library, reject this and try again.
|
// file as a library, reject this and try again.
|
||||||
if (newSeg.Kind == SegmentKind.LibraryDict && !parseAsLibrary) {
|
if (newSeg.Kind == SegmentKind.LibraryDict && !parseAsLibrary) {
|
||||||
|
AddInfoMsg(msgs, offset, "found Library Dictionary segment, retrying as library");
|
||||||
return ParseResult.IsLibrary;
|
return ParseResult.IsLibrary;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,47 +323,57 @@ namespace SourceGen.Tools.Omf {
|
|||||||
}
|
}
|
||||||
newSeg.FileLength = segLen;
|
newSeg.FileLength = segLen;
|
||||||
|
|
||||||
|
//
|
||||||
// Perform validity checks. If any of these fail, we're probably reading something
|
// Perform validity checks. If any of these fail, we're probably reading something
|
||||||
// that isn't OMF (or, if this isn't the first segment, we might have gone off the
|
// that isn't OMF (or, if this isn't the first segment, we might have gone off the
|
||||||
// rails at some point).
|
// rails at some point).
|
||||||
if (numLen != 4 || numSex != 0) {
|
//
|
||||||
Debug.WriteLine("Invalid NUMLEN (" + numLen + ") or NUMSEX (" + numSex + ")");
|
|
||||||
|
if (numLen != 4) {
|
||||||
|
AddErrorMsg(msgs, offset, "NUMLEN must be 4, was " + numLen);
|
||||||
|
return ParseResult.Failure;
|
||||||
|
}
|
||||||
|
if (numSex != 0) {
|
||||||
|
AddErrorMsg(msgs, offset, "NUMSEX must be 0, was " + numSex);
|
||||||
return ParseResult.Failure;
|
return ParseResult.Failure;
|
||||||
}
|
}
|
||||||
if (offset + segLen > data.Length) {
|
if (offset + segLen > data.Length) {
|
||||||
// Segment is longer than the file. (This can happen easily in a static lib.)
|
// Segment is longer than the file. (This can happen easily in a static lib if
|
||||||
Debug.WriteLine("Segment exceeds EOF: offset=" + offset + " len=" + data.Length +
|
// we're not parsing it as such.)
|
||||||
" segLen=" + segLen);
|
AddErrorMsg(msgs, offset, "segment file length exceeds EOF (segLen=" + segLen +
|
||||||
|
", remaining=" + (data.Length - offset) + ")");
|
||||||
return ParseResult.Failure;
|
return ParseResult.Failure;
|
||||||
}
|
}
|
||||||
if (dispName < expectedDispName || dispName > (segLen - LOAD_NAME_LEN)) {
|
if (dispName < expectedDispName || dispName > (segLen - LOAD_NAME_LEN)) {
|
||||||
Debug.WriteLine("Invalid DISPNAME " + dispName + " segLen=" + segLen);
|
AddErrorMsg(msgs, offset, "invalid DISPNAME " + dispName + " (expected " +
|
||||||
|
expectedDispName + ", segLen=" + segLen + ")");
|
||||||
return ParseResult.Failure;
|
return ParseResult.Failure;
|
||||||
}
|
}
|
||||||
if (dispData < expectedDispName + LOAD_NAME_LEN || dispData > (segLen - 1)) {
|
if (dispData < expectedDispName + LOAD_NAME_LEN || dispData > (segLen - 1)) {
|
||||||
Debug.WriteLine("Invalid DISPDATA " + dispData + " segLen=" + segLen);
|
AddErrorMsg(msgs, offset, "invalid DISPDATA " + dispData + " (expected " +
|
||||||
|
(expectedDispName + LOAD_NAME_LEN) + ", segLen=" + segLen + ")");
|
||||||
return ParseResult.Failure;
|
return ParseResult.Failure;
|
||||||
}
|
}
|
||||||
if (newSeg.BankSize > 0x00010000) {
|
if (newSeg.BankSize > 0x00010000) {
|
||||||
Debug.WriteLine("Invalid BANKSIZE $" + newSeg.BankSize.ToString("x"));
|
AddErrorMsg(msgs, offset, "invalid BANKSIZE $" + newSeg.BankSize.ToString("x"));
|
||||||
return ParseResult.Failure;
|
return ParseResult.Failure;
|
||||||
}
|
}
|
||||||
if (newSeg.Align > 0x00010000) {
|
if (newSeg.Align > 0x00010000) {
|
||||||
Debug.WriteLine("Invalid ALIGN $" + newSeg.Align.ToString("x"));
|
AddErrorMsg(msgs, offset, "invalid ALIGN $" + newSeg.Align.ToString("x"));
|
||||||
return ParseResult.Failure;
|
return ParseResult.Failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newSeg.BankSize != 0x00010000 && newSeg.BankSize != 0) {
|
if (newSeg.BankSize != 0x00010000 && newSeg.BankSize != 0) {
|
||||||
// This is fine, just a little weird.
|
// This is fine, just a little weird.
|
||||||
Debug.WriteLine("Unusual BANKSIZE $" + newSeg.BankSize.ToString("x6"));
|
AddInfoMsg(msgs, offset, "unusual BANKSIZE $" + newSeg.BankSize.ToString("x6"));
|
||||||
}
|
}
|
||||||
if (newSeg.Align != 0 && newSeg.Align != 0x0100 && newSeg.Align != 0x00010000) {
|
if (newSeg.Align != 0 && newSeg.Align != 0x0100 && newSeg.Align != 0x00010000) {
|
||||||
// Unexpected; the loader will round up.
|
// Unexpected; the loader will round up.
|
||||||
Debug.WriteLine("Unusual ALIGN $" + newSeg.Align.ToString("x6"));
|
AddInfoMsg(msgs, offset, "unusual ALIGN $" + newSeg.Align.ToString("x6"));
|
||||||
}
|
}
|
||||||
if (newSeg.Entry != 0 && newSeg.Entry >= newSeg.Length) {
|
if (newSeg.Entry != 0 && newSeg.Entry >= newSeg.Length) {
|
||||||
// This is invalid, but if we got this far we might as well keep going.
|
// This is invalid, but if we got this far we might as well keep going.
|
||||||
Debug.WriteLine("Invalid ENTRY $" + newSeg.Entry.ToString("x6"));
|
AddInfoMsg(msgs, offset, "invalid ENTRY $" + newSeg.Entry.ToString("x6"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract LOADNAME. Fixed-width field, padded with spaces. Except for the
|
// Extract LOADNAME. Fixed-width field, padded with spaces. Except for the
|
||||||
@ -354,29 +391,110 @@ namespace SourceGen.Tools.Omf {
|
|||||||
// string preceded by length byte
|
// string preceded by length byte
|
||||||
int segNameLen = data[offset + segNameStart];
|
int segNameLen = data[offset + segNameStart];
|
||||||
if (segNameStart + 1 + segNameLen > segLen) {
|
if (segNameStart + 1 + segNameLen > segLen) {
|
||||||
Debug.WriteLine("Var-width SEGNAME ran off end of segment (len=" +
|
AddInfoMsg(msgs, offset, "var-width SEGNAME ran off end of segment (len=" +
|
||||||
segNameLen + ")");
|
segNameLen + ", segLen=" + segLen + ")");
|
||||||
return ParseResult.Failure;
|
return ParseResult.Failure;
|
||||||
}
|
}
|
||||||
segName = Encoding.ASCII.GetString(data, offset + segNameStart + 1, segNameLen);
|
segName = Encoding.ASCII.GetString(data, offset + segNameStart + 1, segNameLen);
|
||||||
} else {
|
} else {
|
||||||
// fixed-width string
|
// fixed-width string
|
||||||
if (segNameStart + newSeg.LabLen > segLen) {
|
if (segNameStart + newSeg.LabLen > segLen) {
|
||||||
Debug.WriteLine("Fixed-width SEGNAME ran off end of segment (len=" +
|
AddInfoMsg(msgs, offset, "fixed-width SEGNAME ran off end of segment (LABLEN=" +
|
||||||
newSeg.LabLen + ")");
|
newSeg.LabLen + ", segLen=" + segLen + ")");
|
||||||
return ParseResult.Failure;
|
return ParseResult.Failure;
|
||||||
}
|
}
|
||||||
segName = ExtractString(data, offset + segNameStart, newSeg.LabLen);
|
segName = ExtractString(data, offset + segNameStart, newSeg.LabLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.WriteLine("LOADNAME='" + loadName + "' SEGNAME='" + segName + "'");
|
//AddInfoMsg(msgs, offset, "GOT LOADNAME='" + loadName + "' SEGNAME='" + segName + "'");
|
||||||
|
|
||||||
newSeg.LoadName = loadName;
|
newSeg.LoadName = loadName;
|
||||||
newSeg.SegName = segName;
|
newSeg.SegName = segName;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Populate the "raw data" table. We add the fields shown in the specification in
|
||||||
|
// the order in which they appear.
|
||||||
|
//
|
||||||
|
|
||||||
|
if (newSeg.Version == SegmentVersion.v0_0 ||
|
||||||
|
(newSeg.Version == SegmentVersion.v1_0 && !parseAsLibrary)) {
|
||||||
|
newSeg.AddRaw("BLKCNT", blkByteCnt, 4, "blocks");
|
||||||
|
} else {
|
||||||
|
newSeg.AddRaw("BYTECNT", blkByteCnt, 4, "bytes");
|
||||||
|
}
|
||||||
|
newSeg.AddRaw("RESSPC", newSeg.ResSpc, 4, string.Empty);
|
||||||
|
newSeg.AddRaw("LENGTH", newSeg.Length, 4, string.Empty);
|
||||||
|
if (newSeg.Version <= SegmentVersion.v1_0) {
|
||||||
|
string attrStr = AttrsToString(newSeg.Attrs);
|
||||||
|
if (!string.IsNullOrEmpty(attrStr)) {
|
||||||
|
attrStr = " -" + attrStr;
|
||||||
|
}
|
||||||
|
newSeg.AddRaw("KIND", data[offset+0x0c], 1,
|
||||||
|
KindToString(newSeg.Kind) + attrStr);
|
||||||
|
} else {
|
||||||
|
newSeg.AddRaw("undefined", data[offset + 0x0c], 1, string.Empty);
|
||||||
|
}
|
||||||
|
newSeg.AddRaw("LABLEN", newSeg.LabLen, 1, string.Empty);
|
||||||
|
newSeg.AddRaw("NUMLEN", numLen, 1, "must be 4");
|
||||||
|
newSeg.AddRaw("VERSION", data[offset + 0x0f], 1, VersionToString(newSeg.Version));
|
||||||
|
newSeg.AddRaw("BANKSIZE", newSeg.BankSize, 4, string.Empty);
|
||||||
|
if (newSeg.Version >= SegmentVersion.v2_0) {
|
||||||
|
string attrStr = AttrsToString(newSeg.Attrs);
|
||||||
|
if (!string.IsNullOrEmpty(attrStr)) {
|
||||||
|
attrStr = " -" + attrStr;
|
||||||
|
}
|
||||||
|
newSeg.AddRaw("KIND", RawData.GetWord(data, offset + 0x14, 2, false), 2,
|
||||||
|
KindToString(newSeg.Kind) + attrStr);
|
||||||
|
newSeg.AddRaw("undefined", RawData.GetWord(data, offset + 0x16, 2, false), 2,
|
||||||
|
string.Empty);
|
||||||
|
} else {
|
||||||
|
newSeg.AddRaw("undefined", RawData.GetWord(data, offset + 0x14, 4, false), 4,
|
||||||
|
string.Empty);
|
||||||
|
}
|
||||||
|
newSeg.AddRaw("ORG", newSeg.Org, 4, string.Empty);
|
||||||
|
newSeg.AddRaw("ALIGN", newSeg.Align, 4, string.Empty);
|
||||||
|
newSeg.AddRaw("NUMSEX", numSex, 1, "must be 0");
|
||||||
|
if (newSeg.Version == SegmentVersion.v1_0) {
|
||||||
|
newSeg.AddRaw("LCBANK", newSeg.LcBank, 1, string.Empty);
|
||||||
|
} else {
|
||||||
|
newSeg.AddRaw("undefined", data[offset + 0x21], 1, string.Empty);
|
||||||
|
}
|
||||||
|
if (newSeg.Version >= SegmentVersion.v1_0) {
|
||||||
|
newSeg.AddRaw("SEGNUM", newSeg.SegNum, 2, string.Empty);
|
||||||
|
newSeg.AddRaw("ENTRY", newSeg.Entry, 4, string.Empty);
|
||||||
|
newSeg.AddRaw("DISPNAME", dispName, 2, string.Empty);
|
||||||
|
newSeg.AddRaw("DISPDATA", dispData, 2, string.Empty);
|
||||||
|
if (newSeg.Version >= SegmentVersion.v2_1) {
|
||||||
|
newSeg.AddRaw("tempORG", newSeg.TempOrg, 4, string.Empty);
|
||||||
|
}
|
||||||
|
newSeg.AddRaw("LOADNAME", loadName, 10, string.Empty);
|
||||||
|
}
|
||||||
|
newSeg.AddRaw("SEGNAME", segName, 0, string.Empty);
|
||||||
|
|
||||||
segResult = newSeg;
|
segResult = newSeg;
|
||||||
return ParseResult.Success;
|
return ParseResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Helper functions.
|
||||||
|
//
|
||||||
|
|
||||||
|
private void AddRaw(string name, object value, int width, string note) {
|
||||||
|
if (value is byte) {
|
||||||
|
value = (int)(byte)value;
|
||||||
|
}
|
||||||
|
RawValues.Add(new NameValueNote(name, value, width, note));
|
||||||
|
}
|
||||||
|
private static void AddInfoMsg(List<string> msgs, int offset, string msg) {
|
||||||
|
msgs.Add("Note (+" + offset.ToString("x6") + "): " + msg);
|
||||||
|
}
|
||||||
|
private static void AddErrorMsg(List<string> msgs, int offset, string msg) {
|
||||||
|
msgs.Add("Error (+" + offset.ToString("x6") + "): " + msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extracts a fixed-length ASCII string, stopping early if a '\0' is encountered.
|
||||||
|
/// </summary>
|
||||||
private static string ExtractString(byte[] data, int offset, int len) {
|
private static string ExtractString(byte[] data, int offset, int len) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (int i = offset; i < offset + len; i++) {
|
for (int i = offset; i < offset + len; i++) {
|
||||||
@ -388,5 +506,54 @@ namespace SourceGen.Tools.Omf {
|
|||||||
}
|
}
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a segment version to a human-readable string.
|
||||||
|
/// </summary>
|
||||||
|
public static string VersionToString(SegmentVersion vers) {
|
||||||
|
switch (vers) {
|
||||||
|
case SegmentVersion.v0_0: return "v0.0";
|
||||||
|
case SegmentVersion.v1_0: return "v1.0";
|
||||||
|
case SegmentVersion.v2_0: return "v2.0";
|
||||||
|
case SegmentVersion.v2_1: return "v2.1";
|
||||||
|
default: return "v?.?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a segment kind to a human-readable string.
|
||||||
|
/// </summary>
|
||||||
|
public static string KindToString(SegmentKind kind) {
|
||||||
|
switch (kind) {
|
||||||
|
case SegmentKind.Code: return "Code";
|
||||||
|
case SegmentKind.Data: return "Data";
|
||||||
|
case SegmentKind.JumpTable: return "Jump Table";
|
||||||
|
case SegmentKind.PathName: return "Pathname";
|
||||||
|
case SegmentKind.LibraryDict: return "Library Dict";
|
||||||
|
case SegmentKind.Init: return "Init";
|
||||||
|
case SegmentKind.AbsoluteBank: return "Abs Bank";
|
||||||
|
case SegmentKind.DpStack: return "DP/Stack";
|
||||||
|
default: return "???";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string AttrsToString(SegmentAttribute attrs) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
int bit = 1 << i;
|
||||||
|
if (((int)attrs & bit) != 0) {
|
||||||
|
SegmentAttribute attr = (SegmentAttribute)bit;
|
||||||
|
sb.Append(' ');
|
||||||
|
sb.Append(attr.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
return "[OmfSegment " + SegNum + " '" + LoadName + "' '" + SegName + "']";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
135
SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml
Normal file
135
SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
<!--
|
||||||
|
Copyright 2020 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.Omf.WpfGui.OmfSegmentViewer"
|
||||||
|
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.Omf.WpfGui"
|
||||||
|
xmlns:system="clr-namespace:System;assembly=mscorlib"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="OMF Segment Viewer"
|
||||||
|
SizeToContent="Height" Width="600" ResizeMode="NoResize"
|
||||||
|
ShowInTaskbar="False" WindowStartupLocation="CenterOwner">
|
||||||
|
|
||||||
|
<Window.Resources>
|
||||||
|
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||||
|
|
||||||
|
<system:String x:Key="str_FileOffsetLenFmt">File offset {0}, length {1} ({2})</system:String>
|
||||||
|
</Window.Resources>
|
||||||
|
|
||||||
|
<Grid Margin="8">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<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.Row="0" Text="{Binding FileOffsetLen, FallbackValue=File Offset / Length}" Margin="0,8,0,0"/>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1" Text="Header fields:" Margin="0,8,0,0"/>
|
||||||
|
<DataGrid Name="headerList" Grid.Row="2" Height="130" Margin="0,8,0,0"
|
||||||
|
IsReadOnly="True"
|
||||||
|
ItemsSource="{Binding HeaderItems}"
|
||||||
|
FontFamily="{StaticResource GeneralMonoFont}"
|
||||||
|
SnapsToDevicePixels="True"
|
||||||
|
GridLinesVisibility="Vertical"
|
||||||
|
VerticalGridLinesBrush="#FF7F7F7F"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
HeadersVisibility="Column"
|
||||||
|
CanUserReorderColumns="False"
|
||||||
|
CanUserSortColumns="False"
|
||||||
|
SelectionMode="Single">
|
||||||
|
<DataGrid.Resources>
|
||||||
|
<!-- make the no-focus color the same as the in-focus color -->
|
||||||
|
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}"
|
||||||
|
Color="{x:Static SystemColors.HighlightColor}"/>
|
||||||
|
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}"
|
||||||
|
Color="{x:Static SystemColors.HighlightTextColor}"/>
|
||||||
|
</DataGrid.Resources>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="Name" Width="100" Binding="{Binding Name}"/>
|
||||||
|
<DataGridTextColumn Header="Value" Width="120" Binding="{Binding Value}"/>
|
||||||
|
<DataGridTextColumn Header="Notes" Width="280" Binding="{Binding Note}"/>
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="3" Text="Records {N}:" Margin="0,8,0,0"/>
|
||||||
|
<DataGrid Name="recordList" Grid.Row="4" Height="130" Margin="0,8,0,0"
|
||||||
|
IsReadOnly="True"
|
||||||
|
ItemsSource="{Binding RecordItems}"
|
||||||
|
FontFamily="{StaticResource GeneralMonoFont}"
|
||||||
|
SnapsToDevicePixels="True"
|
||||||
|
GridLinesVisibility="Vertical"
|
||||||
|
VerticalGridLinesBrush="#FF7F7F7F"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
HeadersVisibility="Column"
|
||||||
|
CanUserReorderColumns="False"
|
||||||
|
CanUserSortColumns="False"
|
||||||
|
SelectionMode="Single">
|
||||||
|
<DataGrid.Resources>
|
||||||
|
<!-- make the no-focus color the same as the in-focus color -->
|
||||||
|
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}"
|
||||||
|
Color="{x:Static SystemColors.HighlightColor}"/>
|
||||||
|
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}"
|
||||||
|
Color="{x:Static SystemColors.HighlightTextColor}"/>
|
||||||
|
</DataGrid.Resources>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="Type" Width="100" Binding="{Binding Type}"/>
|
||||||
|
<DataGridTextColumn Header="Len" Width="40" Binding="{Binding Len}"/>
|
||||||
|
<DataGridTextColumn Header="Value" Width="300" Binding="{Binding Value}"/>
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="5" Text="Relocation table (for Load file segment):" Margin="0,8,0,0"/>
|
||||||
|
<DataGrid Name="relocList" Grid.Row="6" Height="130" Margin="0,8,0,0"
|
||||||
|
IsReadOnly="True"
|
||||||
|
ItemsSource="{Binding RelocItems}"
|
||||||
|
FontFamily="{StaticResource GeneralMonoFont}"
|
||||||
|
SnapsToDevicePixels="True"
|
||||||
|
GridLinesVisibility="Vertical"
|
||||||
|
VerticalGridLinesBrush="#FF7F7F7F"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
HeadersVisibility="Column"
|
||||||
|
CanUserReorderColumns="False"
|
||||||
|
CanUserSortColumns="False"
|
||||||
|
SelectionMode="Single">
|
||||||
|
<DataGrid.Resources>
|
||||||
|
<!-- make the no-focus color the same as the in-focus color -->
|
||||||
|
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}"
|
||||||
|
Color="{x:Static SystemColors.HighlightColor}"/>
|
||||||
|
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}"
|
||||||
|
Color="{x:Static SystemColors.HighlightTextColor}"/>
|
||||||
|
</DataGrid.Resources>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="Offset" Width="100" Binding="{Binding Offset}"/>
|
||||||
|
<DataGridTextColumn Header="Reference" Width="120" Binding="{Binding Reference}"/>
|
||||||
|
<DataGridTextColumn Header="Width" Width="100" Binding="{Binding Width}"/>
|
||||||
|
<DataGridTextColumn Header="Shift" Width="280" Binding="{Binding Shift}"/>
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
|
||||||
|
<DockPanel Grid.Row="7" LastChildFill="False" Margin="0,16,0,0">
|
||||||
|
<Button DockPanel.Dock="Right" Content="Done" Width="70" IsCancel="True"/>
|
||||||
|
</DockPanel>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
116
SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml.cs
Normal file
116
SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml.cs
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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.Runtime.CompilerServices;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
using Asm65;
|
||||||
|
|
||||||
|
namespace SourceGen.Tools.Omf.WpfGui {
|
||||||
|
/// <summary>
|
||||||
|
/// Apple IIgs OMF segment viewer.
|
||||||
|
/// </summary>
|
||||||
|
public partial class OmfSegmentViewer : Window, INotifyPropertyChanged {
|
||||||
|
private OmfFile mOmfFile;
|
||||||
|
private OmfSegment mOmfSeg;
|
||||||
|
private Formatter mFormatter;
|
||||||
|
|
||||||
|
// INotifyPropertyChanged implementation
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
private void OnPropertyChanged([CallerMemberName] string propertyName = "") {
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private string mFileOffsetLen;
|
||||||
|
public string FileOffsetLen {
|
||||||
|
get { return mFileOffsetLen; }
|
||||||
|
set { mFileOffsetLen = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HeaderItem {
|
||||||
|
public string Name { get; private set; }
|
||||||
|
public string Value { get; private set; }
|
||||||
|
public string Note { get; private set; }
|
||||||
|
|
||||||
|
public HeaderItem(string name, string value, string note) {
|
||||||
|
Name = name;
|
||||||
|
Value = value;
|
||||||
|
Note = note;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<HeaderItem> HeaderItems { get; private set; } = new List<HeaderItem>();
|
||||||
|
|
||||||
|
public class RecordItem {
|
||||||
|
public string Type { get; private set; }
|
||||||
|
public string Len { get; private set; }
|
||||||
|
public string Value { get; private set; }
|
||||||
|
}
|
||||||
|
public List<RecordItem> RecordItems { get; private set; } = new List<RecordItem>();
|
||||||
|
|
||||||
|
public class RelocItem {
|
||||||
|
public string Offset { get; private set; }
|
||||||
|
public string Reference { get; private set; }
|
||||||
|
public string Width { get; private set; }
|
||||||
|
public string Shift { get; private set; }
|
||||||
|
}
|
||||||
|
public List<RelocItem> RelocItems { get; private set; } = new List<RelocItem>();
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="owner">Parent window.</param>
|
||||||
|
/// <param name="omfFile">OMF file object.</param>
|
||||||
|
/// <param name="omfSeg">Segment to view. Must be part of omfFile.</param>
|
||||||
|
/// <param name="formatter">Text formatter.</param>
|
||||||
|
public OmfSegmentViewer(Window owner, OmfFile omfFile, OmfSegment omfSeg,
|
||||||
|
Formatter formatter) {
|
||||||
|
InitializeComponent();
|
||||||
|
Owner = owner;
|
||||||
|
DataContext = this;
|
||||||
|
|
||||||
|
mOmfFile = omfFile;
|
||||||
|
mOmfSeg = omfSeg;
|
||||||
|
mFormatter = formatter;
|
||||||
|
|
||||||
|
string fmt = (string)FindResource("str_FileOffsetLenFmt");
|
||||||
|
FileOffsetLen = string.Format(fmt,
|
||||||
|
mFormatter.FormatOffset24(omfSeg.FileOffset),
|
||||||
|
omfSeg.FileLength,
|
||||||
|
mFormatter.FormatHexValue(omfSeg.FileLength, 4));
|
||||||
|
|
||||||
|
GenerateHeaderItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateHeaderItems() {
|
||||||
|
foreach (OmfSegment.NameValueNote nvn in mOmfSeg.RawValues) {
|
||||||
|
string value;
|
||||||
|
if (nvn.Value is int) {
|
||||||
|
int byteWidth = nvn.Width;
|
||||||
|
if (byteWidth > 3) {
|
||||||
|
byteWidth = 3;
|
||||||
|
}
|
||||||
|
value = mFormatter.FormatHexValue((int)nvn.Value, byteWidth * 2);
|
||||||
|
} else {
|
||||||
|
value = nvn.Value.ToString();
|
||||||
|
}
|
||||||
|
HeaderItems.Add(new HeaderItem(nvn.Name, value, nvn.Note));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -41,12 +41,12 @@ limitations under the License.
|
|||||||
|
|
||||||
<DockPanel Grid.Row="0">
|
<DockPanel Grid.Row="0">
|
||||||
<TextBlock DockPanel.Dock="Left" Text="File:" Margin="0,1,0,0"/>
|
<TextBlock DockPanel.Dock="Left" Text="File:" Margin="0,1,0,0"/>
|
||||||
<TextBox DockPanel.Dock="Left" IsReadOnly="True" Margin="8,0,0,0" Text="C:\\File\Name\Here"/>
|
<TextBox DockPanel.Dock="Left" IsReadOnly="True" Margin="8,0,0,0" Text="{Binding PathName}"/>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
|
|
||||||
<TextBlock Grid.Row="1" Text="File is a {something}, with {N} segments" Margin="0,8,0,0"/>
|
<TextBlock Grid.Row="1" Text="File is a {something}, with {N} segments" Margin="0,8,0,0"/>
|
||||||
|
|
||||||
<DataGrid Name="segmentList" Grid.Row="2" Height="200" Margin="0,8,0,0"
|
<DataGrid Name="segmentList" Grid.Row="2" Height="210" Margin="0,8,0,0"
|
||||||
IsReadOnly="True"
|
IsReadOnly="True"
|
||||||
ItemsSource="{Binding SegmentListItems}"
|
ItemsSource="{Binding SegmentListItems}"
|
||||||
FontFamily="{StaticResource GeneralMonoFont}"
|
FontFamily="{StaticResource GeneralMonoFont}"
|
||||||
@ -67,17 +67,17 @@ limitations under the License.
|
|||||||
</DataGrid.Resources>
|
</DataGrid.Resources>
|
||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
<DataGridTextColumn Header="SEGNUM" Width="50" Binding="{Binding SegNum}"/>
|
<DataGridTextColumn Header="SEGNUM" Width="50" Binding="{Binding SegNum}"/>
|
||||||
<DataGridTextColumn Header="KIND" Width="80" Binding="{Binding Kind}"/>
|
<DataGridTextColumn Header="VER" Width="40" Binding="{Binding Version}"/>
|
||||||
<DataGridTextColumn Header="LOADNAME" Width="100" Binding="{Binding LoadName}"/>
|
<DataGridTextColumn Header="KIND" Width="100" Binding="{Binding Kind}"/>
|
||||||
<DataGridTextColumn Header="SEGNAME" Width="100" Binding="{Binding SegName}"/>
|
<DataGridTextColumn Header="LOADNAME" Width="80" Binding="{Binding LoadName}"/>
|
||||||
<DataGridTextColumn Header="LENGTH" Width="80" Binding="{Binding MemLength}"/>
|
<DataGridTextColumn Header="SEGNAME" Width="130" Binding="{Binding SegName}"/>
|
||||||
<DataGridTextColumn Header="File Length" Width="100" Binding="{Binding FileLength}"/>
|
<DataGridTextColumn Header="LENGTH" Width="80" Binding="{Binding Length}"/>
|
||||||
</DataGrid.Columns>
|
</DataGrid.Columns>
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
|
|
||||||
<TextBlock Grid.Row="3" Text="File notes:" Margin="0,8,0,0"/>
|
<TextBlock Grid.Row="3" Text="Notes and errors:" Margin="0,8,0,0"/>
|
||||||
<TextBox Grid.Row="4" Margin="0,4,0,0" Height="60"
|
<TextBox Grid.Row="4" Margin="0,4,0,0" Height="60"
|
||||||
Text="Test
stuff1
stuff2
stuff3"
|
Text="{Binding MessageStrings}"
|
||||||
IsReadOnly="True" VerticalScrollBarVisibility="Auto">
|
IsReadOnly="True" VerticalScrollBarVisibility="Auto">
|
||||||
</TextBox>
|
</TextBox>
|
||||||
|
|
||||||
|
@ -19,15 +19,19 @@ using System.ComponentModel;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
using Asm65;
|
||||||
|
|
||||||
namespace SourceGen.Tools.Omf.WpfGui {
|
namespace SourceGen.Tools.Omf.WpfGui {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Apple IIgs OMF file viewer.
|
/// Apple IIgs OMF file viewer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class OmfViewer : Window, INotifyPropertyChanged {
|
public partial class OmfViewer : Window, INotifyPropertyChanged {
|
||||||
private string mPathName;
|
|
||||||
private byte[] mFileData;
|
private byte[] mFileData;
|
||||||
|
private OmfFile mOmfFile;
|
||||||
|
private Formatter mFormatter;
|
||||||
|
|
||||||
//private Brush mDefaultLabelColor = SystemColors.WindowTextBrush;
|
//private Brush mDefaultLabelColor = SystemColors.WindowTextBrush;
|
||||||
|
|
||||||
@ -38,65 +42,81 @@ namespace SourceGen.Tools.Omf.WpfGui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class SegmentListItem {
|
public class SegmentListItem {
|
||||||
private OmfSegment mOmfSeg;
|
public OmfSegment OmfSeg { get; private set; }
|
||||||
|
|
||||||
public int SegNum {
|
public int SegNum {
|
||||||
get {
|
get { return OmfSeg.SegNum; }
|
||||||
return mOmfSeg.SegNum;
|
}
|
||||||
}
|
public string Version {
|
||||||
|
get { return OmfSegment.VersionToString(OmfSeg.Version); }
|
||||||
}
|
}
|
||||||
public string Kind {
|
public string Kind {
|
||||||
get {
|
get { return OmfSegment.KindToString(OmfSeg.Kind); }
|
||||||
return mOmfSeg.Kind.ToString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public string LoadName {
|
public string LoadName {
|
||||||
get {
|
get { return OmfSeg.LoadName; }
|
||||||
return mOmfSeg.LoadName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public string SegName {
|
public string SegName {
|
||||||
get {
|
get { return OmfSeg.SegName; }
|
||||||
return mOmfSeg.SegName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public int MemLength {
|
public int Length {
|
||||||
get {
|
get { return OmfSeg.Length; }
|
||||||
return mOmfSeg.Length;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public int FileLength {
|
public int FileLength {
|
||||||
get {
|
get { return OmfSeg.FileLength; }
|
||||||
return mOmfSeg.FileLength;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SegmentListItem(OmfSegment omfSeg) {
|
public SegmentListItem(OmfSegment omfSeg) {
|
||||||
mOmfSeg = omfSeg;
|
OmfSeg = omfSeg;
|
||||||
|
}
|
||||||
|
public override string ToString() {
|
||||||
|
return "[SegmentListItem " + OmfSeg + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SegmentListItem> SegmentListItems { get; private set; } = new List<SegmentListItem>();
|
public List<SegmentListItem> SegmentListItems { get; private set; } = new List<SegmentListItem>();
|
||||||
|
|
||||||
|
private string mPathName;
|
||||||
|
public string PathName {
|
||||||
|
get { return mPathName; }
|
||||||
|
set { mPathName = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
public OmfViewer(Window owner, string pathName, byte[] data) {
|
private string mMessageStrings;
|
||||||
|
public string MessageStrings {
|
||||||
|
get { return mMessageStrings; }
|
||||||
|
set { mMessageStrings = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="owner">Parent window.</param>
|
||||||
|
/// <param name="pathName">Path to file on disk. Only used for display.</param>
|
||||||
|
/// <param name="data">File contents.</param>
|
||||||
|
public OmfViewer(Window owner, string pathName, byte[] data, Formatter formatter) {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Owner = owner;
|
Owner = owner;
|
||||||
DataContext = this;
|
DataContext = this;
|
||||||
|
|
||||||
mPathName = pathName;
|
PathName = pathName;
|
||||||
mFileData = data;
|
mFileData = data;
|
||||||
|
mFormatter = formatter;
|
||||||
|
|
||||||
OmfFile omfFile = new OmfFile(data);
|
mOmfFile = new OmfFile(data);
|
||||||
omfFile.Analyze();
|
mOmfFile.Analyze();
|
||||||
|
|
||||||
foreach (OmfSegment omfSeg in omfFile.SegmentList) {
|
foreach (OmfSegment omfSeg in mOmfFile.SegmentList) {
|
||||||
SegmentListItems.Add(new SegmentListItem(omfSeg));
|
SegmentListItems.Add(new SegmentListItem(omfSeg));
|
||||||
}
|
}
|
||||||
|
MessageStrings = string.Join("\r\n", mOmfFile.MessageList.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SegmentList_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
|
private void SegmentList_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
|
||||||
Debug.WriteLine("DCLICK");
|
SegmentListItem item = (SegmentListItem)((DataGrid)sender).SelectedItem;
|
||||||
|
OmfSegmentViewer dlg = new OmfSegmentViewer(this, mOmfFile, item.OmfSeg, mFormatter);
|
||||||
|
dlg.ShowDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user