Skip to content

Commit bba744e

Browse files
committed
Tidy up AstcDecoder and add more guards
1 parent d8535e5 commit bba744e

File tree

2 files changed

+372
-3
lines changed

2 files changed

+372
-3
lines changed

src/ImageSharp.Textures/TextureFormats/Decoding/AstcDecoder.cs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,30 @@ namespace SixLabors.ImageSharp.Textures.TextureFormats.Decoding;
1010
/// </summary>
1111
internal static class AstcDecoder
1212
{
13+
internal const int AstcBlockSize = 16;
14+
1315
/// <summary>
1416
/// Decodes an ASTC block into RGBA pixels.
1517
/// </summary>
1618
/// <param name="blockData">The 16-byte ASTC block data.</param>
1719
/// <param name="blockWidth">The width of the block footprint (4-12).</param>
1820
/// <param name="blockHeight">The height of the block footprint (4-12).</param>
1921
/// <param name="decodedPixels">The output span for decoded RGBA pixels.</param>
20-
/// <param name="isSrgb">Optional flag to indicate if the output should be in sRGB color space.</param>
22+
/// <exception cref="ArgumentException">Thrown if blockData is not 16 bytes or decodedPixels is the wrong size.</exception>
2123
/// <exception cref="ArgumentOutOfRangeException">Thrown if the block dimensions are invalid.</exception>
22-
public static void DecodeBlock(ReadOnlySpan<byte> blockData, int blockWidth, int blockHeight, Span<byte> decodedPixels, bool isSrgb = false)
24+
public static void DecodeBlock(ReadOnlySpan<byte> blockData, int blockWidth, int blockHeight, Span<byte> decodedPixels)
2325
{
26+
if (blockData.Length != AstcBlockSize)
27+
{
28+
throw new ArgumentException($"ASTC block data must be exactly {AstcBlockSize} bytes. Received {blockData.Length} bytes.", nameof(blockData));
29+
}
30+
31+
int expectedDecodedSize = blockWidth * blockHeight * 4;
32+
if (decodedPixels.Length < expectedDecodedSize)
33+
{
34+
throw new ArgumentException($"Output buffer must be at least {expectedDecodedSize} bytes for {blockWidth}x{blockHeight} block. Received {decodedPixels.Length} bytes.", nameof(decodedPixels));
35+
}
36+
2437
Footprint footprint = Footprint.FromFootprintType(FootprintFromDimensions(blockWidth, blockHeight));
2538

2639
AstcSharp.AstcDecoder.DecompressBlock(blockData, footprint, decodedPixels);
@@ -36,6 +49,9 @@ public static void DecodeBlock(ReadOnlySpan<byte> blockData, int blockWidth, int
3649
/// <param name="blockHeight">The height of the block footprint.</param>
3750
/// <param name="compressedBytesPerBlock">The number of compressed bytes per block.</param>
3851
/// <returns>The decompressed RGBA pixel data.</returns>
52+
/// <exception cref="ArgumentNullException">Thrown if blockData is null.</exception>
53+
/// <exception cref="ArgumentOutOfRangeException">Thrown if dimensions or block parameters are invalid.</exception>
54+
/// <exception cref="ArgumentException">Thrown if blockData length is invalid.</exception>
3955
public static byte[] DecompressImage(
4056
byte[] blockData,
4157
int width,
@@ -44,8 +60,28 @@ public static byte[] DecompressImage(
4460
int blockHeight,
4561
byte compressedBytesPerBlock)
4662
{
63+
ArgumentNullException.ThrowIfNull(blockData);
64+
ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(0, width);
65+
ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(0, height);
66+
67+
if (compressedBytesPerBlock != AstcBlockSize)
68+
{
69+
throw new ArgumentOutOfRangeException(nameof(compressedBytesPerBlock), compressedBytesPerBlock, $"ASTC blocks must be {AstcBlockSize} bytes.");
70+
}
71+
72+
// Validate block dimensions (will throw if invalid)
73+
_ = FootprintFromDimensions(blockWidth, blockHeight);
74+
4775
int blocksWide = (width + blockWidth - 1) / blockWidth;
4876
int blocksHigh = (height + blockHeight - 1) / blockHeight;
77+
int totalBlocks = blocksWide * blocksHigh;
78+
int expectedDataLength = totalBlocks * compressedBytesPerBlock;
79+
80+
if (blockData.Length < expectedDataLength)
81+
{
82+
throw new ArgumentException($"Block data is too small. Expected at least {expectedDataLength} bytes for {width}x{height} texture with {blockWidth}x{blockHeight} blocks, but received {blockData.Length} bytes.", nameof(blockData));
83+
}
84+
4985
byte[] decompressedData = new byte[width * height * 4];
5086
byte[] decodedBlock = new byte[blockWidth * blockHeight * 4];
5187

@@ -105,6 +141,6 @@ private static FootprintType FootprintFromDimensions(int width, int height)
105141
(10, 10) => FootprintType.Footprint10x10,
106142
(12, 10) => FootprintType.Footprint12x10,
107143
(12, 12) => FootprintType.Footprint12x12,
108-
_ => throw new ArgumentOutOfRangeException(nameof(width), "Invalid footprint type."),
144+
_ => throw new ArgumentOutOfRangeException(nameof(width), $"Invalid ASTC block dimensions: {width}x{height}. Valid sizes are 4x4, 5x4, 5x5, 6x5, 6x6, 8x5, 8x6, 8x8, 10x5, 10x6, 10x8, 10x10, 12x10, 12x12."),
109145
};
110146
}

0 commit comments

Comments
 (0)