change the brotli library
This commit is contained in:
parent
380afbf295
commit
2adda81b28
|
@ -55,11 +55,6 @@
|
|||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="BrotliSharpLib, Version=0.2.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Library\BrotliSharpLib.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Library\OpenTK.dll</HintPath>
|
||||
|
@ -142,6 +137,21 @@
|
|||
<Compile Include="AssetStudioForm.Designer.cs">
|
||||
<DependentUpon>AssetStudioForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Brotli\BitReader.cs" />
|
||||
<Compile Include="Brotli\BrotliInputStream.cs" />
|
||||
<Compile Include="Brotli\BrotliRuntimeException.cs" />
|
||||
<Compile Include="Brotli\Context.cs" />
|
||||
<Compile Include="Brotli\Decode.cs" />
|
||||
<Compile Include="Brotli\Dictionary.cs" />
|
||||
<Compile Include="Brotli\Huffman.cs" />
|
||||
<Compile Include="Brotli\HuffmanTreeGroup.cs" />
|
||||
<Compile Include="Brotli\IntReader.cs" />
|
||||
<Compile Include="Brotli\Prefix.cs" />
|
||||
<Compile Include="Brotli\RunningState.cs" />
|
||||
<Compile Include="Brotli\State.cs" />
|
||||
<Compile Include="Brotli\Transform.cs" />
|
||||
<Compile Include="Brotli\Utils.cs" />
|
||||
<Compile Include="Brotli\WordTransformType.cs" />
|
||||
<Compile Include="Classes\Animation.cs" />
|
||||
<Compile Include="Classes\AnimationClip.cs" />
|
||||
<Compile Include="Classes\Animator.cs" />
|
||||
|
|
|
@ -55,11 +55,6 @@
|
|||
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="BrotliSharpLib, Version=0.2.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Library\BrotliSharpLib.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Library\OpenTK.dll</HintPath>
|
||||
|
@ -136,6 +131,21 @@
|
|||
<Compile Include="7zip\ICoder.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Brotli\BitReader.cs" />
|
||||
<Compile Include="Brotli\BrotliInputStream.cs" />
|
||||
<Compile Include="Brotli\BrotliRuntimeException.cs" />
|
||||
<Compile Include="Brotli\Context.cs" />
|
||||
<Compile Include="Brotli\Decode.cs" />
|
||||
<Compile Include="Brotli\Dictionary.cs" />
|
||||
<Compile Include="Brotli\Huffman.cs" />
|
||||
<Compile Include="Brotli\HuffmanTreeGroup.cs" />
|
||||
<Compile Include="Brotli\IntReader.cs" />
|
||||
<Compile Include="Brotli\Prefix.cs" />
|
||||
<Compile Include="Brotli\RunningState.cs" />
|
||||
<Compile Include="Brotli\State.cs" />
|
||||
<Compile Include="Brotli\Transform.cs" />
|
||||
<Compile Include="Brotli\Utils.cs" />
|
||||
<Compile Include="Brotli\WordTransformType.cs" />
|
||||
<Compile Include="StudioClasses\SevenZipHelper.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
|
|
|
@ -0,0 +1,271 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Bit reading helpers.</summary>
|
||||
internal sealed class BitReader
|
||||
{
|
||||
/// <summary>
|
||||
/// Input byte buffer, consist of a ring-buffer and a "slack" region where bytes from the start of
|
||||
/// the ring-buffer are copied.
|
||||
/// </summary>
|
||||
private const int Capacity = 1024;
|
||||
|
||||
private const int Slack = 16;
|
||||
|
||||
private const int IntBufferSize = Capacity + Slack;
|
||||
|
||||
private const int ByteReadSize = Capacity << 2;
|
||||
|
||||
private const int ByteBufferSize = IntBufferSize << 2;
|
||||
|
||||
private readonly byte[] byteBuffer = new byte[ByteBufferSize];
|
||||
|
||||
private readonly int[] intBuffer = new int[IntBufferSize];
|
||||
|
||||
private readonly Org.Brotli.Dec.IntReader intReader = new Org.Brotli.Dec.IntReader();
|
||||
|
||||
private System.IO.Stream input;
|
||||
|
||||
/// <summary>Input stream is finished.</summary>
|
||||
private bool endOfStreamReached;
|
||||
|
||||
/// <summary>Pre-fetched bits.</summary>
|
||||
internal long accumulator;
|
||||
|
||||
/// <summary>Current bit-reading position in accumulator.</summary>
|
||||
internal int bitOffset;
|
||||
|
||||
/// <summary>Offset of next item in intBuffer.</summary>
|
||||
private int intOffset;
|
||||
|
||||
private int tailBytes = 0;
|
||||
|
||||
/* Number of bytes in unfinished "int" item. */
|
||||
/// <summary>Fills up the input buffer.</summary>
|
||||
/// <remarks>
|
||||
/// Fills up the input buffer.
|
||||
/// <p> No-op if there are at least 36 bytes present after current position.
|
||||
/// <p> After encountering the end of the input stream, 64 additional zero bytes are copied to the
|
||||
/// buffer.
|
||||
/// </remarks>
|
||||
internal static void ReadMoreInput(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
// TODO: Split to check and read; move read outside of decoding loop.
|
||||
if (br.intOffset <= Capacity - 9)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (br.endOfStreamReached)
|
||||
{
|
||||
if (IntAvailable(br) >= -2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("No more input");
|
||||
}
|
||||
int readOffset = br.intOffset << 2;
|
||||
int bytesRead = ByteReadSize - readOffset;
|
||||
System.Array.Copy(br.byteBuffer, readOffset, br.byteBuffer, 0, bytesRead);
|
||||
br.intOffset = 0;
|
||||
try
|
||||
{
|
||||
while (bytesRead < ByteReadSize)
|
||||
{
|
||||
int len = br.input.Read(br.byteBuffer, bytesRead, ByteReadSize - bytesRead);
|
||||
// EOF is -1 in Java, but 0 in C#.
|
||||
if (len <= 0)
|
||||
{
|
||||
br.endOfStreamReached = true;
|
||||
br.tailBytes = bytesRead;
|
||||
bytesRead += 3;
|
||||
break;
|
||||
}
|
||||
bytesRead += len;
|
||||
}
|
||||
}
|
||||
catch (System.IO.IOException e)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Failed to read input", e);
|
||||
}
|
||||
Org.Brotli.Dec.IntReader.Convert(br.intReader, bytesRead >> 2);
|
||||
}
|
||||
|
||||
internal static void CheckHealth(Org.Brotli.Dec.BitReader br, bool endOfStream)
|
||||
{
|
||||
if (!br.endOfStreamReached)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int byteOffset = (br.intOffset << 2) + ((br.bitOffset + 7) >> 3) - 8;
|
||||
if (byteOffset > br.tailBytes)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Read after end");
|
||||
}
|
||||
if (endOfStream && (byteOffset != br.tailBytes))
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Unused bytes after end");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Advances the Read buffer by 5 bytes to make room for reading next 24 bits.</summary>
|
||||
internal static void FillBitWindow(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
if (br.bitOffset >= 32)
|
||||
{
|
||||
br.accumulator = ((long)br.intBuffer[br.intOffset++] << 32) | ((long)(((ulong)br.accumulator) >> 32));
|
||||
br.bitOffset -= 32;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Reads the specified number of bits from Read Buffer.</summary>
|
||||
internal static int ReadBits(Org.Brotli.Dec.BitReader br, int n)
|
||||
{
|
||||
FillBitWindow(br);
|
||||
int val = (int)((long)(((ulong)br.accumulator) >> br.bitOffset)) & ((1 << n) - 1);
|
||||
br.bitOffset += n;
|
||||
return val;
|
||||
}
|
||||
|
||||
/// <summary>Initialize bit reader.</summary>
|
||||
/// <remarks>
|
||||
/// Initialize bit reader.
|
||||
/// <p> Initialisation turns bit reader to a ready state. Also a number of bytes is prefetched to
|
||||
/// accumulator. Because of that this method may block until enough data could be read from input.
|
||||
/// </remarks>
|
||||
/// <param name="br">BitReader POJO</param>
|
||||
/// <param name="input">data source</param>
|
||||
internal static void Init(Org.Brotli.Dec.BitReader br, System.IO.Stream input)
|
||||
{
|
||||
if (br.input != null)
|
||||
{
|
||||
throw new System.InvalidOperationException("Bit reader already has associated input stream");
|
||||
}
|
||||
Org.Brotli.Dec.IntReader.Init(br.intReader, br.byteBuffer, br.intBuffer);
|
||||
br.input = input;
|
||||
br.accumulator = 0;
|
||||
br.bitOffset = 64;
|
||||
br.intOffset = Capacity;
|
||||
br.endOfStreamReached = false;
|
||||
Prepare(br);
|
||||
}
|
||||
|
||||
private static void Prepare(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
ReadMoreInput(br);
|
||||
CheckHealth(br, false);
|
||||
FillBitWindow(br);
|
||||
FillBitWindow(br);
|
||||
}
|
||||
|
||||
internal static void Reload(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
if (br.bitOffset == 64)
|
||||
{
|
||||
Prepare(br);
|
||||
}
|
||||
}
|
||||
|
||||
/// <exception cref="System.IO.IOException"/>
|
||||
internal static void Close(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
System.IO.Stream @is = br.input;
|
||||
br.input = null;
|
||||
if (@is != null)
|
||||
{
|
||||
@is.Close();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void JumpToByteBoundary(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
int padding = (64 - br.bitOffset) & 7;
|
||||
if (padding != 0)
|
||||
{
|
||||
int paddingBits = Org.Brotli.Dec.BitReader.ReadBits(br, padding);
|
||||
if (paddingBits != 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Corrupted padding bits");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static int IntAvailable(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
int limit = Capacity;
|
||||
if (br.endOfStreamReached)
|
||||
{
|
||||
limit = (br.tailBytes + 3) >> 2;
|
||||
}
|
||||
return limit - br.intOffset;
|
||||
}
|
||||
|
||||
internal static void CopyBytes(Org.Brotli.Dec.BitReader br, byte[] data, int offset, int length)
|
||||
{
|
||||
if ((br.bitOffset & 7) != 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Unaligned copyBytes");
|
||||
}
|
||||
// Drain accumulator.
|
||||
while ((br.bitOffset != 64) && (length != 0))
|
||||
{
|
||||
data[offset++] = unchecked((byte)((long)(((ulong)br.accumulator) >> br.bitOffset)));
|
||||
br.bitOffset += 8;
|
||||
length--;
|
||||
}
|
||||
if (length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Get data from shadow buffer with "sizeof(int)" granularity.
|
||||
int copyInts = System.Math.Min(IntAvailable(br), length >> 2);
|
||||
if (copyInts > 0)
|
||||
{
|
||||
int readOffset = br.intOffset << 2;
|
||||
System.Array.Copy(br.byteBuffer, readOffset, data, offset, copyInts << 2);
|
||||
offset += copyInts << 2;
|
||||
length -= copyInts << 2;
|
||||
br.intOffset += copyInts;
|
||||
}
|
||||
if (length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Read tail bytes.
|
||||
if (IntAvailable(br) > 0)
|
||||
{
|
||||
// length = 1..3
|
||||
FillBitWindow(br);
|
||||
while (length != 0)
|
||||
{
|
||||
data[offset++] = unchecked((byte)((long)(((ulong)br.accumulator) >> br.bitOffset)));
|
||||
br.bitOffset += 8;
|
||||
length--;
|
||||
}
|
||||
CheckHealth(br, false);
|
||||
return;
|
||||
}
|
||||
// Now it is possible to copy bytes directly.
|
||||
try
|
||||
{
|
||||
while (length > 0)
|
||||
{
|
||||
int len = br.input.Read(data, offset, length);
|
||||
if (len == -1)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Unexpected end of input");
|
||||
}
|
||||
offset += len;
|
||||
length -= len;
|
||||
}
|
||||
}
|
||||
catch (System.IO.IOException e)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Failed to read input", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,223 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="System.IO.Stream"/>
|
||||
/// decorator that decompresses brotli data.
|
||||
/// <p> Not thread-safe.
|
||||
/// </summary>
|
||||
public class BrotliInputStream : System.IO.Stream
|
||||
{
|
||||
public const int DefaultInternalBufferSize = 16384;
|
||||
|
||||
/// <summary>Internal buffer used for efficient byte-by-byte reading.</summary>
|
||||
private byte[] buffer;
|
||||
|
||||
/// <summary>Number of decoded but still unused bytes in internal buffer.</summary>
|
||||
private int remainingBufferBytes;
|
||||
|
||||
/// <summary>Next unused byte offset.</summary>
|
||||
private int bufferOffset;
|
||||
|
||||
/// <summary>Decoder state.</summary>
|
||||
private readonly Org.Brotli.Dec.State state = new Org.Brotli.Dec.State();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a
|
||||
/// <see cref="System.IO.Stream"/>
|
||||
/// wrapper that decompresses brotli data.
|
||||
/// <p> For byte-by-byte reading (
|
||||
/// <see cref="ReadByte()"/>
|
||||
/// ) internal buffer with
|
||||
/// <see cref="DefaultInternalBufferSize"/>
|
||||
/// size is allocated and used.
|
||||
/// <p> Will block the thread until first kilobyte of data of source is available.
|
||||
/// </summary>
|
||||
/// <param name="source">underlying data source</param>
|
||||
/// <exception cref="System.IO.IOException">in case of corrupted data or source stream problems</exception>
|
||||
public BrotliInputStream(System.IO.Stream source)
|
||||
: this(source, DefaultInternalBufferSize, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a
|
||||
/// <see cref="System.IO.Stream"/>
|
||||
/// wrapper that decompresses brotli data.
|
||||
/// <p> For byte-by-byte reading (
|
||||
/// <see cref="ReadByte()"/>
|
||||
/// ) internal buffer of specified size is
|
||||
/// allocated and used.
|
||||
/// <p> Will block the thread until first kilobyte of data of source is available.
|
||||
/// </summary>
|
||||
/// <param name="source">compressed data source</param>
|
||||
/// <param name="byteReadBufferSize">
|
||||
/// size of internal buffer used in case of
|
||||
/// byte-by-byte reading
|
||||
/// </param>
|
||||
/// <exception cref="System.IO.IOException">in case of corrupted data or source stream problems</exception>
|
||||
public BrotliInputStream(System.IO.Stream source, int byteReadBufferSize)
|
||||
: this(source, byteReadBufferSize, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a
|
||||
/// <see cref="System.IO.Stream"/>
|
||||
/// wrapper that decompresses brotli data.
|
||||
/// <p> For byte-by-byte reading (
|
||||
/// <see cref="ReadByte()"/>
|
||||
/// ) internal buffer of specified size is
|
||||
/// allocated and used.
|
||||
/// <p> Will block the thread until first kilobyte of data of source is available.
|
||||
/// </summary>
|
||||
/// <param name="source">compressed data source</param>
|
||||
/// <param name="byteReadBufferSize">
|
||||
/// size of internal buffer used in case of
|
||||
/// byte-by-byte reading
|
||||
/// </param>
|
||||
/// <param name="customDictionary">
|
||||
/// custom dictionary data;
|
||||
/// <see langword="null"/>
|
||||
/// if not used
|
||||
/// </param>
|
||||
/// <exception cref="System.IO.IOException">in case of corrupted data or source stream problems</exception>
|
||||
public BrotliInputStream(System.IO.Stream source, int byteReadBufferSize, byte[] customDictionary)
|
||||
{
|
||||
if (byteReadBufferSize <= 0)
|
||||
{
|
||||
throw new System.ArgumentException("Bad buffer size:" + byteReadBufferSize);
|
||||
}
|
||||
else if (source == null)
|
||||
{
|
||||
throw new System.ArgumentException("source is null");
|
||||
}
|
||||
this.buffer = new byte[byteReadBufferSize];
|
||||
this.remainingBufferBytes = 0;
|
||||
this.bufferOffset = 0;
|
||||
try
|
||||
{
|
||||
Org.Brotli.Dec.State.SetInput(state, source);
|
||||
}
|
||||
catch (Org.Brotli.Dec.BrotliRuntimeException ex)
|
||||
{
|
||||
throw new System.IO.IOException("Brotli decoder initialization failed", ex);
|
||||
}
|
||||
if (customDictionary != null)
|
||||
{
|
||||
Org.Brotli.Dec.Decode.SetCustomDictionary(state, customDictionary);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary><inheritDoc/></summary>
|
||||
/// <exception cref="System.IO.IOException"/>
|
||||
public override void Close()
|
||||
{
|
||||
Org.Brotli.Dec.State.Close(state);
|
||||
}
|
||||
|
||||
/// <summary><inheritDoc/></summary>
|
||||
/// <exception cref="System.IO.IOException"/>
|
||||
public override int ReadByte()
|
||||
{
|
||||
if (bufferOffset >= remainingBufferBytes)
|
||||
{
|
||||
remainingBufferBytes = Read(buffer, 0, buffer.Length);
|
||||
bufferOffset = 0;
|
||||
if (remainingBufferBytes == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return buffer[bufferOffset++] & unchecked((int)(0xFF));
|
||||
}
|
||||
|
||||
/// <summary><inheritDoc/></summary>
|
||||
/// <exception cref="System.IO.IOException"/>
|
||||
public override int Read(byte[] destBuffer, int destOffset, int destLen)
|
||||
{
|
||||
if (destOffset < 0)
|
||||
{
|
||||
throw new System.ArgumentException("Bad offset: " + destOffset);
|
||||
}
|
||||
else if (destLen < 0)
|
||||
{
|
||||
throw new System.ArgumentException("Bad length: " + destLen);
|
||||
}
|
||||
else if (destOffset + destLen > destBuffer.Length)
|
||||
{
|
||||
throw new System.ArgumentException("Buffer overflow: " + (destOffset + destLen) + " > " + destBuffer.Length);
|
||||
}
|
||||
else if (destLen == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int copyLen = System.Math.Max(remainingBufferBytes - bufferOffset, 0);
|
||||
if (copyLen != 0)
|
||||
{
|
||||
copyLen = System.Math.Min(copyLen, destLen);
|
||||
System.Array.Copy(buffer, bufferOffset, destBuffer, destOffset, copyLen);
|
||||
bufferOffset += copyLen;
|
||||
destOffset += copyLen;
|
||||
destLen -= copyLen;
|
||||
if (destLen == 0)
|
||||
{
|
||||
return copyLen;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
state.output = destBuffer;
|
||||
state.outputOffset = destOffset;
|
||||
state.outputLength = destLen;
|
||||
state.outputUsed = 0;
|
||||
Org.Brotli.Dec.Decode.Decompress(state);
|
||||
if (state.outputUsed == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return state.outputUsed + copyLen;
|
||||
}
|
||||
catch (Org.Brotli.Dec.BrotliRuntimeException ex)
|
||||
{
|
||||
throw new System.IO.IOException("Brotli stream decoding failed", ex);
|
||||
}
|
||||
}
|
||||
// <{[INJECTED CODE]}>
|
||||
public override bool CanRead {
|
||||
get {return true;}
|
||||
}
|
||||
|
||||
public override bool CanSeek {
|
||||
get {return false;}
|
||||
}
|
||||
public override long Length {
|
||||
get {throw new System.NotSupportedException();}
|
||||
}
|
||||
public override long Position {
|
||||
get {throw new System.NotSupportedException();}
|
||||
set {throw new System.NotSupportedException();}
|
||||
}
|
||||
public override long Seek(long offset, System.IO.SeekOrigin origin) {
|
||||
throw new System.NotSupportedException();
|
||||
}
|
||||
public override void SetLength(long value){
|
||||
throw new System.NotSupportedException();
|
||||
}
|
||||
|
||||
public override bool CanWrite{get{return false;}}
|
||||
public override System.IAsyncResult BeginWrite(byte[] buffer, int offset,
|
||||
int count, System.AsyncCallback callback, object state) {
|
||||
throw new System.NotSupportedException();
|
||||
}
|
||||
public override void Write(byte[] buffer, int offset, int count) {
|
||||
throw new System.NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Flush() {}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Unchecked exception used internally.</summary>
|
||||
[System.Serializable]
|
||||
internal class BrotliRuntimeException : System.Exception
|
||||
{
|
||||
internal BrotliRuntimeException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
internal BrotliRuntimeException(string message, System.Exception cause)
|
||||
: base(message, cause)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Common context lookup table for all context modes.</summary>
|
||||
internal sealed class Context
|
||||
{
|
||||
internal static readonly int[] Lookup = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12, 44, 44, 44, 44, 44, 44, 44, 44
|
||||
, 44, 44, 32, 32, 24, 40, 28, 12, 12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12, 12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56, 60, 60, 60, 60
|
||||
, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
|
||||
1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
||||
40, 40, 40, 40, 40, 40, 40, 40, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38
|
||||
, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
|
||||
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35
|
||||
, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
|
||||
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,
|
||||
10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24,
|
||||
25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
|
||||
40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54,
|
||||
55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
internal static readonly int[] LookupOffsets = new int[] { 1024, 1536, 1280, 1536, 0, 256, 768, 512 };
|
||||
// CONTEXT_UTF8, last byte.
|
||||
// ASCII range.
|
||||
// UTF8 continuation byte range.
|
||||
// UTF8 lead byte range.
|
||||
// CONTEXT_UTF8 second last byte.
|
||||
// ASCII range.
|
||||
// UTF8 continuation byte range.
|
||||
// UTF8 lead byte range.
|
||||
// CONTEXT_SIGNED, second last byte.
|
||||
// CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits.
|
||||
// CONTEXT_LSB6, last byte.
|
||||
// CONTEXT_MSB6, last byte.
|
||||
// CONTEXT_{M,L}SB6, second last byte,
|
||||
// CONTEXT_LSB6
|
||||
// CONTEXT_MSB6
|
||||
// CONTEXT_UTF8
|
||||
// CONTEXT_SIGNED
|
||||
}
|
||||
}
|
|
@ -0,0 +1,992 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>API for Brotli decompression.</summary>
|
||||
internal sealed class Decode
|
||||
{
|
||||
private const int DefaultCodeLength = 8;
|
||||
|
||||
private const int CodeLengthRepeatCode = 16;
|
||||
|
||||
private const int NumLiteralCodes = 256;
|
||||
|
||||
private const int NumInsertAndCopyCodes = 704;
|
||||
|
||||
private const int NumBlockLengthCodes = 26;
|
||||
|
||||
private const int LiteralContextBits = 6;
|
||||
|
||||
private const int DistanceContextBits = 2;
|
||||
|
||||
private const int HuffmanTableBits = 8;
|
||||
|
||||
private const int HuffmanTableMask = unchecked((int)(0xFF));
|
||||
|
||||
private const int CodeLengthCodes = 18;
|
||||
|
||||
private static readonly int[] CodeLengthCodeOrder = new int[] { 1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||
|
||||
private const int NumDistanceShortCodes = 16;
|
||||
|
||||
private static readonly int[] DistanceShortCodeIndexOffset = new int[] { 3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
|
||||
|
||||
private static readonly int[] DistanceShortCodeValueOffset = new int[] { 0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3 };
|
||||
|
||||
/// <summary>Static Huffman code for the code length code lengths.</summary>
|
||||
private static readonly int[] FixedTable = new int[] { unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003)), unchecked((int)(0x030002)), unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003
|
||||
)), unchecked((int)(0x040001)), unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003)), unchecked((int)(0x030002)), unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003)), unchecked((int
|
||||
)(0x040005)) };
|
||||
|
||||
/// <summary>Decodes a number in the range [0..255], by reading 1 - 11 bits.</summary>
|
||||
private static int DecodeVarLenUnsignedByte(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) != 0)
|
||||
{
|
||||
int n = Org.Brotli.Dec.BitReader.ReadBits(br, 3);
|
||||
if (n == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Org.Brotli.Dec.BitReader.ReadBits(br, n) + (1 << n);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static void DecodeMetaBlockLength(Org.Brotli.Dec.BitReader br, Org.Brotli.Dec.State state)
|
||||
{
|
||||
state.inputEnd = Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1;
|
||||
state.metaBlockLength = 0;
|
||||
state.isUncompressed = false;
|
||||
state.isMetadata = false;
|
||||
if (state.inputEnd && Org.Brotli.Dec.BitReader.ReadBits(br, 1) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int sizeNibbles = Org.Brotli.Dec.BitReader.ReadBits(br, 2) + 4;
|
||||
if (sizeNibbles == 7)
|
||||
{
|
||||
state.isMetadata = true;
|
||||
if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) != 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Corrupted reserved bit");
|
||||
}
|
||||
int sizeBytes = Org.Brotli.Dec.BitReader.ReadBits(br, 2);
|
||||
if (sizeBytes == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < sizeBytes; i++)
|
||||
{
|
||||
int bits = Org.Brotli.Dec.BitReader.ReadBits(br, 8);
|
||||
if (bits == 0 && i + 1 == sizeBytes && sizeBytes > 1)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Exuberant nibble");
|
||||
}
|
||||
state.metaBlockLength |= bits << (i * 8);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < sizeNibbles; i++)
|
||||
{
|
||||
int bits = Org.Brotli.Dec.BitReader.ReadBits(br, 4);
|
||||
if (bits == 0 && i + 1 == sizeNibbles && sizeNibbles > 4)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Exuberant nibble");
|
||||
}
|
||||
state.metaBlockLength |= bits << (i * 4);
|
||||
}
|
||||
}
|
||||
state.metaBlockLength++;
|
||||
if (!state.inputEnd)
|
||||
{
|
||||
state.isUncompressed = Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Decodes the next Huffman code from bit-stream.</summary>
|
||||
private static int ReadSymbol(int[] table, int offset, Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
int val = (int)((long)(((ulong)br.accumulator) >> br.bitOffset));
|
||||
offset += val & HuffmanTableMask;
|
||||
int bits = table[offset] >> 16;
|
||||
int sym = table[offset] & unchecked((int)(0xFFFF));
|
||||
if (bits <= HuffmanTableBits)
|
||||
{
|
||||
br.bitOffset += bits;
|
||||
return sym;
|
||||
}
|
||||
offset += sym;
|
||||
int mask = (1 << bits) - 1;
|
||||
offset += (int)(((uint)(val & mask)) >> HuffmanTableBits);
|
||||
br.bitOffset += ((table[offset] >> 16) + HuffmanTableBits);
|
||||
return table[offset] & unchecked((int)(0xFFFF));
|
||||
}
|
||||
|
||||
private static int ReadBlockLength(int[] table, int offset, Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
int code = ReadSymbol(table, offset, br);
|
||||
int n = Org.Brotli.Dec.Prefix.BlockLengthNBits[code];
|
||||
return Org.Brotli.Dec.Prefix.BlockLengthOffset[code] + Org.Brotli.Dec.BitReader.ReadBits(br, n);
|
||||
}
|
||||
|
||||
private static int TranslateShortCodes(int code, int[] ringBuffer, int index)
|
||||
{
|
||||
if (code < NumDistanceShortCodes)
|
||||
{
|
||||
index += DistanceShortCodeIndexOffset[code];
|
||||
index &= 3;
|
||||
return ringBuffer[index] + DistanceShortCodeValueOffset[code];
|
||||
}
|
||||
return code - NumDistanceShortCodes + 1;
|
||||
}
|
||||
|
||||
private static void MoveToFront(int[] v, int index)
|
||||
{
|
||||
int value = v[index];
|
||||
for (; index > 0; index--)
|
||||
{
|
||||
v[index] = v[index - 1];
|
||||
}
|
||||
v[0] = value;
|
||||
}
|
||||
|
||||
private static void InverseMoveToFrontTransform(byte[] v, int vLen)
|
||||
{
|
||||
int[] mtf = new int[256];
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
mtf[i] = i;
|
||||
}
|
||||
for (int i = 0; i < vLen; i++)
|
||||
{
|
||||
int index = v[i] & unchecked((int)(0xFF));
|
||||
v[i] = unchecked((byte)mtf[index]);
|
||||
if (index != 0)
|
||||
{
|
||||
MoveToFront(mtf, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReadHuffmanCodeLengths(int[] codeLengthCodeLengths, int numSymbols, int[] codeLengths, Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
int symbol = 0;
|
||||
int prevCodeLen = DefaultCodeLength;
|
||||
int repeat = 0;
|
||||
int repeatCodeLen = 0;
|
||||
int space = 32768;
|
||||
int[] table = new int[32];
|
||||
Org.Brotli.Dec.Huffman.BuildHuffmanTable(table, 0, 5, codeLengthCodeLengths, CodeLengthCodes);
|
||||
while (symbol < numSymbols && space > 0)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
int p = (int)(((long)(((ulong)br.accumulator) >> br.bitOffset))) & 31;
|
||||
br.bitOffset += table[p] >> 16;
|
||||
int codeLen = table[p] & unchecked((int)(0xFFFF));
|
||||
if (codeLen < CodeLengthRepeatCode)
|
||||
{
|
||||
repeat = 0;
|
||||
codeLengths[symbol++] = codeLen;
|
||||
if (codeLen != 0)
|
||||
{
|
||||
prevCodeLen = codeLen;
|
||||
space -= 32768 >> codeLen;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int extraBits = codeLen - 14;
|
||||
int newLen = 0;
|
||||
if (codeLen == CodeLengthRepeatCode)
|
||||
{
|
||||
newLen = prevCodeLen;
|
||||
}
|
||||
if (repeatCodeLen != newLen)
|
||||
{
|
||||
repeat = 0;
|
||||
repeatCodeLen = newLen;
|
||||
}
|
||||
int oldRepeat = repeat;
|
||||
if (repeat > 0)
|
||||
{
|
||||
repeat -= 2;
|
||||
repeat <<= extraBits;
|
||||
}
|
||||
repeat += Org.Brotli.Dec.BitReader.ReadBits(br, extraBits) + 3;
|
||||
int repeatDelta = repeat - oldRepeat;
|
||||
if (symbol + repeatDelta > numSymbols)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("symbol + repeatDelta > numSymbols");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
for (int i = 0; i < repeatDelta; i++)
|
||||
{
|
||||
codeLengths[symbol++] = repeatCodeLen;
|
||||
}
|
||||
if (repeatCodeLen != 0)
|
||||
{
|
||||
space -= repeatDelta << (15 - repeatCodeLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (space != 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Unused space");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
// TODO: Pass max_symbol to Huffman table builder instead?
|
||||
Org.Brotli.Dec.Utils.FillWithZeroes(codeLengths, symbol, numSymbols - symbol);
|
||||
}
|
||||
|
||||
// TODO: Use specialized versions for smaller tables.
|
||||
internal static void ReadHuffmanCode(int alphabetSize, int[] table, int offset, Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
bool ok = true;
|
||||
int simpleCodeOrSkip;
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
// TODO: Avoid allocation.
|
||||
int[] codeLengths = new int[alphabetSize];
|
||||
simpleCodeOrSkip = Org.Brotli.Dec.BitReader.ReadBits(br, 2);
|
||||
if (simpleCodeOrSkip == 1)
|
||||
{
|
||||
// Read symbols, codes & code lengths directly.
|
||||
int maxBitsCounter = alphabetSize - 1;
|
||||
int maxBits = 0;
|
||||
int[] symbols = new int[4];
|
||||
int numSymbols = Org.Brotli.Dec.BitReader.ReadBits(br, 2) + 1;
|
||||
while (maxBitsCounter != 0)
|
||||
{
|
||||
maxBitsCounter >>= 1;
|
||||
maxBits++;
|
||||
}
|
||||
// TODO: uncomment when codeLengths is reused.
|
||||
// Utils.fillWithZeroes(codeLengths, 0, alphabetSize);
|
||||
for (int i = 0; i < numSymbols; i++)
|
||||
{
|
||||
symbols[i] = Org.Brotli.Dec.BitReader.ReadBits(br, maxBits) % alphabetSize;
|
||||
codeLengths[symbols[i]] = 2;
|
||||
}
|
||||
codeLengths[symbols[0]] = 1;
|
||||
switch (numSymbols)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
ok = symbols[0] != symbols[1];
|
||||
codeLengths[symbols[1]] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
ok = symbols[0] != symbols[1] && symbols[0] != symbols[2] && symbols[1] != symbols[2];
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
default:
|
||||
{
|
||||
ok = symbols[0] != symbols[1] && symbols[0] != symbols[2] && symbols[0] != symbols[3] && symbols[1] != symbols[2] && symbols[1] != symbols[3] && symbols[2] != symbols[3];
|
||||
if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1)
|
||||
{
|
||||
codeLengths[symbols[2]] = 3;
|
||||
codeLengths[symbols[3]] = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
codeLengths[symbols[0]] = 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Decode Huffman-coded code lengths.
|
||||
int[] codeLengthCodeLengths = new int[CodeLengthCodes];
|
||||
int space = 32;
|
||||
int numCodes = 0;
|
||||
for (int i = simpleCodeOrSkip; i < CodeLengthCodes && space > 0; i++)
|
||||
{
|
||||
int codeLenIdx = CodeLengthCodeOrder[i];
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
int p = (int)((long)(((ulong)br.accumulator) >> br.bitOffset)) & 15;
|
||||
// TODO: Demultiplex FIXED_TABLE.
|
||||
br.bitOffset += FixedTable[p] >> 16;
|
||||
int v = FixedTable[p] & unchecked((int)(0xFFFF));
|
||||
codeLengthCodeLengths[codeLenIdx] = v;
|
||||
if (v != 0)
|
||||
{
|
||||
space -= (32 >> v);
|
||||
numCodes++;
|
||||
}
|
||||
}
|
||||
ok = (numCodes == 1 || space == 0);
|
||||
ReadHuffmanCodeLengths(codeLengthCodeLengths, alphabetSize, codeLengths, br);
|
||||
}
|
||||
if (!ok)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Can't readHuffmanCode");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
Org.Brotli.Dec.Huffman.BuildHuffmanTable(table, offset, HuffmanTableBits, codeLengths, alphabetSize);
|
||||
}
|
||||
|
||||
private static int DecodeContextMap(int contextMapSize, byte[] contextMap, Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
int numTrees = DecodeVarLenUnsignedByte(br) + 1;
|
||||
if (numTrees == 1)
|
||||
{
|
||||
Org.Brotli.Dec.Utils.FillWithZeroes(contextMap, 0, contextMapSize);
|
||||
return numTrees;
|
||||
}
|
||||
bool useRleForZeros = Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1;
|
||||
int maxRunLengthPrefix = 0;
|
||||
if (useRleForZeros)
|
||||
{
|
||||
maxRunLengthPrefix = Org.Brotli.Dec.BitReader.ReadBits(br, 4) + 1;
|
||||
}
|
||||
int[] table = new int[Org.Brotli.Dec.Huffman.HuffmanMaxTableSize];
|
||||
ReadHuffmanCode(numTrees + maxRunLengthPrefix, table, 0, br);
|
||||
for (int i = 0; i < contextMapSize; )
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
int code = ReadSymbol(table, 0, br);
|
||||
if (code == 0)
|
||||
{
|
||||
contextMap[i] = 0;
|
||||
i++;
|
||||
}
|
||||
else if (code <= maxRunLengthPrefix)
|
||||
{
|
||||
int reps = (1 << code) + Org.Brotli.Dec.BitReader.ReadBits(br, code);
|
||||
while (reps != 0)
|
||||
{
|
||||
if (i >= contextMapSize)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Corrupted context map");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
contextMap[i] = 0;
|
||||
i++;
|
||||
reps--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
contextMap[i] = unchecked((byte)(code - maxRunLengthPrefix));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1)
|
||||
{
|
||||
InverseMoveToFrontTransform(contextMap, contextMapSize);
|
||||
}
|
||||
return numTrees;
|
||||
}
|
||||
|
||||
private static void DecodeBlockTypeAndLength(Org.Brotli.Dec.State state, int treeType)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader br = state.br;
|
||||
int[] ringBuffers = state.blockTypeRb;
|
||||
int offset = treeType * 2;
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
int blockType = ReadSymbol(state.blockTypeTrees, treeType * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
|
||||
state.blockLength[treeType] = ReadBlockLength(state.blockLenTrees, treeType * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
|
||||
if (blockType == 1)
|
||||
{
|
||||
blockType = ringBuffers[offset + 1] + 1;
|
||||
}
|
||||
else if (blockType == 0)
|
||||
{
|
||||
blockType = ringBuffers[offset];
|
||||
}
|
||||
else
|
||||
{
|
||||
blockType -= 2;
|
||||
}
|
||||
if (blockType >= state.numBlockTypes[treeType])
|
||||
{
|
||||
blockType -= state.numBlockTypes[treeType];
|
||||
}
|
||||
ringBuffers[offset] = ringBuffers[offset + 1];
|
||||
ringBuffers[offset + 1] = blockType;
|
||||
}
|
||||
|
||||
private static void DecodeLiteralBlockSwitch(Org.Brotli.Dec.State state)
|
||||
{
|
||||
DecodeBlockTypeAndLength(state, 0);
|
||||
int literalBlockType = state.blockTypeRb[1];
|
||||
state.contextMapSlice = literalBlockType << LiteralContextBits;
|
||||
state.literalTreeIndex = state.contextMap[state.contextMapSlice] & unchecked((int)(0xFF));
|
||||
state.literalTree = state.hGroup0.trees[state.literalTreeIndex];
|
||||
int contextMode = state.contextModes[literalBlockType];
|
||||
state.contextLookupOffset1 = Org.Brotli.Dec.Context.LookupOffsets[contextMode];
|
||||
state.contextLookupOffset2 = Org.Brotli.Dec.Context.LookupOffsets[contextMode + 1];
|
||||
}
|
||||
|
||||
private static void DecodeCommandBlockSwitch(Org.Brotli.Dec.State state)
|
||||
{
|
||||
DecodeBlockTypeAndLength(state, 1);
|
||||
state.treeCommandOffset = state.hGroup1.trees[state.blockTypeRb[3]];
|
||||
}
|
||||
|
||||
private static void DecodeDistanceBlockSwitch(Org.Brotli.Dec.State state)
|
||||
{
|
||||
DecodeBlockTypeAndLength(state, 2);
|
||||
state.distContextMapSlice = state.blockTypeRb[5] << DistanceContextBits;
|
||||
}
|
||||
|
||||
private static void MaybeReallocateRingBuffer(Org.Brotli.Dec.State state)
|
||||
{
|
||||
int newSize = state.maxRingBufferSize;
|
||||
if ((long)newSize > state.expectedTotalSize)
|
||||
{
|
||||
/* TODO: Handle 2GB+ cases more gracefully. */
|
||||
int minimalNewSize = (int)state.expectedTotalSize + state.customDictionary.Length;
|
||||
while ((newSize >> 1) > minimalNewSize)
|
||||
{
|
||||
newSize >>= 1;
|
||||
}
|
||||
if (!state.inputEnd && newSize < 16384 && state.maxRingBufferSize >= 16384)
|
||||
{
|
||||
newSize = 16384;
|
||||
}
|
||||
}
|
||||
if (newSize <= state.ringBufferSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int ringBufferSizeWithSlack = newSize + Org.Brotli.Dec.Dictionary.MaxTransformedWordLength;
|
||||
byte[] newBuffer = new byte[ringBufferSizeWithSlack];
|
||||
if (state.ringBuffer != null)
|
||||
{
|
||||
System.Array.Copy(state.ringBuffer, 0, newBuffer, 0, state.ringBufferSize);
|
||||
}
|
||||
else if (state.customDictionary.Length != 0)
|
||||
{
|
||||
/* Prepend custom dictionary, if any. */
|
||||
int length = state.customDictionary.Length;
|
||||
int offset = 0;
|
||||
if (length > state.maxBackwardDistance)
|
||||
{
|
||||
offset = length - state.maxBackwardDistance;
|
||||
length = state.maxBackwardDistance;
|
||||
}
|
||||
System.Array.Copy(state.customDictionary, offset, newBuffer, 0, length);
|
||||
state.pos = length;
|
||||
state.bytesToIgnore = length;
|
||||
}
|
||||
state.ringBuffer = newBuffer;
|
||||
state.ringBufferSize = newSize;
|
||||
}
|
||||
|
||||
/// <summary>Reads next metablock header.</summary>
|
||||
/// <param name="state">decoding state</param>
|
||||
private static void ReadMetablockInfo(Org.Brotli.Dec.State state)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader br = state.br;
|
||||
if (state.inputEnd)
|
||||
{
|
||||
state.nextRunningState = Org.Brotli.Dec.RunningState.Finished;
|
||||
state.bytesToWrite = state.pos;
|
||||
state.bytesWritten = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Write;
|
||||
return;
|
||||
}
|
||||
// TODO: Reset? Do we need this?
|
||||
state.hGroup0.codes = null;
|
||||
state.hGroup0.trees = null;
|
||||
state.hGroup1.codes = null;
|
||||
state.hGroup1.trees = null;
|
||||
state.hGroup2.codes = null;
|
||||
state.hGroup2.trees = null;
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
DecodeMetaBlockLength(br, state);
|
||||
if (state.metaBlockLength == 0 && !state.isMetadata)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (state.isUncompressed || state.isMetadata)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.JumpToByteBoundary(br);
|
||||
state.runningState = state.isMetadata ? Org.Brotli.Dec.RunningState.ReadMetadata : Org.Brotli.Dec.RunningState.CopyUncompressed;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.runningState = Org.Brotli.Dec.RunningState.CompressedBlockStart;
|
||||
}
|
||||
if (state.isMetadata)
|
||||
{
|
||||
return;
|
||||
}
|
||||
state.expectedTotalSize += state.metaBlockLength;
|
||||
if (state.ringBufferSize < state.maxRingBufferSize)
|
||||
{
|
||||
MaybeReallocateRingBuffer(state);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReadMetablockHuffmanCodesAndContextMaps(Org.Brotli.Dec.State state)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader br = state.br;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
state.numBlockTypes[i] = DecodeVarLenUnsignedByte(br) + 1;
|
||||
state.blockLength[i] = 1 << 28;
|
||||
if (state.numBlockTypes[i] > 1)
|
||||
{
|
||||
ReadHuffmanCode(state.numBlockTypes[i] + 2, state.blockTypeTrees, i * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
|
||||
ReadHuffmanCode(NumBlockLengthCodes, state.blockLenTrees, i * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
|
||||
state.blockLength[i] = ReadBlockLength(state.blockLenTrees, i * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
|
||||
}
|
||||
}
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
state.distancePostfixBits = Org.Brotli.Dec.BitReader.ReadBits(br, 2);
|
||||
state.numDirectDistanceCodes = NumDistanceShortCodes + (Org.Brotli.Dec.BitReader.ReadBits(br, 4) << state.distancePostfixBits);
|
||||
state.distancePostfixMask = (1 << state.distancePostfixBits) - 1;
|
||||
int numDistanceCodes = state.numDirectDistanceCodes + (48 << state.distancePostfixBits);
|
||||
// TODO: Reuse?
|
||||
state.contextModes = new byte[state.numBlockTypes[0]];
|
||||
for (int i = 0; i < state.numBlockTypes[0]; )
|
||||
{
|
||||
/* Ensure that less than 256 bits read between readMoreInput. */
|
||||
int limit = System.Math.Min(i + 96, state.numBlockTypes[0]);
|
||||
for (; i < limit; ++i)
|
||||
{
|
||||
state.contextModes[i] = unchecked((byte)(Org.Brotli.Dec.BitReader.ReadBits(br, 2) << 1));
|
||||
}
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
}
|
||||
// TODO: Reuse?
|
||||
state.contextMap = new byte[state.numBlockTypes[0] << LiteralContextBits];
|
||||
int numLiteralTrees = DecodeContextMap(state.numBlockTypes[0] << LiteralContextBits, state.contextMap, br);
|
||||
state.trivialLiteralContext = true;
|
||||
for (int j = 0; j < state.numBlockTypes[0] << LiteralContextBits; j++)
|
||||
{
|
||||
if (state.contextMap[j] != j >> LiteralContextBits)
|
||||
{
|
||||
state.trivialLiteralContext = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO: Reuse?
|
||||
state.distContextMap = new byte[state.numBlockTypes[2] << DistanceContextBits];
|
||||
int numDistTrees = DecodeContextMap(state.numBlockTypes[2] << DistanceContextBits, state.distContextMap, br);
|
||||
Org.Brotli.Dec.HuffmanTreeGroup.Init(state.hGroup0, NumLiteralCodes, numLiteralTrees);
|
||||
Org.Brotli.Dec.HuffmanTreeGroup.Init(state.hGroup1, NumInsertAndCopyCodes, state.numBlockTypes[1]);
|
||||
Org.Brotli.Dec.HuffmanTreeGroup.Init(state.hGroup2, numDistanceCodes, numDistTrees);
|
||||
Org.Brotli.Dec.HuffmanTreeGroup.Decode(state.hGroup0, br);
|
||||
Org.Brotli.Dec.HuffmanTreeGroup.Decode(state.hGroup1, br);
|
||||
Org.Brotli.Dec.HuffmanTreeGroup.Decode(state.hGroup2, br);
|
||||
state.contextMapSlice = 0;
|
||||
state.distContextMapSlice = 0;
|
||||
state.contextLookupOffset1 = Org.Brotli.Dec.Context.LookupOffsets[state.contextModes[0]];
|
||||
state.contextLookupOffset2 = Org.Brotli.Dec.Context.LookupOffsets[state.contextModes[0] + 1];
|
||||
state.literalTreeIndex = 0;
|
||||
state.literalTree = state.hGroup0.trees[0];
|
||||
state.treeCommandOffset = state.hGroup1.trees[0];
|
||||
// TODO: == 0?
|
||||
state.blockTypeRb[0] = state.blockTypeRb[2] = state.blockTypeRb[4] = 1;
|
||||
state.blockTypeRb[1] = state.blockTypeRb[3] = state.blockTypeRb[5] = 0;
|
||||
}
|
||||
|
||||
private static void CopyUncompressedData(Org.Brotli.Dec.State state)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader br = state.br;
|
||||
byte[] ringBuffer = state.ringBuffer;
|
||||
// Could happen if block ends at ring buffer end.
|
||||
if (state.metaBlockLength <= 0)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.Reload(br);
|
||||
state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
|
||||
return;
|
||||
}
|
||||
int chunkLength = System.Math.Min(state.ringBufferSize - state.pos, state.metaBlockLength);
|
||||
Org.Brotli.Dec.BitReader.CopyBytes(br, ringBuffer, state.pos, chunkLength);
|
||||
state.metaBlockLength -= chunkLength;
|
||||
state.pos += chunkLength;
|
||||
if (state.pos == state.ringBufferSize)
|
||||
{
|
||||
state.nextRunningState = Org.Brotli.Dec.RunningState.CopyUncompressed;
|
||||
state.bytesToWrite = state.ringBufferSize;
|
||||
state.bytesWritten = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Write;
|
||||
return;
|
||||
}
|
||||
Org.Brotli.Dec.BitReader.Reload(br);
|
||||
state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
|
||||
}
|
||||
|
||||
private static bool WriteRingBuffer(Org.Brotli.Dec.State state)
|
||||
{
|
||||
/* Ignore custom dictionary bytes. */
|
||||
if (state.bytesToIgnore != 0)
|
||||
{
|
||||
state.bytesWritten += state.bytesToIgnore;
|
||||
state.bytesToIgnore = 0;
|
||||
}
|
||||
int toWrite = System.Math.Min(state.outputLength - state.outputUsed, state.bytesToWrite - state.bytesWritten);
|
||||
if (toWrite != 0)
|
||||
{
|
||||
System.Array.Copy(state.ringBuffer, state.bytesWritten, state.output, state.outputOffset + state.outputUsed, toWrite);
|
||||
state.outputUsed += toWrite;
|
||||
state.bytesWritten += toWrite;
|
||||
}
|
||||
return state.outputUsed < state.outputLength;
|
||||
}
|
||||
|
||||
internal static void SetCustomDictionary(Org.Brotli.Dec.State state, byte[] data)
|
||||
{
|
||||
state.customDictionary = (data == null) ? new byte[0] : data;
|
||||
}
|
||||
|
||||
/// <summary>Actual decompress implementation.</summary>
|
||||
internal static void Decompress(Org.Brotli.Dec.State state)
|
||||
{
|
||||
if (state.runningState == Org.Brotli.Dec.RunningState.Uninitialized)
|
||||
{
|
||||
throw new System.InvalidOperationException("Can't decompress until initialized");
|
||||
}
|
||||
if (state.runningState == Org.Brotli.Dec.RunningState.Closed)
|
||||
{
|
||||
throw new System.InvalidOperationException("Can't decompress after close");
|
||||
}
|
||||
Org.Brotli.Dec.BitReader br = state.br;
|
||||
int ringBufferMask = state.ringBufferSize - 1;
|
||||
byte[] ringBuffer = state.ringBuffer;
|
||||
while (state.runningState != Org.Brotli.Dec.RunningState.Finished)
|
||||
{
|
||||
switch (state.runningState)
|
||||
{
|
||||
case Org.Brotli.Dec.RunningState.BlockStart:
|
||||
{
|
||||
// TODO: extract cases to methods for the better readability.
|
||||
if (state.metaBlockLength < 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid metablock length");
|
||||
}
|
||||
ReadMetablockInfo(state);
|
||||
/* Ring-buffer would be reallocated here. */
|
||||
ringBufferMask = state.ringBufferSize - 1;
|
||||
ringBuffer = state.ringBuffer;
|
||||
continue;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.CompressedBlockStart:
|
||||
{
|
||||
ReadMetablockHuffmanCodesAndContextMaps(state);
|
||||
state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
|
||||
goto case Org.Brotli.Dec.RunningState.MainLoop;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.MainLoop:
|
||||
{
|
||||
// Fall through
|
||||
if (state.metaBlockLength <= 0)
|
||||
{
|
||||
state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
|
||||
continue;
|
||||
}
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
if (state.blockLength[1] == 0)
|
||||
{
|
||||
DecodeCommandBlockSwitch(state);
|
||||
}
|
||||
state.blockLength[1]--;
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
int cmdCode = ReadSymbol(state.hGroup1.codes, state.treeCommandOffset, br);
|
||||
int rangeIdx = (int)(((uint)cmdCode) >> 6);
|
||||
state.distanceCode = 0;
|
||||
if (rangeIdx >= 2)
|
||||
{
|
||||
rangeIdx -= 2;
|
||||
state.distanceCode = -1;
|
||||
}
|
||||
int insertCode = Org.Brotli.Dec.Prefix.InsertRangeLut[rangeIdx] + (((int)(((uint)cmdCode) >> 3)) & 7);
|
||||
int copyCode = Org.Brotli.Dec.Prefix.CopyRangeLut[rangeIdx] + (cmdCode & 7);
|
||||
state.insertLength = Org.Brotli.Dec.Prefix.InsertLengthOffset[insertCode] + Org.Brotli.Dec.BitReader.ReadBits(br, Org.Brotli.Dec.Prefix.InsertLengthNBits[insertCode]);
|
||||
state.copyLength = Org.Brotli.Dec.Prefix.CopyLengthOffset[copyCode] + Org.Brotli.Dec.BitReader.ReadBits(br, Org.Brotli.Dec.Prefix.CopyLengthNBits[copyCode]);
|
||||
state.j = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.InsertLoop;
|
||||
goto case Org.Brotli.Dec.RunningState.InsertLoop;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.InsertLoop:
|
||||
{
|
||||
// Fall through
|
||||
if (state.trivialLiteralContext)
|
||||
{
|
||||
while (state.j < state.insertLength)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
if (state.blockLength[0] == 0)
|
||||
{
|
||||
DecodeLiteralBlockSwitch(state);
|
||||
}
|
||||
state.blockLength[0]--;
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
ringBuffer[state.pos] = unchecked((byte)ReadSymbol(state.hGroup0.codes, state.literalTree, br));
|
||||
state.j++;
|
||||
if (state.pos++ == ringBufferMask)
|
||||
{
|
||||
state.nextRunningState = Org.Brotli.Dec.RunningState.InsertLoop;
|
||||
state.bytesToWrite = state.ringBufferSize;
|
||||
state.bytesWritten = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Write;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int prevByte1 = ringBuffer[(state.pos - 1) & ringBufferMask] & unchecked((int)(0xFF));
|
||||
int prevByte2 = ringBuffer[(state.pos - 2) & ringBufferMask] & unchecked((int)(0xFF));
|
||||
while (state.j < state.insertLength)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
if (state.blockLength[0] == 0)
|
||||
{
|
||||
DecodeLiteralBlockSwitch(state);
|
||||
}
|
||||
int literalTreeIndex = state.contextMap[state.contextMapSlice + (Org.Brotli.Dec.Context.Lookup[state.contextLookupOffset1 + prevByte1] | Org.Brotli.Dec.Context.Lookup[state.contextLookupOffset2 + prevByte2])] & unchecked((int)(0xFF));
|
||||
state.blockLength[0]--;
|
||||
prevByte2 = prevByte1;
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
prevByte1 = ReadSymbol(state.hGroup0.codes, state.hGroup0.trees[literalTreeIndex], br);
|
||||
ringBuffer[state.pos] = unchecked((byte)prevByte1);
|
||||
state.j++;
|
||||
if (state.pos++ == ringBufferMask)
|
||||
{
|
||||
state.nextRunningState = Org.Brotli.Dec.RunningState.InsertLoop;
|
||||
state.bytesToWrite = state.ringBufferSize;
|
||||
state.bytesWritten = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Write;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state.runningState != Org.Brotli.Dec.RunningState.InsertLoop)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
state.metaBlockLength -= state.insertLength;
|
||||
if (state.metaBlockLength <= 0)
|
||||
{
|
||||
state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
|
||||
continue;
|
||||
}
|
||||
if (state.distanceCode < 0)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
if (state.blockLength[2] == 0)
|
||||
{
|
||||
DecodeDistanceBlockSwitch(state);
|
||||
}
|
||||
state.blockLength[2]--;
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
state.distanceCode = ReadSymbol(state.hGroup2.codes, state.hGroup2.trees[state.distContextMap[state.distContextMapSlice + (state.copyLength > 4 ? 3 : state.copyLength - 2)] & unchecked((int)(0xFF))], br);
|
||||
if (state.distanceCode >= state.numDirectDistanceCodes)
|
||||
{
|
||||
state.distanceCode -= state.numDirectDistanceCodes;
|
||||
int postfix = state.distanceCode & state.distancePostfixMask;
|
||||
state.distanceCode = (int)(((uint)state.distanceCode) >> state.distancePostfixBits);
|
||||
int n = ((int)(((uint)state.distanceCode) >> 1)) + 1;
|
||||
int offset = ((2 + (state.distanceCode & 1)) << n) - 4;
|
||||
state.distanceCode = state.numDirectDistanceCodes + postfix + ((offset + Org.Brotli.Dec.BitReader.ReadBits(br, n)) << state.distancePostfixBits);
|
||||
}
|
||||
}
|
||||
// Convert the distance code to the actual distance by possibly looking up past distances
|
||||
// from the ringBuffer.
|
||||
state.distance = TranslateShortCodes(state.distanceCode, state.distRb, state.distRbIdx);
|
||||
if (state.distance < 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Negative distance");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
if (state.maxDistance != state.maxBackwardDistance && state.pos < state.maxBackwardDistance)
|
||||
{
|
||||
state.maxDistance = state.pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.maxDistance = state.maxBackwardDistance;
|
||||
}
|
||||
state.copyDst = state.pos;
|
||||
if (state.distance > state.maxDistance)
|
||||
{
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Transform;
|
||||
continue;
|
||||
}
|
||||
if (state.distanceCode > 0)
|
||||
{
|
||||
state.distRb[state.distRbIdx & 3] = state.distance;
|
||||
state.distRbIdx++;
|
||||
}
|
||||
if (state.copyLength > state.metaBlockLength)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid backward reference");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
state.j = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.CopyLoop;
|
||||
goto case Org.Brotli.Dec.RunningState.CopyLoop;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.CopyLoop:
|
||||
{
|
||||
// fall through
|
||||
int src = (state.pos - state.distance) & ringBufferMask;
|
||||
int dst = state.pos;
|
||||
int copyLength = state.copyLength - state.j;
|
||||
if ((src + copyLength < ringBufferMask) && (dst + copyLength < ringBufferMask))
|
||||
{
|
||||
for (int k = 0; k < copyLength; ++k)
|
||||
{
|
||||
ringBuffer[dst++] = ringBuffer[src++];
|
||||
}
|
||||
state.j += copyLength;
|
||||
state.metaBlockLength -= copyLength;
|
||||
state.pos += copyLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; state.j < state.copyLength; )
|
||||
{
|
||||
ringBuffer[state.pos] = ringBuffer[(state.pos - state.distance) & ringBufferMask];
|
||||
state.metaBlockLength--;
|
||||
state.j++;
|
||||
if (state.pos++ == ringBufferMask)
|
||||
{
|
||||
state.nextRunningState = Org.Brotli.Dec.RunningState.CopyLoop;
|
||||
state.bytesToWrite = state.ringBufferSize;
|
||||
state.bytesWritten = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Write;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state.runningState == Org.Brotli.Dec.RunningState.CopyLoop)
|
||||
{
|
||||
state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.Transform:
|
||||
{
|
||||
if (state.copyLength >= Org.Brotli.Dec.Dictionary.MinWordLength && state.copyLength <= Org.Brotli.Dec.Dictionary.MaxWordLength)
|
||||
{
|
||||
int offset = Org.Brotli.Dec.Dictionary.OffsetsByLength[state.copyLength];
|
||||
int wordId = state.distance - state.maxDistance - 1;
|
||||
int shift = Org.Brotli.Dec.Dictionary.SizeBitsByLength[state.copyLength];
|
||||
int mask = (1 << shift) - 1;
|
||||
int wordIdx = wordId & mask;
|
||||
int transformIdx = (int)(((uint)wordId) >> shift);
|
||||
offset += wordIdx * state.copyLength;
|
||||
if (transformIdx < Org.Brotli.Dec.Transform.Transforms.Length)
|
||||
{
|
||||
int len = Org.Brotli.Dec.Transform.TransformDictionaryWord(ringBuffer, state.copyDst, Org.Brotli.Dec.Dictionary.GetData(), offset, state.copyLength, Org.Brotli.Dec.Transform.Transforms[transformIdx]);
|
||||
state.copyDst += len;
|
||||
state.pos += len;
|
||||
state.metaBlockLength -= len;
|
||||
if (state.copyDst >= state.ringBufferSize)
|
||||
{
|
||||
state.nextRunningState = Org.Brotli.Dec.RunningState.CopyWrapBuffer;
|
||||
state.bytesToWrite = state.ringBufferSize;
|
||||
state.bytesWritten = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Write;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid backward reference");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// COV_NF_LINE
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid backward reference");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
|
||||
continue;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.CopyWrapBuffer:
|
||||
{
|
||||
System.Array.Copy(ringBuffer, state.ringBufferSize, ringBuffer, 0, state.copyDst - state.ringBufferSize);
|
||||
state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
|
||||
continue;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.ReadMetadata:
|
||||
{
|
||||
while (state.metaBlockLength > 0)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
// Optimize
|
||||
Org.Brotli.Dec.BitReader.ReadBits(br, 8);
|
||||
state.metaBlockLength--;
|
||||
}
|
||||
state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
|
||||
continue;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.CopyUncompressed:
|
||||
{
|
||||
CopyUncompressedData(state);
|
||||
continue;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.Write:
|
||||
{
|
||||
if (!WriteRingBuffer(state))
|
||||
{
|
||||
// Output buffer is full.
|
||||
return;
|
||||
}
|
||||
if (state.pos >= state.maxBackwardDistance)
|
||||
{
|
||||
state.maxDistance = state.maxBackwardDistance;
|
||||
}
|
||||
state.pos &= ringBufferMask;
|
||||
state.runningState = state.nextRunningState;
|
||||
continue;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Unexpected state " + state.runningState);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state.runningState == Org.Brotli.Dec.RunningState.Finished)
|
||||
{
|
||||
if (state.metaBlockLength < 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid metablock length");
|
||||
}
|
||||
Org.Brotli.Dec.BitReader.JumpToByteBoundary(br);
|
||||
Org.Brotli.Dec.BitReader.CheckHealth(state.br, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,149 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Utilities for building Huffman decoding tables.</summary>
|
||||
internal sealed class Huffman
|
||||
{
|
||||
/// <summary>
|
||||
/// Maximum possible Huffman table size for an alphabet size of 704, max code length 15 and root
|
||||
/// table bits 8.
|
||||
/// </summary>
|
||||
internal const int HuffmanMaxTableSize = 1080;
|
||||
|
||||
private const int MaxLength = 15;
|
||||
|
||||
/// <summary>Returns reverse(reverse(key, len) + 1, len).</summary>
|
||||
/// <remarks>
|
||||
/// Returns reverse(reverse(key, len) + 1, len).
|
||||
/// <p> reverse(key, len) is the bit-wise reversal of the len least significant bits of key.
|
||||
/// </remarks>
|
||||
private static int GetNextKey(int key, int len)
|
||||
{
|
||||
int step = 1 << (len - 1);
|
||||
while ((key & step) != 0)
|
||||
{
|
||||
step >>= 1;
|
||||
}
|
||||
return (key & (step - 1)) + step;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores
|
||||
/// <paramref name="item"/>
|
||||
/// in
|
||||
/// <c>table[0], table[step], table[2 * step] .., table[end]</c>
|
||||
/// .
|
||||
/// <p> Assumes that end is an integer multiple of step.
|
||||
/// </summary>
|
||||
private static void ReplicateValue(int[] table, int offset, int step, int end, int item)
|
||||
{
|
||||
do
|
||||
{
|
||||
end -= step;
|
||||
table[offset + end] = item;
|
||||
}
|
||||
while (end > 0);
|
||||
}
|
||||
|
||||
/// <param name="count">histogram of bit lengths for the remaining symbols,</param>
|
||||
/// <param name="len">code length of the next processed symbol.</param>
|
||||
/// <returns>table width of the next 2nd level table.</returns>
|
||||
private static int NextTableBitSize(int[] count, int len, int rootBits)
|
||||
{
|
||||
int left = 1 << (len - rootBits);
|
||||
while (len < MaxLength)
|
||||
{
|
||||
left -= count[len];
|
||||
if (left <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
len++;
|
||||
left <<= 1;
|
||||
}
|
||||
return len - rootBits;
|
||||
}
|
||||
|
||||
/// <summary>Builds Huffman lookup table assuming code lengths are in symbol order.</summary>
|
||||
internal static void BuildHuffmanTable(int[] rootTable, int tableOffset, int rootBits, int[] codeLengths, int codeLengthsSize)
|
||||
{
|
||||
int key;
|
||||
// Reversed prefix code.
|
||||
int[] sorted = new int[codeLengthsSize];
|
||||
// Symbols sorted by code length.
|
||||
// TODO: fill with zeroes?
|
||||
int[] count = new int[MaxLength + 1];
|
||||
// Number of codes of each length.
|
||||
int[] offset = new int[MaxLength + 1];
|
||||
// Offsets in sorted table for each length.
|
||||
int symbol;
|
||||
// Build histogram of code lengths.
|
||||
for (symbol = 0; symbol < codeLengthsSize; symbol++)
|
||||
{
|
||||
count[codeLengths[symbol]]++;
|
||||
}
|
||||
// Generate offsets into sorted symbol table by code length.
|
||||
offset[1] = 0;
|
||||
for (int len = 1; len < MaxLength; len++)
|
||||
{
|
||||
offset[len + 1] = offset[len] + count[len];
|
||||
}
|
||||
// Sort symbols by length, by symbol order within each length.
|
||||
for (symbol = 0; symbol < codeLengthsSize; symbol++)
|
||||
{
|
||||
if (codeLengths[symbol] != 0)
|
||||
{
|
||||
sorted[offset[codeLengths[symbol]]++] = symbol;
|
||||
}
|
||||
}
|
||||
int tableBits = rootBits;
|
||||
int tableSize = 1 << tableBits;
|
||||
int totalSize = tableSize;
|
||||
// Special case code with only one value.
|
||||
if (offset[MaxLength] == 1)
|
||||
{
|
||||
for (key = 0; key < totalSize; key++)
|
||||
{
|
||||
rootTable[tableOffset + key] = sorted[0];
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Fill in root table.
|
||||
key = 0;
|
||||
symbol = 0;
|
||||
for (int len = 1, step = 2; len <= rootBits; len++, step <<= 1)
|
||||
{
|
||||
for (; count[len] > 0; count[len]--)
|
||||
{
|
||||
ReplicateValue(rootTable, tableOffset + key, step, tableSize, len << 16 | sorted[symbol++]);
|
||||
key = GetNextKey(key, len);
|
||||
}
|
||||
}
|
||||
// Fill in 2nd level tables and add pointers to root table.
|
||||
int mask = totalSize - 1;
|
||||
int low = -1;
|
||||
int currentOffset = tableOffset;
|
||||
for (int len = rootBits + 1, step = 2; len <= MaxLength; len++, step <<= 1)
|
||||
{
|
||||
for (; count[len] > 0; count[len]--)
|
||||
{
|
||||
if ((key & mask) != low)
|
||||
{
|
||||
currentOffset += tableSize;
|
||||
tableBits = NextTableBitSize(count, len, rootBits);
|
||||
tableSize = 1 << tableBits;
|
||||
totalSize += tableSize;
|
||||
low = key & mask;
|
||||
rootTable[tableOffset + low] = (tableBits + rootBits) << 16 | (currentOffset - tableOffset - low);
|
||||
}
|
||||
ReplicateValue(rootTable, currentOffset + (key >> rootBits), step, tableSize, (len - rootBits) << 16 | sorted[symbol++]);
|
||||
key = GetNextKey(key, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Contains a collection of huffman trees with the same alphabet size.</summary>
|
||||
internal sealed class HuffmanTreeGroup
|
||||
{
|
||||
/// <summary>The maximal alphabet size in this group.</summary>
|
||||
private int alphabetSize;
|
||||
|
||||
/// <summary>Storage for Huffman lookup tables.</summary>
|
||||
internal int[] codes;
|
||||
|
||||
/// <summary>
|
||||
/// Offsets of distinct lookup tables in
|
||||
/// <see cref="codes"/>
|
||||
/// storage.
|
||||
/// </summary>
|
||||
internal int[] trees;
|
||||
|
||||
/// <summary>Initializes the Huffman tree group.</summary>
|
||||
/// <param name="group">POJO to be initialised</param>
|
||||
/// <param name="alphabetSize">the maximal alphabet size in this group</param>
|
||||
/// <param name="n">number of Huffman codes</param>
|
||||
internal static void Init(Org.Brotli.Dec.HuffmanTreeGroup group, int alphabetSize, int n)
|
||||
{
|
||||
group.alphabetSize = alphabetSize;
|
||||
group.codes = new int[n * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize];
|
||||
group.trees = new int[n];
|
||||
}
|
||||
|
||||
/// <summary>Decodes Huffman trees from input stream and constructs lookup tables.</summary>
|
||||
/// <param name="group">target POJO</param>
|
||||
/// <param name="br">data source</param>
|
||||
internal static void Decode(Org.Brotli.Dec.HuffmanTreeGroup group, Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
int next = 0;
|
||||
int n = group.trees.Length;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
group.trees[i] = next;
|
||||
Org.Brotli.Dec.Decode.ReadHuffmanCode(group.alphabetSize, group.codes, next, br);
|
||||
next += Org.Brotli.Dec.Huffman.HuffmanMaxTableSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Byte-to-int conversion magic.</summary>
|
||||
internal sealed class IntReader
|
||||
{
|
||||
private byte[] byteBuffer;
|
||||
|
||||
private int[] intBuffer;
|
||||
|
||||
internal static void Init(Org.Brotli.Dec.IntReader ir, byte[] byteBuffer, int[] intBuffer)
|
||||
{
|
||||
ir.byteBuffer = byteBuffer;
|
||||
ir.intBuffer = intBuffer;
|
||||
}
|
||||
|
||||
/// <summary>Translates bytes to ints.</summary>
|
||||
/// <remarks>
|
||||
/// Translates bytes to ints.
|
||||
/// NB: intLen == 4 * byteSize!
|
||||
/// NB: intLen should be less or equal to intBuffer length.
|
||||
/// </remarks>
|
||||
internal static void Convert(Org.Brotli.Dec.IntReader ir, int intLen)
|
||||
{
|
||||
for (int i = 0; i < intLen; ++i)
|
||||
{
|
||||
ir.intBuffer[i] = ((ir.byteBuffer[i * 4] & unchecked((int)(0xFF)))) | ((ir.byteBuffer[(i * 4) + 1] & unchecked((int)(0xFF))) << 8) | ((ir.byteBuffer[(i * 4) + 2] & unchecked((int)(0xFF))) << 16) | ((ir.byteBuffer[(i * 4) + 3] & unchecked((int
|
||||
)(0xFF))) << 24);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Lookup tables to map prefix codes to value ranges.</summary>
|
||||
/// <remarks>
|
||||
/// Lookup tables to map prefix codes to value ranges.
|
||||
/// <p> This is used during decoding of the block lengths, literal insertion lengths and copy
|
||||
/// lengths.
|
||||
/// <p> Range represents values: [offset, offset + 2 ^ n_bits)
|
||||
/// </remarks>
|
||||
internal sealed class Prefix
|
||||
{
|
||||
internal static readonly int[] BlockLengthOffset = new int[] { 1, 5, 9, 13, 17, 25, 33, 41, 49, 65, 81, 97, 113, 145, 177, 209, 241, 305, 369, 497, 753, 1265, 2289, 4337, 8433, 16625 };
|
||||
|
||||
internal static readonly int[] BlockLengthNBits = new int[] { 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 24 };
|
||||
|
||||
internal static readonly int[] InsertLengthOffset = new int[] { 0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26, 34, 50, 66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594 };
|
||||
|
||||
internal static readonly int[] InsertLengthNBits = new int[] { 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 12, 14, 24 };
|
||||
|
||||
internal static readonly int[] CopyLengthOffset = new int[] { 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 18, 22, 30, 38, 54, 70, 102, 134, 198, 326, 582, 1094, 2118 };
|
||||
|
||||
internal static readonly int[] CopyLengthNBits = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 24 };
|
||||
|
||||
internal static readonly int[] InsertRangeLut = new int[] { 0, 0, 8, 8, 0, 16, 8, 16, 16 };
|
||||
|
||||
internal static readonly int[] CopyRangeLut = new int[] { 0, 8, 0, 8, 16, 0, 16, 8, 16 };
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Enumeration of decoding state-machine.</summary>
|
||||
internal sealed class RunningState
|
||||
{
|
||||
internal const int Uninitialized = 0;
|
||||
|
||||
internal const int BlockStart = 1;
|
||||
|
||||
internal const int CompressedBlockStart = 2;
|
||||
|
||||
internal const int MainLoop = 3;
|
||||
|
||||
internal const int ReadMetadata = 4;
|
||||
|
||||
internal const int CopyUncompressed = 5;
|
||||
|
||||
internal const int InsertLoop = 6;
|
||||
|
||||
internal const int CopyLoop = 7;
|
||||
|
||||
internal const int CopyWrapBuffer = 8;
|
||||
|
||||
internal const int Transform = 9;
|
||||
|
||||
internal const int Finished = 10;
|
||||
|
||||
internal const int Closed = 11;
|
||||
|
||||
internal const int Write = 12;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
internal sealed class State
|
||||
{
|
||||
internal int runningState = Org.Brotli.Dec.RunningState.Uninitialized;
|
||||
|
||||
internal int nextRunningState;
|
||||
|
||||
internal readonly Org.Brotli.Dec.BitReader br = new Org.Brotli.Dec.BitReader();
|
||||
|
||||
internal byte[] ringBuffer;
|
||||
|
||||
internal readonly int[] blockTypeTrees = new int[3 * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize];
|
||||
|
||||
internal readonly int[] blockLenTrees = new int[3 * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize];
|
||||
|
||||
internal int metaBlockLength;
|
||||
|
||||
internal bool inputEnd;
|
||||
|
||||
internal bool isUncompressed;
|
||||
|
||||
internal bool isMetadata;
|
||||
|
||||
internal readonly Org.Brotli.Dec.HuffmanTreeGroup hGroup0 = new Org.Brotli.Dec.HuffmanTreeGroup();
|
||||
|
||||
internal readonly Org.Brotli.Dec.HuffmanTreeGroup hGroup1 = new Org.Brotli.Dec.HuffmanTreeGroup();
|
||||
|
||||
internal readonly Org.Brotli.Dec.HuffmanTreeGroup hGroup2 = new Org.Brotli.Dec.HuffmanTreeGroup();
|
||||
|
||||
internal readonly int[] blockLength = new int[3];
|
||||
|
||||
internal readonly int[] numBlockTypes = new int[3];
|
||||
|
||||
internal readonly int[] blockTypeRb = new int[6];
|
||||
|
||||
internal readonly int[] distRb = new int[] { 16, 15, 11, 4 };
|
||||
|
||||
internal int pos = 0;
|
||||
|
||||
internal int maxDistance = 0;
|
||||
|
||||
internal int distRbIdx = 0;
|
||||
|
||||
internal bool trivialLiteralContext = false;
|
||||
|
||||
internal int literalTreeIndex = 0;
|
||||
|
||||
internal int literalTree;
|
||||
|
||||
internal int j;
|
||||
|
||||
internal int insertLength;
|
||||
|
||||
internal byte[] contextModes;
|
||||
|
||||
internal byte[] contextMap;
|
||||
|
||||
internal int contextMapSlice;
|
||||
|
||||
internal int distContextMapSlice;
|
||||
|
||||
internal int contextLookupOffset1;
|
||||
|
||||
internal int contextLookupOffset2;
|
||||
|
||||
internal int treeCommandOffset;
|
||||
|
||||
internal int distanceCode;
|
||||
|
||||
internal byte[] distContextMap;
|
||||
|
||||
internal int numDirectDistanceCodes;
|
||||
|
||||
internal int distancePostfixMask;
|
||||
|
||||
internal int distancePostfixBits;
|
||||
|
||||
internal int distance;
|
||||
|
||||
internal int copyLength;
|
||||
|
||||
internal int copyDst;
|
||||
|
||||
internal int maxBackwardDistance;
|
||||
|
||||
internal int maxRingBufferSize;
|
||||
|
||||
internal int ringBufferSize = 0;
|
||||
|
||||
internal long expectedTotalSize = 0;
|
||||
|
||||
internal byte[] customDictionary = new byte[0];
|
||||
|
||||
internal int bytesToIgnore = 0;
|
||||
|
||||
internal int outputOffset;
|
||||
|
||||
internal int outputLength;
|
||||
|
||||
internal int outputUsed;
|
||||
|
||||
internal int bytesWritten;
|
||||
|
||||
internal int bytesToWrite;
|
||||
|
||||
internal byte[] output;
|
||||
|
||||
// Current meta-block header information.
|
||||
// TODO: Update to current spec.
|
||||
private static int DecodeWindowBits(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 0)
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
int n = Org.Brotli.Dec.BitReader.ReadBits(br, 3);
|
||||
if (n != 0)
|
||||
{
|
||||
return 17 + n;
|
||||
}
|
||||
n = Org.Brotli.Dec.BitReader.ReadBits(br, 3);
|
||||
if (n != 0)
|
||||
{
|
||||
return 8 + n;
|
||||
}
|
||||
return 17;
|
||||
}
|
||||
|
||||
/// <summary>Associate input with decoder state.</summary>
|
||||
/// <param name="state">uninitialized state without associated input</param>
|
||||
/// <param name="input">compressed data source</param>
|
||||
internal static void SetInput(Org.Brotli.Dec.State state, System.IO.Stream input)
|
||||
{
|
||||
if (state.runningState != Org.Brotli.Dec.RunningState.Uninitialized)
|
||||
{
|
||||
throw new System.InvalidOperationException("State MUST be uninitialized");
|
||||
}
|
||||
Org.Brotli.Dec.BitReader.Init(state.br, input);
|
||||
int windowBits = DecodeWindowBits(state.br);
|
||||
if (windowBits == 9)
|
||||
{
|
||||
/* Reserved case for future expansion. */
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid 'windowBits' code");
|
||||
}
|
||||
state.maxRingBufferSize = 1 << windowBits;
|
||||
state.maxBackwardDistance = state.maxRingBufferSize - 16;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
|
||||
}
|
||||
|
||||
/// <exception cref="System.IO.IOException"/>
|
||||
internal static void Close(Org.Brotli.Dec.State state)
|
||||
{
|
||||
if (state.runningState == Org.Brotli.Dec.RunningState.Uninitialized)
|
||||
{
|
||||
throw new System.InvalidOperationException("State MUST be initialized");
|
||||
}
|
||||
if (state.runningState == Org.Brotli.Dec.RunningState.Closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Closed;
|
||||
Org.Brotli.Dec.BitReader.Close(state.br);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Transformations on dictionary words.</summary>
|
||||
internal sealed class Transform
|
||||
{
|
||||
private readonly byte[] prefix;
|
||||
|
||||
private readonly int type;
|
||||
|
||||
private readonly byte[] suffix;
|
||||
|
||||
internal Transform(string prefix, int type, string suffix)
|
||||
{
|
||||
this.prefix = ReadUniBytes(prefix);
|
||||
this.type = type;
|
||||
this.suffix = ReadUniBytes(suffix);
|
||||
}
|
||||
|
||||
internal static byte[] ReadUniBytes(string uniBytes)
|
||||
{
|
||||
byte[] result = new byte[uniBytes.Length];
|
||||
for (int i = 0; i < result.Length; ++i)
|
||||
{
|
||||
result[i] = unchecked((byte)uniBytes[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static readonly Org.Brotli.Dec.Transform[] Transforms = new Org.Brotli.Dec.Transform[] { new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(string.Empty,
|
||||
Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst1, string.Empty), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " the "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity
|
||||
, string.Empty), new Org.Brotli.Dec.Transform("s ", Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " of "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.UppercaseFirst, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " and "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst2, string.Empty), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast1, string.Empty), new Org.Brotli.Dec.Transform(", ", Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity
|
||||
, ", "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " in "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.Identity, " to "), new Org.Brotli.Dec.Transform("e ", Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "\""), new Org.Brotli.Dec.Transform(string.Empty,
|
||||
Org.Brotli.Dec.WordTransformType.Identity, "."), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "\">"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "\n"), new
|
||||
Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast3, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "]"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.Identity, " for "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst3, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast2, string.Empty), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " a "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " that "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst
|
||||
, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, ". "), new Org.Brotli.Dec.Transform(".", Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType
|
||||
.Identity, ", "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst4, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " with "), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "'"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " from "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity
|
||||
, " by "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst5, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst6, string.Empty), new Org.Brotli.Dec.Transform
|
||||
(" the ", Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast4, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.Identity, ". The "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " on "), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " as "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " is "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast7
|
||||
, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast1, "ing "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "\n\t"), new Org.Brotli.Dec.Transform(string.Empty
|
||||
, Org.Brotli.Dec.WordTransformType.Identity, ":"), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, ". "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "ed "), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst9, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst7, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.OmitLast6, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, ", "), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast8, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " at "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.Identity, "ly "), new Org.Brotli.Dec.Transform(" the ", Org.Brotli.Dec.WordTransformType.Identity, " of "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast5, string.Empty), new Org.Brotli.Dec.Transform(
|
||||
string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast9, string.Empty), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, ", "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst
|
||||
, "\""), new Org.Brotli.Dec.Transform(".", Org.Brotli.Dec.WordTransformType.Identity, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.UppercaseFirst, "\">"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "=\""), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, "."), new Org.Brotli.Dec.Transform(".com/",
|
||||
Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(" the ", Org.Brotli.Dec.WordTransformType.Identity, " of the "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst
|
||||
, "'"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, ". This "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, ","), new Org.Brotli.Dec.Transform(".", Org.Brotli.Dec.WordTransformType
|
||||
.Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, "."), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " not "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, "=\""), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "er "
|
||||
), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "al "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType
|
||||
.UppercaseAll, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "='"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "\""), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, ". "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity,
|
||||
"ful "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, ". "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "ive "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.Identity, "less "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "'"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "est "), new Org.Brotli.Dec.Transform
|
||||
(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, "."), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "\">"), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, "='"
|
||||
), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, ","), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "ize "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.UppercaseAll, "."), new Org.Brotli.Dec.Transform("\u00c2\u00a0", Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, ","), new Org.Brotli.Dec.Transform(string.Empty
|
||||
, Org.Brotli.Dec.WordTransformType.UppercaseFirst, "=\""), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "=\""), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity
|
||||
, "ous "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, ", "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, "='"), new Org.Brotli.Dec.Transform(" ",
|
||||
Org.Brotli.Dec.WordTransformType.UppercaseFirst, ","), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, "=\""), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, ", "), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, ","), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.
|
||||
UppercaseAll, ". "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, "."), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "='"), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType
|
||||
.UppercaseAll, ". "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, "=\""), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, "='"), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType
|
||||
.UppercaseFirst, "='") };
|
||||
|
||||
internal static int TransformDictionaryWord(byte[] dst, int dstOffset, byte[] word, int wordOffset, int len, Org.Brotli.Dec.Transform transform)
|
||||
{
|
||||
int offset = dstOffset;
|
||||
// Copy prefix.
|
||||
byte[] @string = transform.prefix;
|
||||
int tmp = @string.Length;
|
||||
int i = 0;
|
||||
// In most cases tmp < 10 -> no benefits from System.arrayCopy
|
||||
while (i < tmp)
|
||||
{
|
||||
dst[offset++] = @string[i++];
|
||||
}
|
||||
// Copy trimmed word.
|
||||
int op = transform.type;
|
||||
tmp = Org.Brotli.Dec.WordTransformType.GetOmitFirst(op);
|
||||
if (tmp > len)
|
||||
{
|
||||
tmp = len;
|
||||
}
|
||||
wordOffset += tmp;
|
||||
len -= tmp;
|
||||
len -= Org.Brotli.Dec.WordTransformType.GetOmitLast(op);
|
||||
i = len;
|
||||
while (i > 0)
|
||||
{
|
||||
dst[offset++] = word[wordOffset++];
|
||||
i--;
|
||||
}
|
||||
if (op == Org.Brotli.Dec.WordTransformType.UppercaseAll || op == Org.Brotli.Dec.WordTransformType.UppercaseFirst)
|
||||
{
|
||||
int uppercaseOffset = offset - len;
|
||||
if (op == Org.Brotli.Dec.WordTransformType.UppercaseFirst)
|
||||
{
|
||||
len = 1;
|
||||
}
|
||||
while (len > 0)
|
||||
{
|
||||
tmp = dst[uppercaseOffset] & unchecked((int)(0xFF));
|
||||
if (tmp < unchecked((int)(0xc0)))
|
||||
{
|
||||
if (tmp >= 'a' && tmp <= 'z')
|
||||
{
|
||||
dst[uppercaseOffset] ^= unchecked((byte)32);
|
||||
}
|
||||
uppercaseOffset += 1;
|
||||
len -= 1;
|
||||
}
|
||||
else if (tmp < unchecked((int)(0xe0)))
|
||||
{
|
||||
dst[uppercaseOffset + 1] ^= unchecked((byte)32);
|
||||
uppercaseOffset += 2;
|
||||
len -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[uppercaseOffset + 2] ^= unchecked((byte)5);
|
||||
uppercaseOffset += 3;
|
||||
len -= 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Copy suffix.
|
||||
@string = transform.suffix;
|
||||
tmp = @string.Length;
|
||||
i = 0;
|
||||
while (i < tmp)
|
||||
{
|
||||
dst[offset++] = @string[i++];
|
||||
}
|
||||
return offset - dstOffset;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>A set of utility methods.</summary>
|
||||
internal sealed class Utils
|
||||
{
|
||||
private static readonly byte[] ByteZeroes = new byte[1024];
|
||||
|
||||
private static readonly int[] IntZeroes = new int[1024];
|
||||
|
||||
/// <summary>Fills byte array with zeroes.</summary>
|
||||
/// <remarks>
|
||||
/// Fills byte array with zeroes.
|
||||
/// <p> Current implementation uses
|
||||
/// <see cref="System.Array.Copy(object, int, object, int, int)"/>
|
||||
/// , so it should be used for length not
|
||||
/// less than 16.
|
||||
/// </remarks>
|
||||
/// <param name="dest">array to fill with zeroes</param>
|
||||
/// <param name="offset">the first byte to fill</param>
|
||||
/// <param name="length">number of bytes to change</param>
|
||||
internal static void FillWithZeroes(byte[] dest, int offset, int length)
|
||||
{
|
||||
int cursor = 0;
|
||||
while (cursor < length)
|
||||
{
|
||||
int step = System.Math.Min(cursor + 1024, length) - cursor;
|
||||
System.Array.Copy(ByteZeroes, 0, dest, offset + cursor, step);
|
||||
cursor += step;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Fills int array with zeroes.</summary>
|
||||
/// <remarks>
|
||||
/// Fills int array with zeroes.
|
||||
/// <p> Current implementation uses
|
||||
/// <see cref="System.Array.Copy(object, int, object, int, int)"/>
|
||||
/// , so it should be used for length not
|
||||
/// less than 16.
|
||||
/// </remarks>
|
||||
/// <param name="dest">array to fill with zeroes</param>
|
||||
/// <param name="offset">the first item to fill</param>
|
||||
/// <param name="length">number of item to change</param>
|
||||
internal static void FillWithZeroes(int[] dest, int offset, int length)
|
||||
{
|
||||
int cursor = 0;
|
||||
while (cursor < length)
|
||||
{
|
||||
int step = System.Math.Min(cursor + 1024, length) - cursor;
|
||||
System.Array.Copy(IntZeroes, 0, dest, offset + cursor, step);
|
||||
cursor += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Enumeration of all possible word transformations.</summary>
|
||||
/// <remarks>
|
||||
/// Enumeration of all possible word transformations.
|
||||
/// <p>There are two simple types of transforms: omit X first/last symbols, two character-case
|
||||
/// transforms and the identity transform.
|
||||
/// </remarks>
|
||||
internal sealed class WordTransformType
|
||||
{
|
||||
internal const int Identity = 0;
|
||||
|
||||
internal const int OmitLast1 = 1;
|
||||
|
||||
internal const int OmitLast2 = 2;
|
||||
|
||||
internal const int OmitLast3 = 3;
|
||||
|
||||
internal const int OmitLast4 = 4;
|
||||
|
||||
internal const int OmitLast5 = 5;
|
||||
|
||||
internal const int OmitLast6 = 6;
|
||||
|
||||
internal const int OmitLast7 = 7;
|
||||
|
||||
internal const int OmitLast8 = 8;
|
||||
|
||||
internal const int OmitLast9 = 9;
|
||||
|
||||
internal const int UppercaseFirst = 10;
|
||||
|
||||
internal const int UppercaseAll = 11;
|
||||
|
||||
internal const int OmitFirst1 = 12;
|
||||
|
||||
internal const int OmitFirst2 = 13;
|
||||
|
||||
internal const int OmitFirst3 = 14;
|
||||
|
||||
internal const int OmitFirst4 = 15;
|
||||
|
||||
internal const int OmitFirst5 = 16;
|
||||
|
||||
internal const int OmitFirst6 = 17;
|
||||
|
||||
internal const int OmitFirst7 = 18;
|
||||
|
||||
internal const int OmitFirst8 = 19;
|
||||
|
||||
internal const int OmitFirst9 = 20;
|
||||
|
||||
internal static int GetOmitFirst(int type)
|
||||
{
|
||||
return type >= OmitFirst1 ? (type - OmitFirst1 + 1) : 0;
|
||||
}
|
||||
|
||||
internal static int GetOmitLast(int type)
|
||||
{
|
||||
return type <= OmitLast9 ? (type - OmitLast1 + 1) : 0;
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -4,7 +4,7 @@ using System.IO;
|
|||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BrotliSharpLib;
|
||||
using Org.Brotli.Dec;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
|
@ -47,9 +47,10 @@ namespace AssetStudio
|
|||
reader.Position = 0;
|
||||
if (brotliMagic.SequenceEqual(magic))
|
||||
{
|
||||
var buff = reader.ReadBytes((int)reader.BaseStream.Length);
|
||||
var uncompressedData = Brotli.DecompressBuffer(buff, 0, buff.Length);
|
||||
var stream = new MemoryStream(uncompressedData);
|
||||
var brotliStream = new BrotliInputStream(reader.BaseStream);
|
||||
var stream = new MemoryStream();
|
||||
brotliStream.CopyTo(stream);
|
||||
stream.Position = 0;
|
||||
using (reader = new EndianBinaryReader(stream, EndianType.LittleEndian))
|
||||
{
|
||||
ReadWebData(reader);
|
||||
|
|
Loading…
Reference in New Issue