diff --git a/src/HexManiac.Core/Models/PokemonModel.cs b/src/HexManiac.Core/Models/PokemonModel.cs index 05dfb866..e5e5fe07 100644 --- a/src/HexManiac.Core/Models/PokemonModel.cs +++ b/src/HexManiac.Core/Models/PokemonModel.cs @@ -1391,7 +1391,7 @@ namespace HavenSoft.HexManiac.Core.Models { } public override void ObserveAnchorWritten(ModelDelta changeToken, string anchorName, IFormattedRun run) { - Debug.Assert(run.Length > 0); // writing an anchor of length zero is stupid. + Debug.Assert(run.Length > 0, $"Trying to write a run of length zero! {run.FormatString} at {run.Start:X6}"); // writing an anchor of length zero is stupid. lock (threadlock) { int location = run.Start; var index = BinarySearch(location); diff --git a/src/HexManiac.Core/Models/Runs/Factory/LzSpriteRunContentStrategy.cs b/src/HexManiac.Core/Models/Runs/Factory/LzSpriteRunContentStrategy.cs index 1e381668..d1255ebe 100644 --- a/src/HexManiac.Core/Models/Runs/Factory/LzSpriteRunContentStrategy.cs +++ b/src/HexManiac.Core/Models/Runs/Factory/LzSpriteRunContentStrategy.cs @@ -44,7 +44,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs.Factory { } } public override ErrorInfo TryParseData(IDataModel model, string name, int dataIndex, ref IFormattedRun run) { - var error = SpriteRunContentStrategy.IsValid(spriteFormat.BitsPerPixel); + var error = SpriteRunContentStrategy.IsValid(spriteFormat); if (error.HasError) return error; run = new LzSpriteRun(spriteFormat, model, dataIndex, run.PointerSources); if (run.Length == LZRun.DecompressedTooLong) return new ErrorInfo("Decompressed more bytes than expected. Add a ! to override this."); diff --git a/src/HexManiac.Core/Models/Runs/Factory/LzTilemapRunContentStrategy.cs b/src/HexManiac.Core/Models/Runs/Factory/LzTilemapRunContentStrategy.cs index a8270fd3..5c0b2401 100644 --- a/src/HexManiac.Core/Models/Runs/Factory/LzTilemapRunContentStrategy.cs +++ b/src/HexManiac.Core/Models/Runs/Factory/LzTilemapRunContentStrategy.cs @@ -22,7 +22,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs.Factory { } public override ErrorInfo TryParseData(IDataModel model, string name, int dataIndex, ref IFormattedRun run) { - var error = SpriteRunContentStrategy.IsValid(TilemapFormat.BitsPerPixel); + var error = SpriteRunContentStrategy.IsValid(TilemapFormat); if (error.HasError) return error; var lzRun = new LZRun(model, dataIndex); var rowRemainder = lzRun.DecompressedLength % TilemapFormat.TileWidth; diff --git a/src/HexManiac.Core/Models/Runs/Factory/LzTilesetRunContentStrategy.cs b/src/HexManiac.Core/Models/Runs/Factory/LzTilesetRunContentStrategy.cs index 87affcdc..ed50738f 100644 --- a/src/HexManiac.Core/Models/Runs/Factory/LzTilesetRunContentStrategy.cs +++ b/src/HexManiac.Core/Models/Runs/Factory/LzTilesetRunContentStrategy.cs @@ -23,7 +23,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs.Factory { } public override ErrorInfo TryParseData(IDataModel model, string name, int dataIndex, ref IFormattedRun run) { - var error = SpriteRunContentStrategy.IsValid(TilesetFormat.BitsPerPixel); + var error = SpriteRunContentStrategy.IsValid(TilesetFormat); if (error.HasError) return error; var lzRun = new LzTilesetRun(TilesetFormat, model, dataIndex); if (lzRun.Length == LZRun.DecompressedTooLong) return new ErrorInfo("Decompressed more bytes than expected. Add a ! to override this."); diff --git a/src/HexManiac.Core/Models/Runs/Factory/SpriteRunContentStrategy.cs b/src/HexManiac.Core/Models/Runs/Factory/SpriteRunContentStrategy.cs index ccb07705..5b445e4f 100644 --- a/src/HexManiac.Core/Models/Runs/Factory/SpriteRunContentStrategy.cs +++ b/src/HexManiac.Core/Models/Runs/Factory/SpriteRunContentStrategy.cs @@ -36,17 +36,37 @@ namespace HavenSoft.HexManiac.Core.Models.Runs.Factory { } } public override ErrorInfo TryParseData(IDataModel model, string name, int dataIndex, ref IFormattedRun run) { - var error = IsValid(spriteFormat.BitsPerPixel); + var error = IsValid(spriteFormat); if (error.HasError) return error; run = new SpriteRun(model, dataIndex, spriteFormat, run.PointerSources); return ErrorInfo.NoError; } - public static ErrorInfo IsValid(int bitsPerPixel) { - if (!new[] { 1, 2, 4, 8 }.Contains(bitsPerPixel)) { + public static ErrorInfo IsValid(TilemapFormat format) { + if (!format.BitsPerPixel.IsAny(1, 2, 4, 8)) { return new ErrorInfo("Sprite bpp must be 1, 2, 4, or 8."); } return ErrorInfo.NoError; } + + public static ErrorInfo IsValid(TilesetFormat format) { + if (!format.BitsPerPixel.IsAny(1, 2, 4, 8)) { + return new ErrorInfo("Sprite bpp must be 1, 2, 4, or 8."); + } + if (format.MaxTiles == 0 || format.Tiles == 0) { + return new ErrorInfo("Tilesets must have at least 1 tile."); + } + return ErrorInfo.NoError; + } + + public static ErrorInfo IsValid(SpriteFormat format) { + if (!format.BitsPerPixel.IsAny(1, 2, 4, 8)) { + return new ErrorInfo("Sprite bpp must be 1, 2, 4, or 8."); + } + if (format.ExpectedByteLength <= 0) { + return new ErrorInfo("Sprite width/height must positive."); + } + return ErrorInfo.NoError; + } } } diff --git a/src/HexManiac.Core/Models/Runs/Factory/TilemapRunContentStrategy.cs b/src/HexManiac.Core/Models/Runs/Factory/TilemapRunContentStrategy.cs index a00ad297..15113314 100644 --- a/src/HexManiac.Core/Models/Runs/Factory/TilemapRunContentStrategy.cs +++ b/src/HexManiac.Core/Models/Runs/Factory/TilemapRunContentStrategy.cs @@ -28,7 +28,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs.Factory { } public override ErrorInfo TryParseData(IDataModel model, string name, int dataIndex, ref IFormattedRun run) { - var error = SpriteRunContentStrategy.IsValid(format.BitsPerPixel); + var error = SpriteRunContentStrategy.IsValid(format); if (error.HasError) return error; var newRun = new TilemapRun(model, dataIndex, format); run = newRun; diff --git a/src/HexManiac.Core/Models/Runs/Factory/TilesetRunContentStrategy.cs b/src/HexManiac.Core/Models/Runs/Factory/TilesetRunContentStrategy.cs index 393e0b55..688ea675 100644 --- a/src/HexManiac.Core/Models/Runs/Factory/TilesetRunContentStrategy.cs +++ b/src/HexManiac.Core/Models/Runs/Factory/TilesetRunContentStrategy.cs @@ -31,7 +31,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs.Factory { } public override ErrorInfo TryParseData(IDataModel model, string name, int dataIndex, ref IFormattedRun run) { - var error = SpriteRunContentStrategy.IsValid(TilesetFormat.BitsPerPixel); + var error = SpriteRunContentStrategy.IsValid(TilesetFormat); if (error.HasError) return error; var newRun = new TilesetRun(TilesetFormat, model, run.Start, run.PointerSources); var nextRun = model.GetNextRun(run.Start + 1); diff --git a/src/HexManiac.Tests/ImageTests.cs b/src/HexManiac.Tests/ImageTests.cs index 805a892a..9f7b2026 100644 --- a/src/HexManiac.Tests/ImageTests.cs +++ b/src/HexManiac.Tests/ImageTests.cs @@ -882,6 +882,19 @@ namespace HavenSoft.HexManiac.Tests { Assert.Equal("Decompressed more bytes than expected. Add a ! to override this.", Errors[0]); } + [Theory] + [InlineData("`ucs4x0x1`")] + [InlineData("`ucs4x1x0`")] + [InlineData("`uct4x0`")] + [InlineData("`lzs4x0x1`")] + [InlineData("`lzs4x1x0`")] + [InlineData("`lzt4x0`")] + public void ImageFormatWithZeroDimensionErrors(string format) { + WriteCompressedData(0, 0x20); + ViewPort.Edit($"^image{format} "); + Assert.Single(Errors); + } + private void WriteCompressedData(int start, int length) { var compressedData = LZRun.Compress(new byte[length], 0, length); for (int i = 0; i < compressedData.Count; i++) Model[start + i] = compressedData[i];