GZipDecompressor.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. using BestHTTP.Extensions;
  2. using BestHTTP.PlatformSupport.Memory;
  3. using System;
  4. namespace BestHTTP.Decompression
  5. {
  6. public struct DecompressedData
  7. {
  8. public readonly byte[] Data;
  9. public readonly int Length;
  10. internal DecompressedData(byte[] data, int length)
  11. {
  12. this.Data = data;
  13. this.Length = length;
  14. }
  15. }
  16. public sealed class GZipDecompressor : IDisposable
  17. {
  18. private BufferPoolMemoryStream decompressorInputStream;
  19. private BufferPoolMemoryStream decompressorOutputStream;
  20. private Zlib.GZipStream decompressorGZipStream;
  21. private int MinLengthToDecompress = 256;
  22. public GZipDecompressor(int minLengthToDecompress)
  23. {
  24. this.MinLengthToDecompress = minLengthToDecompress;
  25. }
  26. private void CloseDecompressors()
  27. {
  28. if (decompressorGZipStream != null)
  29. decompressorGZipStream.Dispose();
  30. decompressorGZipStream = null;
  31. if (decompressorInputStream != null)
  32. decompressorInputStream.Dispose();
  33. decompressorInputStream = null;
  34. if (decompressorOutputStream != null)
  35. decompressorOutputStream.Dispose();
  36. decompressorOutputStream = null;
  37. }
  38. public DecompressedData Decompress(byte[] data, int offset, int count, bool forceDecompress = false, bool dataCanBeLarger = false)
  39. {
  40. if (decompressorInputStream == null)
  41. decompressorInputStream = new BufferPoolMemoryStream(count);
  42. if (data != null)
  43. decompressorInputStream.Write(data, offset, count);
  44. if (!forceDecompress && decompressorInputStream.Length < MinLengthToDecompress)
  45. return new DecompressedData(null, 0);
  46. decompressorInputStream.Position = 0;
  47. if (decompressorGZipStream == null)
  48. {
  49. decompressorGZipStream = new Zlib.GZipStream(decompressorInputStream,
  50. Zlib.CompressionMode.Decompress,
  51. Zlib.CompressionLevel.Default,
  52. true);
  53. decompressorGZipStream.FlushMode = Zlib.FlushType.Sync;
  54. }
  55. if (decompressorOutputStream == null)
  56. decompressorOutputStream = new BufferPoolMemoryStream();
  57. decompressorOutputStream.SetLength(0);
  58. byte[] copyBuffer = BufferPool.Get(1024, true);
  59. int readCount;
  60. int sumReadCount = 0;
  61. while ((readCount = decompressorGZipStream.Read(copyBuffer, 0, copyBuffer.Length)) != 0)
  62. {
  63. decompressorOutputStream.Write(copyBuffer, 0, readCount);
  64. sumReadCount += readCount;
  65. }
  66. BufferPool.Release(copyBuffer);
  67. // If no read is done (returned with any data) don't zero out the input stream, as it would delete any not yet used data.
  68. if (sumReadCount > 0)
  69. decompressorGZipStream.SetLength(0);
  70. byte[] result = decompressorOutputStream.ToArray(dataCanBeLarger);
  71. return new DecompressedData(result, dataCanBeLarger ? (int)decompressorOutputStream.Length : result.Length);
  72. }
  73. ~GZipDecompressor()
  74. {
  75. Dispose();
  76. }
  77. public void Dispose()
  78. {
  79. CloseDecompressors();
  80. GC.SuppressFinalize(this);
  81. }
  82. }
  83. }