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();