change the brotli library

This commit is contained in:
Perfare 2018-07-15 04:36:28 +08:00
parent 380afbf295
commit 2adda81b28
20 changed files with 2473 additions and 14 deletions

View File

@ -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" />

View File

@ -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>

View File

@ -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);
}
}
}
}

View File

@ -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() {}
}
}

View File

@ -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)
{
}
}
}

View File

@ -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
}
}

View File

@ -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

View File

@ -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);
}
}
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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 };
}
}

View File

@ -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;
}
}

171
AssetStudio/Brotli/State.cs Normal file
View File

@ -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);
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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.

View File

@ -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);