From 24ae357a227976ffca59b4228b7ea746b1412231 Mon Sep 17 00:00:00 2001 From: Benjamin Popp Date: Thu, 1 Jul 2021 22:21:54 -0500 Subject: [PATCH] Fix Array-with-TableStream-pointer expansion When expanding and moving an ArrayRun that contains a pointer to table streams, the array needs to move, which means the table stream may temporarily have no pointers to the table. When the table re-adds itself on the other side, it's important that the table stream already know about the format of the parent table. For example, the length token may come from one of the parent element's fields. --- src/HexManiac.Core/Models/PokemonModel.cs | 2 +- src/HexManiac.Core/Models/Runs/ArrayRun.cs | 4 +++- .../Runs/Factory/TableStreamRunContentStrategy.cs | 2 +- src/HexManiac.Core/Models/Runs/TableStreamRun.cs | 12 ++++++++++-- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/HexManiac.Core/Models/PokemonModel.cs b/src/HexManiac.Core/Models/PokemonModel.cs index 387d7295..76e99495 100644 --- a/src/HexManiac.Core/Models/PokemonModel.cs +++ b/src/HexManiac.Core/Models/PokemonModel.cs @@ -440,7 +440,7 @@ namespace HavenSoft.HexManiac.Core.Models { Debug.Assert(run.Start == source, $"{runs[i].Start:X6}{pointerSourceName} expects a pointer at {source:X6}, but the next pointer was found at {run.Start:X6}."); Debug.Assert(ReadPointer(source) == runs[i].Start, $"Expected {source:X6} to point to {runs[i].Start:X6}{pointerSourceName}"); } else if (run is ITableRun) { - Debug.Assert(run.Start <= source); + Debug.Assert(run.Start <= source, $"The run at {runs[i].Start:X6} expects a pointer at {source:X6}, but found a table at {run.Start:X6}."); Debug.Assert(ReadPointer(source) == runs[i].Start); } else { Debug.Fail($"Pointer must be a {nameof(PointerRun)} or live within an {nameof(ITableRun)}"); diff --git a/src/HexManiac.Core/Models/Runs/ArrayRun.cs b/src/HexManiac.Core/Models/Runs/ArrayRun.cs index fe9c5f46..cf9ea78d 100644 --- a/src/HexManiac.Core/Models/Runs/ArrayRun.cs +++ b/src/HexManiac.Core/Models/Runs/ArrayRun.cs @@ -78,7 +78,9 @@ namespace HavenSoft.HexManiac.Core.Models.Runs { } else { IFormattedRun run = destinationRun; hasError = destinationRun.Start != destination; - if (currentSegment is ArrayRunPointerSegment pointerSegment) { + // if the run isn't a ITableRun, parse the data to see if it's valid + // if it _is_ an ITableRun, skip this step + if (currentSegment is ArrayRunPointerSegment pointerSegment && !(run is ITableRun)) { hasError |= FormatRunFactory.GetStrategy(pointerSegment.InnerFormat).TryParseData(data, string.Empty, destination, ref run).HasError; } } diff --git a/src/HexManiac.Core/Models/Runs/Factory/TableStreamRunContentStrategy.cs b/src/HexManiac.Core/Models/Runs/Factory/TableStreamRunContentStrategy.cs index 213a559b..c21f7e04 100644 --- a/src/HexManiac.Core/Models/Runs/Factory/TableStreamRunContentStrategy.cs +++ b/src/HexManiac.Core/Models/Runs/Factory/TableStreamRunContentStrategy.cs @@ -30,7 +30,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs.Factory { return tableStream.DeserializeRun("", token); } public override void UpdateNewRunFromPointerFormat(IDataModel model, ModelDelta token, string name, IReadOnlyList sourceSegments, int parentIndex, ref IFormattedRun run) { - if (!TableStreamRun.TryParseTableStream(model, run.Start, run.PointerSources, name, Format, null, out var runAttempt)) return; + if (!TableStreamRun.TryParseTableStream(model, run.Start, run.PointerSources, name, Format, sourceSegments, out var runAttempt)) return; model.ClearFormat(token, run.Start, runAttempt.Length); run = runAttempt; } diff --git a/src/HexManiac.Core/Models/Runs/TableStreamRun.cs b/src/HexManiac.Core/Models/Runs/TableStreamRun.cs index 969691b8..9dbb8d30 100644 --- a/src/HexManiac.Core/Models/Runs/TableStreamRun.cs +++ b/src/HexManiac.Core/Models/Runs/TableStreamRun.cs @@ -80,7 +80,14 @@ namespace HavenSoft.HexManiac.Core.Models.Runs { return null; } - public TableStreamRun(IDataModel model, int start, SortedSpan sources, string formatString, IReadOnlyList parsedSegments, IStreamEndStrategy endStream) : base(start, sources) { + public TableStreamRun( + IDataModel model, + int start, + SortedSpan sources, + string formatString, + IReadOnlyList parsedSegments, + IStreamEndStrategy endStream + ) : base(start, sources) { if (parsedSegments == null) parsedSegments = ArrayRun.ParseSegments(formatString.Substring(1, formatString.Length - 2), model); this.model = model; ElementContent = parsedSegments; @@ -121,7 +128,8 @@ namespace HavenSoft.HexManiac.Core.Models.Runs { return format; } - protected override BaseRun Clone(SortedSpan newPointerSources) => new TableStreamRun(model, Start, newPointerSources, FormatString, ElementContent, endStream); + protected override BaseRun Clone(SortedSpan newPointerSources) => + new TableStreamRun(model, Start, newPointerSources, FormatString, ElementContent, endStream); #endregion