// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Formats.Jpg { using System; using System.Runtime.CompilerServices; /// /// 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. /// internal struct Bits { /// /// Gets or sets the accumulator. /// public uint Accumulator; /// /// Gets or sets the mask. /// 0, with mask==0 when unreadbits==0.]]> /// public uint Mask; /// /// Gets or sets the number of unread bits in the accumulator. /// public int UnreadBits; /// /// 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. /// /// The number of bits to ensure. /// Jpeg decoder [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnsureNBits(int n, JpegDecoderCore decoder) { DecoderErrorCode errorCode = this.EnsureNBitsUnsafe(n, decoder); errorCode.EnsureNoError(); } /// /// 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 instead. /// /// The number of bits to ensure. /// Jpeg decoder /// Error code //[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; } } } /// /// Unrolled version of for n==8 /// /// /// public DecoderErrorCode Ensure8BitsUnsafe(JpegDecoderCore decoder) { return this.EnsureBitsStepImpl(decoder); } /// /// Unrolled version of for n==1 /// /// /// 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; } /// /// Receive extend /// /// Byte /// Jpeg decoder /// Read bits value [MethodImpl(MethodImplOptions.AggressiveInlining)] public int ReceiveExtend(byte t, JpegDecoderCore decoder) { int x; DecoderErrorCode errorCode = this.ReceiveExtendUnsafe(t, decoder, out x); errorCode.EnsureNoError(); return x; } /// /// Receive extend /// /// Byte /// Jpeg decoder /// Read bits value /// The 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; } } }