From cf828d06f1bd2afad411f375d0735a4e0f249e2f Mon Sep 17 00:00:00 2001 From: Benjamin Popp Date: Tue, 12 Feb 2019 21:04:11 -0600 Subject: [PATCH] slight refactoring to prep for more array / pointer stuff. Added some insertion points as TODOs --- src/HexManiac.Core/Models/PokemonModel.cs | 23 ++++++++++----------- src/HexManiac.Core/Models/Runs/ArrayRun.cs | 24 ++++++++++++++-------- src/HexManiac.Core/ViewModels/ViewPort.cs | 1 + src/HexManiac.Tests/ArrayRunTests.cs | 4 ++-- 4 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/HexManiac.Core/Models/PokemonModel.cs b/src/HexManiac.Core/Models/PokemonModel.cs index 0686d651..738516c6 100644 --- a/src/HexManiac.Core/Models/PokemonModel.cs +++ b/src/HexManiac.Core/Models/PokemonModel.cs @@ -253,14 +253,6 @@ namespace HavenSoft.HexManiac.Core.Models { // replace / merge with existing // if the only thing changed was the anchor, then don't change the format, just merge the anchor var existingRun = runs[index]; - if (existingRun is PointerRun pointerRun1) { - if (ReadValue(pointerRun1.Start) == 0) { - var name = sourceToUnmappedName[pointerRun1.Start]; - sourceToUnmappedName.Remove(pointerRun1.Start); - unmappedNameToSources[name].Remove(pointerRun1.Start); - } - } - changeToken.RemoveRun(existingRun); run = run.MergeAnchor(existingRun.PointerSources); runs[index] = run; @@ -285,6 +277,8 @@ namespace HavenSoft.HexManiac.Core.Models { } } + // TODO if run is array run, look for pointers in the array to link + if (run is NoInfoRun && run.PointerSources.Count == 0 && !anchorForAddress.ContainsKey(run.Start)) { // this run has no useful information. Remove it. changeToken.RemoveRun(runs[index]); @@ -435,6 +429,8 @@ namespace HavenSoft.HexManiac.Core.Models { } ClearAnchorFormat(changeToken, originalStart, run); + // TODO if the run is an array run, look for pointers to unlink + if (alsoClearData) { for (int i = 0; i < run.Length; i++) changeToken.ChangeData(this, run.Start + i, 0xFF); } @@ -668,10 +664,13 @@ namespace HavenSoft.HexManiac.Core.Models { } else { return new ErrorInfo($"Ascii runs must include a length."); } - } else if (TryParse(model, format, dataIndex, null, out var arrayRun)) { - run = arrayRun; - } else if (format != string.Empty) { - return new ErrorInfo($"Format {format} was not understood."); + } else { + var errorInfo = TryParse(model, format, dataIndex, null, out var arrayRun); + if (errorInfo == ErrorInfo.NoError) { + run = arrayRun; + } else if (format != string.Empty) { + return new ErrorInfo($"Format {format} was not understood."); + } } return ErrorInfo.NoError; diff --git a/src/HexManiac.Core/Models/Runs/ArrayRun.cs b/src/HexManiac.Core/Models/Runs/ArrayRun.cs index fed24ff7..9529675c 100644 --- a/src/HexManiac.Core/Models/Runs/ArrayRun.cs +++ b/src/HexManiac.Core/Models/Runs/ArrayRun.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using System.Text; namespace HavenSoft.HexManiac.Core.Models.Runs { @@ -94,11 +95,11 @@ namespace HavenSoft.HexManiac.Core.Models.Runs { owner = data; FormatString = format; var closeArray = format.LastIndexOf(ArrayEnd.ToString()); - if (!format.StartsWith(ArrayStart.ToString()) || closeArray == -1) throw new FormatException($"Array Content must be wrapped in {ArrayStart}{ArrayEnd}."); + if (!format.StartsWith(ArrayStart.ToString()) || closeArray == -1) throw new ArrayRunParseException($"Array Content must be wrapped in {ArrayStart}{ArrayEnd}."); var segments = format.Substring(1, closeArray - 1); var length = format.Substring(closeArray + 1); ElementContent = ParseSegments(segments); - if (ElementContent.Count == 0) throw new FormatException("Array Content must not be empty."); + if (ElementContent.Count == 0) throw new ArrayRunParseException("Array Content must not be empty."); ElementLength = ElementContent.Sum(e => e.Length); if (length.Length == 0) { @@ -132,21 +133,21 @@ namespace HavenSoft.HexManiac.Core.Models.Runs { Length = ElementLength * ElementCount; } - public static bool TryParse(IDataModel data, string format, int start, IReadOnlyList pointerSources, out ArrayRun self) { + public static ErrorInfo TryParse(IDataModel data, string format, int start, IReadOnlyList pointerSources, out ArrayRun self) { try { self = new ArrayRun(data, format, start, pointerSources); - } catch { + } catch (ArrayRunParseException e) { self = null; - return false; + return new ErrorInfo(e.Message); } - return true; + return ErrorInfo.NoError; } public static bool TrySearch(IDataModel data, string format, out ArrayRun self) { self = null; var closeArray = format.LastIndexOf(ArrayEnd.ToString()); - if (!format.StartsWith(ArrayStart.ToString()) || closeArray == -1) throw new FormatException($"Array Content must be wrapped in {ArrayStart}{ArrayEnd}"); + if (!format.StartsWith(ArrayStart.ToString()) || closeArray == -1) throw new ArrayRunParseException($"Array Content must be wrapped in {ArrayStart}{ArrayEnd}"); var segments = format.Substring(1, closeArray - 1); var length = format.Substring(closeArray + 1); var elementContent = ParseSegments(segments); @@ -208,6 +209,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs { } if (currentSegment.Type == ElementContentType.Pointer) { + // TODO display the pointer in red if it points to outside the data var destination = data.ReadPointer(offsets.SegmentStart); var destinationName = data.GetAnchorFromAddress(offsets.SegmentStart, destination); return new Pointer(offsets.SegmentStart, index - offsets.SegmentStart, destination, destinationName); @@ -261,7 +263,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs { int nameEnd = 0; while (nameEnd < segments.Length && char.IsLetterOrDigit(segments[nameEnd])) nameEnd++; var name = segments.Substring(0, nameEnd); - if (name == string.Empty) throw new FormatException("expected name, but none was found: " + segments); + if (name == string.Empty) throw new ArrayRunParseException("expected name, but none was found: " + segments); segments = segments.Substring(nameEnd); var format = ElementContentType.Unknown; int formatLength = 0; @@ -283,7 +285,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs { (format, formatLength, segmentLength) = (ElementContentType.Pointer, 2, 4); } - if (format == ElementContentType.Unknown) throw new FormatException($"Could not parse format '{segments}'"); + if (format == ElementContentType.Unknown) throw new ArrayRunParseException($"Could not parse format '{segments}'"); segments = segments.Substring(formatLength).Trim(); list.Add(new ArrayRunElementSegment(name, format, segmentLength)); } @@ -339,4 +341,8 @@ namespace HavenSoft.HexManiac.Core.Models.Runs { } } } + + public class ArrayRunParseException : Exception { + public ArrayRunParseException(string message) : base(message) { } + } } diff --git a/src/HexManiac.Core/ViewModels/ViewPort.cs b/src/HexManiac.Core/ViewModels/ViewPort.cs index 9d0747af..0f9bac3e 100644 --- a/src/HexManiac.Core/ViewModels/ViewPort.cs +++ b/src/HexManiac.Core/ViewModels/ViewPort.cs @@ -971,6 +971,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels { if (fullValue == Pointer.NULL || (0 <= fullValue && fullValue < Model.Count)) { Model.WritePointer(history.CurrentChange, index, fullValue); if (!inArray) Model.ObserveRunWritten(history.CurrentChange, new PointerRun(index)); + // TODO do something amazing here... we don't need to observe the run being written, but there's still pointer updates to be done ClearEdits(point); SilentScroll(index + 4); } else { diff --git a/src/HexManiac.Tests/ArrayRunTests.cs b/src/HexManiac.Tests/ArrayRunTests.cs index 1b81e0b4..8e19dc00 100644 --- a/src/HexManiac.Tests/ArrayRunTests.cs +++ b/src/HexManiac.Tests/ArrayRunTests.cs @@ -28,9 +28,9 @@ namespace HavenSoft.HexManiac.Tests { [Fact] public void ArrayElementsMustHaveNames() { var model = new PokemonModel(new byte[0x200]); - var success = ArrayRun.TryParse(model, "[\"\"10]13", 12, null, out var arrayRun); // no name given for the format member + var errorInfo = ArrayRun.TryParse(model, "[\"\"10]13", 12, null, out var arrayRun); // no name given for the format member - Assert.False(success); + Assert.NotEqual(ErrorInfo.NoError, errorInfo); } [Fact]