Browse Source

ErrorCode is now a state of InputProcessor

pull/322/head
Anton Firszov 9 years ago
parent
commit
b75481b849
  1. 84
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/InputProcessor.cs
  2. 61
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.cs
  3. 2
      src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs
  4. 4
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs

84
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/InputProcessor.cs

@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
this.Bytes = Bytes.Create(); this.Bytes = Bytes.Create();
this.InputStream = inputStream; this.InputStream = inputStream;
this.Temp = temp; this.Temp = temp;
this.UnexpectedEndOfStreamReached = false; this.LastErrorCode = OrigDecoderErrorCode.NoError;
} }
/// <summary> /// <summary>
@ -48,48 +48,48 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
public byte[] Temp { get; } public byte[] Temp { get; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether an unexpected EOF reached in <see cref="InputStream"/>. /// Gets a value indicating whether an unexpected EOF reached in <see cref="InputStream"/>.
/// </summary> /// </summary>
public bool UnexpectedEndOfStreamReached { get; set; } public bool ReachedEOF => this.LastErrorCode == OrigDecoderErrorCode.UnexpectedEndOfStream;
public OrigDecoderErrorCode LastErrorCode { get; private set; }
public void ResetErrorState() => this.LastErrorCode = OrigDecoderErrorCode.NoError;
/// <summary> /// <summary>
/// If errorCode indicates unexpected EOF, sets <see cref="UnexpectedEndOfStreamReached"/> to true and returns false. /// If errorCode indicates unexpected EOF, sets <see cref="ReachedEOF"/> to true and returns false.
/// Calls <see cref="DecoderThrowHelper.EnsureNoError"/> and returns true otherwise. /// Calls <see cref="DecoderThrowHelper.EnsureNoError"/> and returns true otherwise.
/// </summary> /// </summary>
/// <param name="errorCode">The <see cref="OrigDecoderErrorCode"/></param> /// <param name="errorCode">The <see cref="OrigDecoderErrorCode"/></param>
/// <returns><see cref="bool"/> indicating whether everything is OK</returns> /// <returns><see cref="bool"/> indicating whether everything is OK</returns>
public bool CheckEOFEnsureNoError(OrigDecoderErrorCode errorCode) public bool CheckEOFEnsureNoError()
{ {
if (errorCode == OrigDecoderErrorCode.UnexpectedEndOfStream) if (this.LastErrorCode == OrigDecoderErrorCode.UnexpectedEndOfStream)
{ {
this.UnexpectedEndOfStreamReached = true;
return false; return false;
} }
errorCode.EnsureNoError(); this.LastErrorCode.EnsureNoError();
return true; return true;
} }
/// <summary> /// <summary>
/// If errorCode indicates unexpected EOF, sets <see cref="UnexpectedEndOfStreamReached"/> to true and returns false. /// If errorCode indicates unexpected EOF, sets <see cref="ReachedEOF"/> to true and returns false.
/// Returns true otherwise. /// Returns true otherwise.
/// </summary> /// </summary>
/// <param name="errorCode">The <see cref="OrigDecoderErrorCode"/></param> /// <param name="errorCode">The <see cref="OrigDecoderErrorCode"/></param>
/// <returns><see cref="bool"/> indicating whether everything is OK</returns> /// <returns><see cref="bool"/> indicating whether everything is OK</returns>
public bool CheckEOF(OrigDecoderErrorCode errorCode) public bool CheckEOF()
{ {
if (errorCode == OrigDecoderErrorCode.UnexpectedEndOfStream) if (this.LastErrorCode == OrigDecoderErrorCode.UnexpectedEndOfStream)
{ {
this.UnexpectedEndOfStreamReached = true;
return false; return false;
} }
return true; return true;
} }
/// <summary> /// <inheritdoc />
/// Dispose
/// </summary>
public void Dispose() public void Dispose()
{ {
this.Bytes.Dispose(); this.Bytes.Dispose();
@ -115,18 +115,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{ {
if (this.Bits.UnreadBits == 0) if (this.Bits.UnreadBits == 0)
{ {
OrigDecoderErrorCode errorCode = this.Bits.Ensure1BitUnsafe(ref this); this.LastErrorCode = this.Bits.Ensure1BitUnsafe(ref this);
if (errorCode != OrigDecoderErrorCode.NoError) if (this.LastErrorCode != OrigDecoderErrorCode.NoError)
{ {
result = false; result = false;
return errorCode; return this.LastErrorCode;
} }
} }
result = (this.Bits.Accumulator & this.Bits.Mask) != 0; result = (this.Bits.Accumulator & this.Bits.Mask) != 0;
this.Bits.UnreadBits--; this.Bits.UnreadBits--;
this.Bits.Mask >>= 1; this.Bits.Mask >>= 1;
return OrigDecoderErrorCode.NoError; return this.LastErrorCode = OrigDecoderErrorCode.NoError;
} }
/// <summary> /// <summary>
@ -150,8 +150,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
this.Bytes.UnreadableBytes = 0; this.Bytes.UnreadableBytes = 0;
} }
OrigDecoderErrorCode errorCode = OrigDecoderErrorCode.NoError; this.LastErrorCode = OrigDecoderErrorCode.NoError;
while (length > 0 && errorCode == OrigDecoderErrorCode.NoError) while (length > 0 && this.LastErrorCode == OrigDecoderErrorCode.NoError)
{ {
if (this.Bytes.J - this.Bytes.I >= length) if (this.Bytes.J - this.Bytes.I >= length)
{ {
@ -166,11 +166,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
length -= this.Bytes.J - this.Bytes.I; length -= this.Bytes.J - this.Bytes.I;
this.Bytes.I += this.Bytes.J - this.Bytes.I; this.Bytes.I += this.Bytes.J - this.Bytes.I;
errorCode = this.Bytes.FillUnsafe(this.InputStream); this.LastErrorCode = this.Bytes.FillUnsafe(this.InputStream);
} }
} }
return errorCode; return this.LastErrorCode;
} }
/// <summary> /// <summary>
@ -183,14 +183,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{ {
if (this.Bits.UnreadBits < count) if (this.Bits.UnreadBits < count)
{ {
this.Bits.EnsureNBits(count, ref this); this.LastErrorCode = this.Bits.EnsureNBitsUnsafe(count, ref this);
if (this.LastErrorCode != OrigDecoderErrorCode.NoError)
{
result = 0;
return this.LastErrorCode;
}
} }
result = this.Bits.Accumulator >> (this.Bits.UnreadBits - count); result = this.Bits.Accumulator >> (this.Bits.UnreadBits - count);
result = result & ((1 << count) - 1); result = result & ((1 << count) - 1);
this.Bits.UnreadBits -= count; this.Bits.UnreadBits -= count;
this.Bits.Mask >>= count; this.Bits.Mask >>= count;
return OrigDecoderErrorCode.NoError; return this.LastErrorCode = OrigDecoderErrorCode.NoError;
} }
/// <summary> /// <summary>
@ -210,9 +215,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
if (this.Bits.UnreadBits < 8) if (this.Bits.UnreadBits < 8)
{ {
OrigDecoderErrorCode errorCode = this.Bits.Ensure8BitsUnsafe(ref this); this.LastErrorCode = this.Bits.Ensure8BitsUnsafe(ref this);
if (errorCode == OrigDecoderErrorCode.NoError) if (this.LastErrorCode == OrigDecoderErrorCode.NoError)
{ {
int lutIndex = (this.Bits.Accumulator >> (this.Bits.UnreadBits - OrigHuffmanTree.LutSizeLog2)) & 0xFF; int lutIndex = (this.Bits.Accumulator >> (this.Bits.UnreadBits - OrigHuffmanTree.LutSizeLog2)) & 0xFF;
int v = huffmanTree.Lut[lutIndex]; int v = huffmanTree.Lut[lutIndex];
@ -223,13 +228,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
this.Bits.UnreadBits -= n; this.Bits.UnreadBits -= n;
this.Bits.Mask >>= n; this.Bits.Mask >>= n;
result = v >> 8; result = v >> 8;
return errorCode; return this.LastErrorCode;
} }
} }
else else
{ {
this.UnreadByteStuffedByte(); this.UnreadByteStuffedByte();
return errorCode; return this.LastErrorCode;
} }
} }
@ -252,7 +257,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
if (code <= huffmanTree.MaxCodes[i]) if (code <= huffmanTree.MaxCodes[i])
{ {
result = huffmanTree.GetValue(code, i); result = huffmanTree.GetValue(code, i);
return OrigDecoderErrorCode.NoError; return this.LastErrorCode = OrigDecoderErrorCode.NoError;
} }
code <<= 1; code <<= 1;
@ -272,8 +277,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Skip(int count) public void Skip(int count)
{ {
OrigDecoderErrorCode errorCode = this.SkipUnsafe(count); this.LastErrorCode = this.SkipUnsafe(count);
errorCode.EnsureNoError(); this.LastErrorCode.EnsureNoError();
} }
/// <summary> /// <summary>
@ -310,14 +315,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
break; break;
} }
OrigDecoderErrorCode errorCode = this.Bytes.FillUnsafe(this.InputStream); this.LastErrorCode = this.Bytes.FillUnsafe(this.InputStream);
if (errorCode != OrigDecoderErrorCode.NoError) if (this.LastErrorCode != OrigDecoderErrorCode.NoError)
{ {
return errorCode; return this.LastErrorCode;
} }
} }
return OrigDecoderErrorCode.NoError; return this.LastErrorCode = OrigDecoderErrorCode.NoError;
} }
/// <summary> /// <summary>
@ -329,8 +334,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadFull(byte[] data, int offset, int length) public void ReadFull(byte[] data, int offset, int length)
{ {
OrigDecoderErrorCode errorCode = this.ReadFullUnsafe(data, offset, length); this.LastErrorCode = this.ReadFullUnsafe(data, offset, length);
errorCode.EnsureNoError(); this.LastErrorCode.EnsureNoError();
} }
/// <summary> /// <summary>
@ -360,7 +365,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <returns>The <see cref="OrigDecoderErrorCode"/></returns> /// <returns>The <see cref="OrigDecoderErrorCode"/></returns>
public OrigDecoderErrorCode ReceiveExtendUnsafe(int t, out int x) public OrigDecoderErrorCode ReceiveExtendUnsafe(int t, out int x)
{ {
return this.Bits.ReceiveExtendUnsafe(t, ref this, out x); this.LastErrorCode = this.Bits.ReceiveExtendUnsafe(t, ref this, out x);
return this.LastErrorCode;
} }
} }
} }

