/// <summary> /// Decompresses data. Uses <see cref="BrotliDecoder"/>. /// </summary> /// <returns>Decompressed data.</returns> /// <param name="compressed">Compressed data.</param> /// <exception cref="ArgumentException">Invalid data.</exception> /// <exception cref="OutOfMemoryException"></exception> public static unsafe byte[] BrotliDecompress(ReadOnlySpan <byte> compressed) { int n = checked (compressed.Length * 4 + 8000); for (int i = 0; i < 3; i++) { if (n < 512_000) { n *= 2; } } //print.it(compressed.Length, n, n/compressed.Length); //usually ~ 80 KB for (; ; n = checked (n * 2)) { byte *b = null; try { b = MemoryUtil.Alloc(n); if (BrotliDecoder.TryDecompress(compressed, new(b, n), out int nw)) { return(new Span <byte>(b, nw).ToArray()); } if (nw == 0) { throw new ArgumentException("cannot decompress this data"); } //print.it(n); } finally { MemoryUtil.Free(b); } } }
/// <summary> /// Compresses data. Uses <see cref="BrotliEncoder"/>. /// </summary> /// <param name="data">Data. See also: <see cref="MemoryMarshal.AsBytes"/>, <see cref="CollectionsMarshal.AsSpan"/>.</param> /// <param name="level">Compression level, 0 (no compression) to 11 (maximal compression). Default 6. Bigger levels don't make much smaller but can make much slower.</param> /// <exception cref="ArgumentOutOfRangeException">Invalid <i>level</i>.</exception> /// <exception cref="OutOfMemoryException"></exception> public static unsafe byte[] BrotliCompress(ReadOnlySpan <byte> data, int level = 6) { int n = BrotliEncoder.GetMaxCompressedLength(data.Length); var b = MemoryUtil.Alloc(n); try { if (!BrotliEncoder.TryCompress(data, new(b, n), out n, level, 22)) { throw new AuException(); } return(new Span <byte>(b, n).ToArray()); } finally { MemoryUtil.Free(b); } }