Files
UltimateFishing/Assets/Scripts/Assembly-CSharp/Unity/IO/Compression/Inflater.cs
2026-02-21 16:45:37 +08:00

566 lines
13 KiB
C#

using System;
namespace Unity.IO.Compression
{
internal class Inflater
{
private static readonly byte[] extraLengthBits = new byte[29]
{
0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
4, 4, 4, 4, 5, 5, 5, 5, 0
};
private static readonly int[] lengthBase = new int[29]
{
3, 4, 5, 6, 7, 8, 9, 10, 11, 13,
15, 17, 19, 23, 27, 31, 35, 43, 51, 59,
67, 83, 99, 115, 131, 163, 195, 227, 258
};
private static readonly int[] distanceBasePosition = new int[32]
{
1, 2, 3, 4, 5, 7, 9, 13, 17, 25,
33, 49, 65, 97, 129, 193, 257, 385, 513, 769,
1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577,
0, 0
};
private static readonly byte[] codeOrder = new byte[19]
{
16, 17, 18, 0, 8, 7, 9, 6, 10, 5,
11, 4, 12, 3, 13, 2, 14, 1, 15
};
private static readonly byte[] staticDistanceTreeTable = new byte[32]
{
0, 16, 8, 24, 4, 20, 12, 28, 2, 18,
10, 26, 6, 22, 14, 30, 1, 17, 9, 25,
5, 21, 13, 29, 3, 19, 11, 27, 7, 23,
15, 31
};
private OutputWindow output;
private InputBuffer input;
private HuffmanTree literalLengthTree;
private HuffmanTree distanceTree;
private InflaterState state;
private bool hasFormatReader;
private int bfinal;
private BlockType blockType;
private byte[] blockLengthBuffer = new byte[4];
private int blockLength;
private int length;
private int distanceCode;
private int extraBits;
private int loopCounter;
private int literalLengthCodeCount;
private int distanceCodeCount;
private int codeLengthCodeCount;
private int codeArraySize;
private int lengthCode;
private byte[] codeList;
private byte[] codeLengthTreeCodeLength;
private HuffmanTree codeLengthTree;
private IFileFormatReader formatReader;
public int AvailableOutput
{
get
{
return output.AvailableBytes;
}
}
public Inflater()
{
output = new OutputWindow();
input = new InputBuffer();
codeList = new byte[320];
codeLengthTreeCodeLength = new byte[19];
Reset();
}
internal void SetFileFormatReader(IFileFormatReader reader)
{
formatReader = reader;
hasFormatReader = true;
Reset();
}
private void Reset()
{
if (hasFormatReader)
{
state = InflaterState.ReadingHeader;
}
else
{
state = InflaterState.ReadingBFinal;
}
}
public void SetInput(byte[] inputBytes, int offset, int length)
{
input.SetInput(inputBytes, offset, length);
}
public bool Finished()
{
return state == InflaterState.Done || state == InflaterState.VerifyingFooter;
}
public bool NeedsInput()
{
return input.NeedsInput();
}
public int Inflate(byte[] bytes, int offset, int length)
{
int num = 0;
do
{
int num2 = output.CopyTo(bytes, offset, length);
if (num2 > 0)
{
if (hasFormatReader)
{
formatReader.UpdateWithBytesRead(bytes, offset, num2);
}
offset += num2;
num += num2;
length -= num2;
}
}
while (length != 0 && !Finished() && Decode());
if (state == InflaterState.VerifyingFooter && output.AvailableBytes == 0)
{
formatReader.Validate();
}
return num;
}
private bool Decode()
{
bool end_of_block = false;
bool flag = false;
if (Finished())
{
return true;
}
if (hasFormatReader)
{
if (state == InflaterState.ReadingHeader)
{
if (!formatReader.ReadHeader(input))
{
return false;
}
state = InflaterState.ReadingBFinal;
}
else if (state == InflaterState.StartReadingFooter || state == InflaterState.ReadingFooter)
{
if (!formatReader.ReadFooter(input))
{
return false;
}
state = InflaterState.VerifyingFooter;
return true;
}
}
if (state == InflaterState.ReadingBFinal)
{
if (!input.EnsureBitsAvailable(1))
{
return false;
}
bfinal = input.GetBits(1);
state = InflaterState.ReadingBType;
}
if (state == InflaterState.ReadingBType)
{
if (!input.EnsureBitsAvailable(2))
{
state = InflaterState.ReadingBType;
return false;
}
blockType = (BlockType)input.GetBits(2);
if (blockType == BlockType.Dynamic)
{
state = InflaterState.ReadingNumLitCodes;
}
else if (blockType == BlockType.Static)
{
literalLengthTree = HuffmanTree.StaticLiteralLengthTree;
distanceTree = HuffmanTree.StaticDistanceTree;
state = InflaterState.DecodeTop;
}
else
{
if (blockType != BlockType.Uncompressed)
{
throw new InvalidDataException(SR.GetString("Unknown block type"));
}
state = InflaterState.UncompressedAligning;
}
}
if (blockType == BlockType.Dynamic)
{
flag = ((state >= InflaterState.DecodeTop) ? DecodeBlock(out end_of_block) : DecodeDynamicBlockHeader());
}
else if (blockType == BlockType.Static)
{
flag = DecodeBlock(out end_of_block);
}
else
{
if (blockType != BlockType.Uncompressed)
{
throw new InvalidDataException(SR.GetString("Unknown block type"));
}
flag = DecodeUncompressedBlock(out end_of_block);
}
if (end_of_block && bfinal != 0)
{
if (hasFormatReader)
{
state = InflaterState.StartReadingFooter;
}
else
{
state = InflaterState.Done;
}
}
return flag;
}
private bool DecodeUncompressedBlock(out bool end_of_block)
{
end_of_block = false;
while (true)
{
switch (state)
{
case InflaterState.UncompressedAligning:
input.SkipToByteBoundary();
state = InflaterState.UncompressedByte1;
goto case InflaterState.UncompressedByte1;
case InflaterState.UncompressedByte1:
case InflaterState.UncompressedByte2:
case InflaterState.UncompressedByte3:
case InflaterState.UncompressedByte4:
{
int bits = input.GetBits(8);
if (bits < 0)
{
return false;
}
blockLengthBuffer[(int)(state - 16)] = (byte)bits;
if (state == InflaterState.UncompressedByte4)
{
blockLength = blockLengthBuffer[0] + blockLengthBuffer[1] * 256;
int num2 = blockLengthBuffer[2] + blockLengthBuffer[3] * 256;
if ((ushort)blockLength != (ushort)(~num2))
{
throw new InvalidDataException(SR.GetString("Invalid block length"));
}
}
break;
}
case InflaterState.DecodingUncompressed:
{
int num = output.CopyFrom(input, blockLength);
blockLength -= num;
if (blockLength == 0)
{
state = InflaterState.ReadingBFinal;
end_of_block = true;
return true;
}
if (output.FreeBytes == 0)
{
return true;
}
return false;
}
default:
throw new InvalidDataException(SR.GetString("Unknown state"));
}
state++;
}
}
private bool DecodeBlock(out bool end_of_block_code_seen)
{
end_of_block_code_seen = false;
int num = output.FreeBytes;
while (num > 258)
{
switch (state)
{
case InflaterState.DecodeTop:
{
int nextSymbol = literalLengthTree.GetNextSymbol(input);
if (nextSymbol < 0)
{
return false;
}
if (nextSymbol < 256)
{
output.Write((byte)nextSymbol);
num--;
break;
}
if (nextSymbol == 256)
{
end_of_block_code_seen = true;
state = InflaterState.ReadingBFinal;
return true;
}
nextSymbol -= 257;
if (nextSymbol < 8)
{
nextSymbol += 3;
extraBits = 0;
}
else if (nextSymbol == 28)
{
nextSymbol = 258;
extraBits = 0;
}
else
{
if (nextSymbol < 0 || nextSymbol >= extraLengthBits.Length)
{
throw new InvalidDataException(SR.GetString("Invalid data"));
}
extraBits = extraLengthBits[nextSymbol];
}
length = nextSymbol;
goto case InflaterState.HaveInitialLength;
}
case InflaterState.HaveInitialLength:
if (extraBits > 0)
{
state = InflaterState.HaveInitialLength;
int bits2 = input.GetBits(extraBits);
if (bits2 < 0)
{
return false;
}
if (length < 0 || length >= lengthBase.Length)
{
throw new InvalidDataException(SR.GetString("Invalid data"));
}
length = lengthBase[length] + bits2;
}
state = InflaterState.HaveFullLength;
goto case InflaterState.HaveFullLength;
case InflaterState.HaveFullLength:
if (blockType == BlockType.Dynamic)
{
distanceCode = distanceTree.GetNextSymbol(input);
}
else
{
distanceCode = input.GetBits(5);
if (distanceCode >= 0)
{
distanceCode = staticDistanceTreeTable[distanceCode];
}
}
if (distanceCode < 0)
{
return false;
}
state = InflaterState.HaveDistCode;
goto case InflaterState.HaveDistCode;
case InflaterState.HaveDistCode:
{
int distance;
if (distanceCode > 3)
{
extraBits = distanceCode - 2 >> 1;
int bits = input.GetBits(extraBits);
if (bits < 0)
{
return false;
}
distance = distanceBasePosition[distanceCode] + bits;
}
else
{
distance = distanceCode + 1;
}
output.WriteLengthDistance(length, distance);
num -= length;
state = InflaterState.DecodeTop;
break;
}
default:
throw new InvalidDataException(SR.GetString("Unknown state"));
}
}
return true;
}
private bool DecodeDynamicBlockHeader()
{
switch (state)
{
case InflaterState.ReadingNumLitCodes:
literalLengthCodeCount = input.GetBits(5);
if (literalLengthCodeCount < 0)
{
return false;
}
literalLengthCodeCount += 257;
state = InflaterState.ReadingNumDistCodes;
goto case InflaterState.ReadingNumDistCodes;
case InflaterState.ReadingNumDistCodes:
distanceCodeCount = input.GetBits(5);
if (distanceCodeCount < 0)
{
return false;
}
distanceCodeCount++;
state = InflaterState.ReadingNumCodeLengthCodes;
goto case InflaterState.ReadingNumCodeLengthCodes;
case InflaterState.ReadingNumCodeLengthCodes:
codeLengthCodeCount = input.GetBits(4);
if (codeLengthCodeCount < 0)
{
return false;
}
codeLengthCodeCount += 4;
loopCounter = 0;
state = InflaterState.ReadingCodeLengthCodes;
goto case InflaterState.ReadingCodeLengthCodes;
case InflaterState.ReadingCodeLengthCodes:
{
while (loopCounter < codeLengthCodeCount)
{
int bits = input.GetBits(3);
if (bits < 0)
{
return false;
}
codeLengthTreeCodeLength[codeOrder[loopCounter]] = (byte)bits;
loopCounter++;
}
for (int l = codeLengthCodeCount; l < codeOrder.Length; l++)
{
codeLengthTreeCodeLength[codeOrder[l]] = 0;
}
codeLengthTree = new HuffmanTree(codeLengthTreeCodeLength);
codeArraySize = literalLengthCodeCount + distanceCodeCount;
loopCounter = 0;
state = InflaterState.ReadingTreeCodesBefore;
goto case InflaterState.ReadingTreeCodesBefore;
}
case InflaterState.ReadingTreeCodesBefore:
case InflaterState.ReadingTreeCodesAfter:
{
while (loopCounter < codeArraySize)
{
if (state == InflaterState.ReadingTreeCodesBefore && (lengthCode = codeLengthTree.GetNextSymbol(input)) < 0)
{
return false;
}
if (lengthCode <= 15)
{
codeList[loopCounter++] = (byte)lengthCode;
}
else
{
if (!input.EnsureBitsAvailable(7))
{
state = InflaterState.ReadingTreeCodesAfter;
return false;
}
if (lengthCode == 16)
{
if (loopCounter == 0)
{
throw new InvalidDataException();
}
byte b = codeList[loopCounter - 1];
int num = input.GetBits(2) + 3;
if (loopCounter + num > codeArraySize)
{
throw new InvalidDataException();
}
for (int i = 0; i < num; i++)
{
codeList[loopCounter++] = b;
}
}
else if (lengthCode == 17)
{
int num = input.GetBits(3) + 3;
if (loopCounter + num > codeArraySize)
{
throw new InvalidDataException();
}
for (int j = 0; j < num; j++)
{
codeList[loopCounter++] = 0;
}
}
else
{
int num = input.GetBits(7) + 11;
if (loopCounter + num > codeArraySize)
{
throw new InvalidDataException();
}
for (int k = 0; k < num; k++)
{
codeList[loopCounter++] = 0;
}
}
}
state = InflaterState.ReadingTreeCodesBefore;
}
byte[] array = new byte[288];
byte[] array2 = new byte[32];
Array.Copy(codeList, array, literalLengthCodeCount);
Array.Copy(codeList, literalLengthCodeCount, array2, 0, distanceCodeCount);
if (array[256] == 0)
{
throw new InvalidDataException();
}
literalLengthTree = new HuffmanTree(array);
distanceTree = new HuffmanTree(array2);
state = InflaterState.DecodeTop;
return true;
}
default:
throw new InvalidDataException(SR.GetString("Unknown state"));
}
}
}
}