61
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.cs

@ -178,7 +178,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
// Copy block to stack // Copy block to stack
this.data.Block = blockRefOnHeap; this.data.Block = blockRefOnHeap;
if (!decoder.InputProcessor.UnexpectedEndOfStreamReached) if (!decoder.InputProcessor.ReachedEOF)
{ {
this.DecodeBlock(decoder, scanIndex); this.DecodeBlock(decoder, scanIndex);
} }
@ -197,10 +197,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{ {
// A more sophisticated decoder could use RST[0-7] markers to resynchronize from corrupt input, // A more sophisticated decoder could use RST[0-7] markers to resynchronize from corrupt input,
// but this one assumes well-formed input, and hence the restart marker follows immediately. // but this one assumes well-formed input, and hence the restart marker follows immediately.
if (!decoder.InputProcessor.UnexpectedEndOfStreamReached) if (!decoder.InputProcessor.ReachedEOF)
{ {
OrigDecoderErrorCode errorCode = decoder.InputProcessor.ReadFullUnsafe(decoder.Temp, 0, 2); decoder.InputProcessor.ReadFullUnsafe(decoder.Temp, 0, 2);
if (decoder.InputProcessor.CheckEOFEnsureNoError(errorCode)) if (decoder.InputProcessor.CheckEOFEnsureNoError())
{ {
if (decoder.Temp[0] != 0xff || decoder.Temp[1] != expectedRst) if (decoder.Temp[0] != 0xff || decoder.Temp[1] != expectedRst)
{ {
@ -318,7 +318,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
else else
{ {
int zig = this.zigStart; int zig = this.zigStart;
OrigDecoderErrorCode errorCode; //OrigDecoderErrorCode errorCode;
if (zig == 0) if (zig == 0)
{ {
zig++; zig++;
@ -326,10 +326,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
// Decode the DC coefficient, as specified in section F.2.2.1. // Decode the DC coefficient, as specified in section F.2.2.1.
int value; int value;
int huffmanIndex = (OrigHuffmanTree.DcTableIndex * OrigHuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].DcTableSelector; int huffmanIndex = (OrigHuffmanTree.DcTableIndex * OrigHuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].DcTableSelector;
errorCode = decoder.InputProcessor.DecodeHuffmanUnsafe( decoder.InputProcessor.DecodeHuffmanUnsafe(
ref decoder.HuffmanTrees[huffmanIndex], ref decoder.HuffmanTrees[huffmanIndex],
out value); out value);
if (!decoder.InputProcessor.CheckEOF(errorCode)) if (!decoder.InputProcessor.CheckEOF())
{ {
return; return;
} }
@ -340,8 +340,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
} }
int deltaDC; int deltaDC;
errorCode = decoder.InputProcessor.ReceiveExtendUnsafe(value, out deltaDC); decoder.InputProcessor.ReceiveExtendUnsafe(value, out deltaDC);
if (!decoder.InputProcessor.CheckEOFEnsureNoError(errorCode)) if (!decoder.InputProcessor.CheckEOFEnsureNoError())
{ {
return; return;
} }
@ -363,8 +363,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
for (; zig <= this.zigEnd; zig++) for (; zig <= this.zigEnd; zig++)
{ {
int value; int value;
errorCode = decoder.InputProcessor.DecodeHuffmanUnsafe(ref decoder.HuffmanTrees[huffmannIdx], out value); decoder.InputProcessor.DecodeHuffmanUnsafe(ref decoder.HuffmanTrees[huffmannIdx], out value);
if (!decoder.InputProcessor.CheckEOF(errorCode)) if (!decoder.InputProcessor.CheckEOF())
{ {
return; return;
} }
@ -380,8 +380,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
} }
int ac; int ac;
errorCode = decoder.InputProcessor.ReceiveExtendUnsafe(val1, out ac); decoder.InputProcessor.ReceiveExtendUnsafe(val1, out ac);
if (!decoder.InputProcessor.CheckEOFEnsureNoError(errorCode)) if (!decoder.InputProcessor.CheckEOFEnsureNoError())
{ {
return; return;
} }
@ -397,8 +397,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
this.eobRun = (ushort)(1 << val0); this.eobRun = (ushort)(1 << val0);
if (val0 != 0) if (val0 != 0)
{ {
errorCode = this.DecodeEobRun(val0, ref decoder.InputProcessor); this.DecodeEobRun(val0, ref decoder.InputProcessor);
if (!decoder.InputProcessor.CheckEOFEnsureNoError(errorCode)) if (!decoder.InputProcessor.CheckEOFEnsureNoError())
{ {
return; return;
} }
@ -415,17 +415,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
} }
} }
private OrigDecoderErrorCode DecodeEobRun(int count, ref InputProcessor decoder) private void DecodeEobRun(int count, ref InputProcessor processor)
{ {
int bitsResult; int bitsResult;
OrigDecoderErrorCode errorCode = decoder.DecodeBitsUnsafe(count, out bitsResult); processor.DecodeBitsUnsafe(count, out bitsResult);
if (errorCode != OrigDecoderErrorCode.NoError) if (processor.LastErrorCode != OrigDecoderErrorCode.NoError)
{ {
return errorCode; return;
} }
this.eobRun |= bitsResult; this.eobRun |= bitsResult;
return OrigDecoderErrorCode.NoError;
} }
/// <summary> /// <summary>
@ -516,8 +515,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
} }
bool bit; bool bit;
OrigDecoderErrorCode errorCode = bp.DecodeBitUnsafe(out bit); bp.DecodeBitUnsafe(out bit);
if (!bp.CheckEOFEnsureNoError(errorCode)) if (!bp.CheckEOFEnsureNoError())
{ {
return; return;
} }
@ -546,8 +545,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
int z = 0; int z = 0;
int val; int val;
OrigDecoderErrorCode errorCode = bp.DecodeHuffmanUnsafe(ref h, out val); bp.DecodeHuffmanUnsafe(ref h, out val);
if (!bp.CheckEOF(errorCode)) if (!bp.CheckEOF())
{ {
return; return;
} }
@ -563,8 +562,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
this.eobRun = 1 << val0; this.eobRun = 1 << val0;
if (val0 != 0) if (val0 != 0)
{ {
errorCode = this.DecodeEobRun(val0, ref bp); this.DecodeEobRun(val0, ref bp);
if (!bp.CheckEOFEnsureNoError(errorCode)) if (!bp.CheckEOFEnsureNoError())
{ {
return; return;
} }
@ -578,8 +577,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
z = delta; z = delta;
bool bit; bool bit;
errorCode = bp.DecodeBitUnsafe(out bit); bp.DecodeBitUnsafe(out bit);
if (!bp.CheckEOFEnsureNoError(errorCode)) if (!bp.CheckEOFEnsureNoError())
{ {
return; return;
} }
@ -600,7 +599,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
} }
zig = this.RefineNonZeroes(ref bp, zig, val0, delta); zig = this.RefineNonZeroes(ref bp, zig, val0, delta);
if (bp.UnexpectedEndOfStreamReached) if (bp.ReachedEOF)
{ {
return; return;
} }
@ -650,8 +649,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
} }
bool bit; bool bit;
OrigDecoderErrorCode errorCode = bp.DecodeBitUnsafe(out bit); bp.DecodeBitUnsafe(out bit);
if (!bp.CheckEOFEnsureNoError(errorCode)) if (!bp.CheckEOFEnsureNoError())
{ {
return int.MinValue; return int.MinValue;
} }

2
src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs

@ -342,7 +342,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
// when this is a progressive image this gets called a number of times // when this is a progressive image this gets called a number of times
// need to know how many times this should be called in total. // need to know how many times this should be called in total.
this.ProcessStartOfScan(remaining); this.ProcessStartOfScan(remaining);
if (this.InputProcessor.UnexpectedEndOfStreamReached || !this.IsProgressive) if (this.InputProcessor.ReachedEOF || !this.IsProgressive)
{ {
// if unexpeced EOF reached or this is not a progressive image we can stop processing bytes as we now have the image data. // if unexpeced EOF reached or this is not a progressive image we can stop processing bytes as we now have the image data.
processBytes = false; processBytes = false;

4
tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs

@ -38,7 +38,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
TestImages.Jpeg.Baseline.Bad.BadEOF, TestImages.Jpeg.Baseline.Bad.BadEOF,
TestImages.Jpeg.Baseline.Bad.ExifUndefType, TestImages.Jpeg.Baseline.Bad.ExifUndefType,
TestImages.Jpeg.Issues.MissingFF00ProgressiveGirl159,
TestImages.Jpeg.Issues.MissingFF00Gear159, TestImages.Jpeg.Issues.MissingFF00Gear159,
}; };
@ -46,7 +45,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{ {
TestImages.Jpeg.Progressive.Fb, TestImages.Jpeg.Progressive.Progress, TestImages.Jpeg.Progressive.Fb, TestImages.Jpeg.Progressive.Progress,
TestImages.Jpeg.Progressive.Festzug, TestImages.Jpeg.Progressive.Bad.BadEOF, TestImages.Jpeg.Progressive.Festzug, TestImages.Jpeg.Progressive.Bad.BadEOF,
TestImages.Jpeg.Issues.BadCoeffsProgressive178 TestImages.Jpeg.Issues.BadCoeffsProgressive178,
TestImages.Jpeg.Issues.MissingFF00ProgressiveGirl159,
}; };
public const PixelTypes CommonNonDefaultPixelTypes = PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.RgbaVector; public const PixelTypes CommonNonDefaultPixelTypes = PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.RgbaVector;

Loading…
Cancel
Save