using System; using System.IO; using System.IO.Compression; using System.Security.Cryptography; using System.Text; public static class EncoderUtils { public static string FromBase64ZlibCompressedString(string text) { if (text == null) return (string)null; using (StringReaderStream stringReaderStream = new StringReaderStream(text, Encoding.ASCII)) { using (CryptoStream cryptoStream = new CryptoStream((Stream)stringReaderStream, (ICryptoTransform)new FromBase64Transform(), CryptoStreamMode.Read)) { cryptoStream.ReadByte(); cryptoStream.ReadByte(); using (DeflateStream deflateStream = new DeflateStream((Stream)cryptoStream, CompressionMode.Decompress, true)) { using (StreamReader streamReader = new StreamReader((Stream)deflateStream, Encoding.ASCII)) return streamReader.ReadToEnd(); } } } } public static byte[] FromBase64String(string text) => text == null ? (byte[])null : Convert.FromBase64String(text); public static string ToBase64String(byte[] bytes) => bytes == null ? (string)null : Convert.ToBase64String(bytes); public static string ToBase64GzipString(Action writeAction) { using (MemoryStream stream = new MemoryStream()) { using (CryptoStream cryptoStream = new CryptoStream((Stream)stream, (ICryptoTransform)new ToBase64Transform(), CryptoStreamMode.Write)) { using (GZipStream gzipStream = new GZipStream((Stream)cryptoStream, CompressionMode.Compress, true)) writeAction(gzipStream); cryptoStream.FlushFinalBlock(); return EncoderUtils.MemoryStreamToString(stream, Encoding.ASCII); } } } public static string FromBase64GzipString(string text) => EncoderUtils.UncompressGzipToString(EncoderUtils.FromBase64String(text)); public static byte[] ToGzipBytes(Action writeAction) { using (MemoryStream stream = new MemoryStream()) { using (GZipStream gzipStream = new GZipStream((Stream)stream, CompressionMode.Compress, true)) writeAction(gzipStream); return EncoderUtils.MemoryStreamToByteArray(stream); } } public static string ToBase64GzipString(string str, Encoding encoding = null) => str == null ? (string)null : EncoderUtils.ToBase64GzipString((Action)(s => EncoderUtils.WriteStringToStream(str, (Stream)s, encoding))); public static byte[] ToGzipBytes(string str, Encoding encoding = null) => str == null ? (byte[])null : EncoderUtils.ToGzipBytes((Action)(s => EncoderUtils.WriteStringToStream(str, (Stream)s, encoding))); public static void WriteStringToStream(string str, Stream stream, Encoding encoding = null) { using (StreamWriter streamWriter = encoding == null ? new StreamWriter(stream) : new StreamWriter(stream, encoding)) streamWriter.Write(str); } public static void UncompressGzipToStream(byte[] bytes, Stream stream) { if (bytes == null) return; using (MemoryStream memoryStream = new MemoryStream(bytes)) { using (GZipStream gzipStream = new GZipStream((Stream)memoryStream, CompressionMode.Decompress)) gzipStream.CopyTo(stream); } } public static string UncompressGzipToString(byte[] bytes) { if (bytes == null) return (string)null; using (MemoryStream stream = new MemoryStream()) { EncoderUtils.UncompressGzipToStream(bytes, (Stream)stream); return EncoderUtils.MemoryStreamToString(stream); } } public static string StreamToString(Stream stream, Encoding encoding = null) { if (stream == null) return (string)null; using (StreamReader streamReader = encoding == null ? new StreamReader(stream) : new StreamReader(stream, encoding)) return streamReader.ReadToEnd(); } public static string MemoryStreamToString(MemoryStream stream, Encoding encoding = null) { if (stream == null) return (string)null; stream.Position = 0L; return EncoderUtils.StreamToString((Stream)stream, encoding); } public static byte[] MemoryStreamToByteArray(MemoryStream stream) { if (stream == null) return (byte[])null; stream.Position = 0L; using (BinaryReader binaryReader = new BinaryReader((Stream)stream)) return binaryReader.ReadBytes((int)stream.Length); } } public class StringReaderStream : Stream { private string input; private readonly Encoding encoding; private int maxBytesPerChar; private int inputLength; private int inputPosition; private readonly long length; private long position; public StringReaderStream(string input) : this(input, Encoding.UTF8) { } public StringReaderStream(string input, Encoding encoding) { this.encoding = encoding ?? throw new ArgumentNullException(nameof(encoding)); this.input = input; this.inputLength = input == null ? 0 : input.Length; if (!string.IsNullOrEmpty(input)) this.length = (long)encoding.GetByteCount(input); this.maxBytesPerChar = encoding == Encoding.ASCII ? 1 : encoding.GetMaxByteCount(1); } public override bool CanRead => true; public override bool CanSeek => false; public override bool CanWrite => false; public override long Length => this.length; public override long Position { get => this.position; set => throw new NotImplementedException(); } public override void Flush() { } public override int Read(byte[] buffer, int offset, int count) { if (this.inputPosition >= this.inputLength) return 0; if (count < this.maxBytesPerChar) throw new ArgumentException("count has to be greater or equal to max encoding byte count per char"); int charCount = Math.Min(this.inputLength - this.inputPosition, count / this.maxBytesPerChar); int bytes = this.encoding.GetBytes(this.input, this.inputPosition, charCount, buffer, offset); this.inputPosition += charCount; this.position += (long)bytes; return bytes; } public override long Seek(long offset, SeekOrigin origin) => throw new NotImplementedException(); public override void SetLength(long value) => throw new NotImplementedException(); public override void Write(byte[] buffer, int offset, int count) => throw new NotImplementedException(); }