mirror of https://github.com/SixLabors/ImageSharp
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
160 lines
5.5 KiB
160 lines
5.5 KiB
// <copyright file="Bits.cs" company="James Jackson-South">
|
|
// Copyright (c) James Jackson-South and contributors.
|
|
// Licensed under the Apache License, Version 2.0.
|
|
// </copyright>
|
|
|
|
namespace ImageSharp.Formats.Jpg
|
|
{
|
|
using System;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
/// <summary>
|
|
/// Holds the unprocessed bits that have been taken from the byte-stream.
|
|
/// The n least significant bits of a form the unread bits, to be read in MSB to
|
|
/// LSB order.
|
|
/// </summary>
|
|
internal struct Bits
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the accumulator.
|
|
/// </summary>
|
|
public uint Accumulator;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the mask.
|
|
/// <![CDATA[mask==1<<(unreadbits-1) when unreadbits>0, with mask==0 when unreadbits==0.]]>
|
|
/// </summary>
|
|
public uint Mask;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the number of unread bits in the accumulator.
|
|
/// </summary>
|
|
public int UnreadBits;
|
|
|
|
/// <summary>
|
|
/// Reads bytes from the byte buffer to ensure that bits.UnreadBits is at
|
|
/// least n. For best performance (avoiding function calls inside hot loops),
|
|
/// the caller is the one responsible for first checking that bits.UnreadBits < n.
|
|
/// </summary>
|
|
/// <param name="n">The number of bits to ensure.</param>
|
|
/// <param name="decoder">Jpeg decoder</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void EnsureNBits(int n, JpegDecoderCore decoder)
|
|
{
|
|
DecoderErrorCode errorCode = this.EnsureNBitsUnsafe(n, decoder);
|
|
errorCode.EnsureNoError();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads bytes from the byte buffer to ensure that bits.UnreadBits is at
|
|
/// least n. For best performance (avoiding function calls inside hot loops),
|
|
/// the caller is the one responsible for first checking that bits.UnreadBits < n.
|
|
/// This method does not throw. Returns <see cref="DecoderErrorCode"/> instead.
|
|
/// </summary>
|
|
/// <param name="n">The number of bits to ensure.</param>
|
|
/// <param name="decoder">Jpeg decoder</param>
|
|
/// <returns>Error code</returns>
|
|
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public DecoderErrorCode EnsureNBitsUnsafe(int n, JpegDecoderCore decoder)
|
|
{
|
|
while (true)
|
|
{
|
|
DecoderErrorCode errorCode = this.EnsureBitsStepImpl(decoder);
|
|
if (errorCode != DecoderErrorCode.NoError || this.UnreadBits >= n)
|
|
{
|
|
return errorCode;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unrolled version of <see cref="EnsureNBitsUnsafe"/> for n==8
|
|
/// </summary>
|
|
/// <param name="decoder"></param>
|
|
/// <returns></returns>
|
|
public DecoderErrorCode Ensure8BitsUnsafe(JpegDecoderCore decoder)
|
|
{
|
|
return this.EnsureBitsStepImpl(decoder);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unrolled version of <see cref="EnsureNBitsUnsafe"/> for n==1
|
|
/// </summary>
|
|
/// <param name="decoder"></param>
|
|
/// <returns></returns>
|
|
public DecoderErrorCode Ensure1BitUnsafe(JpegDecoderCore decoder)
|
|
{
|
|
return this.EnsureBitsStepImpl(decoder);
|
|
}
|
|
|
|
private DecoderErrorCode EnsureBitsStepImpl(JpegDecoderCore decoder)
|
|
{
|
|
byte c;
|
|
DecoderErrorCode errorCode = decoder.Bytes.ReadByteStuffedByteUnsafe(decoder.InputStream, out c);
|
|
|
|
if (errorCode != DecoderErrorCode.NoError)
|
|
{
|
|
return errorCode;
|
|
}
|
|
|
|
this.Accumulator = (this.Accumulator << 8) | c;
|
|
this.UnreadBits += 8;
|
|
if (this.Mask == 0)
|
|
{
|
|
this.Mask = 1 << 7;
|
|
}
|
|
else
|
|
{
|
|
this.Mask <<= 8;
|
|
}
|
|
return errorCode;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Receive extend
|
|
/// </summary>
|
|
/// <param name="t">Byte</param>
|
|
/// <param name="decoder">Jpeg decoder</param>
|
|
/// <returns>Read bits value</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public int ReceiveExtend(byte t, JpegDecoderCore decoder)
|
|
{
|
|
int x;
|
|
DecoderErrorCode errorCode = this.ReceiveExtendUnsafe(t, decoder, out x);
|
|
errorCode.EnsureNoError();
|
|
return x;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Receive extend
|
|
/// </summary>
|
|
/// <param name="t">Byte</param>
|
|
/// <param name="decoder">Jpeg decoder</param>
|
|
/// <param name="x">Read bits value</param>
|
|
/// <returns>The <see cref="DecoderErrorCode"/></returns>
|
|
public DecoderErrorCode ReceiveExtendUnsafe(byte t, JpegDecoderCore decoder, out int x)
|
|
{
|
|
if (this.UnreadBits < t)
|
|
{
|
|
DecoderErrorCode errorCode = this.EnsureNBitsUnsafe(t, decoder);
|
|
if (errorCode != DecoderErrorCode.NoError)
|
|
{
|
|
x = int.MaxValue;
|
|
return errorCode;
|
|
}
|
|
}
|
|
|
|
this.UnreadBits -= t;
|
|
this.Mask >>= t;
|
|
int s = 1 << t;
|
|
x = (int)((this.Accumulator >> this.UnreadBits) & (s - 1));
|
|
|
|
if (x < (s >> 1))
|
|
{
|
|
x += ((-1) << t) + 1;
|
|
}
|
|
|
|
return DecoderErrorCode.NoError;
|
|
}
|
|
}
|
|
}
|