diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bits.cs b/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bits.cs
index ab08b0d4cf..36344b75a6 100644
--- a/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bits.cs
+++ b/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bits.cs
@@ -94,24 +94,45 @@ namespace ImageSharp.Formats.Jpg
/// Byte
/// Jpeg decoder
/// Read bits value
- internal int ReceiveExtend(byte t, JpegDecoderCore decoder)
+ [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)
{
- this.EnsureNBits(t, decoder);
+ 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;
- int x = (int)((this.Accumulator >> this.UnreadBits) & (s - 1));
+ x = (int)((this.Accumulator >> this.UnreadBits) & (s - 1));
if (x < (s >> 1))
{
x += ((-1) << t) + 1;
}
- return x;
+ return DecoderErrorCode.NoError;
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bytes.cs b/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bytes.cs
index 176e0cfbeb..6ca017f4e8 100644
--- a/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bytes.cs
+++ b/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bytes.cs
@@ -101,6 +101,7 @@ namespace ImageSharp.Formats.Jpg
{
return errorCode;
}
+
if (x != JpegConstants.Markers.XFF)
{
return DecoderErrorCode.NoError;
@@ -112,6 +113,7 @@ namespace ImageSharp.Formats.Jpg
{
return errorCode;
}
+
if (x != 0x00)
{
return DecoderErrorCode.MissingFF00;
diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/DecoderThrowHelper.cs b/src/ImageSharp.Formats.Jpeg/Components/Decoder/DecoderThrowHelper.cs
index 18ba02a9a0..84f7579c8a 100644
--- a/src/ImageSharp.Formats.Jpeg/Components/Decoder/DecoderThrowHelper.cs
+++ b/src/ImageSharp.Formats.Jpeg/Components/Decoder/DecoderThrowHelper.cs
@@ -46,18 +46,40 @@ namespace ImageSharp.Formats.Jpg
}
}
+ ///
+ /// Throws an exception if the given is .
+ ///
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void EnsureNoEOF(this DecoderErrorCode errorCode)
+ {
+ if (errorCode == DecoderErrorCode.UnexpectedEndOfStream)
+ {
+ errorCode.ThrowExceptionForErrorCode();
+ }
+ }
+
///
/// Encapsulates methods throwing different flavours of -s.
///
public static class ThrowImageFormatException
{
///
- /// Throws "Fill called when unread bytes exist."
+ /// Throws "Fill called when unread bytes exist".
///
[MethodImpl(MethodImplOptions.NoInlining)]
public static void FillCalledWhenUnreadBytesExist()
{
- throw new ImageFormatException("Fill called when unread bytes exist.");
+ throw new ImageFormatException("Fill called when unread bytes exist!");
+ }
+
+ ///
+ /// Throws "Bad Huffman code".
+ ///
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void BadHuffmanCode()
+ {
+ throw new ImageFormatException("Bad Huffman code!");
}
}
}
diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs b/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs
index ef2ce18883..30cb6c851b 100644
--- a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs
+++ b/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs
@@ -308,7 +308,7 @@ namespace ImageSharp.Formats.Jpg
private void ProcessBlockImpl(JpegDecoderCore decoder, int scanIndex)
{
var b = this.pointers.Block;
-
+ DecoderErrorCode errorCode;
int huffmannIdx = (AcTableIndex * HuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].AcTableSelector;
if (this.ah != 0)
{
@@ -322,9 +322,13 @@ namespace ImageSharp.Formats.Jpg
zig++;
// Decode the DC coefficient, as specified in section F.2.2.1.
- byte value =
- decoder.DecodeHuffman(
- ref decoder.HuffmanTrees[(DcTableIndex * HuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].DcTableSelector]);
+ byte value;
+ int huffmanIndex = (DcTableIndex * HuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].DcTableSelector;
+ errorCode = decoder.DecodeHuffmanUnsafe(
+ ref decoder.HuffmanTrees[huffmanIndex],
+ out value);
+ errorCode.EnsureNoEOF();
+
if (value > 16)
{
throw new ImageFormatException("Excessive DC component");
@@ -347,7 +351,10 @@ namespace ImageSharp.Formats.Jpg
// Decode the AC coefficients, as specified in section F.2.2.2.
for (; zig <= this.zigEnd; zig++)
{
- byte value = decoder.DecodeHuffman(ref decoder.HuffmanTrees[huffmannIdx]);
+ byte value;
+ errorCode = decoder.DecodeHuffmanUnsafe(ref decoder.HuffmanTrees[huffmannIdx], out value);
+ errorCode.EnsureNoEOF();
+
byte val0 = (byte)(value >> 4);
byte val1 = (byte)(value & 0x0f);
if (val1 != 0)
@@ -370,7 +377,8 @@ namespace ImageSharp.Formats.Jpg
this.eobRun = (ushort)(1 << val0);
if (val0 != 0)
{
- this.eobRun |= (ushort)decoder.DecodeBits(val0);
+ errorCode = this.DecodeEobRun(val0, decoder);
+ errorCode.EnsureNoError();
}
this.eobRun--;
@@ -409,6 +417,19 @@ namespace ImageSharp.Formats.Jpg
destArea.LoadColorsFrom(this.pointers.Temp1, this.pointers.Temp2);
}
+ private DecoderErrorCode DecodeEobRun(int count, JpegDecoderCore decoder)
+ {
+ uint bitsResult;
+ DecoderErrorCode errorCode = decoder.DecodeBitsUnsafe(count, out bitsResult);
+ if (errorCode != DecoderErrorCode.NoError)
+ {
+ return errorCode;
+ }
+
+ this.eobRun |= (ushort)bitsResult;
+ return DecoderErrorCode.NoError;
+ }
+
///
/// Gets the block index used to retieve blocks from in
///
@@ -496,7 +517,9 @@ namespace ImageSharp.Formats.Jpg
throw new ImageFormatException("Invalid state for zig DC component");
}
- bool bit = decoder.DecodeBit();
+ bool bit;
+ DecoderErrorCode errorCode = decoder.DecodeBitUnsafe(out bit);
+ errorCode.EnsureNoError();
if (bit)
{
int stuff = (int)Block8x8F.GetScalarAt(b, 0);
@@ -519,7 +542,11 @@ namespace ImageSharp.Formats.Jpg
{
bool done = false;
int z = 0;
- byte val = decoder.DecodeHuffman(ref h);
+
+ byte val;
+ DecoderErrorCode errorCode = decoder.DecodeHuffmanUnsafe(ref h, out val);
+ errorCode.EnsureNoEOF();
+
int val0 = val >> 4;
int val1 = val & 0x0f;
@@ -531,7 +558,8 @@ namespace ImageSharp.Formats.Jpg
this.eobRun = (ushort)(1 << val0);
if (val0 != 0)
{
- this.eobRun |= (ushort)decoder.DecodeBits(val0);
+ errorCode = this.DecodeEobRun(val0, decoder);
+ errorCode.EnsureNoError();
}
done = true;
@@ -540,7 +568,11 @@ namespace ImageSharp.Formats.Jpg
break;
case 1:
z = delta;
- bool bit = decoder.DecodeBit();
+
+ bool bit;
+ errorCode = decoder.DecodeBitUnsafe(out bit);
+ errorCode.EnsureNoError();
+
if (!bit)
{
z = -z;
@@ -606,7 +638,10 @@ namespace ImageSharp.Formats.Jpg
continue;
}
- bool bit = decoder.DecodeBit();
+ bool bit;
+ DecoderErrorCode errorCode = decoder.DecodeBitUnsafe(out bit);
+ errorCode.EnsureNoError();
+
if (!bit)
{
continue;
diff --git a/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs b/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs
index 5571ba7075..1e1210387a 100644
--- a/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs
+++ b/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs
@@ -435,25 +435,31 @@ namespace ImageSharp.Formats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public byte ReadByte()
{
- byte result = this.Bytes.ReadByte(this.InputStream);
- return result;
+ return this.Bytes.ReadByte(this.InputStream);
}
///
/// Decodes a single bit
+ /// TODO: This method (and also the usages) could be optimized by batching!
///
- /// The
- public bool DecodeBit()
+ /// The decoded bit as a
+ /// The
+ public DecoderErrorCode DecodeBitUnsafe(out bool result)
{
if (this.Bits.UnreadBits == 0)
{
- this.Bits.EnsureNBits(1, this);
+ DecoderErrorCode errorCode = this.Bits.EnsureNBitsUnsafe(1, this);
+ if (errorCode != DecoderErrorCode.NoError)
+ {
+ result = false;
+ return errorCode;
+ }
}
- bool ret = (this.Bits.Accumulator & this.Bits.Mask) != 0;
+ result = (this.Bits.Accumulator & this.Bits.Mask) != 0;
this.Bits.UnreadBits--;
this.Bits.Mask >>= 1;
- return ret;
+ return DecoderErrorCode.NoError;
}
///
@@ -517,28 +523,32 @@ namespace ImageSharp.Formats
/// Decodes the given number of bits
///
/// The number of bits to decode.
- /// The
- public uint DecodeBits(int count)
+ /// The result
+ /// The
+ public DecoderErrorCode DecodeBitsUnsafe(int count, out uint result)
{
if (this.Bits.UnreadBits < count)
{
this.Bits.EnsureNBits(count, this);
}
- uint ret = this.Bits.Accumulator >> (this.Bits.UnreadBits - count);
- ret = (uint)(ret & ((1 << count) - 1));
+ result = this.Bits.Accumulator >> (this.Bits.UnreadBits - count);
+ result = (uint)(result & ((1 << count) - 1));
this.Bits.UnreadBits -= count;
this.Bits.Mask >>= count;
- return ret;
+ return DecoderErrorCode.NoError;
}
///
- /// Returns the next Huffman-coded value from the bit-stream, decoded according to the given value.
+ /// Extracts the next Huffman-coded value from the bit-stream into result, decoded according to the given value.
///
/// The huffman value
- /// The
- public byte DecodeHuffman(ref HuffmanTree huffmanTree)
+ /// The decoded
+ /// The
+ public DecoderErrorCode DecodeHuffmanUnsafe(ref HuffmanTree huffmanTree, out byte result)
{
+ result = 0;
+
// Copy stuff to the stack:
if (huffmanTree.Length == 0)
{
@@ -558,16 +568,19 @@ namespace ImageSharp.Formats
int n = (v & 0xFF) - 1;
this.Bits.UnreadBits -= n;
this.Bits.Mask >>= n;
- return (byte)(v >> 8);
+ result = (byte)(v >> 8);
+ return errorCode;
}
}
- else if (errorCode == DecoderErrorCode.UnexpectedEndOfStream)
- {
- errorCode.ThrowExceptionForErrorCode();
- }
+
+ // else if (errorCode == DecoderErrorCode.UnexpectedEndOfStream)
+ // {
+ // errorCode.ThrowExceptionForErrorCode();
+ // }
else
{
this.UnreadByteStuffedByte();
+ return errorCode;
}
}
@@ -589,13 +602,18 @@ namespace ImageSharp.Formats
if (code <= huffmanTree.MaxCodes[i])
{
- return huffmanTree.Values[huffmanTree.Indices[i] + code - huffmanTree.MinCodes[i]];
+ result = huffmanTree.Values[huffmanTree.Indices[i] + code - huffmanTree.MinCodes[i]];
+ return DecoderErrorCode.NoError;
}
code <<= 1;
}
- throw new ImageFormatException("Bad Huffman code");
+ // Unrecoverable error, throwing:
+ DecoderThrowHelper.ThrowImageFormatException.BadHuffmanCode();
+
+ // DUMMY RETURN! C# doesn't know we have thrown an exception!
+ return DecoderErrorCode.NoError;
}
///