Files
test/Assets/PerfectWorld/Scripts/Utils/AFilePackage.cs
T
2026-02-04 15:17:39 +07:00

138 lines
5.5 KiB
C#

using System;
using System.IO;
using System.IO.Compression;
using Unity.SharpZipLib.Zip.Compression.Streams;
using UnityEngine;
using CompressionLevel = System.IO.Compression.CompressionLevel;
namespace BrewMonster
{
public class AFilePackage
{
private const short Z_OK = 0;
private const short Z_ERROR = -2;
private const short Z_BUF_ERROR = -5;
private const short Z_DATA_ERROR = -3;
/*
Uncompress a data buffer
pCompressedBuffer IN buffer contains compressed data to be uncompressed
dwCompressedLength IN the compressed data size
pFileBuffer OUT the uncompressed data buffer
pdwFileLength IN/OUT the uncompressed data buffer size as input
when out, it is the real uncompressed data length
RETURN: 0, ok
-1, dest buffer is too small
-2, unknown error
*/
public static int Uncompress(byte[] compressedBuffer, int compressedLength, byte[] fileBuffer, ref uint fileLength)
{
int result = ZlibUnCompressDeflate(fileBuffer, ref fileLength, compressedBuffer, compressedLength);
return result;
}
/// <summary>
/// Compress data (raw deflate). Caller should allocate dst with size >= dstOffset + srcLen * 2 for safety.
/// 压缩数据(原始 deflate)。调用方应分配 dst 大小 >= dstOffset + srcLen * 2。
/// </summary>
/// <param name="dstOffset">Start index in dst where compressed bytes are written. 压缩数据写入 dst 的起始下标。</param>
/// <param name="dstLen">On input max length; on output actual compressed length. 输入为最大长度,输出为实际压缩长度。</param>
/// <returns>0 ok, non-zero error</returns>
public static int Compress(byte[] src, int srcLen, byte[] dst, int dstOffset, ref int dstLen)
{
try
{
using (var output = new MemoryStream())
{
using (var deflate = new DeflateStream(output, CompressionLevel.Fastest))
{
deflate.Write(src, 0, srcLen);
}
byte[] compressed = output.ToArray();
if (dstOffset + compressed.Length > dst.Length)
return Z_BUF_ERROR;
Buffer.BlockCopy(compressed, 0, dst, dstOffset, compressed.Length);
dstLen = compressed.Length;
return Z_OK;
}
}
catch (Exception e)
{
Console.WriteLine($"ERROR::AFilePackage::Compress: {e.Message}");
return Z_ERROR;
}
}
private static int ZlibUnCompress(byte[] dest, ref int destLen, byte[] source, int sourceLen)
{
try
{
using (MemoryStream input = new MemoryStream(source, 0, sourceLen)) // No need to skip zlib headers manually
using (InflaterInputStream decompressionStream = new InflaterInputStream(input))
using (MemoryStream output = new MemoryStream())
{
decompressionStream.CopyTo(output);
int totalOut = (int)output.Length;
if (totalOut > dest.Length)
{
return Z_BUF_ERROR; // Buffer too small
}
Array.Copy(output.ToArray(), dest, totalOut);
destLen = totalOut;
}
return Z_OK; // Success
}
catch (InvalidDataException invalidDataException)
{
Console.WriteLine($"ERROR::ZlibUnCompress::InvalidDataException: {invalidDataException.Message}");
return Z_DATA_ERROR; // Invalid zlib data
}
catch (Exception e)
{
Console.WriteLine($"ERROR::ZlibUnCompress::Exception: {e.Message}");
return Z_ERROR; // General error
}
}
private static int ZlibUnCompressDeflate(byte[] dest, ref uint destLen, byte[] source, int sourceLen)
{
try
{
using (MemoryStream input = new MemoryStream(source, 2, sourceLen - 6))
using (DeflateStream decompressionStream = new DeflateStream(input, CompressionMode.Decompress))
using (MemoryStream output = new MemoryStream())
{
decompressionStream.CopyTo(output);
uint totalOut = (uint)output.Length;
if (totalOut > dest.Length)
{
return Z_BUF_ERROR; // Buffer too small
}
Array.Copy(output.ToArray(), dest, totalOut);
destLen = totalOut;
}
return Z_OK; // Success
}
catch (InvalidDataException invalidDataException)
{
Console.WriteLine($"ERROR::ZlibUnCompress::InvalidDataException: {invalidDataException.Message}");
return Z_DATA_ERROR; // Invalid zlib data
}
catch (Exception e)
{
Console.WriteLine($"ERROR::ZlibUnCompress::Exception: {e.Message}");
return Z_ERROR; // General error
}
}
}
}