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

339 lines
7.2 KiB
C#

using System;
namespace Unity.IO.Compression
{
internal class GZipDecoder : IFileFormatReader
{
internal enum GzipHeaderState
{
ReadingID1 = 0,
ReadingID2 = 1,
ReadingCM = 2,
ReadingFLG = 3,
ReadingMMTime = 4,
ReadingXFL = 5,
ReadingOS = 6,
ReadingXLen1 = 7,
ReadingXLen2 = 8,
ReadingXLenData = 9,
ReadingFileName = 10,
ReadingComment = 11,
ReadingCRC16Part1 = 12,
ReadingCRC16Part2 = 13,
Done = 14,
ReadingCRC = 15,
ReadingFileSize = 16
}
[Flags]
internal enum GZipOptionalHeaderFlags
{
CRCFlag = 2,
ExtraFieldsFlag = 4,
FileNameFlag = 8,
CommentFlag = 0x10
}
private GzipHeaderState gzipHeaderSubstate;
private GzipHeaderState gzipFooterSubstate;
private int gzip_header_flag;
private int gzip_header_xlen;
private uint expectedCrc32;
private uint expectedOutputStreamSizeModulo;
private int loopCounter;
private uint actualCrc32;
private long actualStreamSizeModulo;
public GZipDecoder()
{
Reset();
}
public void Reset()
{
gzipHeaderSubstate = GzipHeaderState.ReadingID1;
gzipFooterSubstate = GzipHeaderState.ReadingCRC;
expectedCrc32 = 0u;
expectedOutputStreamSizeModulo = 0u;
}
public bool ReadHeader(InputBuffer input)
{
switch (gzipHeaderSubstate)
{
case GzipHeaderState.ReadingID1:
{
int bits = input.GetBits(8);
if (bits < 0)
{
return false;
}
if (bits != 31)
{
throw new InvalidDataException(SR.GetString("Corrupted gzip header"));
}
gzipHeaderSubstate = GzipHeaderState.ReadingID2;
goto case GzipHeaderState.ReadingID2;
}
case GzipHeaderState.ReadingID2:
{
int bits = input.GetBits(8);
if (bits < 0)
{
return false;
}
if (bits != 139)
{
throw new InvalidDataException(SR.GetString("Corrupted gzip header"));
}
gzipHeaderSubstate = GzipHeaderState.ReadingCM;
goto case GzipHeaderState.ReadingCM;
}
case GzipHeaderState.ReadingCM:
{
int bits = input.GetBits(8);
if (bits < 0)
{
return false;
}
if (bits != 8)
{
throw new InvalidDataException(SR.GetString("Unknown compression mode"));
}
gzipHeaderSubstate = GzipHeaderState.ReadingFLG;
goto case GzipHeaderState.ReadingFLG;
}
case GzipHeaderState.ReadingFLG:
{
int bits = input.GetBits(8);
if (bits < 0)
{
return false;
}
gzip_header_flag = bits;
gzipHeaderSubstate = GzipHeaderState.ReadingMMTime;
loopCounter = 0;
goto case GzipHeaderState.ReadingMMTime;
}
case GzipHeaderState.ReadingMMTime:
{
int bits = 0;
while (loopCounter < 4)
{
bits = input.GetBits(8);
if (bits < 0)
{
return false;
}
loopCounter++;
}
gzipHeaderSubstate = GzipHeaderState.ReadingXFL;
loopCounter = 0;
goto case GzipHeaderState.ReadingXFL;
}
case GzipHeaderState.ReadingXFL:
{
int bits = input.GetBits(8);
if (bits < 0)
{
return false;
}
gzipHeaderSubstate = GzipHeaderState.ReadingOS;
goto case GzipHeaderState.ReadingOS;
}
case GzipHeaderState.ReadingOS:
{
int bits = input.GetBits(8);
if (bits < 0)
{
return false;
}
gzipHeaderSubstate = GzipHeaderState.ReadingXLen1;
goto case GzipHeaderState.ReadingXLen1;
}
case GzipHeaderState.ReadingXLen1:
{
if ((gzip_header_flag & 4) == 0)
{
goto case GzipHeaderState.ReadingFileName;
}
int bits = input.GetBits(8);
if (bits < 0)
{
return false;
}
gzip_header_xlen = bits;
gzipHeaderSubstate = GzipHeaderState.ReadingXLen2;
goto case GzipHeaderState.ReadingXLen2;
}
case GzipHeaderState.ReadingXLen2:
{
int bits = input.GetBits(8);
if (bits < 0)
{
return false;
}
gzip_header_xlen |= bits << 8;
gzipHeaderSubstate = GzipHeaderState.ReadingXLenData;
loopCounter = 0;
goto case GzipHeaderState.ReadingXLenData;
}
case GzipHeaderState.ReadingXLenData:
{
int bits = 0;
while (loopCounter < gzip_header_xlen)
{
bits = input.GetBits(8);
if (bits < 0)
{
return false;
}
loopCounter++;
}
gzipHeaderSubstate = GzipHeaderState.ReadingFileName;
loopCounter = 0;
goto case GzipHeaderState.ReadingFileName;
}
case GzipHeaderState.ReadingFileName:
if ((gzip_header_flag & 8) == 0)
{
gzipHeaderSubstate = GzipHeaderState.ReadingComment;
}
else
{
int bits;
do
{
bits = input.GetBits(8);
if (bits < 0)
{
return false;
}
}
while (bits != 0);
gzipHeaderSubstate = GzipHeaderState.ReadingComment;
}
goto case GzipHeaderState.ReadingComment;
case GzipHeaderState.ReadingComment:
if ((gzip_header_flag & 0x10) == 0)
{
gzipHeaderSubstate = GzipHeaderState.ReadingCRC16Part1;
}
else
{
int bits;
do
{
bits = input.GetBits(8);
if (bits < 0)
{
return false;
}
}
while (bits != 0);
gzipHeaderSubstate = GzipHeaderState.ReadingCRC16Part1;
}
goto case GzipHeaderState.ReadingCRC16Part1;
case GzipHeaderState.ReadingCRC16Part1:
{
if ((gzip_header_flag & 2) == 0)
{
gzipHeaderSubstate = GzipHeaderState.Done;
goto case GzipHeaderState.Done;
}
int bits = input.GetBits(8);
if (bits < 0)
{
return false;
}
gzipHeaderSubstate = GzipHeaderState.ReadingCRC16Part2;
goto case GzipHeaderState.ReadingCRC16Part2;
}
case GzipHeaderState.ReadingCRC16Part2:
{
int bits = input.GetBits(8);
if (bits < 0)
{
return false;
}
gzipHeaderSubstate = GzipHeaderState.Done;
goto case GzipHeaderState.Done;
}
case GzipHeaderState.Done:
return true;
default:
throw new InvalidDataException(SR.GetString("Unknown state"));
}
}
public bool ReadFooter(InputBuffer input)
{
input.SkipToByteBoundary();
if (gzipFooterSubstate == GzipHeaderState.ReadingCRC)
{
while (loopCounter < 4)
{
int bits = input.GetBits(8);
if (bits < 0)
{
return false;
}
expectedCrc32 |= (uint)(bits << 8 * loopCounter);
loopCounter++;
}
gzipFooterSubstate = GzipHeaderState.ReadingFileSize;
loopCounter = 0;
}
if (gzipFooterSubstate == GzipHeaderState.ReadingFileSize)
{
if (loopCounter == 0)
{
expectedOutputStreamSizeModulo = 0u;
}
while (loopCounter < 4)
{
int bits2 = input.GetBits(8);
if (bits2 < 0)
{
return false;
}
expectedOutputStreamSizeModulo |= (uint)(bits2 << 8 * loopCounter);
loopCounter++;
}
}
return true;
}
public void UpdateWithBytesRead(byte[] buffer, int offset, int copied)
{
actualCrc32 = Crc32Helper.UpdateCrc32(actualCrc32, buffer, offset, copied);
long num = actualStreamSizeModulo + (uint)copied;
if (num >= 4294967296L)
{
num %= 4294967296L;
}
actualStreamSizeModulo = num;
}
public void Validate()
{
if (expectedCrc32 != actualCrc32)
{
throw new InvalidDataException(SR.GetString("Invalid CRC"));
}
if (actualStreamSizeModulo != expectedOutputStreamSizeModulo)
{
throw new InvalidDataException(SR.GetString("Invalid stream size"));
}
}
}
}