2025-10-11 15:18:09 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
|
2026-03-23 20:01:59 +08:00
|
|
|
|
using ICSharpCode.SharpZipLib.GZip;
|
|
|
|
|
|
|
2025-10-11 15:18:09 +08:00
|
|
|
|
namespace AlicizaX
|
|
|
|
|
|
{
|
|
|
|
|
|
public static partial class Utility
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 压缩解压缩相关的实用函数。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static partial class Compression
|
|
|
|
|
|
{
|
2026-03-23 20:01:59 +08:00
|
|
|
|
private const int CachedBytesLength = 0x1000;
|
|
|
|
|
|
|
2025-10-11 15:18:09 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 压缩数据。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="bytes">要压缩的数据的二进制流。</param>
|
|
|
|
|
|
/// <returns>压缩后的数据的二进制流。</returns>
|
|
|
|
|
|
public static byte[] Compress(byte[] bytes)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (bytes == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Bytes is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return Compress(bytes, 0, bytes.Length);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 压缩数据。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="bytes">要压缩的数据的二进制流。</param>
|
|
|
|
|
|
/// <param name="compressedStream">压缩后的数据的二进制流。</param>
|
|
|
|
|
|
/// <returns>是否压缩数据成功。</returns>
|
|
|
|
|
|
public static bool Compress(byte[] bytes, Stream compressedStream)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (bytes == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Bytes is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return Compress(bytes, 0, bytes.Length, compressedStream);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 压缩数据。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="bytes">要压缩的数据的二进制流。</param>
|
|
|
|
|
|
/// <param name="offset">要压缩的数据的二进制流的偏移。</param>
|
|
|
|
|
|
/// <param name="length">要压缩的数据的二进制流的长度。</param>
|
|
|
|
|
|
/// <returns>压缩后的数据的二进制流。</returns>
|
|
|
|
|
|
public static byte[] Compress(byte[] bytes, int offset, int length)
|
|
|
|
|
|
{
|
|
|
|
|
|
using (MemoryStream compressedStream = new MemoryStream())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Compress(bytes, offset, length, compressedStream))
|
|
|
|
|
|
{
|
|
|
|
|
|
return compressedStream.ToArray();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 压缩数据。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="bytes">要压缩的数据的二进制流。</param>
|
|
|
|
|
|
/// <param name="offset">要压缩的数据的二进制流的偏移。</param>
|
|
|
|
|
|
/// <param name="length">要压缩的数据的二进制流的长度。</param>
|
|
|
|
|
|
/// <param name="compressedStream">压缩后的数据的二进制流。</param>
|
|
|
|
|
|
/// <returns>是否压缩数据成功。</returns>
|
|
|
|
|
|
public static bool Compress(byte[] bytes, int offset, int length, Stream compressedStream)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (bytes == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Bytes is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (offset < 0 || length < 0 || offset + length > bytes.Length)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Offset or length is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (compressedStream == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Compressed stream is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2026-03-23 20:01:59 +08:00
|
|
|
|
using (GZipOutputStream gzipOutputStream = new GZipOutputStream(compressedStream))
|
|
|
|
|
|
{
|
|
|
|
|
|
gzipOutputStream.Write(bytes, offset, length);
|
|
|
|
|
|
gzipOutputStream.Finish();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ProcessHeader(compressedStream);
|
|
|
|
|
|
return true;
|
2025-10-11 15:18:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (exception is GameFrameworkException)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
throw new GameFrameworkException(Text.Format("Can not compress with exception '{0}'.", exception), exception);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 压缩数据。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="stream">要压缩的数据的二进制流。</param>
|
|
|
|
|
|
/// <returns>压缩后的数据的二进制流。</returns>
|
|
|
|
|
|
public static byte[] Compress(Stream stream)
|
|
|
|
|
|
{
|
|
|
|
|
|
using (MemoryStream compressedStream = new MemoryStream())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Compress(stream, compressedStream))
|
|
|
|
|
|
{
|
|
|
|
|
|
return compressedStream.ToArray();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 压缩数据。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="stream">要压缩的数据的二进制流。</param>
|
|
|
|
|
|
/// <param name="compressedStream">压缩后的数据的二进制流。</param>
|
|
|
|
|
|
/// <returns>是否压缩数据成功。</returns>
|
|
|
|
|
|
public static bool Compress(Stream stream, Stream compressedStream)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (stream == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Stream is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (compressedStream == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Compressed stream is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2026-03-23 20:01:59 +08:00
|
|
|
|
byte[] cachedBytes = new byte[CachedBytesLength];
|
|
|
|
|
|
using (GZipOutputStream gzipOutputStream = new GZipOutputStream(compressedStream))
|
|
|
|
|
|
{
|
|
|
|
|
|
int bytesRead;
|
|
|
|
|
|
while ((bytesRead = stream.Read(cachedBytes, 0, CachedBytesLength)) > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
gzipOutputStream.Write(cachedBytes, 0, bytesRead);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
gzipOutputStream.Finish();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ProcessHeader(compressedStream);
|
|
|
|
|
|
return true;
|
2025-10-11 15:18:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (exception is GameFrameworkException)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
throw new GameFrameworkException(Text.Format("Can not compress with exception '{0}'.", exception), exception);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 解压缩数据。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="bytes">要解压缩的数据的二进制流。</param>
|
|
|
|
|
|
/// <returns>解压缩后的数据的二进制流。</returns>
|
|
|
|
|
|
public static byte[] Decompress(byte[] bytes)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (bytes == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Bytes is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return Decompress(bytes, 0, bytes.Length);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 解压缩数据。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="bytes">要解压缩的数据的二进制流。</param>
|
|
|
|
|
|
/// <param name="decompressedStream">解压缩后的数据的二进制流。</param>
|
|
|
|
|
|
/// <returns>是否解压缩数据成功。</returns>
|
|
|
|
|
|
public static bool Decompress(byte[] bytes, Stream decompressedStream)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (bytes == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Bytes is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return Decompress(bytes, 0, bytes.Length, decompressedStream);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 解压缩数据。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="bytes">要解压缩的数据的二进制流。</param>
|
|
|
|
|
|
/// <param name="offset">要解压缩的数据的二进制流的偏移。</param>
|
|
|
|
|
|
/// <param name="length">要解压缩的数据的二进制流的长度。</param>
|
|
|
|
|
|
/// <returns>解压缩后的数据的二进制流。</returns>
|
|
|
|
|
|
public static byte[] Decompress(byte[] bytes, int offset, int length)
|
|
|
|
|
|
{
|
|
|
|
|
|
using (MemoryStream decompressedStream = new MemoryStream())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Decompress(bytes, offset, length, decompressedStream))
|
|
|
|
|
|
{
|
|
|
|
|
|
return decompressedStream.ToArray();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 解压缩数据。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="bytes">要解压缩的数据的二进制流。</param>
|
|
|
|
|
|
/// <param name="offset">要解压缩的数据的二进制流的偏移。</param>
|
|
|
|
|
|
/// <param name="length">要解压缩的数据的二进制流的长度。</param>
|
|
|
|
|
|
/// <param name="decompressedStream">解压缩后的数据的二进制流。</param>
|
|
|
|
|
|
/// <returns>是否解压缩数据成功。</returns>
|
|
|
|
|
|
public static bool Decompress(byte[] bytes, int offset, int length, Stream decompressedStream)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (bytes == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Bytes is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (offset < 0 || length < 0 || offset + length > bytes.Length)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Offset or length is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (decompressedStream == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Decompressed stream is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2026-03-23 20:01:59 +08:00
|
|
|
|
byte[] cachedBytes = new byte[CachedBytesLength];
|
|
|
|
|
|
using (MemoryStream memoryStream = new MemoryStream(bytes, offset, length, false))
|
|
|
|
|
|
using (GZipInputStream gzipInputStream = new GZipInputStream(memoryStream))
|
|
|
|
|
|
{
|
|
|
|
|
|
int bytesRead;
|
|
|
|
|
|
while ((bytesRead = gzipInputStream.Read(cachedBytes, 0, CachedBytesLength)) > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
decompressedStream.Write(cachedBytes, 0, bytesRead);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
2025-10-11 15:18:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (exception is GameFrameworkException)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
throw new GameFrameworkException(Text.Format("Can not decompress with exception '{0}'.", exception), exception);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 解压缩数据。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="stream">要解压缩的数据的二进制流。</param>
|
|
|
|
|
|
/// <returns>是否解压缩数据成功。</returns>
|
|
|
|
|
|
public static byte[] Decompress(Stream stream)
|
|
|
|
|
|
{
|
|
|
|
|
|
using (MemoryStream decompressedStream = new MemoryStream())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Decompress(stream, decompressedStream))
|
|
|
|
|
|
{
|
|
|
|
|
|
return decompressedStream.ToArray();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 解压缩数据。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="stream">要解压缩的数据的二进制流。</param>
|
|
|
|
|
|
/// <param name="decompressedStream">解压缩后的数据的二进制流。</param>
|
|
|
|
|
|
/// <returns>是否解压缩数据成功。</returns>
|
|
|
|
|
|
public static bool Decompress(Stream stream, Stream decompressedStream)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (stream == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Stream is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (decompressedStream == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Decompressed stream is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2026-03-23 20:01:59 +08:00
|
|
|
|
byte[] cachedBytes = new byte[CachedBytesLength];
|
|
|
|
|
|
using (GZipInputStream gzipInputStream = new GZipInputStream(stream))
|
|
|
|
|
|
{
|
|
|
|
|
|
int bytesRead;
|
|
|
|
|
|
while ((bytesRead = gzipInputStream.Read(cachedBytes, 0, CachedBytesLength)) > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
decompressedStream.Write(cachedBytes, 0, bytesRead);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
2025-10-11 15:18:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (exception is GameFrameworkException)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
throw new GameFrameworkException(Text.Format("Can not decompress with exception '{0}'.", exception), exception);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-23 20:01:59 +08:00
|
|
|
|
|
|
|
|
|
|
private static void ProcessHeader(Stream compressedStream)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (compressedStream.Length < 8L)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
long current = compressedStream.Position;
|
|
|
|
|
|
compressedStream.Position = 4L;
|
|
|
|
|
|
compressedStream.WriteByte(25);
|
|
|
|
|
|
compressedStream.WriteByte(134);
|
|
|
|
|
|
compressedStream.WriteByte(2);
|
|
|
|
|
|
compressedStream.WriteByte(32);
|
|
|
|
|
|
compressedStream.Position = current;
|
|
|
|
|
|
}
|
2025-10-11 15:18:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|