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; } /// /// Compress data in zlib format (2-byte header + deflate + 4-byte Adler-32), matching what UnCompress expects. /// 压缩为 zlib 格式(2 字节头 + deflate + 4 字节 Adler-32),与 UnCompress 一致。 /// /// Start index in dst where compressed bytes are written. 压缩数据写入 dst 的起始下标。 /// On input max length; on output actual compressed length. 输入为最大长度,输出为实际压缩长度。 /// 0 ok, non-zero error public static int Compress(byte[] src, int srcOffset, int srcLen, byte[] dst, int dstOffset, ref int dstLen) { try { // Raw deflate into temporary buffer (same as decompression uses DeflateStream) byte[] deflateBytes; using (var deflateOutput = new MemoryStream()) { using (var deflate = new DeflateStream(deflateOutput, CompressionLevel.Optimal)) { deflate.Write(src, srcOffset, srcLen); } deflateBytes = deflateOutput.ToArray(); } // Zlib format: 2-byte header + deflate + 4-byte Adler-32 (matches ZlibUnCompressDeflate which skips 2, length-6) const int zlibHeaderLen = 2; const int zlibFooterLen = 4; int totalLen = zlibHeaderLen + deflateBytes.Length + zlibFooterLen; if (dstOffset + totalLen > dst.Length) return Z_BUF_ERROR; int writeAt = dstOffset; // 2-byte zlib header (deflate, 32K window, default compression) dst[writeAt++] = 0x78; dst[writeAt++] = 0x9C; Buffer.BlockCopy(deflateBytes, 0, dst, writeAt, deflateBytes.Length); writeAt += deflateBytes.Length; // 4-byte Adler-32 of uncompressed data (big-endian) uint adler = Adler32(src, srcOffset, srcLen); dst[writeAt++] = (byte)(adler >> 24); dst[writeAt++] = (byte)(adler >> 16); dst[writeAt++] = (byte)(adler >> 8); dst[writeAt++] = (byte)(adler); dstLen = totalLen; return Z_OK; } catch (Exception e) { Console.WriteLine($"ERROR::AFilePackage::Compress: {e.Message}"); return Z_ERROR; } } private static uint Adler32(byte[] data, int offset, int length) { const uint Mod = 65521u; uint a = 1u, b = 0u; for (int i = 0; i < length; i++) { byte c = data[offset + i]; a = (a + c) % Mod; b = (b + a) % Mod; } return (b << 16) | a; } 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 } } } }