mirror of https://github.com/SixLabors/ImageSharp
2 changed files with 113 additions and 5 deletions
@ -0,0 +1,108 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Buffers; |
|||
using System.IO.Compression; |
|||
using SixLabors.ImageSharp.Formats.Jxl.IO; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder; |
|||
|
|||
/// <summary>
|
|||
/// Allows decoding and decompressing box data.
|
|||
/// </summary>
|
|||
internal sealed class JxlBoxContentDecoder |
|||
{ |
|||
/// <summary>
|
|||
/// Specifies how many bytes to read to fetch box data. This is ignored
|
|||
/// if the box extends till EOF.
|
|||
/// </summary>
|
|||
private ulong boxSize; |
|||
|
|||
/// <summary>
|
|||
/// When true the box size is ignored and is unbounded - that is, keeps going
|
|||
/// till the end of the file or stream.
|
|||
/// </summary>
|
|||
private bool boxExtendsTillEnd; |
|||
|
|||
/// <summary>
|
|||
/// This contains flags that determine whether the box is Brotli-compressed or
|
|||
/// not.
|
|||
/// </summary>
|
|||
private JxlBoxCodingMode codingMode; |
|||
|
|||
/// <summary>
|
|||
/// Prepares parsing the box.
|
|||
/// </summary>
|
|||
/// <param name="codingMode">Specifies box compression.</param>
|
|||
/// <param name="isUnbounded">Specifies whether or not the box size keeps going till the end of stream.</param>
|
|||
/// <param name="size">Specifies the fixed size of the box when it is not unbounded.</param>
|
|||
public void Initialize(JxlBoxCodingMode codingMode, bool isUnbounded, ulong size) |
|||
{ |
|||
this.boxSize = size; |
|||
this.codingMode = codingMode; |
|||
this.boxExtendsTillEnd = isUnbounded; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Prepares parsing the box.
|
|||
/// </summary>
|
|||
/// <param name="isBrotliCompressed">True if the box is compressed with Brotli. If uncompressed - false.</param>
|
|||
/// <param name="isUnbounded">Specifies whether or not the box size keeps going till the end of stream.</param>
|
|||
/// <param name="size">Specifies the fixed size of the box when it is not unbounded.</param>
|
|||
public void Initialize(bool isBrotliCompressed, bool isUnbounded, ulong size) |
|||
=> this.Initialize( |
|||
isBrotliCompressed ? JxlBoxCodingMode.Brotli : JxlBoxCodingMode.Uncompressed, |
|||
isUnbounded, |
|||
size); |
|||
|
|||
public void Process(Stream stream, JxlMemoryWriter writer) |
|||
{ |
|||
byte[] cache = ArrayPool<byte>.Shared.Rent(16384); |
|||
|
|||
try |
|||
{ |
|||
if (this.codingMode == JxlBoxCodingMode.Brotli) |
|||
{ |
|||
using BrotliStream brotli = new(stream, CompressionMode.Decompress, leaveOpen: true); |
|||
|
|||
int bytesRead; |
|||
while ((bytesRead = brotli.Read(cache, 0, cache.Length)) > 0) |
|||
{ |
|||
writer.Write(cache.AsSpan(0, bytesRead)); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
if (this.boxExtendsTillEnd) |
|||
{ |
|||
int bytesRead; |
|||
while ((bytesRead = stream.Read(cache, 0, cache.Length)) > 0) |
|||
{ |
|||
writer.Write(cache.AsSpan(0, bytesRead)); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
ulong bytesLeft = this.boxSize; |
|||
while (bytesLeft > 0) |
|||
{ |
|||
int toRead = (int)Math.Min((ulong)cache.Length, bytesLeft); |
|||
int bytesRead = stream.Read(cache, 0, toRead); |
|||
|
|||
if (bytesRead == 0) |
|||
{ |
|||
throw new EndOfStreamException("Unexpected EOF while reading box content"); |
|||
} |
|||
|
|||
writer.Write(cache.AsSpan(0, bytesRead)); |
|||
bytesLeft -= (ulong)bytesRead; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
finally |
|||
{ |
|||
ArrayPool<byte>.Shared.Return(cache); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue