From b8f4094a77ff077b8bcf616e8fadd25693abe689 Mon Sep 17 00:00:00 2001
From: winscripter <142818255+winscripter@users.noreply.github.com>
Date: Tue, 25 Aug 2026 00:12:11 +0400
Subject: [PATCH] Reduce errors
---
.../Formats/Jxl/Fields/JxlReadVisitor.cs | 12 ----
.../Jxl/Processing/Decoder/JxlBitReader.cs | 65 +++++++++----------
.../Jxl/Processing/Decoder/JxlDecoderCore.cs | 15 ++---
3 files changed, 36 insertions(+), 56 deletions(-)
diff --git a/src/ImageSharp/Formats/Jxl/Fields/JxlReadVisitor.cs b/src/ImageSharp/Formats/Jxl/Fields/JxlReadVisitor.cs
index c60e5985e..d54dba670 100644
--- a/src/ImageSharp/Formats/Jxl/Fields/JxlReadVisitor.cs
+++ b/src/ImageSharp/Formats/Jxl/Fields/JxlReadVisitor.cs
@@ -116,18 +116,6 @@ internal sealed class JxlReadVisitor(JxlBitReader reader) : JxlVisitorBase
reader.SkipBits64((uint)remainingBits);
}
- return this.ThrowIfEndOfStreamOrReturnTrue();
- }
-
- private bool ThrowIfEndOfStreamOrReturnTrue()
- {
- if (reader.IsEndOfStream)
- {
- DebugGuard.IsTrue(false, "Got an invalid end-of-stream");
- this.notEnoughBytes = true;
- return true;
- }
-
return true;
}
}
diff --git a/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlBitReader.cs b/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlBitReader.cs
index 9dbc090ae..33b7307d3 100644
--- a/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlBitReader.cs
+++ b/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlBitReader.cs
@@ -8,56 +8,61 @@ namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder;
///
/// Represents a bitstream reader.
///
-internal ref struct JxlBitReader(ReadOnlySpan bytes)
+internal sealed class JxlBitReader(Stream stream)
{
- private readonly ReadOnlySpan data = bytes;
-
private ulong buffer;
private uint bufferRemainingBits;
private int pointer;
- ///
- /// Gets a value indicating whether this marks an end of stream.
- ///
- public bool IsEndOfStream { get; private set; }
-
///
/// Gets the total number of bits consumed.
///
- public readonly long TotalBitsConsumed => ((long)this.pointer * 8) + (64 - this.bufferRemainingBits);
+ public long TotalBitsConsumed => ((long)this.pointer * 8) + (64 - this.bufferRemainingBits);
///
/// Fetches a new buffer.
///
private void RefillCore()
{
- int remaining = this.data.Length - this.pointer;
- if (remaining <= 0)
- {
- // we don't have any more data... mark an end of stream
- this.buffer = 0;
- this.bufferRemainingBits = 0;
- this.IsEndOfStream = true;
- return;
- }
-
- if (remaining >= 8)
+ Span temp = stackalloc byte[8];
+ int bytesRead = stream.Read(temp);
+ if (bytesRead == 8)
{
- this.buffer = BinaryPrimitives.ReadUInt64LittleEndian(this.data[this.pointer..]);
+ this.buffer = BinaryPrimitives.ReadUInt64LittleEndian(temp);
this.bufferRemainingBits = 64u;
this.pointer += 8;
}
else
{
+ if (bytesRead == 0)
+ {
+ throw new EndOfStreamException();
+ }
+
ulong value = 0;
- for (int i = 0; i < remaining; i++)
+ for (int i = 0; i < bytesRead; i++)
{
- value |= (ulong)this.data[this.pointer + i] << (8 * i);
+ value |= (ulong)temp[i] << (8 * i);
}
this.buffer = value;
- this.bufferRemainingBits = (uint)(remaining * 8);
- this.pointer += remaining;
+ this.bufferRemainingBits = (uint)(bytesRead * 8);
+ this.pointer += bytesRead;
+ }
+ }
+
+ public void JumpToByteBoundary()
+ {
+ uint remainder = (uint)(this.TotalBitsConsumed % 8);
+
+ if (remainder == 0)
+ {
+ return;
+ }
+
+ if (this.ReadBits32(8u - remainder) != 0)
+ {
+ throw new InvalidDataException("Non-zero padding bits");
}
}
@@ -74,11 +79,6 @@ internal ref struct JxlBitReader(ReadOnlySpan bytes)
DebugGuard.MustBeLessThanOrEqualTo(n, 64u, nameof(n));
this.MaybeRefill();
- if (this.IsEndOfStream)
- {
- JxlThrowHelper.ThrowEndOfStream();
- }
-
if (n <= this.bufferRemainingBits)
{
ulong result = this.buffer & ((1UL << (int)n) - 1);
@@ -119,11 +119,6 @@ internal ref struct JxlBitReader(ReadOnlySpan bytes)
DebugGuard.MustBeLessThanOrEqualTo(n, 32u, nameof(n));
this.MaybeRefill();
- if (this.IsEndOfStream)
- {
- JxlThrowHelper.ThrowEndOfStream();
- }
-
if (n <= this.bufferRemainingBits)
{
uint result = (uint)(this.buffer & ((1UL << (int)n) - 1));
diff --git a/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlDecoderCore.cs b/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlDecoderCore.cs
index 0287760e4..0fe20686a 100644
--- a/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlDecoderCore.cs
@@ -1753,11 +1753,6 @@ internal sealed class JxlDecoderCore : ImageDecoderCore, IDisposable
this.frameDecoder.InitializeFrame(reader, this.imageBundle!, this.previewFrame);
- if (!reader.AllReadsWithinBounds)
- {
- return this.TryRequestMoreInput() ? 1 : 0;
- }
-
this.AdvanceCodeStream(reader.TotalBitsConsumed / JxlMath.BitsPerByte);
this.frameHeader = this.frameDecoder.GetFrameHeader();
@@ -2701,13 +2696,13 @@ internal sealed class JxlDecoderCore : ImageDecoderCore, IDisposable
if (!this.gotSignature)
{
- JxlSignatureCheck status = CheckSignature(this.nextInput, this.availableInput);
- if (status == JxlSignatureCheck.InvalidSignature)
+ JxlSignature signature = DetectSignature(this.nextInput, this.availableInput);
+ if (signature == JxlSignature.Invalid)
{
throw new InvalidOperationException("The signature is invalid.");
}
- if (status == JxlSignatureCheck.NotEnoughBytes)
+ if (signature == JxlSignature.NotEnoughBytes)
{
if (this.inputClosed)
{
@@ -2719,7 +2714,7 @@ internal sealed class JxlDecoderCore : ImageDecoderCore, IDisposable
this.gotSignature = true;
- if (status == JxlSignatureCheck.Container)
+ if (signature == JxlSignature.Container)
{
this.haveContainer = true;
}
@@ -2750,6 +2745,8 @@ internal sealed class JxlDecoderCore : ImageDecoderCore, IDisposable
}
}
+ private static void ThrowNotEnoughData() => throw new InvalidOperationException("Not enough data");
+
protected override Image Decode(BufferedReadStream stream, CancellationToken cancellationToken) => throw new NotImplementedException();
protected override ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken) => throw new NotImplementedException();