mirror of
https://github.com/fadden/6502bench.git
synced 2024-12-27 10:32:31 +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 Include="Helper.cs" />
|
||||
<Compile Include="InverseBooleanConverter.cs" />
|
||||
<Compile Include="ListToStringConverter.cs" />
|
||||
<Compile Include="MultiKeyInputGesture.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
<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 =
|
||||
new Tools.Omf.WpfGui.OmfViewer(this.mMainWin, pathName, fileData);
|
||||
new Tools.Omf.WpfGui.OmfViewer(this.mMainWin, pathName, fileData, mFormatter);
|
||||
ov.ShowDialog();
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,9 @@
|
||||
<Compile Include="Tools\ApplesoftToHtml.cs" />
|
||||
<Compile Include="Tools\Omf\OmfFile.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">
|
||||
<DependentUpon>OmfViewer.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@ -281,6 +284,10 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Tools\Omf\WpfGui\OmfSegmentViewer.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Tools\Omf\WpfGui\OmfViewer.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<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
|
||||
/// how the loader works (e.g. page 205).
|
||||
/// - "Undocumented Secrets of the Apple IIGS System Loader" by Neil Parker,
|
||||
/// http://nparker.llx.com/a2/loader.html . Among other things it documents ExpressLoad
|
||||
/// segments, something Apple apparently never did.
|
||||
/// http://nparker.llx.com/a2/loader.html . Among other things it documents the
|
||||
/// contents of ExpressLoad segments, which I haven't found in an official reference.
|
||||
/// - Apple IIgs Tech Note #66, "ExpressLoad Philosophy".
|
||||
///
|
||||
/// Related:
|
||||
@ -76,19 +76,20 @@ namespace SourceGen.Tools.Omf {
|
||||
Object, // output of assembler/compiler, before linking
|
||||
Library, // static code library
|
||||
RunTimeLibrary, // dynamic shared library
|
||||
Indeterminate, // valid OMF, but type is indeterminate
|
||||
Foreign // not OMF, or not IIgs OMF
|
||||
}
|
||||
public FileKind OmfFileKind { get; private set; }
|
||||
|
||||
private bool mIsDamaged;
|
||||
|
||||
private string mDamageMsg = string.Empty;
|
||||
|
||||
private List<OmfSegment> mSegmentList = new List<OmfSegment>();
|
||||
public List<OmfSegment> SegmentList {
|
||||
get { return mSegmentList; }
|
||||
}
|
||||
|
||||
public List<string> MessageList { get; private set; } = new List<string>();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
@ -105,7 +106,13 @@ namespace SourceGen.Tools.Omf {
|
||||
OmfSegment.ParseResult result = DoAnalyze(false);
|
||||
if (result == OmfSegment.ParseResult.IsLibrary ||
|
||||
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 len = mFileData.Length;
|
||||
|
||||
List<string> msgs = new List<string>();
|
||||
|
||||
while (len > 0) {
|
||||
OmfSegment.ParseResult result =
|
||||
OmfSegment.ParseSegment(mFileData, offset, parseAsLibrary, out OmfSegment seg);
|
||||
if (result == OmfSegment.ParseResult.Failure) {
|
||||
// parsing failed; reject file or stop early
|
||||
if (first) {
|
||||
OmfFileKind = FileKind.Foreign;
|
||||
} else {
|
||||
mIsDamaged = true;
|
||||
mDamageMsg = string.Format("File may be damaged; ignoring last {0} bytes",
|
||||
mFileData.Length - offset);
|
||||
}
|
||||
return result;
|
||||
} else if (result == OmfSegment.ParseResult.IsLibrary) {
|
||||
OmfSegment.ParseResult result = OmfSegment.ParseSegment(mFileData, offset,
|
||||
parseAsLibrary, msgs, out OmfSegment seg);
|
||||
|
||||
MessageList.Clear();
|
||||
foreach (string str in msgs) {
|
||||
MessageList.Add(str);
|
||||
}
|
||||
|
||||
if (result == OmfSegment.ParseResult.IsLibrary) {
|
||||
// Need to start over in library mode.
|
||||
Debug.WriteLine("Restarting in library mode");
|
||||
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);
|
||||
mSegmentList.Add(seg);
|
||||
|
@ -76,15 +76,23 @@ namespace SourceGen.Tools.Omf {
|
||||
private const int LOAD_NAME_LEN = 10;
|
||||
|
||||
public class NameValueNote {
|
||||
public string Name { get; set; }
|
||||
public object Value { get; set; }
|
||||
public string Note { get; set; }
|
||||
public string Name { get; private set; }
|
||||
public object Value { get; private 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>
|
||||
/// Values pulled from file header. Useful for display.
|
||||
/// </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 }
|
||||
|
||||
@ -107,9 +115,9 @@ namespace SourceGen.Tools.Omf {
|
||||
BankRel = 0x0100, // v2.1
|
||||
Skip = 0x0200, // v2.1
|
||||
Reloadable = 0x0400, // v2.0
|
||||
AbsoluteBank = 0x0800, // v2.0
|
||||
AbsBank = 0x0800, // v2.0
|
||||
NoSpecial = 0x1000, // v2.0
|
||||
PositionIndep = 0x2000, //
|
||||
PosnIndep = 0x2000, //
|
||||
Private = 0x4000, //
|
||||
Dynamic = 0x8000 //
|
||||
}
|
||||
@ -118,6 +126,7 @@ namespace SourceGen.Tools.Omf {
|
||||
// Header fields.
|
||||
//
|
||||
|
||||
public int FileOffset { get; private set; }
|
||||
public int FileLength { get; private set; } // from BLKCNT or BYTECNT
|
||||
public int ResSpc { get; private set; }
|
||||
public int Length { get; private set; }
|
||||
@ -155,19 +164,31 @@ namespace SourceGen.Tools.Omf {
|
||||
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,
|
||||
out OmfSegment segResult) {
|
||||
List<string> msgs, out OmfSegment segResult) {
|
||||
segResult = null;
|
||||
|
||||
//Debug.WriteLine("PARSE offset=" + offset);
|
||||
|
||||
Debug.Assert(offset < data.Length);
|
||||
if (data.Length - offset < MIN_HEADER_V0) {
|
||||
// Definitely too small.
|
||||
AddErrorMsg(msgs, offset, "remaining file space too small to hold segment");
|
||||
return ParseResult.Failure;
|
||||
}
|
||||
|
||||
//Debug.WriteLine("PARSE offset=" + offset);
|
||||
|
||||
OmfSegment newSeg = new OmfSegment();
|
||||
newSeg.FileOffset = offset;
|
||||
|
||||
// Start with the version number. The meaning of everything else depends on this.
|
||||
int minLen, expectedDispName;
|
||||
@ -189,10 +210,13 @@ namespace SourceGen.Tools.Omf {
|
||||
break;
|
||||
default:
|
||||
// invalid version, this is probably not OMF
|
||||
AddErrorMsg(msgs, offset, "invalid segment type " + data[offset + 0x0f]);
|
||||
return ParseResult.Failure;
|
||||
}
|
||||
if (data.Length - offset < minLen) {
|
||||
// Too small for this version of the header.
|
||||
AddErrorMsg(msgs, offset, "remaining file space too small to hold " +
|
||||
newSeg.Version + " segment");
|
||||
return ParseResult.Failure;
|
||||
}
|
||||
|
||||
@ -227,6 +251,8 @@ namespace SourceGen.Tools.Omf {
|
||||
expectedDispName += 4;
|
||||
|
||||
if (data.Length - offset < minLen + 4) {
|
||||
AddErrorMsg(msgs, offset, "remaining file space too small to hold " +
|
||||
newSeg.Version + " segment");
|
||||
return ParseResult.Failure;
|
||||
}
|
||||
newSeg.TempOrg = RawData.GetWord(data, offset + 0x2c, 4, false);
|
||||
@ -238,14 +264,14 @@ namespace SourceGen.Tools.Omf {
|
||||
kindByte = data[offset + 0x0c];
|
||||
if (!Enum.IsDefined(typeof(SegmentKind), kindByte & 0x1f)) {
|
||||
// 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;
|
||||
}
|
||||
newSeg.Kind = (SegmentKind)(kindByte & 0x1f);
|
||||
|
||||
int kindAttrs = 0;
|
||||
if ((kindByte & 0x20) != 0) {
|
||||
kindAttrs |= (int)SegmentAttribute.PositionIndep;
|
||||
kindAttrs |= (int)SegmentAttribute.PosnIndep;
|
||||
}
|
||||
if ((kindByte & 0x40) != 0) {
|
||||
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.
|
||||
kindWord = RawData.GetWord(data, offset + 0x14, 2, false);
|
||||
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;
|
||||
}
|
||||
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
|
||||
// file as a library, reject this and try again.
|
||||
if (newSeg.Kind == SegmentKind.LibraryDict && !parseAsLibrary) {
|
||||
AddInfoMsg(msgs, offset, "found Library Dictionary segment, retrying as library");
|
||||
return ParseResult.IsLibrary;
|
||||
}
|
||||
|
||||
@ -296,47 +323,57 @@ namespace SourceGen.Tools.Omf {
|
||||
}
|
||||
newSeg.FileLength = segLen;
|
||||
|
||||
//
|
||||
// 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
|
||||
// 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;
|
||||
}
|
||||
if (offset + segLen > data.Length) {
|
||||
// Segment is longer than the file. (This can happen easily in a static lib.)
|
||||
Debug.WriteLine("Segment exceeds EOF: offset=" + offset + " len=" + data.Length +
|
||||
" segLen=" + segLen);
|
||||
// Segment is longer than the file. (This can happen easily in a static lib if
|
||||
// we're not parsing it as such.)
|
||||
AddErrorMsg(msgs, offset, "segment file length exceeds EOF (segLen=" + segLen +
|
||||
", remaining=" + (data.Length - offset) + ")");
|
||||
return ParseResult.Failure;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (newSeg.BankSize > 0x00010000) {
|
||||
Debug.WriteLine("Invalid BANKSIZE $" + newSeg.BankSize.ToString("x"));
|
||||
AddErrorMsg(msgs, offset, "invalid BANKSIZE $" + newSeg.BankSize.ToString("x"));
|
||||
return ParseResult.Failure;
|
||||
}
|
||||
if (newSeg.Align > 0x00010000) {
|
||||
Debug.WriteLine("Invalid ALIGN $" + newSeg.Align.ToString("x"));
|
||||
AddErrorMsg(msgs, offset, "invalid ALIGN $" + newSeg.Align.ToString("x"));
|
||||
return ParseResult.Failure;
|
||||
}
|
||||
|
||||
if (newSeg.BankSize != 0x00010000 && newSeg.BankSize != 0) {
|
||||
// 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) {
|
||||
// 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) {
|
||||
// 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
|
||||
@ -354,29 +391,110 @@ namespace SourceGen.Tools.Omf {
|
||||
// string preceded by length byte
|
||||
int segNameLen = data[offset + segNameStart];
|
||||
if (segNameStart + 1 + segNameLen > segLen) {
|
||||
Debug.WriteLine("Var-width SEGNAME ran off end of segment (len=" +
|
||||
segNameLen + ")");
|
||||
AddInfoMsg(msgs, offset, "var-width SEGNAME ran off end of segment (len=" +
|
||||
segNameLen + ", segLen=" + segLen + ")");
|
||||
return ParseResult.Failure;
|
||||
}
|
||||
segName = Encoding.ASCII.GetString(data, offset + segNameStart + 1, segNameLen);
|
||||
} else {
|
||||
// fixed-width string
|
||||
if (segNameStart + newSeg.LabLen > segLen) {
|
||||
Debug.WriteLine("Fixed-width SEGNAME ran off end of segment (len=" +
|
||||
newSeg.LabLen + ")");
|
||||
AddInfoMsg(msgs, offset, "fixed-width SEGNAME ran off end of segment (LABLEN=" +
|
||||
newSeg.LabLen + ", segLen=" + segLen + ")");
|
||||
return ParseResult.Failure;
|
||||
}
|
||||
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.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;
|
||||
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) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = offset; i < offset + len; i++) {
|
||||
@ -388,5 +506,54 @@ namespace SourceGen.Tools.Omf {
|
||||
}
|
||||
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">
|
||||
<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>
|
||||
|
||||
<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"
|
||||
ItemsSource="{Binding SegmentListItems}"
|
||||
FontFamily="{StaticResource GeneralMonoFont}"
|
||||
@ -67,17 +67,17 @@ limitations under the License.
|
||||
</DataGrid.Resources>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="SEGNUM" Width="50" Binding="{Binding SegNum}"/>
|
||||
<DataGridTextColumn Header="KIND" Width="80" Binding="{Binding Kind}"/>
|
||||
<DataGridTextColumn Header="LOADNAME" Width="100" Binding="{Binding LoadName}"/>
|
||||
<DataGridTextColumn Header="SEGNAME" Width="100" Binding="{Binding SegName}"/>
|
||||
<DataGridTextColumn Header="LENGTH" Width="80" Binding="{Binding MemLength}"/>
|
||||
<DataGridTextColumn Header="File Length" Width="100" Binding="{Binding FileLength}"/>
|
||||
<DataGridTextColumn Header="VER" Width="40" Binding="{Binding Version}"/>
|
||||
<DataGridTextColumn Header="KIND" Width="100" Binding="{Binding Kind}"/>
|
||||
<DataGridTextColumn Header="LOADNAME" Width="80" Binding="{Binding LoadName}"/>
|
||||
<DataGridTextColumn Header="SEGNAME" Width="130" Binding="{Binding SegName}"/>
|
||||
<DataGridTextColumn Header="LENGTH" Width="80" Binding="{Binding Length}"/>
|
||||
</DataGrid.Columns>
|
||||
</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"
|
||||
Text="Test
stuff1
stuff2
stuff3"
|
||||
Text="{Binding MessageStrings}"
|
||||
IsReadOnly="True" VerticalScrollBarVisibility="Auto">
|
||||
</TextBox>
|
||||
|
||||
|
@ -19,15 +19,19 @@ using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
using Asm65;
|
||||
|
||||
namespace SourceGen.Tools.Omf.WpfGui {
|
||||
/// <summary>
|
||||
/// Apple IIgs OMF file viewer.
|
||||
/// </summary>
|
||||
public partial class OmfViewer : Window, INotifyPropertyChanged {
|
||||
private string mPathName;
|
||||
private byte[] mFileData;
|
||||
private OmfFile mOmfFile;
|
||||
private Formatter mFormatter;
|
||||
|
||||
//private Brush mDefaultLabelColor = SystemColors.WindowTextBrush;
|
||||
|
||||
@ -38,65 +42,81 @@ namespace SourceGen.Tools.Omf.WpfGui {
|
||||
}
|
||||
|
||||
public class SegmentListItem {
|
||||
private OmfSegment mOmfSeg;
|
||||
public OmfSegment OmfSeg { get; private set; }
|
||||
|
||||
public int SegNum {
|
||||
get {
|
||||
return mOmfSeg.SegNum;
|
||||
}
|
||||
get { return OmfSeg.SegNum; }
|
||||
}
|
||||
public string Version {
|
||||
get { return OmfSegment.VersionToString(OmfSeg.Version); }
|
||||
}
|
||||
public string Kind {
|
||||
get {
|
||||
return mOmfSeg.Kind.ToString();
|
||||
}
|
||||
get { return OmfSegment.KindToString(OmfSeg.Kind); }
|
||||
}
|
||||
public string LoadName {
|
||||
get {
|
||||
return mOmfSeg.LoadName;
|
||||
}
|
||||
get { return OmfSeg.LoadName; }
|
||||
}
|
||||
public string SegName {
|
||||
get {
|
||||
return mOmfSeg.SegName;
|
||||
}
|
||||
get { return OmfSeg.SegName; }
|
||||
}
|
||||
public int MemLength {
|
||||
get {
|
||||
return mOmfSeg.Length;
|
||||
}
|
||||
public int Length {
|
||||
get { return OmfSeg.Length; }
|
||||
}
|
||||
public int FileLength {
|
||||
get {
|
||||
return mOmfSeg.FileLength;
|
||||
}
|
||||
get { return OmfSeg.FileLength; }
|
||||
}
|
||||
|
||||
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>();
|
||||
|
||||
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();
|
||||
Owner = owner;
|
||||
DataContext = this;
|
||||
|
||||
mPathName = pathName;
|
||||
PathName = pathName;
|
||||
mFileData = data;
|
||||
mFormatter = formatter;
|
||||
|
||||
OmfFile omfFile = new OmfFile(data);
|
||||
omfFile.Analyze();
|
||||
mOmfFile = new OmfFile(data);
|
||||
mOmfFile.Analyze();
|
||||
|
||||
foreach (OmfSegment omfSeg in omfFile.SegmentList) {
|
||||
foreach (OmfSegment omfSeg in mOmfFile.SegmentList) {
|
||||
SegmentListItems.Add(new SegmentListItem(omfSeg));
|
||||
}
|
||||
MessageStrings = string.Join("\r\n", mOmfFile.MessageList.ToArray());
|
||||
}
|
||||
|
||||
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