using System; using Best.HTTP.Shared.Streams; using Best.HTTP.Shared.Logger; using Best.HTTP.Shared.PlatformSupport.Memory; namespace Best.HTTP.Response.Decompression { public sealed class BrotliDecompressor : IDecompressor { #if ((NET_STANDARD_2_1 || UNITY_2021_2_OR_NEWER) && (UNITY_EDITOR || (!UNITY_WEBGL && !(ENABLE_MONO && UNITY_ANDROID)))) && !BESTHTTP_DISABLE_BROTLI private BufferSegmentStream decompressorInputStream; private BufferPoolMemoryStream decompressorOutputStream; private System.IO.Compression.BrotliStream decompressorStream; byte[] copyBuffer = null; #endif private int _minLengthToDecompress; public static bool IsSupported() { // Not enabled under android with the mono runtime #if ((NET_STANDARD_2_1 || UNITY_2021_2_OR_NEWER) && (UNITY_EDITOR || (!UNITY_WEBGL && !(ENABLE_MONO && UNITY_ANDROID)))) && !BESTHTTP_DISABLE_BROTLI return true; #else return false; #endif } public BrotliDecompressor(int minLengthToDecompress) { this._minLengthToDecompress = minLengthToDecompress; } public (BufferSegment decompressed, bool releaseTheOld) Decompress(BufferSegment segment, bool forceDecompress, bool dataCanBeLarger, LoggingContext context) { #if ((NET_STANDARD_2_1 || UNITY_2021_2_OR_NEWER) && (UNITY_EDITOR || (!UNITY_WEBGL && !(ENABLE_MONO && UNITY_ANDROID)))) && !BESTHTTP_DISABLE_BROTLI if (decompressorInputStream == null) decompressorInputStream = new BufferSegmentStream(); if (segment.Data != null) decompressorInputStream.Write(segment); if (!forceDecompress && decompressorInputStream.Length < _minLengthToDecompress) return (BufferSegment.Empty, false); if (decompressorStream == null) { decompressorStream = new System.IO.Compression.BrotliStream(decompressorInputStream, System.IO.Compression.CompressionMode.Decompress, true); } if (decompressorOutputStream == null) decompressorOutputStream = new BufferPoolMemoryStream(); decompressorOutputStream.SetLength(0); if (copyBuffer == null) copyBuffer = BufferPool.Get(4 * 1024, true); int readCount; int sumReadCount = 0; while ((readCount = decompressorStream.Read(copyBuffer, 0, copyBuffer.Length)) != 0) { decompressorOutputStream.Write(copyBuffer, 0, readCount); sumReadCount += readCount; } byte[] result = decompressorOutputStream.ToArray(dataCanBeLarger, context); return (new BufferSegment(result, 0, dataCanBeLarger ? (int)decompressorOutputStream.Length : result.Length), false); #else return (BufferSegment.Empty, false); #endif } public void Dispose() { #if ((NET_STANDARD_2_1 || UNITY_2021_2_OR_NEWER) && (UNITY_EDITOR || (!UNITY_WEBGL && !(ENABLE_MONO && UNITY_ANDROID)))) && !BESTHTTP_DISABLE_BROTLI if (decompressorStream != null) decompressorStream.Dispose(); decompressorStream = null; if (decompressorInputStream != null) decompressorInputStream.Dispose(); decompressorInputStream = null; if (decompressorOutputStream != null) decompressorOutputStream.Dispose(); decompressorOutputStream = null; BufferPool.Release(copyBuffer); copyBuffer = null; #endif } } }