// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Formats.Jpg { 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 int Accumulator; /// /// Gets or sets the mask. /// 0, with mask==0 when unreadbits==0.]]> /// public int 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. /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnsureNBits(int n, ref BufferProcessor bufferProcessor) { DecoderErrorCode errorCode = this.EnsureNBitsUnsafe(n, ref bufferProcessor); 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. /// The /// Error code public DecoderErrorCode EnsureNBitsUnsafe(int n, ref BufferProcessor bufferProcessor) { while (true) { DecoderErrorCode errorCode = this.EnsureBitsStepImpl(ref bufferProcessor); if (errorCode != DecoderErrorCode.NoError || this.UnreadBits >= n) { return errorCode; } } } /// /// Unrolled version of for n==8 /// /// The /// A public DecoderErrorCode Ensure8BitsUnsafe(ref BufferProcessor bufferProcessor) { return this.EnsureBitsStepImpl(ref bufferProcessor); } /// /// Unrolled version of for n==1 /// /// The /// A public DecoderErrorCode Ensure1BitUnsafe(ref BufferProcessor bufferProcessor) { return this.EnsureBitsStepImpl(ref bufferProcessor); } /// /// Receive extend /// /// Byte /// The /// Read bits value [MethodImpl(MethodImplOptions.AggressiveInlining)] public int ReceiveExtend(int t, ref BufferProcessor bufferProcessor) { int x; DecoderErrorCode errorCode = this.ReceiveExtendUnsafe(t, ref bufferProcessor, out x); errorCode.EnsureNoError(); return x; } /// /// Receive extend /// /// Byte /// The /// Read bits value /// The public DecoderErrorCode ReceiveExtendUnsafe(int t, ref BufferProcessor bufferProcessor, out int x) { if (this.UnreadBits < t) { DecoderErrorCode errorCode = this.EnsureNBitsUnsafe(t, ref bufferProcessor); 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; } private DecoderErrorCode EnsureBitsStepImpl(ref BufferProcessor bufferProcessor) { int c; DecoderErrorCode errorCode = bufferProcessor.Bytes.ReadByteStuffedByteUnsafe(bufferProcessor.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; } } }