Browse Source

sanitize MCU processing code

af/merge-core
Anton Firszov 8 years ago
parent
commit
0fc9002dcc
  1. 8
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/InputProcessor.cs
  2. 205
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.cs
  3. 9
      src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs

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

@ -380,5 +380,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
this.LastErrorCode = this.Bits.ReceiveExtendUnsafe(t, ref this, out x);
return this.LastErrorCode;
}
/// <summary>
/// Reset the Huffman decoder.
/// </summary>
public void ResetHuffmanDecoder()
{
this.Bits = default(Bits);
}
}
}

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

@ -94,6 +94,21 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary>
private int eobRun;
/// <summary>
/// The block counter
/// </summary>
private int blockCounter;
/// <summary>
/// The MCU counter
/// </summary>
private int mcuCounter;
/// <summary>
/// The expected RST marker value
/// </summary>
private byte expectedRst;
/// <summary>
/// Initializes a default-constructed <see cref="OrigJpegScanDecoder"/> instance for reading data from <see cref="OrigJpegDecoderCore"/>-s stream.
/// </summary>
@ -139,124 +154,136 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{
decoder.InputProcessor.ResetErrorState();
int blockCount = 0;
int mcu = 0;
byte expectedRst = OrigJpegConstants.Markers.RST0;
this.blockCounter = 0;
this.mcuCounter = 0;
this.expectedRst = OrigJpegConstants.Markers.RST0;
for (int my = 0; my < decoder.MCUCountY; my++)
{
for (int mx = 0; mx < decoder.MCUCountX; mx++)
{
for (int scanIndex = 0; scanIndex < this.componentScanCount; scanIndex++)
{
this.ComponentIndex = this.pointers.ComponentScan[scanIndex].ComponentIndex;
OrigComponent component = decoder.Components[this.ComponentIndex];
this.DecodeBlocksAtMcuIndex(decoder, mx, my);
this.hi = component.HorizontalSamplingFactor;
int vi = component.VerticalSamplingFactor;
for (int j = 0; j < this.hi * vi; j++)
{
if (this.componentScanCount != 1)
{
this.bx = (this.hi * mx) + (j % this.hi);
this.by = (vi * my) + (j / this.hi);
}
else
{
int q = decoder.MCUCountX * this.hi;
this.bx = blockCount % q;
this.by = blockCount / q;
blockCount++;
if (this.bx * 8 >= decoder.ImageWidth || this.by * 8 >= decoder.ImageHeight)
{
continue;
}
}
this.mcuCounter++;
// Find the block at (bx,by) in the component's buffer:
ref Block8x8 blockRefOnHeap = ref component.GetBlockReference(this.bx, this.by);
// Handling restart intervals
// Useful info: https://stackoverflow.com/a/8751802
if (decoder.IsAtRestartInterval(this.mcuCounter))
{
this.ProcessRSTMarker(decoder);
this.Reset(decoder);
}
}
}
}
// Copy block to stack
this.data.Block = blockRefOnHeap;
private void DecodeBlocksAtMcuIndex(OrigJpegDecoderCore decoder, int mx, int my)
{
for (int scanIndex = 0; scanIndex < this.componentScanCount; scanIndex++)
{
this.ComponentIndex = this.pointers.ComponentScan[scanIndex].ComponentIndex;
OrigComponent component = decoder.Components[this.ComponentIndex];
if (!decoder.InputProcessor.ReachedEOF)
{
this.DecodeBlock(decoder, scanIndex);
}
this.hi = component.HorizontalSamplingFactor;
int vi = component.VerticalSamplingFactor;
// Store the result block:
blockRefOnHeap = this.data.Block;
for (int j = 0; j < this.hi * vi; j++)
{
if (this.componentScanCount != 1)
{
this.bx = (this.hi * mx) + (j % this.hi);
this.by = (vi * my) + (j / this.hi);
}
else
{
int q = decoder.MCUCountX * this.hi;
this.bx = this.blockCounter % q;
this.by = this.blockCounter / q;
this.blockCounter++;
if (this.bx * 8 >= decoder.ImageWidth || this.by * 8 >= decoder.ImageHeight)
{
continue;
}
}
// Find the block at (bx,by) in the component's buffer:
ref Block8x8 blockRefOnHeap = ref component.GetBlockReference(this.bx, this.by);
// for j
// Copy block to stack
this.data.Block = blockRefOnHeap;
if (!decoder.InputProcessor.ReachedEOF)
{
this.DecodeBlock(decoder, scanIndex);
}
// for i
mcu++;
// Store the result block:
blockRefOnHeap = this.data.Block;
}
}
}
if (decoder.RestartInterval > 0 && mcu % decoder.RestartInterval == 0 && mcu < decoder.TotalMCUCount)
private void ProcessRSTMarker(OrigJpegDecoderCore decoder)
{
// Attempt to look for RST[0-7] markers to resynchronize from corrupt input.
if (!decoder.InputProcessor.ReachedEOF)
{
decoder.InputProcessor.ReadFullUnsafe(decoder.Temp, 0, 2);
if (decoder.InputProcessor.CheckEOFEnsureNoError())
{
if (decoder.Temp[0] != 0xFF || decoder.Temp[1] != this.expectedRst)
{
// Attempt to look for RST[0-7] markers to resynchronize from corrupt input.
if (!decoder.InputProcessor.ReachedEOF)
bool invalidRst = true;
// Most jpeg's containing well-formed input will have a RST[0-7] marker following immediately
// but some, see Issue #481, contain padding bytes "0xFF" before the RST[0-7] marker.
// If we identify that case we attempt to read until we have bypassed the padded bytes.
// We then check again for our RST marker and throw if invalid.
// No other methods are attempted to resynchronize from corrupt input.
if (decoder.Temp[0] == 0xFF && decoder.Temp[1] == 0xFF)
{
decoder.InputProcessor.ReadFullUnsafe(decoder.Temp, 0, 2);
if (decoder.InputProcessor.CheckEOFEnsureNoError())
while (decoder.Temp[0] == 0xFF && decoder.InputProcessor.CheckEOFEnsureNoError())
{
if (decoder.Temp[0] != 0xFF || decoder.Temp[1] != expectedRst)
{
bool invalidRst = true;
// Most jpeg's containing well-formed input will have a RST[0-7] marker following immediately
// but some, see Issue #481, contain padding bytes "0xFF" before the RST[0-7] marker.
// If we identify that case we attempt to read until we have bypassed the padded bytes.
// We then check again for our RST marker and throw if invalid.
// No other methods are attempted to resynchronize from corrupt input.
if (decoder.Temp[0] == 0xFF && decoder.Temp[1] == 0xFF)
{
while (decoder.Temp[0] == 0xFF && decoder.InputProcessor.CheckEOFEnsureNoError())
{
decoder.InputProcessor.ReadFullUnsafe(decoder.Temp, 0, 1);
if (!decoder.InputProcessor.CheckEOFEnsureNoError())
{
break;
}
}
// Have we found a valid restart marker?
invalidRst = decoder.Temp[0] != expectedRst;
}
if (invalidRst)
{
throw new ImageFormatException("Bad RST marker");
}
}
expectedRst++;
if (expectedRst == OrigJpegConstants.Markers.RST7 + 1)
decoder.InputProcessor.ReadFullUnsafe(decoder.Temp, 0, 1);
if (!decoder.InputProcessor.CheckEOFEnsureNoError())
{
expectedRst = OrigJpegConstants.Markers.RST0;
break;
}
}
}
// Reset the Huffman decoder.
decoder.InputProcessor.Bits = default(Bits);
// Have we found a valid restart marker?
invalidRst = decoder.Temp[0] != this.expectedRst;
}
// Reset the DC components, as per section F.2.1.3.1.
this.ResetDc();
if (invalidRst)
{
throw new ImageFormatException("Bad RST marker");
}
}
// Reset the progressive decoder state, as per section G.1.2.2.
this.eobRun = 0;
this.expectedRst++;
if (this.expectedRst == OrigJpegConstants.Markers.RST7 + 1)
{
this.expectedRst = OrigJpegConstants.Markers.RST0;
}
}
// for mx
}
}
private void ResetDc()
private void Reset(OrigJpegDecoderCore decoder)
{
decoder.InputProcessor.ResetHuffmanDecoder();
this.ResetDcValues();
// Reset the progressive decoder state, as per section G.1.2.2.
this.eobRun = 0;
}
/// <summary>
/// Reset the DC components, as per section F.2.1.3.1.
/// </summary>
private void ResetDcValues()
{
Unsafe.InitBlock(this.pointers.Dc, default(byte), sizeof(int) * OrigJpegDecoderCore.MaxComponents);
}

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

@ -411,6 +411,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.InitDerivedMetaDataProperties();
}
/// <summary>
/// Returns true if 'mcuCounter' is at restart interval
/// </summary>
public bool IsAtRestartInterval(int mcuCounter)
{
return this.RestartInterval > 0 && mcuCounter % this.RestartInterval == 0
&& mcuCounter < this.TotalMCUCount;
}
/// <summary>
/// Assigns derived metadata properties to <see cref="MetaData"/>, eg. horizontal and vertical resolution if it has a JFIF header.
/// </summary>

Loading…
Cancel
Save