using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using SharpCompress.Archives.GZip; using SharpCompress.Archives.Rar; using SharpCompress.Archives.SevenZip; using SharpCompress.Archives.Tar; using SharpCompress.Archives.Zip; using SharpCompress.Common; using SharpCompress.Common.GZip; using SharpCompress.Common.Rar; using SharpCompress.Common.Rar.Headers; using SharpCompress.Common.SevenZip; using SharpCompress.Common.Tar; using SharpCompress.Common.Tar.Headers; using SharpCompress.Common.Zip; using SharpCompress.Common.Zip.Headers; using SharpCompress.Compressors; using SharpCompress.Compressors.BZip2; using SharpCompress.Compressors.Deflate; using SharpCompress.Compressors.Deflate64; using SharpCompress.Compressors.Filters; using SharpCompress.Compressors.LZMA; using SharpCompress.Compressors.LZMA.LZ; using SharpCompress.Compressors.LZMA.RangeCoder; using SharpCompress.Compressors.LZMA.Utilites; using SharpCompress.Compressors.PPMd; using SharpCompress.Compressors.PPMd.H; using SharpCompress.Compressors.PPMd.I1; using SharpCompress.Compressors.Rar; using SharpCompress.Compressors.Rar.UnpackV1; using SharpCompress.Compressors.Rar.UnpackV1.Decode; using SharpCompress.Compressors.Rar.UnpackV1.PPM; using SharpCompress.Compressors.Rar.UnpackV2017; using SharpCompress.Compressors.Rar.VM; using SharpCompress.Compressors.Xz; using SharpCompress.Compressors.Xz.Filters; using SharpCompress.Converters; using SharpCompress.Crypto; using SharpCompress.IO; using SharpCompress.Readers; using SharpCompress.Readers.GZip; using SharpCompress.Readers.Rar; using SharpCompress.Readers.Tar; using SharpCompress.Readers.Zip; using SharpCompress.Writers; using SharpCompress.Writers.GZip; using SharpCompress.Writers.Tar; using SharpCompress.Writers.Zip; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("SharpCompress")] [assembly: AssemblyProduct("SharpCompress")] [assembly: InternalsVisibleTo("SharpCompress.Test,PublicKey=002400000480000094000000060200000024000052534131000400000100010059acfa17d26c447a4d03f16eaa72c9187c04f16e6569dd168b080e39a6f5c9fd00f28c768cd8e9a089d5a0e1b34ccd971488e7afe030ce5ce8df2053cf12ec89f6d38065c434c09ee6af3ee284c5dc08f44774b679bf39298e57efe30d4b00aecf9e4f6f8448b2cb0146d8956dfcab606cc64a0ac38c60a7d78b0d65d3b98dc0")] [assembly: InternalsVisibleTo("SharpCompress.Test.Portable,PublicKey=002400000480000094000000060200000024000052534131000400000100010059acfa17d26c447a4d03f16eaa72c9187c04f16e6569dd168b080e39a6f5c9fd00f28c768cd8e9a089d5a0e1b34ccd971488e7afe030ce5ce8df2053cf12ec89f6d38065c434c09ee6af3ee284c5dc08f44774b679bf39298e57efe30d4b00aecf9e4f6f8448b2cb0146d8956dfcab606cc64a0ac38c60a7d78b0d65d3b98dc0")] [assembly: CLSCompliant(true)] [assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")] [assembly: AssemblyCompany("Adam Hathcock")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("SharpCompress is a compression library for NET Standard 1.0 that can unrar, decompress 7zip, decompress xz, zip/unzip, tar/untar lzip/unlzip, bzip2/unbzip2 and gzip/ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip is implemented.")] [assembly: AssemblyFileVersion("0.24.0")] [assembly: AssemblyInformationalVersion("0.24.0")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.24.0.0")] [module: UnverifiableCode] namespace SharpCompress { internal static class AssemblyInfo { internal const string PublicKeySuffix = ",PublicKey=002400000480000094000000060200000024000052534131000400000100010059acfa17d26c447a4d03f16eaa72c9187c04f16e6569dd168b080e39a6f5c9fd00f28c768cd8e9a089d5a0e1b34ccd971488e7afe030ce5ce8df2053cf12ec89f6d38065c434c09ee6af3ee284c5dc08f44774b679bf39298e57efe30d4b00aecf9e4f6f8448b2cb0146d8956dfcab606cc64a0ac38c60a7d78b0d65d3b98dc0"; } public class Lazy { private readonly Func _lazyFunc; private bool _evaluated; private T _value; public T Value { get { if (!_evaluated) { _value = _lazyFunc(); _evaluated = true; } return _value; } } public Lazy(Func lazyFunc) { _lazyFunc = lazyFunc; } } internal class LazyReadOnlyCollection : ICollection, IEnumerable, IEnumerable { private class LazyLoader : IEnumerator, IDisposable, IEnumerator { private readonly LazyReadOnlyCollection lazyReadOnlyCollection; private bool disposed; private int index = -1; public T Current => lazyReadOnlyCollection.backing[index]; object IEnumerator.Current => Current; internal LazyLoader(LazyReadOnlyCollection lazyReadOnlyCollection) { this.lazyReadOnlyCollection = lazyReadOnlyCollection; } public void Dispose() { if (!disposed) { disposed = true; } } public bool MoveNext() { if (index + 1 < lazyReadOnlyCollection.backing.Count) { index++; return true; } if (!lazyReadOnlyCollection.fullyLoaded && lazyReadOnlyCollection.source.MoveNext()) { lazyReadOnlyCollection.backing.Add(lazyReadOnlyCollection.source.Current); index++; return true; } lazyReadOnlyCollection.fullyLoaded = true; return false; } public void Reset() { throw new NotSupportedException(); } } private readonly List backing = new List(); private readonly IEnumerator source; private bool fullyLoaded; public int Count { get { EnsureFullyLoaded(); return backing.Count; } } public bool IsReadOnly => true; public LazyReadOnlyCollection(IEnumerable source) { this.source = source.GetEnumerator(); } internal void EnsureFullyLoaded() { if (!fullyLoaded) { this.ForEach(delegate { }); fullyLoaded = true; } } internal IEnumerable GetLoaded() { return backing; } public void Add(T item) { throw new NotSupportedException(); } public void Clear() { throw new NotSupportedException(); } public bool Contains(T item) { EnsureFullyLoaded(); return backing.Contains(item); } public void CopyTo(T[] array, int arrayIndex) { EnsureFullyLoaded(); backing.CopyTo(array, arrayIndex); } public bool Remove(T item) { throw new NotSupportedException(); } public IEnumerator GetEnumerator() { return new LazyLoader(this); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } internal class ReadOnlyCollection : ICollection, IEnumerable, IEnumerable { private readonly ICollection collection; public int Count => collection.Count; public bool IsReadOnly => true; public ReadOnlyCollection(ICollection collection) { this.collection = collection; } public void Add(T item) { throw new NotSupportedException(); } public void Clear() { throw new NotSupportedException(); } public bool Contains(T item) { return collection.Contains(item); } public void CopyTo(T[] array, int arrayIndex) { collection.CopyTo(array, arrayIndex); } public bool Remove(T item) { throw new NotSupportedException(); } public IEnumerator GetEnumerator() { return collection.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { throw new NotSupportedException(); } } internal static class Utility { private static readonly Action MemsetDelegate = CreateMemsetDelegate(); public static ReadOnlyCollection ToReadOnly(this IEnumerable items) { return new ReadOnlyCollection(items.ToList()); } public static int URShift(int number, int bits) { if (number >= 0) { return number >> bits; } return (number >> bits) + (2 << ~bits); } public static long URShift(long number, int bits) { if (number >= 0) { return number >> bits; } return (number >> bits) + (2L << ~bits); } public static void Fill(T[] array, int fromindex, int toindex, T val) where T : struct { if (array.Length == 0) { throw new NullReferenceException(); } if (fromindex > toindex) { throw new ArgumentException(); } if (fromindex < 0 || array.Length < toindex) { throw new IndexOutOfRangeException(); } for (int i = ((fromindex > 0) ? fromindex-- : fromindex); i < toindex; i++) { array[i] = val; } } private static Action CreateMemsetDelegate() { DynamicMethod dynamicMethod = new DynamicMethod("Memset", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, null, new Type[3] { typeof(IntPtr), typeof(byte), typeof(uint) }, typeof(Utility), skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Ldarg_2); iLGenerator.Emit(OpCodes.Initblk); iLGenerator.Emit(OpCodes.Ret); return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } public static void Memset(byte[] array, byte what, int length) { GCHandle gCHandle = GCHandle.Alloc(array, GCHandleType.Pinned); MemsetDelegate(gCHandle.AddrOfPinnedObject(), what, (uint)length); gCHandle.Free(); } public static void Memset(T[] array, T what, int length) { for (int i = 0; i < length; i++) { array[i] = what; } } public static void FillFast(T[] array, T val) where T : struct { for (int i = 0; i < array.Length; i++) { array[i] = val; } } public static void FillFast(T[] array, int start, int length, T val) where T : struct { int num = start + length; for (int i = start; i < num; i++) { array[i] = val; } } public static void Fill(T[] array, T val) where T : struct { Fill(array, 0, array.Length, val); } public static void SetSize(this List list, int count) { if (count > list.Count) { for (int i = list.Count; i < count; i++) { list.Add(0); } } else { byte[] array = new byte[count]; list.CopyTo(array, 0); list.Clear(); list.AddRange(array); } } public static void AddRange(this ICollection destination, IEnumerable source) { foreach (T item in source) { destination.Add(item); } } public static void ForEach(this IEnumerable items, Action action) { foreach (T item in items) { action(item); } } public static void Copy(Array sourceArray, long sourceIndex, Array destinationArray, long destinationIndex, long length) { if (sourceIndex > int.MaxValue || sourceIndex < int.MinValue) { throw new ArgumentOutOfRangeException(); } if (destinationIndex > int.MaxValue || destinationIndex < int.MinValue) { throw new ArgumentOutOfRangeException(); } if (length > int.MaxValue || length < int.MinValue) { throw new ArgumentOutOfRangeException(); } Array.Copy(sourceArray, (int)sourceIndex, destinationArray, (int)destinationIndex, (int)length); } public static IEnumerable AsEnumerable(this T item) { yield return item; } public static void CheckNotNull(this object obj, string name) { if (obj == null) { throw new ArgumentNullException(name); } } public static void CheckNotNullOrEmpty(this string obj, string name) { obj.CheckNotNull(name); if (obj.Length == 0) { throw new ArgumentException("String is empty."); } } public static void Skip(this Stream source, long advanceAmount) { if (source.CanSeek) { source.Position += advanceAmount; return; } byte[] transferByteArray = GetTransferByteArray(); int num = 0; int num2 = 0; do { num2 = transferByteArray.Length; if (num2 > advanceAmount) { num2 = (int)advanceAmount; } num = source.Read(transferByteArray, 0, num2); if (num > 0) { advanceAmount -= num; continue; } break; } while (advanceAmount != 0L); } public static void Skip(this Stream source) { byte[] transferByteArray = GetTransferByteArray(); while (source.Read(transferByteArray, 0, transferByteArray.Length) == transferByteArray.Length) { } } public static DateTime DosDateToDateTime(ushort iDate, ushort iTime) { int year = iDate / 512 + 1980; int num = iDate % 512 / 32; int num2 = iDate % 512 % 32; int hour = iTime / 2048; int minute = iTime % 2048 / 32; int second = iTime % 2048 % 32 * 2; if (iDate == ushort.MaxValue || num == 0 || num2 == 0) { year = 1980; num = 1; num2 = 1; } if (iTime == ushort.MaxValue) { hour = (minute = (second = 0)); } DateTime result; try { return new DateTime(year, num, num2, hour, minute, second, DateTimeKind.Local); } catch { result = default(DateTime); } return result; } public static uint DateTimeToDosTime(this DateTime? dateTime) { if (!dateTime.HasValue) { return 0u; } DateTime dateTime2 = dateTime.Value.ToLocalTime(); return (uint)((dateTime2.Second / 2) | (dateTime2.Minute << 5) | (dateTime2.Hour << 11) | (dateTime2.Day << 16) | (dateTime2.Month << 21) | (dateTime2.Year - 1980 << 25)); } public static DateTime DosDateToDateTime(uint iTime) { return DosDateToDateTime((ushort)(iTime / 65536), (ushort)(iTime % 65536)); } public static DateTime UnixTimeToDateTime(long unixtime) { return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(unixtime); } public static long TransferTo(this Stream source, Stream destination) { byte[] transferByteArray = GetTransferByteArray(); long num = 0L; int count; while (ReadTransferBlock(source, transferByteArray, out count)) { num += count; destination.Write(transferByteArray, 0, count); } return num; } public static long TransferTo(this Stream source, Stream destination, Entry entry, IReaderExtractionListener readerExtractionListener) { byte[] transferByteArray = GetTransferByteArray(); int num = 0; long num2 = 0L; int count; while (ReadTransferBlock(source, transferByteArray, out count)) { num2 += count; destination.Write(transferByteArray, 0, count); num++; readerExtractionListener.FireEntryExtractionProgress(entry, num2, num); } return num2; } private static bool ReadTransferBlock(Stream source, byte[] array, out int count) { return (count = source.Read(array, 0, array.Length)) != 0; } private static byte[] GetTransferByteArray() { return new byte[81920]; } public static bool ReadFully(this Stream stream, byte[] buffer) { int num = 0; int num2; while ((num2 = stream.Read(buffer, num, buffer.Length - num)) > 0) { num += num2; if (num >= buffer.Length) { return true; } } return num >= buffer.Length; } public static string TrimNulls(this string source) { return source.Replace('\0', ' ').Trim(); } public static bool BinaryEquals(this byte[] source, byte[] target) { if (source.Length != target.Length) { return false; } for (int i = 0; i < source.Length; i++) { if (source[i] != target[i]) { return false; } } return true; } } } namespace SharpCompress.Writers { public abstract class AbstractWriter : IWriter, IDisposable { private bool _isDisposed; protected Stream OutputStream { get; private set; } public ArchiveType WriterType { get; } protected WriterOptions WriterOptions { get; } protected AbstractWriter(ArchiveType type, WriterOptions writerOptions) { WriterType = type; WriterOptions = writerOptions; } protected void InitalizeStream(Stream stream) { OutputStream = stream; } public abstract void Write(string filename, Stream source, DateTime? modificationTime); protected virtual void Dispose(bool isDisposing) { if (isDisposing) { OutputStream.Dispose(); } } public void Dispose() { if (!_isDisposed) { GC.SuppressFinalize(this); Dispose(isDisposing: true); _isDisposed = true; } } ~AbstractWriter() { if (!_isDisposed) { Dispose(isDisposing: false); _isDisposed = true; } } } public interface IWriter : IDisposable { ArchiveType WriterType { get; } void Write(string filename, Stream source, DateTime? modificationTime); } public static class IWriterExtensions { public static void Write(this IWriter writer, string entryPath, Stream source) { writer.Write(entryPath, source, null); } public static void Write(this IWriter writer, string entryPath, FileInfo source) { if (!source.Exists) { throw new ArgumentException("Source does not exist: " + source.FullName); } using FileStream source2 = source.OpenRead(); writer.Write(entryPath, source2, source.LastWriteTime); } public static void Write(this IWriter writer, string entryPath, string source) { writer.Write(entryPath, new FileInfo(source)); } public static void WriteAll(this IWriter writer, string directory, string searchPattern = "*", SearchOption option = SearchOption.TopDirectoryOnly) { writer.WriteAll(directory, searchPattern, null, option); } public static void WriteAll(this IWriter writer, string directory, string searchPattern = "*", Expression> fileSearchFunc = null, SearchOption option = SearchOption.TopDirectoryOnly) { if (!Directory.Exists(directory)) { throw new ArgumentException("Directory does not exist: " + directory); } if (fileSearchFunc == null) { fileSearchFunc = (string n) => true; } foreach (string item in Directory.EnumerateFiles(directory, searchPattern, option).Where(fileSearchFunc.Compile())) { writer.Write(item.Substring(directory.Length), item); } } } public static class WriterFactory { public static IWriter Open(Stream stream, ArchiveType archiveType, WriterOptions writerOptions) { switch (archiveType) { case ArchiveType.GZip: if (writerOptions.CompressionType != CompressionType.GZip) { throw new InvalidFormatException("GZip archives only support GZip compression type."); } return new GZipWriter(stream, new GZipWriterOptions(writerOptions)); case ArchiveType.Zip: return new ZipWriter(stream, new ZipWriterOptions(writerOptions)); case ArchiveType.Tar: return new TarWriter(stream, new TarWriterOptions(writerOptions)); default: throw new NotSupportedException("Archive Type does not have a Writer: " + archiveType); } } } public class WriterOptions : OptionsBase { public CompressionType CompressionType { get; set; } public WriterOptions(CompressionType compressionType) { CompressionType = compressionType; } public static implicit operator WriterOptions(CompressionType compressionType) { return new WriterOptions(compressionType); } } } namespace SharpCompress.Writers.Zip { internal class ZipCentralDirectoryEntry { private readonly ZipCompressionMethod compression; private readonly string fileName; private readonly ArchiveEncoding archiveEncoding; internal DateTime? ModificationTime { get; set; } internal string Comment { get; set; } internal uint Crc { get; set; } internal ulong Compressed { get; set; } internal ulong Decompressed { get; set; } internal ushort Zip64HeaderOffset { get; set; } internal ulong HeaderOffset { get; } public ZipCentralDirectoryEntry(ZipCompressionMethod compression, string fileName, ulong headerOffset, ArchiveEncoding archiveEncoding) { this.compression = compression; this.fileName = fileName; HeaderOffset = headerOffset; this.archiveEncoding = archiveEncoding; } internal uint Write(Stream outputStream) { byte[] array = archiveEncoding.Encode(fileName); byte[] array2 = archiveEncoding.Encode(Comment); bool flag = Compressed >= uint.MaxValue || Decompressed >= uint.MaxValue; bool flag2 = flag || HeaderOffset >= uint.MaxValue; ZipCompressionMethod zipCompressionMethod = compression; uint value = (uint)(flag2 ? uint.MaxValue : Compressed); uint value2 = (uint)(flag2 ? uint.MaxValue : Decompressed); uint value3 = (uint)(flag2 ? uint.MaxValue : HeaderOffset); int num = (flag2 ? 32 : 0); byte b = (byte)(flag2 ? 45u : 20u); HeaderFlags headerFlags = (object.Equals(archiveEncoding.GetEncoding(), Encoding.UTF8) ? HeaderFlags.Efs : HeaderFlags.None); if (!outputStream.CanSeek) { if (!flag) { headerFlags |= HeaderFlags.UsePostDataDescriptor; } if (zipCompressionMethod == ZipCompressionMethod.LZMA) { headerFlags |= HeaderFlags.Bit1; } } if (Decompressed == 0L && Compressed == 0L) { zipCompressionMethod = ZipCompressionMethod.None; } byte[] obj = new byte[8] { 80, 75, 1, 2, 0, 0, 0, 0 }; obj[4] = b; obj[6] = b; outputStream.Write(obj, 0, 8); outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)headerFlags), 0, 2); outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)zipCompressionMethod), 0, 2); outputStream.Write(DataConverter.LittleEndian.GetBytes(ModificationTime.DateTimeToDosTime()), 0, 4); outputStream.Write(DataConverter.LittleEndian.GetBytes(Crc), 0, 4); outputStream.Write(DataConverter.LittleEndian.GetBytes(value), 0, 4); outputStream.Write(DataConverter.LittleEndian.GetBytes(value2), 0, 4); outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)array.Length), 0, 2); outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)num), 0, 2); outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)array2.Length), 0, 2); outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0), 0, 2); outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0), 0, 2); outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0), 0, 2); outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)33024), 0, 2); outputStream.Write(DataConverter.LittleEndian.GetBytes(value3), 0, 4); outputStream.Write(array, 0, array.Length); if (flag2) { outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)1), 0, 2); outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)(num - 4)), 0, 2); outputStream.Write(DataConverter.LittleEndian.GetBytes(Decompressed), 0, 8); outputStream.Write(DataConverter.LittleEndian.GetBytes(Compressed), 0, 8); outputStream.Write(DataConverter.LittleEndian.GetBytes(HeaderOffset), 0, 8); outputStream.Write(DataConverter.LittleEndian.GetBytes(0), 0, 4); } outputStream.Write(array2, 0, array2.Length); return (uint)(46 + array.Length + num + array2.Length); } } public class ZipWriter : AbstractWriter { internal class ZipWritingStream : Stream { private readonly CRC32 crc = new CRC32(); private readonly ZipCentralDirectoryEntry entry; private readonly Stream originalStream; private readonly Stream writeStream; private readonly ZipWriter writer; private readonly ZipCompressionMethod zipCompressionMethod; private readonly CompressionLevel compressionLevel; private CountingWritableSubStream counting; private ulong decompressed; private bool limitsExceeded; private bool isDisposed; public override bool CanRead => false; public override bool CanSeek => false; public override bool CanWrite => true; public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } internal ZipWritingStream(ZipWriter writer, Stream originalStream, ZipCentralDirectoryEntry entry, ZipCompressionMethod zipCompressionMethod, CompressionLevel compressionLevel) { this.writer = writer; this.originalStream = originalStream; this.writer = writer; this.entry = entry; this.zipCompressionMethod = zipCompressionMethod; this.compressionLevel = compressionLevel; writeStream = GetWriteStream(originalStream); } private Stream GetWriteStream(Stream writeStream) { counting = new CountingWritableSubStream(writeStream); Stream result = counting; switch (zipCompressionMethod) { case ZipCompressionMethod.None: return result; case ZipCompressionMethod.Deflate: return new DeflateStream(counting, CompressionMode.Compress, compressionLevel); case ZipCompressionMethod.BZip2: return new BZip2Stream(counting, CompressionMode.Compress, decompressConcatenated: false); case ZipCompressionMethod.LZMA: { counting.WriteByte(9); counting.WriteByte(20); counting.WriteByte(5); counting.WriteByte(0); LzmaStream lzmaStream = new LzmaStream(new LzmaEncoderProperties(!originalStream.CanSeek), isLzma2: false, counting); counting.Write(lzmaStream.Properties, 0, lzmaStream.Properties.Length); return lzmaStream; } case ZipCompressionMethod.PPMd: counting.Write(writer.PpmdProperties.Properties, 0, 2); return new PpmdStream(writer.PpmdProperties, counting, compress: true); default: throw new NotSupportedException("CompressionMethod: " + zipCompressionMethod); } } protected override void Dispose(bool disposing) { if (isDisposed) { return; } isDisposed = true; base.Dispose(disposing); if (!disposing) { return; } writeStream.Dispose(); if (limitsExceeded) { originalStream.Dispose(); return; } entry.Crc = (uint)crc.Crc32Result; entry.Compressed = counting.Count; entry.Decompressed = decompressed; bool flag = entry.Compressed >= uint.MaxValue || entry.Decompressed >= uint.MaxValue; uint compressed = (uint)(flag ? uint.MaxValue : counting.Count); uint uncompressed = (uint)(flag ? uint.MaxValue : entry.Decompressed); if (originalStream.CanSeek) { originalStream.Position = (long)(entry.HeaderOffset + 6); originalStream.WriteByte(0); if (counting.Count == 0L && entry.Decompressed == 0L) { originalStream.Position = (long)(entry.HeaderOffset + 8); originalStream.WriteByte(0); originalStream.WriteByte(0); } originalStream.Position = (long)(entry.HeaderOffset + 14); writer.WriteFooter(entry.Crc, compressed, uncompressed); if (flag && entry.Zip64HeaderOffset == 0) { throw new NotSupportedException("Attempted to write a stream that is larger than 4GiB without setting the zip64 option"); } if (entry.Zip64HeaderOffset != 0) { originalStream.Position = (long)(entry.HeaderOffset + entry.Zip64HeaderOffset); originalStream.Write(DataConverter.LittleEndian.GetBytes((ushort)1), 0, 2); originalStream.Write(DataConverter.LittleEndian.GetBytes((ushort)16), 0, 2); originalStream.Write(DataConverter.LittleEndian.GetBytes(entry.Decompressed), 0, 8); originalStream.Write(DataConverter.LittleEndian.GetBytes(entry.Compressed), 0, 8); } originalStream.Position = writer.streamPosition + (long)entry.Compressed; writer.streamPosition += (long)entry.Compressed; } else { if (flag) { throw new NotSupportedException("Streams larger than 4GiB are not supported for non-seekable streams"); } originalStream.Write(DataConverter.LittleEndian.GetBytes(134695760u), 0, 4); writer.WriteFooter(entry.Crc, compressed, uncompressed); writer.streamPosition += (long)(entry.Compressed + 16); } writer.entries.Add(entry); } public override void Flush() { writeStream.Flush(); } public override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { if (entry.Zip64HeaderOffset == 0 && (limitsExceeded || decompressed + (uint)count > uint.MaxValue || counting.Count + (uint)count > uint.MaxValue)) { throw new NotSupportedException("Attempted to write a stream that is larger than 4GiB without setting the zip64 option"); } decompressed += (uint)count; crc.SlurpBlock(buffer, offset, count); writeStream.Write(buffer, offset, count); if (entry.Zip64HeaderOffset == 0 && (decompressed > uint.MaxValue || counting.Count > uint.MaxValue)) { limitsExceeded = true; throw new NotSupportedException("Attempted to write a stream that is larger than 4GiB without setting the zip64 option"); } } } private readonly CompressionType compressionType; private readonly CompressionLevel compressionLevel; private readonly List entries = new List(); private readonly string zipComment; private long streamPosition; private PpmdProperties ppmdProps; private readonly bool isZip64; private PpmdProperties PpmdProperties { get { if (ppmdProps == null) { ppmdProps = new PpmdProperties(); } return ppmdProps; } } public ZipWriter(Stream destination, ZipWriterOptions zipWriterOptions) : base(ArchiveType.Zip, zipWriterOptions) { zipComment = zipWriterOptions.ArchiveComment ?? string.Empty; isZip64 = zipWriterOptions.UseZip64; if (destination.CanSeek) { streamPosition = destination.Position; } compressionType = zipWriterOptions.CompressionType; compressionLevel = zipWriterOptions.DeflateCompressionLevel; if (base.WriterOptions.LeaveStreamOpen) { destination = new NonDisposingStream(destination); } InitalizeStream(destination); } protected override void Dispose(bool isDisposing) { if (isDisposing) { ulong num = 0uL; foreach (ZipCentralDirectoryEntry entry in entries) { num += entry.Write(base.OutputStream); } WriteEndRecord(num); } base.Dispose(isDisposing); } private static ZipCompressionMethod ToZipCompressionMethod(CompressionType compressionType) { return compressionType switch { CompressionType.None => ZipCompressionMethod.None, CompressionType.Deflate => ZipCompressionMethod.Deflate, CompressionType.BZip2 => ZipCompressionMethod.BZip2, CompressionType.LZMA => ZipCompressionMethod.LZMA, CompressionType.PPMd => ZipCompressionMethod.PPMd, _ => throw new InvalidFormatException("Invalid compression method: " + compressionType), }; } public override void Write(string entryPath, Stream source, DateTime? modificationTime) { Write(entryPath, source, new ZipWriterEntryOptions { ModificationDateTime = modificationTime }); } public void Write(string entryPath, Stream source, ZipWriterEntryOptions zipWriterEntryOptions) { using Stream destination = WriteToStream(entryPath, zipWriterEntryOptions); source.TransferTo(destination); } public Stream WriteToStream(string entryPath, ZipWriterEntryOptions options) { ZipCompressionMethod zipCompressionMethod = ToZipCompressionMethod(options.CompressionType ?? compressionType); entryPath = NormalizeFilename(entryPath); options.ModificationDateTime = options.ModificationDateTime ?? DateTime.Now; options.EntryComment = options.EntryComment ?? string.Empty; ZipCentralDirectoryEntry entry = new ZipCentralDirectoryEntry(zipCompressionMethod, entryPath, (ulong)streamPosition, base.WriterOptions.ArchiveEncoding) { Comment = options.EntryComment, ModificationTime = options.ModificationDateTime }; bool value = isZip64; if (options.EnableZip64.HasValue) { value = options.EnableZip64.Value; } uint num = (uint)WriteHeader(entryPath, options, entry, value); streamPosition += num; return new ZipWritingStream(this, base.OutputStream, entry, zipCompressionMethod, options.DeflateCompressionLevel ?? compressionLevel); } private string NormalizeFilename(string filename) { filename = filename.Replace('\\', '/'); int num = filename.IndexOf(':'); if (num >= 0) { filename = filename.Remove(0, num + 1); } return filename.Trim(new char[1] { '/' }); } private int WriteHeader(string filename, ZipWriterEntryOptions zipWriterEntryOptions, ZipCentralDirectoryEntry entry, bool useZip64) { if (!base.OutputStream.CanSeek && useZip64) { throw new NotSupportedException("Zip64 extensions are not supported on non-seekable streams"); } ZipCompressionMethod zipCompressionMethod = ToZipCompressionMethod(zipWriterEntryOptions.CompressionType ?? compressionType); byte[] array = base.WriterOptions.ArchiveEncoding.Encode(filename); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes(67324752u), 0, 4); if (zipCompressionMethod == ZipCompressionMethod.Deflate) { if (base.OutputStream.CanSeek && useZip64) { base.OutputStream.Write(new byte[2] { 45, 0 }, 0, 2); } else { base.OutputStream.Write(new byte[2] { 20, 0 }, 0, 2); } } else { base.OutputStream.Write(new byte[2] { 63, 0 }, 0, 2); } HeaderFlags headerFlags = (object.Equals(base.WriterOptions.ArchiveEncoding.GetEncoding(), Encoding.UTF8) ? HeaderFlags.Efs : HeaderFlags.None); if (!base.OutputStream.CanSeek) { headerFlags |= HeaderFlags.UsePostDataDescriptor; if (zipCompressionMethod == ZipCompressionMethod.LZMA) { headerFlags |= HeaderFlags.Bit1; } } base.OutputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)headerFlags), 0, 2); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)zipCompressionMethod), 0, 2); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes(zipWriterEntryOptions.ModificationDateTime.DateTimeToDosTime()), 0, 4); base.OutputStream.Write(new byte[12], 0, 12); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)array.Length), 0, 2); int num = 0; if (base.OutputStream.CanSeek && useZip64) { num = 20; } base.OutputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)num), 0, 2); base.OutputStream.Write(array, 0, array.Length); if (num != 0) { base.OutputStream.Write(new byte[num], 0, num); entry.Zip64HeaderOffset = (ushort)(30 + array.Length); } return 30 + array.Length + num; } private void WriteFooter(uint crc, uint compressed, uint uncompressed) { base.OutputStream.Write(DataConverter.LittleEndian.GetBytes(crc), 0, 4); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes(compressed), 0, 4); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes(uncompressed), 0, 4); } private void WriteEndRecord(ulong size) { byte[] array = base.WriterOptions.ArchiveEncoding.Encode(zipComment); bool num = isZip64 || entries.Count > 65535 || streamPosition >= uint.MaxValue || size >= uint.MaxValue; uint value = (uint)((size >= uint.MaxValue) ? uint.MaxValue : size); uint num2 = (uint)((streamPosition >= uint.MaxValue) ? uint.MaxValue : streamPosition); if (num) { int num3 = 44; base.OutputStream.Write(new byte[4] { 80, 75, 6, 6 }, 0, 4); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes((ulong)num3), 0, 8); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0), 0, 2); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)45), 0, 2); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes(0u), 0, 4); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes(0u), 0, 4); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes((ulong)entries.Count), 0, 8); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes((ulong)entries.Count), 0, 8); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes(size), 0, 8); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes((ulong)streamPosition), 0, 8); base.OutputStream.Write(new byte[4] { 80, 75, 6, 7 }, 0, 4); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes(0uL), 0, 4); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes((ulong)streamPosition + size), 0, 8); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes(0u), 0, 4); streamPosition += num3 + 20; num2 = ((streamPosition >= uint.MaxValue) ? uint.MaxValue : num2); } base.OutputStream.Write(new byte[8] { 80, 75, 5, 6, 0, 0, 0, 0 }, 0, 8); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)entries.Count), 0, 2); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)entries.Count), 0, 2); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes(value), 0, 4); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes(num2), 0, 4); base.OutputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)array.Length), 0, 2); base.OutputStream.Write(array, 0, array.Length); } } public class ZipWriterEntryOptions { public CompressionType? CompressionType { get; set; } public CompressionLevel? DeflateCompressionLevel { get; set; } public string EntryComment { get; set; } public DateTime? ModificationDateTime { get; set; } public bool? EnableZip64 { get; set; } } public class ZipWriterOptions : WriterOptions { public CompressionLevel DeflateCompressionLevel { get; set; } = CompressionLevel.Default; public string ArchiveComment { get; set; } public bool UseZip64 { get; set; } public ZipWriterOptions(CompressionType compressionType) : base(compressionType) { } internal ZipWriterOptions(WriterOptions options) : base(options.CompressionType) { base.LeaveStreamOpen = options.LeaveStreamOpen; base.ArchiveEncoding = options.ArchiveEncoding; if (options is ZipWriterOptions zipWriterOptions) { UseZip64 = zipWriterOptions.UseZip64; DeflateCompressionLevel = zipWriterOptions.DeflateCompressionLevel; ArchiveComment = zipWriterOptions.ArchiveComment; } } } } namespace SharpCompress.Writers.Tar { public class TarWriter : AbstractWriter { private readonly bool finalizeArchiveOnClose; public TarWriter(Stream destination, TarWriterOptions options) : base(ArchiveType.Tar, options) { finalizeArchiveOnClose = options.FinalizeArchiveOnClose; if (!destination.CanWrite) { throw new ArgumentException("Tars require writable streams."); } if (base.WriterOptions.LeaveStreamOpen) { destination = new NonDisposingStream(destination); } switch (options.CompressionType) { case CompressionType.BZip2: destination = new BZip2Stream(destination, CompressionMode.Compress, decompressConcatenated: false); break; case CompressionType.GZip: destination = new GZipStream(destination, CompressionMode.Compress); break; case CompressionType.LZip: destination = new LZipStream(destination, CompressionMode.Compress); break; default: throw new InvalidFormatException("Tar does not support compression: " + options.CompressionType); case CompressionType.None: break; } InitalizeStream(destination); } public override void Write(string filename, Stream source, DateTime? modificationTime) { Write(filename, source, modificationTime, null); } private string NormalizeFilename(string filename) { filename = filename.Replace('\\', '/'); int num = filename.IndexOf(':'); if (num >= 0) { filename = filename.Remove(0, num + 1); } return filename.Trim(new char[1] { '/' }); } public void Write(string filename, Stream source, DateTime? modificationTime, long? size) { if (!source.CanSeek && !size.HasValue) { throw new ArgumentException("Seekable stream is required if no size is given."); } long size2 = size ?? source.Length; TarHeader tarHeader = new TarHeader(base.WriterOptions.ArchiveEncoding); tarHeader.LastModifiedTime = modificationTime ?? TarHeader.EPOCH; tarHeader.Name = NormalizeFilename(filename); tarHeader.Size = size2; tarHeader.Write(base.OutputStream); size = source.TransferTo(base.OutputStream); PadTo512(size.Value, forceZeros: false); } private void PadTo512(long size, bool forceZeros) { int num = (int)size % 512; if (num != 0 || forceZeros) { num = 512 - num; base.OutputStream.Write(new byte[num], 0, num); } } protected override void Dispose(bool isDisposing) { if (isDisposing) { if (finalizeArchiveOnClose) { PadTo512(0L, forceZeros: true); PadTo512(0L, forceZeros: true); } Stream outputStream = base.OutputStream; if (outputStream != null) { if (!(outputStream is BZip2Stream bZip2Stream)) { if (outputStream is LZipStream lZipStream) { lZipStream.Finish(); } } else { bZip2Stream.Finish(); } } } base.Dispose(isDisposing); } } public class TarWriterOptions : WriterOptions { public bool FinalizeArchiveOnClose { get; } public TarWriterOptions(CompressionType compressionType, bool finalizeArchiveOnClose) : base(compressionType) { FinalizeArchiveOnClose = finalizeArchiveOnClose; } internal TarWriterOptions(WriterOptions options) : this(options.CompressionType, finalizeArchiveOnClose: true) { base.ArchiveEncoding = options.ArchiveEncoding; } } } namespace SharpCompress.Writers.GZip { public class GZipWriter : AbstractWriter { private bool _wroteToStream; public GZipWriter(Stream destination, GZipWriterOptions options = null) : base(ArchiveType.GZip, options ?? new GZipWriterOptions()) { if (base.WriterOptions.LeaveStreamOpen) { destination = new NonDisposingStream(destination); } InitalizeStream(new GZipStream(destination, CompressionMode.Compress, options?.CompressionLevel ?? CompressionLevel.Default, base.WriterOptions.ArchiveEncoding.GetEncoding())); } protected override void Dispose(bool isDisposing) { if (isDisposing) { base.OutputStream.Dispose(); } base.Dispose(isDisposing); } public override void Write(string filename, Stream source, DateTime? modificationTime) { if (_wroteToStream) { throw new ArgumentException("Can only write a single stream to a GZip file."); } GZipStream gZipStream = base.OutputStream as GZipStream; gZipStream.FileName = filename; gZipStream.LastModified = modificationTime; source.TransferTo(gZipStream); _wroteToStream = true; } } public class GZipWriterOptions : WriterOptions { public CompressionLevel CompressionLevel { get; set; } = CompressionLevel.Default; public GZipWriterOptions() : base(CompressionType.GZip) { } internal GZipWriterOptions(WriterOptions options) : base(options.CompressionType) { base.LeaveStreamOpen = options.LeaveStreamOpen; base.ArchiveEncoding = options.ArchiveEncoding; if (options is GZipWriterOptions gZipWriterOptions) { CompressionLevel = gZipWriterOptions.CompressionLevel; } } } } namespace SharpCompress.Readers { public abstract class AbstractReader : IReader, IDisposable, IReaderExtractionListener, IExtractionListener where TEntry : Entry where TVolume : Volume { private bool completed; private IEnumerator entriesForCurrentReadStream; private bool wroteCurrentEntry; internal ReaderOptions Options { get; } public ArchiveType ArchiveType { get; } public abstract TVolume Volume { get; } public TEntry Entry => entriesForCurrentReadStream.Current; public bool Cancelled { get; private set; } IEntry IReader.Entry => Entry; public event EventHandler> EntryExtractionProgress; public event EventHandler CompressedBytesRead; public event EventHandler FilePartExtractionBegin; internal AbstractReader(ReaderOptions options, ArchiveType archiveType) { ArchiveType = archiveType; Options = options; } public void Dispose() { entriesForCurrentReadStream?.Dispose(); Volume?.Dispose(); } public void Cancel() { if (!completed) { Cancelled = true; } } public bool MoveToNextEntry() { if (completed) { return false; } if (Cancelled) { throw new InvalidOperationException("Reader has been cancelled."); } if (entriesForCurrentReadStream == null) { return LoadStreamForReading(RequestInitialStream()); } if (!wroteCurrentEntry) { SkipEntry(); } wroteCurrentEntry = false; if (NextEntryForCurrentStream()) { return true; } completed = true; return false; } protected bool LoadStreamForReading(Stream stream) { entriesForCurrentReadStream?.Dispose(); if (stream == null || !stream.CanRead) { throw new MultipartStreamRequiredException("File is split into multiple archives: '" + Entry.Key + "'. A new readable stream is required. Use Cancel if it was intended."); } entriesForCurrentReadStream = GetEntries(stream).GetEnumerator(); return entriesForCurrentReadStream.MoveNext(); } protected virtual Stream RequestInitialStream() { return Volume.Stream; } internal virtual bool NextEntryForCurrentStream() { return entriesForCurrentReadStream.MoveNext(); } protected abstract IEnumerable GetEntries(Stream stream); private void SkipEntry() { if (!Entry.IsDirectory) { Skip(); } } private void Skip() { if (ArchiveType != ArchiveType.Rar && !Entry.IsSolid && Entry.CompressedSize > 0) { FilePart filePart = Entry.Parts.First(); Stream rawStream = filePart.GetRawStream(); if (rawStream != null) { long compressedSize = Entry.CompressedSize; rawStream.Skip(compressedSize); filePart.Skipped = true; return; } } using EntryStream source = OpenEntryStream(); source.Skip(); } public void WriteEntryTo(Stream writableStream) { if (wroteCurrentEntry) { throw new ArgumentException("WriteEntryTo or OpenEntryStream can only be called once."); } if (writableStream == null || !writableStream.CanWrite) { throw new ArgumentNullException("A writable Stream was required. Use Cancel if that was intended."); } Write(writableStream); wroteCurrentEntry = true; } internal void Write(Stream writeStream) { using Stream source = OpenEntryStream(); source.TransferTo(writeStream, Entry, this); } public EntryStream OpenEntryStream() { if (wroteCurrentEntry) { throw new ArgumentException("WriteEntryTo or OpenEntryStream can only be called once."); } EntryStream entryStream = GetEntryStream(); wroteCurrentEntry = true; return entryStream; } protected EntryStream CreateEntryStream(Stream decompressed) { return new EntryStream(this, decompressed); } protected virtual EntryStream GetEntryStream() { return CreateEntryStream(Entry.Parts.First().GetCompressedStream()); } void IExtractionListener.FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes) { this.CompressedBytesRead?.Invoke(this, new CompressedBytesReadEventArgs { CurrentFilePartCompressedBytesRead = currentPartCompressedBytes, CompressedBytesRead = compressedReadBytes }); } void IExtractionListener.FireFilePartExtractionBegin(string name, long size, long compressedSize) { this.FilePartExtractionBegin?.Invoke(this, new FilePartExtractionBeginEventArgs { CompressedSize = compressedSize, Size = size, Name = name }); } void IReaderExtractionListener.FireEntryExtractionProgress(Entry entry, long bytesTransferred, int iterations) { this.EntryExtractionProgress?.Invoke(this, new ReaderExtractionEventArgs(entry, new ReaderProgress(entry, bytesTransferred, iterations))); } } public interface IReader : IDisposable { ArchiveType ArchiveType { get; } IEntry Entry { get; } bool Cancelled { get; } event EventHandler> EntryExtractionProgress; event EventHandler CompressedBytesRead; event EventHandler FilePartExtractionBegin; void WriteEntryTo(Stream writableStream); void Cancel(); bool MoveToNextEntry(); EntryStream OpenEntryStream(); } public static class IReaderExtensions { public static void WriteEntryTo(this IReader reader, string filePath) { using Stream writableStream = File.Open(filePath, FileMode.Create, FileAccess.Write); reader.WriteEntryTo(writableStream); } public static void WriteEntryTo(this IReader reader, FileInfo filePath) { using Stream writableStream = filePath.Open(FileMode.Create); reader.WriteEntryTo(writableStream); } public static void WriteAllToDirectory(this IReader reader, string destinationDirectory, ExtractionOptions options = null) { while (reader.MoveToNextEntry()) { reader.WriteEntryToDirectory(destinationDirectory, options); } } public static void WriteEntryToDirectory(this IReader reader, string destinationDirectory, ExtractionOptions options = null) { ExtractionMethods.WriteEntryToDirectory(reader.Entry, destinationDirectory, options, reader.WriteEntryToFile); } public static void WriteEntryToFile(this IReader reader, string destinationFileName, ExtractionOptions options = null) { ExtractionMethods.WriteEntryToFile(reader.Entry, destinationFileName, options, delegate(string x, FileMode fm) { using FileStream writableStream = File.Open(destinationFileName, fm); reader.WriteEntryTo(writableStream); }); } } internal interface IReaderExtractionListener : IExtractionListener { void FireEntryExtractionProgress(Entry entry, long sizeTransferred, int iterations); } public static class ReaderFactory { public static IReader Open(Stream stream, ReaderOptions options = null) { stream.CheckNotNull("stream"); options = options ?? new ReaderOptions { LeaveStreamOpen = false }; RewindableStream rewindableStream = new RewindableStream(stream); rewindableStream.StartRecording(); if (ZipArchive.IsZipFile(rewindableStream, options.Password)) { rewindableStream.Rewind(stopRecording: true); return ZipReader.Open(rewindableStream, options); } rewindableStream.Rewind(stopRecording: false); if (GZipArchive.IsGZipFile(rewindableStream)) { rewindableStream.Rewind(stopRecording: false); if (TarArchive.IsTarFile(new GZipStream(rewindableStream, CompressionMode.Decompress))) { rewindableStream.Rewind(stopRecording: true); return new TarReader(rewindableStream, options, CompressionType.GZip); } rewindableStream.Rewind(stopRecording: true); return GZipReader.Open(rewindableStream, options); } rewindableStream.Rewind(stopRecording: false); if (BZip2Stream.IsBZip2(rewindableStream)) { rewindableStream.Rewind(stopRecording: false); if (TarArchive.IsTarFile(new BZip2Stream(new NonDisposingStream(rewindableStream), CompressionMode.Decompress, decompressConcatenated: false))) { rewindableStream.Rewind(stopRecording: true); return new TarReader(rewindableStream, options, CompressionType.BZip2); } } rewindableStream.Rewind(stopRecording: false); if (LZipStream.IsLZipFile(rewindableStream)) { rewindableStream.Rewind(stopRecording: false); if (TarArchive.IsTarFile(new LZipStream(new NonDisposingStream(rewindableStream), CompressionMode.Decompress))) { rewindableStream.Rewind(stopRecording: true); return new TarReader(rewindableStream, options, CompressionType.LZip); } } rewindableStream.Rewind(stopRecording: false); if (RarArchive.IsRarFile(rewindableStream, options)) { rewindableStream.Rewind(stopRecording: true); return RarReader.Open(rewindableStream, options); } rewindableStream.Rewind(stopRecording: false); if (TarArchive.IsTarFile(rewindableStream)) { rewindableStream.Rewind(stopRecording: true); return TarReader.Open(rewindableStream, options); } rewindableStream.Rewind(stopRecording: false); if (XZStream.IsXZStream(rewindableStream)) { rewindableStream.Rewind(stopRecording: true); if (TarArchive.IsTarFile(new XZStream(rewindableStream))) { rewindableStream.Rewind(stopRecording: true); return new TarReader(rewindableStream, options, CompressionType.Xz); } } throw new InvalidOperationException("Cannot determine compressed stream type. Supported Reader Formats: Zip, GZip, BZip2, Tar, Rar, LZip, XZ"); } } public class ReaderOptions : OptionsBase { public bool LookForHeader { get; set; } public string Password { get; set; } } public class ReaderProgress { private readonly IEntry _entry; public long BytesTransferred { get; } public int Iterations { get; } public int PercentageRead => (int)Math.Round(PercentageReadExact); public double PercentageReadExact => (float)BytesTransferred / (float)_entry.Size * 100f; public ReaderProgress(IEntry entry, long bytesTransferred, int iterations) { _entry = entry; BytesTransferred = bytesTransferred; Iterations = iterations; } } } namespace SharpCompress.Readers.Zip { public class ZipReader : AbstractReader { private readonly StreamingZipHeaderFactory _headerFactory; public override ZipVolume Volume { get; } private ZipReader(Stream stream, ReaderOptions options) : base(options, ArchiveType.Zip) { Volume = new ZipVolume(stream, options); _headerFactory = new StreamingZipHeaderFactory(options.Password, options.ArchiveEncoding); } public static ZipReader Open(Stream stream, ReaderOptions options = null) { stream.CheckNotNull("stream"); return new ZipReader(stream, options ?? new ReaderOptions()); } protected override IEnumerable GetEntries(Stream stream) { foreach (ZipHeader item in _headerFactory.ReadStreamHeader(stream)) { if (item != null) { switch (item.ZipHeaderType) { case ZipHeaderType.LocalEntry: yield return new ZipEntry(new StreamingZipFilePart(item as LocalEntryHeader, stream)); break; case ZipHeaderType.DirectoryEnd: yield break; } } } } } } namespace SharpCompress.Readers.Tar { public class TarReader : AbstractReader { private readonly CompressionType compressionType; public override TarVolume Volume { get; } internal TarReader(Stream stream, ReaderOptions options, CompressionType compressionType) : base(options, ArchiveType.Tar) { this.compressionType = compressionType; Volume = new TarVolume(stream, options); } protected override Stream RequestInitialStream() { Stream stream = base.RequestInitialStream(); return compressionType switch { CompressionType.BZip2 => new BZip2Stream(stream, CompressionMode.Decompress, decompressConcatenated: false), CompressionType.GZip => new GZipStream(stream, CompressionMode.Decompress), CompressionType.LZip => new LZipStream(stream, CompressionMode.Decompress), CompressionType.Xz => new XZStream(stream), CompressionType.None => stream, _ => throw new NotSupportedException("Invalid compression type: " + compressionType), }; } public static TarReader Open(Stream stream, ReaderOptions options = null) { stream.CheckNotNull("stream"); options = options ?? new ReaderOptions(); RewindableStream rewindableStream = new RewindableStream(stream); rewindableStream.StartRecording(); if (GZipArchive.IsGZipFile(rewindableStream)) { rewindableStream.Rewind(stopRecording: false); if (TarArchive.IsTarFile(new GZipStream(rewindableStream, CompressionMode.Decompress))) { rewindableStream.Rewind(stopRecording: true); return new TarReader(rewindableStream, options, CompressionType.GZip); } throw new InvalidFormatException("Not a tar file."); } rewindableStream.Rewind(stopRecording: false); if (BZip2Stream.IsBZip2(rewindableStream)) { rewindableStream.Rewind(stopRecording: false); if (TarArchive.IsTarFile(new BZip2Stream(rewindableStream, CompressionMode.Decompress, decompressConcatenated: false))) { rewindableStream.Rewind(stopRecording: true); return new TarReader(rewindableStream, options, CompressionType.BZip2); } throw new InvalidFormatException("Not a tar file."); } rewindableStream.Rewind(stopRecording: false); if (LZipStream.IsLZipFile(rewindableStream)) { rewindableStream.Rewind(stopRecording: false); if (TarArchive.IsTarFile(new LZipStream(rewindableStream, CompressionMode.Decompress))) { rewindableStream.Rewind(stopRecording: true); return new TarReader(rewindableStream, options, CompressionType.LZip); } throw new InvalidFormatException("Not a tar file."); } rewindableStream.Rewind(stopRecording: true); return new TarReader(rewindableStream, options, CompressionType.None); } protected override IEnumerable GetEntries(Stream stream) { return TarEntry.GetEntries(StreamingMode.Streaming, stream, compressionType, base.Options.ArchiveEncoding); } } } namespace SharpCompress.Readers.Rar { internal class MultiVolumeRarReader : RarReader { private class MultiVolumeStreamEnumerator : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private readonly MultiVolumeRarReader reader; private readonly IEnumerator nextReadableStreams; private Stream tempStream; private bool isFirst = true; public FilePart Current { get; private set; } object IEnumerator.Current => Current; internal MultiVolumeStreamEnumerator(MultiVolumeRarReader r, IEnumerator nextReadableStreams, Stream tempStream) { reader = r; this.nextReadableStreams = nextReadableStreams; this.tempStream = tempStream; } public IEnumerator GetEnumerator() { return this; } IEnumerator IEnumerable.GetEnumerator() { return this; } public void Dispose() { } public bool MoveNext() { if (isFirst) { Current = reader.Entry.Parts.First(); isFirst = false; return true; } if (!reader.Entry.IsSplitAfter) { return false; } if (tempStream != null) { reader.LoadStreamForReading(tempStream); tempStream = null; } else { if (!nextReadableStreams.MoveNext()) { throw new MultiVolumeExtractionException("No stream provided when requested by MultiVolumeRarReader"); } reader.LoadStreamForReading(nextReadableStreams.Current); } Current = reader.Entry.Parts.First(); return true; } public void Reset() { } } private readonly IEnumerator streams; private Stream tempStream; internal MultiVolumeRarReader(IEnumerable streams, ReaderOptions options) : base(options) { this.streams = streams.GetEnumerator(); } internal override void ValidateArchive(RarVolume archive) { } protected override Stream RequestInitialStream() { if (streams.MoveNext()) { return streams.Current; } throw new MultiVolumeExtractionException("No stream provided when requested by MultiVolumeRarReader"); } internal override bool NextEntryForCurrentStream() { if (!base.NextEntryForCurrentStream()) { if (streams.MoveNext()) { return LoadStreamForReading(streams.Current); } return false; } return true; } protected override IEnumerable CreateFilePartEnumerableForCurrentEntry() { MultiVolumeStreamEnumerator result = new MultiVolumeStreamEnumerator(this, streams, tempStream); tempStream = null; return result; } } internal class NonSeekableStreamFilePart : RarFilePart { internal override string FilePartName => "Unknown Stream - File Entry: " + base.FileHeader.FileName; internal NonSeekableStreamFilePart(MarkHeader mh, FileHeader fh) : base(mh, fh) { } internal override Stream GetCompressedStream() { return base.FileHeader.PackedStream; } } public abstract class RarReader : AbstractReader { private RarVolume volume; internal Lazy UnpackV2017 { get; } = new Lazy(() => new SharpCompress.Compressors.Rar.UnpackV2017.Unpack()); internal Lazy UnpackV1 { get; } = new Lazy(() => new SharpCompress.Compressors.Rar.UnpackV1.Unpack()); public override RarVolume Volume => volume; internal RarReader(ReaderOptions options) : base(options, ArchiveType.Rar) { } internal abstract void ValidateArchive(RarVolume archive); public static RarReader Open(Stream stream, ReaderOptions options = null) { stream.CheckNotNull("stream"); return new SingleVolumeRarReader(stream, options ?? new ReaderOptions()); } public static RarReader Open(IEnumerable streams, ReaderOptions options = null) { streams.CheckNotNull("streams"); return new MultiVolumeRarReader(streams, options ?? new ReaderOptions()); } protected override IEnumerable GetEntries(Stream stream) { volume = new RarReaderVolume(stream, base.Options); foreach (RarFilePart item in volume.ReadFileParts()) { ValidateArchive(volume); yield return new RarReaderEntry(volume.IsSolidArchive, item); } } protected virtual IEnumerable CreateFilePartEnumerableForCurrentEntry() { return base.Entry.Parts; } protected override EntryStream GetEntryStream() { MultiVolumeReadOnlyStream readStream = new MultiVolumeReadOnlyStream(CreateFilePartEnumerableForCurrentEntry().Cast(), this); if (base.Entry.IsRarV3) { return CreateEntryStream(new RarCrcStream(UnpackV1.Value, base.Entry.FileHeader, readStream)); } return CreateEntryStream(new RarCrcStream(UnpackV2017.Value, base.Entry.FileHeader, readStream)); } } public class RarReaderEntry : RarEntry { internal RarFilePart Part { get; } internal override IEnumerable Parts => ((FilePart)Part).AsEnumerable(); internal override FileHeader FileHeader => Part.FileHeader; public override CompressionType CompressionType => CompressionType.Rar; public override long CompressedSize => Part.FileHeader.CompressedSize; public override long Size => Part.FileHeader.UncompressedSize; internal RarReaderEntry(bool solid, RarFilePart part) { Part = part; base.IsSolid = solid; } } public class RarReaderVolume : RarVolume { internal RarReaderVolume(Stream stream, ReaderOptions options) : base(StreamingMode.Streaming, stream, options) { } internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) { return new NonSeekableStreamFilePart(markHeader, fileHeader); } internal override IEnumerable ReadFileParts() { return GetVolumeFileParts(); } } internal class SingleVolumeRarReader : RarReader { private readonly Stream stream; internal SingleVolumeRarReader(Stream stream, ReaderOptions options) : base(options) { this.stream = stream; } internal override void ValidateArchive(RarVolume archive) { if (archive.IsMultiVolume) { throw new MultiVolumeExtractionException("Streamed archive is a Multi-volume archive. Use different RarReader method to extract."); } } protected override Stream RequestInitialStream() { return stream; } } } namespace SharpCompress.Readers.GZip { public class GZipReader : AbstractReader { public override GZipVolume Volume { get; } internal GZipReader(Stream stream, ReaderOptions options) : base(options, ArchiveType.GZip) { Volume = new GZipVolume(stream, options); } public static GZipReader Open(Stream stream, ReaderOptions options = null) { stream.CheckNotNull("stream"); return new GZipReader(stream, options ?? new ReaderOptions()); } protected override IEnumerable GetEntries(Stream stream) { return GZipEntry.GetEntries(stream, base.Options); } } } namespace SharpCompress.IO { internal class BufferedSubStream : NonDisposingStream { private long position; private int cacheOffset; private int cacheLength; private readonly byte[] cache; private long BytesLeftToRead { get; set; } public override bool CanRead => true; public override bool CanSeek => false; public override bool CanWrite => false; public override long Length => BytesLeftToRead; public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } public BufferedSubStream(Stream stream, long origin, long bytesToRead) : base(stream) { position = origin; BytesLeftToRead = bytesToRead; cache = new byte[32768]; } public override void Flush() { throw new NotSupportedException(); } public override int Read(byte[] buffer, int offset, int count) { if (count > BytesLeftToRead) { count = (int)BytesLeftToRead; } if (count > 0) { if (cacheLength == 0) { cacheOffset = 0; base.Stream.Position = position; cacheLength = base.Stream.Read(cache, 0, cache.Length); position += cacheLength; } if (count > cacheLength) { count = cacheLength; } Buffer.BlockCopy(cache, cacheOffset, buffer, offset, count); cacheOffset += count; cacheLength -= count; BytesLeftToRead -= count; } return count; } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } } internal class CountingWritableSubStream : NonDisposingStream { public ulong Count { get; private set; } public override bool CanRead => false; public override bool CanSeek => false; public override bool CanWrite => true; public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } internal CountingWritableSubStream(Stream stream) : base(stream) { } public override void Flush() { base.Stream.Flush(); } public override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { base.Stream.Write(buffer, offset, count); Count += (uint)count; } public override void WriteByte(byte value) { base.Stream.WriteByte(value); ulong count = Count + 1; Count = count; } } internal class ListeningStream : Stream { private long currentEntryTotalReadBytes; private readonly IExtractionListener listener; public Stream Stream { get; } public override bool CanRead => Stream.CanRead; public override bool CanSeek => Stream.CanSeek; public override bool CanWrite => Stream.CanWrite; public override long Length => Stream.Length; public override long Position { get { return Stream.Position; } set { Stream.Position = value; } } public ListeningStream(IExtractionListener listener, Stream stream) { Stream = stream; this.listener = listener; } protected override void Dispose(bool disposing) { if (disposing) { Stream.Dispose(); } base.Dispose(disposing); } public override void Flush() { Stream.Flush(); } public override int Read(byte[] buffer, int offset, int count) { int num = Stream.Read(buffer, offset, count); currentEntryTotalReadBytes += num; listener.FireCompressedBytesRead(currentEntryTotalReadBytes, currentEntryTotalReadBytes); return num; } public override int ReadByte() { int num = Stream.ReadByte(); if (num == -1) { return -1; } currentEntryTotalReadBytes++; listener.FireCompressedBytesRead(currentEntryTotalReadBytes, currentEntryTotalReadBytes); return num; } public override long Seek(long offset, SeekOrigin origin) { return Stream.Seek(offset, origin); } public override void SetLength(long value) { Stream.SetLength(value); } public override void Write(byte[] buffer, int offset, int count) { Stream.Write(buffer, offset, count); } } internal class MarkingBinaryReader : BinaryReader { public virtual long CurrentReadByteCount { get; protected set; } public MarkingBinaryReader(Stream stream) : base(stream) { } public virtual void Mark() { CurrentReadByteCount = 0L; } public override int Read() { throw new NotSupportedException(); } public override int Read(byte[] buffer, int index, int count) { throw new NotSupportedException(); } public override int Read(char[] buffer, int index, int count) { throw new NotSupportedException(); } public override bool ReadBoolean() { return ReadByte() != 0; } public override byte ReadByte() { CurrentReadByteCount++; return base.ReadByte(); } public override byte[] ReadBytes(int count) { CurrentReadByteCount += count; byte[] array = base.ReadBytes(count); if (array.Length != count) { throw new EndOfStreamException($"Could not read the requested amount of bytes. End of stream reached. Requested: {count} Read: {array.Length}"); } return array; } public override char ReadChar() { throw new NotSupportedException(); } public override char[] ReadChars(int count) { throw new NotSupportedException(); } public override decimal ReadDecimal() { throw new NotSupportedException(); } public override double ReadDouble() { throw new NotSupportedException(); } public override short ReadInt16() { return DataConverter.LittleEndian.GetInt16(ReadBytes(2), 0); } public override int ReadInt32() { return DataConverter.LittleEndian.GetInt32(ReadBytes(4), 0); } public override long ReadInt64() { return DataConverter.LittleEndian.GetInt64(ReadBytes(8), 0); } public override sbyte ReadSByte() { return (sbyte)ReadByte(); } public override float ReadSingle() { throw new NotSupportedException(); } public override string ReadString() { throw new NotSupportedException(); } public override ushort ReadUInt16() { return DataConverter.LittleEndian.GetUInt16(ReadBytes(2), 0); } public override uint ReadUInt32() { return DataConverter.LittleEndian.GetUInt32(ReadBytes(4), 0); } public override ulong ReadUInt64() { return DataConverter.LittleEndian.GetUInt64(ReadBytes(8), 0); } public ulong ReadRarVInt(int maxBytes = 10) { return DoReadRarVInt((maxBytes - 1) * 7); } private ulong DoReadRarVInt(int maxShift) { int num = 0; ulong num2 = 0uL; do { byte b = ReadByte(); uint num3 = (uint)(b & 0x7F); long num4 = num3; ulong num5 = (ulong)(num4 << num); if (num4 != (long)(num5 >> num)) { break; } num2 |= num5; if (b == num3) { return num2; } num += 7; } while (num <= maxShift); throw new FormatException("malformed vint"); } public uint ReadRarVIntUInt32(int maxBytes = 5) { return DoReadRarVIntUInt32((maxBytes - 1) * 7); } public ushort ReadRarVIntUInt16(int maxBytes = 3) { return checked((ushort)DoReadRarVIntUInt32((maxBytes - 1) * 7)); } public byte ReadRarVIntByte(int maxBytes = 2) { return checked((byte)DoReadRarVIntUInt32((maxBytes - 1) * 7)); } private uint DoReadRarVIntUInt32(int maxShift) { int num = 0; uint num2 = 0u; do { byte b = ReadByte(); uint num3 = (uint)(b & 0x7F); uint num4 = num3 << num; if (num3 != num4 >> num) { break; } num2 |= num4; if (b == num3) { return num2; } num += 7; } while (num <= maxShift); throw new FormatException("malformed vint"); } } public class NonDisposingStream : Stream { public bool ThrowOnDispose { get; set; } protected Stream Stream { get; } public override bool CanRead => Stream.CanRead; public override bool CanSeek => Stream.CanSeek; public override bool CanWrite => Stream.CanWrite; public override long Length => Stream.Length; public override long Position { get { return Stream.Position; } set { Stream.Position = value; } } public NonDisposingStream(Stream stream, bool throwOnDispose = false) { Stream = stream; ThrowOnDispose = throwOnDispose; } protected override void Dispose(bool disposing) { if (ThrowOnDispose) { throw new InvalidOperationException(string.Format("Attempt to dispose of a {0} when {1} is {2}", "NonDisposingStream", "ThrowOnDispose", ThrowOnDispose)); } } public override void Flush() { Stream.Flush(); } public override int Read(byte[] buffer, int offset, int count) { return Stream.Read(buffer, offset, count); } public override long Seek(long offset, SeekOrigin origin) { return Stream.Seek(offset, origin); } public override void SetLength(long value) { Stream.SetLength(value); } public override void Write(byte[] buffer, int offset, int count) { Stream.Write(buffer, offset, count); } } internal class ReadOnlySubStream : NonDisposingStream { private long BytesLeftToRead { get; set; } public override bool CanRead => true; public override bool CanSeek => false; public override bool CanWrite => false; public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } public ReadOnlySubStream(Stream stream, long bytesToRead) : this(stream, null, bytesToRead) { } public ReadOnlySubStream(Stream stream, long? origin, long bytesToRead) : base(stream) { if (origin.HasValue) { stream.Position = origin.Value; } BytesLeftToRead = bytesToRead; } public override void Flush() { throw new NotSupportedException(); } public override int Read(byte[] buffer, int offset, int count) { if (BytesLeftToRead < count) { count = (int)BytesLeftToRead; } int num = base.Stream.Read(buffer, offset, count); if (num > 0) { BytesLeftToRead -= num; } return num; } public override int ReadByte() { if (BytesLeftToRead <= 0) { return -1; } int num = base.Stream.ReadByte(); if (num != -1) { long bytesLeftToRead = BytesLeftToRead - 1; BytesLeftToRead = bytesLeftToRead; } return num; } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } } internal class RewindableStream : Stream { private readonly Stream stream; private MemoryStream bufferStream = new MemoryStream(); private bool isRewound; private bool isDisposed; internal bool IsRecording { get; private set; } public override bool CanRead => true; public override bool CanSeek => stream.CanSeek; public override bool CanWrite => false; public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { return stream.Position + bufferStream.Position - bufferStream.Length; } set { if (!isRewound) { stream.Position = value; } else if (value < stream.Position - bufferStream.Length || value >= stream.Position) { stream.Position = value; isRewound = false; bufferStream.SetLength(0L); } else { bufferStream.Position = value - stream.Position + bufferStream.Length; } } } public RewindableStream(Stream stream) { this.stream = stream; } protected override void Dispose(bool disposing) { if (!isDisposed) { isDisposed = true; base.Dispose(disposing); if (disposing) { stream.Dispose(); } } } public void Rewind(bool stopRecording) { isRewound = true; IsRecording = !stopRecording; bufferStream.Position = 0L; } public void Rewind(MemoryStream buffer) { if (bufferStream.Position >= buffer.Length) { bufferStream.Position -= buffer.Length; } else { bufferStream.TransferTo(buffer); bufferStream = new MemoryStream(); buffer.Position = 0L; buffer.TransferTo(bufferStream); bufferStream.Position = 0L; } isRewound = true; } public void StartRecording() { if (bufferStream.Position != 0L) { byte[] array = bufferStream.ToArray(); long position = bufferStream.Position; bufferStream.SetLength(0L); bufferStream.Write(array, (int)position, array.Length - (int)position); bufferStream.Position = 0L; } IsRecording = true; } public override void Flush() { throw new NotSupportedException(); } public override int Read(byte[] buffer, int offset, int count) { if (count == 0) { return 0; } int num; if (isRewound && bufferStream.Position != bufferStream.Length) { num = bufferStream.Read(buffer, offset, count); if (num < count) { int num2 = stream.Read(buffer, offset + num, count - num); if (IsRecording) { bufferStream.Write(buffer, offset + num, num2); } num += num2; } if (bufferStream.Position == bufferStream.Length && !IsRecording) { isRewound = false; bufferStream.SetLength(0L); } return num; } num = stream.Read(buffer, offset, count); if (IsRecording) { bufferStream.Write(buffer, offset, num); } return num; } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } } internal enum StreamingMode { Streaming, Seekable } } namespace SharpCompress.Crypto { internal sealed class Crc32Stream : Stream { public const uint DefaultPolynomial = 3988292384u; public const uint DefaultSeed = uint.MaxValue; private static uint[] defaultTable; private readonly uint[] table; private uint hash; private readonly Stream stream; public Stream WrappedStream => stream; public override bool CanRead => stream.CanRead; public override bool CanSeek => false; public override bool CanWrite => stream.CanWrite; public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } public uint Crc => ~hash; public Crc32Stream(Stream stream) : this(stream, 3988292384u, uint.MaxValue) { } public Crc32Stream(Stream stream, uint polynomial, uint seed) { this.stream = stream; table = InitializeTable(polynomial); hash = seed; } public override void Flush() { stream.Flush(); } public override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { stream.Write(buffer, offset, count); hash = CalculateCrc(table, hash, buffer, offset, count); } public override void WriteByte(byte value) { stream.WriteByte(value); hash = CalculateCrc(table, hash, value); } public static uint Compute(byte[] buffer) { return Compute(uint.MaxValue, buffer); } public static uint Compute(uint seed, byte[] buffer) { return Compute(3988292384u, seed, buffer); } public static uint Compute(uint polynomial, uint seed, byte[] buffer) { return ~CalculateCrc(InitializeTable(polynomial), seed, buffer, 0, buffer.Length); } private static uint[] InitializeTable(uint polynomial) { if (polynomial == 3988292384u && defaultTable != null) { return defaultTable; } uint[] array = new uint[256]; for (int i = 0; i < 256; i++) { uint num = (uint)i; for (int j = 0; j < 8; j++) { num = (((num & 1) != 1) ? (num >> 1) : ((num >> 1) ^ polynomial)); } array[i] = num; } if (polynomial == 3988292384u) { defaultTable = array; } return array; } private static uint CalculateCrc(uint[] table, uint crc, byte[] buffer, int offset, int count) { int i = offset; for (int num = offset + count; i < num; i++) { crc = CalculateCrc(table, crc, buffer[i]); } return crc; } private static uint CalculateCrc(uint[] table, uint crc, byte b) { return (crc >> 8) ^ table[(crc ^ b) & 0xFF]; } } public class CryptoException : Exception { public CryptoException() { } public CryptoException(string message) : base(message) { } public CryptoException(string message, Exception exception) : base(message, exception) { } } public class DataLengthException : CryptoException { public DataLengthException() { } public DataLengthException(string message) : base(message) { } public DataLengthException(string message, Exception exception) : base(message, exception) { } } public interface IBlockCipher { string AlgorithmName { get; } bool IsPartialBlockOkay { get; } void Init(bool forEncryption, ICipherParameters parameters); int GetBlockSize(); int ProcessBlock(byte[] inBuf, int inOff, byte[] outBuf, int outOff); void Reset(); } public interface ICipherParameters { } public class KeyParameter : ICipherParameters { private readonly byte[] key; public KeyParameter(byte[] key) { if (key == null) { throw new ArgumentNullException("key"); } this.key = (byte[])key.Clone(); } public KeyParameter(byte[] key, int keyOff, int keyLen) { if (key == null) { throw new ArgumentNullException("key"); } if (keyOff < 0 || keyOff > key.Length) { throw new ArgumentOutOfRangeException("keyOff"); } if (keyLen < 0 || keyOff + keyLen > key.Length) { throw new ArgumentOutOfRangeException("keyLen"); } this.key = new byte[keyLen]; Array.Copy(key, keyOff, this.key, 0, keyLen); } public byte[] GetKey() { return (byte[])key.Clone(); } } public class RijndaelEngine : IBlockCipher { private static readonly int MAXROUNDS = 14; private static readonly int MAXKC = 64; private static readonly byte[] Logtable = new byte[256] { 0, 0, 25, 1, 50, 2, 26, 198, 75, 199, 27, 104, 51, 238, 223, 3, 100, 4, 224, 14, 52, 141, 129, 239, 76, 113, 8, 200, 248, 105, 28, 193, 125, 194, 29, 181, 249, 185, 39, 106, 77, 228, 166, 114, 154, 201, 9, 120, 101, 47, 138, 5, 33, 15, 225, 36, 18, 240, 130, 69, 53, 147, 218, 142, 150, 143, 219, 189, 54, 208, 206, 148, 19, 92, 210, 241, 64, 70, 131, 56, 102, 221, 253, 48, 191, 6, 139, 98, 179, 37, 226, 152, 34, 136, 145, 16, 126, 110, 72, 195, 163, 182, 30, 66, 58, 107, 40, 84, 250, 133, 61, 186, 43, 121, 10, 21, 155, 159, 94, 202, 78, 212, 172, 229, 243, 115, 167, 87, 175, 88, 168, 80, 244, 234, 214, 116, 79, 174, 233, 213, 231, 230, 173, 232, 44, 215, 117, 122, 235, 22, 11, 245, 89, 203, 95, 176, 156, 169, 81, 160, 127, 12, 246, 111, 23, 196, 73, 236, 216, 67, 31, 45, 164, 118, 123, 183, 204, 187, 62, 90, 251, 96, 177, 134, 59, 82, 161, 108, 170, 85, 41, 157, 151, 178, 135, 144, 97, 190, 220, 252, 188, 149, 207, 205, 55, 63, 91, 209, 83, 57, 132, 60, 65, 162, 109, 71, 20, 42, 158, 93, 86, 242, 211, 171, 68, 17, 146, 217, 35, 32, 46, 137, 180, 124, 184, 38, 119, 153, 227, 165, 103, 74, 237, 222, 197, 49, 254, 24, 13, 99, 140, 128, 192, 247, 112, 7 }; private static readonly byte[] Alogtable = new byte[511] { 0, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53, 95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170, 229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49, 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205, 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136, 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154, 181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163, 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160, 251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65, 195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117, 159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128, 155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84, 252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202, 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14, 18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23, 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53, 95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170, 229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49, 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205, 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136, 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154, 181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163, 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160, 251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65, 195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117, 159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128, 155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84, 252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202, 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14, 18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23, 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1 }; private static readonly byte[] S = new byte[256] { 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22 }; private static readonly byte[] Si = new byte[256] { 82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125 }; private static readonly byte[] rcon = new byte[30] { 1, 2, 4, 8, 16, 32, 64, 128, 27, 54, 108, 216, 171, 77, 154, 47, 94, 188, 99, 198, 151, 53, 106, 212, 179, 125, 250, 239, 197, 145 }; private static readonly byte[][] shifts0 = new byte[5][] { new byte[4] { 0, 8, 16, 24 }, new byte[4] { 0, 8, 16, 24 }, new byte[4] { 0, 8, 16, 24 }, new byte[4] { 0, 8, 16, 32 }, new byte[4] { 0, 8, 24, 32 } }; private static readonly byte[][] shifts1 = new byte[5][] { new byte[4] { 0, 24, 16, 8 }, new byte[4] { 0, 32, 24, 16 }, new byte[4] { 0, 40, 32, 24 }, new byte[4] { 0, 48, 40, 24 }, new byte[4] { 0, 56, 40, 32 } }; private readonly int BC; private readonly long BC_MASK; private int ROUNDS; private readonly int blockBits; private long[][] workingKey; private long A0; private long A1; private long A2; private long A3; private bool forEncryption; private readonly byte[] shifts0SC; private readonly byte[] shifts1SC; public string AlgorithmName => "Rijndael"; public bool IsPartialBlockOkay => false; private byte Mul0x2(int b) { if (b != 0) { return Alogtable[25 + (Logtable[b] & 0xFF)]; } return 0; } private byte Mul0x3(int b) { if (b != 0) { return Alogtable[1 + (Logtable[b] & 0xFF)]; } return 0; } private byte Mul0x9(int b) { if (b >= 0) { return Alogtable[199 + b]; } return 0; } private byte Mul0xb(int b) { if (b >= 0) { return Alogtable[104 + b]; } return 0; } private byte Mul0xd(int b) { if (b >= 0) { return Alogtable[238 + b]; } return 0; } private byte Mul0xe(int b) { if (b >= 0) { return Alogtable[223 + b]; } return 0; } private void KeyAddition(long[] rk) { A0 ^= rk[0]; A1 ^= rk[1]; A2 ^= rk[2]; A3 ^= rk[3]; } private long Shift(long r, int shift) { ulong num = (ulong)r >> shift; if (shift > 31) { num &= 0xFFFFFFFFu; } return (long)(num | (ulong)(r << BC - shift)) & BC_MASK; } private void ShiftRow(byte[] shiftsSC) { A1 = Shift(A1, shiftsSC[1]); A2 = Shift(A2, shiftsSC[2]); A3 = Shift(A3, shiftsSC[3]); } private long ApplyS(long r, byte[] box) { long num = 0L; for (int i = 0; i < BC; i += 8) { num |= (long)(box[(int)((r >> i) & 0xFF)] & 0xFF) << i; } return num; } private void Substitution(byte[] box) { A0 = ApplyS(A0, box); A1 = ApplyS(A1, box); A2 = ApplyS(A2, box); A3 = ApplyS(A3, box); } private void MixColumn() { long num2; long num3; long num4; long num = (num2 = (num3 = (num4 = 0L))); for (int i = 0; i < BC; i += 8) { int num5 = (int)((A0 >> i) & 0xFF); int num6 = (int)((A1 >> i) & 0xFF); int num7 = (int)((A2 >> i) & 0xFF); int num8 = (int)((A3 >> i) & 0xFF); num |= (long)((Mul0x2(num5) ^ Mul0x3(num6) ^ num7 ^ num8) & 0xFF) << i; num2 |= (long)((Mul0x2(num6) ^ Mul0x3(num7) ^ num8 ^ num5) & 0xFF) << i; num3 |= (long)((Mul0x2(num7) ^ Mul0x3(num8) ^ num5 ^ num6) & 0xFF) << i; num4 |= (long)((Mul0x2(num8) ^ Mul0x3(num5) ^ num6 ^ num7) & 0xFF) << i; } A0 = num; A1 = num2; A2 = num3; A3 = num4; } private void InvMixColumn() { long num2; long num3; long num4; long num = (num2 = (num3 = (num4 = 0L))); for (int i = 0; i < BC; i += 8) { int num5 = (int)((A0 >> i) & 0xFF); int num6 = (int)((A1 >> i) & 0xFF); int num7 = (int)((A2 >> i) & 0xFF); int num8 = (int)((A3 >> i) & 0xFF); num5 = ((num5 != 0) ? (Logtable[num5 & 0xFF] & 0xFF) : (-1)); num6 = ((num6 != 0) ? (Logtable[num6 & 0xFF] & 0xFF) : (-1)); num7 = ((num7 != 0) ? (Logtable[num7 & 0xFF] & 0xFF) : (-1)); num8 = ((num8 != 0) ? (Logtable[num8 & 0xFF] & 0xFF) : (-1)); num |= (long)((Mul0xe(num5) ^ Mul0xb(num6) ^ Mul0xd(num7) ^ Mul0x9(num8)) & 0xFF) << i; num2 |= (long)((Mul0xe(num6) ^ Mul0xb(num7) ^ Mul0xd(num8) ^ Mul0x9(num5)) & 0xFF) << i; num3 |= (long)((Mul0xe(num7) ^ Mul0xb(num8) ^ Mul0xd(num5) ^ Mul0x9(num6)) & 0xFF) << i; num4 |= (long)((Mul0xe(num8) ^ Mul0xb(num5) ^ Mul0xd(num6) ^ Mul0x9(num7)) & 0xFF) << i; } A0 = num; A1 = num2; A2 = num3; A3 = num4; } private long[][] GenerateWorkingKey(byte[] key) { int num = 0; int num2 = key.Length * 8; byte[,] array = new byte[4, MAXKC]; long[][] array2 = new long[MAXROUNDS + 1][]; for (int i = 0; i < MAXROUNDS + 1; i++) { array2[i] = new long[4]; } int num3 = num2 switch { 128 => 4, 160 => 5, 192 => 6, 224 => 7, 256 => 8, _ => throw new ArgumentException("Key length not 128/160/192/224/256 bits."), }; if (num2 >= blockBits) { ROUNDS = num3 + 6; } else { ROUNDS = BC / 8 + 6; } int num4 = 0; for (int j = 0; j < key.Length; j++) { array[j % 4, j / 4] = key[num4++]; } int num5 = 0; int num6 = 0; while (num6 < num3 && num5 < (ROUNDS + 1) * (BC / 8)) { for (int k = 0; k < 4; k++) { array2[num5 / (BC / 8)][k] |= (long)(array[k, num6] & 0xFF) << num5 * 8 % BC; } num6++; num5++; } while (num5 < (ROUNDS + 1) * (BC / 8)) { for (int l = 0; l < 4; l++) { array[l, 0] ^= S[array[(l + 1) % 4, num3 - 1] & 0xFF]; } array[0, 0] ^= rcon[num++]; if (num3 <= 6) { for (int m = 1; m < num3; m++) { for (int n = 0; n < 4; n++) { array[n, m] ^= array[n, m - 1]; } } } else { for (int num7 = 1; num7 < 4; num7++) { for (int num8 = 0; num8 < 4; num8++) { array[num8, num7] ^= array[num8, num7 - 1]; } } for (int num9 = 0; num9 < 4; num9++) { array[num9, 4] ^= S[array[num9, 3] & 0xFF]; } for (int num10 = 5; num10 < num3; num10++) { for (int num11 = 0; num11 < 4; num11++) { array[num11, num10] ^= array[num11, num10 - 1]; } } } int num12 = 0; while (num12 < num3 && num5 < (ROUNDS + 1) * (BC / 8)) { for (int num13 = 0; num13 < 4; num13++) { array2[num5 / (BC / 8)][num13] |= (long)(array[num13, num12] & 0xFF) << num5 * 8 % BC; } num12++; num5++; } } return array2; } public RijndaelEngine() : this(128) { } public RijndaelEngine(int blockBits) { switch (blockBits) { case 128: BC = 32; BC_MASK = 4294967295L; shifts0SC = shifts0[0]; shifts1SC = shifts1[0]; break; case 160: BC = 40; BC_MASK = 1099511627775L; shifts0SC = shifts0[1]; shifts1SC = shifts1[1]; break; case 192: BC = 48; BC_MASK = 281474976710655L; shifts0SC = shifts0[2]; shifts1SC = shifts1[2]; break; case 224: BC = 56; BC_MASK = 72057594037927935L; shifts0SC = shifts0[3]; shifts1SC = shifts1[3]; break; case 256: BC = 64; BC_MASK = -1L; shifts0SC = shifts0[4]; shifts1SC = shifts1[4]; break; default: throw new ArgumentException("unknown blocksize to Rijndael"); } this.blockBits = blockBits; } public void Init(bool forEncryption, ICipherParameters parameters) { if (parameters is KeyParameter keyParameter) { workingKey = GenerateWorkingKey(keyParameter.GetKey()); this.forEncryption = forEncryption; return; } throw new ArgumentException("invalid parameter passed to Rijndael init - " + parameters.GetType()); } public int GetBlockSize() { return BC / 2; } public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff) { if (workingKey == null) { throw new InvalidOperationException("Rijndael engine not initialised"); } if (inOff + BC / 2 > input.Length) { throw new DataLengthException("input buffer too short"); } if (outOff + BC / 2 > output.Length) { throw new DataLengthException("output buffer too short"); } UnPackBlock(input, inOff); if (forEncryption) { EncryptBlock(workingKey); } else { DecryptBlock(workingKey); } PackBlock(output, outOff); return BC / 2; } public void Reset() { } private void UnPackBlock(byte[] bytes, int off) { int num = off; A0 = bytes[num++] & 0xFF; A1 = bytes[num++] & 0xFF; A2 = bytes[num++] & 0xFF; A3 = bytes[num++] & 0xFF; for (int i = 8; i != BC; i += 8) { A0 |= (long)(bytes[num++] & 0xFF) << i; A1 |= (long)(bytes[num++] & 0xFF) << i; A2 |= (long)(bytes[num++] & 0xFF) << i; A3 |= (long)(bytes[num++] & 0xFF) << i; } } private void PackBlock(byte[] bytes, int off) { int num = off; for (int i = 0; i != BC; i += 8) { bytes[num++] = (byte)(A0 >> i); bytes[num++] = (byte)(A1 >> i); bytes[num++] = (byte)(A2 >> i); bytes[num++] = (byte)(A3 >> i); } } private void EncryptBlock(long[][] rk) { KeyAddition(rk[0]); for (int i = 1; i < ROUNDS; i++) { Substitution(S); ShiftRow(shifts0SC); MixColumn(); KeyAddition(rk[i]); } Substitution(S); ShiftRow(shifts0SC); KeyAddition(rk[ROUNDS]); } private void DecryptBlock(long[][] rk) { KeyAddition(rk[ROUNDS]); Substitution(Si); ShiftRow(shifts1SC); for (int num = ROUNDS - 1; num > 0; num--) { KeyAddition(rk[num]); InvMixColumn(); Substitution(Si); ShiftRow(shifts1SC); } KeyAddition(rk[0]); } } } namespace SharpCompress.Converters { internal abstract class DataConverter { private class CopyConverter : DataConverter { public unsafe override double GetDouble(byte[] data, int index) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length - index < 8) { throw new ArgumentException("index"); } if (index < 0) { throw new ArgumentException("index"); } double result = default(double); byte* ptr = (byte*)(&result); for (int i = 0; i < 8; i++) { ptr[i] = data[index + i]; } return result; } public unsafe override ulong GetUInt64(byte[] data, int index) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length - index < 8) { throw new ArgumentException("index"); } if (index < 0) { throw new ArgumentException("index"); } ulong result = default(ulong); byte* ptr = (byte*)(&result); for (int i = 0; i < 8; i++) { ptr[i] = data[index + i]; } return result; } public unsafe override long GetInt64(byte[] data, int index) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length - index < 8) { throw new ArgumentException("index"); } if (index < 0) { throw new ArgumentException("index"); } long result = default(long); byte* ptr = (byte*)(&result); for (int i = 0; i < 8; i++) { ptr[i] = data[index + i]; } return result; } public unsafe override float GetFloat(byte[] data, int index) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length - index < 4) { throw new ArgumentException("index"); } if (index < 0) { throw new ArgumentException("index"); } float result = default(float); byte* ptr = (byte*)(&result); for (int i = 0; i < 4; i++) { ptr[i] = data[index + i]; } return result; } public unsafe override int GetInt32(byte[] data, int index) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length - index < 4) { throw new ArgumentException("index"); } if (index < 0) { throw new ArgumentException("index"); } int result = default(int); byte* ptr = (byte*)(&result); for (int i = 0; i < 4; i++) { ptr[i] = data[index + i]; } return result; } public unsafe override uint GetUInt32(byte[] data, int index) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length - index < 4) { throw new ArgumentException("index"); } if (index < 0) { throw new ArgumentException("index"); } uint result = default(uint); byte* ptr = (byte*)(&result); for (int i = 0; i < 4; i++) { ptr[i] = data[index + i]; } return result; } public unsafe override short GetInt16(byte[] data, int index) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length - index < 2) { throw new ArgumentException("index"); } if (index < 0) { throw new ArgumentException("index"); } short result = default(short); byte* ptr = (byte*)(&result); for (int i = 0; i < 2; i++) { ptr[i] = data[index + i]; } return result; } public unsafe override ushort GetUInt16(byte[] data, int index) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length - index < 2) { throw new ArgumentException("index"); } if (index < 0) { throw new ArgumentException("index"); } ushort result = default(ushort); byte* ptr = (byte*)(&result); for (int i = 0; i < 2; i++) { ptr[i] = data[index + i]; } return result; } public unsafe override void PutBytes(byte[] dest, int destIdx, double value) { Check(dest, destIdx, 8); fixed (byte* ptr = &dest[destIdx]) { long* ptr2 = (long*)(&value); *(long*)ptr = *ptr2; } } public unsafe override void PutBytes(byte[] dest, int destIdx, float value) { Check(dest, destIdx, 4); fixed (byte* ptr = &dest[destIdx]) { uint* ptr2 = (uint*)(&value); *(uint*)ptr = *ptr2; } } public unsafe override void PutBytes(byte[] dest, int destIdx, int value) { Check(dest, destIdx, 4); fixed (byte* ptr = &dest[destIdx]) { uint* ptr2 = (uint*)(&value); *(uint*)ptr = *ptr2; } } public unsafe override void PutBytes(byte[] dest, int destIdx, uint value) { Check(dest, destIdx, 4); fixed (byte* ptr = &dest[destIdx]) { uint* ptr2 = &value; *(uint*)ptr = *ptr2; } } public unsafe override void PutBytes(byte[] dest, int destIdx, long value) { Check(dest, destIdx, 8); fixed (byte* ptr = &dest[destIdx]) { long* ptr2 = &value; *(long*)ptr = *ptr2; } } public unsafe override void PutBytes(byte[] dest, int destIdx, ulong value) { Check(dest, destIdx, 8); fixed (byte* ptr = &dest[destIdx]) { ulong* ptr2 = &value; *(ulong*)ptr = *ptr2; } } public unsafe override void PutBytes(byte[] dest, int destIdx, short value) { Check(dest, destIdx, 2); fixed (byte* ptr = &dest[destIdx]) { ushort* ptr2 = (ushort*)(&value); *(ushort*)ptr = *ptr2; } } public unsafe override void PutBytes(byte[] dest, int destIdx, ushort value) { Check(dest, destIdx, 2); fixed (byte* ptr = &dest[destIdx]) { ushort* ptr2 = &value; *(ushort*)ptr = *ptr2; } } } private class SwapConverter : DataConverter { public unsafe override double GetDouble(byte[] data, int index) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length - index < 8) { throw new ArgumentException("index"); } if (index < 0) { throw new ArgumentException("index"); } double result = default(double); byte* ptr = (byte*)(&result); for (int i = 0; i < 8; i++) { ptr[7 - i] = data[index + i]; } return result; } public unsafe override ulong GetUInt64(byte[] data, int index) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length - index < 8) { throw new ArgumentException("index"); } if (index < 0) { throw new ArgumentException("index"); } ulong result = default(ulong); byte* ptr = (byte*)(&result); for (int i = 0; i < 8; i++) { ptr[7 - i] = data[index + i]; } return result; } public unsafe override long GetInt64(byte[] data, int index) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length - index < 8) { throw new ArgumentException("index"); } if (index < 0) { throw new ArgumentException("index"); } long result = default(long); byte* ptr = (byte*)(&result); for (int i = 0; i < 8; i++) { ptr[7 - i] = data[index + i]; } return result; } public unsafe override float GetFloat(byte[] data, int index) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length - index < 4) { throw new ArgumentException("index"); } if (index < 0) { throw new ArgumentException("index"); } float result = default(float); byte* ptr = (byte*)(&result); for (int i = 0; i < 4; i++) { ptr[3 - i] = data[index + i]; } return result; } public unsafe override int GetInt32(byte[] data, int index) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length - index < 4) { throw new ArgumentException("index"); } if (index < 0) { throw new ArgumentException("index"); } int result = default(int); byte* ptr = (byte*)(&result); for (int i = 0; i < 4; i++) { ptr[3 - i] = data[index + i]; } return result; } public unsafe override uint GetUInt32(byte[] data, int index) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length - index < 4) { throw new ArgumentException("index"); } if (index < 0) { throw new ArgumentException("index"); } uint result = default(uint); byte* ptr = (byte*)(&result); for (int i = 0; i < 4; i++) { ptr[3 - i] = data[index + i]; } return result; } public unsafe override short GetInt16(byte[] data, int index) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length - index < 2) { throw new ArgumentException("index"); } if (index < 0) { throw new ArgumentException("index"); } short result = default(short); byte* ptr = (byte*)(&result); for (int i = 0; i < 2; i++) { ptr[1 - i] = data[index + i]; } return result; } public unsafe override ushort GetUInt16(byte[] data, int index) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length - index < 2) { throw new ArgumentException("index"); } if (index < 0) { throw new ArgumentException("index"); } ushort result = default(ushort); byte* ptr = (byte*)(&result); for (int i = 0; i < 2; i++) { ptr[1 - i] = data[index + i]; } return result; } public unsafe override void PutBytes(byte[] dest, int destIdx, double value) { Check(dest, destIdx, 8); fixed (byte* ptr = &dest[destIdx]) { byte* ptr2 = (byte*)(&value); for (int i = 0; i < 8; i++) { ptr[i] = ptr2[7 - i]; } } } public unsafe override void PutBytes(byte[] dest, int destIdx, float value) { Check(dest, destIdx, 4); fixed (byte* ptr = &dest[destIdx]) { byte* ptr2 = (byte*)(&value); for (int i = 0; i < 4; i++) { ptr[i] = ptr2[3 - i]; } } } public unsafe override void PutBytes(byte[] dest, int destIdx, int value) { Check(dest, destIdx, 4); fixed (byte* ptr = &dest[destIdx]) { byte* ptr2 = (byte*)(&value); for (int i = 0; i < 4; i++) { ptr[i] = ptr2[3 - i]; } } } public unsafe override void PutBytes(byte[] dest, int destIdx, uint value) { Check(dest, destIdx, 4); fixed (byte* ptr = &dest[destIdx]) { byte* ptr2 = (byte*)(&value); for (int i = 0; i < 4; i++) { ptr[i] = ptr2[3 - i]; } } } public unsafe override void PutBytes(byte[] dest, int destIdx, long value) { Check(dest, destIdx, 8); fixed (byte* ptr = &dest[destIdx]) { byte* ptr2 = (byte*)(&value); for (int i = 0; i < 8; i++) { ptr[i] = ptr2[7 - i]; } } } public unsafe override void PutBytes(byte[] dest, int destIdx, ulong value) { Check(dest, destIdx, 8); fixed (byte* ptr = &dest[destIdx]) { byte* ptr2 = (byte*)(&value); for (int i = 0; i < 8; i++) { ptr[i] = ptr2[7 - i]; } } } public unsafe override void PutBytes(byte[] dest, int destIdx, short value) { Check(dest, destIdx, 2); fixed (byte* ptr = &dest[destIdx]) { byte* ptr2 = (byte*)(&value); for (int i = 0; i < 2; i++) { ptr[i] = ptr2[1 - i]; } } } public unsafe override void PutBytes(byte[] dest, int destIdx, ushort value) { Check(dest, destIdx, 2); fixed (byte* ptr = &dest[destIdx]) { byte* ptr2 = (byte*)(&value); for (int i = 0; i < 2; i++) { ptr[i] = ptr2[1 - i]; } } } } private static readonly DataConverter SwapConv = new SwapConverter(); public static readonly bool IsLittleEndian = BitConverter.IsLittleEndian; public static DataConverter LittleEndian { get { if (!BitConverter.IsLittleEndian) { return SwapConv; } return Native; } } public static DataConverter BigEndian { get { if (!BitConverter.IsLittleEndian) { return Native; } return SwapConv; } } public static DataConverter Native { get; } = new CopyConverter(); public abstract double GetDouble(byte[] data, int index); public abstract float GetFloat(byte[] data, int index); public abstract long GetInt64(byte[] data, int index); public abstract int GetInt32(byte[] data, int index); public abstract short GetInt16(byte[] data, int index); [CLSCompliant(false)] public abstract uint GetUInt32(byte[] data, int index); [CLSCompliant(false)] public abstract ushort GetUInt16(byte[] data, int index); [CLSCompliant(false)] public abstract ulong GetUInt64(byte[] data, int index); public abstract void PutBytes(byte[] dest, int destIdx, double value); public abstract void PutBytes(byte[] dest, int destIdx, float value); public abstract void PutBytes(byte[] dest, int destIdx, int value); public abstract void PutBytes(byte[] dest, int destIdx, long value); public abstract void PutBytes(byte[] dest, int destIdx, short value); [CLSCompliant(false)] public abstract void PutBytes(byte[] dest, int destIdx, ushort value); [CLSCompliant(false)] public abstract void PutBytes(byte[] dest, int destIdx, uint value); [CLSCompliant(false)] public abstract void PutBytes(byte[] dest, int destIdx, ulong value); public byte[] GetBytes(double value) { byte[] array = new byte[8]; PutBytes(array, 0, value); return array; } public byte[] GetBytes(float value) { byte[] array = new byte[4]; PutBytes(array, 0, value); return array; } public byte[] GetBytes(int value) { byte[] array = new byte[4]; PutBytes(array, 0, value); return array; } public byte[] GetBytes(long value) { byte[] array = new byte[8]; PutBytes(array, 0, value); return array; } public byte[] GetBytes(short value) { byte[] array = new byte[2]; PutBytes(array, 0, value); return array; } [CLSCompliant(false)] public byte[] GetBytes(ushort value) { byte[] array = new byte[2]; PutBytes(array, 0, value); return array; } [CLSCompliant(false)] public byte[] GetBytes(uint value) { byte[] array = new byte[4]; PutBytes(array, 0, value); return array; } [CLSCompliant(false)] public byte[] GetBytes(ulong value) { byte[] array = new byte[8]; PutBytes(array, 0, value); return array; } internal void Check(byte[] dest, int destIdx, int size) { if (dest == null) { throw new ArgumentNullException("dest"); } if (destIdx < 0 || destIdx > dest.Length - size) { throw new ArgumentException("destIdx"); } } } } namespace SharpCompress.Compressors { public enum CompressionMode { Compress, Decompress } } namespace SharpCompress.Compressors.Xz { public static class BinaryUtils { public static int ReadLittleEndianInt32(this BinaryReader reader) { byte[] array = reader.ReadBytes(4); return array[0] + (array[1] << 8) + (array[2] << 16) + (array[3] << 24); } internal static uint ReadLittleEndianUInt32(this BinaryReader reader) { return (uint)reader.ReadLittleEndianInt32(); } public static int ReadLittleEndianInt32(this Stream stream) { byte[] array = new byte[4]; if (!stream.ReadFully(array)) { throw new EndOfStreamException(); } return array[0] + (array[1] << 8) + (array[2] << 16) + (array[3] << 24); } internal static uint ReadLittleEndianUInt32(this Stream stream) { return (uint)stream.ReadLittleEndianInt32(); } internal static byte[] ToBigEndianBytes(this uint uint32) { byte[] bytes = BitConverter.GetBytes(uint32); if (BitConverter.IsLittleEndian) { Array.Reverse((Array)bytes); } return bytes; } internal static byte[] ToLittleEndianBytes(this uint uint32) { byte[] bytes = BitConverter.GetBytes(uint32); if (!BitConverter.IsLittleEndian) { Array.Reverse((Array)bytes); } return bytes; } } public enum CheckType : byte { NONE = 0, CRC32 = 1, CRC64 = 4, SHA256 = 10 } internal static class Crc32 { public const uint DefaultPolynomial = 3988292384u; public const uint DefaultSeed = uint.MaxValue; private static uint[] defaultTable; public static uint Compute(byte[] buffer) { return Compute(uint.MaxValue, buffer); } public static uint Compute(uint seed, byte[] buffer) { return Compute(3988292384u, seed, buffer); } public static uint Compute(uint polynomial, uint seed, byte[] buffer) { return ~CalculateHash(InitializeTable(polynomial), seed, buffer, 0, buffer.Length); } private static uint[] InitializeTable(uint polynomial) { if (polynomial == 3988292384u && defaultTable != null) { return defaultTable; } uint[] array = new uint[256]; for (int i = 0; i < 256; i++) { uint num = (uint)i; for (int j = 0; j < 8; j++) { num = (((num & 1) != 1) ? (num >> 1) : ((num >> 1) ^ polynomial)); } array[i] = num; } if (polynomial == 3988292384u) { defaultTable = array; } return array; } private static uint CalculateHash(uint[] table, uint seed, IList buffer, int start, int size) { uint num = seed; for (int i = start; i < size - start; i++) { num = (num >> 8) ^ table[buffer[i] ^ (num & 0xFF)]; } return num; } } internal static class Crc64 { public const ulong DefaultSeed = 0uL; internal static ulong[] Table; public const ulong Iso3309Polynomial = 15564440312192434176uL; public static ulong Compute(byte[] buffer) { return Compute(0uL, buffer); } public static ulong Compute(ulong seed, byte[] buffer) { if (Table == null) { Table = CreateTable(15564440312192434176uL); } return CalculateHash(seed, Table, buffer, 0, buffer.Length); } public static ulong CalculateHash(ulong seed, ulong[] table, IList buffer, int start, int size) { ulong num = seed; for (int i = start; i < size; i++) { num = (num >> 8) ^ table[(buffer[i] ^ num) & 0xFF]; } return num; } public static ulong[] CreateTable(ulong polynomial) { ulong[] array = new ulong[256]; for (int i = 0; i < 256; i++) { ulong num = (ulong)i; for (int j = 0; j < 8; j++) { num = (((num & 1) != 1) ? (num >> 1) : ((num >> 1) ^ polynomial)); } array[i] = num; } return array; } } internal static class MultiByteIntegers { public static ulong ReadXZInteger(this BinaryReader reader, int MaxBytes = 9) { if (MaxBytes <= 0) { throw new ArgumentOutOfRangeException(); } if (MaxBytes > 9) { MaxBytes = 9; } byte b = reader.ReadByte(); ulong num = (ulong)b & 0x7FuL; int num2 = 0; while ((b & 0x80) != 0) { if (++num2 >= MaxBytes) { throw new InvalidDataException(); } b = reader.ReadByte(); if (b == 0) { throw new InvalidDataException(); } num |= (ulong)((long)(b & 0x7F) << num2 * 7); } return num; } } public abstract class ReadOnlyStream : Stream { public Stream BaseStream { get; protected set; } public override bool CanRead => BaseStream.CanRead; public override bool CanSeek => false; public override bool CanWrite => false; public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } public override void Flush() { throw new NotSupportedException(); } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } } internal sealed class XZBlock : XZReadOnlyStream { private CheckType _checkType; private readonly int _checkSize; private bool _streamConnected; private int _numFilters; private byte _blockHeaderSizeByte; private Stream _decomStream; private bool _endOfStream; private bool _paddingSkipped; private bool _crcChecked; private ulong _bytesRead; public int BlockHeaderSize => (_blockHeaderSizeByte + 1) * 4; public ulong? CompressedSize { get; private set; } public ulong? UncompressedSize { get; private set; } public Stack Filters { get; private set; } = new Stack(); public bool HeaderIsLoaded { get; private set; } public XZBlock(Stream stream, CheckType checkType, int checkSize) : base(stream) { _checkType = checkType; _checkSize = checkSize; } public override int Read(byte[] buffer, int offset, int count) { int num = 0; if (!HeaderIsLoaded) { LoadHeader(); } if (!_streamConnected) { ConnectStream(); } if (!_endOfStream) { num = _decomStream.Read(buffer, offset, count); } if (num != count) { _endOfStream = true; } if (_endOfStream && !_paddingSkipped) { SkipPadding(); } if (_endOfStream && !_crcChecked) { CheckCrc(); } _bytesRead += (ulong)num; return num; } private void SkipPadding() { int num = (int)(base.BaseStream.Position % 4); if (num > 0) { byte[] array = new byte[4 - num]; base.BaseStream.Read(array, 0, array.Length); if (array.Any((byte b) => b != 0)) { throw new InvalidDataException("Padding bytes were non-null"); } } _paddingSkipped = true; } private void CheckCrc() { byte[] buffer = new byte[_checkSize]; base.BaseStream.Read(buffer, 0, _checkSize); _crcChecked = true; } private void ConnectStream() { _decomStream = base.BaseStream; while (Filters.Any()) { BlockFilter blockFilter = Filters.Pop(); blockFilter.SetBaseStream(_decomStream); _decomStream = blockFilter; } _streamConnected = true; } private void LoadHeader() { ReadHeaderSize(); using (MemoryStream input = new MemoryStream(CacheHeader())) { using BinaryReader binaryReader = new BinaryReader(input); binaryReader.BaseStream.Position = 1L; ReadBlockFlags(binaryReader); ReadFilters(binaryReader, 0L); } HeaderIsLoaded = true; } private void ReadHeaderSize() { _blockHeaderSizeByte = (byte)base.BaseStream.ReadByte(); if (_blockHeaderSizeByte == 0) { throw new XZIndexMarkerReachedException(); } } private byte[] CacheHeader() { byte[] array = new byte[BlockHeaderSize - 4]; array[0] = _blockHeaderSizeByte; if (base.BaseStream.Read(array, 1, BlockHeaderSize - 5) != BlockHeaderSize - 5) { throw new EndOfStreamException("Reached end of stream unexectedly"); } uint num = base.BaseStream.ReadLittleEndianUInt32(); uint num2 = Crc32.Compute(array); if (num != num2) { throw new InvalidDataException("Block header corrupt"); } return array; } private void ReadBlockFlags(BinaryReader reader) { byte b = reader.ReadByte(); _numFilters = (b & 3) + 1; if ((byte)(b & 0x3C) != 0) { throw new InvalidDataException("Reserved bytes used, perhaps an unknown XZ implementation"); } bool num = (b & 0x40) != 0; bool flag = (b & 0x80) != 0; if (num) { CompressedSize = reader.ReadXZInteger(); } if (flag) { UncompressedSize = reader.ReadXZInteger(); } } private void ReadFilters(BinaryReader reader, long baseStreamOffset = 0L) { int num = 0; for (int i = 0; i < _numFilters; i++) { BlockFilter blockFilter = BlockFilter.Read(reader); if ((i + 1 == _numFilters && !blockFilter.AllowAsLast) || (i + 1 < _numFilters && !blockFilter.AllowAsNonLast)) { throw new InvalidDataException("Block Filters in bad order"); } if (blockFilter.ChangesDataSize && i + 1 < _numFilters) { num++; } blockFilter.ValidateFilter(); Filters.Push(blockFilter); } if (num > 2) { throw new InvalidDataException("More than two non-last block filters cannot change stream size"); } int count = BlockHeaderSize - (4 + (int)(reader.BaseStream.Position - baseStreamOffset)); if (!reader.ReadBytes(count).All((byte b) => b == 0)) { throw new InvalidDataException("Block header contains unknown fields"); } } } public class XZFooter { private readonly BinaryReader _reader; private readonly byte[] _magicBytes = new byte[2] { 89, 90 }; public long StreamStartPosition { get; private set; } public long BackwardSize { get; private set; } public byte[] StreamFlags { get; private set; } public XZFooter(BinaryReader reader) { _reader = reader; StreamStartPosition = reader.BaseStream.Position; } public static XZFooter FromStream(Stream stream) { XZFooter xZFooter = new XZFooter(new BinaryReader(new NonDisposingStream(stream), Encoding.UTF8)); xZFooter.Process(); return xZFooter; } public void Process() { uint num = _reader.ReadLittleEndianUInt32(); byte[] buffer = _reader.ReadBytes(6); uint num2 = Crc32.Compute(buffer); if (num != num2) { throw new InvalidDataException("Footer corrupt"); } using (MemoryStream input = new MemoryStream(buffer)) { using BinaryReader binaryReader = new BinaryReader(input); BackwardSize = (binaryReader.ReadLittleEndianUInt32() + 1) * 4; StreamFlags = binaryReader.ReadBytes(2); } if (!_reader.ReadBytes(2).SequenceEqual(_magicBytes)) { throw new InvalidDataException("Magic footer missing"); } } } public class XZHeader { private readonly BinaryReader _reader; private readonly byte[] MagicHeader = new byte[6] { 253, 55, 122, 88, 90, 0 }; public CheckType BlockCheckType { get; private set; } public int BlockCheckSize => (int)(BlockCheckType + 2) / 3 * 4; public XZHeader(BinaryReader reader) { _reader = reader; } public static XZHeader FromStream(Stream stream) { XZHeader xZHeader = new XZHeader(new BinaryReader(new NonDisposingStream(stream), Encoding.UTF8)); xZHeader.Process(); return xZHeader; } public void Process() { CheckMagicBytes(_reader.ReadBytes(6)); ProcessStreamFlags(); } private void ProcessStreamFlags() { byte[] array = _reader.ReadBytes(2); uint num = _reader.ReadLittleEndianUInt32(); uint num2 = Crc32.Compute(array); if (num != num2) { throw new InvalidDataException("Stream header corrupt"); } BlockCheckType = (CheckType)(array[1] & 0xF); if ((byte)(array[1] & 0xF0) != 0 || array[0] != 0) { throw new InvalidDataException("Unknown XZ Stream Version"); } } private void CheckMagicBytes(byte[] header) { if (!header.SequenceEqual(MagicHeader)) { throw new InvalidDataException("Invalid XZ Stream"); } } } [CLSCompliant(false)] public class XZIndex { private readonly BinaryReader _reader; private readonly bool _indexMarkerAlreadyVerified; public long StreamStartPosition { get; private set; } public ulong NumberOfRecords { get; private set; } public List Records { get; } = new List(); public XZIndex(BinaryReader reader, bool indexMarkerAlreadyVerified) { _reader = reader; _indexMarkerAlreadyVerified = indexMarkerAlreadyVerified; StreamStartPosition = reader.BaseStream.Position; if (indexMarkerAlreadyVerified) { StreamStartPosition--; } } public static XZIndex FromStream(Stream stream, bool indexMarkerAlreadyVerified) { XZIndex xZIndex = new XZIndex(new BinaryReader(new NonDisposingStream(stream), Encoding.UTF8), indexMarkerAlreadyVerified); xZIndex.Process(); return xZIndex; } public void Process() { if (!_indexMarkerAlreadyVerified) { VerifyIndexMarker(); } NumberOfRecords = _reader.ReadXZInteger(); for (ulong num = 0uL; num < NumberOfRecords; num++) { Records.Add(XZIndexRecord.FromBinaryReader(_reader)); } SkipPadding(); VerifyCrc32(); } private void VerifyIndexMarker() { if (_reader.ReadByte() != 0) { throw new InvalidDataException("Not an index block"); } } private void SkipPadding() { int num = (int)(_reader.BaseStream.Position - StreamStartPosition) % 4; if (num > 0 && _reader.ReadBytes(4 - num).Any((byte b) => b != 0)) { throw new InvalidDataException("Padding bytes were non-null"); } } private void VerifyCrc32() { _reader.ReadLittleEndianUInt32(); } } public class XZIndexMarkerReachedException : Exception { } [CLSCompliant(false)] public class XZIndexRecord { public ulong UnpaddedSize { get; private set; } public ulong UncompressedSize { get; private set; } protected XZIndexRecord() { } public static XZIndexRecord FromBinaryReader(BinaryReader br) { return new XZIndexRecord { UnpaddedSize = br.ReadXZInteger(), UncompressedSize = br.ReadXZInteger() }; } } public abstract class XZReadOnlyStream : ReadOnlyStream { public XZReadOnlyStream(Stream stream) { base.BaseStream = stream; if (!base.BaseStream.CanRead) { throw new InvalidDataException("Must be able to read from stream"); } } } [CLSCompliant(false)] public sealed class XZStream : XZReadOnlyStream { private XZBlock _currentBlock; private bool _endOfStream; public XZHeader Header { get; private set; } public XZIndex Index { get; private set; } public XZFooter Footer { get; private set; } public bool HeaderIsRead { get; private set; } public static bool IsXZStream(Stream stream) { try { return XZHeader.FromStream(stream) != null; } catch (Exception) { return false; } } private void AssertBlockCheckTypeIsSupported() { switch (Header.BlockCheckType) { case CheckType.SHA256: throw new NotImplementedException(); default: throw new NotSupportedException("Check Type unknown to this version of decoder."); case CheckType.NONE: case CheckType.CRC32: case CheckType.CRC64: break; } } public XZStream(Stream stream) : base(stream) { } public override int Read(byte[] buffer, int offset, int count) { int result = 0; if (_endOfStream) { return result; } if (!HeaderIsRead) { ReadHeader(); } result = ReadBlocks(buffer, offset, count); if (result < count) { _endOfStream = true; ReadIndex(); ReadFooter(); } return result; } private void ReadHeader() { Header = XZHeader.FromStream(base.BaseStream); AssertBlockCheckTypeIsSupported(); HeaderIsRead = true; } private void ReadIndex() { Index = XZIndex.FromStream(base.BaseStream, indexMarkerAlreadyVerified: true); } private void ReadFooter() { Footer = XZFooter.FromStream(base.BaseStream); } private int ReadBlocks(byte[] buffer, int offset, int count) { int num = 0; if (_currentBlock == null) { NextBlock(); } while (true) { try { if (num >= count) { break; } int num2 = count - num; int offset2 = offset + num; int num3 = _currentBlock.Read(buffer, offset2, num2); if (num3 < num2) { NextBlock(); } num += num3; continue; } catch (XZIndexMarkerReachedException) { } break; } return num; } private void NextBlock() { _currentBlock = new XZBlock(base.BaseStream, Header.BlockCheckType, Header.BlockCheckSize); } } } namespace SharpCompress.Compressors.Xz.Filters { internal abstract class BlockFilter : ReadOnlyStream { public enum FilterTypes : ulong { DELTA = 3uL, ARCH_x86_FILTER = 4uL, ARCH_PowerPC_FILTER = 5uL, ARCH_IA64_FILTER = 6uL, ARCH_ARM_FILTER = 7uL, ARCH_ARMTHUMB_FILTER = 8uL, ARCH_SPARC_FILTER = 9uL, LZMA2 = 33uL } private static readonly Dictionary FilterMap = new Dictionary { { FilterTypes.LZMA2, typeof(Lzma2Filter) } }; public abstract bool AllowAsLast { get; } public abstract bool AllowAsNonLast { get; } public abstract bool ChangesDataSize { get; } public FilterTypes FilterType { get; set; } public abstract void Init(byte[] properties); public abstract void ValidateFilter(); public static BlockFilter Read(BinaryReader reader) { FilterTypes filterTypes = (FilterTypes)reader.ReadXZInteger(); if (!FilterMap.ContainsKey(filterTypes)) { throw new NotImplementedException($"Filter {filterTypes} has not yet been implemented"); } BlockFilter obj = Activator.CreateInstance(FilterMap[filterTypes]) as BlockFilter; ulong num = reader.ReadXZInteger(); if (num > int.MaxValue) { throw new InvalidDataException("Block filter information too large"); } byte[] properties = reader.ReadBytes((int)num); obj.Init(properties); return obj; } public abstract void SetBaseStream(Stream stream); } internal class Lzma2Filter : BlockFilter { private byte _dictionarySize; public override bool AllowAsLast => true; public override bool AllowAsNonLast => false; public override bool ChangesDataSize => true; public uint DictionarySize { get { if (_dictionarySize > 40) { throw new OverflowException("Dictionary size greater than UInt32.Max"); } if (_dictionarySize == 40) { return uint.MaxValue; } int num = 2 | (_dictionarySize & 1); int num2 = _dictionarySize / 2 + 11; return (uint)(num << num2); } } public override void Init(byte[] properties) { if (properties.Length != 1) { throw new InvalidDataException("LZMA properties unexpected length"); } _dictionarySize = (byte)(properties[0] & 0x3F); if ((properties[0] & 0xC0) != 0) { throw new InvalidDataException("Reserved bits used in LZMA properties"); } } public override void ValidateFilter() { } public override void SetBaseStream(Stream stream) { base.BaseStream = new LzmaStream(new byte[1] { _dictionarySize }, stream); } public override int Read(byte[] buffer, int offset, int count) { return base.BaseStream.Read(buffer, offset, count); } public override int ReadByte() { return base.BaseStream.ReadByte(); } } } namespace SharpCompress.Compressors.Rar { internal interface IRarUnpack { bool Suspended { get; set; } long DestSize { get; } int Char { get; } int PpmEscChar { get; set; } void DoUnpack(FileHeader fileHeader, Stream readStream, Stream writeStream); void DoUnpack(); } internal class MultiVolumeReadOnlyStream : Stream { private long currentPosition; private long maxPosition; private IEnumerator filePartEnumerator; private Stream currentStream; private readonly IExtractionListener streamListener; private long currentPartTotalReadBytes; private long currentEntryTotalReadBytes; public override bool CanRead => true; public override bool CanSeek => false; public override bool CanWrite => false; public uint CurrentCrc { get; private set; } public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } internal MultiVolumeReadOnlyStream(IEnumerable parts, IExtractionListener streamListener) { this.streamListener = streamListener; filePartEnumerator = parts.GetEnumerator(); filePartEnumerator.MoveNext(); InitializeNextFilePart(); } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) { if (filePartEnumerator != null) { filePartEnumerator.Dispose(); filePartEnumerator = null; } currentStream = null; } } private void InitializeNextFilePart() { maxPosition = filePartEnumerator.Current.FileHeader.CompressedSize; currentPosition = 0L; currentStream = filePartEnumerator.Current.GetCompressedStream(); currentPartTotalReadBytes = 0L; CurrentCrc = filePartEnumerator.Current.FileHeader.FileCrc; streamListener.FireFilePartExtractionBegin(filePartEnumerator.Current.FilePartName, filePartEnumerator.Current.FileHeader.CompressedSize, filePartEnumerator.Current.FileHeader.UncompressedSize); } public override int Read(byte[] buffer, int offset, int count) { int num = 0; int num2 = offset; int num3 = count; while (num3 > 0) { int count2 = num3; if (num3 > maxPosition - currentPosition) { count2 = (int)(maxPosition - currentPosition); } int num4 = currentStream.Read(buffer, num2, count2); if (num4 < 0) { throw new EndOfStreamException(); } currentPosition += num4; num2 += num4; num3 -= num4; num += num4; if (maxPosition - currentPosition != 0L || !filePartEnumerator.Current.FileHeader.IsSplitAfter) { break; } if (filePartEnumerator.Current.FileHeader.R4Salt != null) { throw new InvalidFormatException("Sharpcompress currently does not support multi-volume decryption."); } string fileName = filePartEnumerator.Current.FileHeader.FileName; if (!filePartEnumerator.MoveNext()) { throw new InvalidFormatException("Multi-part rar file is incomplete. Entry expects a new volume: " + fileName); } InitializeNextFilePart(); } currentPartTotalReadBytes += num; currentEntryTotalReadBytes += num; streamListener.FireCompressedBytesRead(currentPartTotalReadBytes, currentEntryTotalReadBytes); return num; } public override void Flush() { throw new NotSupportedException(); } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } } internal static class RarCRC { private static readonly uint[] crcTab; public static uint CheckCrc(uint startCrc, byte b) { return crcTab[(startCrc ^ b) & 0xFF] ^ (startCrc >> 8); } public static uint CheckCrc(uint startCrc, byte[] data, int offset, int count) { int num = Math.Min(data.Length - offset, count); for (int i = 0; i < num; i++) { startCrc = crcTab[(startCrc ^ data[offset + i]) & 0xFF] ^ (startCrc >> 8); } return startCrc; } static RarCRC() { crcTab = new uint[256]; for (uint num = 0u; num < 256; num++) { uint num2 = num; for (int i = 0; i < 8; i++) { if ((num2 & 1) != 0) { num2 >>= 1; num2 ^= 0xEDB88320u; } else { num2 >>= 1; } } crcTab[num] = num2; } } } internal class RarCrcStream : RarStream { private readonly MultiVolumeReadOnlyStream readStream; private uint currentCrc; public RarCrcStream(IRarUnpack unpack, FileHeader fileHeader, MultiVolumeReadOnlyStream readStream) : base(unpack, fileHeader, readStream) { this.readStream = readStream; ResetCrc(); } public uint GetCrc() { return ~currentCrc; } public void ResetCrc() { currentCrc = uint.MaxValue; } public override int Read(byte[] buffer, int offset, int count) { int num = base.Read(buffer, offset, count); if (num != 0) { currentCrc = RarCRC.CheckCrc(currentCrc, buffer, offset, num); } else if (GetCrc() != readStream.CurrentCrc && count != 0) { throw new InvalidFormatException("file crc mismatch"); } return num; } } internal class RarStream : Stream { private readonly IRarUnpack unpack; private readonly FileHeader fileHeader; private readonly Stream readStream; private bool fetch; private byte[] tmpBuffer = new byte[65536]; private int tmpOffset; private int tmpCount; private byte[] outBuffer; private int outOffset; private int outCount; private int outTotal; private bool isDisposed; public override bool CanRead => true; public override bool CanSeek => false; public override bool CanWrite => false; public override long Length => fileHeader.UncompressedSize; public override long Position { get { return fileHeader.UncompressedSize - unpack.DestSize; } set { throw new NotSupportedException(); } } public RarStream(IRarUnpack unpack, FileHeader fileHeader, Stream readStream) { this.unpack = unpack; this.fileHeader = fileHeader; this.readStream = readStream; fetch = true; unpack.DoUnpack(fileHeader, readStream, this); fetch = false; } protected override void Dispose(bool disposing) { if (!isDisposed) { isDisposed = true; base.Dispose(disposing); readStream.Dispose(); } } public override void Flush() { } public override int Read(byte[] buffer, int offset, int count) { outTotal = 0; if (tmpCount > 0) { int num = ((tmpCount < count) ? tmpCount : count); Buffer.BlockCopy(tmpBuffer, tmpOffset, buffer, offset, num); tmpOffset += num; tmpCount -= num; offset += num; count -= num; outTotal += num; } if (count > 0 && unpack.DestSize > 0) { outBuffer = buffer; outOffset = offset; outCount = count; fetch = true; unpack.DoUnpack(); fetch = false; } return outTotal; } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { if (!fetch) { throw new NotSupportedException(); } if (outCount > 0) { int num = ((outCount < count) ? outCount : count); Buffer.BlockCopy(buffer, offset, outBuffer, outOffset, num); outOffset += num; outCount -= num; offset += num; count -= num; outTotal += num; } if (count > 0) { if (tmpBuffer.Length < tmpCount + count) { byte[] dst = new byte[(tmpBuffer.Length * 2 > tmpCount + count) ? (tmpBuffer.Length * 2) : (tmpCount + count)]; Buffer.BlockCopy(tmpBuffer, 0, dst, 0, tmpCount); tmpBuffer = dst; } Buffer.BlockCopy(buffer, offset, tmpBuffer, tmpCount, count); tmpCount += count; tmpOffset = 0; unpack.Suspended = true; } else { unpack.Suspended = false; } } } } namespace SharpCompress.Compressors.Rar.VM { internal class BitInput { internal const int MAX_SIZE = 32768; public int inAddr; public int inBit; public bool ExternalBuffer; public int InAddr { get { return inAddr; } set { inAddr = value; } } public int InBit { get { return inBit; } set { inBit = value; } } internal byte[] InBuf { get; } internal BitInput() { InBuf = new byte[32768]; } internal void InitBitInput() { inAddr = 0; inBit = 0; } internal void faddbits(uint bits) { AddBits((int)bits); } internal void AddBits(int bits) { bits += inBit; inAddr += bits >> 3; inBit = bits & 7; } internal uint fgetbits() { return (uint)GetBits(); } internal uint getbits() { return (uint)GetBits(); } internal int GetBits() { return Utility.URShift(((InBuf[inAddr] & 0xFF) << 16) + ((InBuf[inAddr + 1] & 0xFF) << 8) + (InBuf[inAddr + 2] & 0xFF), 8 - inBit) & 0xFFFF; } internal bool Overflow(int IncPtr) { return inAddr + IncPtr >= 32768; } } internal class RarVM : BitInput { public const int VM_MEMSIZE = 262144; public static readonly int VM_MEMMASK = 262143; public const int VM_GLOBALMEMADDR = 245760; public const int VM_GLOBALMEMSIZE = 8192; public const int VM_FIXEDGLOBALSIZE = 64; private const int regCount = 8; private const long UINT_MASK = 4294967295L; private readonly int[] R = new int[8]; private VMFlags flags; private int maxOpCount = 25000000; private int codeSize; private int IP; internal byte[] Mem { get; private set; } internal RarVM() { Mem = null; } internal void init() { if (Mem == null) { Mem = new byte[262148]; } } private bool IsVMMem(byte[] mem) { return Mem == mem; } private int GetValue(bool byteMode, byte[] mem, int offset) { if (byteMode) { if (IsVMMem(mem)) { return mem[offset]; } return mem[offset] & 0xFF; } if (IsVMMem(mem)) { return DataConverter.LittleEndian.GetInt32(mem, offset); } return DataConverter.BigEndian.GetInt32(mem, offset); } private void SetValue(bool byteMode, byte[] mem, int offset, int value) { if (byteMode) { if (IsVMMem(mem)) { mem[offset] = (byte)value; } else { mem[offset] = (byte)((mem[offset] & 0) | (byte)(value & 0xFF)); } } else if (IsVMMem(mem)) { DataConverter.LittleEndian.PutBytes(mem, offset, value); } else { DataConverter.BigEndian.PutBytes(mem, offset, value); } } internal void SetLowEndianValue(List mem, int offset, int value) { mem[offset] = (byte)(value & 0xFF); mem[offset + 1] = (byte)(Utility.URShift(value, 8) & 0xFF); mem[offset + 2] = (byte)(Utility.URShift(value, 16) & 0xFF); mem[offset + 3] = (byte)(Utility.URShift(value, 24) & 0xFF); } private int GetOperand(VMPreparedOperand cmdOp) { int num = 0; if (cmdOp.Type == VMOpType.VM_OPREGMEM) { int index = (cmdOp.Offset + cmdOp.Base) & VM_MEMMASK; return DataConverter.LittleEndian.GetInt32(Mem, index); } int offset = cmdOp.Offset; return DataConverter.LittleEndian.GetInt32(Mem, offset); } public void execute(VMPreparedProgram prg) { for (int i = 0; i < prg.InitR.Length; i++) { R[i] = prg.InitR[i]; } long num = Math.Min(prg.GlobalData.Count, 8192) & 0xFFFFFFFFu; if (num != 0L) { for (int j = 0; j < num; j++) { Mem[245760 + j] = prg.GlobalData[j]; } } long num2 = Math.Min(prg.StaticData.Count, 8192 - num) & 0xFFFFFFFFu; if (num2 != 0L) { for (int k = 0; k < num2; k++) { Mem[245760 + (int)num + k] = prg.StaticData[k]; } } R[7] = 262144; flags = VMFlags.None; List list = ((prg.AltCommands.Count != 0) ? prg.AltCommands : prg.Commands); if (!ExecuteCode(list, prg.CommandCount)) { list[0].OpCode = VMCommands.VM_RET; } int num3 = GetValue(byteMode: false, Mem, 245792) & VM_MEMMASK; int num4 = GetValue(byteMode: false, Mem, 245788) & VM_MEMMASK; if (num3 + num4 >= 262144) { num3 = 0; num4 = 0; } prg.FilteredDataOffset = num3; prg.FilteredDataSize = num4; prg.GlobalData.Clear(); int num5 = Math.Min(GetValue(byteMode: false, Mem, 245808), 8128); if (num5 != 0) { prg.GlobalData.SetSize(num5 + 64); for (int l = 0; l < num5 + 64; l++) { prg.GlobalData[l] = Mem[245760 + l]; } } } private bool setIP(int ip) { if (ip >= codeSize) { return true; } if (--maxOpCount <= 0) { return false; } IP = ip; return true; } private bool ExecuteCode(List preparedCode, int cmdCount) { maxOpCount = 25000000; codeSize = cmdCount; IP = 0; while (true) { VMPreparedCommand vMPreparedCommand = preparedCode[IP]; int operand = GetOperand(vMPreparedCommand.Op1); int operand2 = GetOperand(vMPreparedCommand.Op2); switch (vMPreparedCommand.OpCode) { case VMCommands.VM_MOV: SetValue(vMPreparedCommand.IsByteMode, Mem, operand, GetValue(vMPreparedCommand.IsByteMode, Mem, operand2)); break; case VMCommands.VM_MOVB: SetValue(byteMode: true, Mem, operand, GetValue(byteMode: true, Mem, operand2)); break; case VMCommands.VM_MOVD: SetValue(byteMode: false, Mem, operand, GetValue(byteMode: false, Mem, operand2)); break; case VMCommands.VM_CMP: { VMFlags value4 = (VMFlags)GetValue(vMPreparedCommand.IsByteMode, Mem, operand); VMFlags vMFlags = value4 - GetValue(vMPreparedCommand.IsByteMode, Mem, operand2); if (vMFlags == VMFlags.None) { flags = VMFlags.VM_FZ; } else { flags = ((vMFlags > value4) ? VMFlags.VM_FC : (VMFlags.None | (vMFlags & VMFlags.VM_FS))); } break; } case VMCommands.VM_CMPB: { VMFlags value10 = (VMFlags)GetValue(byteMode: true, Mem, operand); VMFlags vMFlags3 = value10 - GetValue(byteMode: true, Mem, operand2); if (vMFlags3 == VMFlags.None) { flags = VMFlags.VM_FZ; } else { flags = ((vMFlags3 > value10) ? VMFlags.VM_FC : (VMFlags.None | (vMFlags3 & VMFlags.VM_FS))); } break; } case VMCommands.VM_CMPD: { VMFlags value9 = (VMFlags)GetValue(byteMode: false, Mem, operand); VMFlags vMFlags2 = value9 - GetValue(byteMode: false, Mem, operand2); if (vMFlags2 == VMFlags.None) { flags = VMFlags.VM_FZ; } else { flags = ((vMFlags2 > value9) ? VMFlags.VM_FC : (VMFlags.None | (vMFlags2 & VMFlags.VM_FS))); } break; } case VMCommands.VM_ADD: { int value13 = GetValue(vMPreparedCommand.IsByteMode, Mem, operand); int num17 = (int)(((long)value13 + (long)GetValue(vMPreparedCommand.IsByteMode, Mem, operand2)) & -1); if (vMPreparedCommand.IsByteMode) { num17 &= 0xFF; flags = ((num17 < value13) ? VMFlags.VM_FC : ((VMFlags)(0 | ((num17 == 0) ? 2 : (((num17 & 0x80) != 0) ? 80000000 : 0))))); } else { flags = ((num17 < value13) ? VMFlags.VM_FC : ((VMFlags)(0 | ((num17 == 0) ? 2 : (num17 & 0x4C4B400))))); } SetValue(vMPreparedCommand.IsByteMode, Mem, operand, num17); break; } case VMCommands.VM_ADDB: SetValue(byteMode: true, Mem, operand, (int)(GetValue(byteMode: true, Mem, operand) & (uint.MaxValue + GetValue(byteMode: true, Mem, operand2)) & -1)); break; case VMCommands.VM_ADDD: SetValue(byteMode: false, Mem, operand, (int)(GetValue(byteMode: false, Mem, operand) & (uint.MaxValue + GetValue(byteMode: false, Mem, operand2)) & -1)); break; case VMCommands.VM_SUB: { int value3 = GetValue(vMPreparedCommand.IsByteMode, Mem, operand); int num6 = (int)(value3 & (uint.MaxValue - GetValue(vMPreparedCommand.IsByteMode, Mem, operand2)) & -1); flags = ((num6 == 0) ? VMFlags.VM_FZ : ((num6 > value3) ? VMFlags.VM_FC : ((VMFlags)(0 | (num6 & 0x4C4B400))))); SetValue(vMPreparedCommand.IsByteMode, Mem, operand, num6); break; } case VMCommands.VM_SUBB: SetValue(byteMode: true, Mem, operand, (int)(GetValue(byteMode: true, Mem, operand) & (uint.MaxValue - GetValue(byteMode: true, Mem, operand2)) & -1)); break; case VMCommands.VM_SUBD: SetValue(byteMode: false, Mem, operand, (int)(GetValue(byteMode: false, Mem, operand) & (uint.MaxValue - GetValue(byteMode: false, Mem, operand2)) & -1)); break; case VMCommands.VM_JZ: if ((flags & VMFlags.VM_FZ) != VMFlags.None) { setIP(GetValue(byteMode: false, Mem, operand)); continue; } break; case VMCommands.VM_JNZ: if ((flags & VMFlags.VM_FZ) == 0) { setIP(GetValue(byteMode: false, Mem, operand)); continue; } break; case VMCommands.VM_INC: { int num12 = (int)(GetValue(vMPreparedCommand.IsByteMode, Mem, operand) & 0x100000000L); if (vMPreparedCommand.IsByteMode) { num12 &= 0xFF; } SetValue(vMPreparedCommand.IsByteMode, Mem, operand, num12); flags = ((num12 == 0) ? VMFlags.VM_FZ : ((VMFlags)(num12 & 0x4C4B400))); break; } case VMCommands.VM_INCB: SetValue(byteMode: true, Mem, operand, (int)(GetValue(byteMode: true, Mem, operand) & 0x100000000L)); break; case VMCommands.VM_INCD: SetValue(byteMode: false, Mem, operand, (int)(GetValue(byteMode: false, Mem, operand) & 0x100000000L)); break; case VMCommands.VM_DEC: { int num3 = (int)(GetValue(vMPreparedCommand.IsByteMode, Mem, operand) & 0xFFFFFFFEu); SetValue(vMPreparedCommand.IsByteMode, Mem, operand, num3); flags = ((num3 == 0) ? VMFlags.VM_FZ : ((VMFlags)(num3 & 0x4C4B400))); break; } case VMCommands.VM_DECB: SetValue(byteMode: true, Mem, operand, (int)(GetValue(byteMode: true, Mem, operand) & 0xFFFFFFFEu)); break; case VMCommands.VM_DECD: SetValue(byteMode: false, Mem, operand, (int)(GetValue(byteMode: false, Mem, operand) & 0xFFFFFFFEu)); break; case VMCommands.VM_JMP: setIP(GetValue(byteMode: false, Mem, operand)); continue; case VMCommands.VM_XOR: { int num19 = GetValue(vMPreparedCommand.IsByteMode, Mem, operand) ^ GetValue(vMPreparedCommand.IsByteMode, Mem, operand2); flags = ((num19 == 0) ? VMFlags.VM_FZ : ((VMFlags)(num19 & 0x4C4B400))); SetValue(vMPreparedCommand.IsByteMode, Mem, operand, num19); break; } case VMCommands.VM_AND: { int num16 = GetValue(vMPreparedCommand.IsByteMode, Mem, operand) & GetValue(vMPreparedCommand.IsByteMode, Mem, operand2); flags = ((num16 == 0) ? VMFlags.VM_FZ : ((VMFlags)(num16 & 0x4C4B400))); SetValue(vMPreparedCommand.IsByteMode, Mem, operand, num16); break; } case VMCommands.VM_OR: { int num14 = GetValue(vMPreparedCommand.IsByteMode, Mem, operand) | GetValue(vMPreparedCommand.IsByteMode, Mem, operand2); flags = ((num14 == 0) ? VMFlags.VM_FZ : ((VMFlags)(num14 & 0x4C4B400))); SetValue(vMPreparedCommand.IsByteMode, Mem, operand, num14); break; } case VMCommands.VM_TEST: { int num7 = GetValue(vMPreparedCommand.IsByteMode, Mem, operand) & GetValue(vMPreparedCommand.IsByteMode, Mem, operand2); flags = ((num7 == 0) ? VMFlags.VM_FZ : ((VMFlags)(num7 & 0x4C4B400))); break; } case VMCommands.VM_JS: if ((flags & VMFlags.VM_FS) != VMFlags.None) { setIP(GetValue(byteMode: false, Mem, operand)); continue; } break; case VMCommands.VM_JNS: if ((flags & VMFlags.VM_FS) == 0) { setIP(GetValue(byteMode: false, Mem, operand)); continue; } break; case VMCommands.VM_JB: if ((flags & VMFlags.VM_FC) != VMFlags.None) { setIP(GetValue(byteMode: false, Mem, operand)); continue; } break; case VMCommands.VM_JBE: if ((flags & (VMFlags)3) != VMFlags.None) { setIP(GetValue(byteMode: false, Mem, operand)); continue; } break; case VMCommands.VM_JA: if ((flags & (VMFlags)3) == 0) { setIP(GetValue(byteMode: false, Mem, operand)); continue; } break; case VMCommands.VM_JAE: if ((flags & VMFlags.VM_FC) == 0) { setIP(GetValue(byteMode: false, Mem, operand)); continue; } break; case VMCommands.VM_PUSH: R[7] -= 4; SetValue(byteMode: false, Mem, R[7] & VM_MEMMASK, GetValue(byteMode: false, Mem, operand)); break; case VMCommands.VM_POP: SetValue(byteMode: false, Mem, operand, GetValue(byteMode: false, Mem, R[7] & VM_MEMMASK)); R[7] += 4; break; case VMCommands.VM_CALL: R[7] -= 4; SetValue(byteMode: false, Mem, R[7] & VM_MEMMASK, IP + 1); setIP(GetValue(byteMode: false, Mem, operand)); continue; case VMCommands.VM_NOT: SetValue(vMPreparedCommand.IsByteMode, Mem, operand, ~GetValue(vMPreparedCommand.IsByteMode, Mem, operand)); break; case VMCommands.VM_SHL: { int value16 = GetValue(vMPreparedCommand.IsByteMode, Mem, operand); int value17 = GetValue(vMPreparedCommand.IsByteMode, Mem, operand2); int num20 = value16 << value17; flags = (VMFlags)(((num20 == 0) ? 2 : (num20 & 0x4C4B400)) | ((((value16 << value17 - 1) & int.MinValue) != 0) ? 1 : 0)); SetValue(vMPreparedCommand.IsByteMode, Mem, operand, num20); break; } case VMCommands.VM_SHR: { int value14 = GetValue(vMPreparedCommand.IsByteMode, Mem, operand); int value15 = GetValue(vMPreparedCommand.IsByteMode, Mem, operand2); int num18 = Utility.URShift(value14, value15); flags = (VMFlags)(((num18 == 0) ? 2 : (num18 & 0x4C4B400)) | (Utility.URShift(value14, value15 - 1) & 1)); SetValue(vMPreparedCommand.IsByteMode, Mem, operand, num18); break; } case VMCommands.VM_SAR: { int value11 = GetValue(vMPreparedCommand.IsByteMode, Mem, operand); int value12 = GetValue(vMPreparedCommand.IsByteMode, Mem, operand2); int num15 = value11 >> value12; flags = (VMFlags)(((num15 == 0) ? 2 : (num15 & 0x4C4B400)) | ((value11 >> value12 - 1) & 1)); SetValue(vMPreparedCommand.IsByteMode, Mem, operand, num15); break; } case VMCommands.VM_NEG: { int num13 = -GetValue(vMPreparedCommand.IsByteMode, Mem, operand); flags = ((num13 == 0) ? VMFlags.VM_FZ : ((VMFlags)(1 | (num13 & 0x4C4B400)))); SetValue(vMPreparedCommand.IsByteMode, Mem, operand, num13); break; } case VMCommands.VM_NEGB: SetValue(byteMode: true, Mem, operand, -GetValue(byteMode: true, Mem, operand)); break; case VMCommands.VM_NEGD: SetValue(byteMode: false, Mem, operand, -GetValue(byteMode: false, Mem, operand)); break; case VMCommands.VM_PUSHA: { int num10 = 0; int num11 = R[7] - 4; while (num10 < 8) { SetValue(byteMode: false, Mem, num11 & VM_MEMMASK, R[num10]); num10++; num11 -= 4; } R[7] -= 32; break; } case VMCommands.VM_POPA: { int num8 = 0; int num9 = R[7]; while (num8 < 8) { R[7 - num8] = GetValue(byteMode: false, Mem, num9 & VM_MEMMASK); num8++; num9 += 4; } break; } case VMCommands.VM_PUSHF: R[7] -= 4; SetValue(byteMode: false, Mem, R[7] & VM_MEMMASK, (int)flags); break; case VMCommands.VM_POPF: flags = (VMFlags)GetValue(byteMode: false, Mem, R[7] & VM_MEMMASK); R[7] += 4; break; case VMCommands.VM_MOVZX: SetValue(byteMode: false, Mem, operand, GetValue(byteMode: true, Mem, operand2)); break; case VMCommands.VM_MOVSX: SetValue(byteMode: false, Mem, operand, (byte)GetValue(byteMode: true, Mem, operand2)); break; case VMCommands.VM_XCHG: { int value8 = GetValue(vMPreparedCommand.IsByteMode, Mem, operand); SetValue(vMPreparedCommand.IsByteMode, Mem, operand, GetValue(vMPreparedCommand.IsByteMode, Mem, operand2)); SetValue(vMPreparedCommand.IsByteMode, Mem, operand2, value8); break; } case VMCommands.VM_MUL: { int value7 = (int)(GetValue(vMPreparedCommand.IsByteMode, Mem, operand) & (uint.MaxValue * GetValue(vMPreparedCommand.IsByteMode, Mem, operand2)) & -1 & -1); SetValue(vMPreparedCommand.IsByteMode, Mem, operand, value7); break; } case VMCommands.VM_DIV: { int value5 = GetValue(vMPreparedCommand.IsByteMode, Mem, operand2); if (value5 != 0) { int value6 = GetValue(vMPreparedCommand.IsByteMode, Mem, operand) / value5; SetValue(vMPreparedCommand.IsByteMode, Mem, operand, value6); } break; } case VMCommands.VM_ADC: { int value2 = GetValue(vMPreparedCommand.IsByteMode, Mem, operand); int num4 = (int)(flags & VMFlags.VM_FC); int num5 = (int)(value2 & (uint.MaxValue + GetValue(vMPreparedCommand.IsByteMode, Mem, operand2)) & (uint.MaxValue + num4) & -1); if (vMPreparedCommand.IsByteMode) { num5 &= 0xFF; } flags = ((num5 < value2 || (num5 == value2 && num4 != 0)) ? VMFlags.VM_FC : ((VMFlags)(0 | ((num5 == 0) ? 2 : (num5 & 0x4C4B400))))); SetValue(vMPreparedCommand.IsByteMode, Mem, operand, num5); break; } case VMCommands.VM_SBB: { int value = GetValue(vMPreparedCommand.IsByteMode, Mem, operand); int num = (int)(flags & VMFlags.VM_FC); int num2 = (int)(value & (uint.MaxValue - GetValue(vMPreparedCommand.IsByteMode, Mem, operand2)) & (uint.MaxValue - num) & -1); if (vMPreparedCommand.IsByteMode) { num2 &= 0xFF; } flags = ((num2 > value || (num2 == value && num != 0)) ? VMFlags.VM_FC : ((VMFlags)(0 | ((num2 == 0) ? 2 : (num2 & 0x4C4B400))))); SetValue(vMPreparedCommand.IsByteMode, Mem, operand, num2); break; } case VMCommands.VM_RET: if (R[7] >= 262144) { return true; } setIP(GetValue(byteMode: false, Mem, R[7] & VM_MEMMASK)); R[7] += 4; continue; case VMCommands.VM_STANDARD: ExecuteStandardFilter((VMStandardFilters)vMPreparedCommand.Op1.Data); break; } IP++; maxOpCount--; } } public void prepare(byte[] code, int codeSize, VMPreparedProgram prg) { InitBitInput(); int count = Math.Min(32768, codeSize); Buffer.BlockCopy(code, 0, base.InBuf, 0, count); byte b = 0; for (int i = 1; i < codeSize; i++) { b ^= code[i]; } AddBits(8); prg.CommandCount = 0; if (b == code[0]) { VMStandardFilters vMStandardFilters = IsStandardFilter(code, codeSize); if (vMStandardFilters != VMStandardFilters.VMSF_NONE) { VMPreparedCommand vMPreparedCommand = new VMPreparedCommand(); vMPreparedCommand.OpCode = VMCommands.VM_STANDARD; vMPreparedCommand.Op1.Data = (int)vMStandardFilters; vMPreparedCommand.Op1.Type = VMOpType.VM_OPNONE; vMPreparedCommand.Op2.Type = VMOpType.VM_OPNONE; codeSize = 0; prg.Commands.Add(vMPreparedCommand); prg.CommandCount++; } int bits = GetBits(); AddBits(1); if ((bits & 0x8000) != 0) { long num = ReadData(this) & 0x100000000L; int num2 = 0; while (inAddr < codeSize && num2 < num) { prg.StaticData.Add((byte)(GetBits() >> 8)); AddBits(8); num2++; } } while (inAddr < codeSize) { VMPreparedCommand vMPreparedCommand2 = new VMPreparedCommand(); int bits2 = GetBits(); if ((bits2 & 0x8000) == 0) { vMPreparedCommand2.OpCode = (VMCommands)(bits2 >> 12); AddBits(4); } else { vMPreparedCommand2.OpCode = (VMCommands)((bits2 >> 10) - 24); AddBits(6); } if ((VMCmdFlags.VM_CmdFlags[(int)vMPreparedCommand2.OpCode] & 4) != 0) { vMPreparedCommand2.IsByteMode = GetBits() >> 15 == 1; AddBits(1); } else { vMPreparedCommand2.IsByteMode = false; } vMPreparedCommand2.Op1.Type = VMOpType.VM_OPNONE; vMPreparedCommand2.Op2.Type = VMOpType.VM_OPNONE; int num3 = VMCmdFlags.VM_CmdFlags[(int)vMPreparedCommand2.OpCode] & 3; if (num3 > 0) { decodeArg(vMPreparedCommand2.Op1, vMPreparedCommand2.IsByteMode); if (num3 == 2) { decodeArg(vMPreparedCommand2.Op2, vMPreparedCommand2.IsByteMode); } else if (vMPreparedCommand2.Op1.Type == VMOpType.VM_OPINT && (VMCmdFlags.VM_CmdFlags[(int)vMPreparedCommand2.OpCode] & 0x18) != 0) { int num4 = vMPreparedCommand2.Op1.Data; if (num4 >= 256) { num4 -= 256; } else { if (num4 >= 136) { num4 -= 264; } else if (num4 >= 16) { num4 -= 8; } else if (num4 >= 8) { num4 -= 16; } num4 += prg.CommandCount; } vMPreparedCommand2.Op1.Data = num4; } } prg.CommandCount++; prg.Commands.Add(vMPreparedCommand2); } } VMPreparedCommand vMPreparedCommand3 = new VMPreparedCommand(); vMPreparedCommand3.OpCode = VMCommands.VM_RET; vMPreparedCommand3.Op1.Type = VMOpType.VM_OPNONE; vMPreparedCommand3.Op2.Type = VMOpType.VM_OPNONE; prg.Commands.Add(vMPreparedCommand3); prg.CommandCount++; if (codeSize != 0) { optimize(prg); } } private void decodeArg(VMPreparedOperand op, bool byteMode) { int bits = GetBits(); if ((bits & 0x8000) != 0) { op.Type = VMOpType.VM_OPREG; op.Data = (bits >> 12) & 7; op.Offset = op.Data; AddBits(4); return; } if ((bits & 0xC000) == 0) { op.Type = VMOpType.VM_OPINT; if (byteMode) { op.Data = (bits >> 6) & 0xFF; AddBits(10); } else { AddBits(2); op.Data = ReadData(this); } return; } op.Type = VMOpType.VM_OPREGMEM; if ((bits & 0x2000) == 0) { op.Data = (bits >> 10) & 7; op.Offset = op.Data; op.Base = 0; AddBits(6); return; } if ((bits & 0x1000) == 0) { op.Data = (bits >> 9) & 7; op.Offset = op.Data; AddBits(7); } else { op.Data = 0; AddBits(4); } op.Base = ReadData(this); } private void optimize(VMPreparedProgram prg) { List commands = prg.Commands; foreach (VMPreparedCommand item in commands) { switch (item.OpCode) { case VMCommands.VM_MOV: item.OpCode = (item.IsByteMode ? VMCommands.VM_MOVB : VMCommands.VM_MOVD); continue; case VMCommands.VM_CMP: item.OpCode = (item.IsByteMode ? VMCommands.VM_CMPB : VMCommands.VM_CMPD); continue; } if ((VMCmdFlags.VM_CmdFlags[(int)item.OpCode] & 0x40) == 0) { continue; } bool flag = false; for (int i = commands.IndexOf(item) + 1; i < commands.Count; i++) { int num = VMCmdFlags.VM_CmdFlags[(int)commands[i].OpCode]; if ((num & 0x38) != 0) { flag = true; break; } if ((num & 0x40) != 0) { break; } } if (!flag) { switch (item.OpCode) { case VMCommands.VM_ADD: item.OpCode = (item.IsByteMode ? VMCommands.VM_ADDB : VMCommands.VM_ADDD); break; case VMCommands.VM_SUB: item.OpCode = (item.IsByteMode ? VMCommands.VM_SUBB : VMCommands.VM_SUBD); break; case VMCommands.VM_INC: item.OpCode = (item.IsByteMode ? VMCommands.VM_INCB : VMCommands.VM_INCD); break; case VMCommands.VM_DEC: item.OpCode = (item.IsByteMode ? VMCommands.VM_DECB : VMCommands.VM_DECD); break; case VMCommands.VM_NEG: item.OpCode = (item.IsByteMode ? VMCommands.VM_NEGB : VMCommands.VM_NEGD); break; } } } } internal static int ReadData(BitInput rarVM) { int bits = rarVM.GetBits(); switch (bits & 0xC000) { case 0: rarVM.AddBits(6); return (bits >> 10) & 0xF; case 16384: if ((bits & 0x3C00) == 0) { bits = -256 | ((bits >> 2) & 0xFF); rarVM.AddBits(14); } else { bits = (bits >> 6) & 0xFF; rarVM.AddBits(10); } return bits; case 32768: rarVM.AddBits(2); bits = rarVM.GetBits(); rarVM.AddBits(16); return bits; default: rarVM.AddBits(2); bits = rarVM.GetBits() << 16; rarVM.AddBits(16); bits |= rarVM.GetBits(); rarVM.AddBits(16); return bits; } } private VMStandardFilters IsStandardFilter(byte[] code, int codeSize) { VMStandardFilterSignature[] array = new VMStandardFilterSignature[7] { new VMStandardFilterSignature(53, 2908186759u, VMStandardFilters.VMSF_E8), new VMStandardFilterSignature(57, 1020781950u, VMStandardFilters.VMSF_E8E9), new VMStandardFilterSignature(120, 929663295u, VMStandardFilters.VMSF_ITANIUM), new VMStandardFilterSignature(29, 235276157u, VMStandardFilters.VMSF_DELTA), new VMStandardFilterSignature(149, 472669640u, VMStandardFilters.VMSF_RGB), new VMStandardFilterSignature(216, 3162892033u, VMStandardFilters.VMSF_AUDIO), new VMStandardFilterSignature(40, 1186579808u, VMStandardFilters.VMSF_UPCASE) }; uint num = RarCRC.CheckCrc(uint.MaxValue, code, 0, code.Length) ^ 0xFFFFFFFFu; for (int i = 0; i < array.Length; i++) { if (array[i].CRC == num && array[i].Length == code.Length) { return array[i].Type; } } return VMStandardFilters.VMSF_NONE; } private void ExecuteStandardFilter(VMStandardFilters filterType) { switch (filterType) { case VMStandardFilters.VMSF_E8: case VMStandardFilters.VMSF_E8E9: { int num43 = R[4]; long num44 = R[6] & -1; if (num43 >= 245760) { break; } int num45 = 16777216; byte b4 = (byte)((filterType == VMStandardFilters.VMSF_E8E9) ? 233u : 232u); int num46 = 0; while (num46 < num43 - 4) { byte b5 = Mem[num46++]; if (b5 != 232 && b5 != b4) { continue; } long num47 = num46 + num44; long num48 = GetValue(byteMode: false, Mem, num46); if ((num48 & int.MinValue) != 0L) { if (((num48 + num47) & int.MinValue) == 0L) { SetValue(byteMode: false, Mem, num46, (int)num48 + num45); } } else if (((num48 - num45) & int.MinValue) != 0L) { SetValue(byteMode: false, Mem, num46, (int)(num48 - num47)); } num46 += 4; } break; } case VMStandardFilters.VMSF_ITANIUM: { int num20 = R[4]; long number = R[6] & -1; if (num20 >= 245760) { break; } int num21 = 0; byte[] array = new byte[16] { 4, 4, 6, 6, 0, 0, 7, 7, 4, 4, 0, 0, 4, 4, 0, 0 }; number = Utility.URShift(number, 4); while (num21 < num20 - 21) { int num22 = (Mem[num21] & 0x1F) - 16; if (num22 >= 0) { byte b3 = array[num22]; if (b3 != 0) { for (int l = 0; l <= 2; l++) { if ((b3 & (1 << l)) != 0) { int num23 = l * 41 + 5; if (filterItanium_GetBits(num21, num23 + 37, 4) == 5) { int num24 = filterItanium_GetBits(num21, num23 + 13, 20); filterItanium_SetBits(num21, (int)(num24 - number) & 0xFFFFF, num23 + 13, 20); } } } } } num21 += 16; number++; } break; } case VMStandardFilters.VMSF_DELTA: { int num49 = R[4] & -1; int num50 = R[0] & -1; int num51 = 0; int num52 = (num49 * 2) & -1; SetValue(byteMode: false, Mem, 245792, num49); if (num49 >= 122880) { break; } for (int num53 = 0; num53 < num50; num53++) { byte b6 = 0; for (int num54 = num49 + num53; num54 < num52; num54 += num50) { b6 = (Mem[num54] = (byte)(b6 - Mem[num51++])); } } break; } case VMStandardFilters.VMSF_RGB: { int num4 = R[4]; int num5 = R[0] - 3; int num6 = R[1]; int num7 = 3; int num8 = 0; int num9 = num4; SetValue(byteMode: false, Mem, 245792, num4); if (num4 >= 122880 || num6 < 0) { break; } for (int i = 0; i < num7; i++) { long num10 = 0L; for (int j = i; j < num4; j += num7) { int num11 = j - num5; long num15; if (num11 >= 3) { int num12 = num9 + num11; int num13 = Mem[num12] & 0xFF; int num14 = Mem[num12 - 3] & 0xFF; num15 = num10 + num13 - num14; int num16 = Math.Abs((int)(num15 - num10)); int num17 = Math.Abs((int)(num15 - num13)); int num18 = Math.Abs((int)(num15 - num14)); num15 = ((num16 <= num17 && num16 <= num18) ? num10 : ((num17 > num18) ? num14 : num13)); } else { num15 = num10; } num10 = (num15 - Mem[num8++]) & 0xFF & 0xFF; Mem[num9 + j] = (byte)(num10 & 0xFF); } } int k = num6; for (int num19 = num4 - 2; k < num19; k += 3) { byte b2 = Mem[num9 + k + 1]; Mem[num9 + k] = (byte)(Mem[num9 + k] + b2); Mem[num9 + k + 2] = (byte)(Mem[num9 + k + 2] + b2); } break; } case VMStandardFilters.VMSF_AUDIO: { int num25 = R[4]; int num26 = R[0]; int num27 = 0; int num28 = num25; SetValue(byteMode: false, Mem, 245792, num25); if (num25 >= 122880) { break; } for (int m = 0; m < num26; m++) { long num29 = 0L; long num30 = 0L; long[] array2 = new long[7]; int num31 = 0; int num32 = 0; int num33 = 0; int num34 = 0; int num35 = 0; int num36 = m; int num37 = 0; while (num36 < num25) { int num38 = num32; num32 = (int)(num30 - num31); num31 = (int)num30; long number2 = 8 * num29 + num33 * num31 + num34 * num32 + num35 * num38; number2 = Utility.URShift(number2, 3) & 0xFF; long num39 = Mem[num27++]; number2 -= num39; Mem[num28 + num36] = (byte)number2; num30 = (byte)(number2 - num29); if (num30 >= 128) { num30 = -(256 - num30); } num29 = number2; if (num39 >= 128) { num39 = -(256 - num39); } int num40 = (int)num39 << 3; array2[0] += Math.Abs(num40); array2[1] += Math.Abs(num40 - num31); array2[2] += Math.Abs(num40 + num31); array2[3] += Math.Abs(num40 - num32); array2[4] += Math.Abs(num40 + num32); array2[5] += Math.Abs(num40 - num38); array2[6] += Math.Abs(num40 + num38); if ((num37 & 0x1F) == 0) { long num41 = array2[0]; long num42 = 0L; array2[0] = 0L; for (int n = 1; n < array2.Length; n++) { if (array2[n] < num41) { num41 = array2[n]; num42 = n; } array2[n] = 0L; } switch ((int)num42) { case 1: if (num33 >= -16) { num33--; } break; case 2: if (num33 < 16) { num33++; } break; case 3: if (num34 >= -16) { num34--; } break; case 4: if (num34 < 16) { num34++; } break; case 5: if (num35 >= -16) { num35--; } break; case 6: if (num35 < 16) { num35++; } break; } } num36 += num26; num37++; } } break; } case VMStandardFilters.VMSF_UPCASE: { int num = R[4]; int num2 = 0; int num3 = num; if (num >= 122880) { break; } while (num2 < num) { byte b = Mem[num2++]; if (b == 2 && (b = Mem[num2++]) != 2) { b -= 32; } Mem[num3++] = b; } SetValue(byteMode: false, Mem, 245788, num3 - num); SetValue(byteMode: false, Mem, 245792, num); break; } } } private void filterItanium_SetBits(int curPos, int bitField, int bitPos, int bitCount) { int num = bitPos / 8; int num2 = bitPos & 7; int num3 = Utility.URShift(-1, 32 - bitCount); num3 = ~(num3 << num2); bitField <<= num2; for (int i = 0; i < 4; i++) { Mem[curPos + num + i] &= (byte)num3; Mem[curPos + num + i] |= (byte)bitField; num3 = Utility.URShift(num3, 8) | -16777216; bitField = Utility.URShift(bitField, 8); } } private int filterItanium_GetBits(int curPos, int bitPos, int bitCount) { int num = bitPos / 8; int bits = bitPos & 7; return Utility.URShift((Mem[curPos + num++] & 0xFF) | ((Mem[curPos + num++] & 0xFF) << 8) | ((Mem[curPos + num++] & 0xFF) << 16) | ((Mem[curPos + num] & 0xFF) << 24), bits) & Utility.URShift(-1, 32 - bitCount); } public virtual void setMemory(int pos, byte[] data, int offset, int dataSize) { if (pos < 262144) { for (int i = 0; i < Math.Min(data.Length - offset, dataSize) && 262144 - pos >= i; i++) { Mem[pos + i] = data[offset + i]; } } } } internal class VMCmdFlags { public const byte VMCF_OP0 = 0; public const byte VMCF_OP1 = 1; public const byte VMCF_OP2 = 2; public const byte VMCF_OPMASK = 3; public const byte VMCF_BYTEMODE = 4; public const byte VMCF_JUMP = 8; public const byte VMCF_PROC = 16; public const byte VMCF_USEFLAGS = 32; public const byte VMCF_CHFLAGS = 64; public static byte[] VM_CmdFlags = new byte[40] { 6, 70, 70, 70, 41, 41, 69, 69, 9, 70, 70, 70, 70, 41, 41, 41, 41, 41, 41, 1, 1, 17, 16, 5, 70, 70, 70, 69, 0, 0, 32, 64, 2, 2, 6, 6, 6, 102, 102, 0 }; } internal enum VMCommands { VM_MOV, VM_CMP, VM_ADD, VM_SUB, VM_JZ, VM_JNZ, VM_INC, VM_DEC, VM_JMP, VM_XOR, VM_AND, VM_OR, VM_TEST, VM_JS, VM_JNS, VM_JB, VM_JBE, VM_JA, VM_JAE, VM_PUSH, VM_POP, VM_CALL, VM_RET, VM_NOT, VM_SHL, VM_SHR, VM_SAR, VM_NEG, VM_PUSHA, VM_POPA, VM_PUSHF, VM_POPF, VM_MOVZX, VM_MOVSX, VM_XCHG, VM_MUL, VM_DIV, VM_ADC, VM_SBB, VM_PRINT, VM_MOVB, VM_MOVD, VM_CMPB, VM_CMPD, VM_ADDB, VM_ADDD, VM_SUBB, VM_SUBD, VM_INCB, VM_INCD, VM_DECB, VM_DECD, VM_NEGB, VM_NEGD, VM_STANDARD } internal enum VMFlags { None = 0, VM_FC = 1, VM_FZ = 2, VM_FS = 80000000 } internal enum VMOpType { VM_OPREG, VM_OPINT, VM_OPREGMEM, VM_OPNONE } internal class VMPreparedCommand { internal VMCommands OpCode { get; set; } internal bool IsByteMode { get; set; } internal VMPreparedOperand Op1 { get; } internal VMPreparedOperand Op2 { get; } internal VMPreparedCommand() { Op1 = new VMPreparedOperand(); Op2 = new VMPreparedOperand(); } } internal class VMPreparedOperand { internal VMOpType Type { get; set; } internal int Data { get; set; } internal int Base { get; set; } internal int Offset { get; set; } } internal class VMPreparedProgram { internal List Commands = new List(); internal List AltCommands = new List(); internal List GlobalData = new List(); internal List StaticData = new List(); internal int[] InitR = new int[7]; public int CommandCount { get; set; } internal int FilteredDataOffset { get; set; } internal int FilteredDataSize { get; set; } } internal enum VMStandardFilters { VMSF_NONE, VMSF_E8, VMSF_E8E9, VMSF_ITANIUM, VMSF_RGB, VMSF_AUDIO, VMSF_DELTA, VMSF_UPCASE } internal class VMStandardFilterSignature { internal int Length { get; } internal uint CRC { get; } internal VMStandardFilters Type { get; } internal VMStandardFilterSignature(int length, uint crc, VMStandardFilters type) { Length = length; CRC = crc; Type = type; } } } namespace SharpCompress.Compressors.Rar.UnpackV2017 { internal class BitInput { public const int MAX_SIZE = 32768; public int InAddr; public int InBit; public bool ExternalBuffer; public byte[] InBuf; public BitInput(bool AllocBuffer) { ExternalBuffer = false; if (AllocBuffer) { uint num = 32771u; InBuf = new byte[num]; } else { InBuf = null; } } public void faddbits(uint Bits) { addbits(Bits); } public uint fgetbits() { return getbits(); } private void SetExternalBuffer(byte[] Buf) { InBuf = Buf; ExternalBuffer = true; } public void InitBitInput() { InAddr = (InBit = 0); } public void addbits(uint _Bits) { int num = checked((int)_Bits); num += InBit; InAddr += num >> 3; InBit = num & 7; } public uint getbits() { return (uint)((((InBuf[InAddr] << 16) | (InBuf[InAddr + 1] << 8) | InBuf[InAddr + 2]) >>> 8 - InBit) & 0xFFFF); } public uint getbits32() { return (uint)(((((InBuf[InAddr] << 24) | (InBuf[InAddr + 1] << 16) | (InBuf[InAddr + 2] << 8) | InBuf[InAddr + 3]) << InBit) | (InBuf[InAddr + 4] >>> 8 - InBit)) & -1); } private bool Overflow(uint IncPtr) { return InAddr + IncPtr >= 32768; } } internal class FragmentedWindow { private const int MAX_MEM_BLOCKS = 32; private readonly byte[][] Mem = new byte[32][]; private readonly uint[] MemSize = new uint[32]; public byte this[uint Item] { get { if (Item < MemSize[0]) { return Mem[0][Item]; } for (uint num = 1u; num < MemSize.Length; num++) { if (Item < MemSize[num]) { return Mem[num][Item - MemSize[num - 1]]; } } return Mem[0][0]; } set { if (Item < MemSize[0]) { Mem[0][Item] = value; return; } for (uint num = 1u; num < MemSize.Length; num++) { if (Item < MemSize[num]) { Mem[num][Item - MemSize[num - 1]] = value; return; } } Mem[0][0] = value; } } private void Reset() { for (uint num = 0u; num < Mem.Length; num++) { if (Mem[num] != null) { Mem[num] = null; } } } public void Init(uint WinSize) { Reset(); uint num = 0u; uint num2 = 0u; while (num2 < WinSize && num < Mem.Length) { uint num3 = WinSize - num2; uint num4 = Math.Max(num3 / (uint)(Mem.Length - num), 4194304u); byte[] array = null; while (num3 >= num4) { array = new byte[num3]; if (array != null) { break; } num3 -= num3 / 32; } if (array == null) { throw new InvalidOperationException(); } Mem[num] = array; num2 += num3; MemSize[num] = num2; num++; } if (num2 < WinSize) { throw new InvalidOperationException(); } } public void GetBuffer(uint Item, out byte[] buf, out uint offset) { if (Item < MemSize[0]) { buf = Mem[0]; offset = Item; return; } for (uint num = 1u; num < MemSize.Length; num++) { if (Item < MemSize[num]) { buf = Mem[num]; offset = Item - MemSize[num - 1]; return; } } buf = Mem[0]; offset = 0u; } public void CopyString(uint Length, uint Distance, ref uint UnpPtr, uint MaxWinMask) { uint num = UnpPtr - Distance; while (Length-- != 0) { this[UnpPtr] = this[num++ & MaxWinMask]; UnpPtr = (UnpPtr + 1) & MaxWinMask; } } public void CopyData(byte[] Dest, uint destOffset, uint WinPos, uint Size) { for (uint num = 0u; num < Size; num++) { Dest[destOffset + num] = this[WinPos + num]; } } public uint GetBlockSize(uint StartPos, uint RequiredSize) { for (uint num = 0u; num < MemSize.Length; num++) { if (StartPos < MemSize[num]) { return Math.Min(MemSize[num] - StartPos, RequiredSize); } } return 0u; } } internal static class PackDef { public const uint MAX_LZ_MATCH = 4097u; public const uint MAX3_LZ_MATCH = 257u; public const uint LOW_DIST_REP_COUNT = 16u; public const uint NC = 306u; public const uint DC = 64u; public const uint LDC = 16u; public const uint RC = 44u; public const uint HUFF_TABLE_SIZE = 430u; public const uint BC = 20u; public const uint NC30 = 299u; public const uint DC30 = 60u; public const uint LDC30 = 17u; public const uint RC30 = 28u; public const uint BC30 = 20u; public const uint HUFF_TABLE_SIZE30 = 404u; public const uint NC20 = 298u; public const uint DC20 = 48u; public const uint RC20 = 28u; public const uint BC20 = 19u; public const uint MC20 = 257u; public const uint LARGEST_TABLE_SIZE = 306u; public const int FILTER_DELTA = 0; public const int FILTER_E8 = 1; public const int FILTER_E8E9 = 2; public const int FILTER_ARM = 3; public const int FILTER_AUDIO = 4; public const int FILTER_RGB = 5; public const int FILTER_ITANIUM = 6; public const int FILTER_PPM = 7; public const int FILTER_NONE = 8; } internal sealed class Unpack : BitInput, IRarUnpack { internal static class Unpack15Local { public static readonly uint[] ShortLen1 = new uint[16] { 1u, 3u, 4u, 4u, 5u, 6u, 7u, 8u, 8u, 4u, 4u, 5u, 6u, 6u, 4u, 0u }; public static readonly uint[] ShortXor1 = new uint[15] { 0u, 160u, 208u, 224u, 240u, 248u, 252u, 254u, 255u, 192u, 128u, 144u, 152u, 156u, 176u }; public static readonly uint[] ShortLen2 = new uint[16] { 2u, 3u, 3u, 3u, 4u, 4u, 5u, 6u, 6u, 4u, 4u, 5u, 6u, 6u, 4u, 0u }; public static readonly uint[] ShortXor2 = new uint[15] { 0u, 64u, 96u, 160u, 208u, 224u, 240u, 248u, 252u, 192u, 128u, 144u, 152u, 156u, 176u }; } internal static class Unpack20Local { public static readonly byte[] LDecode = new byte[28] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224 }; public static readonly byte[] LBits = new byte[28] { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 }; public static readonly uint[] DDecode = new uint[48] { 0u, 1u, 2u, 3u, 4u, 6u, 8u, 12u, 16u, 24u, 32u, 48u, 64u, 96u, 128u, 192u, 256u, 384u, 512u, 768u, 1024u, 1536u, 2048u, 3072u, 4096u, 6144u, 8192u, 12288u, 16384u, 24576u, 32768u, 49152u, 65536u, 98304u, 131072u, 196608u, 262144u, 327680u, 393216u, 458752u, 524288u, 589824u, 655360u, 720896u, 786432u, 851968u, 917504u, 983040u }; public static readonly byte[] DBits = new byte[48] { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 }; public static readonly byte[] SDDecode = new byte[8] { 0, 4, 8, 16, 32, 64, 128, 192 }; public static readonly byte[] SDBits = new byte[8] { 2, 2, 3, 4, 5, 6, 6, 6 }; } private FileHeader fileHeader; private Stream readStream; private Stream writeStream; private const int STARTL1 = 2; private static readonly uint[] DecL1 = new uint[11] { 32768u, 40960u, 49152u, 53248u, 57344u, 59904u, 60928u, 61440u, 61952u, 61952u, 65535u }; private static readonly uint[] PosL1 = new uint[13] { 0u, 0u, 0u, 2u, 3u, 5u, 7u, 11u, 16u, 20u, 24u, 32u, 32u }; private const int STARTL2 = 3; private static readonly uint[] DecL2 = new uint[10] { 40960u, 49152u, 53248u, 57344u, 59904u, 60928u, 61440u, 61952u, 62016u, 65535u }; private static readonly uint[] PosL2 = new uint[13] { 0u, 0u, 0u, 0u, 5u, 7u, 9u, 13u, 18u, 22u, 26u, 34u, 36u }; private const int STARTHF0 = 4; private static readonly uint[] DecHf0 = new uint[9] { 32768u, 49152u, 57344u, 61952u, 61952u, 61952u, 61952u, 61952u, 65535u }; private static readonly uint[] PosHf0 = new uint[13] { 0u, 0u, 0u, 0u, 0u, 8u, 16u, 24u, 33u, 33u, 33u, 33u, 33u }; private const int STARTHF1 = 5; private static readonly uint[] DecHf1 = new uint[8] { 8192u, 49152u, 57344u, 61440u, 61952u, 61952u, 63456u, 65535u }; private static readonly uint[] PosHf1 = new uint[13] { 0u, 0u, 0u, 0u, 0u, 0u, 4u, 44u, 60u, 76u, 80u, 80u, 127u }; private const int STARTHF2 = 5; private static readonly uint[] DecHf2 = new uint[8] { 4096u, 9216u, 32768u, 49152u, 64000u, 65535u, 65535u, 65535u }; private static readonly uint[] PosHf2 = new uint[13] { 0u, 0u, 0u, 0u, 0u, 0u, 2u, 7u, 53u, 117u, 233u, 0u, 0u }; private const int STARTHF3 = 6; private static readonly uint[] DecHf3 = new uint[7] { 2048u, 9216u, 60928u, 65152u, 65535u, 65535u, 65535u }; private static readonly uint[] PosHf3 = new uint[13] { 0u, 0u, 0u, 0u, 0u, 0u, 0u, 2u, 16u, 218u, 251u, 0u, 0u }; private const int STARTHF4 = 8; private static readonly uint[] DecHf4 = new uint[6] { 65280u, 65535u, 65535u, 65535u, 65535u, 65535u }; private static readonly uint[] PosHf4 = new uint[13] { 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 255u, 0u, 0u, 0u }; private byte[] FilterSrcMemory = new byte[0]; private byte[] FilterDstMemory = new byte[0]; private readonly List Filters = new List(); private readonly uint[] OldDist = new uint[4]; private uint OldDistPtr; private uint LastLength; private uint LastDist; private uint UnpPtr; private uint WrPtr; private int ReadTop; private int ReadBorder; private UnpackBlockHeader BlockHeader; private UnpackBlockTables BlockTables; private uint WriteBorder; private byte[] Window; private readonly FragmentedWindow FragWindow = new FragmentedWindow(); private bool Fragmented; private long DestUnpSize; private bool UnpAllBuf; private bool UnpSomeRead; private long WrittenFileSize; private bool FileExtracted; private readonly ushort[] ChSet = new ushort[256]; private readonly ushort[] ChSetA = new ushort[256]; private readonly ushort[] ChSetB = new ushort[256]; private readonly ushort[] ChSetC = new ushort[256]; private readonly byte[] NToPl = new byte[256]; private readonly byte[] NToPlB = new byte[256]; private readonly byte[] NToPlC = new byte[256]; private uint FlagBuf; private uint AvrPlc; private uint AvrPlcB; private uint AvrLn1; private uint AvrLn2; private uint AvrLn3; private int Buf60; private int NumHuf; private int StMode; private int LCount; private int FlagsCnt; private uint Nhfb; private uint Nlzb; private uint MaxDist3; private DecodeTable[] MD = new DecodeTable[4]; private readonly byte[] UnpOldTable20 = new byte[1028]; private bool UnpAudioBlock; private uint UnpChannels; private uint UnpCurChannel; private int UnpChannelDelta; private AudioVariables[] AudV = new AudioVariables[4]; public const int BLOCK_LZ = 0; public const int BLOCK_PPM = 1; private int PrevLowDist; private int LowDistRepCount; private int PPMEscChar; private readonly byte[] UnpOldTable = new byte[404]; private int UnpBlockType; private bool TablesRead2; private bool TablesRead3; private bool TablesRead5; private readonly BitInput VMCodeInp = new BitInput(AllocBuffer: true); private readonly List Filters30 = new List(); private readonly List PrgStack = new List(); private readonly List OldFilterLengths = new List(); private int LastFilter; private uint MaxWinSize; private uint MaxWinMask; public bool Suspended { get; set; } public long DestSize => DestUnpSize; public int Char { get { if (InAddr > 32738) { UnpReadBuf(); } return InBuf[InAddr++]; } } public int PpmEscChar { get { return PPMEscChar; } set { PPMEscChar = value; } } private BitInput Inp => this; private void _UnpackCtor() { for (int i = 0; i < AudV.Length; i++) { AudV[i] = new AudioVariables(); } } private int UnpIO_UnpRead(byte[] buf, int offset, int count) { return readStream.Read(buf, offset, count); } private void UnpIO_UnpWrite(byte[] buf, uint offset, uint count) { checked { writeStream.Write(buf, (int)offset, (int)count); } } public void DoUnpack(FileHeader fileHeader, Stream readStream, Stream writeStream) { DestUnpSize = fileHeader.UncompressedSize; this.fileHeader = fileHeader; this.readStream = readStream; this.writeStream = writeStream; if (!fileHeader.IsStored) { Init(fileHeader.WindowSize, fileHeader.IsSolid); } Suspended = false; DoUnpack(); } public void DoUnpack() { if (fileHeader.IsStored) { UnstoreFile(); } else { DoUnpack(fileHeader.CompressionAlgorithm, fileHeader.IsSolid); } } private void UnstoreFile() { byte[] array = new byte[65536]; do { int num = readStream.Read(array, 0, (int)Math.Min(array.Length, DestUnpSize)); if (num != 0) { writeStream.Write(array, 0, num); DestUnpSize -= num; continue; } break; } while (!Suspended); } public static byte[] EnsureCapacity(byte[] array, int length) { if (array.Length >= length) { return array; } return new byte[length]; } private uint RawGet4(byte[] D, int offset) { return (uint)(D[offset] + (D[offset + 1] << 8) + (D[offset + 2] << 16) + (D[offset + 3] << 24)); } private void RawPut4(uint Field, byte[] D, int offset) { D[offset] = (byte)Field; D[offset + 1] = (byte)(Field >> 8); D[offset + 2] = (byte)(Field >> 16); D[offset + 3] = (byte)(Field >> 24); } private void Unpack15(bool Solid) { UnpInitData(Solid); UnpInitData15(Solid); UnpReadBuf(); if (!Solid) { InitHuff(); UnpPtr = 0u; } else { UnpPtr = WrPtr; } DestUnpSize--; if (DestUnpSize >= 0) { GetFlagsBuf(); FlagsCnt = 8; } while (DestUnpSize >= 0) { UnpPtr &= MaxWinMask; if (Inp.InAddr > ReadTop - 30 && !UnpReadBuf()) { break; } if (((WrPtr - UnpPtr) & MaxWinMask) < 270 && WrPtr != UnpPtr) { UnpWriteBuf20(); } if (StMode != 0) { HuffDecode(); continue; } if (--FlagsCnt < 0) { GetFlagsBuf(); FlagsCnt = 7; } if ((FlagBuf & 0x80) != 0) { FlagBuf <<= 1; if (Nlzb > Nhfb) { LongLZ(); } else { HuffDecode(); } continue; } FlagBuf <<= 1; if (--FlagsCnt < 0) { GetFlagsBuf(); FlagsCnt = 7; } if ((FlagBuf & 0x80) != 0) { FlagBuf <<= 1; if (Nlzb > Nhfb) { HuffDecode(); } else { LongLZ(); } } else { FlagBuf <<= 1; ShortLZ(); } } UnpWriteBuf20(); } private uint GetShortLen1(uint pos) { if (pos != 1) { return Unpack15Local.ShortLen1[pos]; } return (uint)(Buf60 + 3); } private uint GetShortLen2(uint pos) { if (pos != 3) { return Unpack15Local.ShortLen2[pos]; } return (uint)(Buf60 + 3); } private void ShortLZ() { NumHuf = 0; uint num = Inp.fgetbits(); if (LCount == 2) { Inp.faddbits(1u); if (num >= 32768) { CopyString15(LastDist, LastLength); return; } num <<= 1; LCount = 0; } num >>= 8; uint num2; if (AvrLn1 < 37) { for (num2 = 0u; ((num ^ Unpack15Local.ShortXor1[num2]) & ~(255 >> (int)GetShortLen1(num2))) != 0L; num2++) { } Inp.faddbits(GetShortLen1(num2)); } else { for (num2 = 0u; ((num ^ Unpack15Local.ShortXor2[num2]) & ~(255 >> (int)GetShortLen2(num2))) != 0L; num2++) { } Inp.faddbits(GetShortLen2(num2)); } uint num4; switch (num2) { case 9u: LCount++; CopyString15(LastDist, LastLength); return; case 14u: LCount = 0; num2 = DecodeNum(Inp.fgetbits(), 3u, DecL2, PosL2) + 5; num4 = (Inp.fgetbits() >> 1) | 0x8000; Inp.faddbits(15u); LastLength = num2; LastDist = num4; CopyString15(num4, num2); return; case 0u: case 1u: case 2u: case 3u: case 4u: case 5u: case 6u: case 7u: case 8u: { LCount = 0; AvrLn1 += num2; AvrLn1 -= AvrLn1 >> 4; int num3 = (int)(DecodeNum(Inp.fgetbits(), 5u, DecHf2, PosHf2) & 0xFF); num4 = ChSetA[num3]; if (--num3 != -1) { uint num5 = ChSetA[num3]; ChSetA[num3 + 1] = (ushort)num5; ChSetA[num3] = (ushort)num4; } num2 += 2; num4 = (OldDist[OldDistPtr++] = num4 + 1); OldDistPtr &= 3u; LastLength = num2; LastDist = num4; CopyString15(num4, num2); return; } } LCount = 0; uint num6 = num2; num4 = OldDist[(OldDistPtr - (num2 - 9)) & 3]; num2 = DecodeNum(Inp.fgetbits(), 2u, DecL1, PosL1) + 2; if (num2 == 257 && num6 == 10) { Buf60 ^= 1; return; } if (num4 > 256) { num2++; } if (num4 >= MaxDist3) { num2++; } OldDist[OldDistPtr++] = num4; OldDistPtr &= 3u; LastLength = num2; LastDist = num4; CopyString15(num4, num2); } private void LongLZ() { NumHuf = 0; Nlzb += 16u; if (Nlzb > 255) { Nlzb = 144u; Nhfb >>= 1; } uint avrLn = AvrLn2; uint num = Inp.fgetbits(); uint num2; if (AvrLn2 >= 122) { num2 = DecodeNum(num, 3u, DecL2, PosL2); } else if (AvrLn2 >= 64) { num2 = DecodeNum(num, 2u, DecL1, PosL1); } else if (num < 256) { num2 = num; Inp.faddbits(16u); } else { for (num2 = 0u; ((num << (int)num2) & 0x8000) == 0; num2++) { } Inp.faddbits(num2 + 1); } AvrLn2 += num2; AvrLn2 -= AvrLn2 >> 5; num = Inp.fgetbits(); uint num3 = ((AvrPlcB > 10495) ? DecodeNum(num, 5u, DecHf2, PosHf2) : ((AvrPlcB <= 1791) ? DecodeNum(num, 4u, DecHf0, PosHf0) : DecodeNum(num, 5u, DecHf1, PosHf1))); AvrPlcB += num3; AvrPlcB -= AvrPlcB >> 8; uint num5; uint num4; while (true) { num4 = ChSetB[num3 & 0xFF]; num5 = NToPlB[num4++ & 0xFF]++; if ((num4 & 0xFF) == 0) { break; } CorrHuff(ChSetB, NToPlB); } ChSetB[num3 & 0xFF] = ChSetB[num5]; ChSetB[num5] = (ushort)num4; num4 = ((num4 & 0xFF00) | (Inp.fgetbits() >> 8)) >> 1; Inp.faddbits(7u); uint avrLn2 = AvrLn3; if (num2 != 1 && num2 != 4) { if (num2 == 0 && num4 <= MaxDist3) { AvrLn3++; AvrLn3 -= AvrLn3 >> 8; } else if (AvrLn3 != 0) { AvrLn3--; } } num2 += 3; if (num4 >= MaxDist3) { num2++; } if (num4 <= 256) { num2 += 8; } if (avrLn2 > 176 || (AvrPlc >= 10752 && avrLn < 64)) { MaxDist3 = 32512u; } else { MaxDist3 = 8193u; } OldDist[OldDistPtr++] = num4; OldDistPtr &= 3u; LastLength = num2; LastDist = num4; CopyString15(num4, num2); } private void HuffDecode() { uint num = Inp.fgetbits(); int num2 = (int)((AvrPlc > 30207) ? DecodeNum(num, 8u, DecHf4, PosHf4) : ((AvrPlc > 24063) ? DecodeNum(num, 6u, DecHf3, PosHf3) : ((AvrPlc > 13823) ? DecodeNum(num, 5u, DecHf2, PosHf2) : ((AvrPlc <= 3583) ? DecodeNum(num, 4u, DecHf0, PosHf0) : DecodeNum(num, 5u, DecHf1, PosHf1))))); num2 &= 0xFF; if (StMode != 0) { if (num2 == 0 && num > 4095) { num2 = 256; } if (--num2 == -1) { num = Inp.fgetbits(); Inp.faddbits(1u); if ((num & 0x8000) != 0) { NumHuf = (StMode = 0); return; } uint length = (((num & 0x4000) != 0) ? 4u : 3u); Inp.faddbits(1u); uint num3 = DecodeNum(Inp.fgetbits(), 5u, DecHf2, PosHf2); num3 = (num3 << 5) | (Inp.fgetbits() >> 11); Inp.faddbits(5u); CopyString15(num3, length); return; } } else if (NumHuf++ >= 16 && FlagsCnt == 0) { StMode = 1; } AvrPlc += (uint)num2; AvrPlc -= AvrPlc >> 8; Nhfb += 16u; if (Nhfb > 255) { Nhfb = 144u; Nlzb >>= 1; } Window[UnpPtr++] = (byte)(ChSet[num2] >> 8); DestUnpSize--; uint num4; uint num5; while (true) { num4 = ChSet[num2]; num5 = NToPl[num4++ & 0xFF]++; if ((num4 & 0xFF) <= 161) { break; } CorrHuff(ChSet, NToPl); } ChSet[num2] = ChSet[num5]; ChSet[num5] = (ushort)num4; } private void GetFlagsBuf() { uint num = DecodeNum(Inp.fgetbits(), 5u, DecHf2, PosHf2); if (num >= ChSetC.Length) { return; } uint num2; uint num3; while (true) { num2 = ChSetC[num]; FlagBuf = num2 >> 8; num3 = NToPlC[num2++ & 0xFF]++; if ((num2 & 0xFF) != 0) { break; } CorrHuff(ChSetC, NToPlC); } ChSetC[num] = ChSetC[num3]; ChSetC[num3] = (ushort)num2; } private void UnpInitData15(bool Solid) { if (!Solid) { AvrPlcB = (AvrLn1 = (AvrLn2 = (AvrLn3 = 0u))); NumHuf = (Buf60 = 0); AvrPlc = 13568u; MaxDist3 = 8193u; Nhfb = (Nlzb = 128u); } FlagsCnt = 0; FlagBuf = 0u; StMode = 0; LCount = 0; ReadTop = 0; } private void InitHuff() { for (uint num = 0u; num < 256; num++) { ChSet[num] = (ChSetB[num] = (ushort)(num << 8)); ChSetA[num] = (ushort)num; ChSetC[num] = (ushort)(((~num + 1) & 0xFF) << 8); } Utility.Memset(NToPl, 0, NToPl.Length); Utility.Memset(NToPlB, 0, NToPlB.Length); Utility.Memset(NToPlC, 0, NToPlC.Length); CorrHuff(ChSetB, NToPlB); } private void CorrHuff(ushort[] CharSet, byte[] NumToPlace) { for (int num = 7; num >= 0; num--) { for (int i = 0; i < 32; i++) { CharSet[i] = (ushort)((CharSet[i] & -256) | num); } } Utility.Memset(NumToPlace, 0, NToPl.Length); for (int num = 6; num >= 0; num--) { NumToPlace[num] = (byte)((7 - num) * 32); } } private void CopyString15(uint Distance, uint Length) { DestUnpSize -= Length; while (Length-- != 0) { Window[UnpPtr] = Window[(UnpPtr - Distance) & MaxWinMask]; UnpPtr = (UnpPtr + 1) & MaxWinMask; } } private uint DecodeNum(uint Num, uint StartPos, uint[] DecTab, uint[] PosTab) { Num &= 0xFFF0; int i; for (i = 0; DecTab[i] <= Num; i++) { StartPos++; } Inp.faddbits(StartPos); return (Num - ((i != 0) ? DecTab[i - 1] : 0) >> (int)(16 - StartPos)) + PosTab[StartPos]; } private void CopyString20(uint Length, uint Distance) { LastDist = (OldDist[OldDistPtr++ & 3] = Distance); LastLength = Length; DestUnpSize -= Length; CopyString(Length, Distance); } private void Unpack20(bool Solid) { if (Suspended) { UnpPtr = WrPtr; } else { UnpInitData(Solid); if (!UnpReadBuf() || ((!Solid || !TablesRead2) && !ReadTables20())) { return; } DestUnpSize--; } while (DestUnpSize >= 0) { UnpPtr &= MaxWinMask; if (Inp.InAddr > ReadTop - 30 && !UnpReadBuf()) { break; } if (((WrPtr - UnpPtr) & MaxWinMask) < 270 && WrPtr != UnpPtr) { UnpWriteBuf20(); if (Suspended) { return; } } if (UnpAudioBlock) { uint num = DecodeNumber(Inp, MD[UnpCurChannel]); if (num == 256) { if (!ReadTables20()) { break; } continue; } Window[UnpPtr++] = DecodeAudio((int)num); if (++UnpCurChannel == UnpChannels) { UnpCurChannel = 0u; } DestUnpSize--; continue; } uint num2 = DecodeNumber(Inp, BlockTables.LD); if (num2 < 256) { Window[UnpPtr++] = (byte)num2; DestUnpSize--; } else if (num2 > 269) { uint num3 = (uint)(Unpack20Local.LDecode[num2 -= 270] + 3); uint num4; if ((num4 = Unpack20Local.LBits[num2]) != 0) { num3 += Inp.getbits() >> (int)(16 - num4); Inp.addbits(num4); } uint num5 = DecodeNumber(Inp, BlockTables.DD); uint num6 = Unpack20Local.DDecode[num5] + 1; if ((num4 = Unpack20Local.DBits[num5]) != 0) { num6 += Inp.getbits() >> (int)(16 - num4); Inp.addbits(num4); } if (num6 >= 8192) { num3++; if ((long)num6 >= 262144L) { num3++; } } CopyString20(num3, num6); } else if (num2 == 269) { if (!ReadTables20()) { break; } } else if (num2 == 256) { CopyString20(LastLength, LastDist); } else if (num2 < 261) { uint num7 = OldDist[(OldDistPtr - (num2 - 256)) & 3]; uint num8 = DecodeNumber(Inp, BlockTables.RD); uint num9 = (uint)(Unpack20Local.LDecode[num8] + 2); uint num4; if ((num4 = Unpack20Local.LBits[num8]) != 0) { num9 += Inp.getbits() >> (int)(16 - num4); Inp.addbits(num4); } if (num7 >= 257) { num9++; if (num7 >= 8192) { num9++; if (num7 >= 262144) { num9++; } } } CopyString20(num9, num7); } else if (num2 < 270) { uint num10 = (uint)(Unpack20Local.SDDecode[num2 -= 261] + 1); uint num4; if ((num4 = Unpack20Local.SDBits[num2]) != 0) { num10 += Inp.getbits() >> (int)(16 - num4); Inp.addbits(num4); } CopyString20(2u, num10); } } ReadLastTables(); UnpWriteBuf20(); } private void UnpWriteBuf20() { if (UnpPtr != WrPtr) { UnpSomeRead = true; } if (UnpPtr < WrPtr) { UnpIO_UnpWrite(Window, WrPtr, (uint)((int)(0 - WrPtr) & MaxWinMask)); UnpIO_UnpWrite(Window, 0u, UnpPtr); UnpAllBuf = true; } else { UnpIO_UnpWrite(Window, WrPtr, UnpPtr - WrPtr); } WrPtr = UnpPtr; } private bool ReadTables20() { byte[] array = new byte[19]; byte[] array2 = new byte[1028]; if (Inp.InAddr > ReadTop - 25 && !UnpReadBuf()) { return false; } uint num = Inp.getbits(); UnpAudioBlock = (num & 0x8000) != 0; if ((num & 0x4000) != 0) { Utility.Memset(UnpOldTable20, 0, UnpOldTable20.Length); } Inp.addbits(2u); uint num2; if (UnpAudioBlock) { UnpChannels = ((num >> 12) & 3) + 1; if (UnpCurChannel >= UnpChannels) { UnpCurChannel = 0u; } Inp.addbits(2u); num2 = 257 * UnpChannels; } else { num2 = 374u; } for (uint num3 = 0u; num3 < 19; num3++) { array[num3] = (byte)(Inp.getbits() >> 12); Inp.addbits(4u); } MakeDecodeTables(array, 0, BlockTables.BD, 19u); uint num4 = 0u; while (num4 < num2) { if (Inp.InAddr > ReadTop - 5 && !UnpReadBuf()) { return false; } uint num5 = DecodeNumber(Inp, BlockTables.BD); uint num6; switch (num5) { case 0u: case 1u: case 2u: case 3u: case 4u: case 5u: case 6u: case 7u: case 8u: case 9u: case 10u: case 11u: case 12u: case 13u: case 14u: case 15u: array2[num4] = (byte)((num5 + UnpOldTable20[num4]) & 0xF); num4++; continue; case 16u: { uint num7 = (Inp.getbits() >> 14) + 3; Inp.addbits(2u); if (num4 == 0) { return false; } while (num7-- != 0 && num4 < num2) { array2[num4] = array2[num4 - 1]; num4++; } continue; } case 17u: num6 = (Inp.getbits() >> 13) + 3; Inp.addbits(3u); break; default: num6 = (Inp.getbits() >> 9) + 11; Inp.addbits(7u); break; } while (num6-- != 0 && num4 < num2) { array2[num4++] = 0; } } TablesRead2 = true; if (Inp.InAddr > ReadTop) { return true; } if (UnpAudioBlock) { for (uint num8 = 0u; num8 < UnpChannels; num8++) { MakeDecodeTables(array2, (int)(num8 * 257), MD[num8], 257u); } } else { MakeDecodeTables(array2, 0, BlockTables.LD, 298u); MakeDecodeTables(array2, 298, BlockTables.DD, 48u); MakeDecodeTables(array2, 346, BlockTables.RD, 28u); } Array.Copy(array2, 0, UnpOldTable20, 0, UnpOldTable20.Length); return true; } private void ReadLastTables() { if (ReadTop < Inp.InAddr + 5) { return; } if (UnpAudioBlock) { if (DecodeNumber(Inp, MD[UnpCurChannel]) == 256) { ReadTables20(); } } else if (DecodeNumber(Inp, BlockTables.LD) == 269) { ReadTables20(); } } private void UnpInitData20(bool Solid) { if (!Solid) { TablesRead2 = false; UnpAudioBlock = false; UnpChannelDelta = 0; UnpCurChannel = 0u; UnpChannels = 1u; AudV = new AudioVariables[4]; Utility.Memset(UnpOldTable20, 0, UnpOldTable20.Length); MD = new DecodeTable[4]; } } private byte DecodeAudio(int Delta) { AudioVariables audioVariables = AudV[UnpCurChannel]; audioVariables.ByteCount++; audioVariables.D4 = audioVariables.D3; audioVariables.D3 = audioVariables.D2; audioVariables.D2 = audioVariables.LastDelta - audioVariables.D1; audioVariables.D1 = audioVariables.LastDelta; uint num = (uint)(((8 * audioVariables.LastChar + audioVariables.K1 * audioVariables.D1 + audioVariables.K2 * audioVariables.D2 + audioVariables.K3 * audioVariables.D3 + audioVariables.K4 * audioVariables.D4 + audioVariables.K5 * UnpChannelDelta >> 3) & 0xFF) - Delta); int num2 = (sbyte)Delta; num2 <<= 3; audioVariables.Dif[0] += (uint)Math.Abs(num2); audioVariables.Dif[1] += (uint)Math.Abs(num2 - audioVariables.D1); audioVariables.Dif[2] += (uint)Math.Abs(num2 + audioVariables.D1); audioVariables.Dif[3] += (uint)Math.Abs(num2 - audioVariables.D2); audioVariables.Dif[4] += (uint)Math.Abs(num2 + audioVariables.D2); audioVariables.Dif[5] += (uint)Math.Abs(num2 - audioVariables.D3); audioVariables.Dif[6] += (uint)Math.Abs(num2 + audioVariables.D3); audioVariables.Dif[7] += (uint)Math.Abs(num2 - audioVariables.D4); audioVariables.Dif[8] += (uint)Math.Abs(num2 + audioVariables.D4); audioVariables.Dif[9] += (uint)Math.Abs(num2 - UnpChannelDelta); audioVariables.Dif[10] += (uint)Math.Abs(num2 + UnpChannelDelta); UnpChannelDelta = (audioVariables.LastDelta = (sbyte)(num - audioVariables.LastChar)); audioVariables.LastChar = (int)num; if ((audioVariables.ByteCount & 0x1F) == 0) { uint num3 = audioVariables.Dif[0]; uint num4 = 0u; audioVariables.Dif[0] = 0u; for (uint num5 = 1u; num5 < audioVariables.Dif.Length; num5++) { if (audioVariables.Dif[num5] < num3) { num3 = audioVariables.Dif[num5]; num4 = num5; } audioVariables.Dif[num5] = 0u; } switch (num4) { case 1u: if (audioVariables.K1 >= -16) { audioVariables.K1--; } break; case 2u: if (audioVariables.K1 < 16) { audioVariables.K1++; } break; case 3u: if (audioVariables.K2 >= -16) { audioVariables.K2--; } break; case 4u: if (audioVariables.K2 < 16) { audioVariables.K2++; } break; case 5u: if (audioVariables.K3 >= -16) { audioVariables.K3--; } break; case 6u: if (audioVariables.K3 < 16) { audioVariables.K3++; } break; case 7u: if (audioVariables.K4 >= -16) { audioVariables.K4--; } break; case 8u: if (audioVariables.K4 < 16) { audioVariables.K4++; } break; case 9u: if (audioVariables.K5 >= -16) { audioVariables.K5--; } break; case 10u: if (audioVariables.K5 < 16) { audioVariables.K5++; } break; } } return (byte)num; } private void Unpack5(bool Solid) { FileExtracted = true; if (!Suspended) { UnpInitData(Solid); if (!UnpReadBuf() || !ReadBlockHeader(Inp, ref BlockHeader) || !ReadTables(Inp, ref BlockHeader, ref BlockTables) || !TablesRead5) { return; } } while (true) { UnpPtr &= MaxWinMask; if (Inp.InAddr >= ReadBorder) { bool flag = false; while (Inp.InAddr > BlockHeader.BlockStart + BlockHeader.BlockSize - 1 || (Inp.InAddr == BlockHeader.BlockStart + BlockHeader.BlockSize - 1 && Inp.InBit >= BlockHeader.BlockBitSize)) { if (BlockHeader.LastBlockInFile) { flag = true; break; } if (!ReadBlockHeader(Inp, ref BlockHeader) || !ReadTables(Inp, ref BlockHeader, ref BlockTables)) { return; } } if (flag || !UnpReadBuf()) { break; } } if (((WriteBorder - UnpPtr) & MaxWinMask) < 4100 && WriteBorder != UnpPtr) { UnpWriteBuf(); if (WrittenFileSize > DestUnpSize) { return; } if (Suspended) { FileExtracted = false; return; } } uint num = DecodeNumber(Inp, BlockTables.LD); if (num < 256) { if (Fragmented) { FragWindow[UnpPtr++] = (byte)num; } else { Window[UnpPtr++] = (byte)num; } } else if (num >= 262) { uint num2 = SlotToLength(Inp, num - 262); uint num3 = 1u; uint num4 = DecodeNumber(Inp, BlockTables.DD); uint num5; if (num4 < 4) { num5 = 0u; num3 += num4; } else { num5 = num4 / 2 - 1; num3 += (2 | (num4 & 1)) << (int)num5; } if (num5 != 0) { if (num5 >= 4) { if (num5 > 4) { num3 += Inp.getbits32() >> (int)(36 - num5) << 4; Inp.addbits(num5 - 4); } uint num6 = DecodeNumber(Inp, BlockTables.LDD); num3 += num6; } else { num3 += Inp.getbits32() >> (int)(32 - num5); Inp.addbits(num5); } } if (num3 > 256) { num2++; if (num3 > 8192) { num2++; if (num3 > 262144) { num2++; } } } InsertOldDist(num3); LastLength = num2; if (Fragmented) { FragWindow.CopyString(num2, num3, ref UnpPtr, MaxWinMask); } else { CopyString(num2, num3); } } else if (num == 256) { UnpackFilter filter = new UnpackFilter(); if (!ReadFilter(Inp, filter) || !AddFilter(filter)) { break; } } else if (num == 257) { if (LastLength != 0) { if (Fragmented) { FragWindow.CopyString(LastLength, OldDist[0], ref UnpPtr, MaxWinMask); } else { CopyString(LastLength, OldDist[0]); } } } else if (num < 262) { uint num7 = num - 258; uint num8 = OldDist[num7]; for (uint num9 = num7; num9 != 0; num9--) { OldDist[num9] = OldDist[num9 - 1]; } OldDist[0] = num8; uint slot = DecodeNumber(Inp, BlockTables.RD); uint length = (LastLength = SlotToLength(Inp, slot)); if (Fragmented) { FragWindow.CopyString(length, num8, ref UnpPtr, MaxWinMask); } else { CopyString(length, num8); } } } UnpWriteBuf(); } private uint ReadFilterData(BitInput Inp) { uint num = (Inp.fgetbits() >> 14) + 1; Inp.addbits(2u); uint num2 = 0u; for (uint num3 = 0u; num3 < num; num3++) { num2 += Inp.fgetbits() >> 8 << (int)(num3 * 8); Inp.addbits(8u); } return num2; } private bool ReadFilter(BitInput Inp, UnpackFilter Filter) { if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 16 && !UnpReadBuf()) { return false; } Filter.BlockStart = ReadFilterData(Inp); Filter.BlockLength = ReadFilterData(Inp); if (Filter.BlockLength > 4194304) { Filter.BlockLength = 0u; } Filter.Type = (byte)(Inp.fgetbits() >> 13); Inp.faddbits(3u); if (Filter.Type == 0) { Filter.Channels = (byte)((Inp.fgetbits() >> 11) + 1); Inp.faddbits(5u); } return true; } private bool AddFilter(UnpackFilter Filter) { if (Filters.Count >= 8192) { UnpWriteBuf(); if (Filters.Count >= 8192) { InitFilters(); } } Filter.NextWindow = WrPtr != UnpPtr && ((WrPtr - UnpPtr) & MaxWinMask) <= Filter.BlockStart; Filter.BlockStart = (Filter.BlockStart + UnpPtr) & MaxWinMask; Filters.Add(Filter); return true; } private bool UnpReadBuf() { int num = ReadTop - Inp.InAddr; if (num < 0) { return false; } BlockHeader.BlockSize -= Inp.InAddr - BlockHeader.BlockStart; if (Inp.InAddr > 16384) { if (num > 0) { Buffer.BlockCopy(Inp.InBuf, Inp.InAddr, Inp.InBuf, 0, num); } Inp.InAddr = 0; ReadTop = num; } else { num = ReadTop; } int num2 = 0; if (32768 != num) { num2 = UnpIO_UnpRead(Inp.InBuf, num, 32768 - num); } if (num2 > 0) { ReadTop += num2; } ReadBorder = ReadTop - 30; BlockHeader.BlockStart = Inp.InAddr; if (BlockHeader.BlockSize != -1) { ReadBorder = Math.Min(ReadBorder, BlockHeader.BlockStart + BlockHeader.BlockSize - 1); } return num2 != -1; } private void UnpWriteBuf() { uint num = WrPtr; uint num2 = (UnpPtr - num) & MaxWinMask; uint num3 = num2; bool flag = false; for (int i = 0; i < Filters.Count; i++) { UnpackFilter unpackFilter = Filters[i]; if (unpackFilter.Type == 8) { continue; } if (unpackFilter.NextWindow) { if (((unpackFilter.BlockStart - WrPtr) & MaxWinMask) <= num2) { unpackFilter.NextWindow = false; } continue; } uint blockStart = unpackFilter.BlockStart; uint blockLength = unpackFilter.BlockLength; if (((blockStart - num) & MaxWinMask) >= num3) { continue; } if (num != blockStart) { UnpWriteArea(num, blockStart); num = blockStart; num3 = (UnpPtr - num) & MaxWinMask; } if (blockLength <= num3) { if (blockLength == 0) { continue; } uint num4 = (blockStart + blockLength) & MaxWinMask; FilterSrcMemory = EnsureCapacity(FilterSrcMemory, checked((int)blockLength)); byte[] filterSrcMemory = FilterSrcMemory; if (blockStart < num4 || num4 == 0) { if (Fragmented) { FragWindow.CopyData(filterSrcMemory, 0u, blockStart, blockLength); } else { Utility.Copy(Window, blockStart, filterSrcMemory, 0L, blockLength); } } else { uint num5 = MaxWinSize - blockStart; if (Fragmented) { FragWindow.CopyData(filterSrcMemory, 0u, blockStart, num5); FragWindow.CopyData(filterSrcMemory, num5, 0u, num4); } else { Utility.Copy(Window, blockStart, filterSrcMemory, 0L, num5); Utility.Copy(Window, 0L, filterSrcMemory, num5, num4); } } byte[] array = ApplyFilter(filterSrcMemory, blockLength, unpackFilter); Filters[i].Type = 8; if (array != null) { UnpIO_UnpWrite(array, 0u, blockLength); } UnpSomeRead = true; WrittenFileSize += blockLength; num = num4; num3 = (UnpPtr - num) & MaxWinMask; continue; } WrPtr = num; for (int j = i; j < Filters.Count; j++) { UnpackFilter unpackFilter2 = Filters[j]; if (unpackFilter2.Type != 8) { unpackFilter2.NextWindow = false; } } flag = true; break; } int num6 = 0; for (int k = 0; k < Filters.Count; k++) { if (num6 > 0) { Filters[k - num6] = Filters[k]; } if (Filters[k].Type == 8) { num6++; } } if (num6 > 0) { Filters.RemoveRange(Filters.Count - num6, num6); } if (!flag) { UnpWriteArea(num, UnpPtr); WrPtr = UnpPtr; } WriteBorder = (UnpPtr + Math.Min(MaxWinSize, 4194304u)) & MaxWinMask; if (WriteBorder == UnpPtr || (WrPtr != UnpPtr && ((WrPtr - UnpPtr) & MaxWinMask) < ((WriteBorder - UnpPtr) & MaxWinMask))) { WriteBorder = WrPtr; } } private byte[] ApplyFilter(byte[] __d, uint DataSize, UnpackFilter Flt) { int num = 0; switch (Flt.Type) { case 1: case 2: { uint num9 = (uint)WrittenFileSize; byte b2 = (byte)((Flt.Type == 2) ? 233 : 232); uint num10 = 0u; while (num10 + 4 < DataSize) { byte b3 = __d[num++]; num10++; if (b3 != 232 && b3 != b2) { continue; } uint num11 = (num10 + num9) % 16777216; uint num12 = RawGet4(__d, num); if ((num12 & 0x80000000u) != 0) { if (((num12 + num11) & 0x80000000u) == 0) { RawPut4(num12 + 16777216, __d, num); } } else if (((num12 - 16777216) & 0x80000000u) != 0) { RawPut4(num12 - num11, __d, num); } num += 4; num10 += 4; } return __d; } case 3: { uint num5 = (uint)WrittenFileSize; for (uint num6 = 0u; num6 + 3 < DataSize; num6 += 4) { long num7 = num + num6; if (__d[num7 + 3] == 235) { uint num8 = (uint)(__d[num7] + __d[num7 + 1] * 256 + __d[num7 + 2] * 65536); num8 -= (num5 + num6) / 4; __d[num7] = (byte)num8; __d[num7 + 1] = (byte)(num8 >> 8); __d[num7 + 2] = (byte)(num8 >> 16); } } return __d; } case 0: { uint channels = Flt.Channels; uint num2 = 0u; FilterDstMemory = EnsureCapacity(FilterDstMemory, checked((int)DataSize)); byte[] filterDstMemory = FilterDstMemory; for (uint num3 = 0u; num3 < channels; num3++) { byte b = 0; for (uint num4 = num3; num4 < DataSize; num4 += channels) { b = (filterDstMemory[num4] = (byte)(b - __d[num + num2++])); } } return filterDstMemory; } default: return null; } } private void UnpWriteArea(uint StartPtr, uint EndPtr) { if (EndPtr != StartPtr) { UnpSomeRead = true; } if (EndPtr < StartPtr) { UnpAllBuf = true; } if (Fragmented) { uint num = (EndPtr - StartPtr) & MaxWinMask; while (num != 0) { uint blockSize = FragWindow.GetBlockSize(StartPtr, num); FragWindow.GetBuffer(StartPtr, out var buf, out var offset); UnpWriteData(buf, offset, blockSize); num -= blockSize; StartPtr = (StartPtr + blockSize) & MaxWinMask; } } else if (EndPtr < StartPtr) { UnpWriteData(Window, StartPtr, MaxWinSize - StartPtr); UnpWriteData(Window, 0u, EndPtr); } else { UnpWriteData(Window, StartPtr, EndPtr - StartPtr); } } private void UnpWriteData(byte[] Data, uint offset, uint Size) { if (WrittenFileSize < DestUnpSize) { uint num = Size; long num2 = DestUnpSize - WrittenFileSize; if (num > num2) { num = (uint)num2; } UnpIO_UnpWrite(Data, offset, num); WrittenFileSize += Size; } } private void UnpInitData50(bool Solid) { if (!Solid) { TablesRead5 = false; } } private bool ReadBlockHeader(BitInput Inp, ref UnpackBlockHeader Header) { Header.HeaderSize = 0; if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 7 && !UnpReadBuf()) { return false; } Inp.faddbits((uint)((8 - Inp.InBit) & 7)); byte b = (byte)(Inp.fgetbits() >> 8); Inp.faddbits(8u); uint num = (uint)(((b >> 3) & 3) + 1); if (num == 4) { return false; } Header.HeaderSize = (int)(2 + num); Header.BlockBitSize = (b & 7) + 1; byte b2 = (byte)(Inp.fgetbits() >> 8); Inp.faddbits(8u); int num2 = 0; for (uint num3 = 0u; num3 < num; num3++) { num2 += (int)(Inp.fgetbits() >> 8 << (int)(num3 * 8)); Inp.addbits(8u); } Header.BlockSize = num2; if ((byte)(0x5A ^ b ^ num2 ^ (num2 >> 8) ^ (num2 >> 16)) != b2) { return false; } Header.BlockStart = Inp.InAddr; ReadBorder = Math.Min(ReadBorder, Header.BlockStart + Header.BlockSize - 1); Header.LastBlockInFile = (b & 0x40) != 0; Header.TablePresent = (b & 0x80) != 0; return true; } private bool ReadTables(BitInput Inp, ref UnpackBlockHeader Header, ref UnpackBlockTables Tables) { if (!Header.TablePresent) { return true; } if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 25 && !UnpReadBuf()) { return false; } byte[] array = new byte[20]; for (uint num = 0u; num < 20; num++) { uint num2 = (byte)(Inp.fgetbits() >> 12); Inp.faddbits(4u); if (num2 == 15) { uint num3 = (byte)(Inp.fgetbits() >> 12); Inp.faddbits(4u); if (num3 == 0) { array[num] = 15; continue; } num3 += 2; while (num3-- != 0 && num < array.Length) { array[num++] = 0; } num--; } else { array[num] = (byte)num2; } } MakeDecodeTables(array, 0, Tables.BD, 20u); byte[] array2 = new byte[430]; uint num4 = 0u; while (num4 < 430) { if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 5 && !UnpReadBuf()) { return false; } uint num5 = DecodeNumber(Inp, Tables.BD); if (num5 < 16) { array2[num4] = (byte)num5; num4++; } else if (num5 < 18) { uint num6; if (num5 == 16) { num6 = (Inp.fgetbits() >> 13) + 3; Inp.faddbits(3u); } else { num6 = (Inp.fgetbits() >> 9) + 11; Inp.faddbits(7u); } if (num4 == 0) { return false; } while (num6-- != 0 && num4 < 430) { array2[num4] = array2[num4 - 1]; num4++; } } else { uint num7; if (num5 == 18) { num7 = (Inp.fgetbits() >> 13) + 3; Inp.faddbits(3u); } else { num7 = (Inp.fgetbits() >> 9) + 11; Inp.faddbits(7u); } while (num7-- != 0 && num4 < 430) { array2[num4++] = 0; } } } TablesRead5 = true; if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop) { return false; } MakeDecodeTables(array2, 0, Tables.LD, 306u); MakeDecodeTables(array2, 306, Tables.DD, 64u); MakeDecodeTables(array2, 370, Tables.LDD, 16u); MakeDecodeTables(array2, 386, Tables.RD, 44u); return true; } private void InitFilters() { Filters.Clear(); } private void InsertOldDist(uint Distance) { OldDist[3] = OldDist[2]; OldDist[2] = OldDist[1]; OldDist[1] = OldDist[0]; OldDist[0] = Distance; } private void CopyString(uint Length, uint Distance) { uint num = UnpPtr - Distance; if (num < MaxWinSize - 4097 && UnpPtr < MaxWinSize - 4097) { byte[] window = Window; while (Length-- != 0) { window[UnpPtr++] = window[num++]; } } else { while (Length-- != 0) { Window[UnpPtr] = Window[num++ & MaxWinMask]; UnpPtr = (UnpPtr + 1) & MaxWinMask; } } } private uint DecodeNumber(BitInput Inp, DecodeTable Dec) { uint num = Inp.getbits() & 0xFFFE; if (num < Dec.DecodeLen[Dec.QuickBits]) { uint num2 = num >> (int)(16 - Dec.QuickBits); Inp.addbits(Dec.QuickLen[num2]); return Dec.QuickNum[num2]; } uint num3 = 15u; for (uint num4 = Dec.QuickBits + 1; num4 < 15; num4++) { if (num < Dec.DecodeLen[num4]) { num3 = num4; break; } } Inp.addbits(num3); uint num5 = num - Dec.DecodeLen[num3 - 1]; num5 >>= (int)(16 - num3); uint num6 = Dec.DecodePos[num3] + num5; if (num6 >= Dec.MaxNum) { num6 = 0u; } return Dec.DecodeNum[num6]; } private uint SlotToLength(BitInput Inp, uint Slot) { uint num = 2u; uint num2; if (Slot < 8) { num2 = 0u; num += Slot; } else { num2 = Slot / 4 - 1; num += (4 | (Slot & 3)) << (int)num2; } if (num2 != 0) { num += Inp.getbits() >> (int)(16 - num2); Inp.addbits(num2); } return num; } public Unpack() : base(AllocBuffer: true) { _UnpackCtor(); Window = null; Fragmented = false; Suspended = false; UnpAllBuf = false; UnpSomeRead = false; MaxWinSize = 0u; MaxWinMask = 0u; UnpInitData(Solid: false); UnpInitData15(Solid: false); InitHuff(); } private void Init(uint WinSize, bool Solid) { if (WinSize == 0) { throw new InvalidFormatException("invalid window size (possibly due to a rar file with a 4GB being unpacked on a 32-bit platform)"); } if (WinSize < 262144) { WinSize = 262144u; } if (WinSize <= MaxWinSize || WinSize >> 16 > 65536) { return; } bool flag = Solid && (Window != null || Fragmented); if (flag && Fragmented) { throw new InvalidFormatException("Grow && Fragmented"); } byte[] array = (Fragmented ? null : new byte[WinSize]); if (array == null) { if (flag || WinSize < 16777216) { throw new InvalidFormatException("Grow || WinSize<0x1000000"); } if (Window != null) { Window = null; } FragWindow.Init(WinSize); Fragmented = true; } if (!Fragmented) { if (flag) { for (uint num = 1u; num <= MaxWinSize; num++) { array[(UnpPtr - num) & (WinSize - 1)] = Window[(UnpPtr - num) & (MaxWinSize - 1)]; } } Window = array; } MaxWinSize = WinSize; MaxWinMask = MaxWinSize - 1; } private void DoUnpack(uint Method, bool Solid) { switch (Method) { case 15u: if (!Fragmented) { Unpack15(Solid); } break; case 20u: case 26u: if (!Fragmented) { Unpack20(Solid); } break; case 29u: if (!Fragmented) { throw new NotImplementedException(); } break; case 50u: Unpack5(Solid); break; default: throw new InvalidFormatException("unknown compression method " + Method); } } private void UnpInitData(bool Solid) { if (!Solid) { Utility.Memset(OldDist, 0u, OldDist.Length); OldDistPtr = 0u; LastDist = (LastLength = 0u); BlockTables = default(UnpackBlockTables); BlockTables.Init(); UnpPtr = (WrPtr = 0u); WriteBorder = Math.Min(MaxWinSize, 4194304u) & MaxWinMask; } InitFilters(); Inp.InitBitInput(); WrittenFileSize = 0L; ReadTop = 0; ReadBorder = 0; BlockHeader = default(UnpackBlockHeader); BlockHeader.BlockSize = -1; UnpInitData20(Solid); UnpInitData50(Solid); } private void MakeDecodeTables(byte[] LengthTable, int offset, DecodeTable Dec, uint Size) { Dec.MaxNum = Size; uint[] array = new uint[16]; for (uint num = 0u; num < Size; num++) { array[LengthTable[offset + num] & 0xF]++; } array[0] = 0u; Utility.FillFast(Dec.DecodeNum, (ushort)0); Dec.DecodePos[0] = 0u; Dec.DecodeLen[0] = 0u; uint num2 = 0u; for (int i = 1; i < 16; i++) { num2 += array[i]; uint num3 = num2 << 16 - i; num2 *= 2; Dec.DecodeLen[i] = num3; Dec.DecodePos[i] = Dec.DecodePos[i - 1] + array[i - 1]; } uint[] array2 = new uint[Dec.DecodePos.Length]; Array.Copy(Dec.DecodePos, 0, array2, 0, array2.Length); for (uint num4 = 0u; num4 < Size; num4++) { byte b = (byte)(LengthTable[offset + num4] & 0xF); if (b != 0) { uint num5 = array2[b]; Dec.DecodeNum[num5] = (ushort)num4; array2[b]++; } } if (Size - 298 <= 1 || Size == 306) { Dec.QuickBits = 10u; } else { Dec.QuickBits = 7u; } uint num6 = (uint)(1 << (int)Dec.QuickBits); byte b2 = 1; for (uint num7 = 0u; num7 < num6; num7++) { uint num8 = num7 << (int)(16 - Dec.QuickBits); while (b2 < Dec.DecodeLen.Length && num8 >= Dec.DecodeLen[b2]) { b2++; } Dec.QuickLen[num7] = b2; uint num9 = num8 - Dec.DecodeLen[b2 - 1]; num9 >>= 16 - b2; uint num10; if (b2 < Dec.DecodePos.Length && (num10 = Dec.DecodePos[b2] + num9) < Size) { Dec.QuickNum[num7] = Dec.DecodeNum[num10]; } else { Dec.QuickNum[num7] = 0; } } } private bool IsFileExtracted() { return FileExtracted; } private void SetDestSize(long DestSize) { DestUnpSize = DestSize; FileExtracted = false; } private void SetSuspended(bool Suspended) { this.Suspended = Suspended; } private uint GetChar() { if (Inp.InAddr > 32738) { UnpReadBuf(); } return Inp.InBuf[Inp.InAddr++]; } } internal static class UnpackGlobal { public const int MAX_QUICK_DECODE_BITS = 10; public const int MAX_UNPACK_FILTERS = 8192; public const int MAX3_UNPACK_FILTERS = 8192; private const int MAX3_UNPACK_CHANNELS = 1024; public const int MAX_FILTER_BLOCK_SIZE = 4194304; public const int UNPACK_MAX_WRITE = 4194304; } internal sealed class DecodeTable { public uint MaxNum; public readonly uint[] DecodeLen = new uint[16]; public readonly uint[] DecodePos = new uint[16]; public uint QuickBits; public readonly byte[] QuickLen = new byte[1024]; public readonly ushort[] QuickNum = new ushort[1024]; public readonly ushort[] DecodeNum = new ushort[306]; } internal struct UnpackBlockHeader { public int BlockSize; public int BlockBitSize; public int BlockStart; public int HeaderSize; public bool LastBlockInFile; public bool TablePresent; } internal struct UnpackBlockTables { public DecodeTable LD; public DecodeTable DD; public DecodeTable LDD; public DecodeTable RD; public DecodeTable BD; public void Init() { LD = new DecodeTable(); DD = new DecodeTable(); LDD = new DecodeTable(); RD = new DecodeTable(); BD = new DecodeTable(); } } internal class UnpackFilter { public byte Type; public uint BlockStart; public uint BlockLength; public byte Channels; public bool NextWindow; } internal class UnpackFilter30 { public uint BlockStart; public uint BlockLength; public bool NextWindow; public uint ParentFilter; } internal class AudioVariables { public int K1; public int K2; public int K3; public int K4; public int K5; public int D1; public int D2; public int D3; public int D4; public int LastDelta; public readonly uint[] Dif = new uint[11]; public uint ByteCount; public int LastChar; } } namespace SharpCompress.Compressors.Rar.UnpackV1 { internal sealed class Unpack : SharpCompress.Compressors.Rar.VM.BitInput, IRarUnpack { private readonly SharpCompress.Compressors.Rar.VM.BitInput Inp; private readonly ModelPpm ppm = new ModelPpm(); private readonly RarVM rarVM = new RarVM(); private readonly List filters = new List(); private readonly List prgStack = new List(); private readonly List oldFilterLengths = new List(); private int lastFilter; private bool tablesRead; private readonly byte[] unpOldTable = new byte[404]; private BlockTypes unpBlockType; private long writtenFileSize; private bool ppmError; private int prevLowDist; private int lowDistRepCount; private static readonly int[] DBitLengthCounts = new int[19] { 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 14, 0, 12 }; private FileHeader fileHeader; private int readBorder; private bool suspended; internal bool unpAllBuf; private Stream readStream; private Stream writeStream; internal bool unpSomeRead; private int readTop; private long destUnpSize; private byte[] window; private readonly int[] oldDist = new int[4]; private int unpPtr; private int wrPtr; private int oldDistPtr; private readonly int[] ChSet = new int[256]; private readonly int[] ChSetA = new int[256]; private readonly int[] ChSetB = new int[256]; private readonly int[] ChSetC = new int[256]; private readonly int[] Place = new int[256]; private readonly int[] PlaceA = new int[256]; private readonly int[] PlaceB = new int[256]; private readonly int[] PlaceC = new int[256]; private readonly int[] NToPl = new int[256]; private readonly int[] NToPlB = new int[256]; private readonly int[] NToPlC = new int[256]; private int FlagBuf; private int AvrPlc; private int AvrPlcB; private int AvrLn1; private int AvrLn2; private int AvrLn3; private int Buf60; private int NumHuf; private int StMode; private int LCount; private int FlagsCnt; private int Nhfb; private int Nlzb; private int MaxDist3; private int lastDist; private int lastLength; private const int STARTL1 = 2; private static readonly int[] DecL1 = new int[11] { 32768, 40960, 49152, 53248, 57344, 59904, 60928, 61440, 61952, 61952, 65535 }; private static readonly int[] PosL1 = new int[13] { 0, 0, 0, 2, 3, 5, 7, 11, 16, 20, 24, 32, 32 }; private const int STARTL2 = 3; private static readonly int[] DecL2 = new int[10] { 40960, 49152, 53248, 57344, 59904, 60928, 61440, 61952, 62016, 65535 }; private static readonly int[] PosL2 = new int[13] { 0, 0, 0, 0, 5, 7, 9, 13, 18, 22, 26, 34, 36 }; private const int STARTHF0 = 4; private static readonly int[] DecHf0 = new int[9] { 32768, 49152, 57344, 61952, 61952, 61952, 61952, 61952, 65535 }; private static readonly int[] PosHf0 = new int[13] { 0, 0, 0, 0, 0, 8, 16, 24, 33, 33, 33, 33, 33 }; private const int STARTHF1 = 5; private static readonly int[] DecHf1 = new int[8] { 8192, 49152, 57344, 61440, 61952, 61952, 63456, 65535 }; private static readonly int[] PosHf1 = new int[13] { 0, 0, 0, 0, 0, 0, 4, 44, 60, 76, 80, 80, 127 }; private const int STARTHF2 = 5; private static readonly int[] DecHf2 = new int[8] { 4096, 9216, 32768, 49152, 64000, 65535, 65535, 65535 }; private static readonly int[] PosHf2 = new int[13] { 0, 0, 0, 0, 0, 0, 2, 7, 53, 117, 233, 0, 0 }; private const int STARTHF3 = 6; private static readonly int[] DecHf3 = new int[7] { 2048, 9216, 60928, 65152, 65535, 65535, 65535 }; private static readonly int[] PosHf3 = new int[13] { 0, 0, 0, 0, 0, 0, 0, 2, 16, 218, 251, 0, 0 }; private const int STARTHF4 = 8; private static readonly int[] DecHf4 = new int[6] { 65280, 65535, 65535, 65535, 65535, 65535 }; private static readonly int[] PosHf4 = new int[13] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0 }; private static readonly int[] ShortLen1 = new int[16] { 1, 3, 4, 4, 5, 6, 7, 8, 8, 4, 4, 5, 6, 6, 4, 0 }; private static readonly int[] ShortXor1 = new int[15] { 0, 160, 208, 224, 240, 248, 252, 254, 255, 192, 128, 144, 152, 156, 176 }; private static readonly int[] ShortLen2 = new int[16] { 2, 3, 3, 3, 4, 4, 5, 6, 6, 4, 4, 5, 6, 6, 4, 0 }; private static readonly int[] ShortXor2 = new int[15] { 0, 64, 96, 160, 208, 224, 240, 248, 252, 192, 128, 144, 152, 156, 176 }; private readonly MultDecode[] MD = new MultDecode[4]; private readonly byte[] UnpOldTable20 = new byte[1028]; private int UnpAudioBlock; private int UnpChannels; private int UnpCurChannel; private int UnpChannelDelta; private readonly SharpCompress.Compressors.Rar.UnpackV1.Decode.AudioVariables[] AudV = new SharpCompress.Compressors.Rar.UnpackV1.Decode.AudioVariables[4]; private readonly LitDecode LD = new LitDecode(); private readonly DistDecode DD = new DistDecode(); private readonly LowDistDecode LDD = new LowDistDecode(); private readonly RepDecode RD = new RepDecode(); private readonly BitDecode BD = new BitDecode(); private static readonly int[] LDecode = new int[28] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224 }; private static readonly byte[] LBits = new byte[28] { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 }; private static readonly int[] DDecode = new int[48] { 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152, 65536, 98304, 131072, 196608, 262144, 327680, 393216, 458752, 524288, 589824, 655360, 720896, 786432, 851968, 917504, 983040 }; private static readonly int[] DBits = new int[48] { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 }; private static readonly int[] SDDecode = new int[8] { 0, 4, 8, 16, 32, 64, 128, 192 }; private static readonly int[] SDBits = new int[8] { 2, 2, 3, 4, 5, 6, 6, 6 }; private const int MAX_QUICK_DECODE_BITS = 10; private const int MAX_UNPACK_FILTERS = 8192; private const int MAX3_UNPACK_FILTERS = 8192; private const int MAX3_UNPACK_CHANNELS = 1024; private const int MAX_FILTER_BLOCK_SIZE = 4194304; private const int UNPACK_MAX_WRITE = 4194304; private bool TablesRead5; private int WriteBorder; private const int MaxWinSize = 4194304; private const int MaxWinMask = 4194303; public int BlockSize; public int BlockBitSize; public int BlockStart; public int HeaderSize; public bool LastBlockInFile; public bool TablePresent; public bool FileExtracted { get; private set; } public long DestSize { get { return destUnpSize; } set { destUnpSize = value; FileExtracted = false; } } public bool Suspended { get { return suspended; } set { suspended = value; } } public int Char { get { if (inAddr > 32738) { unpReadBuf(); } return base.InBuf[inAddr++] & 0xFF; } } public int PpmEscChar { get; set; } private int UnpPtr { get { return unpPtr; } set { unpPtr = value; } } private int ReadBorder { get { return readBorder; } set { readBorder = value; } } private long DestUnpSize { get { return destUnpSize; } set { destUnpSize = value; } } private long WrittenFileSize { get { return writtenFileSize; } set { writtenFileSize = value; } } private byte[] Window => window; private uint LastLength { get { return (uint)lastLength; } set { lastLength = (int)value; } } private int WrPtr { get { return wrPtr; } set { wrPtr = value; } } private Unpack BlockHeader => this; private Unpack Header => this; private int ReadTop { get { return readTop; } set { readTop = value; } } private List Filters => filters; public Unpack() { Inp = this; } private void Init(byte[] window) { if (window == null) { this.window = new byte[4194304]; } else { this.window = window; } inAddr = 0; UnpInitData(solid: false); } public void DoUnpack(FileHeader fileHeader, Stream readStream, Stream writeStream) { destUnpSize = fileHeader.UncompressedSize; this.fileHeader = fileHeader; this.readStream = readStream; this.writeStream = writeStream; if (!fileHeader.IsSolid) { Init(null); } suspended = false; DoUnpack(); } public void DoUnpack() { if (fileHeader.CompressionMethod == 0) { UnstoreFile(); return; } switch (fileHeader.CompressionAlgorithm) { case 15: unpack15(fileHeader.IsSolid); break; case 20: case 26: unpack20(fileHeader.IsSolid); break; case 29: case 36: Unpack29(fileHeader.IsSolid); break; case 50: Unpack5(fileHeader.IsSolid); break; default: throw new InvalidFormatException("unknown rar compression version " + fileHeader.CompressionAlgorithm); } } private void UnstoreFile() { byte[] array = new byte[65536]; do { int num = readStream.Read(array, 0, (int)Math.Min(array.Length, destUnpSize)); if (num != 0 && num != -1) { num = (int)((num < destUnpSize) ? num : destUnpSize); writeStream.Write(array, 0, num); if (destUnpSize >= 0) { destUnpSize -= num; } continue; } break; } while (!suspended); } private void Unpack29(bool solid) { int[] array = new int[60]; byte[] array2 = new byte[60]; if (array[1] == 0) { int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; while (num4 < DBitLengthCounts.Length) { int num5 = DBitLengthCounts[num4]; int num6 = 0; while (num6 < num5) { array[num3] = num; array2[num3] = (byte)num2; num6++; num3++; num += 1 << num2; } num4++; num2++; } } FileExtracted = true; if (!suspended) { UnpInitData(solid); if (!unpReadBuf() || ((!solid || !tablesRead) && !ReadTables())) { return; } } if (ppmError) { return; } while (true) { unpPtr &= 4194303; if (inAddr > readBorder && !unpReadBuf()) { break; } if (((wrPtr - unpPtr) & 0x3FFFFF) < 260 && wrPtr != unpPtr) { UnpWriteBuf(); if (destUnpSize <= 0) { return; } if (suspended) { FileExtracted = false; return; } } if (unpBlockType == BlockTypes.BLOCK_PPM) { int num7 = ppm.DecodeChar(); if (num7 == -1) { ppmError = true; break; } if (num7 == PpmEscChar) { int num8 = ppm.DecodeChar(); if (num8 == 0) { if (!ReadTables()) { break; } continue; } if (num8 == 2 || num8 == -1) { break; } if (num8 == 3) { if (!ReadVMCodePPM()) { break; } continue; } if (num8 == 4) { int num9 = 0; int num10 = 0; bool flag = false; for (int i = 0; i < 4; i++) { if (flag) { break; } int num11 = ppm.DecodeChar(); if (num11 == -1) { flag = true; } else if (i == 3) { num10 = num11 & 0xFF; } else { num9 = (num9 << 8) + (num11 & 0xFF); } } if (flag) { break; } CopyString(num10 + 32, num9 + 2); continue; } if (num8 == 5) { int num12 = ppm.DecodeChar(); if (num12 == -1) { break; } CopyString(num12 + 4, 1); continue; } } window[unpPtr++] = (byte)num7; continue; } int num13 = this.decodeNumber(LD); if (num13 < 256) { window[unpPtr++] = (byte)num13; } else if (num13 >= 271) { int num14 = LDecode[num13 -= 271] + 3; int num15; if ((num15 = LBits[num13]) > 0) { num14 += Utility.URShift(GetBits(), 16 - num15); AddBits(num15); } int num16 = this.decodeNumber(DD); int num17 = array[num16] + 1; if ((num15 = array2[num16]) > 0) { if (num16 > 9) { if (num15 > 4) { num17 += Utility.URShift(GetBits(), 20 - num15) << 4; AddBits(num15 - 4); } if (lowDistRepCount > 0) { lowDistRepCount--; num17 += prevLowDist; } else { int num18 = this.decodeNumber(LDD); if (num18 == 16) { lowDistRepCount = 15; num17 += prevLowDist; } else { num17 += num18; prevLowDist = num18; } } } else { num17 += Utility.URShift(GetBits(), 16 - num15); AddBits(num15); } } if (num17 >= 8192) { num14++; if ((long)num17 >= 262144L) { num14++; } } InsertOldDist(num17); InsertLastMatch(num14, num17); CopyString(num14, num17); } else if (num13 == 256) { if (!ReadEndOfBlock()) { break; } } else if (num13 == 257) { if (!ReadVMCode()) { break; } } else if (num13 == 258) { if (lastLength != 0) { CopyString(lastLength, lastDist); } } else if (num13 < 263) { int num19 = num13 - 259; int num20 = oldDist[num19]; for (int num21 = num19; num21 > 0; num21--) { oldDist[num21] = oldDist[num21 - 1]; } oldDist[0] = num20; int num22 = this.decodeNumber(RD); int num23 = LDecode[num22] + 2; int num15; if ((num15 = LBits[num22]) > 0) { num23 += Utility.URShift(GetBits(), 16 - num15); AddBits(num15); } InsertLastMatch(num23, num20); CopyString(num23, num20); } else if (num13 < 272) { int num24 = SDDecode[num13 -= 263] + 1; int num15; if ((num15 = SDBits[num13]) > 0) { num24 += Utility.URShift(GetBits(), 16 - num15); AddBits(num15); } InsertOldDist(num24); InsertLastMatch(2, num24); CopyString(2, num24); } } UnpWriteBuf(); } private void UnpWriteBuf() { int num = wrPtr; int num2 = (unpPtr - num) & 0x3FFFFF; for (int i = 0; i < prgStack.Count; i++) { UnpackFilter unpackFilter = prgStack[i]; if (unpackFilter == null) { continue; } if (unpackFilter.NextWindow) { unpackFilter.NextWindow = false; continue; } int blockStart = unpackFilter.BlockStart; int blockLength = unpackFilter.BlockLength; if (((blockStart - num) & 0x3FFFFF) >= num2) { continue; } if (num != blockStart) { UnpWriteArea(num, blockStart); num = blockStart; num2 = (unpPtr - num) & 0x3FFFFF; } if (blockLength <= num2) { int num3 = (blockStart + blockLength) & 0x3FFFFF; if (blockStart < num3 || num3 == 0) { rarVM.setMemory(0, window, blockStart, blockLength); } else { int num4 = 4194304 - blockStart; rarVM.setMemory(0, window, blockStart, num4); rarVM.setMemory(num4, window, 0, num3); } VMPreparedProgram program = filters[unpackFilter.ParentFilter].Program; VMPreparedProgram program2 = unpackFilter.Program; if (program.GlobalData.Count > 64) { program2.GlobalData.Clear(); for (int j = 0; j < program.GlobalData.Count - 64; j++) { program2.GlobalData[64 + j] = program.GlobalData[64 + j]; } } ExecuteCode(program2); if (program2.GlobalData.Count > 64) { if (program.GlobalData.Count < program2.GlobalData.Count) { program.GlobalData.SetSize(program2.GlobalData.Count); } for (int k = 0; k < program2.GlobalData.Count - 64; k++) { program.GlobalData[64 + k] = program2.GlobalData[64 + k]; } } else { program.GlobalData.Clear(); } int filteredDataOffset = program2.FilteredDataOffset; int filteredDataSize = program2.FilteredDataSize; byte[] array = new byte[filteredDataSize]; for (int l = 0; l < filteredDataSize; l++) { array[l] = rarVM.Mem[filteredDataOffset + l]; } prgStack[i] = null; while (i + 1 < prgStack.Count) { UnpackFilter unpackFilter2 = prgStack[i + 1]; if (unpackFilter2 == null || unpackFilter2.BlockStart != blockStart || unpackFilter2.BlockLength != filteredDataSize || unpackFilter2.NextWindow) { break; } rarVM.setMemory(0, array, 0, filteredDataSize); VMPreparedProgram program3 = filters[unpackFilter2.ParentFilter].Program; VMPreparedProgram program4 = unpackFilter2.Program; if (program3.GlobalData.Count > 64) { program4.GlobalData.SetSize(program3.GlobalData.Count); for (int m = 0; m < program3.GlobalData.Count - 64; m++) { program4.GlobalData[64 + m] = program3.GlobalData[64 + m]; } } ExecuteCode(program4); if (program4.GlobalData.Count > 64) { if (program3.GlobalData.Count < program4.GlobalData.Count) { program3.GlobalData.SetSize(program4.GlobalData.Count); } for (int n = 0; n < program4.GlobalData.Count - 64; n++) { program3.GlobalData[64 + n] = program4.GlobalData[64 + n]; } } else { program3.GlobalData.Clear(); } filteredDataOffset = program4.FilteredDataOffset; filteredDataSize = program4.FilteredDataSize; array = new byte[filteredDataSize]; for (int num5 = 0; num5 < filteredDataSize; num5++) { array[num5] = program4.GlobalData[filteredDataOffset + num5]; } i++; prgStack[i] = null; } writeStream.Write(array, 0, filteredDataSize); unpSomeRead = true; writtenFileSize += filteredDataSize; destUnpSize -= filteredDataSize; num = num3; num2 = (unpPtr - num) & 0x3FFFFF; continue; } for (int num6 = i; num6 < prgStack.Count; num6++) { UnpackFilter unpackFilter3 = prgStack[num6]; if (unpackFilter3 != null && unpackFilter3.NextWindow) { unpackFilter3.NextWindow = false; } } wrPtr = num; return; } UnpWriteArea(num, unpPtr); wrPtr = unpPtr; } private void UnpWriteArea(int startPtr, int endPtr) { if (endPtr != startPtr) { unpSomeRead = true; } if (endPtr < startPtr) { UnpWriteData(window, startPtr, -startPtr & 0x3FFFFF); UnpWriteData(window, 0, endPtr); unpAllBuf = true; } else { UnpWriteData(window, startPtr, endPtr - startPtr); } } private void UnpWriteData(byte[] data, int offset, int size) { if (destUnpSize > 0) { int num = size; if (num > destUnpSize) { num = (int)destUnpSize; } writeStream.Write(data, offset, num); writtenFileSize += size; destUnpSize -= size; } } private void InsertOldDist(uint distance) { InsertOldDist((int)distance); } private void InsertOldDist(int distance) { oldDist[3] = oldDist[2]; oldDist[2] = oldDist[1]; oldDist[1] = oldDist[0]; oldDist[0] = distance; } private void InsertLastMatch(int length, int distance) { lastDist = distance; lastLength = length; } private void CopyString(uint length, uint distance) { CopyString((int)length, (int)distance); } private void CopyString(int length, int distance) { int num = unpPtr - distance; if (num >= 0 && num < 4194044 && unpPtr < 4194044) { window[unpPtr++] = window[num++]; while (--length > 0) { window[unpPtr++] = window[num++]; } } else { while (length-- != 0) { window[unpPtr] = window[num++ & 0x3FFFFF]; unpPtr = (unpPtr + 1) & 0x3FFFFF; } } } private void UnpInitData(bool solid) { if (!solid) { tablesRead = false; Utility.Fill(oldDist, 0); oldDistPtr = 0; lastDist = 0; lastLength = 0; Utility.Fill(unpOldTable, (byte)0); unpPtr = 0; wrPtr = 0; PpmEscChar = 2; WriteBorder = Math.Min(4194304, 4194304) & 0x3FFFFF; InitFilters(); } InitBitInput(); ppmError = false; writtenFileSize = 0L; readTop = 0; readBorder = 0; unpInitData20(solid); } private void InitFilters() { oldFilterLengths.Clear(); lastFilter = 0; filters.Clear(); prgStack.Clear(); } private bool ReadEndOfBlock() { int bits = GetBits(); bool flag = false; bool flag2; if ((bits & 0x8000) != 0) { flag2 = true; AddBits(1); } else { flag = true; flag2 = (bits & 0x4000) != 0; AddBits(2); } tablesRead = !flag2; if (!flag) { if (flag2) { return ReadTables(); } return true; } return false; } private bool ReadTables() { byte[] array = new byte[20]; byte[] array2 = new byte[404]; if (inAddr > readTop - 25 && !unpReadBuf()) { return false; } AddBits((8 - inBit) & 7); long num = GetBits() & -1; if ((num & 0x8000) != 0L) { unpBlockType = BlockTypes.BLOCK_PPM; return ppm.DecodeInit(this, PpmEscChar); } unpBlockType = BlockTypes.BLOCK_LZ; prevLowDist = 0; lowDistRepCount = 0; if ((num & 0x4000) == 0L) { Utility.Fill(unpOldTable, (byte)0); } AddBits(2); for (int i = 0; i < 20; i++) { int num2 = Utility.URShift(GetBits(), 12) & 0xFF; AddBits(4); if (num2 == 15) { int num3 = Utility.URShift(GetBits(), 12) & 0xFF; AddBits(4); if (num3 == 0) { array[i] = 15; continue; } num3 += 2; while (num3-- > 0 && i < array.Length) { array[i++] = 0; } i--; } else { array[i] = (byte)num2; } } UnpackUtility.makeDecodeTables(array, 0, BD, 20); int num4 = 404; int num5 = 0; while (num5 < num4) { if (inAddr > readTop - 5 && !unpReadBuf()) { return false; } int num6 = this.decodeNumber(BD); if (num6 < 16) { array2[num5] = (byte)((num6 + unpOldTable[num5]) & 0xF); num5++; } else if (num6 < 18) { int num7; if (num6 == 16) { num7 = Utility.URShift(GetBits(), 13) + 3; AddBits(3); } else { num7 = Utility.URShift(GetBits(), 9) + 11; AddBits(7); } while (num7-- > 0 && num5 < num4) { array2[num5] = array2[num5 - 1]; num5++; } } else { int num8; if (num6 == 18) { num8 = Utility.URShift(GetBits(), 13) + 3; AddBits(3); } else { num8 = Utility.URShift(GetBits(), 9) + 11; AddBits(7); } while (num8-- > 0 && num5 < num4) { array2[num5++] = 0; } } } tablesRead = true; if (inAddr > readTop) { return false; } UnpackUtility.makeDecodeTables(array2, 0, LD, 299); UnpackUtility.makeDecodeTables(array2, 299, DD, 60); UnpackUtility.makeDecodeTables(array2, 359, LDD, 17); UnpackUtility.makeDecodeTables(array2, 376, RD, 28); Buffer.BlockCopy(array2, 0, unpOldTable, 0, unpOldTable.Length); return true; } private bool ReadVMCode() { int num = GetBits() >> 8; AddBits(8); int num2 = (num & 7) + 1; switch (num2) { case 7: num2 = (GetBits() >> 8) + 7; AddBits(8); break; case 8: num2 = GetBits(); AddBits(16); break; } List list = new List(); for (int i = 0; i < num2; i++) { if (inAddr >= readTop - 1 && !unpReadBuf() && i < num2 - 1) { return false; } list.Add((byte)(GetBits() >> 8)); AddBits(8); } return AddVMCode(num, list, num2); } private bool ReadVMCodePPM() { int num = ppm.DecodeChar(); if (num == -1) { return false; } int num2 = (num & 7) + 1; switch (num2) { case 7: { int num5 = ppm.DecodeChar(); if (num5 == -1) { return false; } num2 = num5 + 7; break; } case 8: { int num3 = ppm.DecodeChar(); if (num3 == -1) { return false; } int num4 = ppm.DecodeChar(); if (num4 == -1) { return false; } num2 = num3 * 256 + num4; break; } } List list = new List(); for (int i = 0; i < num2; i++) { int num6 = ppm.DecodeChar(); if (num6 == -1) { return false; } list.Add((byte)num6); } return AddVMCode(num, list, num2); } private bool AddVMCode(int firstByte, List vmCode, int length) { SharpCompress.Compressors.Rar.VM.BitInput bitInput = new SharpCompress.Compressors.Rar.VM.BitInput(); bitInput.InitBitInput(); for (int i = 0; i < Math.Min(32768, vmCode.Count); i++) { bitInput.InBuf[i] = vmCode[i]; } rarVM.init(); int num; if ((firstByte & 0x80) != 0) { num = RarVM.ReadData(bitInput); if (num == 0) { InitFilters(); } else { num--; } } else { num = lastFilter; } if (num > filters.Count || num > oldFilterLengths.Count) { return false; } lastFilter = num; bool flag = num == filters.Count; UnpackFilter unpackFilter = new UnpackFilter(); UnpackFilter unpackFilter2; if (flag) { if (num > 1024) { return false; } unpackFilter2 = new UnpackFilter(); filters.Add(unpackFilter2); unpackFilter.ParentFilter = filters.Count - 1; oldFilterLengths.Add(0); unpackFilter2.ExecCount = 0; } else { unpackFilter2 = filters[num]; unpackFilter.ParentFilter = num; unpackFilter2.ExecCount++; } prgStack.Add(unpackFilter); unpackFilter.ExecCount = unpackFilter2.ExecCount; int num2 = RarVM.ReadData(bitInput); if ((firstByte & 0x40) != 0) { num2 += 258; } unpackFilter.BlockStart = (num2 + unpPtr) & 0x3FFFFF; if ((firstByte & 0x20) != 0) { unpackFilter.BlockLength = RarVM.ReadData(bitInput); } else { unpackFilter.BlockLength = ((num < oldFilterLengths.Count) ? oldFilterLengths[num] : 0); } unpackFilter.NextWindow = wrPtr != unpPtr && ((wrPtr - unpPtr) & 0x3FFFFF) <= num2; oldFilterLengths[num] = unpackFilter.BlockLength; Utility.Fill(unpackFilter.Program.InitR, 0); unpackFilter.Program.InitR[3] = 245760; unpackFilter.Program.InitR[4] = unpackFilter.BlockLength; unpackFilter.Program.InitR[5] = unpackFilter.ExecCount; if ((firstByte & 0x10) != 0) { int num3 = Utility.URShift(bitInput.GetBits(), 9); bitInput.AddBits(7); for (int j = 0; j < 7; j++) { if ((num3 & (1 << j)) != 0) { unpackFilter.Program.InitR[j] = RarVM.ReadData(bitInput); } } } if (flag) { int num4 = RarVM.ReadData(bitInput); if (num4 >= 65536 || num4 == 0) { return false; } byte[] array = new byte[num4]; for (int k = 0; k < num4; k++) { if (bitInput.Overflow(3)) { return false; } array[k] = (byte)(bitInput.GetBits() >> 8); bitInput.AddBits(8); } rarVM.prepare(array, num4, unpackFilter2.Program); } unpackFilter.Program.AltCommands = unpackFilter2.Program.Commands; unpackFilter.Program.CommandCount = unpackFilter2.Program.CommandCount; int count = unpackFilter2.Program.StaticData.Count; if (count > 0 && count < 8192) { unpackFilter.Program.StaticData = unpackFilter2.Program.StaticData; } if (unpackFilter.Program.GlobalData.Count < 64) { unpackFilter.Program.GlobalData.Clear(); unpackFilter.Program.GlobalData.SetSize(64); } List globalData = unpackFilter.Program.GlobalData; for (int l = 0; l < 7; l++) { rarVM.SetLowEndianValue(globalData, l * 4, unpackFilter.Program.InitR[l]); } rarVM.SetLowEndianValue(globalData, 28, unpackFilter.BlockLength); rarVM.SetLowEndianValue(globalData, 32, 0); rarVM.SetLowEndianValue(globalData, 36, 0); rarVM.SetLowEndianValue(globalData, 40, 0); rarVM.SetLowEndianValue(globalData, 44, unpackFilter.ExecCount); for (int m = 0; m < 16; m++) { globalData[48 + m] = 0; } if ((firstByte & 8) != 0) { if (bitInput.Overflow(3)) { return false; } int num5 = RarVM.ReadData(bitInput); if (num5 > 8128) { return false; } int count2 = unpackFilter.Program.GlobalData.Count; if (count2 < num5 + 64) { unpackFilter.Program.GlobalData.SetSize(num5 + 64 - count2); } int num6 = 64; globalData = unpackFilter.Program.GlobalData; for (int n = 0; n < num5; n++) { if (bitInput.Overflow(3)) { return false; } globalData[num6 + n] = (byte)Utility.URShift(bitInput.GetBits(), 8); bitInput.AddBits(8); } } return true; } private void ExecuteCode(VMPreparedProgram Prg) { if (Prg.GlobalData.Count > 0) { Prg.InitR[6] = (int)writtenFileSize; rarVM.SetLowEndianValue(Prg.GlobalData, 36, (int)writtenFileSize); rarVM.SetLowEndianValue(Prg.GlobalData, 40, (int)Utility.URShift(writtenFileSize, 32)); rarVM.execute(Prg); } } private void CleanUp() { if (ppm != null) { ppm.SubAlloc?.StopSubAllocator(); } } private void unpack15(bool solid) { if (suspended) { unpPtr = wrPtr; } else { UnpInitData(solid); oldUnpInitData(solid); unpReadBuf(); if (!solid) { initHuff(); unpPtr = 0; } else { unpPtr = wrPtr; } destUnpSize--; } if (destUnpSize >= 0) { getFlagsBuf(); FlagsCnt = 8; } while (destUnpSize >= 0) { unpPtr &= 4194303; if (inAddr > readTop - 30 && !unpReadBuf()) { break; } if (((wrPtr - unpPtr) & 0x3FFFFF) < 270 && wrPtr != unpPtr) { oldUnpWriteBuf(); if (suspended) { return; } } if (StMode != 0) { huffDecode(); continue; } if (--FlagsCnt < 0) { getFlagsBuf(); FlagsCnt = 7; } if ((FlagBuf & 0x80) != 0) { FlagBuf <<= 1; if (Nlzb > Nhfb) { longLZ(); } else { huffDecode(); } continue; } FlagBuf <<= 1; if (--FlagsCnt < 0) { getFlagsBuf(); FlagsCnt = 7; } if ((FlagBuf & 0x80) != 0) { FlagBuf <<= 1; if (Nlzb > Nhfb) { huffDecode(); } else { longLZ(); } } else { FlagBuf <<= 1; shortLZ(); } } oldUnpWriteBuf(); } private bool unpReadBuf() { int num = readTop - inAddr; if (num < 0) { return false; } if (inAddr > 16384) { if (num > 0) { Array.Copy(base.InBuf, inAddr, base.InBuf, 0, num); } inAddr = 0; readTop = num; } else { num = readTop; } int num2 = readStream.Read(base.InBuf, num, (32768 - num) & -16); if (num2 > 0) { readTop += num2; } readBorder = readTop - 30; return num2 != -1; } private int getShortLen1(int pos) { if (pos != 1) { return ShortLen1[pos]; } return Buf60 + 3; } private int getShortLen2(int pos) { if (pos != 3) { return ShortLen2[pos]; } return Buf60 + 3; } private void shortLZ() { NumHuf = 0; int num = GetBits(); if (LCount == 2) { AddBits(1); if (num >= 32768) { oldCopyString(lastDist, lastLength); return; } num <<= 1; LCount = 0; } num = Utility.URShift(num, 8); int i; if (AvrLn1 < 37) { for (i = 0; ((num ^ ShortXor1[i]) & ~Utility.URShift(255, getShortLen1(i))) != 0; i++) { } AddBits(getShortLen1(i)); } else { for (i = 0; ((num ^ ShortXor2[i]) & ~(255 >> getShortLen2(i))) != 0; i++) { } AddBits(getShortLen2(i)); } if (i >= 9) { int distance; switch (i) { case 9: LCount++; oldCopyString(lastDist, lastLength); return; case 14: LCount = 0; i = decodeNum(GetBits(), 3, DecL2, PosL2) + 5; distance = (GetBits() >> 1) | 0x8000; AddBits(15); lastLength = i; lastDist = distance; oldCopyString(distance, i); return; } LCount = 0; int num2 = i; distance = oldDist[(oldDistPtr - (i - 9)) & 3]; i = decodeNum(GetBits(), 2, DecL1, PosL1) + 2; if (i == 257 && num2 == 10) { Buf60 ^= 1; return; } if (distance > 256) { i++; } if (distance >= MaxDist3) { i++; } oldDist[oldDistPtr++] = distance; oldDistPtr &= 3; lastLength = i; lastDist = distance; oldCopyString(distance, i); } else { LCount = 0; AvrLn1 += i; AvrLn1 -= AvrLn1 >> 4; int num3 = decodeNum(GetBits(), 5, DecHf2, PosHf2) & 0xFF; int distance = ChSetA[num3]; if (--num3 != -1) { PlaceA[distance]--; int num4 = ChSetA[num3]; PlaceA[num4]++; ChSetA[num3 + 1] = num4; ChSetA[num3] = distance; } i += 2; distance = (oldDist[oldDistPtr++] = distance + 1); oldDistPtr &= 3; lastLength = i; lastDist = distance; oldCopyString(distance, i); } } private void longLZ() { NumHuf = 0; Nlzb += 16; if (Nlzb > 255) { Nlzb = 144; Nhfb = Utility.URShift(Nhfb, 1); } int avrLn = AvrLn2; int bits = GetBits(); int i; if (AvrLn2 >= 122) { i = decodeNum(bits, 3, DecL2, PosL2); } else if (AvrLn2 >= 64) { i = decodeNum(bits, 2, DecL1, PosL1); } else if (bits < 256) { i = bits; AddBits(16); } else { for (i = 0; ((bits << i) & 0x8000) == 0; i++) { } AddBits(i + 1); } AvrLn2 += i; AvrLn2 -= Utility.URShift(AvrLn2, 5); bits = GetBits(); int num = ((AvrPlcB > 10495) ? decodeNum(bits, 5, DecHf2, PosHf2) : ((AvrPlcB <= 1791) ? decodeNum(bits, 4, DecHf0, PosHf0) : decodeNum(bits, 5, DecHf1, PosHf1))); AvrPlcB += num; AvrPlcB -= AvrPlcB >> 8; int num3; int num2; while (true) { num2 = ChSetB[num & 0xFF]; num3 = NToPlB[num2++ & 0xFF]++; if ((num2 & 0xFF) != 0) { break; } corrHuff(ChSetB, NToPlB); } ChSetB[num] = ChSetB[num3]; ChSetB[num3] = num2; num2 = Utility.URShift((num2 & 0xFF00) | Utility.URShift(GetBits(), 8), 1); AddBits(7); int avrLn2 = AvrLn3; if (i != 1 && i != 4) { if (i == 0 && num2 <= MaxDist3) { AvrLn3++; AvrLn3 -= AvrLn3 >> 8; } else if (AvrLn3 > 0) { AvrLn3--; } } i += 3; if (num2 >= MaxDist3) { i++; } if (num2 <= 256) { i += 8; } if (avrLn2 > 176 || (AvrPlc >= 10752 && avrLn < 64)) { MaxDist3 = 32512; } else { MaxDist3 = 8193; } oldDist[oldDistPtr++] = num2; oldDistPtr &= 3; lastLength = i; lastDist = num2; oldCopyString(num2, i); } private void huffDecode() { int bits = GetBits(); int num = ((AvrPlc > 30207) ? decodeNum(bits, 8, DecHf4, PosHf4) : ((AvrPlc > 24063) ? decodeNum(bits, 6, DecHf3, PosHf3) : ((AvrPlc > 13823) ? decodeNum(bits, 5, DecHf2, PosHf2) : ((AvrPlc <= 3583) ? decodeNum(bits, 4, DecHf0, PosHf0) : decodeNum(bits, 5, DecHf1, PosHf1))))); num &= 0xFF; if (StMode != 0) { if (num == 0 && bits > 4095) { num = 256; } if (--num == -1) { bits = GetBits(); AddBits(1); if ((bits & 0x8000) != 0) { NumHuf = (StMode = 0); return; } int length = (((bits & 0x4000) != 0) ? 4 : 3); AddBits(1); int num2 = decodeNum(GetBits(), 5, DecHf2, PosHf2); num2 = (num2 << 5) | Utility.URShift(GetBits(), 11); AddBits(5); oldCopyString(num2, length); return; } } else if (NumHuf++ >= 16 && FlagsCnt == 0) { StMode = 1; } AvrPlc += num; AvrPlc -= Utility.URShift(AvrPlc, 8); Nhfb += 16; if (Nhfb > 255) { Nhfb = 144; Nlzb = Utility.URShift(Nlzb, 1); } window[unpPtr++] = (byte)Utility.URShift(ChSet[num], 8); destUnpSize--; int num3; int num4; while (true) { num3 = ChSet[num]; num4 = NToPl[num3++ & 0xFF]++; if ((num3 & 0xFF) <= 161) { break; } corrHuff(ChSet, NToPl); } ChSet[num] = ChSet[num4]; ChSet[num4] = num3; } private void getFlagsBuf() { int num = decodeNum(GetBits(), 5, DecHf2, PosHf2); int num2; int num3; while (true) { num2 = ChSetC[num]; FlagBuf = Utility.URShift(num2, 8); num3 = NToPlC[num2++ & 0xFF]++; if ((num2 & 0xFF) != 0) { break; } corrHuff(ChSetC, NToPlC); } ChSetC[num] = ChSetC[num3]; ChSetC[num3] = num2; } private void oldUnpInitData(bool Solid) { if (!Solid) { AvrPlcB = (AvrLn1 = (AvrLn2 = (AvrLn3 = (NumHuf = (Buf60 = 0))))); AvrPlc = 13568; MaxDist3 = 8193; Nhfb = (Nlzb = 128); } FlagsCnt = 0; FlagBuf = 0; StMode = 0; LCount = 0; readTop = 0; } private void initHuff() { for (int i = 0; i < 256; i++) { Place[i] = (PlaceA[i] = (PlaceB[i] = i)); PlaceC[i] = (~i + 1) & 0xFF; ChSet[i] = (ChSetB[i] = i << 8); ChSetA[i] = i; ChSetC[i] = ((~i + 1) & 0xFF) << 8; } Utility.Fill(NToPl, 0); Utility.Fill(NToPlB, 0); Utility.Fill(NToPlC, 0); corrHuff(ChSetB, NToPlB); } private void corrHuff(int[] CharSet, int[] NumToPlace) { int num = 0; for (int num2 = 7; num2 >= 0; num2--) { int num3 = 0; while (num3 < 32) { CharSet[num] = (CharSet[num] & -256) | num2; num3++; num++; } } Utility.Fill(NumToPlace, 0); for (int num2 = 6; num2 >= 0; num2--) { NumToPlace[num2] = (7 - num2) * 32; } } private void oldCopyString(int Distance, int Length) { destUnpSize -= Length; while (Length-- != 0) { window[unpPtr] = window[(unpPtr - Distance) & 0x3FFFFF]; unpPtr = (unpPtr + 1) & 0x3FFFFF; } } private int decodeNum(int Num, int StartPos, int[] DecTab, int[] PosTab) { Num &= 0xFFF0; int i; for (i = 0; DecTab[i] <= Num; i++) { StartPos++; } AddBits(StartPos); return Utility.URShift(Num - ((i != 0) ? DecTab[i - 1] : 0), 16 - StartPos) + PosTab[StartPos]; } private void oldUnpWriteBuf() { if (unpPtr != wrPtr) { unpSomeRead = true; } if (unpPtr < wrPtr) { writeStream.Write(window, wrPtr, -wrPtr & 0x3FFFFF); writeStream.Write(window, 0, unpPtr); unpAllBuf = true; } else { writeStream.Write(window, wrPtr, unpPtr - wrPtr); } wrPtr = unpPtr; } private void unpack20(bool solid) { if (suspended) { unpPtr = wrPtr; } else { UnpInitData(solid); if (!unpReadBuf() || (!solid && !ReadTables20())) { return; } destUnpSize--; } while (destUnpSize >= 0) { unpPtr &= 4194303; if (inAddr > readTop - 30 && !unpReadBuf()) { break; } if (((wrPtr - unpPtr) & 0x3FFFFF) < 270 && wrPtr != unpPtr) { oldUnpWriteBuf(); if (suspended) { return; } } if (UnpAudioBlock != 0) { int num = this.decodeNumber(MD[UnpCurChannel]); if (num == 256) { if (!ReadTables20()) { break; } continue; } window[unpPtr++] = DecodeAudio(num); if (++UnpCurChannel == UnpChannels) { UnpCurChannel = 0; } destUnpSize--; continue; } int num2 = this.decodeNumber(LD); if (num2 < 256) { window[unpPtr++] = (byte)num2; destUnpSize--; } else if (num2 > 269) { int num3 = LDecode[num2 -= 270] + 3; int num4; if ((num4 = LBits[num2]) > 0) { num3 += Utility.URShift(GetBits(), 16 - num4); AddBits(num4); } int num5 = this.decodeNumber(DD); int num6 = DDecode[num5] + 1; if ((num4 = DBits[num5]) > 0) { num6 += Utility.URShift(GetBits(), 16 - num4); AddBits(num4); } if (num6 >= 8192) { num3++; if ((long)num6 >= 262144L) { num3++; } } CopyString20(num3, num6); } else if (num2 == 269) { if (!ReadTables20()) { break; } } else if (num2 == 256) { CopyString20(lastLength, lastDist); } else if (num2 < 261) { int num7 = oldDist[(oldDistPtr - (num2 - 256)) & 3]; int num8 = this.decodeNumber(RD); int num9 = LDecode[num8] + 2; int num4; if ((num4 = LBits[num8]) > 0) { num9 += Utility.URShift(GetBits(), 16 - num4); AddBits(num4); } if (num7 >= 257) { num9++; if (num7 >= 8192) { num9++; if (num7 >= 262144) { num9++; } } } CopyString20(num9, num7); } else if (num2 < 270) { int num10 = SDDecode[num2 -= 261] + 1; int num4; if ((num4 = SDBits[num2]) > 0) { num10 += Utility.URShift(GetBits(), 16 - num4); AddBits(num4); } CopyString20(2, num10); } } ReadLastTables(); oldUnpWriteBuf(); } private void CopyString20(int Length, int Distance) { lastDist = (oldDist[oldDistPtr++ & 3] = Distance); lastLength = Length; destUnpSize -= Length; int num = unpPtr - Distance; if (num < 4194004 && unpPtr < 4194004) { window[unpPtr++] = window[num++]; window[unpPtr++] = window[num++]; while (Length > 2) { Length--; window[unpPtr++] = window[num++]; } } else { while (Length-- != 0) { window[unpPtr] = window[num++ & 0x3FFFFF]; unpPtr = (unpPtr + 1) & 0x3FFFFF; } } } private bool ReadTables20() { byte[] array = new byte[19]; byte[] array2 = new byte[1028]; if (inAddr > readTop - 25 && !unpReadBuf()) { return false; } int bits = GetBits(); UnpAudioBlock = bits & 0x8000; if ((bits & 0x4000) == 0) { Utility.Fill(UnpOldTable20, (byte)0); } AddBits(2); int num; if (UnpAudioBlock != 0) { UnpChannels = (Utility.URShift(bits, 12) & 3) + 1; if (UnpCurChannel >= UnpChannels) { UnpCurChannel = 0; } AddBits(2); num = 257 * UnpChannels; } else { num = 374; } int i; for (i = 0; i < 19; i++) { array[i] = (byte)Utility.URShift(GetBits(), 12); AddBits(4); } UnpackUtility.makeDecodeTables(array, 0, BD, 19); i = 0; while (i < num) { if (inAddr > readTop - 5 && !unpReadBuf()) { return false; } int num2 = this.decodeNumber(BD); if (num2 < 16) { array2[i] = (byte)((num2 + UnpOldTable20[i]) & 0xF); i++; continue; } int num3; switch (num2) { case 16: num3 = Utility.URShift(GetBits(), 14) + 3; AddBits(2); while (num3-- > 0 && i < num) { array2[i] = array2[i - 1]; i++; } continue; case 17: num3 = Utility.URShift(GetBits(), 13) + 3; AddBits(3); break; default: num3 = Utility.URShift(GetBits(), 9) + 11; AddBits(7); break; } while (num3-- > 0 && i < num) { array2[i++] = 0; } } if (inAddr > readTop) { return true; } if (UnpAudioBlock != 0) { for (i = 0; i < UnpChannels; i++) { UnpackUtility.makeDecodeTables(array2, i * 257, MD[i], 257); } } else { UnpackUtility.makeDecodeTables(array2, 0, LD, 298); UnpackUtility.makeDecodeTables(array2, 298, DD, 48); UnpackUtility.makeDecodeTables(array2, 346, RD, 28); } for (int j = 0; j < UnpOldTable20.Length; j++) { UnpOldTable20[j] = array2[j]; } return true; } private void unpInitData20(bool Solid) { if (!Solid) { UnpChannelDelta = (UnpCurChannel = 0); UnpChannels = 1; AudV[0] = new SharpCompress.Compressors.Rar.UnpackV1.Decode.AudioVariables(); AudV[1] = new SharpCompress.Compressors.Rar.UnpackV1.Decode.AudioVariables(); AudV[2] = new SharpCompress.Compressors.Rar.UnpackV1.Decode.AudioVariables(); AudV[3] = new SharpCompress.Compressors.Rar.UnpackV1.Decode.AudioVariables(); Utility.Fill(UnpOldTable20, (byte)0); } } private void ReadLastTables() { if (readTop < inAddr + 5) { return; } if (UnpAudioBlock != 0) { if (this.decodeNumber(MD[UnpCurChannel]) == 256) { ReadTables20(); } } else if (this.decodeNumber(LD) == 269) { ReadTables20(); } } private byte DecodeAudio(int Delta) { SharpCompress.Compressors.Rar.UnpackV1.Decode.AudioVariables audioVariables = AudV[UnpCurChannel]; audioVariables.ByteCount++; audioVariables.D4 = audioVariables.D3; audioVariables.D3 = audioVariables.D2; audioVariables.D2 = audioVariables.LastDelta - audioVariables.D1; audioVariables.D1 = audioVariables.LastDelta; int num = (Utility.URShift(8 * audioVariables.LastChar + audioVariables.K1 * audioVariables.D1 + (audioVariables.K2 * audioVariables.D2 + audioVariables.K3 * audioVariables.D3) + (audioVariables.K4 * audioVariables.D4 + audioVariables.K5 * UnpChannelDelta), 3) & 0xFF) - Delta; int num2 = (byte)Delta << 3; audioVariables.Dif[0] += Math.Abs(num2); audioVariables.Dif[1] += Math.Abs(num2 - audioVariables.D1); audioVariables.Dif[2] += Math.Abs(num2 + audioVariables.D1); audioVariables.Dif[3] += Math.Abs(num2 - audioVariables.D2); audioVariables.Dif[4] += Math.Abs(num2 + audioVariables.D2); audioVariables.Dif[5] += Math.Abs(num2 - audioVariables.D3); audioVariables.Dif[6] += Math.Abs(num2 + audioVariables.D3); audioVariables.Dif[7] += Math.Abs(num2 - audioVariables.D4); audioVariables.Dif[8] += Math.Abs(num2 + audioVariables.D4); audioVariables.Dif[9] += Math.Abs(num2 - UnpChannelDelta); audioVariables.Dif[10] += Math.Abs(num2 + UnpChannelDelta); audioVariables.LastDelta = (byte)(num - audioVariables.LastChar); UnpChannelDelta = audioVariables.LastDelta; audioVariables.LastChar = num; if ((audioVariables.ByteCount & 0x1F) == 0) { int num3 = audioVariables.Dif[0]; int num4 = 0; audioVariables.Dif[0] = 0; for (int i = 1; i < audioVariables.Dif.Length; i++) { if (audioVariables.Dif[i] < num3) { num3 = audioVariables.Dif[i]; num4 = i; } audioVariables.Dif[i] = 0; } switch (num4) { case 1: if (audioVariables.K1 >= -16) { audioVariables.K1--; } break; case 2: if (audioVariables.K1 < 16) { audioVariables.K1++; } break; case 3: if (audioVariables.K2 >= -16) { audioVariables.K2--; } break; case 4: if (audioVariables.K2 < 16) { audioVariables.K2++; } break; case 5: if (audioVariables.K3 >= -16) { audioVariables.K3--; } break; case 6: if (audioVariables.K3 < 16) { audioVariables.K3++; } break; case 7: if (audioVariables.K4 >= -16) { audioVariables.K4--; } break; case 8: if (audioVariables.K4 < 16) { audioVariables.K4++; } break; case 9: if (audioVariables.K5 >= -16) { audioVariables.K5--; } break; case 10: if (audioVariables.K5 < 16) { audioVariables.K5++; } break; } } return (byte)num; } private uint OldDistN(int i) { return (uint)oldDist[i]; } private void SetOldDistN(int i, uint value) { oldDist[i] = (int)value; } public void Unpack5(bool Solid) { FileExtracted = true; if (!Suspended) { UnpInitData(Solid); if (!UnpReadBuf() || !ReadBlockHeader() || !ReadTables() || !TablesRead5) { return; } } while (true) { UnpPtr &= 4194303; if (Inp.InAddr >= ReadBorder) { bool flag = false; while (Inp.InAddr > BlockHeader.BlockStart + BlockHeader.BlockSize - 1 || (Inp.InAddr == BlockHeader.BlockStart + BlockHeader.BlockSize - 1 && Inp.InBit >= BlockHeader.BlockBitSize)) { if (BlockHeader.LastBlockInFile) { flag = true; break; } if (!ReadBlockHeader() || !ReadTables()) { return; } } if (flag || !UnpReadBuf()) { break; } } if ((long)((WriteBorder - UnpPtr) & 0x3FFFFF) < 4100L && WriteBorder != UnpPtr) { UnpWriteBuf(); if (WrittenFileSize > DestUnpSize) { return; } if (Suspended) { FileExtracted = false; return; } } uint num = this.DecodeNumber(LD); if (num < 256) { Window[UnpPtr++] = (byte)num; } else if (num >= 262) { uint num2 = SlotToLength(num - 262); uint num3 = 1u; uint num4 = this.DecodeNumber(DD); int num5; if (num4 < 4) { num5 = 0; num3 += num4; } else { num5 = (int)(num4 / 2 - 1); num3 += (2 | (num4 & 1)) << num5; } if (num5 > 0) { if (num5 >= 4) { if (num5 > 4) { num3 += Inp.getbits() >> 36 - num5 << 4; Inp.AddBits(num5 - 4); } uint num6 = this.DecodeNumber(LDD); num3 += num6; } else { num3 += Inp.getbits() >> 32 - num5; Inp.AddBits(num5); } } if (num3 > 256) { num2++; if (num3 > 8192) { num2++; if (num3 > 262144) { num2++; } } } InsertOldDist(num3); LastLength = num2; CopyString(num2, num3); } else if (num == 256) { UnpackFilter filter = new UnpackFilter(); if (!ReadFilter(filter) || !AddFilter(filter)) { break; } } else if (num == 257) { if (LastLength != 0) { CopyString(LastLength, OldDistN(0)); } } else if (num < 262) { int num7 = (int)(num - 258); uint num8 = OldDistN(num7); for (int num9 = num7; num9 > 0; num9--) { SetOldDistN(num9, OldDistN(num9 - 1)); } SetOldDistN(0, num8); uint slot = this.DecodeNumber(RD); uint length = (LastLength = SlotToLength(slot)); CopyString(length, num8); } } UnpWriteBuf(); } private uint ReadFilterData() { uint num = (Inp.fgetbits() >> 14) + 1; Inp.AddBits(2); uint num2 = 0u; for (int i = 0; i < num; i++) { num2 += Inp.fgetbits() >> 8 << i * 8; Inp.AddBits(8); } return num2; } private bool ReadFilter(UnpackFilter Filter) { if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 16 && !UnpReadBuf()) { return false; } Filter.uBlockStart = ReadFilterData(); Filter.uBlockLength = ReadFilterData(); if (Filter.BlockLength > 4194304) { Filter.BlockLength = 0; } Filter.Type = (byte)(Inp.fgetbits() >> 13); Inp.faddbits(3u); if (Filter.Type == 0) { Filter.Channels = (byte)((Inp.fgetbits() >> 11) + 1); Inp.faddbits(5u); } return true; } private bool AddFilter(UnpackFilter Filter) { if (Filters.Count >= 8192) { UnpWriteBuf(); if (Filters.Count >= 8192) { InitFilters(); } } Filter.NextWindow = WrPtr != UnpPtr && ((WrPtr - UnpPtr) & 0x3FFFFF) <= Filter.BlockStart; Filter.uBlockStart = (uint)((Filter.BlockStart + UnpPtr) & 0x3FFFFF); Filters.Add(Filter); return true; } private bool UnpReadBuf() { int num = ReadTop - Inp.InAddr; if (num < 0) { return false; } BlockHeader.BlockSize -= Inp.InAddr - BlockHeader.BlockStart; if (Inp.InAddr > 16384) { if (num > 0) { Array.Copy(base.InBuf, inAddr, base.InBuf, 0, num); } Inp.InAddr = 0; ReadTop = num; } else { num = ReadTop; } int num2 = 0; if (32768 != num) { num2 = readStream.Read(base.InBuf, num, 32768 - num); } if (num2 > 0) { ReadTop += num2; } ReadBorder = ReadTop - 30; BlockHeader.BlockStart = Inp.InAddr; if (BlockHeader.BlockSize != -1) { ReadBorder = Math.Min(ReadBorder, BlockHeader.BlockStart + BlockHeader.BlockSize - 1); } return num2 != -1; } private void UnpInitData50(bool Solid) { if (!Solid) { TablesRead5 = false; } } private bool ReadBlockHeader() { Header.HeaderSize = 0; if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 7 && !UnpReadBuf()) { return false; } Inp.faddbits((uint)((8 - Inp.InBit) & 7)); byte b = (byte)(Inp.fgetbits() >> 8); Inp.faddbits(8u); uint num = (uint)(((b >> 3) & 3) + 1); if (num == 4) { return false; } Header.HeaderSize = (int)(2 + num); Header.BlockBitSize = (b & 7) + 1; byte b2 = (byte)(Inp.fgetbits() >> 8); Inp.faddbits(8u); int num2 = 0; for (int i = 0; i < num; i++) { num2 += (int)(Inp.fgetbits() >> 8 << i * 8); Inp.AddBits(8); } Header.BlockSize = num2; if ((byte)(0x5A ^ b ^ num2 ^ (num2 >> 8) ^ (num2 >> 16)) != b2) { return false; } Header.BlockStart = Inp.InAddr; ReadBorder = Math.Min(ReadBorder, Header.BlockStart + Header.BlockSize - 1); Header.LastBlockInFile = (b & 0x40) != 0; Header.TablePresent = (b & 0x80) != 0; return true; } private uint SlotToLength(uint Slot) { uint num = 2u; int num2; if (Slot < 8) { num2 = 0; num += Slot; } else { num2 = (int)(Slot / 4 - 1); num += (4 | (Slot & 3)) << num2; } if (num2 > 0) { num += getbits() >> 16 - num2; AddBits(num2); } return num; } } internal class UnpackFilter { public byte Type; public byte Channels; internal uint uBlockStart { get { return (uint)BlockStart; } set { BlockStart = (int)value; } } internal uint uBlockLength { get { return (uint)BlockLength; } set { BlockLength = (int)value; } } internal int BlockStart { get; set; } internal int BlockLength { get; set; } internal int ExecCount { get; set; } internal bool NextWindow { get; set; } internal int ParentFilter { get; set; } internal VMPreparedProgram Program { get; set; } internal UnpackFilter() { Program = new VMPreparedProgram(); } } internal static class UnpackUtility { internal static uint DecodeNumber(this SharpCompress.Compressors.Rar.VM.BitInput input, SharpCompress.Compressors.Rar.UnpackV1.Decode.Decode dec) { return (uint)input.decodeNumber(dec); } internal static int decodeNumber(this SharpCompress.Compressors.Rar.VM.BitInput input, SharpCompress.Compressors.Rar.UnpackV1.Decode.Decode dec) { long num = input.GetBits() & 0xFFFE; int[] decodeLen = dec.DecodeLen; int num2 = ((num < decodeLen[8]) ? ((num < decodeLen[4]) ? ((num < decodeLen[2]) ? ((num < decodeLen[1]) ? 1 : 2) : ((num >= decodeLen[3]) ? 4 : 3)) : ((num < decodeLen[6]) ? ((num >= decodeLen[5]) ? 6 : 5) : ((num >= decodeLen[7]) ? 8 : 7))) : ((num < decodeLen[12]) ? ((num < decodeLen[10]) ? ((num >= decodeLen[9]) ? 10 : 9) : ((num >= decodeLen[11]) ? 12 : 11)) : ((num >= decodeLen[14]) ? 15 : ((num >= decodeLen[13]) ? 14 : 13)))); input.AddBits(num2); int num3 = dec.DecodePos[num2] + Utility.URShift((int)num - decodeLen[num2 - 1], 16 - num2); if (num3 >= dec.MaxNum) { num3 = 0; } return dec.DecodeNum[num3]; } internal static void makeDecodeTables(byte[] lenTab, int offset, SharpCompress.Compressors.Rar.UnpackV1.Decode.Decode dec, int size) { int[] array = new int[16]; int[] array2 = new int[16]; Utility.Fill(array, 0); Utility.Fill(dec.DecodeNum, 0); for (int i = 0; i < size; i++) { array[lenTab[offset + i] & 0xF]++; } array[0] = 0; array2[0] = 0; dec.DecodePos[0] = 0; dec.DecodeLen[0] = 0; long num = 0L; for (int i = 1; i < 16; i++) { num = 2 * (num + array[i]); long num2 = num << 15 - i; if (num2 > 65535) { num2 = 65535L; } dec.DecodeLen[i] = (int)num2; array2[i] = (dec.DecodePos[i] = dec.DecodePos[i - 1] + array[i - 1]); } for (int i = 0; i < size; i++) { if (lenTab[offset + i] != 0) { dec.DecodeNum[array2[lenTab[offset + i] & 0xF]++] = i; } } dec.MaxNum = size; } } } namespace SharpCompress.Compressors.Rar.UnpackV1.PPM { internal enum BlockTypes { BLOCK_LZ, BLOCK_PPM } } namespace SharpCompress.Compressors.Rar.UnpackV1.Decode { internal class AudioVariables { internal int[] Dif { get; } internal int ByteCount { get; set; } internal int D1 { get; set; } internal int D2 { get; set; } internal int D3 { get; set; } internal int D4 { get; set; } internal int K1 { get; set; } internal int K2 { get; set; } internal int K3 { get; set; } internal int K4 { get; set; } internal int K5 { get; set; } internal int LastChar { get; set; } internal int LastDelta { get; set; } internal AudioVariables() { Dif = new int[11]; } } internal class BitDecode : Decode { internal BitDecode() : base(new int[20]) { } } internal enum CodeType { CODE_HUFFMAN, CODE_LZ, CODE_LZ2, CODE_REPEATLZ, CODE_CACHELZ, CODE_STARTFILE, CODE_ENDFILE, CODE_VM, CODE_VMDATA } internal class Decode { internal int[] DecodeLen { get; } internal int[] DecodeNum { get; } internal int[] DecodePos { get; } internal int MaxNum { get; set; } internal Decode() : this(new int[2]) { } protected Decode(int[] customDecodeNum) { DecodeLen = new int[16]; DecodePos = new int[16]; DecodeNum = customDecodeNum; } } internal class DistDecode : Decode { internal DistDecode() : base(new int[60]) { } } internal enum FilterType : byte { FILTER_DELTA, FILTER_E8, FILTER_E8E9, FILTER_ARM, FILTER_AUDIO, FILTER_RGB, FILTER_ITANIUM, FILTER_PPM, FILTER_NONE } internal class LitDecode : Decode { internal LitDecode() : base(new int[299]) { } } internal class LowDistDecode : Decode { internal LowDistDecode() : base(new int[17]) { } } internal class MultDecode : Decode { internal MultDecode() : base(new int[257]) { } } internal static class PackDef { public const int MAXWINSIZE = 4194304; public const int MAXWINMASK = 4194303; public const uint MAX_LZ_MATCH = 4097u; public const uint MAX3_LZ_MATCH = 257u; public const int LOW_DIST_REP_COUNT = 16; public const int NC = 299; public const int DC = 60; public const int LDC = 17; public const int RC = 28; public const int HUFF_TABLE_SIZE = 404; public const int BC = 20; public const uint NC30 = 299u; public const uint DC30 = 60u; public const uint LDC30 = 17u; public const uint RC30 = 28u; public const uint BC30 = 20u; public const uint HUFF_TABLE_SIZE30 = 404u; public const int NC20 = 298; public const int DC20 = 48; public const int RC20 = 28; public const int BC20 = 19; public const int MC20 = 257; public const uint LARGEST_TABLE_SIZE = 306u; } internal class RepDecode : Decode { internal RepDecode() : base(new int[28]) { } } } namespace SharpCompress.Compressors.PPMd { public class PpmdProperties { private int _allocatorSize; internal Allocator _allocator; public int ModelOrder { get; } public PpmdVersion Version { get; } = PpmdVersion.I1; internal ModelRestorationMethod RestorationMethod { get; } public int AllocatorSize { get { return _allocatorSize; } set { _allocatorSize = value; if (Version == PpmdVersion.I1) { if (_allocator == null) { _allocator = new Allocator(); } _allocator.Start(_allocatorSize); } } } public byte[] Properties => DataConverter.LittleEndian.GetBytes((ushort)(ModelOrder - 1 + ((AllocatorSize >> 20) - 1 << 4) + ((ushort)RestorationMethod << 12))); public PpmdProperties() : this(16777216, 6) { } public PpmdProperties(int allocatorSize, int modelOrder) : this(allocatorSize, modelOrder, ModelRestorationMethod.Restart) { } internal PpmdProperties(int allocatorSize, int modelOrder, ModelRestorationMethod modelRestorationMethod) { AllocatorSize = allocatorSize; ModelOrder = modelOrder; RestorationMethod = modelRestorationMethod; } public PpmdProperties(byte[] properties) { if (properties.Length == 2) { ushort uInt = DataConverter.LittleEndian.GetUInt16(properties, 0); AllocatorSize = ((uInt >> 4) & 0xFF) + 1 << 20; ModelOrder = (uInt & 0xF) + 1; RestorationMethod = (ModelRestorationMethod)(uInt >> 12); } else if (properties.Length == 5) { Version = PpmdVersion.H7Z; AllocatorSize = DataConverter.LittleEndian.GetInt32(properties, 1); ModelOrder = properties[0]; } } } public class PpmdStream : Stream { private readonly PpmdProperties _properties; private readonly Stream _stream; private readonly bool _compress; private readonly Model _model; private readonly ModelPpm _modelH; private readonly SharpCompress.Compressors.LZMA.RangeCoder.Decoder _decoder; private long _position; private bool _isDisposed; public override bool CanRead => !_compress; public override bool CanSeek => false; public override bool CanWrite => _compress; public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { return _position; } set { throw new NotSupportedException(); } } public PpmdStream(PpmdProperties properties, Stream stream, bool compress) { _properties = properties; _stream = stream; _compress = compress; if (properties.Version == PpmdVersion.I1) { _model = new Model(); if (compress) { _model.EncodeStart(properties); } else { _model.DecodeStart(stream, properties); } } if (properties.Version == PpmdVersion.H) { _modelH = new ModelPpm(); if (compress) { throw new NotImplementedException(); } _modelH.DecodeInit(stream, properties.ModelOrder, properties.AllocatorSize); } if (properties.Version == PpmdVersion.H7Z) { _modelH = new ModelPpm(); if (compress) { throw new NotImplementedException(); } _modelH.DecodeInit(null, properties.ModelOrder, properties.AllocatorSize); _decoder = new SharpCompress.Compressors.LZMA.RangeCoder.Decoder(); _decoder.Init(stream); } } public override void Flush() { } protected override void Dispose(bool isDisposing) { if (!_isDisposed) { _isDisposed = true; if (isDisposing && _compress) { _model.EncodeBlock(_stream, new MemoryStream(), final: true); } base.Dispose(isDisposing); } } public override int Read(byte[] buffer, int offset, int count) { if (_compress) { return 0; } int i = 0; if (_properties.Version == PpmdVersion.I1) { i = _model.DecodeBlock(_stream, buffer, offset, count); } if (_properties.Version == PpmdVersion.H) { for (; i < count; i++) { int num; if ((num = _modelH.DecodeChar()) < 0) { break; } buffer[offset++] = (byte)num; } } if (_properties.Version == PpmdVersion.H7Z) { for (; i < count; i++) { int num2; if ((num2 = _modelH.DecodeChar(_decoder)) < 0) { break; } buffer[offset++] = (byte)num2; } } _position += i; return i; } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { if (_compress) { _model.EncodeBlock(_stream, new MemoryStream(buffer, offset, count), final: false); } } } public enum PpmdVersion { H, H7Z, I1 } } namespace SharpCompress.Compressors.PPMd.I1 { internal class Allocator { private const uint UNIT_SIZE = 12u; private const uint LOCAL_OFFSET = 4u; private const uint NODE_OFFSET = 16u; private const uint HEAP_OFFSET = 472u; private const uint N1 = 4u; private const uint N2 = 4u; private const uint N3 = 4u; private const uint N4 = 26u; private const uint INDEX_COUNT = 38u; private static readonly byte[] INDEX_TO_UNITS; private static readonly byte[] UNITS_TO_INDEX; public uint _allocatorSize; public uint _glueCount; public Pointer _baseUnit; public Pointer _lowUnit; public Pointer _highUnit; public Pointer _text; public Pointer _heap; public MemoryNode[] _memoryNodes; public byte[] _memory; static Allocator() { INDEX_TO_UNITS = new byte[38]; uint num = 0u; uint num2 = 1u; while (num < 4) { INDEX_TO_UNITS[num] = (byte)num2; num++; num2++; } num2++; while (num < 8) { INDEX_TO_UNITS[num] = (byte)num2; num++; num2 += 2; } num2++; while (num < 12) { INDEX_TO_UNITS[num] = (byte)num2; num++; num2 += 3; } num2++; while (num < 38) { INDEX_TO_UNITS[num] = (byte)num2; num++; num2 += 4; } UNITS_TO_INDEX = new byte[128]; for (num2 = (num = 0u); num2 < 128; num2++) { num += (uint)((INDEX_TO_UNITS[num] < num2 + 1) ? 1 : 0); UNITS_TO_INDEX[num2] = (byte)num; } } public Allocator() { _memoryNodes = new MemoryNode[38]; } public void Initialize() { for (int i = 0; (long)i < 38L; i++) { _memoryNodes[i] = new MemoryNode((uint)(16uL + (ulong)(i * 12)), _memory); _memoryNodes[i].Stamp = 0u; _memoryNodes[i].Next = MemoryNode.ZERO; _memoryNodes[i].UnitCount = 0u; } _text = _heap; uint num = 12 * (_allocatorSize / 8 / 12 * 7); _highUnit = _heap + _allocatorSize; _lowUnit = _highUnit - num; _baseUnit = _highUnit - num; _glueCount = 0u; } public void Start(int allocatorSize) { if (_allocatorSize != (uint)allocatorSize) { Stop(); _memory = new byte[472 + allocatorSize]; _heap = new Pointer(472u, _memory); _allocatorSize = (uint)allocatorSize; } } public void Stop() { if (_allocatorSize != 0) { _allocatorSize = 0u; _memory = null; _heap = Pointer.ZERO; } } public uint GetMemoryUsed() { uint num = _allocatorSize - (_highUnit - _lowUnit) - (_baseUnit - _text); for (uint num2 = 0u; num2 < 38; num2++) { num -= (uint)(12 * INDEX_TO_UNITS[num2] * (int)_memoryNodes[num2].Stamp); } return num; } public Pointer AllocateUnits(uint unitCount) { uint num = UNITS_TO_INDEX[unitCount - 1]; if (_memoryNodes[num].Available) { return _memoryNodes[num].Remove(); } Pointer lowUnit = _lowUnit; _lowUnit += (uint)(INDEX_TO_UNITS[num] * 12); if (_lowUnit <= _highUnit) { return lowUnit; } _lowUnit -= (uint)(INDEX_TO_UNITS[num] * 12); return AllocateUnitsRare(num); } public Pointer AllocateContext() { if (_highUnit != _lowUnit) { return _highUnit -= 12u; } if (_memoryNodes[0].Available) { return _memoryNodes[0].Remove(); } return AllocateUnitsRare(0u); } public Pointer ExpandUnits(Pointer oldPointer, uint oldUnitCount) { uint num = UNITS_TO_INDEX[oldUnitCount - 1]; uint num2 = UNITS_TO_INDEX[oldUnitCount]; if (num == num2) { return oldPointer; } Pointer pointer = AllocateUnits(oldUnitCount + 1); if (pointer != Pointer.ZERO) { CopyUnits(pointer, oldPointer, oldUnitCount); _memoryNodes[num].Insert(oldPointer, oldUnitCount); } return pointer; } public Pointer ShrinkUnits(Pointer oldPointer, uint oldUnitCount, uint newUnitCount) { uint num = UNITS_TO_INDEX[oldUnitCount - 1]; uint num2 = UNITS_TO_INDEX[newUnitCount - 1]; if (num == num2) { return oldPointer; } if (_memoryNodes[num2].Available) { Pointer pointer = _memoryNodes[num2].Remove(); CopyUnits(pointer, oldPointer, newUnitCount); _memoryNodes[num].Insert(oldPointer, INDEX_TO_UNITS[num]); return pointer; } SplitBlock(oldPointer, num, num2); return oldPointer; } public void FreeUnits(Pointer pointer, uint unitCount) { uint num = UNITS_TO_INDEX[unitCount - 1]; _memoryNodes[num].Insert(pointer, INDEX_TO_UNITS[num]); } public void SpecialFreeUnits(Pointer pointer) { if (pointer != _baseUnit) { _memoryNodes[0].Insert(pointer, 1u); return; } MemoryNode memoryNode = pointer; memoryNode.Stamp = uint.MaxValue; _baseUnit += 12u; } public Pointer MoveUnitsUp(Pointer oldPointer, uint unitCount) { uint num = UNITS_TO_INDEX[unitCount - 1]; if (oldPointer > _baseUnit + 16384 || oldPointer > _memoryNodes[num].Next) { return oldPointer; } Pointer pointer = _memoryNodes[num].Remove(); CopyUnits(pointer, oldPointer, unitCount); unitCount = INDEX_TO_UNITS[num]; if (oldPointer != _baseUnit) { _memoryNodes[num].Insert(oldPointer, unitCount); } else { _baseUnit += unitCount * 12; } return pointer; } public void ExpandText() { uint[] array = new uint[38]; while (true) { MemoryNode memoryNode2; MemoryNode memoryNode = (memoryNode2 = _baseUnit); if (memoryNode.Stamp != uint.MaxValue) { break; } _baseUnit = memoryNode2 + memoryNode2.UnitCount; array[UNITS_TO_INDEX[memoryNode2.UnitCount - 1]]++; memoryNode2.Stamp = 0u; } for (uint num = 0u; num < 38; num++) { MemoryNode memoryNode2 = _memoryNodes[num]; while (array[num] != 0) { while (memoryNode2.Next.Stamp == 0) { memoryNode2.Unlink(); _memoryNodes[num].Stamp--; if (--array[num] == 0) { break; } } memoryNode2 = memoryNode2.Next; } } } private Pointer AllocateUnitsRare(uint index) { if (_glueCount == 0) { GlueFreeBlocks(); if (_memoryNodes[index].Available) { return _memoryNodes[index].Remove(); } } uint num = index; do { if (++num == 38) { _glueCount--; num = (uint)(INDEX_TO_UNITS[index] * 12); if (_baseUnit - _text <= num) { return Pointer.ZERO; } return _baseUnit -= num; } } while (!_memoryNodes[num].Available); Pointer pointer = _memoryNodes[num].Remove(); SplitBlock(pointer, num, index); return pointer; } private void SplitBlock(Pointer pointer, uint oldIndex, uint newIndex) { uint num = (uint)(INDEX_TO_UNITS[oldIndex] - INDEX_TO_UNITS[newIndex]); Pointer pointer2 = pointer + (uint)(INDEX_TO_UNITS[newIndex] * 12); uint num2 = UNITS_TO_INDEX[num - 1]; if (INDEX_TO_UNITS[num2] != num) { uint num3 = INDEX_TO_UNITS[--num2]; _memoryNodes[num2].Insert(pointer2, num3); pointer2 += num3 * 12; num -= num3; } _memoryNodes[UNITS_TO_INDEX[num - 1]].Insert(pointer2, num); } private void GlueFreeBlocks() { MemoryNode memoryNode = new MemoryNode(4u, _memory); memoryNode.Stamp = 0u; memoryNode.Next = MemoryNode.ZERO; memoryNode.UnitCount = 0u; if (_lowUnit != _highUnit) { _lowUnit[0] = 0; } MemoryNode memoryNode2 = memoryNode; for (uint num = 0u; num < 38; num++) { while (_memoryNodes[num].Available) { MemoryNode memoryNode3 = _memoryNodes[num].Remove(); if (memoryNode3.UnitCount == 0) { continue; } while (true) { MemoryNode memoryNode5; MemoryNode memoryNode4 = (memoryNode5 = memoryNode3 + memoryNode3.UnitCount); if (memoryNode4.Stamp != uint.MaxValue) { break; } memoryNode3.UnitCount += memoryNode5.UnitCount; memoryNode5.UnitCount = 0u; } memoryNode2.Link(memoryNode3); memoryNode2 = memoryNode3; } } while (memoryNode.Available) { MemoryNode memoryNode3 = memoryNode.Remove(); uint num2 = memoryNode3.UnitCount; if (num2 != 0) { while (num2 > 128) { _memoryNodes[37].Insert(memoryNode3, 128u); num2 -= 128; memoryNode3 += 128; } uint num3 = UNITS_TO_INDEX[num2 - 1]; if (INDEX_TO_UNITS[num3] != num2) { uint num4 = num2 - INDEX_TO_UNITS[--num3]; _memoryNodes[num4 - 1].Insert(memoryNode3 + (num2 - num4), num4); } _memoryNodes[num3].Insert(memoryNode3, INDEX_TO_UNITS[num3]); } } _glueCount = 8192u; } private void CopyUnits(Pointer target, Pointer source, uint unitCount) { do { target[0] = source[0]; target[1] = source[1]; target[2] = source[2]; target[3] = source[3]; target[4] = source[4]; target[5] = source[5]; target[6] = source[6]; target[7] = source[7]; target[8] = source[8]; target[9] = source[9]; target[10] = source[10]; target[11] = source[11]; target += 12u; source += 12u; } while (--unitCount != 0); } } internal class Coder { private const uint RANGE_TOP = 16777216u; private const uint RANGE_BOTTOM = 32768u; private uint _low; private uint _code; private uint _range; public uint _lowCount; public uint _highCount; public uint _scale; public void RangeEncoderInitialize() { _low = 0u; _range = uint.MaxValue; } public void RangeEncoderNormalize(Stream stream) { while (true) { if ((_low ^ (_low + _range)) >= 16777216) { if (_range >= 32768) { break; } if ((_range = (uint)((int)(0L - (long)_low) & 0x7FFF)) != 0) { } } stream.WriteByte((byte)(_low >> 24)); _range <<= 8; _low <<= 8; } } public void RangeEncodeSymbol() { _low += _lowCount * (_range /= _scale); _range *= _highCount - _lowCount; } public void RangeShiftEncodeSymbol(int rangeShift) { _low += _lowCount * (_range >>= rangeShift); _range *= _highCount - _lowCount; } public void RangeEncoderFlush(Stream stream) { for (uint num = 0u; num < 4; num++) { stream.WriteByte((byte)(_low >> 24)); _low <<= 8; } } public void RangeDecoderInitialize(Stream stream) { _low = 0u; _code = 0u; _range = uint.MaxValue; for (uint num = 0u; num < 4; num++) { _code = (_code << 8) | (byte)stream.ReadByte(); } } public void RangeDecoderNormalize(Stream stream) { while (true) { if ((_low ^ (_low + _range)) >= 16777216) { if (_range >= 32768) { break; } if ((_range = (uint)((int)(0L - (long)_low) & 0x7FFF)) != 0) { } } _code = (_code << 8) | (byte)stream.ReadByte(); _range <<= 8; _low <<= 8; } } public uint RangeGetCurrentCount() { return (_code - _low) / (_range /= _scale); } public uint RangeGetCurrentShiftCount(int rangeShift) { return (_code - _low) / (_range >>= rangeShift); } public void RangeRemoveSubrange() { _low += _range * _lowCount; _range *= _highCount - _lowCount; } } internal struct MemoryNode { public uint _address; public byte[] _memory; public static readonly MemoryNode ZERO = new MemoryNode(0u, null); public const int SIZE = 12; public uint Stamp { get { return (uint)(_memory[_address] | (_memory[_address + 1] << 8) | (_memory[_address + 2] << 16) | (_memory[_address + 3] << 24)); } set { _memory[_address] = (byte)value; _memory[_address + 1] = (byte)(value >> 8); _memory[_address + 2] = (byte)(value >> 16); _memory[_address + 3] = (byte)(value >> 24); } } public MemoryNode Next { get { return new MemoryNode((uint)(_memory[_address + 4] | (_memory[_address + 5] << 8) | (_memory[_address + 6] << 16) | (_memory[_address + 7] << 24)), _memory); } set { _memory[_address + 4] = (byte)value._address; _memory[_address + 5] = (byte)(value._address >> 8); _memory[_address + 6] = (byte)(value._address >> 16); _memory[_address + 7] = (byte)(value._address >> 24); } } public uint UnitCount { get { return (uint)(_memory[_address + 8] | (_memory[_address + 9] << 8) | (_memory[_address + 10] << 16) | (_memory[_address + 11] << 24)); } set { _memory[_address + 8] = (byte)value; _memory[_address + 9] = (byte)(value >> 8); _memory[_address + 10] = (byte)(value >> 16); _memory[_address + 11] = (byte)(value >> 24); } } public bool Available => Next._address != 0; public MemoryNode(uint address, byte[] memory) { _address = address; _memory = memory; } public void Link(MemoryNode memoryNode) { memoryNode.Next = Next; Next = memoryNode; } public void Unlink() { Next = Next.Next; } public void Insert(MemoryNode memoryNode, uint unitCount) { Link(memoryNode); memoryNode.Stamp = uint.MaxValue; memoryNode.UnitCount = unitCount; Stamp++; } public MemoryNode Remove() { MemoryNode next = Next; Unlink(); Stamp--; return next; } public static implicit operator MemoryNode(Pointer pointer) { return new MemoryNode(pointer._address, pointer._memory); } public static MemoryNode operator +(MemoryNode memoryNode, int offset) { memoryNode._address = (uint)(memoryNode._address + offset * 12); return memoryNode; } public static MemoryNode operator +(MemoryNode memoryNode, uint offset) { memoryNode._address += offset * 12; return memoryNode; } public static MemoryNode operator -(MemoryNode memoryNode, int offset) { memoryNode._address = (uint)(memoryNode._address - offset * 12); return memoryNode; } public static MemoryNode operator -(MemoryNode memoryNode, uint offset) { memoryNode._address -= offset * 12; return memoryNode; } public static bool operator ==(MemoryNode memoryNode1, MemoryNode memoryNode2) { return memoryNode1._address == memoryNode2._address; } public static bool operator !=(MemoryNode memoryNode1, MemoryNode memoryNode2) { return memoryNode1._address != memoryNode2._address; } public override bool Equals(object obj) { if (obj is MemoryNode) { return ((MemoryNode)obj)._address == _address; } return base.Equals(obj); } public override int GetHashCode() { return _address.GetHashCode(); } } internal class Model { internal struct PpmContext { public uint _address; public byte[] _memory; public static readonly PpmContext ZERO = new PpmContext(0u, null); public const int SIZE = 12; public byte NumberStatistics { get { return _memory[_address]; } set { _memory[_address] = value; } } public byte Flags { get { return _memory[_address + 1]; } set { _memory[_address + 1] = value; } } public ushort SummaryFrequency { get { return (ushort)(_memory[_address + 2] | (_memory[_address + 3] << 8)); } set { _memory[_address + 2] = (byte)value; _memory[_address + 3] = (byte)(value >> 8); } } public PpmState Statistics { get { return new PpmState((uint)(_memory[_address + 4] | (_memory[_address + 5] << 8) | (_memory[_address + 6] << 16) | (_memory[_address + 7] << 24)), _memory); } set { _memory[_address + 4] = (byte)value._address; _memory[_address + 5] = (byte)(value._address >> 8); _memory[_address + 6] = (byte)(value._address >> 16); _memory[_address + 7] = (byte)(value._address >> 24); } } public PpmContext Suffix { get { return new PpmContext((uint)(_memory[_address + 8] | (_memory[_address + 9] << 8) | (_memory[_address + 10] << 16) | (_memory[_address + 11] << 24)), _memory); } set { _memory[_address + 8] = (byte)value._address; _memory[_address + 9] = (byte)(value._address >> 8); _memory[_address + 10] = (byte)(value._address >> 16); _memory[_address + 11] = (byte)(value._address >> 24); } } public PpmState FirstState => new PpmState(_address + 2, _memory); public byte FirstStateSymbol { get { return _memory[_address + 2]; } set { _memory[_address + 2] = value; } } public byte FirstStateFrequency { get { return _memory[_address + 3]; } set { _memory[_address + 3] = value; } } public PpmContext FirstStateSuccessor { get { return new PpmContext((uint)(_memory[_address + 4] | (_memory[_address + 5] << 8) | (_memory[_address + 6] << 16) | (_memory[_address + 7] << 24)), _memory); } set { _memory[_address + 4] = (byte)value._address; _memory[_address + 5] = (byte)(value._address >> 8); _memory[_address + 6] = (byte)(value._address >> 16); _memory[_address + 7] = (byte)(value._address >> 24); } } public PpmContext(uint address, byte[] memory) { _address = address; _memory = memory; } public static implicit operator PpmContext(Pointer pointer) { return new PpmContext(pointer._address, pointer._memory); } public static PpmContext operator +(PpmContext context, int offset) { context._address = (uint)(context._address + offset * 12); return context; } public static PpmContext operator -(PpmContext context, int offset) { context._address = (uint)(context._address - offset * 12); return context; } public static bool operator <=(PpmContext context1, PpmContext context2) { return context1._address <= context2._address; } public static bool operator >=(PpmContext context1, PpmContext context2) { return context1._address >= context2._address; } public static bool operator ==(PpmContext context1, PpmContext context2) { return context1._address == context2._address; } public static bool operator !=(PpmContext context1, PpmContext context2) { return context1._address != context2._address; } public override bool Equals(object obj) { if (obj is PpmContext) { return ((PpmContext)obj)._address == _address; } return base.Equals(obj); } public override int GetHashCode() { return _address.GetHashCode(); } } public const uint SIGNATURE = 2225909647u; public const char VARIANT = 'I'; public const int MAXIMUM_ORDER = 16; private const byte UPPER_FREQUENCY = 5; private const byte INTERVAL_BIT_COUNT = 7; private const byte PERIOD_BIT_COUNT = 7; private const byte TOTAL_BIT_COUNT = 14; private const uint INTERVAL = 128u; private const uint BINARY_SCALE = 16384u; private const uint MAXIMUM_FREQUENCY = 124u; private const uint ORDER_BOUND = 9u; private readonly See2Context[,] _see2Contexts; private readonly See2Context _emptySee2Context; private PpmContext _maximumContext; private readonly ushort[,] _binarySummary = new ushort[25, 64]; private readonly byte[] _numberStatisticsToBinarySummaryIndex = new byte[256]; private readonly byte[] _probabilities = new byte[260]; private readonly byte[] _characterMask = new byte[256]; private byte _escapeCount; private int _modelOrder; private int _orderFall; private int _initialEscape; private int _initialRunLength; private int _runLength; private byte _previousSuccess; private byte _numberMasked; private ModelRestorationMethod _method; private PpmState _foundState; private Allocator _allocator; private Coder _coder; private PpmContext _minimumContext; private byte _numberStatistics; private readonly PpmState[] _decodeStates = new PpmState[256]; private static readonly ushort[] INITIAL_BINARY_ESCAPES = new ushort[8] { 15581, 7999, 22975, 18675, 25761, 23228, 26162, 24657 }; private static readonly byte[] EXPONENTIAL_ESCAPES = new byte[16] { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; public Model() { _numberStatisticsToBinarySummaryIndex[0] = 0; _numberStatisticsToBinarySummaryIndex[1] = 2; for (int i = 2; i < 11; i++) { _numberStatisticsToBinarySummaryIndex[i] = 4; } for (int j = 11; j < 256; j++) { _numberStatisticsToBinarySummaryIndex[j] = 6; } uint num = 1u; uint num2 = 1u; uint num3 = 5u; for (int k = 0; k < 5; k++) { _probabilities[k] = (byte)k; } for (int l = 5; l < 260; l++) { _probabilities[l] = (byte)num3; num--; if (num == 0) { num2++; num = num2; num3++; } } _see2Contexts = new See2Context[24, 32]; for (int m = 0; m < 24; m++) { for (int n = 0; n < 32; n++) { _see2Contexts[m, n] = new See2Context(); } } _emptySee2Context = new See2Context(); _emptySee2Context._summary = 44943; _emptySee2Context._shift = 172; _emptySee2Context._count = 132; } public void Encode(Stream target, Stream source, PpmdProperties properties) { if (target == null) { throw new ArgumentNullException("target"); } if (source == null) { throw new ArgumentNullException("source"); } EncodeStart(properties); EncodeBlock(target, source, final: true); } internal Coder EncodeStart(PpmdProperties properties) { _allocator = properties._allocator; _coder = new Coder(); _coder.RangeEncoderInitialize(); StartModel(properties.ModelOrder, properties.RestorationMethod); return _coder; } internal void EncodeBlock(Stream target, Stream source, bool final) { while (true) { _minimumContext = _maximumContext; _numberStatistics = _minimumContext.NumberStatistics; int num = source.ReadByte(); if (num < 0 && !final) { break; } if (_numberStatistics != 0) { EncodeSymbol1(num, _minimumContext); _coder.RangeEncodeSymbol(); } else { EncodeBinarySymbol(num, _minimumContext); _coder.RangeShiftEncodeSymbol(14); } while (_foundState == PpmState.ZERO) { _coder.RangeEncoderNormalize(target); do { _orderFall++; _minimumContext = _minimumContext.Suffix; if (_minimumContext == PpmContext.ZERO) { _coder.RangeEncoderFlush(target); return; } } while (_minimumContext.NumberStatistics == _numberMasked); EncodeSymbol2(num, _minimumContext); _coder.RangeEncodeSymbol(); } if (_orderFall == 0 && (Pointer)_foundState.Successor >= _allocator._baseUnit) { _maximumContext = _foundState.Successor; } else { UpdateModel(_minimumContext); if (_escapeCount == 0) { ClearMask(); } } _coder.RangeEncoderNormalize(target); } } public void Decode(Stream target, Stream source, PpmdProperties properties) { if (target == null) { throw new ArgumentNullException("target"); } if (source == null) { throw new ArgumentNullException("source"); } DecodeStart(source, properties); byte[] array = new byte[65536]; int count; while ((count = DecodeBlock(source, array, 0, array.Length)) != 0) { target.Write(array, 0, count); } } internal Coder DecodeStart(Stream source, PpmdProperties properties) { _allocator = properties._allocator; _coder = new Coder(); _coder.RangeDecoderInitialize(source); StartModel(properties.ModelOrder, properties.RestorationMethod); _minimumContext = _maximumContext; _numberStatistics = _minimumContext.NumberStatistics; return _coder; } internal int DecodeBlock(Stream source, byte[] buffer, int offset, int count) { if (_minimumContext == PpmContext.ZERO) { return 0; } int num = 0; while (num < count) { if (_numberStatistics != 0) { DecodeSymbol1(_minimumContext); } else { DecodeBinarySymbol(_minimumContext); } _coder.RangeRemoveSubrange(); for (; _foundState == PpmState.ZERO; DecodeSymbol2(_minimumContext), _coder.RangeRemoveSubrange()) { _coder.RangeDecoderNormalize(source); while (true) { _orderFall++; _minimumContext = _minimumContext.Suffix; if (_minimumContext == PpmContext.ZERO) { break; } if (_minimumContext.NumberStatistics == _numberMasked) { continue; } goto IL_009d; } goto end_IL_015d; IL_009d:; } buffer[offset] = _foundState.Symbol; offset++; num++; if (_orderFall == 0 && (Pointer)_foundState.Successor >= _allocator._baseUnit) { _maximumContext = _foundState.Successor; } else { UpdateModel(_minimumContext); if (_escapeCount == 0) { ClearMask(); } } _minimumContext = _maximumContext; _numberStatistics = _minimumContext.NumberStatistics; _coder.RangeDecoderNormalize(source); continue; end_IL_015d: break; } return num; } private void StartModel(int modelOrder, ModelRestorationMethod modelRestorationMethod) { Array.Clear(_characterMask, 0, _characterMask.Length); _escapeCount = 1; if (modelOrder < 2) { _orderFall = _modelOrder; PpmContext ppmContext = _maximumContext; while (ppmContext.Suffix != PpmContext.ZERO) { _orderFall--; ppmContext = ppmContext.Suffix; } return; } _modelOrder = modelOrder; _orderFall = modelOrder; _method = modelRestorationMethod; _allocator.Initialize(); _initialRunLength = -((modelOrder < 12) ? modelOrder : 12) - 1; _runLength = _initialRunLength; _maximumContext = _allocator.AllocateContext(); _maximumContext.Suffix = PpmContext.ZERO; _maximumContext.NumberStatistics = byte.MaxValue; _maximumContext.SummaryFrequency = (ushort)(_maximumContext.NumberStatistics + 2); _maximumContext.Statistics = _allocator.AllocateUnits(128u); _previousSuccess = 0; for (int i = 0; i < 256; i++) { PpmState ppmState = _maximumContext.Statistics[i]; ppmState.Symbol = (byte)i; ppmState.Frequency = 1; ppmState.Successor = PpmContext.ZERO; } uint num = 0u; int j = 0; for (; num < 25; num++) { for (; _probabilities[j] == num; j++) { } for (int k = 0; k < 8; k++) { _binarySummary[num, k] = (ushort)(16384uL - (ulong)(INITIAL_BINARY_ESCAPES[k] / (j + 1))); } for (int l = 8; l < 64; l += 8) { for (int m = 0; m < 8; m++) { _binarySummary[num, l + m] = _binarySummary[num, m]; } } } num = 0u; uint num2 = 0u; for (; num < 24; num++) { for (; _probabilities[num2 + 3] == num + 3; num2++) { } for (int n = 0; n < 32; n++) { _see2Contexts[num, n].Initialize(2 * num2 + 5); } } } private void UpdateModel(PpmContext minimumContext) { PpmState state = PpmState.ZERO; PpmContext ppmContext = _maximumContext; uint frequency = _foundState.Frequency; byte symbol = _foundState.Symbol; PpmContext ppmContext2 = _foundState.Successor; PpmContext suffix = minimumContext.Suffix; if (frequency < 31 && suffix != PpmContext.ZERO) { if (suffix.NumberStatistics != 0) { state = suffix.Statistics; if (state.Symbol != symbol) { byte symbol2; do { symbol2 = state[1].Symbol; ++state; } while (symbol2 != symbol); if (state[0].Frequency >= state[-1].Frequency) { Swap(state[0], state[-1]); --state; } } uint num = (((uint)state.Frequency < 115u) ? 2u : 0u); state.Frequency += (byte)num; suffix.SummaryFrequency += (byte)num; } else { state = suffix.FirstState; state.Frequency += ((state.Frequency < 32) ? ((byte)1) : ((byte)0)); } } if (_orderFall == 0 && ppmContext2 != PpmContext.ZERO) { _foundState.Successor = CreateSuccessors(skip: true, state, minimumContext); if (!(_foundState.Successor == PpmContext.ZERO)) { _maximumContext = _foundState.Successor; return; } } else { _allocator._text[0] = symbol; ++_allocator._text; PpmContext successor = _allocator._text; if (!(_allocator._text >= _allocator._baseUnit)) { if (ppmContext2 != PpmContext.ZERO) { if (ppmContext2 < _allocator._baseUnit) { ppmContext2 = CreateSuccessors(skip: false, state, minimumContext); } } else { ppmContext2 = ReduceOrder(state, minimumContext); } if (!(ppmContext2 == PpmContext.ZERO)) { if (--_orderFall == 0) { successor = ppmContext2; _allocator._text -= ((_maximumContext != minimumContext) ? 1 : 0); } else if (_method > ModelRestorationMethod.Freeze) { successor = ppmContext2; _allocator._text = _allocator._heap; _orderFall = 0; } uint numberStatistics = minimumContext.NumberStatistics; uint num2 = minimumContext.SummaryFrequency - numberStatistics - frequency; byte b = (byte)((symbol >= 64) ? 8u : 0u); while (true) { if (ppmContext != minimumContext) { uint numberStatistics2 = ppmContext.NumberStatistics; if (numberStatistics2 != 0) { if ((numberStatistics2 & 1) != 0) { state = _allocator.ExpandUnits(ppmContext.Statistics, numberStatistics2 + 1 >> 1); if (state == PpmState.ZERO) { break; } ppmContext.Statistics = state; } ppmContext.SummaryFrequency += (ushort)((3 * numberStatistics2 + 1 < numberStatistics) ? 1 : 0); } else { state = _allocator.AllocateUnits(1u); if (state == PpmState.ZERO) { break; } Copy(state, ppmContext.FirstState); ppmContext.Statistics = state; if ((uint)state.Frequency < 30u) { state.Frequency += state.Frequency; } else { state.Frequency = 120; } ppmContext.SummaryFrequency = (ushort)((uint)(state.Frequency + _initialEscape) + ((numberStatistics > 2) ? 1u : 0u)); } uint num = (uint)(2 * frequency * (ppmContext.SummaryFrequency + 6)); uint num3 = num2 + ppmContext.SummaryFrequency; if (num < 6 * num3) { num = (uint)(1 + ((num > num3) ? 1 : 0) + ((num >= 4 * num3) ? 1 : 0)); ppmContext.SummaryFrequency += 4; } else { num = (uint)(4 + ((num > 9 * num3) ? 1 : 0) + ((num > 12 * num3) ? 1 : 0) + ((num > 15 * num3) ? 1 : 0)); ppmContext.SummaryFrequency += (ushort)num; } state = ppmContext.Statistics + ++ppmContext.NumberStatistics; state.Successor = successor; state.Symbol = symbol; state.Frequency = (byte)num; ppmContext.Flags |= b; ppmContext = ppmContext.Suffix; continue; } _maximumContext = ppmContext2; return; } } } } RestoreModel(ppmContext, minimumContext, ppmContext2); } private PpmContext CreateSuccessors(bool skip, PpmState state, PpmContext context) { PpmContext successor = _foundState.Successor; PpmState[] array = new PpmState[16]; uint num = 0u; byte symbol = _foundState.Symbol; if (!skip) { array[num++] = _foundState; if (context.Suffix == PpmContext.ZERO) { goto IL_016a; } } bool flag = false; if (state != PpmState.ZERO) { context = context.Suffix; flag = true; } do { if (flag) { flag = false; } else { context = context.Suffix; if (context.NumberStatistics != 0) { state = context.Statistics; byte symbol2; if (state.Symbol != symbol) { do { symbol2 = state[1].Symbol; ++state; } while (symbol2 != symbol); } symbol2 = (((uint)state.Frequency < 115u) ? ((byte)1) : ((byte)0)); state.Frequency += symbol2; context.SummaryFrequency += symbol2; } else { state = context.FirstState; state.Frequency += (((context.Suffix.NumberStatistics == 0) & (state.Frequency < 24)) ? ((byte)1) : ((byte)0)); } } if (state.Successor != successor) { context = state.Successor; break; } array[num++] = state; } while (context.Suffix != PpmContext.ZERO); goto IL_016a; IL_016a: if (num == 0) { return context; } byte numberStatistics = 0; byte b = (byte)((symbol >= 64) ? 16u : 0u); symbol = successor.NumberStatistics; byte firstStateSymbol = symbol; PpmContext firstStateSuccessor = (Pointer)successor + 1; b |= (byte)((symbol >= 64) ? 8 : 0); byte firstStateFrequency; if (context.NumberStatistics != 0) { state = context.Statistics; if (state.Symbol != symbol) { byte symbol3; do { symbol3 = state[1].Symbol; ++state; } while (symbol3 != symbol); } uint num2 = (uint)(state.Frequency - 1); uint num3 = (uint)(context.SummaryFrequency - context.NumberStatistics - num2); firstStateFrequency = (byte)(1 + ((2 * num2 > num3) ? ((int)((num2 + 2 * num3 - 3) / num3)) : ((5 * num2 > num3) ? 1 : 0))); } else { firstStateFrequency = context.FirstStateFrequency; } do { PpmContext ppmContext = _allocator.AllocateContext(); if (ppmContext == PpmContext.ZERO) { return PpmContext.ZERO; } ppmContext.NumberStatistics = numberStatistics; ppmContext.Flags = b; ppmContext.FirstStateSymbol = firstStateSymbol; ppmContext.FirstStateFrequency = firstStateFrequency; ppmContext.FirstStateSuccessor = firstStateSuccessor; ppmContext.Suffix = context; context = ppmContext; array[--num].Successor = context; } while (num != 0); return context; } private PpmContext ReduceOrder(PpmState state, PpmContext context) { PpmState[] array = new PpmState[16]; uint num = 0u; PpmContext ppmContext = context; PpmContext ppmContext2 = _allocator._text; byte symbol = _foundState.Symbol; array[num++] = _foundState; _foundState.Successor = ppmContext2; _orderFall++; bool flag = false; if (state != PpmState.ZERO) { context = context.Suffix; flag = true; } while (true) { if (flag) { flag = false; } else { if (context.Suffix == PpmContext.ZERO) { if (_method > ModelRestorationMethod.Freeze) { do { array[--num].Successor = context; } while (num != 0); _allocator._text = _allocator._heap + 1; _orderFall = 1; } return context; } context = context.Suffix; if (context.NumberStatistics != 0) { state = context.Statistics; byte symbol2; if (state.Symbol != symbol) { do { symbol2 = state[1].Symbol; ++state; } while (symbol2 != symbol); } symbol2 = (byte)(((uint)state.Frequency < 115u) ? 2u : 0u); state.Frequency += symbol2; context.SummaryFrequency += symbol2; } else { state = context.FirstState; state.Frequency += ((state.Frequency < 32) ? ((byte)1) : ((byte)0)); } } if (state.Successor != PpmContext.ZERO) { break; } array[num++] = state; state.Successor = ppmContext2; _orderFall++; } if (_method > ModelRestorationMethod.Freeze) { context = state.Successor; do { array[--num].Successor = context; } while (num != 0); _allocator._text = _allocator._heap + 1; _orderFall = 1; return context; } if (state.Successor <= ppmContext2) { PpmState foundState = _foundState; _foundState = state; state.Successor = CreateSuccessors(skip: false, PpmState.ZERO, context); _foundState = foundState; } if (_orderFall == 1 && ppmContext == _maximumContext) { _foundState.Successor = state.Successor; --_allocator._text; } return state.Successor; } private void RestoreModel(PpmContext context, PpmContext minimumContext, PpmContext foundStateSuccessor) { _allocator._text = _allocator._heap; PpmContext ppmContext = _maximumContext; while (ppmContext != context) { if (--ppmContext.NumberStatistics == 0) { ppmContext.Flags = (byte)((ppmContext.Flags & 0x10) + ((ppmContext.Statistics.Symbol >= 64) ? 8 : 0)); PpmState statistics = ppmContext.Statistics; Copy(ppmContext.FirstState, statistics); _allocator.SpecialFreeUnits(statistics); ppmContext.FirstStateFrequency = (byte)(ppmContext.FirstStateFrequency + 11 >> 3); } else { Refresh((uint)(ppmContext.NumberStatistics + 3 >> 1), scale: false, ppmContext); } ppmContext = ppmContext.Suffix; } while (ppmContext != minimumContext) { if (ppmContext.NumberStatistics == 0) { ppmContext.FirstStateFrequency -= (byte)(ppmContext.FirstStateFrequency >> 1); } else if ((ppmContext.SummaryFrequency += 4) > 128 + 4 * ppmContext.NumberStatistics) { Refresh((uint)(ppmContext.NumberStatistics + 2 >> 1), scale: true, ppmContext); } ppmContext = ppmContext.Suffix; } if (_method > ModelRestorationMethod.Freeze) { _maximumContext = foundStateSuccessor; _allocator._glueCount += (((_allocator._memoryNodes[1].Stamp & 1) == 0) ? 1u : 0u); return; } if (_method == ModelRestorationMethod.Freeze) { while (_maximumContext.Suffix != PpmContext.ZERO) { _maximumContext = _maximumContext.Suffix; } RemoveBinaryContexts(0, _maximumContext); _method++; _allocator._glueCount = 0u; _orderFall = _modelOrder; return; } if (_method == ModelRestorationMethod.Restart || _allocator.GetMemoryUsed() < _allocator._allocatorSize >> 1) { StartModel(_modelOrder, _method); _escapeCount = 0; return; } while (_maximumContext.Suffix != PpmContext.ZERO) { _maximumContext = _maximumContext.Suffix; } do { CutOff(0, _maximumContext); _allocator.ExpandText(); } while (_allocator.GetMemoryUsed() > 3 * (_allocator._allocatorSize >> 2)); _allocator._glueCount = 0u; _orderFall = _modelOrder; } private static void Swap(PpmState state1, PpmState state2) { byte symbol = state1.Symbol; byte frequency = state1.Frequency; PpmContext successor = state1.Successor; state1.Symbol = state2.Symbol; state1.Frequency = state2.Frequency; state1.Successor = state2.Successor; state2.Symbol = symbol; state2.Frequency = frequency; state2.Successor = successor; } private static void Copy(PpmState state1, PpmState state2) { state1.Symbol = state2.Symbol; state1.Frequency = state2.Frequency; state1.Successor = state2.Successor; } private static int Mean(int sum, int shift, int round) { return sum + (1 << shift - round) >> shift; } private void ClearMask() { _escapeCount = 1; Array.Clear(_characterMask, 0, _characterMask.Length); } private void EncodeBinarySymbol(int symbol, PpmContext context) { PpmState firstState = context.FirstState; int num = _probabilities[firstState.Frequency - 1]; int num2 = _numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] + _previousSuccess + context.Flags + ((_runLength >> 26) & 0x20); if (firstState.Symbol == symbol) { _foundState = firstState; firstState.Frequency += ((firstState.Frequency < 196) ? ((byte)1) : ((byte)0)); _coder._lowCount = 0u; _coder._highCount = _binarySummary[num, num2]; _binarySummary[num, num2] += (ushort)(128L - (long)Mean(_binarySummary[num, num2], 7, 2)); _previousSuccess = 1; _runLength++; } else { _coder._lowCount = _binarySummary[num, num2]; _binarySummary[num, num2] -= (ushort)Mean(_binarySummary[num, num2], 7, 2); _coder._highCount = 16384u; _initialEscape = EXPONENTIAL_ESCAPES[_binarySummary[num, num2] >> 10]; _characterMask[firstState.Symbol] = _escapeCount; _previousSuccess = 0; _numberMasked = 0; _foundState = PpmState.ZERO; } } private void EncodeSymbol1(int symbol, PpmContext context) { uint symbol2 = context.Statistics.Symbol; PpmState statistics = context.Statistics; _coder._scale = context.SummaryFrequency; if (symbol2 == symbol) { _coder._highCount = statistics.Frequency; _previousSuccess = (byte)((2 * _coder._highCount >= _coder._scale) ? 1u : 0u); _foundState = statistics; _foundState.Frequency += 4; context.SummaryFrequency += 4; _runLength += _previousSuccess; if ((uint)statistics.Frequency > 124u) { Rescale(context); } _coder._lowCount = 0u; return; } uint num = statistics.Frequency; symbol2 = context.NumberStatistics; _previousSuccess = 0; while (true) { PpmState ppmState = ++statistics; if (ppmState.Symbol == symbol) { break; } num += statistics.Frequency; if (--symbol2 == 0) { _coder._lowCount = num; _characterMask[statistics.Symbol] = _escapeCount; _numberMasked = context.NumberStatistics; symbol2 = context.NumberStatistics; _foundState = PpmState.ZERO; do { byte[] characterMask = _characterMask; ppmState = --statistics; characterMask[ppmState.Symbol] = _escapeCount; } while (--symbol2 != 0); _coder._highCount = _coder._scale; return; } } _coder._highCount = (_coder._lowCount = num) + statistics.Frequency; Update1(statistics, context); } private void EncodeSymbol2(int symbol, PpmContext context) { See2Context see2Context = MakeEscapeFrequency(context); uint num = 0u; uint num2 = (uint)(context.NumberStatistics - _numberMasked); PpmState ppmState = context.Statistics - 1; while (true) { uint symbol2 = ppmState[1].Symbol; ++ppmState; if (_characterMask[symbol2] != _escapeCount) { _characterMask[symbol2] = _escapeCount; if (symbol2 == symbol) { break; } num += ppmState.Frequency; if (--num2 == 0) { _coder._lowCount = num; _coder._scale += _coder._lowCount; _coder._highCount = _coder._scale; see2Context._summary += (ushort)_coder._scale; _numberMasked = context.NumberStatistics; return; } } } _coder._lowCount = num; num += ppmState.Frequency; _coder._highCount = num; PpmState ppmState2 = ppmState; while (--num2 != 0) { uint symbol2; do { symbol2 = ppmState2[1].Symbol; ++ppmState2; } while (_characterMask[symbol2] == _escapeCount); num += ppmState2.Frequency; } _coder._scale += num; see2Context.Update(); Update2(ppmState, context); } private void DecodeBinarySymbol(PpmContext context) { PpmState firstState = context.FirstState; int num = _probabilities[firstState.Frequency - 1]; int num2 = _numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] + _previousSuccess + context.Flags + ((_runLength >> 26) & 0x20); if (_coder.RangeGetCurrentShiftCount(14) < _binarySummary[num, num2]) { _foundState = firstState; firstState.Frequency += ((firstState.Frequency < 196) ? ((byte)1) : ((byte)0)); _coder._lowCount = 0u; _coder._highCount = _binarySummary[num, num2]; _binarySummary[num, num2] += (ushort)(128L - (long)Mean(_binarySummary[num, num2], 7, 2)); _previousSuccess = 1; _runLength++; } else { _coder._lowCount = _binarySummary[num, num2]; _binarySummary[num, num2] -= (ushort)Mean(_binarySummary[num, num2], 7, 2); _coder._highCount = 16384u; _initialEscape = EXPONENTIAL_ESCAPES[_binarySummary[num, num2] >> 10]; _characterMask[firstState.Symbol] = _escapeCount; _previousSuccess = 0; _numberMasked = 0; _foundState = PpmState.ZERO; } } private void DecodeSymbol1(PpmContext context) { uint num = context.Statistics.Frequency; PpmState statistics = context.Statistics; _coder._scale = context.SummaryFrequency; uint num2 = _coder.RangeGetCurrentCount(); if (num2 < num) { _coder._highCount = num; _previousSuccess = (byte)((2 * _coder._highCount >= _coder._scale) ? 1u : 0u); _foundState = statistics; num += 4; _foundState.Frequency = (byte)num; context.SummaryFrequency += 4; _runLength += _previousSuccess; if (num > 124) { Rescale(context); } _coder._lowCount = 0u; return; } uint num3 = context.NumberStatistics; _previousSuccess = 0; while (true) { uint num4 = num; PpmState ppmState = ++statistics; if ((num = num4 + ppmState.Frequency) > num2) { break; } if (--num3 == 0) { _coder._lowCount = num; _characterMask[statistics.Symbol] = _escapeCount; _numberMasked = context.NumberStatistics; num3 = context.NumberStatistics; _foundState = PpmState.ZERO; do { byte[] characterMask = _characterMask; ppmState = --statistics; characterMask[ppmState.Symbol] = _escapeCount; } while (--num3 != 0); _coder._highCount = _coder._scale; return; } } _coder._highCount = num; _coder._lowCount = _coder._highCount - statistics.Frequency; Update1(statistics, context); } private void DecodeSymbol2(PpmContext context) { See2Context see2Context = MakeEscapeFrequency(context); uint num = 0u; uint num2 = (uint)(context.NumberStatistics - _numberMasked); uint num3 = 0u; PpmState ppmState = context.Statistics - 1; while (true) { uint symbol = ppmState[1].Symbol; ++ppmState; if (_characterMask[symbol] != _escapeCount) { num += ppmState.Frequency; _decodeStates[num3++] = ppmState; if (--num2 == 0) { break; } } } _coder._scale += num; uint num4 = _coder.RangeGetCurrentCount(); num3 = 0u; ppmState = _decodeStates[num3]; if (num4 < num) { num = 0u; while ((num += ppmState.Frequency) <= num4) { ppmState = _decodeStates[++num3]; } _coder._highCount = num; _coder._lowCount = _coder._highCount - ppmState.Frequency; see2Context.Update(); Update2(ppmState, context); return; } _coder._lowCount = num; _coder._highCount = _coder._scale; num2 = (uint)(context.NumberStatistics - _numberMasked); _numberMasked = context.NumberStatistics; do { _characterMask[_decodeStates[num3].Symbol] = _escapeCount; num3++; } while (--num2 != 0); see2Context._summary += (ushort)_coder._scale; } private void Update1(PpmState state, PpmContext context) { _foundState = state; _foundState.Frequency += 4; context.SummaryFrequency += 4; if (state[0].Frequency > state[-1].Frequency) { Swap(state[0], state[-1]); _foundState = --state; if ((uint)state.Frequency > 124u) { Rescale(context); } } } private void Update2(PpmState state, PpmContext context) { _foundState = state; _foundState.Frequency += 4; context.SummaryFrequency += 4; if ((uint)state.Frequency > 124u) { Rescale(context); } _escapeCount++; _runLength = _initialRunLength; } private See2Context MakeEscapeFrequency(PpmContext context) { uint num = (uint)(2 * context.NumberStatistics); See2Context see2Context; if (context.NumberStatistics != byte.MaxValue) { num = context.Suffix.NumberStatistics; int num2 = _probabilities[context.NumberStatistics + 2] - 3; int num3 = ((context.SummaryFrequency > 11 * (context.NumberStatistics + 1)) ? 1 : 0) + ((2 * context.NumberStatistics < num + _numberMasked) ? 2 : 0) + context.Flags; see2Context = _see2Contexts[num2, num3]; _coder._scale = see2Context.Mean(); } else { see2Context = _emptySee2Context; _coder._scale = 1u; } return see2Context; } private void Rescale(PpmContext context) { uint num = context.NumberStatistics; PpmState foundState; for (foundState = _foundState; foundState != context.Statistics; --foundState) { Swap(foundState[0], foundState[-1]); } foundState.Frequency += 4; context.SummaryFrequency += 4; uint num2 = (uint)(context.SummaryFrequency - foundState.Frequency); int num3 = ((_orderFall != 0 || _method > ModelRestorationMethod.Freeze) ? 1 : 0); foundState.Frequency = (byte)(foundState.Frequency + num3 >> 1); context.SummaryFrequency = foundState.Frequency; do { uint num4 = num2; PpmState ppmState = ++foundState; num2 = num4 - ppmState.Frequency; foundState.Frequency = (byte)(foundState.Frequency + num3 >> 1); context.SummaryFrequency += foundState.Frequency; if (foundState[0].Frequency > foundState[-1].Frequency) { PpmState ppmState2 = foundState; byte symbol = ppmState2.Symbol; byte frequency = ppmState2.Frequency; PpmContext successor = ppmState2.Successor; byte num5; do { Copy(ppmState2[0], ppmState2[-1]); num5 = frequency; ppmState = --ppmState2; } while (num5 > ppmState[-1].Frequency); ppmState2.Symbol = symbol; ppmState2.Frequency = frequency; ppmState2.Successor = successor; } } while (--num != 0); if (foundState.Frequency == 0) { PpmState ppmState; do { num++; ppmState = --foundState; } while (ppmState.Frequency == 0); num2 += num; uint num6 = (uint)(context.NumberStatistics + 2 >> 1); context.NumberStatistics -= (byte)num; if (context.NumberStatistics == 0) { byte symbol = context.Statistics.Symbol; byte frequency = context.Statistics.Frequency; PpmContext successor = context.Statistics.Successor; frequency = (byte)((2 * frequency + num2 - 1) / num2); if ((uint)frequency > 41u) { frequency = 41; } _allocator.FreeUnits(context.Statistics, num6); context.FirstStateSymbol = symbol; context.FirstStateFrequency = frequency; context.FirstStateSuccessor = successor; context.Flags = (byte)((context.Flags & 0x10) + ((symbol >= 64) ? 8 : 0)); _foundState = context.FirstState; return; } context.Statistics = _allocator.ShrinkUnits(context.Statistics, num6, (uint)(context.NumberStatistics + 2 >> 1)); context.Flags &= 247; num = context.NumberStatistics; foundState = context.Statistics; context.Flags |= (byte)((foundState.Symbol >= 64) ? 8 : 0); do { byte flags = context.Flags; ppmState = ++foundState; context.Flags = (byte)(flags | (byte)((ppmState.Symbol >= 64) ? 8 : 0)); } while (--num != 0); } num2 -= num2 >> 1; context.SummaryFrequency += (ushort)num2; context.Flags |= 4; _foundState = context.Statistics; } private void Refresh(uint oldUnitCount, bool scale, PpmContext context) { int num = context.NumberStatistics; int num2 = (scale ? 1 : 0); context.Statistics = _allocator.ShrinkUnits(context.Statistics, oldUnitCount, (uint)(num + 2 >> 1)); PpmState statistics = context.Statistics; context.Flags = (byte)((context.Flags & (16 + (scale ? 4 : 0))) + ((statistics.Symbol >= 64) ? 8 : 0)); int num3 = context.SummaryFrequency - statistics.Frequency; statistics.Frequency = (byte)(statistics.Frequency + num2 >> num2); context.SummaryFrequency = statistics.Frequency; do { int num4 = num3; PpmState ppmState = ++statistics; num3 = num4 - ppmState.Frequency; statistics.Frequency = (byte)(statistics.Frequency + num2 >> num2); context.SummaryFrequency += statistics.Frequency; context.Flags |= (byte)((statistics.Symbol >= 64) ? 8 : 0); } while (--num != 0); num3 = num3 + num2 >> num2; context.SummaryFrequency += (ushort)num3; } private PpmContext CutOff(int order, PpmContext context) { if (context.NumberStatistics == 0) { PpmState firstState = context.FirstState; if ((Pointer)firstState.Successor >= _allocator._baseUnit) { if (order < _modelOrder) { firstState.Successor = CutOff(order + 1, firstState.Successor); } else { firstState.Successor = PpmContext.ZERO; } if (firstState.Successor == PpmContext.ZERO && (long)order > 9L) { _allocator.SpecialFreeUnits(context); return PpmContext.ZERO; } return context; } _allocator.SpecialFreeUnits(context); return PpmContext.ZERO; } uint num = (uint)(context.NumberStatistics + 2 >> 1); context.Statistics = _allocator.MoveUnitsUp(context.Statistics, num); int numberStatistics = context.NumberStatistics; for (PpmState firstState = context.Statistics + numberStatistics; firstState >= context.Statistics; --firstState) { if (firstState.Successor < _allocator._baseUnit) { firstState.Successor = PpmContext.ZERO; Swap(firstState, context.Statistics[numberStatistics--]); } else if (order < _modelOrder) { firstState.Successor = CutOff(order + 1, firstState.Successor); } else { firstState.Successor = PpmContext.ZERO; } } if (numberStatistics != context.NumberStatistics && order != 0) { context.NumberStatistics = (byte)numberStatistics; PpmState firstState = context.Statistics; if (numberStatistics < 0) { _allocator.FreeUnits(firstState, num); _allocator.SpecialFreeUnits(context); return PpmContext.ZERO; } if (numberStatistics == 0) { context.Flags = (byte)((context.Flags & 0x10) + ((firstState.Symbol >= 64) ? 8 : 0)); Copy(context.FirstState, firstState); _allocator.FreeUnits(firstState, num); context.FirstStateFrequency = (byte)(context.FirstStateFrequency + 11 >> 3); } else { Refresh(num, context.SummaryFrequency > 16 * numberStatistics, context); } } return context; } private PpmContext RemoveBinaryContexts(int order, PpmContext context) { if (context.NumberStatistics == 0) { PpmState firstState = context.FirstState; if ((Pointer)firstState.Successor >= _allocator._baseUnit && order < _modelOrder) { firstState.Successor = RemoveBinaryContexts(order + 1, firstState.Successor); } else { firstState.Successor = PpmContext.ZERO; } if (firstState.Successor == PpmContext.ZERO && (context.Suffix.NumberStatistics == 0 || context.Suffix.Flags == byte.MaxValue)) { _allocator.FreeUnits(context, 1u); return PpmContext.ZERO; } return context; } for (PpmState ppmState = context.Statistics + context.NumberStatistics; ppmState >= context.Statistics; --ppmState) { if ((Pointer)ppmState.Successor >= _allocator._baseUnit && order < _modelOrder) { ppmState.Successor = RemoveBinaryContexts(order + 1, ppmState.Successor); } else { ppmState.Successor = PpmContext.ZERO; } } return context; } } internal enum ModelRestorationMethod { Restart, CutOff, Freeze } internal struct Pointer { public uint _address; public byte[] _memory; public static readonly Pointer ZERO = new Pointer(0u, null); public const int SIZE = 1; public byte this[int offset] { get { return _memory[_address + offset]; } set { _memory[_address + offset] = value; } } public Pointer(uint address, byte[] memory) { _address = address; _memory = memory; } public static implicit operator Pointer(MemoryNode memoryNode) { return new Pointer(memoryNode._address, memoryNode._memory); } public static implicit operator Pointer(Model.PpmContext context) { return new Pointer(context._address, context._memory); } public static implicit operator Pointer(PpmState state) { return new Pointer(state._address, state._memory); } public static Pointer operator +(Pointer pointer, int offset) { pointer._address = (uint)(pointer._address + offset); return pointer; } public static Pointer operator +(Pointer pointer, uint offset) { pointer._address += offset; return pointer; } public static Pointer operator ++(Pointer pointer) { pointer._address++; return pointer; } public static Pointer operator -(Pointer pointer, int offset) { pointer._address = (uint)(pointer._address - offset); return pointer; } public static Pointer operator -(Pointer pointer, uint offset) { pointer._address -= offset; return pointer; } public static Pointer operator --(Pointer pointer) { pointer._address--; return pointer; } public static uint operator -(Pointer pointer1, Pointer pointer2) { return pointer1._address - pointer2._address; } public static bool operator <(Pointer pointer1, Pointer pointer2) { return pointer1._address < pointer2._address; } public static bool operator <=(Pointer pointer1, Pointer pointer2) { return pointer1._address <= pointer2._address; } public static bool operator >(Pointer pointer1, Pointer pointer2) { return pointer1._address > pointer2._address; } public static bool operator >=(Pointer pointer1, Pointer pointer2) { return pointer1._address >= pointer2._address; } public static bool operator ==(Pointer pointer1, Pointer pointer2) { return pointer1._address == pointer2._address; } public static bool operator !=(Pointer pointer1, Pointer pointer2) { return pointer1._address != pointer2._address; } public override bool Equals(object obj) { if (obj is Pointer) { return ((Pointer)obj)._address == _address; } return base.Equals(obj); } public override int GetHashCode() { return _address.GetHashCode(); } } internal struct PpmState { public uint _address; public byte[] _memory; public static readonly PpmState ZERO = new PpmState(0u, null); public const int SIZE = 6; public byte Symbol { get { return _memory[_address]; } set { _memory[_address] = value; } } public byte Frequency { get { return _memory[_address + 1]; } set { _memory[_address + 1] = value; } } public Model.PpmContext Successor { get { return new Model.PpmContext((uint)(_memory[_address + 2] | (_memory[_address + 3] << 8) | (_memory[_address + 4] << 16) | (_memory[_address + 5] << 24)), _memory); } set { _memory[_address + 2] = (byte)value._address; _memory[_address + 3] = (byte)(value._address >> 8); _memory[_address + 4] = (byte)(value._address >> 16); _memory[_address + 5] = (byte)(value._address >> 24); } } public PpmState this[int offset] => new PpmState((uint)(_address + offset * 6), _memory); public PpmState(uint address, byte[] memory) { _address = address; _memory = memory; } public static implicit operator PpmState(Pointer pointer) { return new PpmState(pointer._address, pointer._memory); } public static PpmState operator +(PpmState state, int offset) { state._address = (uint)(state._address + offset * 6); return state; } public static PpmState operator ++(PpmState state) { state._address += 6u; return state; } public static PpmState operator -(PpmState state, int offset) { state._address = (uint)(state._address - offset * 6); return state; } public static PpmState operator --(PpmState state) { state._address -= 6u; return state; } public static bool operator <=(PpmState state1, PpmState state2) { return state1._address <= state2._address; } public static bool operator >=(PpmState state1, PpmState state2) { return state1._address >= state2._address; } public static bool operator ==(PpmState state1, PpmState state2) { return state1._address == state2._address; } public static bool operator !=(PpmState state1, PpmState state2) { return state1._address != state2._address; } public override bool Equals(object obj) { if (obj is PpmState) { return ((PpmState)obj)._address == _address; } return base.Equals(obj); } public override int GetHashCode() { return _address.GetHashCode(); } } internal class See2Context { private const byte PERIOD_BIT_COUNT = 7; public ushort _summary; public byte _shift; public byte _count; public void Initialize(uint initialValue) { _shift = 3; _summary = (ushort)(initialValue << (int)_shift); _count = 7; } public uint Mean() { uint num = (uint)(_summary >> (int)_shift); _summary = (ushort)(_summary - num); return (uint)(num + ((num == 0) ? 1 : 0)); } public void Update() { if (_shift < 7 && --_count == 0) { _summary += _summary; _count = (byte)(3 << (int)_shift++); } } } } namespace SharpCompress.Compressors.PPMd.H { internal class FreqData : Pointer { internal const int SIZE = 6; internal int SummFreq { get { return DataConverter.LittleEndian.GetInt16(base.Memory, Address) & 0xFFFF; } set { DataConverter.LittleEndian.PutBytes(base.Memory, Address, (short)value); } } internal FreqData(byte[] memory) : base(memory) { } internal FreqData Initialize(byte[] mem) { return Initialize(mem); } internal void IncrementSummFreq(int dSummFreq) { short @int = DataConverter.LittleEndian.GetInt16(base.Memory, Address); @int += (short)dSummFreq; DataConverter.LittleEndian.PutBytes(base.Memory, Address, @int); } internal int GetStats() { return DataConverter.LittleEndian.GetInt32(base.Memory, Address + 2); } internal virtual void SetStats(State state) { SetStats(state.Address); } internal void SetStats(int state) { DataConverter.LittleEndian.PutBytes(base.Memory, Address + 2, state); } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("FreqData["); stringBuilder.Append("\n Address="); stringBuilder.Append(Address); stringBuilder.Append("\n size="); stringBuilder.Append(6); stringBuilder.Append("\n summFreq="); stringBuilder.Append(SummFreq); stringBuilder.Append("\n stats="); stringBuilder.Append(GetStats()); stringBuilder.Append("\n]"); return stringBuilder.ToString(); } } internal class ModelPpm { public const int MAX_O = 64; public const int INT_BITS = 7; public const int PERIOD_BITS = 7; public static readonly int TOT_BITS = 14; public static readonly int INTERVAL = 128; public static readonly int BIN_SCALE = 1 << TOT_BITS; public const int MAX_FREQ = 124; private readonly See2Context[][] _see2Cont = new See2Context[25][]; private See2Context _dummySee2Cont; private PpmContext _minContext; private PpmContext _maxContext; private int _numMasked; private int _initEsc; private int _orderFall; private int _maxOrder; private int _runLength; private int _initRl; private readonly int[] _charMask = new int[256]; private readonly int[] _ns2Indx = new int[256]; private readonly int[] _ns2BsIndx = new int[256]; private readonly int[] _hb2Flag = new int[256]; private int _escCount; private int _prevSuccess; private int _hiBitsFlag; private readonly int[][] _binSumm = new int[128][]; private static readonly int[] INIT_BIN_ESC = new int[8] { 15581, 7999, 22975, 18675, 25761, 23228, 26162, 24657 }; private readonly State _tempState1 = new State(null); private readonly State _tempState2 = new State(null); private readonly State _tempState3 = new State(null); private readonly State _tempState4 = new State(null); private readonly StateRef _tempStateRef1 = new StateRef(); private readonly StateRef _tempStateRef2 = new StateRef(); private readonly PpmContext _tempPpmContext1 = new PpmContext(null); private readonly PpmContext _tempPpmContext2 = new PpmContext(null); private readonly PpmContext _tempPpmContext3 = new PpmContext(null); private readonly PpmContext _tempPpmContext4 = new PpmContext(null); private readonly int[] _ps = new int[64]; public SubAllocator SubAlloc { get; } = new SubAllocator(); public virtual See2Context DummySee2Cont => _dummySee2Cont; public virtual int InitRl => _initRl; public virtual int EscCount { get { return _escCount; } set { _escCount = value & 0xFF; } } public virtual int[] CharMask => _charMask; public virtual int NumMasked { get { return _numMasked; } set { _numMasked = value; } } public virtual int PrevSuccess { get { return _prevSuccess; } set { _prevSuccess = value & 0xFF; } } public virtual int InitEsc { get { return _initEsc; } set { _initEsc = value; } } public virtual int RunLength { get { return _runLength; } set { _runLength = value; } } public virtual int HiBitsFlag { get { return _hiBitsFlag; } set { _hiBitsFlag = value & 0xFF; } } public virtual int[][] BinSumm => _binSumm; internal RangeCoder Coder { get; private set; } internal State FoundState { get; private set; } public virtual byte[] Heap => SubAlloc.Heap; public virtual int OrderFall => _orderFall; private void InitBlock() { for (int i = 0; i < 25; i++) { _see2Cont[i] = new See2Context[16]; } for (int j = 0; j < 128; j++) { _binSumm[j] = new int[64]; } } public ModelPpm() { InitBlock(); _minContext = null; _maxContext = null; } private void RestartModelRare() { Utility.Fill(_charMask, 0); SubAlloc.InitSubAllocator(); _initRl = -((_maxOrder < 12) ? _maxOrder : 12) - 1; int address = SubAlloc.AllocContext(); _minContext.Address = address; _maxContext.Address = address; _minContext.SetSuffix(0); _orderFall = _maxOrder; _minContext.NumStats = 256; _minContext.FreqData.SummFreq = _minContext.NumStats + 1; address = SubAlloc.AllocUnits(128); FoundState.Address = address; _minContext.FreqData.SetStats(address); State state = new State(SubAlloc.Heap); address = _minContext.FreqData.GetStats(); _runLength = _initRl; _prevSuccess = 0; for (int i = 0; i < 256; i++) { state.Address = address + i * 6; state.Symbol = i; state.Freq = 1; state.SetSuccessor(0); } for (int j = 0; j < 128; j++) { for (int k = 0; k < 8; k++) { for (int l = 0; l < 64; l += 8) { _binSumm[j][k + l] = BIN_SCALE - INIT_BIN_ESC[k] / (j + 2); } } } for (int m = 0; m < 25; m++) { for (int n = 0; n < 16; n++) { _see2Cont[m][n].Initialize(5 * m + 10); } } } private void StartModelRare(int maxOrder) { _escCount = 1; _maxOrder = maxOrder; RestartModelRare(); _ns2BsIndx[0] = 0; _ns2BsIndx[1] = 2; for (int i = 0; i < 9; i++) { _ns2BsIndx[2 + i] = 4; } for (int j = 0; j < 245; j++) { _ns2BsIndx[11 + j] = 6; } int k; for (k = 0; k < 3; k++) { _ns2Indx[k] = k; } int num = k; int num2 = 1; int num3 = 1; for (; k < 256; k++) { _ns2Indx[k] = num; if (--num2 == 0) { num2 = ++num3; num++; } } for (int l = 0; l < 64; l++) { _hb2Flag[l] = 0; } for (int m = 0; m < 192; m++) { _hb2Flag[64 + m] = 8; } _dummySee2Cont.Shift = 7; } private void ClearMask() { _escCount = 1; Utility.Fill(_charMask, 0); } internal bool DecodeInit(IRarUnpack unpackRead, int escChar) { int num = unpackRead.Char & 0xFF; bool flag = (num & 0x20) != 0; int num2 = 0; if (flag) { num2 = unpackRead.Char; } else if (SubAlloc.GetAllocatedMemory() == 0) { return false; } if ((num & 0x40) != 0) { escChar = unpackRead.Char; unpackRead.PpmEscChar = escChar; } Coder = new RangeCoder(unpackRead); if (flag) { num = (num & 0x1F) + 1; if (num > 16) { num = 16 + (num - 16) * 3; } if (num == 1) { SubAlloc.StopSubAllocator(); return false; } SubAlloc.StartSubAllocator(num2 + 1 << 20); _minContext = new PpmContext(Heap); _maxContext = new PpmContext(Heap); FoundState = new State(Heap); _dummySee2Cont = new See2Context(); for (int i = 0; i < 25; i++) { for (int j = 0; j < 16; j++) { _see2Cont[i][j] = new See2Context(); } } StartModelRare(num); } return _minContext.Address != 0; } public virtual int DecodeChar() { if (_minContext.Address <= SubAlloc.PText || _minContext.Address > SubAlloc.HeapEnd) { return -1; } if (_minContext.NumStats != 1) { if (_minContext.FreqData.GetStats() <= SubAlloc.PText || _minContext.FreqData.GetStats() > SubAlloc.HeapEnd) { return -1; } if (!_minContext.DecodeSymbol1(this)) { return -1; } } else { _minContext.DecodeBinSymbol(this); } Coder.Decode(); while (FoundState.Address == 0) { Coder.AriDecNormalize(); do { _orderFall++; _minContext.Address = _minContext.GetSuffix(); if (_minContext.Address <= SubAlloc.PText || _minContext.Address > SubAlloc.HeapEnd) { return -1; } } while (_minContext.NumStats == _numMasked); if (!_minContext.DecodeSymbol2(this)) { return -1; } Coder.Decode(); } int symbol = FoundState.Symbol; if (_orderFall == 0 && FoundState.GetSuccessor() > SubAlloc.PText) { int successor = FoundState.GetSuccessor(); _minContext.Address = successor; _maxContext.Address = successor; } else { UpdateModel(); if (_escCount == 0) { ClearMask(); } } Coder.AriDecNormalize(); return symbol; } public virtual See2Context[][] GetSee2Cont() { return _see2Cont; } public virtual void IncEscCount(int dEscCount) { EscCount += dEscCount; } public virtual void IncRunLength(int dRunLength) { RunLength += dRunLength; } public virtual int[] GetHb2Flag() { return _hb2Flag; } public virtual int[] GetNs2BsIndx() { return _ns2BsIndx; } public virtual int[] GetNs2Indx() { return _ns2Indx; } private int CreateSuccessors(bool skip, State p1) { StateRef tempStateRef = _tempStateRef2; State state = _tempState1.Initialize(Heap); PpmContext ppmContext = _tempPpmContext1.Initialize(Heap); ppmContext.Address = _minContext.Address; PpmContext ppmContext2 = _tempPpmContext2.Initialize(Heap); ppmContext2.Address = FoundState.GetSuccessor(); State state2 = _tempState2.Initialize(Heap); int num = 0; bool flag = false; if (!skip) { _ps[num++] = FoundState.Address; if (ppmContext.GetSuffix() == 0) { flag = true; } } if (!flag) { bool flag2 = false; if (p1.Address != 0) { state2.Address = p1.Address; ppmContext.Address = ppmContext.GetSuffix(); flag2 = true; } do { if (!flag2) { ppmContext.Address = ppmContext.GetSuffix(); if (ppmContext.NumStats != 1) { state2.Address = ppmContext.FreqData.GetStats(); if (state2.Symbol != FoundState.Symbol) { do { state2.IncrementAddress(); } while (state2.Symbol != FoundState.Symbol); } } else { state2.Address = ppmContext.GetOneState().Address; } } flag2 = false; if (state2.GetSuccessor() != ppmContext2.Address) { ppmContext.Address = state2.GetSuccessor(); break; } _ps[num++] = state2.Address; } while (ppmContext.GetSuffix() != 0); } if (num == 0) { return ppmContext.Address; } tempStateRef.Symbol = Heap[ppmContext2.Address]; tempStateRef.SetSuccessor(ppmContext2.Address + 1); if (ppmContext.NumStats != 1) { if (ppmContext.Address <= SubAlloc.PText) { return 0; } state2.Address = ppmContext.FreqData.GetStats(); if (state2.Symbol != tempStateRef.Symbol) { do { state2.IncrementAddress(); } while (state2.Symbol != tempStateRef.Symbol); } int num2 = state2.Freq - 1; int num3 = ppmContext.FreqData.SummFreq - ppmContext.NumStats - num2; tempStateRef.Freq = 1 + ((2 * num2 > num3) ? ((2 * num2 + 3 * num3 - 1) / (2 * num3)) : ((5 * num2 > num3) ? 1 : 0)); } else { tempStateRef.Freq = ppmContext.GetOneState().Freq; } do { state.Address = _ps[--num]; ppmContext.Address = ppmContext.CreateChild(this, state, tempStateRef); if (ppmContext.Address == 0) { return 0; } } while (num != 0); return ppmContext.Address; } private void UpdateModelRestart() { RestartModelRare(); _escCount = 0; } private void UpdateModel() { StateRef tempStateRef = _tempStateRef1; tempStateRef.Values = FoundState; State state = _tempState3.Initialize(Heap); State state2 = _tempState4.Initialize(Heap); PpmContext ppmContext = _tempPpmContext3.Initialize(Heap); PpmContext ppmContext2 = _tempPpmContext4.Initialize(Heap); ppmContext.Address = _minContext.GetSuffix(); if (tempStateRef.Freq < 31 && ppmContext.Address != 0) { if (ppmContext.NumStats != 1) { state.Address = ppmContext.FreqData.GetStats(); if (state.Symbol != tempStateRef.Symbol) { do { state.IncrementAddress(); } while (state.Symbol != tempStateRef.Symbol); state2.Address = state.Address - 6; if (state.Freq >= state2.Freq) { State.PpmdSwap(state, state2); state.DecrementAddress(); } } if (state.Freq < 115) { state.IncrementFreq(2); ppmContext.FreqData.IncrementSummFreq(2); } } else { state.Address = ppmContext.GetOneState().Address; if (state.Freq < 32) { state.IncrementFreq(1); } } } if (_orderFall == 0) { FoundState.SetSuccessor(CreateSuccessors(skip: true, state)); _minContext.Address = FoundState.GetSuccessor(); _maxContext.Address = FoundState.GetSuccessor(); if (_minContext.Address == 0) { UpdateModelRestart(); } return; } SubAlloc.Heap[SubAlloc.PText] = (byte)tempStateRef.Symbol; SubAlloc.IncPText(); ppmContext2.Address = SubAlloc.PText; if (SubAlloc.PText >= SubAlloc.FakeUnitsStart) { UpdateModelRestart(); return; } if (tempStateRef.GetSuccessor() != 0) { if (tempStateRef.GetSuccessor() <= SubAlloc.PText) { tempStateRef.SetSuccessor(CreateSuccessors(skip: false, state)); if (tempStateRef.GetSuccessor() == 0) { UpdateModelRestart(); return; } } if (--_orderFall == 0) { ppmContext2.Address = tempStateRef.GetSuccessor(); if (_maxContext.Address != _minContext.Address) { SubAlloc.DecPText(1); } } } else { FoundState.SetSuccessor(ppmContext2.Address); tempStateRef.SetSuccessor(_minContext); } int numStats = _minContext.NumStats; int num = _minContext.FreqData.SummFreq - numStats - (tempStateRef.Freq - 1); ppmContext.Address = _maxContext.Address; while (ppmContext.Address != _minContext.Address) { int numStats2; if ((numStats2 = ppmContext.NumStats) != 1) { if ((numStats2 & 1) == 0) { ppmContext.FreqData.SetStats(SubAlloc.ExpandUnits(ppmContext.FreqData.GetStats(), Utility.URShift(numStats2, 1))); if (ppmContext.FreqData.GetStats() == 0) { UpdateModelRestart(); return; } } int dSummFreq = ((2 * numStats2 < numStats) ? 1 : 0) + 2 * (((4 * numStats2 <= numStats) ? 1 : 0) & ((ppmContext.FreqData.SummFreq <= 8 * numStats2) ? 1 : 0)); ppmContext.FreqData.IncrementSummFreq(dSummFreq); } else { state.Address = SubAlloc.AllocUnits(1); if (state.Address == 0) { UpdateModelRestart(); return; } state.SetValues(ppmContext.GetOneState()); ppmContext.FreqData.SetStats(state); if (state.Freq < 30) { state.IncrementFreq(state.Freq); } else { state.Freq = 120; } ppmContext.FreqData.SummFreq = state.Freq + _initEsc + ((numStats > 3) ? 1 : 0); } int num2 = 2 * tempStateRef.Freq * (ppmContext.FreqData.SummFreq + 6); int num3 = num + ppmContext.FreqData.SummFreq; if (num2 < 6 * num3) { num2 = 1 + ((num2 > num3) ? 1 : 0) + ((num2 >= 4 * num3) ? 1 : 0); ppmContext.FreqData.IncrementSummFreq(3); } else { num2 = 4 + ((num2 >= 9 * num3) ? 1 : 0) + ((num2 >= 12 * num3) ? 1 : 0) + ((num2 >= 15 * num3) ? 1 : 0); ppmContext.FreqData.IncrementSummFreq(num2); } state.Address = ppmContext.FreqData.GetStats() + numStats2 * 6; state.SetSuccessor(ppmContext2); state.Symbol = tempStateRef.Symbol; state.Freq = num2; numStats2 = (ppmContext.NumStats = numStats2 + 1); ppmContext.Address = ppmContext.GetSuffix(); } int successor = tempStateRef.GetSuccessor(); _maxContext.Address = successor; _minContext.Address = successor; } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("ModelPPM["); stringBuilder.Append("\n numMasked="); stringBuilder.Append(_numMasked); stringBuilder.Append("\n initEsc="); stringBuilder.Append(_initEsc); stringBuilder.Append("\n orderFall="); stringBuilder.Append(_orderFall); stringBuilder.Append("\n maxOrder="); stringBuilder.Append(_maxOrder); stringBuilder.Append("\n runLength="); stringBuilder.Append(_runLength); stringBuilder.Append("\n initRL="); stringBuilder.Append(_initRl); stringBuilder.Append("\n escCount="); stringBuilder.Append(_escCount); stringBuilder.Append("\n prevSuccess="); stringBuilder.Append(_prevSuccess); stringBuilder.Append("\n foundState="); stringBuilder.Append(FoundState); stringBuilder.Append("\n coder="); stringBuilder.Append(Coder); stringBuilder.Append("\n subAlloc="); stringBuilder.Append(SubAlloc); stringBuilder.Append("\n]"); return stringBuilder.ToString(); } internal bool DecodeInit(Stream stream, int maxOrder, int maxMemory) { if (stream != null) { Coder = new RangeCoder(stream); } if (maxOrder == 1) { SubAlloc.StopSubAllocator(); return false; } SubAlloc.StartSubAllocator(maxMemory); _minContext = new PpmContext(Heap); _maxContext = new PpmContext(Heap); FoundState = new State(Heap); _dummySee2Cont = new See2Context(); for (int i = 0; i < 25; i++) { for (int j = 0; j < 16; j++) { _see2Cont[i][j] = new See2Context(); } } StartModelRare(maxOrder); return _minContext.Address != 0; } internal void NextContext() { int successor = FoundState.GetSuccessor(); if (_orderFall == 0 && successor > SubAlloc.PText) { _minContext.Address = successor; _maxContext.Address = successor; } else { UpdateModel(); } } public int DecodeChar(SharpCompress.Compressors.LZMA.RangeCoder.Decoder decoder) { if (_minContext.NumStats != 1) { State state = _tempState1.Initialize(Heap); state.Address = _minContext.FreqData.GetStats(); int threshold; int num; if ((threshold = (int)decoder.GetThreshold((uint)_minContext.FreqData.SummFreq)) < (num = state.Freq)) { decoder.Decode(0u, (uint)state.Freq); byte result = (byte)state.Symbol; _minContext.update1_0(this, state.Address); NextContext(); return result; } _prevSuccess = 0; int num2 = _minContext.NumStats - 1; do { state.IncrementAddress(); if ((num += state.Freq) > threshold) { decoder.Decode((uint)(num - state.Freq), (uint)state.Freq); byte result2 = (byte)state.Symbol; _minContext.Update1(this, state.Address); NextContext(); return result2; } } while (--num2 > 0); if (threshold >= _minContext.FreqData.SummFreq) { return -2; } _hiBitsFlag = _hb2Flag[FoundState.Symbol]; decoder.Decode((uint)num, (uint)(_minContext.FreqData.SummFreq - num)); for (num2 = 0; num2 < 256; num2++) { _charMask[num2] = -1; } _charMask[state.Symbol] = 0; num2 = _minContext.NumStats - 1; do { state.DecrementAddress(); _charMask[state.Symbol] = 0; } while (--num2 > 0); } else { State state2 = _tempState1.Initialize(Heap); state2.Address = _minContext.GetOneState().Address; _hiBitsFlag = GetHb2Flag()[FoundState.Symbol]; int num3 = state2.Freq - 1; int arrayIndex = _minContext.GetArrayIndex(this, state2); int num4 = _binSumm[num3][arrayIndex]; if (decoder.DecodeBit((uint)num4, 14) == 0) { _binSumm[num3][arrayIndex] = (num4 + INTERVAL - _minContext.GetMean(num4, 7, 2)) & 0xFFFF; FoundState.Address = state2.Address; byte result3 = (byte)state2.Symbol; state2.IncrementFreq((state2.Freq < 128) ? 1 : 0); _prevSuccess = 1; IncRunLength(1); NextContext(); return result3; } num4 = (num4 - _minContext.GetMean(num4, 7, 2)) & 0xFFFF; _binSumm[num3][arrayIndex] = num4; _initEsc = PpmContext.EXP_ESCAPE[Utility.URShift(num4, 10)]; for (int i = 0; i < 256; i++) { _charMask[i] = -1; } _charMask[state2.Symbol] = 0; _prevSuccess = 0; } while (true) { State state3 = _tempState1.Initialize(Heap); int numStats = _minContext.NumStats; do { _orderFall++; _minContext.Address = _minContext.GetSuffix(); if (_minContext.Address <= SubAlloc.PText || _minContext.Address > SubAlloc.HeapEnd) { return -1; } } while (_minContext.NumStats == numStats); int num5 = 0; state3.Address = _minContext.FreqData.GetStats(); int num6 = 0; int num7 = _minContext.NumStats - numStats; do { int num8 = _charMask[state3.Symbol]; num5 += state3.Freq & num8; _minContext._ps[num6] = state3.Address; state3.IncrementAddress(); num6 -= num8; } while (num6 != num7); int escFreq; See2Context see2Context = _minContext.MakeEscFreq(this, numStats, out escFreq); escFreq += num5; int threshold2 = (int)decoder.GetThreshold((uint)escFreq); if (threshold2 < num5) { State state4 = _tempState2.Initialize(Heap); num5 = 0; num6 = 0; state4.Address = _minContext._ps[num6]; while ((num5 += state4.Freq) <= threshold2) { num6++; state4.Address = _minContext._ps[num6]; } state3.Address = state4.Address; decoder.Decode((uint)(num5 - state3.Freq), (uint)state3.Freq); see2Context.Update(); byte result4 = (byte)state3.Symbol; _minContext.Update2(this, state3.Address); UpdateModel(); return result4; } if (threshold2 >= escFreq) { break; } decoder.Decode((uint)num5, (uint)(escFreq - num5)); see2Context.Summ += escFreq; do { state3.Address = _minContext._ps[--num6]; _charMask[state3.Symbol] = 0; } while (num6 != 0); } return -2; } } internal abstract class Pointer { internal byte[] Memory { get; private set; } internal virtual int Address { get; set; } internal Pointer(byte[] mem) { Memory = mem; } protected T Initialize(byte[] mem) where T : Pointer { Memory = mem; Address = 0; return this as T; } } internal class PpmContext : Pointer { private static readonly int UNION_SIZE; public static readonly int SIZE; private int _numStats; private readonly FreqData _freqData; private readonly State _oneState; private int _suffix; public static readonly int[] EXP_ESCAPE; private readonly State _tempState1 = new State(null); private readonly State _tempState2 = new State(null); private readonly State _tempState3 = new State(null); private readonly State _tempState4 = new State(null); private readonly State _tempState5 = new State(null); private PpmContext _tempPpmContext; internal int[] _ps = new int[256]; internal FreqData FreqData { get { return _freqData; } set { _freqData.SummFreq = value.SummFreq; _freqData.SetStats(value.GetStats()); } } public virtual int NumStats { get { if (base.Memory != null) { _numStats = DataConverter.LittleEndian.GetInt16(base.Memory, Address) & 0xFFFF; } return _numStats; } set { _numStats = value & 0xFFFF; if (base.Memory != null) { DataConverter.LittleEndian.PutBytes(base.Memory, Address, (short)value); } } } internal override int Address { get { return base.Address; } set { base.Address = value; _oneState.Address = value + 2; _freqData.Address = value + 2; } } public PpmContext(byte[] memory) : base(memory) { _oneState = new State(memory); _freqData = new FreqData(memory); } internal PpmContext Initialize(byte[] mem) { _oneState.Initialize(mem); _freqData.Initialize(mem); return Initialize(mem); } internal State GetOneState() { return _oneState; } internal void SetOneState(StateRef oneState) { _oneState.SetValues(oneState); } internal int GetSuffix() { if (base.Memory != null) { _suffix = DataConverter.LittleEndian.GetInt32(base.Memory, Address + 8); } return _suffix; } internal void SetSuffix(PpmContext suffix) { SetSuffix(suffix.Address); } internal void SetSuffix(int suffix) { _suffix = suffix; if (base.Memory != null) { DataConverter.LittleEndian.PutBytes(base.Memory, Address + 8, suffix); } } private PpmContext GetTempPpmContext(byte[] memory) { if (_tempPpmContext == null) { _tempPpmContext = new PpmContext(null); } return _tempPpmContext.Initialize(memory); } internal int CreateChild(ModelPpm model, State pStats, StateRef firstState) { PpmContext tempPpmContext = GetTempPpmContext(model.SubAlloc.Heap); tempPpmContext.Address = model.SubAlloc.AllocContext(); if (tempPpmContext != null) { tempPpmContext.NumStats = 1; tempPpmContext.SetOneState(firstState); tempPpmContext.SetSuffix(this); pStats.SetSuccessor(tempPpmContext); } return tempPpmContext.Address; } internal void Rescale(ModelPpm model) { int numStats = NumStats; int num = NumStats - 1; State state = new State(model.Heap); State state2 = new State(model.Heap); State state3 = new State(model.Heap); state2.Address = model.FoundState.Address; while (state2.Address != _freqData.GetStats()) { state3.Address = state2.Address - 6; State.PpmdSwap(state2, state3); state2.DecrementAddress(); } state3.Address = _freqData.GetStats(); state3.IncrementFreq(4); _freqData.IncrementSummFreq(4); int num2 = _freqData.SummFreq - state2.Freq; int num3 = ((model.OrderFall != 0) ? 1 : 0); state2.Freq = Utility.URShift(state2.Freq + num3, 1); _freqData.SummFreq = state2.Freq; do { state2.IncrementAddress(); num2 -= state2.Freq; state2.Freq = Utility.URShift(state2.Freq + num3, 1); _freqData.IncrementSummFreq(state2.Freq); state3.Address = state2.Address - 6; if (state2.Freq > state3.Freq) { state.Address = state2.Address; StateRef stateRef = new StateRef(); stateRef.Values = state; State state4 = new State(model.Heap); State state5 = new State(model.Heap); do { state4.Address = state.Address - 6; state.SetValues(state4); state.DecrementAddress(); state5.Address = state.Address - 6; } while (state.Address != _freqData.GetStats() && stateRef.Freq > state5.Freq); state.SetValues(stateRef); } } while (--num != 0); if (state2.Freq == 0) { do { num++; state2.DecrementAddress(); } while (state2.Freq == 0); num2 += num; NumStats -= num; if (NumStats == 1) { StateRef stateRef2 = new StateRef(); state3.Address = _freqData.GetStats(); stateRef2.Values = state3; do { stateRef2.DecrementFreq(Utility.URShift(stateRef2.Freq, 1)); num2 = Utility.URShift(num2, 1); } while (num2 > 1); model.SubAlloc.FreeUnits(_freqData.GetStats(), Utility.URShift(numStats + 1, 1)); _oneState.SetValues(stateRef2); model.FoundState.Address = _oneState.Address; return; } } num2 -= Utility.URShift(num2, 1); _freqData.IncrementSummFreq(num2); int num4 = Utility.URShift(numStats + 1, 1); int num5 = Utility.URShift(NumStats + 1, 1); if (num4 != num5) { _freqData.SetStats(model.SubAlloc.ShrinkUnits(_freqData.GetStats(), num4, num5)); } model.FoundState.Address = _freqData.GetStats(); } internal int GetArrayIndex(ModelPpm model, State rs) { PpmContext tempPpmContext = GetTempPpmContext(model.SubAlloc.Heap); tempPpmContext.Address = GetSuffix(); return 0 + model.PrevSuccess + model.GetNs2BsIndx()[tempPpmContext.NumStats - 1] + (model.HiBitsFlag + 2 * model.GetHb2Flag()[rs.Symbol]) + (Utility.URShift(model.RunLength, 26) & 0x20); } internal int GetMean(int summ, int shift, int round) { return Utility.URShift(summ + (1 << shift - round), shift); } internal void DecodeBinSymbol(ModelPpm model) { State state = _tempState1.Initialize(model.Heap); state.Address = _oneState.Address; model.HiBitsFlag = model.GetHb2Flag()[model.FoundState.Symbol]; int num = state.Freq - 1; int arrayIndex = GetArrayIndex(model, state); int num2 = model.BinSumm[num][arrayIndex]; if (model.Coder.GetCurrentShiftCount(ModelPpm.TOT_BITS) < num2) { model.FoundState.Address = state.Address; state.IncrementFreq((state.Freq < 128) ? 1 : 0); model.Coder.SubRange.LowCount = 0L; model.Coder.SubRange.HighCount = num2; num2 = (num2 + ModelPpm.INTERVAL - GetMean(num2, 7, 2)) & 0xFFFF; model.BinSumm[num][arrayIndex] = num2; model.PrevSuccess = 1; model.IncRunLength(1); } else { model.Coder.SubRange.LowCount = num2; num2 = (num2 - GetMean(num2, 7, 2)) & 0xFFFF; model.BinSumm[num][arrayIndex] = num2; model.Coder.SubRange.HighCount = ModelPpm.BIN_SCALE; model.InitEsc = EXP_ESCAPE[Utility.URShift(num2, 10)]; model.NumMasked = 1; model.CharMask[state.Symbol] = model.EscCount; model.PrevSuccess = 0; model.FoundState.Address = 0; } } internal void Update1(ModelPpm model, int p) { model.FoundState.Address = p; model.FoundState.IncrementFreq(4); _freqData.IncrementSummFreq(4); State state = _tempState3.Initialize(model.Heap); State state2 = _tempState4.Initialize(model.Heap); state.Address = p; state2.Address = p - 6; if (state.Freq > state2.Freq) { State.PpmdSwap(state, state2); model.FoundState.Address = state2.Address; if (state2.Freq > 124) { Rescale(model); } } } internal void update1_0(ModelPpm model, int p) { model.FoundState.Address = p; model.PrevSuccess = ((2 * model.FoundState.Freq > _freqData.SummFreq) ? 1 : 0); model.IncRunLength(model.PrevSuccess); _freqData.IncrementSummFreq(4); model.FoundState.IncrementFreq(4); if (model.FoundState.Freq > 124) { Rescale(model); } } internal bool DecodeSymbol2(ModelPpm model) { int num = NumStats - model.NumMasked; See2Context see2Context = MakeEscFreq2(model, num); RangeCoder coder = model.Coder; State state = _tempState1.Initialize(model.Heap); State state2 = _tempState2.Initialize(model.Heap); state.Address = _freqData.GetStats() - 6; int num2 = 0; int num3 = 0; while (true) { state.IncrementAddress(); if (model.CharMask[state.Symbol] != model.EscCount) { num3 += state.Freq; _ps[num2++] = state.Address; if (--num == 0) { break; } } } coder.SubRange.IncScale(num3); long num4 = coder.CurrentCount; if (num4 >= coder.SubRange.Scale) { return false; } num2 = 0; state.Address = _ps[num2]; if (num4 < num3) { num3 = 0; while ((num3 += state.Freq) <= num4) { state.Address = _ps[++num2]; } coder.SubRange.HighCount = num3; coder.SubRange.LowCount = num3 - state.Freq; see2Context.Update(); Update2(model, state.Address); } else { coder.SubRange.LowCount = num3; coder.SubRange.HighCount = coder.SubRange.Scale; num = NumStats - model.NumMasked; num2--; do { state2.Address = _ps[++num2]; model.CharMask[state2.Symbol] = model.EscCount; } while (--num != 0); see2Context.IncSumm((int)coder.SubRange.Scale); model.NumMasked = NumStats; } return true; } internal void Update2(ModelPpm model, int p) { State state = _tempState5.Initialize(model.Heap); state.Address = p; model.FoundState.Address = p; model.FoundState.IncrementFreq(4); _freqData.IncrementSummFreq(4); if (state.Freq > 124) { Rescale(model); } model.IncEscCount(1); model.RunLength = model.InitRl; } private See2Context MakeEscFreq2(ModelPpm model, int diff) { int numStats = NumStats; See2Context see2Context; if (numStats != 256) { PpmContext tempPpmContext = GetTempPpmContext(model.Heap); tempPpmContext.Address = GetSuffix(); int num = model.GetNs2Indx()[diff - 1]; int num2 = 0; num2 += ((diff < tempPpmContext.NumStats - numStats) ? 1 : 0); num2 += 2 * ((_freqData.SummFreq < 11 * numStats) ? 1 : 0); num2 += 4 * ((model.NumMasked > diff) ? 1 : 0); num2 += model.HiBitsFlag; see2Context = model.GetSee2Cont()[num][num2]; model.Coder.SubRange.Scale = see2Context.Mean; } else { see2Context = model.DummySee2Cont; model.Coder.SubRange.Scale = 1L; } return see2Context; } internal See2Context MakeEscFreq(ModelPpm model, int numMasked, out int escFreq) { int numStats = NumStats; int num = numStats - numMasked; See2Context see2Context; if (numStats != 256) { PpmContext tempPpmContext = GetTempPpmContext(model.Heap); tempPpmContext.Address = GetSuffix(); int num2 = model.GetNs2Indx()[num - 1]; int num3 = 0; num3 += ((num < tempPpmContext.NumStats - numStats) ? 1 : 0); num3 += 2 * ((_freqData.SummFreq < 11 * numStats) ? 1 : 0); num3 += 4 * ((numMasked > num) ? 1 : 0); num3 += model.HiBitsFlag; see2Context = model.GetSee2Cont()[num2][num3]; escFreq = see2Context.Mean; } else { see2Context = model.DummySee2Cont; escFreq = 1; } return see2Context; } internal bool DecodeSymbol1(ModelPpm model) { RangeCoder coder = model.Coder; coder.SubRange.Scale = _freqData.SummFreq; State state = new State(model.Heap); state.Address = _freqData.GetStats(); long num = coder.CurrentCount; if (num >= coder.SubRange.Scale) { return false; } int num2; if (num < (num2 = state.Freq)) { coder.SubRange.HighCount = num2; model.PrevSuccess = ((2 * num2 > coder.SubRange.Scale) ? 1 : 0); model.IncRunLength(model.PrevSuccess); num2 += 4; model.FoundState.Address = state.Address; model.FoundState.Freq = num2; _freqData.IncrementSummFreq(4); if (num2 > 124) { Rescale(model); } coder.SubRange.LowCount = 0L; return true; } if (model.FoundState.Address == 0) { return false; } model.PrevSuccess = 0; int numStats = NumStats; int num3 = numStats - 1; while ((num2 += state.IncrementAddress().Freq) <= num) { if (--num3 == 0) { model.HiBitsFlag = model.GetHb2Flag()[model.FoundState.Symbol]; coder.SubRange.LowCount = num2; model.CharMask[state.Symbol] = model.EscCount; model.NumMasked = numStats; num3 = numStats - 1; model.FoundState.Address = 0; do { model.CharMask[state.DecrementAddress().Symbol] = model.EscCount; } while (--num3 != 0); coder.SubRange.HighCount = coder.SubRange.Scale; return true; } } coder.SubRange.LowCount = num2 - state.Freq; coder.SubRange.HighCount = num2; Update1(model, state.Address); return true; } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("PPMContext["); stringBuilder.Append("\n Address="); stringBuilder.Append(Address); stringBuilder.Append("\n size="); stringBuilder.Append(SIZE); stringBuilder.Append("\n numStats="); stringBuilder.Append(NumStats); stringBuilder.Append("\n Suffix="); stringBuilder.Append(GetSuffix()); stringBuilder.Append("\n freqData="); stringBuilder.Append(_freqData); stringBuilder.Append("\n oneState="); stringBuilder.Append(_oneState); stringBuilder.Append("\n]"); return stringBuilder.ToString(); } static PpmContext() { SIZE = 2 + UNION_SIZE + 4; EXP_ESCAPE = new int[16] { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; UNION_SIZE = Math.Max(6, 6); } } internal class RangeCoder { internal const int TOP = 16777216; internal const int BOT = 32768; internal const long UINT_MASK = 4294967295L; private long _low; private long _code; private long _range; private readonly IRarUnpack _unpackRead; private readonly Stream _stream; internal int CurrentCount { get { _range = (_range / SubRange.Scale) & 0xFFFFFFFFu; return (int)((_code - _low) / _range); } } private long Char { get { if (_unpackRead != null) { return _unpackRead.Char; } if (_stream != null) { return _stream.ReadByte(); } return -1L; } } internal SubRange SubRange { get; private set; } internal RangeCoder(IRarUnpack unpackRead) { _unpackRead = unpackRead; Init(); } internal RangeCoder(Stream stream) { _stream = stream; Init(); } private void Init() { SubRange = new SubRange(); _low = (_code = 0L); _range = 4294967295L; for (int i = 0; i < 4; i++) { _code = ((_code << 8) | Char) & 0xFFFFFFFFu; } } internal long GetCurrentShiftCount(int shift) { _range = Utility.URShift(_range, shift); return ((_code - _low) / _range) & 0xFFFFFFFFu; } internal void Decode() { _low = (_low + _range * SubRange.LowCount) & 0xFFFFFFFFu; _range = (_range * (SubRange.HighCount - SubRange.LowCount)) & 0xFFFFFFFFu; } internal void AriDecNormalize() { bool flag = false; while ((_low ^ (_low + _range)) < 16777216 || (flag = _range < 32768)) { if (flag) { _range = -_low & 0x7FFF & 0xFFFFFFFFu; flag = false; } _code = ((_code << 8) | Char) & 0xFFFFFFFFu; _range = (_range << 8) & 0xFFFFFFFFu; _low = (_low << 8) & 0xFFFFFFFFu; } } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("RangeCoder["); stringBuilder.Append("\n low="); stringBuilder.Append(_low); stringBuilder.Append("\n code="); stringBuilder.Append(_code); stringBuilder.Append("\n range="); stringBuilder.Append(_range); stringBuilder.Append("\n subrange="); stringBuilder.Append(SubRange); stringBuilder.Append("]"); return stringBuilder.ToString(); } } internal class SubRange { private long _lowCount; private long _highCount; private long _scale; internal long HighCount { get { return _highCount; } set { _highCount = value & 0xFFFFFFFFu; } } internal long LowCount { get { return _lowCount & 0xFFFFFFFFu; } set { _lowCount = value & 0xFFFFFFFFu; } } internal long Scale { get { return _scale; } set { _scale = value & 0xFFFFFFFFu; } } internal void IncScale(int dScale) { Scale += dScale; } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("SubRange["); stringBuilder.Append("\n lowCount="); stringBuilder.Append(_lowCount); stringBuilder.Append("\n highCount="); stringBuilder.Append(_highCount); stringBuilder.Append("\n scale="); stringBuilder.Append(_scale); stringBuilder.Append("]"); return stringBuilder.ToString(); } } internal class RarMemBlock : Pointer { public const int SIZE = 12; private int _stamp; private int _nu; private int _next; private int _prev; internal int Stamp { get { if (base.Memory != null) { _stamp = DataConverter.LittleEndian.GetInt16(base.Memory, Address) & 0xFFFF; } return _stamp; } set { _stamp = value; if (base.Memory != null) { DataConverter.LittleEndian.PutBytes(base.Memory, Address, (short)value); } } } public RarMemBlock(byte[] memory) : base(memory) { } internal void InsertAt(RarMemBlock p) { RarMemBlock rarMemBlock = new RarMemBlock(base.Memory); SetPrev(p.Address); rarMemBlock.Address = GetPrev(); SetNext(rarMemBlock.GetNext()); rarMemBlock.SetNext(this); rarMemBlock.Address = GetNext(); rarMemBlock.SetPrev(this); } internal void Remove() { RarMemBlock rarMemBlock = new RarMemBlock(base.Memory); rarMemBlock.Address = GetPrev(); rarMemBlock.SetNext(GetNext()); rarMemBlock.Address = GetNext(); rarMemBlock.SetPrev(GetPrev()); } internal int GetNext() { if (base.Memory != null) { _next = DataConverter.LittleEndian.GetInt32(base.Memory, Address + 4); } return _next; } internal void SetNext(RarMemBlock next) { SetNext(next.Address); } internal void SetNext(int next) { _next = next; if (base.Memory != null) { DataConverter.LittleEndian.PutBytes(base.Memory, Address + 4, next); } } internal int GetNu() { if (base.Memory != null) { _nu = DataConverter.LittleEndian.GetInt16(base.Memory, Address + 2) & 0xFFFF; } return _nu; } internal void SetNu(int nu) { _nu = nu & 0xFFFF; if (base.Memory != null) { DataConverter.LittleEndian.PutBytes(base.Memory, Address + 2, (short)nu); } } internal int GetPrev() { if (base.Memory != null) { _prev = DataConverter.LittleEndian.GetInt32(base.Memory, Address + 8); } return _prev; } internal void SetPrev(RarMemBlock prev) { SetPrev(prev.Address); } internal void SetPrev(int prev) { _prev = prev; if (base.Memory != null) { DataConverter.LittleEndian.PutBytes(base.Memory, Address + 8, prev); } } } internal class RarNode : Pointer { private int _next; public const int SIZE = 4; public RarNode(byte[] memory) : base(memory) { } internal int GetNext() { if (base.Memory != null) { _next = DataConverter.LittleEndian.GetInt32(base.Memory, Address); } return _next; } internal void SetNext(RarNode next) { SetNext(next.Address); } internal void SetNext(int next) { _next = next; if (base.Memory != null) { DataConverter.LittleEndian.PutBytes(base.Memory, Address, next); } } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("State["); stringBuilder.Append("\n Address="); stringBuilder.Append(Address); stringBuilder.Append("\n size="); stringBuilder.Append(4); stringBuilder.Append("\n next="); stringBuilder.Append(GetNext()); stringBuilder.Append("\n]"); return stringBuilder.ToString(); } } internal class See2Context { public const int SIZE = 4; private int _summ; private int _shift; private int _count; public virtual int Mean { get { int num = Utility.URShift(_summ, _shift); _summ -= num; return num + ((num == 0) ? 1 : 0); } } public virtual int Count { get { return _count; } set { _count = value & 0xFF; } } public virtual int Shift { get { return _shift; } set { _shift = value & 0xFF; } } public virtual int Summ { get { return _summ; } set { _summ = value & 0xFFFF; } } public void Initialize(int initVal) { _shift = 3; _summ = (initVal << _shift) & 0xFFFF; _count = 4; } public virtual void Update() { if (_shift < 7 && --_count == 0) { _summ += _summ; _count = 3 << _shift++; } _summ &= 65535; _count &= 255; _shift &= 255; } public virtual void IncSumm(int dSumm) { Summ += dSumm; } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("SEE2Context["); stringBuilder.Append("\n size="); stringBuilder.Append(4); stringBuilder.Append("\n summ="); stringBuilder.Append(_summ); stringBuilder.Append("\n shift="); stringBuilder.Append(_shift); stringBuilder.Append("\n count="); stringBuilder.Append(_count); stringBuilder.Append("\n]"); return stringBuilder.ToString(); } } internal class State : Pointer { internal const int SIZE = 6; internal int Symbol { get { return base.Memory[Address] & 0xFF; } set { base.Memory[Address] = (byte)value; } } internal int Freq { get { return base.Memory[Address + 1] & 0xFF; } set { base.Memory[Address + 1] = (byte)value; } } internal State(byte[] memory) : base(memory) { } internal State Initialize(byte[] mem) { return Initialize(mem); } internal void IncrementFreq(int dFreq) { base.Memory[Address + 1] = (byte)(base.Memory[Address + 1] + dFreq); } internal int GetSuccessor() { return DataConverter.LittleEndian.GetInt32(base.Memory, Address + 2); } internal void SetSuccessor(PpmContext successor) { SetSuccessor(successor.Address); } internal void SetSuccessor(int successor) { DataConverter.LittleEndian.PutBytes(base.Memory, Address + 2, successor); } internal void SetValues(StateRef state) { Symbol = state.Symbol; Freq = state.Freq; SetSuccessor(state.GetSuccessor()); } internal void SetValues(State ptr) { Array.Copy(ptr.Memory, ptr.Address, base.Memory, Address, 6); } internal State DecrementAddress() { Address -= 6; return this; } internal State IncrementAddress() { Address += 6; return this; } internal static void PpmdSwap(State ptr1, State ptr2) { byte[] memory = ptr1.Memory; byte[] memory2 = ptr2.Memory; int num = 0; int num2 = ptr1.Address; int num3 = ptr2.Address; while (num < 6) { byte b = memory[num2]; memory[num2] = memory2[num3]; memory2[num3] = b; num++; num2++; num3++; } } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("State["); stringBuilder.Append("\n Address="); stringBuilder.Append(Address); stringBuilder.Append("\n size="); stringBuilder.Append(6); stringBuilder.Append("\n symbol="); stringBuilder.Append(Symbol); stringBuilder.Append("\n freq="); stringBuilder.Append(Freq); stringBuilder.Append("\n successor="); stringBuilder.Append(GetSuccessor()); stringBuilder.Append("\n]"); return stringBuilder.ToString(); } } internal class StateRef { private int _symbol; private int _freq; private int _successor; internal int Symbol { get { return _symbol; } set { _symbol = value & 0xFF; } } internal int Freq { get { return _freq; } set { _freq = value & 0xFF; } } internal State Values { set { Freq = value.Freq; SetSuccessor(value.GetSuccessor()); Symbol = value.Symbol; } } public virtual void IncrementFreq(int dFreq) { _freq = (_freq + dFreq) & 0xFF; } public virtual void DecrementFreq(int dFreq) { _freq = (_freq - dFreq) & 0xFF; } public virtual int GetSuccessor() { return _successor; } public virtual void SetSuccessor(PpmContext successor) { SetSuccessor(successor.Address); } public virtual void SetSuccessor(int successor) { _successor = successor; } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("State["); stringBuilder.Append("\n symbol="); stringBuilder.Append(Symbol); stringBuilder.Append("\n freq="); stringBuilder.Append(Freq); stringBuilder.Append("\n successor="); stringBuilder.Append(GetSuccessor()); stringBuilder.Append("\n]"); return stringBuilder.ToString(); } } internal class SubAllocator { public const int N1 = 4; public const int N2 = 4; public const int N3 = 4; public static readonly int N4; public static readonly int N_INDEXES; public static readonly int UNIT_SIZE; public const int FIXED_UNIT_SIZE = 12; private int _subAllocatorSize; private readonly int[] _indx2Units = new int[N_INDEXES]; private readonly int[] _units2Indx = new int[128]; private int _glueCount; private int _heapStart; private int _loUnit; private int _hiUnit; private readonly RarNode[] _freeList = new RarNode[N_INDEXES]; private int _pText; private int _unitsStart; private int _heapEnd; private int _fakeUnitsStart; private byte[] _heap; private int _freeListPos; private int _tempMemBlockPos; private RarNode _tempRarNode; private RarMemBlock _tempRarMemBlock1; private RarMemBlock _tempRarMemBlock2; private RarMemBlock _tempRarMemBlock3; public virtual int FakeUnitsStart { get { return _fakeUnitsStart; } set { _fakeUnitsStart = value; } } public virtual int HeapEnd => _heapEnd; public virtual int PText { get { return _pText; } set { _pText = value; } } public virtual int UnitsStart { get { return _unitsStart; } set { _unitsStart = value; } } public virtual byte[] Heap => _heap; public SubAllocator() { Clean(); } public virtual void Clean() { _subAllocatorSize = 0; } private void InsertNode(int p, int indx) { RarNode tempRarNode = _tempRarNode; tempRarNode.Address = p; tempRarNode.SetNext(_freeList[indx].GetNext()); _freeList[indx].SetNext(tempRarNode); } public virtual void IncPText() { _pText++; } private int RemoveNode(int indx) { int next = _freeList[indx].GetNext(); RarNode tempRarNode = _tempRarNode; tempRarNode.Address = next; _freeList[indx].SetNext(tempRarNode.GetNext()); return next; } private int U2B(int nu) { return UNIT_SIZE * nu; } private int MbPtr(int basePtr, int items) { return basePtr + U2B(items); } private void SplitBlock(int pv, int oldIndx, int newIndx) { int num = _indx2Units[oldIndx] - _indx2Units[newIndx]; int num2 = pv + U2B(_indx2Units[newIndx]); int num3; if (_indx2Units[num3 = _units2Indx[num - 1]] != num) { InsertNode(num2, --num3); num2 += U2B(num3 = _indx2Units[num3]); num -= num3; } InsertNode(num2, _units2Indx[num - 1]); } public virtual void StopSubAllocator() { if (_subAllocatorSize != 0) { _subAllocatorSize = 0; _heap = null; _heapStart = 1; _tempRarNode = null; _tempRarMemBlock1 = null; _tempRarMemBlock2 = null; _tempRarMemBlock3 = null; } } public virtual int GetAllocatedMemory() { return _subAllocatorSize; } public virtual bool StartSubAllocator(int saSize) { if (_subAllocatorSize == saSize) { return true; } StopSubAllocator(); int num = saSize / 12 * UNIT_SIZE + UNIT_SIZE; int num2 = (_tempMemBlockPos = 1 + num + 4 * N_INDEXES) + 12; _heap = new byte[num2]; _heapStart = 1; _heapEnd = _heapStart + num - UNIT_SIZE; _subAllocatorSize = saSize; _freeListPos = _heapStart + num; int num3 = 0; int num4 = _freeListPos; while (num3 < _freeList.Length) { _freeList[num3] = new RarNode(_heap); _freeList[num3].Address = num4; num3++; num4 += 4; } _tempRarNode = new RarNode(_heap); _tempRarMemBlock1 = new RarMemBlock(_heap); _tempRarMemBlock2 = new RarMemBlock(_heap); _tempRarMemBlock3 = new RarMemBlock(_heap); return true; } private void GlueFreeBlocks() { RarMemBlock tempRarMemBlock = _tempRarMemBlock1; tempRarMemBlock.Address = _tempMemBlockPos; RarMemBlock tempRarMemBlock2 = _tempRarMemBlock2; RarMemBlock tempRarMemBlock3 = _tempRarMemBlock3; if (_loUnit != _hiUnit) { _heap[_loUnit] = 0; } int i = 0; tempRarMemBlock.SetPrev(tempRarMemBlock); tempRarMemBlock.SetNext(tempRarMemBlock); for (; i < N_INDEXES; i++) { while (_freeList[i].GetNext() != 0) { tempRarMemBlock2.Address = RemoveNode(i); tempRarMemBlock2.InsertAt(tempRarMemBlock); tempRarMemBlock2.Stamp = 65535; tempRarMemBlock2.SetNu(_indx2Units[i]); } } tempRarMemBlock2.Address = tempRarMemBlock.GetNext(); while (tempRarMemBlock2.Address != tempRarMemBlock.Address) { tempRarMemBlock3.Address = MbPtr(tempRarMemBlock2.Address, tempRarMemBlock2.GetNu()); while (tempRarMemBlock3.Stamp == 65535 && tempRarMemBlock2.GetNu() + tempRarMemBlock3.GetNu() < 65536) { tempRarMemBlock3.Remove(); tempRarMemBlock2.SetNu(tempRarMemBlock2.GetNu() + tempRarMemBlock3.GetNu()); tempRarMemBlock3.Address = MbPtr(tempRarMemBlock2.Address, tempRarMemBlock2.GetNu()); } tempRarMemBlock2.Address = tempRarMemBlock2.GetNext(); } tempRarMemBlock2.Address = tempRarMemBlock.GetNext(); while (tempRarMemBlock2.Address != tempRarMemBlock.Address) { tempRarMemBlock2.Remove(); int num = tempRarMemBlock2.GetNu(); while (num > 128) { InsertNode(tempRarMemBlock2.Address, N_INDEXES - 1); num -= 128; tempRarMemBlock2.Address = MbPtr(tempRarMemBlock2.Address, 128); } if (_indx2Units[i = _units2Indx[num - 1]] != num) { int num2 = num - _indx2Units[--i]; InsertNode(MbPtr(tempRarMemBlock2.Address, num - num2), num2 - 1); } InsertNode(tempRarMemBlock2.Address, i); tempRarMemBlock2.Address = tempRarMemBlock.GetNext(); } } private int AllocUnitsRare(int indx) { if (_glueCount == 0) { _glueCount = 255; GlueFreeBlocks(); if (_freeList[indx].GetNext() != 0) { return RemoveNode(indx); } } int num = indx; do { if (++num == N_INDEXES) { _glueCount--; num = U2B(_indx2Units[indx]); int num2 = 12 * _indx2Units[indx]; if (_fakeUnitsStart - _pText > num2) { _fakeUnitsStart -= num2; _unitsStart -= num; return _unitsStart; } return 0; } } while (_freeList[num].GetNext() == 0); int num3 = RemoveNode(num); SplitBlock(num3, num, indx); return num3; } public virtual int AllocUnits(int nu) { int num = _units2Indx[nu - 1]; if (_freeList[num].GetNext() != 0) { return RemoveNode(num); } int loUnit = _loUnit; _loUnit += U2B(_indx2Units[num]); if (_loUnit <= _hiUnit) { return loUnit; } _loUnit -= U2B(_indx2Units[num]); return AllocUnitsRare(num); } public virtual int AllocContext() { if (_hiUnit != _loUnit) { return _hiUnit -= UNIT_SIZE; } if (_freeList[0].GetNext() != 0) { return RemoveNode(0); } return AllocUnitsRare(0); } public virtual int ExpandUnits(int oldPtr, int oldNu) { int num = _units2Indx[oldNu - 1]; int num2 = _units2Indx[oldNu - 1 + 1]; if (num == num2) { return oldPtr; } int num3 = AllocUnits(oldNu + 1); if (num3 != 0) { Array.Copy(_heap, oldPtr, _heap, num3, U2B(oldNu)); InsertNode(oldPtr, num); } return num3; } public virtual int ShrinkUnits(int oldPtr, int oldNu, int newNu) { int num = _units2Indx[oldNu - 1]; int num2 = _units2Indx[newNu - 1]; if (num == num2) { return oldPtr; } if (_freeList[num2].GetNext() != 0) { int num3 = RemoveNode(num2); Array.Copy(_heap, oldPtr, _heap, num3, U2B(newNu)); InsertNode(oldPtr, num); return num3; } SplitBlock(oldPtr, num, num2); return oldPtr; } public virtual void FreeUnits(int ptr, int oldNu) { InsertNode(ptr, _units2Indx[oldNu - 1]); } public virtual void DecPText(int dPText) { PText -= dPText; } public virtual void InitSubAllocator() { Utility.Fill(_heap, _freeListPos, _freeListPos + SizeOfFreeList(), (byte)0); _pText = _heapStart; int num = 12 * (_subAllocatorSize / 8 / 12 * 7); int num2 = num / 12 * UNIT_SIZE; int num3 = _subAllocatorSize - num; int num4 = num3 / 12 * UNIT_SIZE + num3 % 12; _hiUnit = _heapStart + _subAllocatorSize; _loUnit = (_unitsStart = _heapStart + num4); _fakeUnitsStart = _heapStart + num3; _hiUnit = _loUnit + num2; int num5 = 0; int num6 = 1; while (num5 < 4) { _indx2Units[num5] = num6 & 0xFF; num5++; num6++; } num6++; while (num5 < 8) { _indx2Units[num5] = num6 & 0xFF; num5++; num6 += 2; } num6++; while (num5 < 12) { _indx2Units[num5] = num6 & 0xFF; num5++; num6 += 3; } num6++; while (num5 < 12 + N4) { _indx2Units[num5] = num6 & 0xFF; num5++; num6 += 4; } _glueCount = 0; num6 = 0; num5 = 0; for (; num6 < 128; num6++) { num5 += ((_indx2Units[num5] < num6 + 1) ? 1 : 0); _units2Indx[num6] = num5 & 0xFF; } } private int SizeOfFreeList() { return _freeList.Length * 4; } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("SubAllocator["); stringBuilder.Append("\n subAllocatorSize="); stringBuilder.Append(_subAllocatorSize); stringBuilder.Append("\n glueCount="); stringBuilder.Append(_glueCount); stringBuilder.Append("\n heapStart="); stringBuilder.Append(_heapStart); stringBuilder.Append("\n loUnit="); stringBuilder.Append(_loUnit); stringBuilder.Append("\n hiUnit="); stringBuilder.Append(_hiUnit); stringBuilder.Append("\n pText="); stringBuilder.Append(_pText); stringBuilder.Append("\n unitsStart="); stringBuilder.Append(_unitsStart); stringBuilder.Append("\n]"); return stringBuilder.ToString(); } static SubAllocator() { N4 = 26; N_INDEXES = 12 + N4; UNIT_SIZE = Math.Max(PpmContext.SIZE, 12); } } } namespace SharpCompress.Compressors.LZMA { internal class AesDecoderStream : DecoderStream2 { private readonly Stream mStream; private readonly ICryptoTransform mDecoder; private readonly byte[] mBuffer; private long mWritten; private readonly long mLimit; private int mOffset; private int mEnding; private int mUnderflow; private bool isDisposed; public override long Position => mWritten; public override long Length => mLimit; public AesDecoderStream(Stream input, byte[] info, IPasswordProvider pass, long limit) { mStream = input; mLimit = limit; if (((int)input.Length & 0xF) != 0) { throw new NotSupportedException("AES decoder does not support padding."); } Init(info, out var numCyclesPower, out var salt, out var iv); byte[] bytes = Encoding.Unicode.GetBytes(pass.CryptoGetTextPassword()); byte[] rgbKey = InitKey(numCyclesPower, salt, bytes); using (Aes aes = Aes.Create()) { aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.None; mDecoder = aes.CreateDecryptor(rgbKey, iv); } mBuffer = new byte[4096]; } protected override void Dispose(bool disposing) { try { if (!isDisposed) { isDisposed = true; if (disposing) { mStream.Dispose(); mDecoder.Dispose(); } } } finally { base.Dispose(disposing); } } public override int Read(byte[] buffer, int offset, int count) { if (count == 0 || mWritten == mLimit) { return 0; } if (mUnderflow > 0) { return HandleUnderflow(buffer, offset, count); } if (mEnding - mOffset < 16) { Buffer.BlockCopy(mBuffer, mOffset, mBuffer, 0, mEnding - mOffset); mEnding -= mOffset; mOffset = 0; do { int num = mStream.Read(mBuffer, mEnding, mBuffer.Length - mEnding); if (num == 0) { throw new EndOfStreamException(); } mEnding += num; } while (mEnding - mOffset < 16); } if (count > mLimit - mWritten) { count = (int)(mLimit - mWritten); } if (count < 16) { return HandleUnderflow(buffer, offset, count); } if (count > mEnding - mOffset) { count = mEnding - mOffset; } int num2 = mDecoder.TransformBlock(mBuffer, mOffset, count & -16, buffer, offset); mOffset += num2; mWritten += num2; return num2; } private void Init(byte[] info, out int numCyclesPower, out byte[] salt, out byte[] iv) { byte b = info[0]; numCyclesPower = b & 0x3F; if ((b & 0xC0) == 0) { salt = new byte[0]; iv = new byte[0]; return; } int num = (b >> 7) & 1; int num2 = (b >> 6) & 1; if (info.Length == 1) { throw new InvalidOperationException(); } byte b2 = info[1]; num += b2 >> 4; num2 += b2 & 0xF; if (info.Length < 2 + num + num2) { throw new InvalidOperationException(); } salt = new byte[num]; for (int i = 0; i < num; i++) { salt[i] = info[i + 2]; } iv = new byte[16]; for (int j = 0; j < num2; j++) { iv[j] = info[j + num + 2]; } if (numCyclesPower <= 24) { return; } throw new NotSupportedException(); } private byte[] InitKey(int mNumCyclesPower, byte[] salt, byte[] pass) { if (mNumCyclesPower == 63) { byte[] array = new byte[32]; int i; for (i = 0; i < salt.Length; i++) { array[i] = salt[i]; } for (int j = 0; j < pass.Length; j++) { if (i >= 32) { break; } array[i++] = pass[j]; } return array; } using SHA256 sHA = SHA256.Create(); byte[] array2 = new byte[8]; long num = 1L << mNumCyclesPower; for (long num2 = 0L; num2 < num; num2++) { sHA.TransformBlock(salt, 0, salt.Length, null, 0); sHA.TransformBlock(pass, 0, pass.Length, null, 0); sHA.TransformBlock(array2, 0, 8, null, 0); for (int k = 0; k < 8; k++) { if (++array2[k] != 0) { break; } } } sHA.TransformFinalBlock(array2, 0, 0); return sHA.Hash; } private int HandleUnderflow(byte[] buffer, int offset, int count) { if (mUnderflow == 0) { int inputCount = (mEnding - mOffset) & -16; mUnderflow = mDecoder.TransformBlock(mBuffer, mOffset, inputCount, mBuffer, mOffset); } if (count > mUnderflow) { count = mUnderflow; } Buffer.BlockCopy(mBuffer, mOffset, buffer, offset, count); mWritten += count; mOffset += count; mUnderflow -= count; return count; } } internal class Bcj2DecoderStream : DecoderStream2 { private class RangeDecoder { internal readonly Stream _mStream; internal uint _range; internal uint _code; public RangeDecoder(Stream stream) { _mStream = stream; _range = uint.MaxValue; for (int i = 0; i < 5; i++) { _code = (_code << 8) | ReadByte(); } } public byte ReadByte() { int num = _mStream.ReadByte(); if (num < 0) { throw new EndOfStreamException(); } return (byte)num; } public void Dispose() { _mStream.Dispose(); } } private class StatusDecoder { private const int NUM_MOVE_BITS = 5; private const int K_NUM_BIT_MODEL_TOTAL_BITS = 11; private const uint K_BIT_MODEL_TOTAL = 2048u; private uint _prob; public StatusDecoder() { _prob = 1024u; } private void UpdateModel(uint symbol) { if (symbol == 0) { _prob += 2048 - _prob >> 5; } else { _prob -= _prob >> 5; } } public uint Decode(RangeDecoder decoder) { uint num = (decoder._range >> 11) * _prob; if (decoder._code < num) { decoder._range = num; _prob += 2048 - _prob >> 5; if (decoder._range < 16777216) { decoder._code = (decoder._code << 8) | decoder.ReadByte(); decoder._range <<= 8; } return 0u; } decoder._range -= num; decoder._code -= num; _prob -= _prob >> 5; if (decoder._range < 16777216) { decoder._code = (decoder._code << 8) | decoder.ReadByte(); decoder._range <<= 8; } return 1u; } } private const int K_NUM_TOP_BITS = 24; private const uint K_TOP_VALUE = 16777216u; private readonly Stream _mMainStream; private readonly Stream _mCallStream; private readonly Stream _mJumpStream; private readonly RangeDecoder _mRangeDecoder; private readonly StatusDecoder[] _mStatusDecoder; private long _mWritten; private readonly IEnumerator _mIter; private bool _mFinished; private bool _isDisposed; public Bcj2DecoderStream(Stream[] streams, byte[] info, long limit) { if (info != null && info.Length != 0) { throw new NotSupportedException(); } if (streams.Length != 4) { throw new NotSupportedException(); } _mMainStream = streams[0]; _mCallStream = streams[1]; _mJumpStream = streams[2]; _mRangeDecoder = new RangeDecoder(streams[3]); _mStatusDecoder = new StatusDecoder[258]; for (int i = 0; i < _mStatusDecoder.Length; i++) { _mStatusDecoder[i] = new StatusDecoder(); } _mIter = Run().GetEnumerator(); } protected override void Dispose(bool disposing) { if (!_isDisposed) { _isDisposed = true; base.Dispose(disposing); _mMainStream.Dispose(); _mCallStream.Dispose(); _mJumpStream.Dispose(); } } private static bool IsJcc(byte b0, byte b1) { if (b0 == 15) { return (b1 & 0xF0) == 128; } return false; } private static bool IsJ(byte b0, byte b1) { if ((b1 & 0xFE) != 232) { return IsJcc(b0, b1); } return true; } private static int GetIndex(byte b0, byte b1) { return b1 switch { 232 => b0, 233 => 256, _ => 257, }; } public override int Read(byte[] buffer, int offset, int count) { if (count == 0 || _mFinished) { return 0; } for (int i = 0; i < count; i++) { if (!_mIter.MoveNext()) { _mFinished = true; return i; } buffer[offset + i] = _mIter.Current; } return count; } public override int ReadByte() { if (_mFinished) { return -1; } if (!_mIter.MoveNext()) { _mFinished = true; return -1; } return _mIter.Current; } public IEnumerable Run() { byte prevByte = 0; uint processedBytes = 0u; while (true) { byte b = 0; uint i; for (i = 0u; i < 262144; i++) { int num = _mMainStream.ReadByte(); if (num < 0) { yield break; } b = (byte)num; _mWritten++; yield return b; if (IsJ(prevByte, b)) { break; } prevByte = b; } processedBytes += i; if (i == 262144) { continue; } if (_mStatusDecoder[GetIndex(prevByte, b)].Decode(_mRangeDecoder) == 1) { Stream stream = ((b == 232) ? _mCallStream : _mJumpStream); uint num2 = 0u; for (i = 0u; i < 4; i++) { int num3 = stream.ReadByte(); if (num3 < 0) { throw new EndOfStreamException(); } num2 <<= 8; num2 |= (uint)num3; } uint dest = num2 - (uint)(int)(_mWritten + 4); _mWritten++; yield return (byte)dest; _mWritten++; yield return (byte)(dest >> 8); _mWritten++; yield return (byte)(dest >> 16); _mWritten++; yield return (byte)(dest >> 24); prevByte = (byte)(dest >> 24); processedBytes += 4; } else { prevByte = b; } } } } internal class BitVector { private readonly uint[] _mBits; public int Length { get; } public bool this[int index] { get { if (index < 0 || index >= Length) { throw new ArgumentOutOfRangeException("index"); } return (_mBits[index >> 5] & (uint)(1 << index)) != 0; } } public BitVector(int length) { Length = length; _mBits = new uint[length + 31 >> 5]; } public BitVector(int length, bool initValue) { Length = length; _mBits = new uint[length + 31 >> 5]; if (initValue) { for (int i = 0; i < _mBits.Length; i++) { _mBits[i] = uint.MaxValue; } } } public BitVector(List bits) : this(bits.Count) { for (int i = 0; i < bits.Count; i++) { if (bits[i]) { SetBit(i); } } } public bool[] ToArray() { bool[] array = new bool[Length]; for (int i = 0; i < array.Length; i++) { array[i] = this[i]; } return array; } public void SetBit(int index) { if (index < 0 || index >= Length) { throw new ArgumentOutOfRangeException("index"); } _mBits[index >> 5] |= (uint)(1 << index); } internal bool GetAndSet(int index) { if (index < 0 || index >= Length) { throw new ArgumentOutOfRangeException("index"); } uint num = _mBits[index >> 5]; uint num2 = (uint)(1 << index); _mBits[index >> 5] |= num2; return (num & num2) != 0; } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(Length); for (int i = 0; i < Length; i++) { stringBuilder.Append(this[i] ? 'x' : '.'); } return stringBuilder.ToString(); } } internal static class Crc { internal const uint INIT_CRC = uint.MaxValue; internal static readonly uint[] TABLE; static Crc() { TABLE = new uint[1024]; for (uint num = 0u; num < 256; num++) { uint num2 = num; for (int i = 0; i < 8; i++) { num2 = (num2 >> 1) ^ (0xEDB88320u & ~((num2 & 1) - 1)); } TABLE[num] = num2; } for (uint num3 = 256u; num3 < TABLE.Length; num3++) { uint num4 = TABLE[num3 - 256]; TABLE[num3] = TABLE[num4 & 0xFF] ^ (num4 >> 8); } } public static uint From(Stream stream, long length) { uint crc = uint.MaxValue; byte[] array = new byte[Math.Min(length, 4096L)]; while (length > 0) { int num = stream.Read(array, 0, (int)Math.Min(length, array.Length)); if (num == 0) { throw new EndOfStreamException(); } crc = Update(crc, array, 0, num); length -= num; } return Finish(crc); } public static uint Finish(uint crc) { return ~crc; } public static uint Update(uint crc, byte bt) { return TABLE[(crc & 0xFF) ^ bt] ^ (crc >> 8); } public static uint Update(uint crc, uint value) { crc ^= value; return TABLE[768 + (crc & 0xFF)] ^ TABLE[512 + ((crc >> 8) & 0xFF)] ^ TABLE[256 + ((crc >> 16) & 0xFF)] ^ TABLE[crc >> 24]; } public static uint Update(uint crc, ulong value) { return Update(Update(crc, (uint)value), (uint)(value >> 32)); } public static uint Update(uint crc, long value) { return Update(crc, (ulong)value); } public static uint Update(uint crc, byte[] buffer, int offset, int length) { for (int i = 0; i < length; i++) { crc = Update(crc, buffer[offset + i]); } return crc; } } internal abstract class DecoderStream2 : Stream { public override bool CanRead => true; public override bool CanSeek => false; public override bool CanWrite => false; public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } public override void Flush() { throw new NotSupportedException(); } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } } internal static class DecoderStreamHelper { private static int FindCoderIndexForOutStreamIndex(CFolder folderInfo, int outStreamIndex) { for (int i = 0; i < folderInfo._coders.Count; i++) { CCoderInfo cCoderInfo = folderInfo._coders[i]; outStreamIndex -= cCoderInfo._numOutStreams; if (outStreamIndex < 0) { return i; } } throw new InvalidOperationException("Could not link output stream to coder."); } private static void FindPrimaryOutStreamIndex(CFolder folderInfo, out int primaryCoderIndex, out int primaryOutStreamIndex) { bool flag = false; primaryCoderIndex = -1; primaryOutStreamIndex = -1; int num = 0; for (int i = 0; i < folderInfo._coders.Count; i++) { int num2 = 0; while (num2 < folderInfo._coders[i]._numOutStreams) { if (folderInfo.FindBindPairForOutStream(num) < 0) { if (flag) { throw new NotSupportedException("Multiple output streams."); } flag = true; primaryCoderIndex = i; primaryOutStreamIndex = num; } num2++; num++; } } if (!flag) { throw new NotSupportedException("No output stream."); } } private static Stream CreateDecoderStream(Stream[] packStreams, long[] packSizes, Stream[] outStreams, CFolder folderInfo, int coderIndex, IPasswordProvider pass) { CCoderInfo cCoderInfo = folderInfo._coders[coderIndex]; if (cCoderInfo._numOutStreams != 1) { throw new NotSupportedException("Multiple output streams are not supported."); } int num = 0; for (int i = 0; i < coderIndex; i++) { num += folderInfo._coders[i]._numInStreams; } int num2 = 0; for (int j = 0; j < coderIndex; j++) { num2 += folderInfo._coders[j]._numOutStreams; } Stream[] array = new Stream[cCoderInfo._numInStreams]; int num3 = 0; while (num3 < array.Length) { int num4 = folderInfo.FindBindPairForInStream(num); if (num4 >= 0) { int outIndex = folderInfo._bindPairs[num4]._outIndex; if (outStreams[outIndex] != null) { throw new NotSupportedException("Overlapping stream bindings are not supported."); } int coderIndex2 = FindCoderIndexForOutStreamIndex(folderInfo, outIndex); array[num3] = CreateDecoderStream(packStreams, packSizes, outStreams, folderInfo, coderIndex2, pass); if (outStreams[outIndex] != null) { throw new NotSupportedException("Overlapping stream bindings are not supported."); } outStreams[outIndex] = array[num3]; } else { int num5 = folderInfo.FindPackStreamArrayIndex(num); if (num5 < 0) { throw new NotSupportedException("Could not find input stream binding."); } array[num3] = packStreams[num5]; } num3++; num++; } long limit = folderInfo._unpackSizes[num2]; return DecoderRegistry.CreateDecoderStream(cCoderInfo._methodId, array, cCoderInfo._props, pass, limit); } internal static Stream CreateDecoderStream(Stream inStream, long startPos, long[] packSizes, CFolder folderInfo, IPasswordProvider pass) { if (!folderInfo.CheckStructure()) { throw new NotSupportedException("Unsupported stream binding structure."); } Stream[] array = new Stream[folderInfo._packStreams.Count]; for (int i = 0; i < folderInfo._packStreams.Count; i++) { array[i] = new BufferedSubStream(inStream, startPos, packSizes[i]); startPos += packSizes[i]; } Stream[] outStreams = new Stream[folderInfo._unpackSizes.Count]; FindPrimaryOutStreamIndex(folderInfo, out var primaryCoderIndex, out var _); return CreateDecoderStream(array, packSizes, outStreams, folderInfo, primaryCoderIndex, pass); } } internal class DataErrorException : Exception { public DataErrorException() : base("Data Error") { } } internal class InvalidParamException : Exception { public InvalidParamException() : base("Invalid Parameter") { } } internal interface ICodeProgress { void SetProgress(long inSize, long outSize); } internal interface ICoder { void Code(Stream inStream, Stream outStream, long inSize, long outSize, ICodeProgress progress); } internal enum CoderPropId { DefaultProp, DictionarySize, UsedMemorySize, Order, BlockSize, PosStateBits, LitContextBits, LitPosBits, NumFastBytes, MatchFinder, MatchFinderCycles, NumPasses, Algorithm, NumThreads, EndMarker } internal interface ISetCoderProperties { void SetCoderProperties(CoderPropId[] propIDs, object[] properties); } internal interface IWriteCoderProperties { void WriteCoderProperties(Stream outStream); } internal interface ISetDecoderProperties { void SetDecoderProperties(byte[] properties); } internal static class Log { private static readonly Stack INDENT; private static bool NEEDS_INDENT; static Log() { INDENT = new Stack(); NEEDS_INDENT = true; INDENT.Push(""); } public static void PushIndent(string indent = " ") { INDENT.Push(INDENT.Peek() + indent); } public static void PopIndent() { if (INDENT.Count == 1) { throw new InvalidOperationException(); } INDENT.Pop(); } private static void EnsureIndent() { if (NEEDS_INDENT) { NEEDS_INDENT = false; } } public static void Write(object value) { EnsureIndent(); } public static void Write(string text) { EnsureIndent(); } public static void Write(string format, params object[] args) { EnsureIndent(); } public static void WriteLine() { NEEDS_INDENT = true; } public static void WriteLine(object value) { EnsureIndent(); NEEDS_INDENT = true; } public static void WriteLine(string text) { EnsureIndent(); NEEDS_INDENT = true; } public static void WriteLine(string format, params object[] args) { EnsureIndent(); NEEDS_INDENT = true; } } public class LZipStream : Stream { private readonly Stream _stream; private readonly CountingWritableSubStream _countingWritableSubStream; private bool _disposed; private bool _finished; private long _writeCount; public CompressionMode Mode { get; } public override bool CanRead => Mode == CompressionMode.Decompress; public override bool CanSeek => false; public override bool CanWrite => Mode == CompressionMode.Compress; public override long Length { get { throw new NotImplementedException(); } } public override long Position { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } public LZipStream(Stream stream, CompressionMode mode) { Mode = mode; if (mode == CompressionMode.Decompress) { int num = ValidateAndReadSize(stream); if (num == 0) { throw new IOException("Not an LZip stream"); } byte[] properties = GetProperties(num); _stream = new LzmaStream(properties, stream); } else { int dictionary = 106496; WriteHeaderSize(stream); _countingWritableSubStream = new CountingWritableSubStream(stream); _stream = new Crc32Stream(new LzmaStream(new LzmaEncoderProperties(eos: true, dictionary), isLzma2: false, _countingWritableSubStream)); } } public void Finish() { if (!_finished) { if (Mode == CompressionMode.Compress) { Crc32Stream crc32Stream = (Crc32Stream)_stream; crc32Stream.WrappedStream.Dispose(); crc32Stream.Dispose(); ulong count = _countingWritableSubStream.Count; byte[] bytes = DataConverter.LittleEndian.GetBytes(crc32Stream.Crc); _countingWritableSubStream.Write(bytes, 0, bytes.Length); bytes = DataConverter.LittleEndian.GetBytes(_writeCount); _countingWritableSubStream.Write(bytes, 0, bytes.Length); bytes = DataConverter.LittleEndian.GetBytes(count + 6 + 20); _countingWritableSubStream.Write(bytes, 0, bytes.Length); } _finished = true; } } protected override void Dispose(bool disposing) { if (!_disposed) { _disposed = true; if (disposing) { Finish(); _stream.Dispose(); } } } public override void Flush() { _stream.Flush(); } public override int Read(byte[] buffer, int offset, int count) { return _stream.Read(buffer, offset, count); } public override int ReadByte() { return _stream.ReadByte(); } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotImplementedException(); } public override void Write(byte[] buffer, int offset, int count) { _stream.Write(buffer, offset, count); _writeCount += count; } public override void WriteByte(byte value) { _stream.WriteByte(value); _writeCount++; } public static bool IsLZipFile(Stream stream) { return ValidateAndReadSize(stream) != 0; } public static int ValidateAndReadSize(Stream stream) { if (stream == null) { throw new ArgumentNullException("stream"); } byte[] array = new byte[6]; if (stream.Read(array, 0, array.Length) != 6) { return 0; } if (array[0] != 76 || array[1] != 90 || array[2] != 73 || array[3] != 80 || array[4] != 1) { return 0; } int num = array[5] & 0x1F; int num2 = (array[5] & 0xE0) >> 5; return (1 << num) - num2 * (1 << num - 4); } public static void WriteHeaderSize(Stream stream) { if (stream == null) { throw new ArgumentNullException("stream"); } byte[] buffer = new byte[6] { 76, 90, 73, 80, 1, 113 }; stream.Write(buffer, 0, 6); } private static byte[] GetProperties(int dictionarySize) { return new byte[5] { 93, (byte)(dictionarySize & 0xFF), (byte)((dictionarySize >> 8) & 0xFF), (byte)((dictionarySize >> 16) & 0xFF), (byte)((dictionarySize >> 24) & 0xFF) }; } } internal abstract class Base { public struct State { public uint _index; public void Init() { _index = 0u; } public void UpdateChar() { if (_index < 4) { _index = 0u; } else if (_index < 10) { _index -= 3u; } else { _index -= 6u; } } public void UpdateMatch() { _index = ((_index < 7) ? 7u : 10u); } public void UpdateRep() { _index = ((_index < 7) ? 8u : 11u); } public void UpdateShortRep() { _index = ((_index < 7) ? 9u : 11u); } public bool IsCharState() { return _index < 7; } } public const uint K_NUM_REP_DISTANCES = 4u; public const uint K_NUM_STATES = 12u; public const int K_NUM_POS_SLOT_BITS = 6; public const int K_DIC_LOG_SIZE_MIN = 0; public const int K_NUM_LEN_TO_POS_STATES_BITS = 2; public const uint K_NUM_LEN_TO_POS_STATES = 4u; public const uint K_MATCH_MIN_LEN = 2u; public const int K_NUM_ALIGN_BITS = 4; public const uint K_ALIGN_TABLE_SIZE = 16u; public const uint K_ALIGN_MASK = 15u; public const uint K_START_POS_MODEL_INDEX = 4u; public const uint K_END_POS_MODEL_INDEX = 14u; public const uint K_NUM_POS_MODELS = 10u; public const uint K_NUM_FULL_DISTANCES = 128u; public const uint K_NUM_LIT_POS_STATES_BITS_ENCODING_MAX = 4u; public const uint K_NUM_LIT_CONTEXT_BITS_MAX = 8u; public const int K_NUM_POS_STATES_BITS_MAX = 4; public const uint K_NUM_POS_STATES_MAX = 16u; public const int K_NUM_POS_STATES_BITS_ENCODING_MAX = 4; public const uint K_NUM_POS_STATES_ENCODING_MAX = 16u; public const int K_NUM_LOW_LEN_BITS = 3; public const int K_NUM_MID_LEN_BITS = 3; public const int K_NUM_HIGH_LEN_BITS = 8; public const uint K_NUM_LOW_LEN_SYMBOLS = 8u; public const uint K_NUM_MID_LEN_SYMBOLS = 8u; public const uint K_NUM_LEN_SYMBOLS = 272u; public const uint K_MATCH_MAX_LEN = 273u; public static uint GetLenToPosState(uint len) { len -= 2; if (len < 4) { return len; } return 3u; } } internal class Decoder : ICoder, ISetDecoderProperties { private class LenDecoder { private BitDecoder _choice; private BitDecoder _choice2; private readonly BitTreeDecoder[] _lowCoder = new BitTreeDecoder[16]; private readonly BitTreeDecoder[] _midCoder = new BitTreeDecoder[16]; private BitTreeDecoder _highCoder = new BitTreeDecoder(8); private uint _numPosStates; public void Create(uint numPosStates) { for (uint num = _numPosStates; num < numPosStates; num++) { _lowCoder[num] = new BitTreeDecoder(3); _midCoder[num] = new BitTreeDecoder(3); } _numPosStates = numPosStates; } public void Init() { _choice.Init(); for (uint num = 0u; num < _numPosStates; num++) { _lowCoder[num].Init(); _midCoder[num].Init(); } _choice2.Init(); _highCoder.Init(); } public uint Decode(SharpCompress.Compressors.LZMA.RangeCoder.Decoder rangeDecoder, uint posState) { if (_choice.Decode(rangeDecoder) == 0) { return _lowCoder[posState].Decode(rangeDecoder); } uint num = 8u; if (_choice2.Decode(rangeDecoder) == 0) { return num + _midCoder[posState].Decode(rangeDecoder); } num += 8; return num + _highCoder.Decode(rangeDecoder); } } private class LiteralDecoder { private struct Decoder2 { private BitDecoder[] _decoders; public void Create() { _decoders = new BitDecoder[768]; } public void Init() { for (int i = 0; i < 768; i++) { _decoders[i].Init(); } } public byte DecodeNormal(SharpCompress.Compressors.LZMA.RangeCoder.Decoder rangeDecoder) { uint num = 1u; do { num = (num << 1) | _decoders[num].Decode(rangeDecoder); } while (num < 256); return (byte)num; } public byte DecodeWithMatchByte(SharpCompress.Compressors.LZMA.RangeCoder.Decoder rangeDecoder, byte matchByte) { uint num = 1u; do { uint num2 = (uint)((matchByte >> 7) & 1); matchByte <<= 1; uint num3 = _decoders[(1 + num2 << 8) + num].Decode(rangeDecoder); num = (num << 1) | num3; if (num2 != num3) { while (num < 256) { num = (num << 1) | _decoders[num].Decode(rangeDecoder); } break; } } while (num < 256); return (byte)num; } } private Decoder2[] _coders; private int _numPrevBits; private int _numPosBits; private uint _posMask; public void Create(int numPosBits, int numPrevBits) { if (_coders == null || _numPrevBits != numPrevBits || _numPosBits != numPosBits) { _numPosBits = numPosBits; _posMask = (uint)((1 << numPosBits) - 1); _numPrevBits = numPrevBits; uint num = (uint)(1 << _numPrevBits + _numPosBits); _coders = new Decoder2[num]; for (uint num2 = 0u; num2 < num; num2++) { _coders[num2].Create(); } } } public void Init() { uint num = (uint)(1 << _numPrevBits + _numPosBits); for (uint num2 = 0u; num2 < num; num2++) { _coders[num2].Init(); } } private uint GetState(uint pos, byte prevByte) { return ((pos & _posMask) << _numPrevBits) + (uint)(prevByte >> 8 - _numPrevBits); } public byte DecodeNormal(SharpCompress.Compressors.LZMA.RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte) { return _coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); } public byte DecodeWithMatchByte(SharpCompress.Compressors.LZMA.RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte) { return _coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); } } private OutWindow _outWindow; private readonly BitDecoder[] _isMatchDecoders = new BitDecoder[192]; private readonly BitDecoder[] _isRepDecoders = new BitDecoder[12]; private readonly BitDecoder[] _isRepG0Decoders = new BitDecoder[12]; private readonly BitDecoder[] _isRepG1Decoders = new BitDecoder[12]; private readonly BitDecoder[] _isRepG2Decoders = new BitDecoder[12]; private readonly BitDecoder[] _isRep0LongDecoders = new BitDecoder[192]; private readonly BitTreeDecoder[] _posSlotDecoder = new BitTreeDecoder[4]; private readonly BitDecoder[] _posDecoders = new BitDecoder[114]; private BitTreeDecoder _posAlignDecoder = new BitTreeDecoder(4); private readonly LenDecoder _lenDecoder = new LenDecoder(); private readonly LenDecoder _repLenDecoder = new LenDecoder(); private readonly LiteralDecoder _literalDecoder = new LiteralDecoder(); private int _dictionarySize; private uint _posStateMask; private Base.State _state; private uint _rep0; private uint _rep1; private uint _rep2; private uint _rep3; public Decoder() { _dictionarySize = -1; for (int i = 0; (long)i < 4L; i++) { _posSlotDecoder[i] = new BitTreeDecoder(6); } } private void CreateDictionary() { if (_dictionarySize < 0) { throw new InvalidParamException(); } _outWindow = new OutWindow(); int windowSize = Math.Max(_dictionarySize, 4096); _outWindow.Create(windowSize); } private void SetLiteralProperties(int lp, int lc) { if (lp > 8) { throw new InvalidParamException(); } if (lc > 8) { throw new InvalidParamException(); } _literalDecoder.Create(lp, lc); } private void SetPosBitsProperties(int pb) { if (pb > 4) { throw new InvalidParamException(); } uint num = (uint)(1 << pb); _lenDecoder.Create(num); _repLenDecoder.Create(num); _posStateMask = num - 1; } private void Init() { for (uint num = 0u; num < 12; num++) { for (uint num2 = 0u; num2 <= _posStateMask; num2++) { uint num3 = (num << 4) + num2; _isMatchDecoders[num3].Init(); _isRep0LongDecoders[num3].Init(); } _isRepDecoders[num].Init(); _isRepG0Decoders[num].Init(); _isRepG1Decoders[num].Init(); _isRepG2Decoders[num].Init(); } _literalDecoder.Init(); for (uint num = 0u; num < 4; num++) { _posSlotDecoder[num].Init(); } for (uint num = 0u; num < 114; num++) { _posDecoders[num].Init(); } _lenDecoder.Init(); _repLenDecoder.Init(); _posAlignDecoder.Init(); _state.Init(); _rep0 = 0u; _rep1 = 0u; _rep2 = 0u; _rep3 = 0u; } public void Code(Stream inStream, Stream outStream, long inSize, long outSize, ICodeProgress progress) { if (_outWindow == null) { CreateDictionary(); } _outWindow.Init(outStream); if (outSize > 0) { _outWindow.SetLimit(outSize); } else { _outWindow.SetLimit(long.MaxValue - _outWindow._total); } SharpCompress.Compressors.LZMA.RangeCoder.Decoder decoder = new SharpCompress.Compressors.LZMA.RangeCoder.Decoder(); decoder.Init(inStream); Code(_dictionarySize, _outWindow, decoder); _outWindow.ReleaseStream(); decoder.ReleaseStream(); if (!decoder.IsFinished || (inSize > 0 && decoder._total != inSize)) { throw new DataErrorException(); } if (_outWindow.HasPending) { throw new DataErrorException(); } _outWindow = null; } internal bool Code(int dictionarySize, OutWindow outWindow, SharpCompress.Compressors.LZMA.RangeCoder.Decoder rangeDecoder) { int num = Math.Max(dictionarySize, 1); outWindow.CopyPending(); while (outWindow.HasSpace) { uint num2 = (uint)(int)outWindow._total & _posStateMask; if (_isMatchDecoders[(_state._index << 4) + num2].Decode(rangeDecoder) == 0) { byte prevByte = outWindow.GetByte(0); byte b = (_state.IsCharState() ? _literalDecoder.DecodeNormal(rangeDecoder, (uint)outWindow._total, prevByte) : _literalDecoder.DecodeWithMatchByte(rangeDecoder, (uint)outWindow._total, prevByte, outWindow.GetByte((int)_rep0))); outWindow.PutByte(b); _state.UpdateChar(); continue; } uint len; if (_isRepDecoders[_state._index].Decode(rangeDecoder) == 1) { if (_isRepG0Decoders[_state._index].Decode(rangeDecoder) == 0) { if (_isRep0LongDecoders[(_state._index << 4) + num2].Decode(rangeDecoder) == 0) { _state.UpdateShortRep(); outWindow.PutByte(outWindow.GetByte((int)_rep0)); continue; } } else { uint rep; if (_isRepG1Decoders[_state._index].Decode(rangeDecoder) == 0) { rep = _rep1; } else { if (_isRepG2Decoders[_state._index].Decode(rangeDecoder) == 0) { rep = _rep2; } else { rep = _rep3; _rep3 = _rep2; } _rep2 = _rep1; } _rep1 = _rep0; _rep0 = rep; } len = _repLenDecoder.Decode(rangeDecoder, num2) + 2; _state.UpdateRep(); } else { _rep3 = _rep2; _rep2 = _rep1; _rep1 = _rep0; len = 2 + _lenDecoder.Decode(rangeDecoder, num2); _state.UpdateMatch(); uint num3 = _posSlotDecoder[Base.GetLenToPosState(len)].Decode(rangeDecoder); if (num3 >= 4) { int num4 = (int)((num3 >> 1) - 1); _rep0 = (2 | (num3 & 1)) << num4; if (num3 < 14) { _rep0 += BitTreeDecoder.ReverseDecode(_posDecoders, _rep0 - num3 - 1, rangeDecoder, num4); } else { _rep0 += rangeDecoder.DecodeDirectBits(num4 - 4) << 4; _rep0 += _posAlignDecoder.ReverseDecode(rangeDecoder); } } else { _rep0 = num3; } } if (_rep0 >= outWindow._total || _rep0 >= num) { if (_rep0 == uint.MaxValue) { return true; } throw new DataErrorException(); } outWindow.CopyBlock((int)_rep0, (int)len); } return false; } public void SetDecoderProperties(byte[] properties) { if (properties.Length < 1) { throw new InvalidParamException(); } int lc = properties[0] % 9; int num = properties[0] / 9; int lp = num % 5; int num2 = num / 5; if (num2 > 4) { throw new InvalidParamException(); } SetLiteralProperties(lp, lc); SetPosBitsProperties(num2); Init(); if (properties.Length >= 5) { _dictionarySize = 0; for (int i = 0; i < 4; i++) { _dictionarySize += properties[1 + i] << i * 8; } } } public void Train(Stream stream) { if (_outWindow == null) { CreateDictionary(); } _outWindow.Train(stream); } } internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties { private enum EMatchFinderType { Bt2, Bt4 } private class LiteralEncoder { public struct Encoder2 { private BitEncoder[] _encoders; public void Create() { _encoders = new BitEncoder[768]; } public void Init() { for (int i = 0; i < 768; i++) { _encoders[i].Init(); } } public void Encode(SharpCompress.Compressors.LZMA.RangeCoder.Encoder rangeEncoder, byte symbol) { uint num = 1u; for (int num2 = 7; num2 >= 0; num2--) { uint num3 = (uint)((symbol >> num2) & 1); _encoders[num].Encode(rangeEncoder, num3); num = (num << 1) | num3; } } public void EncodeMatched(SharpCompress.Compressors.LZMA.RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol) { uint num = 1u; bool flag = true; for (int num2 = 7; num2 >= 0; num2--) { uint num3 = (uint)((symbol >> num2) & 1); uint num4 = num; if (flag) { uint num5 = (uint)((matchByte >> num2) & 1); num4 += 1 + num5 << 8; flag = num5 == num3; } _encoders[num4].Encode(rangeEncoder, num3); num = (num << 1) | num3; } } public uint GetPrice(bool matchMode, byte matchByte, byte symbol) { uint num = 0u; uint num2 = 1u; int num3 = 7; if (matchMode) { while (num3 >= 0) { uint num4 = (uint)((matchByte >> num3) & 1); uint num5 = (uint)((symbol >> num3) & 1); num += _encoders[(1 + num4 << 8) + num2].GetPrice(num5); num2 = (num2 << 1) | num5; if (num4 != num5) { num3--; break; } num3--; } } while (num3 >= 0) { uint num6 = (uint)((symbol >> num3) & 1); num += _encoders[num2].GetPrice(num6); num2 = (num2 << 1) | num6; num3--; } return num; } } private Encoder2[] _coders; private int _numPrevBits; private int _numPosBits; private uint _posMask; public void Create(int numPosBits, int numPrevBits) { if (_coders == null || _numPrevBits != numPrevBits || _numPosBits != numPosBits) { _numPosBits = numPosBits; _posMask = (uint)((1 << numPosBits) - 1); _numPrevBits = numPrevBits; uint num = (uint)(1 << _numPrevBits + _numPosBits); _coders = new Encoder2[num]; for (uint num2 = 0u; num2 < num; num2++) { _coders[num2].Create(); } } } public void Init() { uint num = (uint)(1 << _numPrevBits + _numPosBits); for (uint num2 = 0u; num2 < num; num2++) { _coders[num2].Init(); } } public Encoder2 GetSubCoder(uint pos, byte prevByte) { return _coders[(int)((pos & _posMask) << _numPrevBits) + (prevByte >> 8 - _numPrevBits)]; } } private class LenEncoder { private BitEncoder _choice; private BitEncoder _choice2; private readonly BitTreeEncoder[] _lowCoder = new BitTreeEncoder[16]; private readonly BitTreeEncoder[] _midCoder = new BitTreeEncoder[16]; private BitTreeEncoder _highCoder = new BitTreeEncoder(8); public LenEncoder() { for (uint num = 0u; num < 16; num++) { _lowCoder[num] = new BitTreeEncoder(3); _midCoder[num] = new BitTreeEncoder(3); } } public void Init(uint numPosStates) { _choice.Init(); _choice2.Init(); for (uint num = 0u; num < numPosStates; num++) { _lowCoder[num].Init(); _midCoder[num].Init(); } _highCoder.Init(); } public void Encode(SharpCompress.Compressors.LZMA.RangeCoder.Encoder rangeEncoder, uint symbol, uint posState) { if (symbol < 8) { _choice.Encode(rangeEncoder, 0u); _lowCoder[posState].Encode(rangeEncoder, symbol); return; } symbol -= 8; _choice.Encode(rangeEncoder, 1u); if (symbol < 8) { _choice2.Encode(rangeEncoder, 0u); _midCoder[posState].Encode(rangeEncoder, symbol); } else { _choice2.Encode(rangeEncoder, 1u); _highCoder.Encode(rangeEncoder, symbol - 8); } } public void SetPrices(uint posState, uint numSymbols, uint[] prices, uint st) { uint price = _choice.GetPrice0(); uint price2 = _choice.GetPrice1(); uint num = price2 + _choice2.GetPrice0(); uint num2 = price2 + _choice2.GetPrice1(); uint num3 = 0u; for (num3 = 0u; num3 < 8; num3++) { if (num3 >= numSymbols) { return; } prices[st + num3] = price + _lowCoder[posState].GetPrice(num3); } for (; num3 < 16; num3++) { if (num3 >= numSymbols) { return; } prices[st + num3] = num + _midCoder[posState].GetPrice(num3 - 8); } for (; num3 < numSymbols; num3++) { prices[st + num3] = num2 + _highCoder.GetPrice(num3 - 8 - 8); } } } private class LenPriceTableEncoder : LenEncoder { private readonly uint[] _prices = new uint[4352]; private uint _tableSize; private readonly uint[] _counters = new uint[16]; public void SetTableSize(uint tableSize) { _tableSize = tableSize; } public uint GetPrice(uint symbol, uint posState) { return _prices[posState * 272 + symbol]; } private void UpdateTable(uint posState) { SetPrices(posState, _tableSize, _prices, posState * 272); _counters[posState] = _tableSize; } public void UpdateTables(uint numPosStates) { for (uint num = 0u; num < numPosStates; num++) { UpdateTable(num); } } public new void Encode(SharpCompress.Compressors.LZMA.RangeCoder.Encoder rangeEncoder, uint symbol, uint posState) { base.Encode(rangeEncoder, symbol, posState); if (--_counters[posState] == 0) { UpdateTable(posState); } } } private class Optimal { public Base.State _state; public bool _prev1IsChar; public bool _prev2; public uint _posPrev2; public uint _backPrev2; public uint _price; public uint _posPrev; public uint _backPrev; public uint _backs0; public uint _backs1; public uint _backs2; public uint _backs3; public void MakeAsChar() { _backPrev = uint.MaxValue; _prev1IsChar = false; } public void MakeAsShortRep() { _backPrev = 0u; _prev1IsChar = false; } public bool IsShortRep() { return _backPrev == 0; } } private const uint K_IFINITY_PRICE = 268435455u; private static readonly byte[] G_FAST_POS; private Base.State _state; private byte _previousByte; private readonly uint[] _repDistances = new uint[4]; private const int K_DEFAULT_DICTIONARY_LOG_SIZE = 22; private const uint K_NUM_FAST_BYTES_DEFAULT = 32u; private const uint K_NUM_LEN_SPEC_SYMBOLS = 16u; private const uint K_NUM_OPTS = 4096u; private readonly Optimal[] _optimum = new Optimal[4096]; private BinTree _matchFinder; private readonly SharpCompress.Compressors.LZMA.RangeCoder.Encoder _rangeEncoder = new SharpCompress.Compressors.LZMA.RangeCoder.Encoder(); private readonly BitEncoder[] _isMatch = new BitEncoder[192]; private readonly BitEncoder[] _isRep = new BitEncoder[12]; private readonly BitEncoder[] _isRepG0 = new BitEncoder[12]; private readonly BitEncoder[] _isRepG1 = new BitEncoder[12]; private readonly BitEncoder[] _isRepG2 = new BitEncoder[12]; private readonly BitEncoder[] _isRep0Long = new BitEncoder[192]; private readonly BitTreeEncoder[] _posSlotEncoder = new BitTreeEncoder[4]; private readonly BitEncoder[] _posEncoders = new BitEncoder[114]; private BitTreeEncoder _posAlignEncoder = new BitTreeEncoder(4); private readonly LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder(); private readonly LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder(); private readonly LiteralEncoder _literalEncoder = new LiteralEncoder(); private readonly uint[] _matchDistances = new uint[548]; private uint _numFastBytes = 32u; private uint _longestMatchLength; private uint _numDistancePairs; private uint _additionalOffset; private uint _optimumEndIndex; private uint _optimumCurrentIndex; private bool _longestMatchWasFound; private readonly uint[] _posSlotPrices = new uint[256]; private readonly uint[] _distancesPrices = new uint[512]; private readonly uint[] _alignPrices = new uint[16]; private uint _alignPriceCount; private uint _distTableSize = 44u; private int _posStateBits = 2; private uint _posStateMask = 3u; private int _numLiteralPosStateBits; private int _numLiteralContextBits = 3; private uint _dictionarySize = 4194304u; private uint _dictionarySizePrev = uint.MaxValue; private uint _numFastBytesPrev = uint.MaxValue; private long _nowPos64; private bool _finished; private Stream _inStream; private EMatchFinderType _matchFinderType = EMatchFinderType.Bt4; private bool _writeEndMark; private bool _needReleaseMfStream; private bool _processingMode; private readonly uint[] _reps = new uint[4]; private readonly uint[] _repLens = new uint[4]; private const int K_PROP_SIZE = 5; private readonly byte[] _properties = new byte[5]; private readonly uint[] _tempPrices = new uint[128]; private uint _matchPriceCount; private static readonly string[] K_MATCH_FINDER_I_DS; private uint _trainSize; static Encoder() { G_FAST_POS = new byte[2048]; K_MATCH_FINDER_I_DS = new string[2] { "BT2", "BT4" }; int num = 2; G_FAST_POS[0] = 0; G_FAST_POS[1] = 1; for (byte b = 2; b < 22; b++) { uint num2 = (uint)(1 << (b >> 1) - 1); uint num3 = 0u; while (num3 < num2) { G_FAST_POS[num] = b; num3++; num++; } } } private static uint GetPosSlot(uint pos) { if (pos < 2048) { return G_FAST_POS[pos]; } if (pos < 2097152) { return (uint)(G_FAST_POS[pos >> 10] + 20); } return (uint)(G_FAST_POS[pos >> 20] + 40); } private static uint GetPosSlot2(uint pos) { if (pos < 131072) { return (uint)(G_FAST_POS[pos >> 6] + 12); } if (pos < 134217728) { return (uint)(G_FAST_POS[pos >> 16] + 32); } return (uint)(G_FAST_POS[pos >> 26] + 52); } private void BaseInit() { _state.Init(); _previousByte = 0; for (uint num = 0u; num < 4; num++) { _repDistances[num] = 0u; } } private void Create() { if (_matchFinder == null) { BinTree binTree = new BinTree(); int type = 4; if (_matchFinderType == EMatchFinderType.Bt2) { type = 2; } binTree.SetType(type); _matchFinder = binTree; } _literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits); if (_dictionarySize != _dictionarySizePrev || _numFastBytesPrev != _numFastBytes) { _matchFinder.Create(_dictionarySize, 4096u, _numFastBytes, 4370u); _dictionarySizePrev = _dictionarySize; _numFastBytesPrev = _numFastBytes; } } public Encoder() { for (int i = 0; (long)i < 4096L; i++) { _optimum[i] = new Optimal(); } for (int j = 0; (long)j < 4L; j++) { _posSlotEncoder[j] = new BitTreeEncoder(6); } } private void SetWriteEndMarkerMode(bool writeEndMarker) { _writeEndMark = writeEndMarker; } private void Init() { BaseInit(); _rangeEncoder.Init(); for (uint num = 0u; num < 12; num++) { for (uint num2 = 0u; num2 <= _posStateMask; num2++) { uint num3 = (num << 4) + num2; _isMatch[num3].Init(); _isRep0Long[num3].Init(); } _isRep[num].Init(); _isRepG0[num].Init(); _isRepG1[num].Init(); _isRepG2[num].Init(); } _literalEncoder.Init(); for (uint num = 0u; num < 4; num++) { _posSlotEncoder[num].Init(); } for (uint num = 0u; num < 114; num++) { _posEncoders[num].Init(); } _lenEncoder.Init((uint)(1 << _posStateBits)); _repMatchLenEncoder.Init((uint)(1 << _posStateBits)); _posAlignEncoder.Init(); _longestMatchWasFound = false; _optimumEndIndex = 0u; _optimumCurrentIndex = 0u; _additionalOffset = 0u; } private void ReadMatchDistances(out uint lenRes, out uint numDistancePairs) { lenRes = 0u; numDistancePairs = _matchFinder.GetMatches(_matchDistances); if (numDistancePairs != 0) { lenRes = _matchDistances[numDistancePairs - 2]; if (lenRes == _numFastBytes) { lenRes += _matchFinder.GetMatchLen((int)(lenRes - 1), _matchDistances[numDistancePairs - 1], 273 - lenRes); } } _additionalOffset++; } private void MovePos(uint num) { if (num != 0) { _matchFinder.Skip(num); _additionalOffset += num; } } private uint GetRepLen1Price(Base.State state, uint posState) { return _isRepG0[state._index].GetPrice0() + _isRep0Long[(state._index << 4) + posState].GetPrice0(); } private uint GetPureRepPrice(uint repIndex, Base.State state, uint posState) { uint price; if (repIndex == 0) { price = _isRepG0[state._index].GetPrice0(); return price + _isRep0Long[(state._index << 4) + posState].GetPrice1(); } price = _isRepG0[state._index].GetPrice1(); if (repIndex == 1) { return price + _isRepG1[state._index].GetPrice0(); } price += _isRepG1[state._index].GetPrice1(); return price + _isRepG2[state._index].GetPrice(repIndex - 2); } private uint GetRepPrice(uint repIndex, uint len, Base.State state, uint posState) { return _repMatchLenEncoder.GetPrice(len - 2, posState) + GetPureRepPrice(repIndex, state, posState); } private uint GetPosLenPrice(uint pos, uint len, uint posState) { uint lenToPosState = Base.GetLenToPosState(len); uint num = ((pos >= 128) ? (_posSlotPrices[(lenToPosState << 6) + GetPosSlot2(pos)] + _alignPrices[pos & 0xF]) : _distancesPrices[lenToPosState * 128 + pos]); return num + _lenEncoder.GetPrice(len - 2, posState); } private uint Backward(out uint backRes, uint cur) { _optimumEndIndex = cur; uint posPrev = _optimum[cur]._posPrev; uint backPrev = _optimum[cur]._backPrev; do { if (_optimum[cur]._prev1IsChar) { _optimum[posPrev].MakeAsChar(); _optimum[posPrev]._posPrev = posPrev - 1; if (_optimum[cur]._prev2) { _optimum[posPrev - 1]._prev1IsChar = false; _optimum[posPrev - 1]._posPrev = _optimum[cur]._posPrev2; _optimum[posPrev - 1]._backPrev = _optimum[cur]._backPrev2; } } uint num = posPrev; uint backPrev2 = backPrev; backPrev = _optimum[num]._backPrev; posPrev = _optimum[num]._posPrev; _optimum[num]._backPrev = backPrev2; _optimum[num]._posPrev = cur; cur = num; } while (cur != 0); backRes = _optimum[0]._backPrev; _optimumCurrentIndex = _optimum[0]._posPrev; return _optimumCurrentIndex; } private uint GetOptimum(uint position, out uint backRes) { if (_optimumEndIndex != _optimumCurrentIndex) { uint result = _optimum[_optimumCurrentIndex]._posPrev - _optimumCurrentIndex; backRes = _optimum[_optimumCurrentIndex]._backPrev; _optimumCurrentIndex = _optimum[_optimumCurrentIndex]._posPrev; return result; } _optimumCurrentIndex = (_optimumEndIndex = 0u); uint lenRes; uint numDistancePairs; if (!_longestMatchWasFound) { ReadMatchDistances(out lenRes, out numDistancePairs); } else { lenRes = _longestMatchLength; numDistancePairs = _numDistancePairs; _longestMatchWasFound = false; } uint num = _matchFinder.GetNumAvailableBytes() + 1; if (num < 2) { backRes = uint.MaxValue; return 1u; } if (num > 273) { num = 273u; } uint num2 = 0u; for (uint num3 = 0u; num3 < 4; num3++) { _reps[num3] = _repDistances[num3]; _repLens[num3] = _matchFinder.GetMatchLen(-1, _reps[num3], 273u); if (_repLens[num3] > _repLens[num2]) { num2 = num3; } } if (_repLens[num2] >= _numFastBytes) { backRes = num2; uint num4 = _repLens[num2]; MovePos(num4 - 1); return num4; } if (lenRes >= _numFastBytes) { backRes = _matchDistances[numDistancePairs - 1] + 4; MovePos(lenRes - 1); return lenRes; } byte indexByte = _matchFinder.GetIndexByte(-1); byte indexByte2 = _matchFinder.GetIndexByte((int)(0 - _repDistances[0] - 1 - 1)); if (lenRes < 2 && indexByte != indexByte2 && _repLens[num2] < 2) { backRes = uint.MaxValue; return 1u; } _optimum[0]._state = _state; uint num5 = position & _posStateMask; _optimum[1]._price = _isMatch[(_state._index << 4) + num5].GetPrice0() + _literalEncoder.GetSubCoder(position, _previousByte).GetPrice(!_state.IsCharState(), indexByte2, indexByte); _optimum[1].MakeAsChar(); uint price = _isMatch[(_state._index << 4) + num5].GetPrice1(); uint num6 = price + _isRep[_state._index].GetPrice1(); if (indexByte2 == indexByte) { uint num7 = num6 + GetRepLen1Price(_state, num5); if (num7 < _optimum[1]._price) { _optimum[1]._price = num7; _optimum[1].MakeAsShortRep(); } } uint num8 = ((lenRes >= _repLens[num2]) ? lenRes : _repLens[num2]); if (num8 < 2) { backRes = _optimum[1]._backPrev; return 1u; } _optimum[1]._posPrev = 0u; _optimum[0]._backs0 = _reps[0]; _optimum[0]._backs1 = _reps[1]; _optimum[0]._backs2 = _reps[2]; _optimum[0]._backs3 = _reps[3]; uint num9 = num8; do { _optimum[num9--]._price = 268435455u; } while (num9 >= 2); for (uint num3 = 0u; num3 < 4; num3++) { uint num10 = _repLens[num3]; if (num10 < 2) { continue; } uint num11 = num6 + GetPureRepPrice(num3, _state, num5); do { uint num12 = num11 + _repMatchLenEncoder.GetPrice(num10 - 2, num5); Optimal optimal = _optimum[num10]; if (num12 < optimal._price) { optimal._price = num12; optimal._posPrev = 0u; optimal._backPrev = num3; optimal._prev1IsChar = false; } } while (--num10 >= 2); } uint num13 = price + _isRep[_state._index].GetPrice0(); num9 = ((_repLens[0] >= 2) ? (_repLens[0] + 1) : 2u); if (num9 <= lenRes) { uint num14; for (num14 = 0u; num9 > _matchDistances[num14]; num14 += 2) { } while (true) { uint num15 = _matchDistances[num14 + 1]; uint num16 = num13 + GetPosLenPrice(num15, num9, num5); Optimal optimal2 = _optimum[num9]; if (num16 < optimal2._price) { optimal2._price = num16; optimal2._posPrev = 0u; optimal2._backPrev = num15 + 4; optimal2._prev1IsChar = false; } if (num9 == _matchDistances[num14]) { num14 += 2; if (num14 == numDistancePairs) { break; } } num9++; } } uint num17 = 0u; uint lenRes2; while (true) { num17++; if (num17 == num8) { return Backward(out backRes, num17); } ReadMatchDistances(out lenRes2, out numDistancePairs); if (lenRes2 >= _numFastBytes) { break; } position++; uint num18 = _optimum[num17]._posPrev; Base.State state; if (_optimum[num17]._prev1IsChar) { num18--; if (_optimum[num17]._prev2) { state = _optimum[_optimum[num17]._posPrev2]._state; if (_optimum[num17]._backPrev2 < 4) { state.UpdateRep(); } else { state.UpdateMatch(); } } else { state = _optimum[num18]._state; } state.UpdateChar(); } else { state = _optimum[num18]._state; } if (num18 == num17 - 1) { if (_optimum[num17].IsShortRep()) { state.UpdateShortRep(); } else { state.UpdateChar(); } } else { uint num19; if (_optimum[num17]._prev1IsChar && _optimum[num17]._prev2) { num18 = _optimum[num17]._posPrev2; num19 = _optimum[num17]._backPrev2; state.UpdateRep(); } else { num19 = _optimum[num17]._backPrev; if (num19 < 4) { state.UpdateRep(); } else { state.UpdateMatch(); } } Optimal optimal3 = _optimum[num18]; switch (num19) { case 0u: _reps[0] = optimal3._backs0; _reps[1] = optimal3._backs1; _reps[2] = optimal3._backs2; _reps[3] = optimal3._backs3; break; case 1u: _reps[0] = optimal3._backs1; _reps[1] = optimal3._backs0; _reps[2] = optimal3._backs2; _reps[3] = optimal3._backs3; break; case 2u: _reps[0] = optimal3._backs2; _reps[1] = optimal3._backs0; _reps[2] = optimal3._backs1; _reps[3] = optimal3._backs3; break; case 3u: _reps[0] = optimal3._backs3; _reps[1] = optimal3._backs0; _reps[2] = optimal3._backs1; _reps[3] = optimal3._backs2; break; default: _reps[0] = num19 - 4; _reps[1] = optimal3._backs0; _reps[2] = optimal3._backs1; _reps[3] = optimal3._backs2; break; } } _optimum[num17]._state = state; _optimum[num17]._backs0 = _reps[0]; _optimum[num17]._backs1 = _reps[1]; _optimum[num17]._backs2 = _reps[2]; _optimum[num17]._backs3 = _reps[3]; uint price2 = _optimum[num17]._price; indexByte = _matchFinder.GetIndexByte(-1); indexByte2 = _matchFinder.GetIndexByte((int)(0 - _reps[0] - 1 - 1)); num5 = position & _posStateMask; uint num20 = price2 + _isMatch[(state._index << 4) + num5].GetPrice0() + _literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(-2)).GetPrice(!state.IsCharState(), indexByte2, indexByte); Optimal optimal4 = _optimum[num17 + 1]; bool flag = false; if (num20 < optimal4._price) { optimal4._price = num20; optimal4._posPrev = num17; optimal4.MakeAsChar(); flag = true; } price = price2 + _isMatch[(state._index << 4) + num5].GetPrice1(); num6 = price + _isRep[state._index].GetPrice1(); if (indexByte2 == indexByte && (optimal4._posPrev >= num17 || optimal4._backPrev != 0)) { uint num21 = num6 + GetRepLen1Price(state, num5); if (num21 <= optimal4._price) { optimal4._price = num21; optimal4._posPrev = num17; optimal4.MakeAsShortRep(); flag = true; } } uint val = _matchFinder.GetNumAvailableBytes() + 1; val = Math.Min(4095 - num17, val); num = val; if (num < 2) { continue; } if (num > _numFastBytes) { num = _numFastBytes; } if (!flag && indexByte2 != indexByte) { uint limit = Math.Min(val - 1, _numFastBytes); uint matchLen = _matchFinder.GetMatchLen(0, _reps[0], limit); if (matchLen >= 2) { Base.State state2 = state; state2.UpdateChar(); uint num22 = (position + 1) & _posStateMask; uint num23 = num20 + _isMatch[(state2._index << 4) + num22].GetPrice1() + _isRep[state2._index].GetPrice1(); uint num24 = num17 + 1 + matchLen; while (num8 < num24) { _optimum[++num8]._price = 268435455u; } uint num25 = num23 + GetRepPrice(0u, matchLen, state2, num22); Optimal optimal5 = _optimum[num24]; if (num25 < optimal5._price) { optimal5._price = num25; optimal5._posPrev = num17 + 1; optimal5._backPrev = 0u; optimal5._prev1IsChar = true; optimal5._prev2 = false; } } } uint num26 = 2u; for (uint num27 = 0u; num27 < 4; num27++) { uint num28 = _matchFinder.GetMatchLen(-1, _reps[num27], num); if (num28 < 2) { continue; } uint num29 = num28; while (true) { if (num8 < num17 + num28) { _optimum[++num8]._price = 268435455u; continue; } uint num30 = num6 + GetRepPrice(num27, num28, state, num5); Optimal optimal6 = _optimum[num17 + num28]; if (num30 < optimal6._price) { optimal6._price = num30; optimal6._posPrev = num17; optimal6._backPrev = num27; optimal6._prev1IsChar = false; } if (--num28 < 2) { break; } } num28 = num29; if (num27 == 0) { num26 = num28 + 1; } if (num28 >= val) { continue; } uint limit2 = Math.Min(val - 1 - num28, _numFastBytes); uint matchLen2 = _matchFinder.GetMatchLen((int)num28, _reps[num27], limit2); if (matchLen2 >= 2) { Base.State state3 = state; state3.UpdateRep(); uint num31 = (position + num28) & _posStateMask; uint num32 = num6 + GetRepPrice(num27, num28, state, num5) + _isMatch[(state3._index << 4) + num31].GetPrice0() + _literalEncoder.GetSubCoder(position + num28, _matchFinder.GetIndexByte((int)(num28 - 1 - 1))).GetPrice(matchMode: true, _matchFinder.GetIndexByte((int)(num28 - 1 - (_reps[num27] + 1))), _matchFinder.GetIndexByte((int)(num28 - 1))); state3.UpdateChar(); num31 = (position + num28 + 1) & _posStateMask; uint num33 = num32 + _isMatch[(state3._index << 4) + num31].GetPrice1() + _isRep[state3._index].GetPrice1(); uint num34 = num28 + 1 + matchLen2; while (num8 < num17 + num34) { _optimum[++num8]._price = 268435455u; } uint num35 = num33 + GetRepPrice(0u, matchLen2, state3, num31); Optimal optimal7 = _optimum[num17 + num34]; if (num35 < optimal7._price) { optimal7._price = num35; optimal7._posPrev = num17 + num28 + 1; optimal7._backPrev = 0u; optimal7._prev1IsChar = true; optimal7._prev2 = true; optimal7._posPrev2 = num17; optimal7._backPrev2 = num27; } } } if (lenRes2 > num) { lenRes2 = num; for (numDistancePairs = 0u; lenRes2 > _matchDistances[numDistancePairs]; numDistancePairs += 2) { } _matchDistances[numDistancePairs] = lenRes2; numDistancePairs += 2; } if (lenRes2 < num26) { continue; } num13 = price + _isRep[state._index].GetPrice0(); while (num8 < num17 + lenRes2) { _optimum[++num8]._price = 268435455u; } uint num36; for (num36 = 0u; num26 > _matchDistances[num36]; num36 += 2) { } uint num37 = num26; while (true) { uint num38 = _matchDistances[num36 + 1]; uint num39 = num13 + GetPosLenPrice(num38, num37, num5); Optimal optimal8 = _optimum[num17 + num37]; if (num39 < optimal8._price) { optimal8._price = num39; optimal8._posPrev = num17; optimal8._backPrev = num38 + 4; optimal8._prev1IsChar = false; } if (num37 == _matchDistances[num36]) { if (num37 < val) { uint limit3 = Math.Min(val - 1 - num37, _numFastBytes); uint matchLen3 = _matchFinder.GetMatchLen((int)num37, num38, limit3); if (matchLen3 >= 2) { Base.State state4 = state; state4.UpdateMatch(); uint num40 = (position + num37) & _posStateMask; uint num41 = num39 + _isMatch[(state4._index << 4) + num40].GetPrice0() + _literalEncoder.GetSubCoder(position + num37, _matchFinder.GetIndexByte((int)(num37 - 1 - 1))).GetPrice(matchMode: true, _matchFinder.GetIndexByte((int)(num37 - (num38 + 1) - 1)), _matchFinder.GetIndexByte((int)(num37 - 1))); state4.UpdateChar(); num40 = (position + num37 + 1) & _posStateMask; uint num42 = num41 + _isMatch[(state4._index << 4) + num40].GetPrice1() + _isRep[state4._index].GetPrice1(); uint num43 = num37 + 1 + matchLen3; while (num8 < num17 + num43) { _optimum[++num8]._price = 268435455u; } num39 = num42 + GetRepPrice(0u, matchLen3, state4, num40); optimal8 = _optimum[num17 + num43]; if (num39 < optimal8._price) { optimal8._price = num39; optimal8._posPrev = num17 + num37 + 1; optimal8._backPrev = 0u; optimal8._prev1IsChar = true; optimal8._prev2 = true; optimal8._posPrev2 = num17; optimal8._backPrev2 = num38 + 4; } } } num36 += 2; if (num36 == numDistancePairs) { break; } } num37++; } } _numDistancePairs = numDistancePairs; _longestMatchLength = lenRes2; _longestMatchWasFound = true; return Backward(out backRes, num17); } private bool ChangePair(uint smallDist, uint bigDist) { if (smallDist < 33554432) { return bigDist >= smallDist << 7; } return false; } private void WriteEndMarker(uint posState) { if (_writeEndMark) { _isMatch[(_state._index << 4) + posState].Encode(_rangeEncoder, 1u); _isRep[_state._index].Encode(_rangeEncoder, 0u); _state.UpdateMatch(); uint num = 2u; _lenEncoder.Encode(_rangeEncoder, num - 2, posState); uint symbol = 63u; uint lenToPosState = Base.GetLenToPosState(num); _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, symbol); int num2 = 30; uint num3 = (uint)((1 << num2) - 1); _rangeEncoder.EncodeDirectBits(num3 >> 4, num2 - 4); _posAlignEncoder.ReverseEncode(_rangeEncoder, num3 & 0xF); } } private void Flush(uint nowPos) { ReleaseMfStream(); WriteEndMarker(nowPos & _posStateMask); _rangeEncoder.FlushData(); _rangeEncoder.FlushStream(); } public void CodeOneBlock(out long inSize, out long outSize, out bool finished) { inSize = 0L; outSize = 0L; finished = true; if (_inStream != null) { _matchFinder.SetStream(_inStream); _needReleaseMfStream = true; _inStream = null; } if (_finished) { return; } _finished = true; long nowPos = _nowPos64; if (_nowPos64 == 0L) { if (_trainSize != 0) { while (_trainSize != 0 && (!_processingMode || !_matchFinder.IsDataStarved)) { _matchFinder.Skip(1u); _trainSize--; } if (_trainSize == 0) { _previousByte = _matchFinder.GetIndexByte(-1); } } if (_processingMode && _matchFinder.IsDataStarved) { _finished = false; return; } if (_matchFinder.GetNumAvailableBytes() == 0) { Flush((uint)_nowPos64); return; } ReadMatchDistances(out var _, out var _); uint num = (uint)(int)_nowPos64 & _posStateMask; _isMatch[(_state._index << 4) + num].Encode(_rangeEncoder, 0u); _state.UpdateChar(); byte indexByte = _matchFinder.GetIndexByte((int)(0 - _additionalOffset)); _literalEncoder.GetSubCoder((uint)_nowPos64, _previousByte).Encode(_rangeEncoder, indexByte); _previousByte = indexByte; _additionalOffset--; _nowPos64++; } if (_processingMode && _matchFinder.IsDataStarved) { _finished = false; return; } if (_matchFinder.GetNumAvailableBytes() == 0) { Flush((uint)_nowPos64); return; } while (true) { if (_processingMode && _matchFinder.IsDataStarved) { _finished = false; return; } uint backRes; uint optimum = GetOptimum((uint)_nowPos64, out backRes); uint num2 = (uint)(int)_nowPos64 & _posStateMask; uint num3 = (_state._index << 4) + num2; if (optimum == 1 && backRes == uint.MaxValue) { _isMatch[num3].Encode(_rangeEncoder, 0u); byte indexByte2 = _matchFinder.GetIndexByte((int)(0 - _additionalOffset)); LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder((uint)_nowPos64, _previousByte); if (!_state.IsCharState()) { byte indexByte3 = _matchFinder.GetIndexByte((int)(0 - _repDistances[0] - 1 - _additionalOffset)); subCoder.EncodeMatched(_rangeEncoder, indexByte3, indexByte2); } else { subCoder.Encode(_rangeEncoder, indexByte2); } _previousByte = indexByte2; _state.UpdateChar(); } else { _isMatch[num3].Encode(_rangeEncoder, 1u); if (backRes < 4) { _isRep[_state._index].Encode(_rangeEncoder, 1u); if (backRes == 0) { _isRepG0[_state._index].Encode(_rangeEncoder, 0u); if (optimum == 1) { _isRep0Long[num3].Encode(_rangeEncoder, 0u); } else { _isRep0Long[num3].Encode(_rangeEncoder, 1u); } } else { _isRepG0[_state._index].Encode(_rangeEncoder, 1u); if (backRes == 1) { _isRepG1[_state._index].Encode(_rangeEncoder, 0u); } else { _isRepG1[_state._index].Encode(_rangeEncoder, 1u); _isRepG2[_state._index].Encode(_rangeEncoder, backRes - 2); } } if (optimum == 1) { _state.UpdateShortRep(); } else { _repMatchLenEncoder.Encode(_rangeEncoder, optimum - 2, num2); _state.UpdateRep(); } uint num4 = _repDistances[backRes]; if (backRes != 0) { for (uint num5 = backRes; num5 >= 1; num5--) { _repDistances[num5] = _repDistances[num5 - 1]; } _repDistances[0] = num4; } } else { _isRep[_state._index].Encode(_rangeEncoder, 0u); _state.UpdateMatch(); _lenEncoder.Encode(_rangeEncoder, optimum - 2, num2); backRes -= 4; uint posSlot = GetPosSlot(backRes); uint lenToPosState = Base.GetLenToPosState(optimum); _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot); if (posSlot >= 4) { int num6 = (int)((posSlot >> 1) - 1); uint num7 = (2 | (posSlot & 1)) << num6; uint num8 = backRes - num7; if (posSlot < 14) { BitTreeEncoder.ReverseEncode(_posEncoders, num7 - posSlot - 1, _rangeEncoder, num6, num8); } else { _rangeEncoder.EncodeDirectBits(num8 >> 4, num6 - 4); _posAlignEncoder.ReverseEncode(_rangeEncoder, num8 & 0xF); _alignPriceCount++; } } uint num9 = backRes; for (uint num10 = 3u; num10 >= 1; num10--) { _repDistances[num10] = _repDistances[num10 - 1]; } _repDistances[0] = num9; _matchPriceCount++; } _previousByte = _matchFinder.GetIndexByte((int)(optimum - 1 - _additionalOffset)); } _additionalOffset -= optimum; _nowPos64 += optimum; if (_additionalOffset == 0) { if (_matchPriceCount >= 128) { FillDistancesPrices(); } if (_alignPriceCount >= 16) { FillAlignPrices(); } inSize = _nowPos64; outSize = _rangeEncoder.GetProcessedSizeAdd(); if (_processingMode && _matchFinder.IsDataStarved) { _finished = false; return; } if (_matchFinder.GetNumAvailableBytes() == 0) { Flush((uint)_nowPos64); return; } if (_nowPos64 - nowPos >= 4096) { break; } } } _finished = false; finished = false; } private void ReleaseMfStream() { if (_matchFinder != null && _needReleaseMfStream) { _matchFinder.ReleaseStream(); _needReleaseMfStream = false; } } private void SetOutStream(Stream outStream) { _rangeEncoder.SetStream(outStream); } private void ReleaseOutStream() { _rangeEncoder.ReleaseStream(); } private void ReleaseStreams() { ReleaseMfStream(); ReleaseOutStream(); } public void SetStreams(Stream inStream, Stream outStream, long inSize, long outSize) { _inStream = inStream; _finished = false; Create(); SetOutStream(outStream); Init(); _matchFinder.Init(); FillDistancesPrices(); FillAlignPrices(); _lenEncoder.SetTableSize(_numFastBytes + 1 - 2); _lenEncoder.UpdateTables((uint)(1 << _posStateBits)); _repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - 2); _repMatchLenEncoder.UpdateTables((uint)(1 << _posStateBits)); _nowPos64 = 0L; } public void Code(Stream inStream, Stream outStream, long inSize, long outSize, ICodeProgress progress) { _needReleaseMfStream = false; _processingMode = false; try { SetStreams(inStream, outStream, inSize, outSize); while (true) { CodeOneBlock(out var inSize2, out var outSize2, out var finished); if (finished) { break; } progress?.SetProgress(inSize2, outSize2); } } finally { ReleaseStreams(); } } public long Code(Stream inStream, bool final) { _matchFinder.SetStream(inStream); _processingMode = !final; try { long inSize; bool finished; do { CodeOneBlock(out inSize, out var _, out finished); } while (!finished); return inSize; } finally { _matchFinder.ReleaseStream(); if (final) { ReleaseStreams(); } } } public void Train(Stream trainStream) { if (_nowPos64 > 0) { throw new InvalidOperationException(); } _trainSize = (uint)trainStream.Length; if (_trainSize != 0) { _matchFinder.SetStream(trainStream); while (_trainSize != 0 && !_matchFinder.IsDataStarved) { _matchFinder.Skip(1u); _trainSize--; } if (_trainSize == 0) { _previousByte = _matchFinder.GetIndexByte(-1); } _matchFinder.ReleaseStream(); } } public void WriteCoderProperties(Stream outStream) { _properties[0] = (byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits); for (int i = 0; i < 4; i++) { _properties[1 + i] = (byte)((_dictionarySize >> 8 * i) & 0xFF); } outStream.Write(_properties, 0, 5); } private void FillDistancesPrices() { for (uint num = 4u; num < 128; num++) { uint posSlot = GetPosSlot(num); int num2 = (int)((posSlot >> 1) - 1); uint num3 = (2 | (posSlot & 1)) << num2; _tempPrices[num] = BitTreeEncoder.ReverseGetPrice(_posEncoders, num3 - posSlot - 1, num2, num - num3); } for (uint num4 = 0u; num4 < 4; num4++) { BitTreeEncoder bitTreeEncoder = _posSlotEncoder[num4]; uint num5 = num4 << 6; for (uint num6 = 0u; num6 < _distTableSize; num6++) { _posSlotPrices[num5 + num6] = bitTreeEncoder.GetPrice(num6); } for (uint num6 = 14u; num6 < _distTableSize; num6++) { _posSlotPrices[num5 + num6] += (num6 >> 1) - 1 - 4 << 6; } uint num7 = num4 * 128; uint num8; for (num8 = 0u; num8 < 4; num8++) { _distancesPrices[num7 + num8] = _posSlotPrices[num5 + num8]; } for (; num8 < 128; num8++) { _distancesPrices[num7 + num8] = _posSlotPrices[num5 + GetPosSlot(num8)] + _tempPrices[num8]; } } _matchPriceCount = 0u; } private void FillAlignPrices() { for (uint num = 0u; num < 16; num++) { _alignPrices[num] = _posAlignEncoder.ReverseGetPrice(num); } _alignPriceCount = 0u; } private static int FindMatchFinder(string s) { for (int i = 0; i < K_MATCH_FINDER_I_DS.Length; i++) { if (s == K_MATCH_FINDER_I_DS[i]) { return i; } } return -1; } public void SetCoderProperties(CoderPropId[] propIDs, object[] properties) { for (uint num = 0u; num < properties.Length; num++) { object obj = properties[num]; switch (propIDs[num]) { case CoderPropId.NumFastBytes: if (!(obj is int num2)) { throw new InvalidParamException(); } if (num2 < 5 || (long)num2 > 273L) { throw new InvalidParamException(); } _numFastBytes = (uint)num2; break; case CoderPropId.MatchFinder: { if (!(obj is string)) { throw new InvalidParamException(); } EMatchFinderType matchFinderType = _matchFinderType; int num6 = FindMatchFinder(((string)obj).ToUpper()); if (num6 < 0) { throw new InvalidParamException(); } _matchFinderType = (EMatchFinderType)num6; if (_matchFinder != null && matchFinderType != _matchFinderType) { _dictionarySizePrev = uint.MaxValue; _matchFinder = null; } break; } case CoderPropId.DictionarySize: { if (!(obj is int num7)) { throw new InvalidParamException(); } if ((long)num7 < 1L || (long)num7 > 1073741824L) { throw new InvalidParamException(); } _dictionarySize = (uint)num7; int i; for (i = 0; (long)i < 30L && num7 > (uint)(1 << i); i++) { } _distTableSize = (uint)(i * 2); break; } case CoderPropId.PosStateBits: if (!(obj is int num3)) { throw new InvalidParamException(); } if (num3 < 0 || (long)num3 > 4L) { throw new InvalidParamException(); } _posStateBits = num3; _posStateMask = (uint)((1 << _posStateBits) - 1); break; case CoderPropId.LitPosBits: if (!(obj is int num5)) { throw new InvalidParamException(); } if (num5 < 0 || (long)num5 > 4L) { throw new InvalidParamException(); } _numLiteralPosStateBits = num5; break; case CoderPropId.LitContextBits: if (!(obj is int num4)) { throw new InvalidParamException(); } if (num4 < 0 || (long)num4 > 8L) { throw new InvalidParamException(); } _numLiteralContextBits = num4; break; case CoderPropId.EndMarker: if (!(obj is bool)) { throw new InvalidParamException(); } SetWriteEndMarkerMode((bool)obj); break; default: throw new InvalidParamException(); case CoderPropId.Algorithm: break; } } } public void SetTrainSize(uint trainSize) { _trainSize = trainSize; } } public class LzmaEncoderProperties { internal CoderPropId[] _propIDs; internal object[] _properties; public LzmaEncoderProperties() : this(eos: false) { } public LzmaEncoderProperties(bool eos) : this(eos, 1048576) { } public LzmaEncoderProperties(bool eos, int dictionary) : this(eos, dictionary, 32) { } public LzmaEncoderProperties(bool eos, int dictionary, int numFastBytes) { int num = 2; int num2 = 3; int num3 = 0; int num4 = 2; string text = "bt4"; _propIDs = new CoderPropId[8] { CoderPropId.DictionarySize, CoderPropId.PosStateBits, CoderPropId.LitContextBits, CoderPropId.LitPosBits, CoderPropId.Algorithm, CoderPropId.NumFastBytes, CoderPropId.MatchFinder, CoderPropId.EndMarker }; _properties = new object[8] { dictionary, num, num2, num3, num4, numFastBytes, text, eos }; } } public class LzmaStream : Stream { private readonly Stream _inputStream; private readonly long _inputSize; private readonly long _outputSize; private readonly int _dictionarySize; private readonly OutWindow _outWindow = new OutWindow(); private readonly SharpCompress.Compressors.LZMA.RangeCoder.Decoder _rangeDecoder = new SharpCompress.Compressors.LZMA.RangeCoder.Decoder(); private Decoder _decoder; private long _position; private bool _endReached; private long _availableBytes; private long _rangeDecoderLimit; private long _inputPosition; private readonly bool _isLzma2; private bool _uncompressedChunk; private bool _needDictReset = true; private bool _needProps = true; private readonly Encoder _encoder; private bool _isDisposed; public override bool CanRead => _encoder == null; public override bool CanSeek => false; public override bool CanWrite => _encoder != null; public override long Length => _position + _availableBytes; public override long Position { get { return _position; } set { throw new NotSupportedException(); } } public byte[] Properties { get; } = new byte[5]; public LzmaStream(byte[] properties, Stream inputStream) : this(properties, inputStream, -1L, -1L, null, properties.Length < 5) { } public LzmaStream(byte[] properties, Stream inputStream, long inputSize) : this(properties, inputStream, inputSize, -1L, null, properties.Length < 5) { } public LzmaStream(byte[] properties, Stream inputStream, long inputSize, long outputSize) : this(properties, inputStream, inputSize, outputSize, null, properties.Length < 5) { } public LzmaStream(byte[] properties, Stream inputStream, long inputSize, long outputSize, Stream presetDictionary, bool isLzma2) { _inputStream = inputStream; _inputSize = inputSize; _outputSize = outputSize; _isLzma2 = isLzma2; if (!isLzma2) { _dictionarySize = DataConverter.LittleEndian.GetInt32(properties, 1); _outWindow.Create(_dictionarySize); if (presetDictionary != null) { _outWindow.Train(presetDictionary); } _rangeDecoder.Init(inputStream); _decoder = new Decoder(); _decoder.SetDecoderProperties(properties); Properties = properties; _availableBytes = ((outputSize < 0) ? long.MaxValue : outputSize); _rangeDecoderLimit = inputSize; } else { _dictionarySize = 2 | (properties[0] & 1); _dictionarySize <<= (properties[0] >> 1) + 11; _outWindow.Create(_dictionarySize); if (presetDictionary != null) { _outWindow.Train(presetDictionary); _needDictReset = false; } Properties = new byte[1]; _availableBytes = 0L; } } public LzmaStream(LzmaEncoderProperties properties, bool isLzma2, Stream outputStream) : this(properties, isLzma2, null, outputStream) { } public LzmaStream(LzmaEncoderProperties properties, bool isLzma2, Stream presetDictionary, Stream outputStream) { _isLzma2 = isLzma2; _availableBytes = 0L; _endReached = true; if (isLzma2) { throw new NotImplementedException(); } _encoder = new Encoder(); _encoder.SetCoderProperties(properties._propIDs, properties._properties); MemoryStream memoryStream = new MemoryStream(5); _encoder.WriteCoderProperties(memoryStream); Properties = memoryStream.ToArray(); _encoder.SetStreams(null, outputStream, -1L, -1L); if (presetDictionary != null) { _encoder.Train(presetDictionary); } } public override void Flush() { } protected override void Dispose(bool disposing) { if (_isDisposed) { return; } _isDisposed = true; if (disposing) { if (_encoder != null) { _position = _encoder.Code(null, final: true); } _inputStream?.Dispose(); } base.Dispose(disposing); } public override int Read(byte[] buffer, int offset, int count) { if (_endReached) { return 0; } int num = 0; while (num < count) { if (_availableBytes == 0L) { if (_isLzma2) { DecodeChunkHeader(); } else { _endReached = true; } if (_endReached) { break; } } int num2 = count - num; if (num2 > _availableBytes) { num2 = (int)_availableBytes; } _outWindow.SetLimit(num2); if (_uncompressedChunk) { _inputPosition += _outWindow.CopyStream(_inputStream, num2); } else if (_decoder.Code(_dictionarySize, _outWindow, _rangeDecoder) && _outputSize < 0) { _availableBytes = _outWindow.AvailableBytes; } int num3 = _outWindow.Read(buffer, offset, num2); num += num3; offset += num3; _position += num3; _availableBytes -= num3; if (_availableBytes == 0L && !_uncompressedChunk) { _rangeDecoder.ReleaseStream(); if (!_rangeDecoder.IsFinished || (_rangeDecoderLimit >= 0 && _rangeDecoder._total != _rangeDecoderLimit)) { throw new DataErrorException(); } _inputPosition += _rangeDecoder._total; if (_outWindow.HasPending) { throw new DataErrorException(); } } } if (_endReached) { if (_inputSize >= 0 && _inputPosition != _inputSize) { throw new DataErrorException(); } if (_outputSize >= 0 && _position != _outputSize) { throw new DataErrorException(); } } return num; } private void DecodeChunkHeader() { int num = _inputStream.ReadByte(); _inputPosition++; if (num == 0) { _endReached = true; return; } if (num >= 224 || num == 1) { _needProps = true; _needDictReset = false; _outWindow.Reset(); } else if (_needDictReset) { throw new DataErrorException(); } if (num >= 128) { _uncompressedChunk = false; _availableBytes = (num & 0x1F) << 16; _availableBytes += (_inputStream.ReadByte() << 8) + _inputStream.ReadByte() + 1; _inputPosition += 2L; _rangeDecoderLimit = (_inputStream.ReadByte() << 8) + _inputStream.ReadByte() + 1; _inputPosition += 2L; if (num >= 192) { _needProps = false; Properties[0] = (byte)_inputStream.ReadByte(); _inputPosition++; _decoder = new Decoder(); _decoder.SetDecoderProperties(Properties); } else { if (_needProps) { throw new DataErrorException(); } if (num >= 160) { _decoder = new Decoder(); _decoder.SetDecoderProperties(Properties); } } _rangeDecoder.Init(_inputStream); } else { if (num > 2) { throw new DataErrorException(); } _uncompressedChunk = true; _availableBytes = (_inputStream.ReadByte() << 8) + _inputStream.ReadByte() + 1; _inputPosition += 2L; } } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { if (_encoder != null) { _position = _encoder.Code(new MemoryStream(buffer, offset, count), final: false); } } } internal static class DecoderRegistry { private const uint K_COPY = 0u; private const uint K_DELTA = 3u; private const uint K_LZMA2 = 33u; private const uint K_LZMA = 196865u; private const uint K_PPMD = 197633u; private const uint K_BCJ = 50528515u; private const uint K_BCJ2 = 50528539u; private const uint K_DEFLATE = 262408u; private const uint K_B_ZIP2 = 262658u; internal static Stream CreateDecoderStream(CMethodId id, Stream[] inStreams, byte[] info, IPasswordProvider pass, long limit) { switch (id._id) { case 0uL: if (info != null) { throw new NotSupportedException(); } return inStreams.Single(); case 33uL: case 196865uL: return new LzmaStream(info, inStreams.Single(), -1L, limit); case 116459265uL: return new AesDecoderStream(inStreams.Single(), info, pass, limit); case 50528515uL: return new BCJFilter(isEncoder: false, inStreams.Single()); case 50528539uL: return new Bcj2DecoderStream(inStreams, info, limit); case 262658uL: return new BZip2Stream(inStreams.Single(), CompressionMode.Decompress, decompressConcatenated: true); case 197633uL: return new PpmdStream(new PpmdProperties(info), inStreams.Single(), compress: false); case 262408uL: return new DeflateStream(inStreams.Single(), CompressionMode.Decompress); default: throw new NotSupportedException(); } } } } namespace SharpCompress.Compressors.LZMA.Utilites { internal class CrcBuilderStream : Stream { private readonly Stream _mTarget; private uint _mCrc; private bool _mFinished; private bool _isDisposed; public long Processed { get; private set; } public override bool CanRead => false; public override bool CanSeek => false; public override bool CanWrite => true; public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } public CrcBuilderStream(Stream target) { _mTarget = target; _mCrc = uint.MaxValue; } protected override void Dispose(bool disposing) { if (!_isDisposed) { _isDisposed = true; _mTarget.Dispose(); base.Dispose(disposing); } } public uint Finish() { if (!_mFinished) { _mFinished = true; _mCrc = Crc.Finish(_mCrc); } return _mCrc; } public override void Flush() { } public override int Read(byte[] buffer, int offset, int count) { throw new InvalidOperationException(); } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { if (_mFinished) { throw new InvalidOperationException("CRC calculation has been finished."); } Processed += count; _mCrc = Crc.Update(_mCrc, buffer, offset, count); _mTarget.Write(buffer, offset, count); } } internal class CrcCheckStream : Stream { private readonly uint _mExpectedCrc; private uint _mCurrentCrc; private bool _mClosed; private readonly long[] _mBytes = new long[256]; private long _mLength; public override bool CanRead => false; public override bool CanSeek => false; public override bool CanWrite => true; public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } public CrcCheckStream(uint crc) { _mExpectedCrc = crc; _mCurrentCrc = uint.MaxValue; } protected override void Dispose(bool disposing) { if (_mCurrentCrc != _mExpectedCrc) { throw new InvalidOperationException(); } try { if (disposing && !_mClosed) { _mClosed = true; _mCurrentCrc = Crc.Finish(_mCurrentCrc); } } finally { base.Dispose(disposing); } } public override void Flush() { } public override int Read(byte[] buffer, int offset, int count) { throw new InvalidOperationException(); } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { _mLength += count; for (int i = 0; i < count; i++) { _mBytes[buffer[offset + i]]++; } _mCurrentCrc = Crc.Update(_mCurrentCrc, buffer, offset, count); } } internal interface IPasswordProvider { string CryptoGetTextPassword(); } internal enum BlockType : byte { End, Header, ArchiveProperties, AdditionalStreamsInfo, MainStreamsInfo, FilesInfo, PackInfo, UnpackInfo, SubStreamsInfo, Size, Crc, Folder, CodersUnpackSize, NumUnpackStream, EmptyStream, EmptyFile, Anti, Name, CTime, ATime, MTime, WinAttributes, Comment, EncodedHeader, StartPos, Dummy } internal static class Utils { [Conditional("DEBUG")] public static void Assert(bool expression) { if (!expression) { if (Debugger.IsAttached) { Debugger.Break(); } throw new Exception("Assertion failed."); } } public static void ReadExact(this Stream stream, byte[] buffer, int offset, int length) { if (stream == null) { throw new ArgumentNullException("stream"); } if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0 || offset > buffer.Length) { throw new ArgumentOutOfRangeException("offset"); } if (length < 0 || length > buffer.Length - offset) { throw new ArgumentOutOfRangeException("length"); } while (length > 0) { int num = stream.Read(buffer, offset, length); if (num <= 0) { throw new EndOfStreamException(); } offset += num; length -= num; } } } } namespace SharpCompress.Compressors.LZMA.RangeCoder { internal class Encoder { public const uint K_TOP_VALUE = 16777216u; private Stream _stream; public ulong _low; public uint _range; private uint _cacheSize; private byte _cache; public void SetStream(Stream stream) { _stream = stream; } public void ReleaseStream() { _stream = null; } public void Init() { _low = 0uL; _range = uint.MaxValue; _cacheSize = 1u; _cache = 0; } public void FlushData() { for (int i = 0; i < 5; i++) { ShiftLow(); } } public void FlushStream() { _stream.Flush(); } public void CloseStream() { _stream.Dispose(); } public void Encode(uint start, uint size, uint total) { _low += start * (_range /= total); _range *= size; while (_range < 16777216) { _range <<= 8; ShiftLow(); } } public void ShiftLow() { if ((uint)_low < 4278190080u || (int)(_low >> 32) == 1) { byte b = _cache; do { _stream.WriteByte((byte)(b + (_low >> 32))); b = byte.MaxValue; } while (--_cacheSize != 0); _cache = (byte)((uint)_low >> 24); } _cacheSize++; _low = (uint)((int)_low << 8); } public void EncodeDirectBits(uint v, int numTotalBits) { for (int num = numTotalBits - 1; num >= 0; num--) { _range >>= 1; if (((v >> num) & 1) == 1) { _low += _range; } if (_range < 16777216) { _range <<= 8; ShiftLow(); } } } public void EncodeBit(uint size0, int numTotalBits, uint symbol) { uint num = (_range >> numTotalBits) * size0; if (symbol == 0) { _range = num; } else { _low += num; _range -= num; } while (_range < 16777216) { _range <<= 8; ShiftLow(); } } public long GetProcessedSizeAdd() { return -1L; } } internal class Decoder { public const uint K_TOP_VALUE = 16777216u; public uint _range; public uint _code; public Stream _stream; public long _total; public bool IsFinished => _code == 0; public void Init(Stream stream) { _stream = stream; _code = 0u; _range = uint.MaxValue; for (int i = 0; i < 5; i++) { _code = (_code << 8) | (byte)_stream.ReadByte(); } _total = 5L; } public void ReleaseStream() { _stream = null; } public void CloseStream() { _stream.Dispose(); } public void Normalize() { while (_range < 16777216) { _code = (_code << 8) | (byte)_stream.ReadByte(); _range <<= 8; _total++; } } public void Normalize2() { if (_range < 16777216) { _code = (_code << 8) | (byte)_stream.ReadByte(); _range <<= 8; _total++; } } public uint GetThreshold(uint total) { return _code / (_range /= total); } public void Decode(uint start, uint size) { _code -= start * _range; _range *= size; Normalize(); } public uint DecodeDirectBits(int numTotalBits) { uint num = _range; uint num2 = _code; uint num3 = 0u; for (int num4 = numTotalBits; num4 > 0; num4--) { num >>= 1; uint num5 = num2 - num >> 31; num2 -= num & (num5 - 1); num3 = (num3 << 1) | (1 - num5); if (num < 16777216) { num2 = (num2 << 8) | (byte)_stream.ReadByte(); num <<= 8; _total++; } } _range = num; _code = num2; return num3; } public uint DecodeBit(uint size0, int numTotalBits) { uint num = (_range >> numTotalBits) * size0; uint result; if (_code < num) { result = 0u; _range = num; } else { result = 1u; _code -= num; _range -= num; } Normalize(); return result; } } internal struct BitEncoder { public const int K_NUM_BIT_MODEL_TOTAL_BITS = 11; public const uint K_BIT_MODEL_TOTAL = 2048u; private const int K_NUM_MOVE_BITS = 5; private const int K_NUM_MOVE_REDUCING_BITS = 2; public const int K_NUM_BIT_PRICE_SHIFT_BITS = 6; private uint _prob; private static readonly uint[] PROB_PRICES; public void Init() { _prob = 1024u; } public void UpdateModel(uint symbol) { if (symbol == 0) { _prob += 2048 - _prob >> 5; } else { _prob -= _prob >> 5; } } public void Encode(Encoder encoder, uint symbol) { uint num = (encoder._range >> 11) * _prob; if (symbol == 0) { encoder._range = num; _prob += 2048 - _prob >> 5; } else { encoder._low += num; encoder._range -= num; _prob -= _prob >> 5; } if (encoder._range < 16777216) { encoder._range <<= 8; encoder.ShiftLow(); } } static BitEncoder() { PROB_PRICES = new uint[512]; for (int num = 8; num >= 0; num--) { int num2 = 1 << 9 - num - 1; uint num3 = (uint)(1 << 9 - num); for (uint num4 = (uint)num2; num4 < num3; num4++) { PROB_PRICES[num4] = (uint)(num << 6) + (num3 - num4 << 6 >> 9 - num - 1); } } } public uint GetPrice(uint symbol) { return PROB_PRICES[(((_prob - symbol) ^ (int)(0 - symbol)) & 0x7FF) >> 2]; } public uint GetPrice0() { return PROB_PRICES[_prob >> 2]; } public uint GetPrice1() { return PROB_PRICES[2048 - _prob >> 2]; } } internal struct BitDecoder { public const int K_NUM_BIT_MODEL_TOTAL_BITS = 11; public const uint K_BIT_MODEL_TOTAL = 2048u; private const int K_NUM_MOVE_BITS = 5; private uint _prob; public void UpdateModel(int numMoveBits, uint symbol) { if (symbol == 0) { _prob += 2048 - _prob >> numMoveBits; } else { _prob -= _prob >> numMoveBits; } } public void Init() { _prob = 1024u; } public uint Decode(Decoder rangeDecoder) { uint num = (rangeDecoder._range >> 11) * _prob; if (rangeDecoder._code < num) { rangeDecoder._range = num; _prob += 2048 - _prob >> 5; if (rangeDecoder._range < 16777216) { rangeDecoder._code = (rangeDecoder._code << 8) | (byte)rangeDecoder._stream.ReadByte(); rangeDecoder._range <<= 8; rangeDecoder._total++; } return 0u; } rangeDecoder._range -= num; rangeDecoder._code -= num; _prob -= _prob >> 5; if (rangeDecoder._range < 16777216) { rangeDecoder._code = (rangeDecoder._code << 8) | (byte)rangeDecoder._stream.ReadByte(); rangeDecoder._range <<= 8; rangeDecoder._total++; } return 1u; } } internal struct BitTreeEncoder { private readonly BitEncoder[] _models; private readonly int _numBitLevels; public BitTreeEncoder(int numBitLevels) { _numBitLevels = numBitLevels; _models = new BitEncoder[1 << numBitLevels]; } public void Init() { for (uint num = 1u; num < 1 << _numBitLevels; num++) { _models[num].Init(); } } public void Encode(Encoder rangeEncoder, uint symbol) { uint num = 1u; int num2 = _numBitLevels; while (num2 > 0) { num2--; uint num3 = (symbol >> num2) & 1; _models[num].Encode(rangeEncoder, num3); num = (num << 1) | num3; } } public void ReverseEncode(Encoder rangeEncoder, uint symbol) { uint num = 1u; for (uint num2 = 0u; num2 < _numBitLevels; num2++) { uint num3 = symbol & 1; _models[num].Encode(rangeEncoder, num3); num = (num << 1) | num3; symbol >>= 1; } } public uint GetPrice(uint symbol) { uint num = 0u; uint num2 = 1u; int num3 = _numBitLevels; while (num3 > 0) { num3--; uint num4 = (symbol >> num3) & 1; num += _models[num2].GetPrice(num4); num2 = (num2 << 1) + num4; } return num; } public uint ReverseGetPrice(uint symbol) { uint num = 0u; uint num2 = 1u; for (int num3 = _numBitLevels; num3 > 0; num3--) { uint num4 = symbol & 1; symbol >>= 1; num += _models[num2].GetPrice(num4); num2 = (num2 << 1) | num4; } return num; } public static uint ReverseGetPrice(BitEncoder[] models, uint startIndex, int numBitLevels, uint symbol) { uint num = 0u; uint num2 = 1u; for (int num3 = numBitLevels; num3 > 0; num3--) { uint num4 = symbol & 1; symbol >>= 1; num += models[startIndex + num2].GetPrice(num4); num2 = (num2 << 1) | num4; } return num; } public static void ReverseEncode(BitEncoder[] models, uint startIndex, Encoder rangeEncoder, int numBitLevels, uint symbol) { uint num = 1u; for (int i = 0; i < numBitLevels; i++) { uint num2 = symbol & 1; models[startIndex + num].Encode(rangeEncoder, num2); num = (num << 1) | num2; symbol >>= 1; } } } internal struct BitTreeDecoder { private readonly BitDecoder[] _models; private readonly int _numBitLevels; public BitTreeDecoder(int numBitLevels) { _numBitLevels = numBitLevels; _models = new BitDecoder[1 << numBitLevels]; } public void Init() { for (uint num = 1u; num < 1 << _numBitLevels; num++) { _models[num].Init(); } } public uint Decode(Decoder rangeDecoder) { uint num = 1u; for (int num2 = _numBitLevels; num2 > 0; num2--) { num = (num << 1) + _models[num].Decode(rangeDecoder); } return num - (uint)(1 << _numBitLevels); } public uint ReverseDecode(Decoder rangeDecoder) { uint num = 1u; uint num2 = 0u; for (int i = 0; i < _numBitLevels; i++) { uint num3 = _models[num].Decode(rangeDecoder); num <<= 1; num += num3; num2 |= num3 << i; } return num2; } public static uint ReverseDecode(BitDecoder[] models, uint startIndex, Decoder rangeDecoder, int numBitLevels) { uint num = 1u; uint num2 = 0u; for (int i = 0; i < numBitLevels; i++) { uint num3 = models[startIndex + num].Decode(rangeDecoder); num <<= 1; num += num3; num2 |= num3 << i; } return num2; } } } namespace SharpCompress.Compressors.LZMA.LZ { internal class BinTree : InWindow { private uint _cyclicBufferPos; private uint _cyclicBufferSize; private uint _matchMaxLen; private uint[] _son; private uint[] _hash; private uint _cutValue = 255u; private uint _hashMask; private uint _hashSizeSum; private bool _hashArray = true; private const uint K_HASH2_SIZE = 1024u; private const uint K_HASH3_SIZE = 65536u; private const uint K_BT2_HASH_SIZE = 65536u; private const uint K_START_MAX_LEN = 1u; private const uint K_HASH3_OFFSET = 1024u; private const uint K_EMPTY_HASH_VALUE = 0u; private const uint K_MAX_VAL_FOR_NORMALIZE = 2147483647u; private uint _kNumHashDirectBytes; private uint _kMinMatchCheck = 4u; private uint _kFixHashSize = 66560u; public void SetType(int numHashBytes) { _hashArray = numHashBytes > 2; if (_hashArray) { _kNumHashDirectBytes = 0u; _kMinMatchCheck = 4u; _kFixHashSize = 66560u; } else { _kNumHashDirectBytes = 2u; _kMinMatchCheck = 3u; _kFixHashSize = 0u; } } public new void SetStream(Stream stream) { base.SetStream(stream); } public new void ReleaseStream() { base.ReleaseStream(); } public new void Init() { base.Init(); for (uint num = 0u; num < _hashSizeSum; num++) { _hash[num] = 0u; } _cyclicBufferPos = 0u; ReduceOffsets(-1); } public new void MovePos() { if (++_cyclicBufferPos >= _cyclicBufferSize) { _cyclicBufferPos = 0u; } base.MovePos(); if (_pos == int.MaxValue) { Normalize(); } } public new byte GetIndexByte(int index) { return base.GetIndexByte(index); } public new uint GetMatchLen(int index, uint distance, uint limit) { return base.GetMatchLen(index, distance, limit); } public new uint GetNumAvailableBytes() { return base.GetNumAvailableBytes(); } public void Create(uint historySize, uint keepAddBufferBefore, uint matchMaxLen, uint keepAddBufferAfter) { if (historySize > 2147483391) { throw new Exception(); } _cutValue = 16 + (matchMaxLen >> 1); uint keepSizeReserv = (historySize + keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + 256; Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, keepSizeReserv); _matchMaxLen = matchMaxLen; uint num = historySize + 1; if (_cyclicBufferSize != num) { _son = new uint[(_cyclicBufferSize = num) * 2]; } uint num2 = 65536u; if (_hashArray) { num2 = historySize - 1; num2 |= num2 >> 1; num2 |= num2 >> 2; num2 |= num2 >> 4; num2 |= num2 >> 8; num2 >>= 1; num2 |= 0xFFFF; if (num2 > 16777216) { num2 >>= 1; } _hashMask = num2; num2++; num2 += _kFixHashSize; } if (num2 != _hashSizeSum) { _hash = new uint[_hashSizeSum = num2]; } } public uint GetMatches(uint[] distances) { uint num; if (_pos + _matchMaxLen <= _streamPos) { num = _matchMaxLen; } else { num = _streamPos - _pos; if (num < _kMinMatchCheck) { MovePos(); return 0u; } } uint num2 = 0u; uint num3 = ((_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0u); uint num4 = _bufferOffset + _pos; uint num5 = 1u; uint num6 = 0u; uint num7 = 0u; uint num10; if (_hashArray) { uint num8 = Crc.TABLE[_bufferBase[num4]] ^ _bufferBase[num4 + 1]; num6 = num8 & 0x3FF; int num9 = (int)num8 ^ (_bufferBase[num4 + 2] << 8); num7 = (uint)(num9 & 0xFFFF); num10 = ((uint)num9 ^ (Crc.TABLE[_bufferBase[num4 + 3]] << 5)) & _hashMask; } else { num10 = (uint)(_bufferBase[num4] ^ (_bufferBase[num4 + 1] << 8)); } uint num11 = _hash[_kFixHashSize + num10]; if (_hashArray) { uint num12 = _hash[num6]; uint num13 = _hash[1024 + num7]; _hash[num6] = _pos; _hash[1024 + num7] = _pos; if (num12 > num3 && _bufferBase[_bufferOffset + num12] == _bufferBase[num4]) { num5 = (distances[num2++] = 2u); distances[num2++] = _pos - num12 - 1; } if (num13 > num3 && _bufferBase[_bufferOffset + num13] == _bufferBase[num4]) { if (num13 == num12) { num2 -= 2; } num5 = (distances[num2++] = 3u); distances[num2++] = _pos - num13 - 1; num12 = num13; } if (num2 != 0 && num12 == num11) { num2 -= 2; num5 = 1u; } } _hash[_kFixHashSize + num10] = _pos; uint num14 = (_cyclicBufferPos << 1) + 1; uint num15 = _cyclicBufferPos << 1; uint val2; uint val = (val2 = _kNumHashDirectBytes); if (_kNumHashDirectBytes != 0 && num11 > num3 && _bufferBase[_bufferOffset + num11 + _kNumHashDirectBytes] != _bufferBase[num4 + _kNumHashDirectBytes]) { num5 = (distances[num2++] = _kNumHashDirectBytes); distances[num2++] = _pos - num11 - 1; } uint cutValue = _cutValue; while (true) { if (num11 <= num3 || cutValue-- == 0) { _son[num14] = (_son[num15] = 0u); break; } uint num16 = _pos - num11; uint num17 = ((num16 <= _cyclicBufferPos) ? (_cyclicBufferPos - num16) : (_cyclicBufferPos - num16 + _cyclicBufferSize)) << 1; uint num18 = _bufferOffset + num11; uint num19 = Math.Min(val, val2); if (_bufferBase[num18 + num19] == _bufferBase[num4 + num19]) { while (++num19 != num && _bufferBase[num18 + num19] == _bufferBase[num4 + num19]) { } if (num5 < num19) { num5 = (distances[num2++] = num19); distances[num2++] = num16 - 1; if (num19 == num) { _son[num15] = _son[num17]; _son[num14] = _son[num17 + 1]; break; } } } if (_bufferBase[num18 + num19] < _bufferBase[num4 + num19]) { _son[num15] = num11; num15 = num17 + 1; num11 = _son[num15]; val2 = num19; } else { _son[num14] = num11; num14 = num17; num11 = _son[num14]; val = num19; } } MovePos(); return num2; } public void Skip(uint num) { do { uint num2; if (_pos + _matchMaxLen <= _streamPos) { num2 = _matchMaxLen; } else { num2 = _streamPos - _pos; if (num2 < _kMinMatchCheck) { MovePos(); continue; } } uint num3 = ((_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0u); uint num4 = _bufferOffset + _pos; uint num9; if (_hashArray) { uint num5 = Crc.TABLE[_bufferBase[num4]] ^ _bufferBase[num4 + 1]; uint num6 = num5 & 0x3FF; _hash[num6] = _pos; int num7 = (int)num5 ^ (_bufferBase[num4 + 2] << 8); uint num8 = (uint)(num7 & 0xFFFF); _hash[1024 + num8] = _pos; num9 = ((uint)num7 ^ (Crc.TABLE[_bufferBase[num4 + 3]] << 5)) & _hashMask; } else { num9 = (uint)(_bufferBase[num4] ^ (_bufferBase[num4 + 1] << 8)); } uint num10 = _hash[_kFixHashSize + num9]; _hash[_kFixHashSize + num9] = _pos; uint num11 = (_cyclicBufferPos << 1) + 1; uint num12 = _cyclicBufferPos << 1; uint val2; uint val = (val2 = _kNumHashDirectBytes); uint cutValue = _cutValue; while (true) { if (num10 <= num3 || cutValue-- == 0) { _son[num11] = (_son[num12] = 0u); break; } uint num13 = _pos - num10; uint num14 = ((num13 <= _cyclicBufferPos) ? (_cyclicBufferPos - num13) : (_cyclicBufferPos - num13 + _cyclicBufferSize)) << 1; uint num15 = _bufferOffset + num10; uint num16 = Math.Min(val, val2); if (_bufferBase[num15 + num16] == _bufferBase[num4 + num16]) { while (++num16 != num2 && _bufferBase[num15 + num16] == _bufferBase[num4 + num16]) { } if (num16 == num2) { _son[num12] = _son[num14]; _son[num11] = _son[num14 + 1]; break; } } if (_bufferBase[num15 + num16] < _bufferBase[num4 + num16]) { _son[num12] = num10; num12 = num14 + 1; num10 = _son[num12]; val2 = num16; } else { _son[num11] = num10; num11 = num14; num10 = _son[num11]; val = num16; } } MovePos(); } while (--num != 0); } private void NormalizeLinks(uint[] items, uint numItems, uint subValue) { for (uint num = 0u; num < numItems; num++) { uint num2 = items[num]; num2 = ((num2 > subValue) ? (num2 - subValue) : 0u); items[num] = num2; } } private void Normalize() { uint subValue = _pos - _cyclicBufferSize; NormalizeLinks(_son, _cyclicBufferSize * 2, subValue); NormalizeLinks(_hash, _hashSizeSum, subValue); ReduceOffsets((int)subValue); } public void SetCutValue(uint cutValue) { _cutValue = cutValue; } } internal class InWindow { public byte[] _bufferBase; private Stream _stream; private uint _posLimit; private bool _streamEndWasReached; private uint _pointerToLastSafePosition; public uint _bufferOffset; public uint _blockSize; public uint _pos; private uint _keepSizeBefore; private uint _keepSizeAfter; public uint _streamPos; public bool IsDataStarved => _streamPos - _pos < _keepSizeAfter; public void MoveBlock() { uint num = _bufferOffset + _pos - _keepSizeBefore; if (num != 0) { num--; } uint num2 = _bufferOffset + _streamPos - num; for (uint num3 = 0u; num3 < num2; num3++) { _bufferBase[num3] = _bufferBase[num + num3]; } _bufferOffset -= num; } public virtual void ReadBlock() { if (_streamEndWasReached) { return; } while (true) { int num = (int)(0 - _bufferOffset + _blockSize - _streamPos); if (num == 0) { return; } int num2 = ((_stream != null) ? _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), num) : 0); if (num2 == 0) { break; } _streamPos += (uint)num2; if (_streamPos >= _pos + _keepSizeAfter) { _posLimit = _streamPos - _keepSizeAfter; } } _posLimit = _streamPos; if (_bufferOffset + _posLimit > _pointerToLastSafePosition) { _posLimit = _pointerToLastSafePosition - _bufferOffset; } _streamEndWasReached = true; } private void Free() { _bufferBase = null; } public void Create(uint keepSizeBefore, uint keepSizeAfter, uint keepSizeReserv) { _keepSizeBefore = keepSizeBefore; _keepSizeAfter = keepSizeAfter; uint num = keepSizeBefore + keepSizeAfter + keepSizeReserv; if (_bufferBase == null || _blockSize != num) { Free(); _blockSize = num; _bufferBase = new byte[_blockSize]; } _pointerToLastSafePosition = _blockSize - keepSizeAfter; _streamEndWasReached = false; } public void SetStream(Stream stream) { _stream = stream; if (_streamEndWasReached) { _streamEndWasReached = false; if (IsDataStarved) { ReadBlock(); } } } public void ReleaseStream() { _stream = null; } public void Init() { _bufferOffset = 0u; _pos = 0u; _streamPos = 0u; _streamEndWasReached = false; ReadBlock(); } public void MovePos() { _pos++; if (_pos > _posLimit) { if (_bufferOffset + _pos > _pointerToLastSafePosition) { MoveBlock(); } ReadBlock(); } } public byte GetIndexByte(int index) { return _bufferBase[_bufferOffset + _pos + index]; } public uint GetMatchLen(int index, uint distance, uint limit) { if (_streamEndWasReached && _pos + index + limit > _streamPos) { limit = _streamPos - (uint)(int)(_pos + index); } distance++; uint num = _bufferOffset + _pos + (uint)index; uint num2; for (num2 = 0u; num2 < limit && _bufferBase[num + num2] == _bufferBase[num + num2 - distance]; num2++) { } return num2; } public uint GetNumAvailableBytes() { return _streamPos - _pos; } public void ReduceOffsets(int subValue) { _bufferOffset += (uint)subValue; _posLimit -= (uint)subValue; _pos -= (uint)subValue; _streamPos -= (uint)subValue; } } internal class OutWindow { private byte[] _buffer; private int _windowSize; private int _pos; private int _streamPos; private int _pendingLen; private int _pendingDist; private Stream _stream; public long _total; public long _limit; public bool HasSpace { get { if (_pos < _windowSize) { return _total < _limit; } return false; } } public bool HasPending => _pendingLen > 0; public int AvailableBytes => _pos - _streamPos; public void Create(int windowSize) { if (_windowSize != windowSize) { _buffer = new byte[windowSize]; } else { _buffer[windowSize - 1] = 0; } _windowSize = windowSize; _pos = 0; _streamPos = 0; _pendingLen = 0; _total = 0L; _limit = 0L; } public void Reset() { Create(_windowSize); } public void Init(Stream stream) { ReleaseStream(); _stream = stream; } public void Train(Stream stream) { long length = stream.Length; int num = (int)((length < _windowSize) ? length : _windowSize); stream.Position = length - num; _total = 0L; _limit = num; _pos = _windowSize - num; CopyStream(stream, num); if (_pos == _windowSize) { _pos = 0; } _streamPos = _pos; } public void ReleaseStream() { Flush(); _stream = null; } public void Flush() { if (_stream == null) { return; } int num = _pos - _streamPos; if (num != 0) { _stream.Write(_buffer, _streamPos, num); if (_pos >= _windowSize) { _pos = 0; } _streamPos = _pos; } } public void CopyBlock(int distance, int len) { int num = len; int num2 = _pos - distance - 1; if (num2 < 0) { num2 += _windowSize; } while (num > 0 && _pos < _windowSize && _total < _limit) { if (num2 >= _windowSize) { num2 = 0; } _buffer[_pos++] = _buffer[num2++]; _total++; if (_pos >= _windowSize) { Flush(); } num--; } _pendingLen = num; _pendingDist = distance; } public void PutByte(byte b) { _buffer[_pos++] = b; _total++; if (_pos >= _windowSize) { Flush(); } } public byte GetByte(int distance) { int num = _pos - distance - 1; if (num < 0) { num += _windowSize; } return _buffer[num]; } public int CopyStream(Stream stream, int len) { int num = len; while (num > 0 && _pos < _windowSize && _total < _limit) { int num2 = _windowSize - _pos; if (num2 > _limit - _total) { num2 = (int)(_limit - _total); } if (num2 > num) { num2 = num; } int num3 = stream.Read(_buffer, _pos, num2); if (num3 == 0) { throw new DataErrorException(); } num -= num3; _pos += num3; _total += num3; if (_pos >= _windowSize) { Flush(); } } return len - num; } public void SetLimit(long size) { _limit = _total + size; } public int Read(byte[] buffer, int offset, int count) { if (_streamPos >= _pos) { return 0; } int num = _pos - _streamPos; if (num > count) { num = count; } Buffer.BlockCopy(_buffer, _streamPos, buffer, offset, num); _streamPos += num; if (_streamPos >= _windowSize) { _pos = 0; _streamPos = 0; } return num; } public void CopyPending() { if (_pendingLen > 0) { CopyBlock(_pendingDist, _pendingLen); } } } } namespace SharpCompress.Compressors.Filters { internal class BCJ2Filter : Stream { private readonly Stream _baseStream; private readonly byte[] _input = new byte[4096]; private int _inputOffset; private int _inputCount; private bool _endReached; private long _position; private readonly byte[] _output = new byte[4]; private int _outputOffset; private int _outputCount; private readonly byte[] _control; private readonly byte[] _data1; private readonly byte[] _data2; private int _controlPos; private int _data1Pos; private int _data2Pos; private readonly ushort[] _p = new ushort[258]; private uint _range; private uint _code; private byte _prevByte; private bool _isDisposed; private const int K_NUM_TOP_BITS = 24; private const int K_TOP_VALUE = 16777216; private const int K_NUM_BIT_MODEL_TOTAL_BITS = 11; private const int K_BIT_MODEL_TOTAL = 2048; private const int K_NUM_MOVE_BITS = 5; public override bool CanRead => true; public override bool CanSeek => false; public override bool CanWrite => false; public override long Length => _baseStream.Length + _data1.Length + _data2.Length; public override long Position { get { return _position; } set { throw new NotSupportedException(); } } private static bool IsJ(byte b0, byte b1) { if ((b1 & 0xFE) != 232) { return IsJcc(b0, b1); } return true; } private static bool IsJcc(byte b0, byte b1) { if (b0 == 15) { return (b1 & 0xF0) == 128; } return false; } public BCJ2Filter(byte[] control, byte[] data1, byte[] data2, Stream baseStream) { _control = control; _data1 = data1; _data2 = data2; _baseStream = baseStream; for (int i = 0; i < _p.Length; i++) { _p[i] = 1024; } _code = 0u; _range = uint.MaxValue; for (int i = 0; i < 5; i++) { _code = (_code << 8) | control[_controlPos++]; } } protected override void Dispose(bool disposing) { if (!_isDisposed) { _isDisposed = true; base.Dispose(disposing); _baseStream.Dispose(); } } public override void Flush() { throw new NotSupportedException(); } public override int Read(byte[] buffer, int offset, int count) { int num = 0; byte b = 0; while (!_endReached && num < count) { while (_outputOffset < _outputCount) { b = _output[_outputOffset++]; buffer[offset++] = b; num++; _position++; _prevByte = b; if (num == count) { return num; } } if (_inputOffset == _inputCount) { _inputOffset = 0; _inputCount = _baseStream.Read(_input, 0, _input.Length); if (_inputCount == 0) { _endReached = true; break; } } b = _input[_inputOffset++]; buffer[offset++] = b; num++; _position++; if (!IsJ(_prevByte, b)) { _prevByte = b; continue; } int num2 = b switch { 232 => _prevByte, 233 => 256, _ => 257, }; uint num3 = (_range >> 11) * _p[num2]; if (_code < num3) { _range = num3; _p[num2] += (ushort)(2048 - _p[num2] >> 5); if (_range < 16777216) { _range <<= 8; _code = (_code << 8) | _control[_controlPos++]; } _prevByte = b; continue; } _range -= num3; _code -= num3; _p[num2] -= (ushort)(_p[num2] >> 5); if (_range < 16777216) { _range <<= 8; _code = (_code << 8) | _control[_controlPos++]; } uint num4 = (uint)((b != 232) ? ((_data2[_data2Pos++] << 24) | (_data2[_data2Pos++] << 16) | (_data2[_data2Pos++] << 8) | _data2[_data2Pos++]) : ((_data1[_data1Pos++] << 24) | (_data1[_data1Pos++] << 16) | (_data1[_data1Pos++] << 8) | _data1[_data1Pos++])); num4 -= (uint)(int)(_position + 4); _output[0] = (byte)num4; _output[1] = (byte)(num4 >> 8); _output[2] = (byte)(num4 >> 16); _output[3] = (byte)(num4 >> 24); _outputOffset = 0; _outputCount = 4; } return num; } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } } internal class BCJFilter : Filter { private static readonly bool[] MASK_TO_ALLOWED_STATUS = new bool[8] { true, true, true, false, true, false, false, false }; private static readonly int[] MASK_TO_BIT_NUMBER = new int[8] { 0, 1, 2, 2, 3, 3, 3, 3 }; private int _pos; private int _prevMask; public BCJFilter(bool isEncoder, Stream baseStream) : base(isEncoder, baseStream, 5) { _pos = 5; } private static bool Test86MsByte(byte b) { if (b != 0) { return b == byte.MaxValue; } return true; } protected override int Transform(byte[] buffer, int offset, int count) { int num = offset - 1; int num2 = offset + count - 5; int i; for (i = offset; i <= num2; i++) { if ((buffer[i] & 0xFE) != 232) { continue; } num = i - num; if ((num & -4) != 0) { _prevMask = 0; } else { _prevMask = (_prevMask << num - 1) & 7; if (_prevMask != 0 && (!MASK_TO_ALLOWED_STATUS[_prevMask] || Test86MsByte(buffer[i + 4 - MASK_TO_BIT_NUMBER[_prevMask]]))) { num = i; _prevMask = (_prevMask << 1) | 1; continue; } } num = i; if (Test86MsByte(buffer[i + 4])) { int num3 = buffer[i + 1] | (buffer[i + 2] << 8) | (buffer[i + 3] << 16) | (buffer[i + 4] << 24); int num4; while (true) { num4 = ((!_isEncoder) ? (num3 - (_pos + i - offset)) : (num3 + (_pos + i - offset))); if (_prevMask == 0) { break; } int num5 = MASK_TO_BIT_NUMBER[_prevMask] * 8; if (!Test86MsByte((byte)(num4 >> 24 - num5))) { break; } num3 = num4 ^ ((1 << 32 - num5) - 1); } buffer[i + 1] = (byte)num4; buffer[i + 2] = (byte)(num4 >> 8); buffer[i + 3] = (byte)(num4 >> 16); buffer[i + 4] = (byte)(~(((num4 >> 24) & 1) - 1)); i += 4; } else { _prevMask = (_prevMask << 1) | 1; } } num = i - num; _prevMask = (((num & -4) == 0) ? (_prevMask << num - 1) : 0); i -= offset; _pos += i; return i; } } internal abstract class Filter : Stream { protected bool _isEncoder; protected Stream _baseStream; private readonly byte[] _tail; private readonly byte[] _window; private int _transformed; private int _read; private bool _endReached; private bool _isDisposed; public override bool CanRead => !_isEncoder; public override bool CanSeek => false; public override bool CanWrite => _isEncoder; public override long Length => _baseStream.Length; public override long Position { get { return _baseStream.Position; } set { throw new NotSupportedException(); } } protected Filter(bool isEncoder, Stream baseStream, int lookahead) { _isEncoder = isEncoder; _baseStream = baseStream; _tail = new byte[lookahead - 1]; _window = new byte[_tail.Length * 2]; } protected override void Dispose(bool disposing) { if (!_isDisposed) { _isDisposed = true; base.Dispose(disposing); _baseStream.Dispose(); } } public override void Flush() { throw new NotSupportedException(); } public override int Read(byte[] buffer, int offset, int count) { int num = 0; if (_transformed > 0) { int num2 = _transformed; if (num2 > count) { num2 = count; } Buffer.BlockCopy(_tail, 0, buffer, offset, num2); _transformed -= num2; _read -= num2; offset += num2; count -= num2; num += num2; Buffer.BlockCopy(_tail, num2, _tail, 0, _read); } if (count == 0) { return num; } int num3 = _read; if (num3 > count) { num3 = count; } Buffer.BlockCopy(_tail, 0, buffer, offset, num3); _read -= num3; Buffer.BlockCopy(_tail, num3, _tail, 0, _read); while (!_endReached && num3 < count) { int num4 = _baseStream.Read(buffer, offset + num3, count - num3); num3 += num4; if (num4 == 0) { _endReached = true; } } while (!_endReached && _read < _tail.Length) { int num5 = _baseStream.Read(_tail, _read, _tail.Length - _read); _read += num5; if (num5 == 0) { _endReached = true; } } if (num3 > _tail.Length) { _transformed = Transform(buffer, offset, num3); offset += _transformed; count -= _transformed; num += _transformed; num3 -= _transformed; _transformed = 0; } if (count == 0) { return num; } Buffer.BlockCopy(buffer, offset, _window, 0, num3); Buffer.BlockCopy(_tail, 0, _window, num3, _read); if (num3 + _read > _tail.Length) { _transformed = Transform(_window, 0, num3 + _read); } else { _transformed = num3 + _read; } Buffer.BlockCopy(_window, 0, buffer, offset, num3); Buffer.BlockCopy(_window, num3, _tail, 0, _read); num += num3; _transformed -= num3; return num; } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { Transform(buffer, offset, count); _baseStream.Write(buffer, offset, count); } protected abstract int Transform(byte[] buffer, int offset, int count); } } namespace SharpCompress.Compressors.Deflate { internal class CRC32 { private const int BUFFER_SIZE = 8192; private static readonly uint[] crc32Table; private uint runningCrc32Result = uint.MaxValue; public long TotalBytesRead { get; private set; } public int Crc32Result => (int)(~runningCrc32Result); static CRC32() { uint num = 3988292384u; crc32Table = new uint[256]; for (uint num2 = 0u; num2 < 256; num2++) { uint num3 = num2; for (uint num4 = 8u; num4 != 0; num4--) { num3 = (((num3 & 1) != 1) ? (num3 >> 1) : ((num3 >> 1) ^ num)); } crc32Table[num2] = num3; } } public uint GetCrc32(Stream input) { return GetCrc32AndCopy(input, null); } public uint GetCrc32AndCopy(Stream input, Stream output) { if (input == null) { throw new ZlibException("The input stream must not be null."); } byte[] array = new byte[8192]; int count = 8192; TotalBytesRead = 0L; int num = input.Read(array, 0, count); output?.Write(array, 0, num); TotalBytesRead += num; while (num > 0) { SlurpBlock(array, 0, num); num = input.Read(array, 0, count); output?.Write(array, 0, num); TotalBytesRead += num; } return ~runningCrc32Result; } public int ComputeCrc32(int W, byte B) { return _InternalComputeCrc32((uint)W, B); } internal int _InternalComputeCrc32(uint W, byte B) { return (int)(crc32Table[(W ^ B) & 0xFF] ^ (W >> 8)); } public void SlurpBlock(byte[] block, int offset, int count) { if (block == null) { throw new ZlibException("The data buffer must not be null."); } for (int i = 0; i < count; i++) { int num = offset + i; runningCrc32Result = (runningCrc32Result >> 8) ^ crc32Table[block[num] ^ (runningCrc32Result & 0xFF)]; } TotalBytesRead += count; } private uint gf2_matrix_times(uint[] matrix, uint vec) { uint num = 0u; int num2 = 0; while (vec != 0) { if ((vec & 1) == 1) { num ^= matrix[num2]; } vec >>= 1; num2++; } return num; } private void gf2_matrix_square(uint[] square, uint[] mat) { for (int i = 0; i < 32; i++) { square[i] = gf2_matrix_times(mat, mat[i]); } } public void Combine(int crc, int length) { uint[] array = new uint[32]; uint[] array2 = new uint[32]; if (length == 0) { return; } uint num = ~runningCrc32Result; array2[0] = 3988292384u; uint num2 = 1u; for (int i = 1; i < 32; i++) { array2[i] = num2; num2 <<= 1; } gf2_matrix_square(array, array2); gf2_matrix_square(array2, array); uint num3 = (uint)length; do { gf2_matrix_square(array, array2); if ((num3 & 1) == 1) { num = gf2_matrix_times(array, num); } num3 >>= 1; if (num3 == 0) { break; } gf2_matrix_square(array2, array); if ((num3 & 1) == 1) { num = gf2_matrix_times(array2, num); } num3 >>= 1; } while (num3 != 0); num ^= (uint)crc; runningCrc32Result = ~num; } } internal sealed class DeflateManager { internal enum BlockState { NeedMore, BlockDone, FinishStarted, FinishDone } internal enum DeflateFlavor { Store, Fast, Slow } internal delegate BlockState CompressFunc(FlushType flush); internal class Config { internal int GoodLength; internal int MaxLazy; internal int NiceLength; internal int MaxChainLength; internal DeflateFlavor Flavor; private static readonly Config[] Table; private Config(int goodLength, int maxLazy, int niceLength, int maxChainLength, DeflateFlavor flavor) { GoodLength = goodLength; MaxLazy = maxLazy; NiceLength = niceLength; MaxChainLength = maxChainLength; Flavor = flavor; } public static Config Lookup(CompressionLevel level) { return Table[(int)level]; } static Config() { Table = new Config[10] { new Config(0, 0, 0, 0, DeflateFlavor.Store), new Config(4, 4, 8, 4, DeflateFlavor.Fast), new Config(4, 5, 16, 8, DeflateFlavor.Fast), new Config(4, 6, 32, 32, DeflateFlavor.Fast), new Config(4, 4, 16, 16, DeflateFlavor.Slow), new Config(8, 16, 32, 32, DeflateFlavor.Slow), new Config(8, 16, 128, 128, DeflateFlavor.Slow), new Config(8, 32, 128, 256, DeflateFlavor.Slow), new Config(32, 128, 258, 1024, DeflateFlavor.Slow), new Config(32, 258, 258, 4096, DeflateFlavor.Slow) }; } } private sealed class Tree { internal const int Buf_size = 16; private static readonly int HEAP_SIZE = 2 * InternalConstants.L_CODES + 1; internal static readonly sbyte[] bl_order = new sbyte[19] { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; private static readonly sbyte[] _dist_code = new sbyte[512] { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 }; internal static readonly sbyte[] LengthCode = new sbyte[256] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 }; internal static readonly int[] LengthBase = new int[29] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0 }; internal static readonly int[] DistanceBase = new int[30] { 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 }; internal short[] dyn_tree; internal int max_code; internal StaticTree staticTree; internal static int DistanceCode(int dist) { if (dist >= 256) { return _dist_code[256 + SharedUtils.URShift(dist, 7)]; } return _dist_code[dist]; } internal void gen_bitlen(DeflateManager s) { short[] array = dyn_tree; short[] treeCodes = staticTree.treeCodes; int[] extraBits = staticTree.extraBits; int extraBase = staticTree.extraBase; int maxLength = staticTree.maxLength; int num = 0; for (int i = 0; i <= InternalConstants.MAX_BITS; i++) { s.bl_count[i] = 0; } array[s.heap[s.heap_max] * 2 + 1] = 0; int j; for (j = s.heap_max + 1; j < HEAP_SIZE; j++) { int num2 = s.heap[j]; int i = array[array[num2 * 2 + 1] * 2 + 1] + 1; if (i > maxLength) { i = maxLength; num++; } array[num2 * 2 + 1] = (short)i; if (num2 <= max_code) { s.bl_count[i]++; int num3 = 0; if (num2 >= extraBase) { num3 = extraBits[num2 - extraBase]; } short num4 = array[num2 * 2]; s.opt_len += num4 * (i + num3); if (treeCodes != null) { s.static_len += num4 * (treeCodes[num2 * 2 + 1] + num3); } } } if (num == 0) { return; } do { int i = maxLength - 1; while (s.bl_count[i] == 0) { i--; } s.bl_count[i]--; s.bl_count[i + 1] = (short)(s.bl_count[i + 1] + 2); s.bl_count[maxLength]--; num -= 2; } while (num > 0); for (int i = maxLength; i != 0; i--) { int num2 = s.bl_count[i]; while (num2 != 0) { int num5 = s.heap[--j]; if (num5 <= max_code) { if (array[num5 * 2 + 1] != i) { s.opt_len = (int)(s.opt_len + ((long)i - (long)array[num5 * 2 + 1]) * array[num5 * 2]); array[num5 * 2 + 1] = (short)i; } num2--; } } } } internal void build_tree(DeflateManager s) { short[] array = dyn_tree; short[] treeCodes = staticTree.treeCodes; int elems = staticTree.elems; int num = -1; s.heap_len = 0; s.heap_max = HEAP_SIZE; for (int i = 0; i < elems; i++) { if (array[i * 2] != 0) { num = (s.heap[++s.heap_len] = i); s.depth[i] = 0; } else { array[i * 2 + 1] = 0; } } int num2; while (s.heap_len < 2) { num2 = (s.heap[++s.heap_len] = ((num < 2) ? (++num) : 0)); array[num2 * 2] = 1; s.depth[num2] = 0; s.opt_len--; if (treeCodes != null) { s.static_len -= treeCodes[num2 * 2 + 1]; } } max_code = num; for (int i = s.heap_len / 2; i >= 1; i--) { s.pqdownheap(array, i); } num2 = elems; do { int i = s.heap[1]; s.heap[1] = s.heap[s.heap_len--]; s.pqdownheap(array, 1); int num3 = s.heap[1]; s.heap[--s.heap_max] = i; s.heap[--s.heap_max] = num3; array[num2 * 2] = (short)(array[i * 2] + array[num3 * 2]); s.depth[num2] = (sbyte)(Math.Max((byte)s.depth[i], (byte)s.depth[num3]) + 1); array[i * 2 + 1] = (array[num3 * 2 + 1] = (short)num2); s.heap[1] = num2++; s.pqdownheap(array, 1); } while (s.heap_len >= 2); s.heap[--s.heap_max] = s.heap[1]; gen_bitlen(s); gen_codes(array, num, s.bl_count); } internal static void gen_codes(short[] tree, int max_code, short[] bl_count) { short[] array = new short[InternalConstants.MAX_BITS + 1]; short num = 0; for (int i = 1; i <= InternalConstants.MAX_BITS; i++) { num = (array[i] = (short)(num + bl_count[i - 1] << 1)); } for (int j = 0; j <= max_code; j++) { int num2 = tree[j * 2 + 1]; if (num2 != 0) { tree[j * 2] = (short)bi_reverse(array[num2]++, num2); } } } internal static int bi_reverse(int code, int len) { int num = 0; do { num |= code & 1; code >>= 1; num <<= 1; } while (--len > 0); return num >> 1; } } internal static readonly int[] ExtraLengthBits = new int[29] { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; internal static readonly int[] ExtraDistanceBits = new int[30] { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; private const int MEM_LEVEL_MAX = 9; private const int MEM_LEVEL_DEFAULT = 8; private CompressFunc DeflateFunction; private static readonly string[] _ErrorMessage = new string[10] { "need dictionary", "stream end", "", "file error", "stream error", "data error", "insufficient memory", "buffer error", "incompatible version", "" }; private const int PRESET_DICT = 32; private const int INIT_STATE = 42; private const int BUSY_STATE = 113; private const int FINISH_STATE = 666; private const int Z_DEFLATED = 8; private const int STORED_BLOCK = 0; private const int STATIC_TREES = 1; private const int DYN_TREES = 2; private const int Z_BINARY = 0; private const int Z_ASCII = 1; private const int Z_UNKNOWN = 2; private const int Buf_size = 16; private const int MIN_MATCH = 3; private const int MAX_MATCH = 258; private const int MIN_LOOKAHEAD = 262; private static readonly int HEAP_SIZE = 2 * InternalConstants.L_CODES + 1; private const int END_BLOCK = 256; internal ZlibCodec _codec; internal int status; internal byte[] pending; internal int nextPending; internal int pendingCount; internal sbyte data_type; internal int last_flush; internal int w_size; internal int w_bits; internal int w_mask; internal byte[] window; internal int window_size; internal short[] prev; private short[] head; private int ins_h; private int hash_size; private int hash_bits; private int hash_mask; private int hash_shift; private int blockStart; private Config config; private int match_length; private int prev_match; private int match_available; private int strstart; private int match_start; private int lookahead; private int prev_length; private CompressionLevel compressionLevel; private CompressionStrategy compressionStrategy; private readonly short[] dyn_ltree; private readonly short[] dyn_dtree; private readonly short[] bl_tree; private readonly Tree treeLiterals = new Tree(); private readonly Tree treeDistances = new Tree(); private readonly Tree treeBitLengths = new Tree(); private readonly short[] bl_count = new short[InternalConstants.MAX_BITS + 1]; private readonly int[] heap = new int[2 * InternalConstants.L_CODES + 1]; private int heap_len; private int heap_max; private readonly sbyte[] depth = new sbyte[2 * InternalConstants.L_CODES + 1]; private int _lengthOffset; internal int lit_bufsize; internal int last_lit; internal int _distanceOffset; internal int opt_len; internal int static_len; internal int matches; internal int last_eob_len; internal short bi_buf; internal int bi_valid; private bool Rfc1950BytesEmitted; internal bool WantRfc1950HeaderBytes { get; set; } = true; internal DeflateManager() { dyn_ltree = new short[HEAP_SIZE * 2]; dyn_dtree = new short[(2 * InternalConstants.D_CODES + 1) * 2]; bl_tree = new short[(2 * InternalConstants.BL_CODES + 1) * 2]; } private void _InitializeLazyMatch() { window_size = 2 * w_size; Array.Clear(head, 0, hash_size); config = Config.Lookup(compressionLevel); SetDeflater(); strstart = 0; blockStart = 0; lookahead = 0; match_length = (prev_length = 2); match_available = 0; ins_h = 0; } private void _InitializeTreeData() { treeLiterals.dyn_tree = dyn_ltree; treeLiterals.staticTree = StaticTree.Literals; treeDistances.dyn_tree = dyn_dtree; treeDistances.staticTree = StaticTree.Distances; treeBitLengths.dyn_tree = bl_tree; treeBitLengths.staticTree = StaticTree.BitLengths; bi_buf = 0; bi_valid = 0; last_eob_len = 8; _InitializeBlocks(); } internal void _InitializeBlocks() { for (int i = 0; i < InternalConstants.L_CODES; i++) { dyn_ltree[i * 2] = 0; } for (int j = 0; j < InternalConstants.D_CODES; j++) { dyn_dtree[j * 2] = 0; } for (int k = 0; k < InternalConstants.BL_CODES; k++) { bl_tree[k * 2] = 0; } dyn_ltree[512] = 1; opt_len = (static_len = 0); last_lit = (matches = 0); } internal void pqdownheap(short[] tree, int k) { int num = heap[k]; for (int num2 = k << 1; num2 <= heap_len; num2 <<= 1) { if (num2 < heap_len && IsSmaller(tree, heap[num2 + 1], heap[num2], depth)) { num2++; } if (IsSmaller(tree, num, heap[num2], depth)) { break; } heap[k] = heap[num2]; k = num2; } heap[k] = num; } internal static bool IsSmaller(short[] tree, int n, int m, sbyte[] depth) { short num = tree[n * 2]; short num2 = tree[m * 2]; if (num >= num2) { if (num == num2) { return depth[n] <= depth[m]; } return false; } return true; } internal void ScanTree(short[] tree, int maxCode) { int num = -1; int num2 = tree[1]; int num3 = 0; int num4 = 7; int num5 = 4; if (num2 == 0) { num4 = 138; num5 = 3; } tree[(maxCode + 1) * 2 + 1] = short.MaxValue; for (int i = 0; i <= maxCode; i++) { int num6 = num2; num2 = tree[(i + 1) * 2 + 1]; if (++num3 < num4 && num6 == num2) { continue; } if (num3 < num5) { bl_tree[num6 * 2] = (short)(bl_tree[num6 * 2] + num3); } else if (num6 != 0) { if (num6 != num) { bl_tree[num6 * 2]++; } bl_tree[InternalConstants.REP_3_6 * 2]++; } else if (num3 <= 10) { bl_tree[InternalConstants.REPZ_3_10 * 2]++; } else { bl_tree[InternalConstants.REPZ_11_138 * 2]++; } num3 = 0; num = num6; if (num2 == 0) { num4 = 138; num5 = 3; } else if (num6 == num2) { num4 = 6; num5 = 3; } else { num4 = 7; num5 = 4; } } } internal int BuildBlTree() { ScanTree(dyn_ltree, treeLiterals.max_code); ScanTree(dyn_dtree, treeDistances.max_code); treeBitLengths.build_tree(this); int num = InternalConstants.BL_CODES - 1; while (num >= 3 && bl_tree[Tree.bl_order[num] * 2 + 1] == 0) { num--; } opt_len += 3 * (num + 1) + 5 + 5 + 4; return num; } internal void send_all_trees(int lcodes, int dcodes, int blcodes) { send_bits(lcodes - 257, 5); send_bits(dcodes - 1, 5); send_bits(blcodes - 4, 4); for (int i = 0; i < blcodes; i++) { send_bits(bl_tree[Tree.bl_order[i] * 2 + 1], 3); } send_tree(dyn_ltree, lcodes - 1); send_tree(dyn_dtree, dcodes - 1); } internal void send_tree(short[] tree, int max_code) { int num = -1; int num2 = tree[1]; int num3 = 0; int num4 = 7; int num5 = 4; if (num2 == 0) { num4 = 138; num5 = 3; } for (int i = 0; i <= max_code; i++) { int num6 = num2; num2 = tree[(i + 1) * 2 + 1]; if (++num3 < num4 && num6 == num2) { continue; } if (num3 < num5) { do { send_code(num6, bl_tree); } while (--num3 != 0); } else if (num6 != 0) { if (num6 != num) { send_code(num6, bl_tree); num3--; } send_code(InternalConstants.REP_3_6, bl_tree); send_bits(num3 - 3, 2); } else if (num3 <= 10) { send_code(InternalConstants.REPZ_3_10, bl_tree); send_bits(num3 - 3, 3); } else { send_code(InternalConstants.REPZ_11_138, bl_tree); send_bits(num3 - 11, 7); } num3 = 0; num = num6; if (num2 == 0) { num4 = 138; num5 = 3; } else if (num6 == num2) { num4 = 6; num5 = 3; } else { num4 = 7; num5 = 4; } } } private void put_bytes(byte[] p, int start, int len) { Array.Copy(p, start, pending, pendingCount, len); pendingCount += len; } internal void send_code(int c, short[] tree) { int num = c * 2; send_bits(tree[num] & 0xFFFF, tree[num + 1] & 0xFFFF); } internal void send_bits(int value, int length) { if (bi_valid > 16 - length) { bi_buf |= (short)((value << bi_valid) & 0xFFFF); pending[pendingCount++] = (byte)bi_buf; pending[pendingCount++] = (byte)(bi_buf >> 8); bi_buf = (short)(value >>> 16 - bi_valid); bi_valid += length - 16; } else { bi_buf |= (short)((value << bi_valid) & 0xFFFF); bi_valid += length; } } internal void _tr_align() { send_bits(2, 3); send_code(256, StaticTree.lengthAndLiteralsTreeCodes); bi_flush(); if (1 + last_eob_len + 10 - bi_valid < 9) { send_bits(2, 3); send_code(256, StaticTree.lengthAndLiteralsTreeCodes); bi_flush(); } last_eob_len = 7; } internal bool _tr_tally(int dist, int lc) { pending[_distanceOffset + last_lit * 2] = (byte)((uint)dist >> 8); pending[_distanceOffset + last_lit * 2 + 1] = (byte)dist; pending[_lengthOffset + last_lit] = (byte)lc; last_lit++; if (dist == 0) { dyn_ltree[lc * 2]++; } else { matches++; dist--; dyn_ltree[(Tree.LengthCode[lc] + InternalConstants.LITERALS + 1) * 2]++; dyn_dtree[Tree.DistanceCode(dist) * 2]++; } if ((last_lit & 0x1FFF) == 0 && compressionLevel > CompressionLevel.Level2) { int num = last_lit << 3; int num2 = strstart - blockStart; for (int i = 0; i < InternalConstants.D_CODES; i++) { num = (int)(num + dyn_dtree[i * 2] * (5L + (long)ExtraDistanceBits[i])); } num >>= 3; if (matches < last_lit / 2 && num < num2 / 2) { return true; } } if (last_lit != lit_bufsize - 1) { return last_lit == lit_bufsize; } return true; } internal void send_compressed_block(short[] ltree, short[] dtree) { int num = 0; if (last_lit != 0) { do { int num2 = _distanceOffset + num * 2; int num3 = ((pending[num2] << 8) & 0xFF00) | (pending[num2 + 1] & 0xFF); int num4 = pending[_lengthOffset + num] & 0xFF; num++; if (num3 == 0) { send_code(num4, ltree); continue; } int num5 = Tree.LengthCode[num4]; send_code(num5 + InternalConstants.LITERALS + 1, ltree); int num6 = ExtraLengthBits[num5]; if (num6 != 0) { num4 -= Tree.LengthBase[num5]; send_bits(num4, num6); } num3--; num5 = Tree.DistanceCode(num3); send_code(num5, dtree); num6 = ExtraDistanceBits[num5]; if (num6 != 0) { num3 -= Tree.DistanceBase[num5]; send_bits(num3, num6); } } while (num < last_lit); } send_code(256, ltree); last_eob_len = ltree[513]; } internal void set_data_type() { int i = 0; int num = 0; int num2 = 0; for (; i < 7; i++) { num2 += dyn_ltree[i * 2]; } for (; i < 128; i++) { num += dyn_ltree[i * 2]; } for (; i < InternalConstants.LITERALS; i++) { num2 += dyn_ltree[i * 2]; } data_type = (sbyte)((num2 <= num >> 2) ? 1 : 0); } internal void bi_flush() { if (bi_valid == 16) { pending[pendingCount++] = (byte)bi_buf; pending[pendingCount++] = (byte)(bi_buf >> 8); bi_buf = 0; bi_valid = 0; } else if (bi_valid >= 8) { pending[pendingCount++] = (byte)bi_buf; bi_buf >>= 8; bi_valid -= 8; } } internal void bi_windup() { if (bi_valid > 8) { pending[pendingCount++] = (byte)bi_buf; pending[pendingCount++] = (byte)(bi_buf >> 8); } else if (bi_valid > 0) { pending[pendingCount++] = (byte)bi_buf; } bi_buf = 0; bi_valid = 0; } internal void copy_block(int buf, int len, bool header) { bi_windup(); last_eob_len = 8; if (header) { pending[pendingCount++] = (byte)len; pending[pendingCount++] = (byte)(len >> 8); pending[pendingCount++] = (byte)(~len); pending[pendingCount++] = (byte)(~len >> 8); } put_bytes(window, buf, len); } internal void flush_block_only(bool eof) { _tr_flush_block((blockStart >= 0) ? blockStart : (-1), strstart - blockStart, eof); blockStart = strstart; _codec.flush_pending(); } internal BlockState DeflateNone(FlushType flush) { int num = 65535; if (num > pending.Length - 5) { num = pending.Length - 5; } while (true) { if (lookahead <= 1) { _fillWindow(); if (lookahead == 0 && flush == FlushType.None) { return BlockState.NeedMore; } if (lookahead == 0) { break; } } strstart += lookahead; lookahead = 0; int num2 = blockStart + num; if (strstart == 0 || strstart >= num2) { lookahead = strstart - num2; strstart = num2; flush_block_only(eof: false); if (_codec.AvailableBytesOut == 0) { return BlockState.NeedMore; } } if (strstart - blockStart >= w_size - 262) { flush_block_only(eof: false); if (_codec.AvailableBytesOut == 0) { return BlockState.NeedMore; } } } flush_block_only(flush == FlushType.Finish); if (_codec.AvailableBytesOut == 0) { if (flush != FlushType.Finish) { return BlockState.NeedMore; } return BlockState.FinishStarted; } if (flush != FlushType.Finish) { return BlockState.BlockDone; } return BlockState.FinishDone; } internal void _tr_stored_block(int buf, int stored_len, bool eof) { send_bits(eof ? 1 : 0, 3); copy_block(buf, stored_len, header: true); } internal void _tr_flush_block(int buf, int stored_len, bool eof) { int num = 0; int num2; int num3; if (compressionLevel > CompressionLevel.None) { if (data_type == 2) { set_data_type(); } treeLiterals.build_tree(this); treeDistances.build_tree(this); num = BuildBlTree(); num2 = opt_len + 3 + 7 >> 3; num3 = static_len + 3 + 7 >> 3; if (num3 <= num2) { num2 = num3; } } else { num2 = (num3 = stored_len + 5); } if (stored_len + 4 <= num2 && buf != -1) { _tr_stored_block(buf, stored_len, eof); } else if (num3 == num2) { send_bits(2 + (eof ? 1 : 0), 3); send_compressed_block(StaticTree.lengthAndLiteralsTreeCodes, StaticTree.distTreeCodes); } else { send_bits(4 + (eof ? 1 : 0), 3); send_all_trees(treeLiterals.max_code + 1, treeDistances.max_code + 1, num + 1); send_compressed_block(dyn_ltree, dyn_dtree); } _InitializeBlocks(); if (eof) { bi_windup(); } } private void _fillWindow() { do { int num = window_size - lookahead - strstart; int num2; if (num == 0 && strstart == 0 && lookahead == 0) { num = w_size; } else if (num == -1) { num--; } else if (strstart >= w_size + w_size - 262) { Array.Copy(window, w_size, window, 0, w_size); match_start -= w_size; strstart -= w_size; blockStart -= w_size; num2 = hash_size; int num3 = num2; do { int num4 = head[--num3] & 0xFFFF; head[num3] = (short)((num4 >= w_size) ? (num4 - w_size) : 0); } while (--num2 != 0); num2 = w_size; num3 = num2; do { int num4 = prev[--num3] & 0xFFFF; prev[num3] = (short)((num4 >= w_size) ? (num4 - w_size) : 0); } while (--num2 != 0); num += w_size; } if (_codec.AvailableBytesIn == 0) { break; } num2 = _codec.read_buf(window, strstart + lookahead, num); lookahead += num2; if (lookahead >= 3) { ins_h = window[strstart] & 0xFF; ins_h = ((ins_h << hash_shift) ^ (window[strstart + 1] & 0xFF)) & hash_mask; } } while (lookahead < 262 && _codec.AvailableBytesIn != 0); } internal BlockState DeflateFast(FlushType flush) { int num = 0; while (true) { if (lookahead < 262) { _fillWindow(); if (lookahead < 262 && flush == FlushType.None) { return BlockState.NeedMore; } if (lookahead == 0) { break; } } if (lookahead >= 3) { ins_h = ((ins_h << hash_shift) ^ (window[strstart + 2] & 0xFF)) & hash_mask; num = head[ins_h] & 0xFFFF; prev[strstart & w_mask] = head[ins_h]; head[ins_h] = (short)strstart; } if (num != 0L && ((strstart - num) & 0xFFFF) <= w_size - 262 && compressionStrategy != CompressionStrategy.HuffmanOnly) { match_length = longest_match(num); } bool flag; if (match_length >= 3) { flag = _tr_tally(strstart - match_start, match_length - 3); lookahead -= match_length; if (match_length <= config.MaxLazy && lookahead >= 3) { match_length--; do { strstart++; ins_h = ((ins_h << hash_shift) ^ (window[strstart + 2] & 0xFF)) & hash_mask; num = head[ins_h] & 0xFFFF; prev[strstart & w_mask] = head[ins_h]; head[ins_h] = (short)strstart; } while (--match_length != 0); strstart++; } else { strstart += match_length; match_length = 0; ins_h = window[strstart] & 0xFF; ins_h = ((ins_h << hash_shift) ^ (window[strstart + 1] & 0xFF)) & hash_mask; } } else { flag = _tr_tally(0, window[strstart] & 0xFF); lookahead--; strstart++; } if (flag) { flush_block_only(eof: false); if (_codec.AvailableBytesOut == 0) { return BlockState.NeedMore; } } } flush_block_only(flush == FlushType.Finish); if (_codec.AvailableBytesOut == 0) { if (flush == FlushType.Finish) { return BlockState.FinishStarted; } return BlockState.NeedMore; } if (flush != FlushType.Finish) { return BlockState.BlockDone; } return BlockState.FinishDone; } internal BlockState DeflateSlow(FlushType flush) { int num = 0; while (true) { if (lookahead < 262) { _fillWindow(); if (lookahead < 262 && flush == FlushType.None) { return BlockState.NeedMore; } if (lookahead == 0) { break; } } if (lookahead >= 3) { ins_h = ((ins_h << hash_shift) ^ (window[strstart + 2] & 0xFF)) & hash_mask; num = head[ins_h] & 0xFFFF; prev[strstart & w_mask] = head[ins_h]; head[ins_h] = (short)strstart; } prev_length = match_length; prev_match = match_start; match_length = 2; if (num != 0 && prev_length < config.MaxLazy && ((strstart - num) & 0xFFFF) <= w_size - 262) { if (compressionStrategy != CompressionStrategy.HuffmanOnly) { match_length = longest_match(num); } if (match_length <= 5 && (compressionStrategy == CompressionStrategy.Filtered || (match_length == 3 && strstart - match_start > 4096))) { match_length = 2; } } if (prev_length >= 3 && match_length <= prev_length) { int num2 = strstart + lookahead - 3; bool flag = _tr_tally(strstart - 1 - prev_match, prev_length - 3); lookahead -= prev_length - 1; prev_length -= 2; do { if (++strstart <= num2) { ins_h = ((ins_h << hash_shift) ^ (window[strstart + 2] & 0xFF)) & hash_mask; num = head[ins_h] & 0xFFFF; prev[strstart & w_mask] = head[ins_h]; head[ins_h] = (short)strstart; } } while (--prev_length != 0); match_available = 0; match_length = 2; strstart++; if (flag) { flush_block_only(eof: false); if (_codec.AvailableBytesOut == 0) { return BlockState.NeedMore; } } } else if (match_available != 0) { if (_tr_tally(0, window[strstart - 1] & 0xFF)) { flush_block_only(eof: false); } strstart++; lookahead--; if (_codec.AvailableBytesOut == 0) { return BlockState.NeedMore; } } else { match_available = 1; strstart++; lookahead--; } } if (match_available != 0) { bool flag = _tr_tally(0, window[strstart - 1] & 0xFF); match_available = 0; } flush_block_only(flush == FlushType.Finish); if (_codec.AvailableBytesOut == 0) { if (flush == FlushType.Finish) { return BlockState.FinishStarted; } return BlockState.NeedMore; } if (flush != FlushType.Finish) { return BlockState.BlockDone; } return BlockState.FinishDone; } internal int longest_match(int cur_match) { int num = config.MaxChainLength; int num2 = strstart; int num3 = prev_length; int num4 = ((strstart > w_size - 262) ? (strstart - (w_size - 262)) : 0); int niceLength = config.NiceLength; int num5 = w_mask; int num6 = strstart + 258; byte b = window[num2 + num3 - 1]; byte b2 = window[num2 + num3]; if (prev_length >= config.GoodLength) { num >>= 2; } if (niceLength > lookahead) { niceLength = lookahead; } do { int num7 = cur_match; if (window[num7 + num3] != b2 || window[num7 + num3 - 1] != b || window[num7] != window[num2] || window[++num7] != window[num2 + 1]) { continue; } num2 += 2; num7++; while (window[++num2] == window[++num7] && window[++num2] == window[++num7] && window[++num2] == window[++num7] && window[++num2] == window[++num7] && window[++num2] == window[++num7] && window[++num2] == window[++num7] && window[++num2] == window[++num7] && window[++num2] == window[++num7] && num2 < num6) { } int num8 = 258 - (num6 - num2); num2 = num6 - 258; if (num8 > num3) { match_start = cur_match; num3 = num8; if (num8 >= niceLength) { break; } b = window[num2 + num3 - 1]; b2 = window[num2 + num3]; } } while ((cur_match = prev[cur_match & num5] & 0xFFFF) > num4 && --num != 0); if (num3 <= lookahead) { return num3; } return lookahead; } internal int Initialize(ZlibCodec codec, CompressionLevel level) { return Initialize(codec, level, 15); } internal int Initialize(ZlibCodec codec, CompressionLevel level, int bits) { return Initialize(codec, level, bits, 8, CompressionStrategy.Default); } internal int Initialize(ZlibCodec codec, CompressionLevel level, int bits, CompressionStrategy compressionStrategy) { return Initialize(codec, level, bits, 8, compressionStrategy); } internal int Initialize(ZlibCodec codec, CompressionLevel level, int windowBits, int memLevel, CompressionStrategy strategy) { _codec = codec; _codec.Message = null; if (windowBits < 9 || windowBits > 15) { throw new ZlibException("windowBits must be in the range 9..15."); } if (memLevel < 1 || memLevel > 9) { throw new ZlibException($"memLevel must be in the range 1.. {9}"); } _codec.dstate = this; w_bits = windowBits; w_size = 1 << w_bits; w_mask = w_size - 1; hash_bits = memLevel + 7; hash_size = 1 << hash_bits; hash_mask = hash_size - 1; hash_shift = (hash_bits + 3 - 1) / 3; window = new byte[w_size * 2]; prev = new short[w_size]; head = new short[hash_size]; lit_bufsize = 1 << memLevel + 6; pending = new byte[lit_bufsize * 4]; _distanceOffset = lit_bufsize; _lengthOffset = 3 * lit_bufsize; compressionLevel = level; compressionStrategy = strategy; Reset(); return 0; } internal void Reset() { _codec.TotalBytesIn = (_codec.TotalBytesOut = 0L); _codec.Message = null; pendingCount = 0; nextPending = 0; Rfc1950BytesEmitted = false; status = (WantRfc1950HeaderBytes ? 42 : 113); _codec._Adler32 = Adler.Adler32(0u, null, 0, 0); last_flush = 0; _InitializeTreeData(); _InitializeLazyMatch(); } internal int End() { if (status != 42 && status != 113 && status != 666) { return -2; } pending = null; head = null; prev = null; window = null; if (status != 113) { return 0; } return -3; } private void SetDeflater() { switch (config.Flavor) { case DeflateFlavor.Store: DeflateFunction = DeflateNone; break; case DeflateFlavor.Fast: DeflateFunction = DeflateFast; break; case DeflateFlavor.Slow: DeflateFunction = DeflateSlow; break; } } internal int SetParams(CompressionLevel level, CompressionStrategy strategy) { int result = 0; if (compressionLevel != level) { Config config = Config.Lookup(level); if (config.Flavor != this.config.Flavor && _codec.TotalBytesIn != 0L) { result = _codec.Deflate(FlushType.Partial); } compressionLevel = level; this.config = config; SetDeflater(); } compressionStrategy = strategy; return result; } internal int SetDictionary(byte[] dictionary) { int num = dictionary.Length; int sourceIndex = 0; if (dictionary == null || status != 42) { throw new ZlibException("Stream error."); } _codec._Adler32 = Adler.Adler32(_codec._Adler32, dictionary, 0, dictionary.Length); if (num < 3) { return 0; } if (num > w_size - 262) { num = w_size - 262; sourceIndex = dictionary.Length - num; } Array.Copy(dictionary, sourceIndex, window, 0, num); strstart = num; blockStart = num; ins_h = window[0] & 0xFF; ins_h = ((ins_h << hash_shift) ^ (window[1] & 0xFF)) & hash_mask; for (int i = 0; i <= num - 3; i++) { ins_h = ((ins_h << hash_shift) ^ (window[i + 2] & 0xFF)) & hash_mask; prev[i & w_mask] = head[ins_h]; head[ins_h] = (short)i; } return 0; } internal int Deflate(FlushType flush) { if (_codec.OutputBuffer == null || (_codec.InputBuffer == null && _codec.AvailableBytesIn != 0) || (status == 666 && flush != FlushType.Finish)) { _codec.Message = _ErrorMessage[4]; throw new ZlibException($"Something is fishy. [{_codec.Message}]"); } if (_codec.AvailableBytesOut == 0) { _codec.Message = _ErrorMessage[7]; throw new ZlibException("OutputBuffer is full (AvailableBytesOut == 0)"); } int num = last_flush; last_flush = (int)flush; if (status == 42) { int num2 = 8 + (w_bits - 8 << 4) << 8; int num3 = (int)((compressionLevel - 1) & (CompressionLevel)255) >> 1; if (num3 > 3) { num3 = 3; } num2 |= num3 << 6; if (strstart != 0) { num2 |= 0x20; } num2 += 31 - num2 % 31; status = 113; pending[pendingCount++] = (byte)(num2 >> 8); pending[pendingCount++] = (byte)num2; if (strstart != 0) { pending[pendingCount++] = (byte)((_codec._Adler32 & 0xFF000000u) >> 24); pending[pendingCount++] = (byte)((_codec._Adler32 & 0xFF0000) >> 16); pending[pendingCount++] = (byte)((_codec._Adler32 & 0xFF00) >> 8); pending[pendingCount++] = (byte)(_codec._Adler32 & 0xFF); } _codec._Adler32 = Adler.Adler32(0u, null, 0, 0); } if (pendingCount != 0) { _codec.flush_pending(); if (_codec.AvailableBytesOut == 0) { last_flush = -1; return 0; } } else if (_codec.AvailableBytesIn == 0 && (int)flush <= num && flush != FlushType.Finish) { return 0; } if (status == 666 && _codec.AvailableBytesIn != 0) { _codec.Message = _ErrorMessage[7]; throw new ZlibException("status == FINISH_STATE && _codec.AvailableBytesIn != 0"); } if (_codec.AvailableBytesIn != 0 || lookahead != 0 || (flush != FlushType.None && status != 666)) { BlockState blockState = DeflateFunction(flush); if (blockState == BlockState.FinishStarted || blockState == BlockState.FinishDone) { status = 666; } switch (blockState) { case BlockState.NeedMore: case BlockState.FinishStarted: if (_codec.AvailableBytesOut == 0) { last_flush = -1; } return 0; case BlockState.BlockDone: if (flush == FlushType.Partial) { _tr_align(); } else { _tr_stored_block(0, 0, eof: false); if (flush == FlushType.Full) { for (int i = 0; i < hash_size; i++) { head[i] = 0; } } } _codec.flush_pending(); if (_codec.AvailableBytesOut == 0) { last_flush = -1; return 0; } break; } } if (flush != FlushType.Finish) { return 0; } if (!WantRfc1950HeaderBytes || Rfc1950BytesEmitted) { return 1; } pending[pendingCount++] = (byte)((_codec._Adler32 & 0xFF000000u) >> 24); pending[pendingCount++] = (byte)((_codec._Adler32 & 0xFF0000) >> 16); pending[pendingCount++] = (byte)((_codec._Adler32 & 0xFF00) >> 8); pending[pendingCount++] = (byte)(_codec._Adler32 & 0xFF); _codec.flush_pending(); Rfc1950BytesEmitted = true; if (pendingCount == 0) { return 1; } return 0; } } public class DeflateStream : Stream { private readonly ZlibBaseStream _baseStream; private bool _disposed; public virtual FlushType FlushMode { get { return _baseStream._flushMode; } set { if (_disposed) { throw new ObjectDisposedException("DeflateStream"); } _baseStream._flushMode = value; } } public int BufferSize { get { return _baseStream._bufferSize; } set { if (_disposed) { throw new ObjectDisposedException("DeflateStream"); } if (_baseStream._workingBuffer != null) { throw new ZlibException("The working buffer is already set."); } if (value < 1024) { throw new ZlibException($"Don't be silly. {value} bytes?? Use a bigger buffer, at least {1024}."); } _baseStream._bufferSize = value; } } public CompressionStrategy Strategy { get { return _baseStream.Strategy; } set { if (_disposed) { throw new ObjectDisposedException("DeflateStream"); } _baseStream.Strategy = value; } } public virtual long TotalIn => _baseStream._z.TotalBytesIn; public virtual long TotalOut => _baseStream._z.TotalBytesOut; public override bool CanRead { get { if (_disposed) { throw new ObjectDisposedException("DeflateStream"); } return _baseStream._stream.CanRead; } } public override bool CanSeek => false; public override bool CanWrite { get { if (_disposed) { throw new ObjectDisposedException("DeflateStream"); } return _baseStream._stream.CanWrite; } } public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Writer) { return _baseStream._z.TotalBytesOut; } if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Reader) { return _baseStream._z.TotalBytesIn; } return 0L; } set { throw new NotSupportedException(); } } public MemoryStream InputBuffer => new MemoryStream(_baseStream._z.InputBuffer, _baseStream._z.NextIn, _baseStream._z.AvailableBytesIn); public DeflateStream(Stream stream, CompressionMode mode, CompressionLevel level = CompressionLevel.Default, Encoding forceEncoding = null) { _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.DEFLATE, forceEncoding); } protected override void Dispose(bool disposing) { try { if (!_disposed) { if (disposing) { _baseStream?.Dispose(); } _disposed = true; } } finally { base.Dispose(disposing); } } public override void Flush() { if (_disposed) { throw new ObjectDisposedException("DeflateStream"); } _baseStream.Flush(); } public override int Read(byte[] buffer, int offset, int count) { if (_disposed) { throw new ObjectDisposedException("DeflateStream"); } return _baseStream.Read(buffer, offset, count); } public override int ReadByte() { if (_disposed) { throw new ObjectDisposedException("DeflateStream"); } return _baseStream.ReadByte(); } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { if (_disposed) { throw new ObjectDisposedException("DeflateStream"); } _baseStream.Write(buffer, offset, count); } public override void WriteByte(byte value) { if (_disposed) { throw new ObjectDisposedException("DeflateStream"); } _baseStream.WriteByte(value); } } public enum FlushType { None, Partial, Sync, Full, Finish } public class GZipStream : Stream { internal static readonly DateTime UNIX_EPOCH = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); private string _comment; private string _fileName; internal ZlibBaseStream BaseStream; private bool _disposed; private bool _firstReadDone; private int _headerByteCount; private readonly Encoding _encoding; public DateTime? LastModified { get; set; } public virtual FlushType FlushMode { get { return BaseStream._flushMode; } set { if (_disposed) { throw new ObjectDisposedException("GZipStream"); } BaseStream._flushMode = value; } } public int BufferSize { get { return BaseStream._bufferSize; } set { if (_disposed) { throw new ObjectDisposedException("GZipStream"); } if (BaseStream._workingBuffer != null) { throw new ZlibException("The working buffer is already set."); } if (value < 1024) { throw new ZlibException($"Don't be silly. {value} bytes?? Use a bigger buffer, at least {1024}."); } BaseStream._bufferSize = value; } } internal virtual long TotalIn => BaseStream._z.TotalBytesIn; internal virtual long TotalOut => BaseStream._z.TotalBytesOut; public override bool CanRead { get { if (_disposed) { throw new ObjectDisposedException("GZipStream"); } return BaseStream._stream.CanRead; } } public override bool CanSeek => false; public override bool CanWrite { get { if (_disposed) { throw new ObjectDisposedException("GZipStream"); } return BaseStream._stream.CanWrite; } } public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { if (BaseStream._streamMode == ZlibBaseStream.StreamMode.Writer) { return BaseStream._z.TotalBytesOut + _headerByteCount; } if (BaseStream._streamMode == ZlibBaseStream.StreamMode.Reader) { return BaseStream._z.TotalBytesIn + BaseStream._gzipHeaderByteCount; } return 0L; } set { throw new NotSupportedException(); } } public string Comment { get { return _comment; } set { if (_disposed) { throw new ObjectDisposedException("GZipStream"); } _comment = value; } } public string FileName { get { return _fileName; } set { if (_disposed) { throw new ObjectDisposedException("GZipStream"); } _fileName = value; if (_fileName == null) { return; } if (_fileName.IndexOf("/") != -1) { _fileName = _fileName.Replace("/", "\\"); } if (_fileName.EndsWith("\\")) { throw new InvalidOperationException("Illegal filename"); } if (_fileName.IndexOf("\\") == -1) { return; } int length = _fileName.Length; int num = length; while (--num >= 0) { if (_fileName[num] == '\\') { _fileName = _fileName.Substring(num + 1, length - num - 1); } } } } public int Crc32 { get; private set; } public GZipStream(Stream stream, CompressionMode mode) : this(stream, mode, CompressionLevel.Default, Encoding.UTF8) { } public GZipStream(Stream stream, CompressionMode mode, CompressionLevel level) : this(stream, mode, level, Encoding.UTF8) { } public GZipStream(Stream stream, CompressionMode mode, CompressionLevel level, Encoding encoding) { BaseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.GZIP, encoding); _encoding = encoding; } protected override void Dispose(bool disposing) { try { if (!_disposed) { if (disposing && BaseStream != null) { BaseStream.Dispose(); Crc32 = BaseStream.Crc32; } _disposed = true; } } finally { base.Dispose(disposing); } } public override void Flush() { if (_disposed) { throw new ObjectDisposedException("GZipStream"); } BaseStream.Flush(); } public override int Read(byte[] buffer, int offset, int count) { if (_disposed) { throw new ObjectDisposedException("GZipStream"); } int result = BaseStream.Read(buffer, offset, count); if (!_firstReadDone) { _firstReadDone = true; FileName = BaseStream._GzipFileName; Comment = BaseStream._GzipComment; } return result; } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { if (_disposed) { throw new ObjectDisposedException("GZipStream"); } if (BaseStream._streamMode == ZlibBaseStream.StreamMode.Undefined) { if (!BaseStream._wantCompress) { throw new InvalidOperationException(); } _headerByteCount = EmitHeader(); } BaseStream.Write(buffer, offset, count); } private int EmitHeader() { byte[] array = ((Comment == null) ? null : _encoding.GetBytes(Comment)); byte[] array2 = ((FileName == null) ? null : _encoding.GetBytes(FileName)); int num = ((Comment != null) ? (array.Length + 1) : 0); int num2 = ((FileName != null) ? (array2.Length + 1) : 0); byte[] array3 = new byte[10 + num + num2]; int num3 = 0; array3[num3++] = 31; array3[num3++] = 139; array3[num3++] = 8; byte b = 0; if (Comment != null) { b ^= 0x10; } if (FileName != null) { b ^= 8; } array3[num3++] = b; if (!LastModified.HasValue) { LastModified = DateTime.Now; } int value = (int)(LastModified.Value - UNIX_EPOCH).TotalSeconds; DataConverter.LittleEndian.PutBytes(array3, num3, value); num3 += 4; array3[num3++] = 0; array3[num3++] = byte.MaxValue; if (num2 != 0) { Array.Copy(array2, 0, array3, num3, num2 - 1); num3 += num2 - 1; array3[num3++] = 0; } if (num != 0) { Array.Copy(array, 0, array3, num3, num - 1); num3 += num - 1; array3[num3++] = 0; } BaseStream._stream.Write(array3, 0, array3.Length); return array3.Length; } } internal sealed class InflateBlocks { private enum InflateBlockMode { TYPE, LENS, STORED, TABLE, BTREE, DTREE, CODES, DRY, DONE, BAD } private const int MANY = 1440; internal static readonly int[] border = new int[19] { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; internal ZlibCodec _codec; internal int[] bb = new int[1]; internal int bitb; internal int bitk; internal int[] blens; internal uint check; internal object checkfn; internal InflateCodes codes = new InflateCodes(); internal int end; internal int[] hufts; internal int index; internal InfTree inftree = new InfTree(); internal int last; internal int left; private InflateBlockMode mode; internal int readAt; internal int table; internal int[] tb = new int[1]; internal byte[] window; internal int writeAt; internal InflateBlocks(ZlibCodec codec, object checkfn, int w) { _codec = codec; hufts = new int[4320]; window = new byte[w]; end = w; this.checkfn = checkfn; mode = InflateBlockMode.TYPE; Reset(); } internal uint Reset() { uint result = check; mode = InflateBlockMode.TYPE; bitk = 0; bitb = 0; readAt = (writeAt = 0); if (checkfn != null) { _codec._Adler32 = (check = Adler.Adler32(0u, null, 0, 0)); } return result; } internal int Process(int r) { int num = _codec.NextIn; int num2 = _codec.AvailableBytesIn; int num3 = bitb; int i = bitk; int num4 = writeAt; int num5 = ((num4 < readAt) ? (readAt - num4 - 1) : (end - num4)); while (true) { switch (mode) { case InflateBlockMode.TYPE: { for (; i < 3; i += 8) { if (num2 != 0) { r = 0; num2--; num3 |= (_codec.InputBuffer[num++] & 0xFF) << i; continue; } bitb = num3; bitk = i; _codec.AvailableBytesIn = num2; _codec.TotalBytesIn += num - _codec.NextIn; _codec.NextIn = num; writeAt = num4; return Flush(r); } int num6 = num3 & 7; last = num6 & 1; switch ((uint)(num6 >>> 1)) { case 0u: num3 >>= 3; i -= 3; num6 = i & 7; num3 >>= num6; i -= num6; mode = InflateBlockMode.LENS; break; case 1u: { int[] array = new int[1]; int[] array2 = new int[1]; int[][] array3 = new int[1][]; int[][] array4 = new int[1][]; InfTree.inflate_trees_fixed(array, array2, array3, array4, _codec); codes.Init(array[0], array2[0], array3[0], 0, array4[0], 0); num3 >>= 3; i -= 3; mode = InflateBlockMode.CODES; break; } case 2u: num3 >>= 3; i -= 3; mode = InflateBlockMode.TABLE; break; case 3u: num3 >>= 3; i -= 3; mode = InflateBlockMode.BAD; _codec.Message = "invalid block type"; r = -3; bitb = num3; bitk = i; _codec.AvailableBytesIn = num2; _codec.TotalBytesIn += num - _codec.NextIn; _codec.NextIn = num; writeAt = num4; return Flush(r); } break; } case InflateBlockMode.LENS: for (; i < 32; i += 8) { if (num2 != 0) { r = 0; num2--; num3 |= (_codec.InputBuffer[num++] & 0xFF) << i; continue; } bitb = num3; bitk = i; _codec.AvailableBytesIn = num2; _codec.TotalBytesIn += num - _codec.NextIn; _codec.NextIn = num; writeAt = num4; return Flush(r); } if (((~num3 >> 16) & 0xFFFF) != (num3 & 0xFFFF)) { mode = InflateBlockMode.BAD; _codec.Message = "invalid stored block lengths"; r = -3; bitb = num3; bitk = i; _codec.AvailableBytesIn = num2; _codec.TotalBytesIn += num - _codec.NextIn; _codec.NextIn = num; writeAt = num4; return Flush(r); } left = num3 & 0xFFFF; num3 = (i = 0); mode = ((left != 0) ? InflateBlockMode.STORED : ((last != 0) ? InflateBlockMode.DRY : InflateBlockMode.TYPE)); break; case InflateBlockMode.STORED: { if (num2 == 0) { bitb = num3; bitk = i; _codec.AvailableBytesIn = num2; _codec.TotalBytesIn += num - _codec.NextIn; _codec.NextIn = num; writeAt = num4; return Flush(r); } if (num5 == 0) { if (num4 == end && readAt != 0) { num4 = 0; num5 = ((num4 < readAt) ? (readAt - num4 - 1) : (end - num4)); } if (num5 == 0) { writeAt = num4; r = Flush(r); num4 = writeAt; num5 = ((num4 < readAt) ? (readAt - num4 - 1) : (end - num4)); if (num4 == end && readAt != 0) { num4 = 0; num5 = ((num4 < readAt) ? (readAt - num4 - 1) : (end - num4)); } if (num5 == 0) { bitb = num3; bitk = i; _codec.AvailableBytesIn = num2; _codec.TotalBytesIn += num - _codec.NextIn; _codec.NextIn = num; writeAt = num4; return Flush(r); } } } r = 0; int num6 = left; if (num6 > num2) { num6 = num2; } if (num6 > num5) { num6 = num5; } Array.Copy(_codec.InputBuffer, num, window, num4, num6); num += num6; num2 -= num6; num4 += num6; num5 -= num6; if ((left -= num6) == 0) { mode = ((last != 0) ? InflateBlockMode.DRY : InflateBlockMode.TYPE); } break; } case InflateBlockMode.TABLE: { for (; i < 14; i += 8) { if (num2 != 0) { r = 0; num2--; num3 |= (_codec.InputBuffer[num++] & 0xFF) << i; continue; } bitb = num3; bitk = i; _codec.AvailableBytesIn = num2; _codec.TotalBytesIn += num - _codec.NextIn; _codec.NextIn = num; writeAt = num4; return Flush(r); } int num6 = (table = num3 & 0x3FFF); if ((num6 & 0x1F) > 29 || ((num6 >> 5) & 0x1F) > 29) { mode = InflateBlockMode.BAD; _codec.Message = "too many length or distance symbols"; r = -3; bitb = num3; bitk = i; _codec.AvailableBytesIn = num2; _codec.TotalBytesIn += num - _codec.NextIn; _codec.NextIn = num; writeAt = num4; return Flush(r); } num6 = 258 + (num6 & 0x1F) + ((num6 >> 5) & 0x1F); if (blens == null || blens.Length < num6) { blens = new int[num6]; } else { Array.Clear(blens, 0, num6); } num3 >>= 14; i -= 14; index = 0; mode = InflateBlockMode.BTREE; goto case InflateBlockMode.BTREE; } case InflateBlockMode.BTREE: { while (index < 4 + (table >> 10)) { for (; i < 3; i += 8) { if (num2 != 0) { r = 0; num2--; num3 |= (_codec.InputBuffer[num++] & 0xFF) << i; continue; } bitb = num3; bitk = i; _codec.AvailableBytesIn = num2; _codec.TotalBytesIn += num - _codec.NextIn; _codec.NextIn = num; writeAt = num4; return Flush(r); } blens[border[index++]] = num3 & 7; num3 >>= 3; i -= 3; } while (index < 19) { blens[border[index++]] = 0; } bb[0] = 7; int num6 = inftree.inflate_trees_bits(blens, bb, tb, hufts, _codec); if (num6 != 0) { r = num6; if (r == -3) { blens = null; mode = InflateBlockMode.BAD; } bitb = num3; bitk = i; _codec.AvailableBytesIn = num2; _codec.TotalBytesIn += num - _codec.NextIn; _codec.NextIn = num; writeAt = num4; return Flush(r); } index = 0; mode = InflateBlockMode.DTREE; goto case InflateBlockMode.DTREE; } case InflateBlockMode.DTREE: { int num6; while (true) { num6 = table; if (index >= 258 + (num6 & 0x1F) + ((num6 >> 5) & 0x1F)) { break; } for (num6 = bb[0]; i < num6; i += 8) { if (num2 != 0) { r = 0; num2--; num3 |= (_codec.InputBuffer[num++] & 0xFF) << i; continue; } bitb = num3; bitk = i; _codec.AvailableBytesIn = num2; _codec.TotalBytesIn += num - _codec.NextIn; _codec.NextIn = num; writeAt = num4; return Flush(r); } num6 = hufts[(tb[0] + (num3 & InternalInflateConstants.InflateMask[num6])) * 3 + 1]; int num7 = hufts[(tb[0] + (num3 & InternalInflateConstants.InflateMask[num6])) * 3 + 2]; if (num7 < 16) { num3 >>= num6; i -= num6; blens[index++] = num7; continue; } int num8 = ((num7 == 18) ? 7 : (num7 - 14)); int num9 = ((num7 == 18) ? 11 : 3); for (; i < num6 + num8; i += 8) { if (num2 != 0) { r = 0; num2--; num3 |= (_codec.InputBuffer[num++] & 0xFF) << i; continue; } bitb = num3; bitk = i; _codec.AvailableBytesIn = num2; _codec.TotalBytesIn += num - _codec.NextIn; _codec.NextIn = num; writeAt = num4; return Flush(r); } num3 >>= num6; i -= num6; num9 += num3 & InternalInflateConstants.InflateMask[num8]; num3 >>= num8; i -= num8; num8 = index; num6 = table; if (num8 + num9 > 258 + (num6 & 0x1F) + ((num6 >> 5) & 0x1F) || (num7 == 16 && num8 < 1)) { blens = null; mode = InflateBlockMode.BAD; _codec.Message = "invalid bit length repeat"; r = -3; bitb = num3; bitk = i; _codec.AvailableBytesIn = num2; _codec.TotalBytesIn += num - _codec.NextIn; _codec.NextIn = num; writeAt = num4; return Flush(r); } num7 = ((num7 == 16) ? blens[num8 - 1] : 0); do { blens[num8++] = num7; } while (--num9 != 0); index = num8; } tb[0] = -1; int[] array5 = new int[1] { 9 }; int[] array6 = new int[1] { 6 }; int[] array7 = new int[1]; int[] array8 = new int[1]; num6 = table; num6 = inftree.inflate_trees_dynamic(257 + (num6 & 0x1F), 1 + ((num6 >> 5) & 0x1F), blens, array5, array6, array7, array8, hufts, _codec); if (num6 != 0) { if (num6 == -3) { blens = null; mode = InflateBlockMode.BAD; } r = num6; bitb = num3; bitk = i; _codec.AvailableBytesIn = num2; _codec.TotalBytesIn += num - _codec.NextIn; _codec.NextIn = num; writeAt = num4; return Flush(r); } codes.Init(array5[0], array6[0], hufts, array7[0], hufts, array8[0]); mode = InflateBlockMode.CODES; goto case InflateBlockMode.CODES; } case InflateBlockMode.CODES: bitb = num3; bitk = i; _codec.AvailableBytesIn = num2; _codec.TotalBytesIn += num - _codec.NextIn; _codec.NextIn = num; writeAt = num4; r = codes.Process(this, r); if (r != 1) { return Flush(r); } r = 0; num = _codec.NextIn; num2 = _codec.AvailableBytesIn; num3 = bitb; i = bitk; num4 = writeAt; num5 = ((num4 < readAt) ? (readAt - num4 - 1) : (end - num4)); if (last == 0) { mode = InflateBlockMode.TYPE; break; } mode = InflateBlockMode.DRY; goto case InflateBlockMode.DRY; case InflateBlockMode.DRY: writeAt = num4; r = Flush(r); num4 = writeAt; num5 = ((num4 < readAt) ? (readAt - num4 - 1) : (end - num4)); if (readAt != writeAt) { bitb = num3; bitk = i; _codec.AvailableBytesIn = num2; _codec.TotalBytesIn += num - _codec.NextIn; _codec.NextIn = num; writeAt = num4; return Flush(r); } mode = InflateBlockMode.DONE; goto case InflateBlockMode.DONE; case InflateBlockMode.DONE: r = 1; bitb = num3; bitk = i; _codec.AvailableBytesIn = num2; _codec.TotalBytesIn += num - _codec.NextIn; _codec.NextIn = num; writeAt = num4; return Flush(r); case InflateBlockMode.BAD: r = -3; bitb = num3; bitk = i; _codec.AvailableBytesIn = num2; _codec.TotalBytesIn += num - _codec.NextIn; _codec.NextIn = num; writeAt = num4; return Flush(r); default: r = -2; bitb = num3; bitk = i; _codec.AvailableBytesIn = num2; _codec.TotalBytesIn += num - _codec.NextIn; _codec.NextIn = num; writeAt = num4; return Flush(r); } } } internal void Free() { Reset(); window = null; hufts = null; } internal void SetDictionary(byte[] d, int start, int n) { Array.Copy(d, start, window, 0, n); readAt = (writeAt = n); } internal int SyncPoint() { if (mode != InflateBlockMode.LENS) { return 0; } return 1; } internal int Flush(int r) { for (int i = 0; i < 2; i++) { int num = ((i != 0) ? (writeAt - readAt) : (((readAt <= writeAt) ? writeAt : end) - readAt)); if (num == 0) { if (r == -5) { r = 0; } return r; } if (num > _codec.AvailableBytesOut) { num = _codec.AvailableBytesOut; } if (num != 0 && r == -5) { r = 0; } _codec.AvailableBytesOut -= num; _codec.TotalBytesOut += num; if (checkfn != null) { _codec._Adler32 = (check = Adler.Adler32(check, window, readAt, num)); } Array.Copy(window, readAt, _codec.OutputBuffer, _codec.NextOut, num); _codec.NextOut += num; readAt += num; if (readAt == end && i == 0) { readAt = 0; if (writeAt == end) { writeAt = 0; } } else { i++; } } return r; } } internal static class InternalInflateConstants { internal static readonly int[] InflateMask = new int[17] { 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535 }; } internal sealed class InflateCodes { private const int START = 0; private const int LEN = 1; private const int LENEXT = 2; private const int DIST = 3; private const int DISTEXT = 4; private const int COPY = 5; private const int LIT = 6; private const int WASH = 7; private const int END = 8; private const int BADCODE = 9; internal int bitsToGet; internal byte dbits; internal int dist; internal int[] dtree; internal int dtree_index; internal byte lbits; internal int len; internal int lit; internal int[] ltree; internal int ltree_index; internal int mode; internal int need; internal int[] tree; internal int tree_index; internal void Init(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index) { mode = 0; lbits = (byte)bl; dbits = (byte)bd; ltree = tl; ltree_index = tl_index; dtree = td; dtree_index = td_index; tree = null; } internal int Process(InflateBlocks blocks, int r) { int num = 0; int num2 = 0; int num3 = 0; ZlibCodec codec = blocks._codec; num3 = codec.NextIn; int num4 = codec.AvailableBytesIn; num = blocks.bitb; num2 = blocks.bitk; int num5 = blocks.writeAt; int num6 = ((num5 < blocks.readAt) ? (blocks.readAt - num5 - 1) : (blocks.end - num5)); while (true) { switch (mode) { case 0: if (num6 >= 258 && num4 >= 10) { blocks.bitb = num; blocks.bitk = num2; codec.AvailableBytesIn = num4; codec.TotalBytesIn += num3 - codec.NextIn; codec.NextIn = num3; blocks.writeAt = num5; r = InflateFast(lbits, dbits, ltree, ltree_index, dtree, dtree_index, blocks, codec); num3 = codec.NextIn; num4 = codec.AvailableBytesIn; num = blocks.bitb; num2 = blocks.bitk; num5 = blocks.writeAt; num6 = ((num5 < blocks.readAt) ? (blocks.readAt - num5 - 1) : (blocks.end - num5)); if (r != 0) { mode = ((r == 1) ? 7 : 9); break; } } need = lbits; tree = ltree; tree_index = ltree_index; mode = 1; goto case 1; case 1: { int num7; for (num7 = need; num2 < num7; num2 += 8) { if (num4 != 0) { r = 0; num4--; num |= (codec.InputBuffer[num3++] & 0xFF) << num2; continue; } int num11 = (tree_index + (num & InternalInflateConstants.InflateMask[num2])) * 3; if (num2 >= tree[num11 + 1]) { break; } blocks.bitb = num; blocks.bitk = num2; codec.AvailableBytesIn = num4; codec.TotalBytesIn += num3 - codec.NextIn; codec.NextIn = num3; blocks.writeAt = num5; return blocks.Flush(r); } int num9 = (tree_index + (num & InternalInflateConstants.InflateMask[num7])) * 3; num >>= tree[num9 + 1]; num2 -= tree[num9 + 1]; int num10 = tree[num9]; if (num10 == 0) { lit = tree[num9 + 2]; mode = 6; break; } if ((num10 & 0x10) != 0) { bitsToGet = num10 & 0xF; len = tree[num9 + 2]; mode = 2; break; } if ((num10 & 0x40) == 0) { need = num10; tree_index = num9 / 3 + tree[num9 + 2]; break; } if ((num10 & 0x20) != 0) { mode = 7; break; } mode = 9; codec.Message = "invalid literal/length code"; r = -3; blocks.bitb = num; blocks.bitk = num2; codec.AvailableBytesIn = num4; codec.TotalBytesIn += num3 - codec.NextIn; codec.NextIn = num3; blocks.writeAt = num5; return blocks.Flush(r); } case 2: { int num7; for (num7 = bitsToGet; num2 < num7; num2 += 8) { if (num4 != 0) { r = 0; num4--; num |= (codec.InputBuffer[num3++] & 0xFF) << num2; continue; } blocks.bitb = num; blocks.bitk = num2; codec.AvailableBytesIn = num4; codec.TotalBytesIn += num3 - codec.NextIn; codec.NextIn = num3; blocks.writeAt = num5; return blocks.Flush(r); } len += num & InternalInflateConstants.InflateMask[num7]; num >>= num7; num2 -= num7; need = dbits; tree = dtree; tree_index = dtree_index; mode = 3; goto case 3; } case 3: { int num7; for (num7 = need; num2 < num7; num2 += 8) { if (num4 != 0) { r = 0; num4--; num |= (codec.InputBuffer[num3++] & 0xFF) << num2; continue; } int num8 = (tree_index + (num & InternalInflateConstants.InflateMask[num2])) * 3; if (num2 >= tree[num8 + 1]) { break; } blocks.bitb = num; blocks.bitk = num2; codec.AvailableBytesIn = num4; codec.TotalBytesIn += num3 - codec.NextIn; codec.NextIn = num3; blocks.writeAt = num5; return blocks.Flush(r); } int num9 = (tree_index + (num & InternalInflateConstants.InflateMask[num7])) * 3; num >>= tree[num9 + 1]; num2 -= tree[num9 + 1]; int num10 = tree[num9]; if ((num10 & 0x10) != 0) { bitsToGet = num10 & 0xF; dist = tree[num9 + 2]; mode = 4; break; } if ((num10 & 0x40) == 0) { need = num10; tree_index = num9 / 3 + tree[num9 + 2]; break; } mode = 9; codec.Message = "invalid distance code"; r = -3; blocks.bitb = num; blocks.bitk = num2; codec.AvailableBytesIn = num4; codec.TotalBytesIn += num3 - codec.NextIn; codec.NextIn = num3; blocks.writeAt = num5; return blocks.Flush(r); } case 4: { int num7; for (num7 = bitsToGet; num2 < num7; num2 += 8) { if (num4 != 0) { r = 0; num4--; num |= (codec.InputBuffer[num3++] & 0xFF) << num2; continue; } blocks.bitb = num; blocks.bitk = num2; codec.AvailableBytesIn = num4; codec.TotalBytesIn += num3 - codec.NextIn; codec.NextIn = num3; blocks.writeAt = num5; return blocks.Flush(r); } dist += num & InternalInflateConstants.InflateMask[num7]; num >>= num7; num2 -= num7; mode = 5; goto case 5; } case 5: { int i; for (i = num5 - dist; i < 0; i += blocks.end) { } while (len != 0) { if (num6 == 0) { if (num5 == blocks.end && blocks.readAt != 0) { num5 = 0; num6 = ((num5 < blocks.readAt) ? (blocks.readAt - num5 - 1) : (blocks.end - num5)); } if (num6 == 0) { blocks.writeAt = num5; r = blocks.Flush(r); num5 = blocks.writeAt; num6 = ((num5 < blocks.readAt) ? (blocks.readAt - num5 - 1) : (blocks.end - num5)); if (num5 == blocks.end && blocks.readAt != 0) { num5 = 0; num6 = ((num5 < blocks.readAt) ? (blocks.readAt - num5 - 1) : (blocks.end - num5)); } if (num6 == 0) { blocks.bitb = num; blocks.bitk = num2; codec.AvailableBytesIn = num4; codec.TotalBytesIn += num3 - codec.NextIn; codec.NextIn = num3; blocks.writeAt = num5; return blocks.Flush(r); } } } blocks.window[num5++] = blocks.window[i++]; num6--; if (i == blocks.end) { i = 0; } len--; } mode = 0; break; } case 6: if (num6 == 0) { if (num5 == blocks.end && blocks.readAt != 0) { num5 = 0; num6 = ((num5 < blocks.readAt) ? (blocks.readAt - num5 - 1) : (blocks.end - num5)); } if (num6 == 0) { blocks.writeAt = num5; r = blocks.Flush(r); num5 = blocks.writeAt; num6 = ((num5 < blocks.readAt) ? (blocks.readAt - num5 - 1) : (blocks.end - num5)); if (num5 == blocks.end && blocks.readAt != 0) { num5 = 0; num6 = ((num5 < blocks.readAt) ? (blocks.readAt - num5 - 1) : (blocks.end - num5)); } if (num6 == 0) { blocks.bitb = num; blocks.bitk = num2; codec.AvailableBytesIn = num4; codec.TotalBytesIn += num3 - codec.NextIn; codec.NextIn = num3; blocks.writeAt = num5; return blocks.Flush(r); } } } r = 0; blocks.window[num5++] = (byte)lit; num6--; mode = 0; break; case 7: if (num2 > 7) { num2 -= 8; num4++; num3--; } blocks.writeAt = num5; r = blocks.Flush(r); num5 = blocks.writeAt; num6 = ((num5 < blocks.readAt) ? (blocks.readAt - num5 - 1) : (blocks.end - num5)); if (blocks.readAt != blocks.writeAt) { blocks.bitb = num; blocks.bitk = num2; codec.AvailableBytesIn = num4; codec.TotalBytesIn += num3 - codec.NextIn; codec.NextIn = num3; blocks.writeAt = num5; return blocks.Flush(r); } mode = 8; goto case 8; case 8: r = 1; blocks.bitb = num; blocks.bitk = num2; codec.AvailableBytesIn = num4; codec.TotalBytesIn += num3 - codec.NextIn; codec.NextIn = num3; blocks.writeAt = num5; return blocks.Flush(r); case 9: r = -3; blocks.bitb = num; blocks.bitk = num2; codec.AvailableBytesIn = num4; codec.TotalBytesIn += num3 - codec.NextIn; codec.NextIn = num3; blocks.writeAt = num5; return blocks.Flush(r); default: r = -2; blocks.bitb = num; blocks.bitk = num2; codec.AvailableBytesIn = num4; codec.TotalBytesIn += num3 - codec.NextIn; codec.NextIn = num3; blocks.writeAt = num5; return blocks.Flush(r); } } } internal int InflateFast(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index, InflateBlocks s, ZlibCodec z) { int nextIn = z.NextIn; int num = z.AvailableBytesIn; int num2 = s.bitb; int num3 = s.bitk; int num4 = s.writeAt; int num5 = ((num4 < s.readAt) ? (s.readAt - num4 - 1) : (s.end - num4)); int num6 = InternalInflateConstants.InflateMask[bl]; int num7 = InternalInflateConstants.InflateMask[bd]; int num12; while (true) { if (num3 < 20) { num--; num2 |= (z.InputBuffer[nextIn++] & 0xFF) << num3; num3 += 8; continue; } int num8 = num2 & num6; int[] array = tl; int num9 = tl_index; int num10 = (num9 + num8) * 3; int num11; if ((num11 = array[num10]) == 0) { num2 >>= array[num10 + 1]; num3 -= array[num10 + 1]; s.window[num4++] = (byte)array[num10 + 2]; num5--; } else { while (true) { num2 >>= array[num10 + 1]; num3 -= array[num10 + 1]; if ((num11 & 0x10) != 0) { num11 &= 0xF; num12 = array[num10 + 2] + (num2 & InternalInflateConstants.InflateMask[num11]); num2 >>= num11; for (num3 -= num11; num3 < 15; num3 += 8) { num--; num2 |= (z.InputBuffer[nextIn++] & 0xFF) << num3; } num8 = num2 & num7; array = td; num9 = td_index; num10 = (num9 + num8) * 3; num11 = array[num10]; while (true) { num2 >>= array[num10 + 1]; num3 -= array[num10 + 1]; if ((num11 & 0x10) != 0) { break; } if ((num11 & 0x40) == 0) { num8 += array[num10 + 2]; num8 += num2 & InternalInflateConstants.InflateMask[num11]; num10 = (num9 + num8) * 3; num11 = array[num10]; continue; } z.Message = "invalid distance code"; num12 = z.AvailableBytesIn - num; num12 = ((num3 >> 3 < num12) ? (num3 >> 3) : num12); num += num12; nextIn -= num12; num3 -= num12 << 3; s.bitb = num2; s.bitk = num3; z.AvailableBytesIn = num; z.TotalBytesIn += nextIn - z.NextIn; z.NextIn = nextIn; s.writeAt = num4; return -3; } for (num11 &= 0xF; num3 < num11; num3 += 8) { num--; num2 |= (z.InputBuffer[nextIn++] & 0xFF) << num3; } int num13 = array[num10 + 2] + (num2 & InternalInflateConstants.InflateMask[num11]); num2 >>= num11; num3 -= num11; num5 -= num12; int num14; if (num4 >= num13) { num14 = num4 - num13; if (num4 - num14 > 0 && 2 > num4 - num14) { s.window[num4++] = s.window[num14++]; s.window[num4++] = s.window[num14++]; num12 -= 2; } else { Array.Copy(s.window, num14, s.window, num4, 2); num4 += 2; num14 += 2; num12 -= 2; } } else { num14 = num4 - num13; do { num14 += s.end; } while (num14 < 0); num11 = s.end - num14; if (num12 > num11) { num12 -= num11; if (num4 - num14 > 0 && num11 > num4 - num14) { do { s.window[num4++] = s.window[num14++]; } while (--num11 != 0); } else { Array.Copy(s.window, num14, s.window, num4, num11); num4 += num11; num14 += num11; num11 = 0; } num14 = 0; } } if (num4 - num14 > 0 && num12 > num4 - num14) { do { s.window[num4++] = s.window[num14++]; } while (--num12 != 0); break; } Array.Copy(s.window, num14, s.window, num4, num12); num4 += num12; num14 += num12; num12 = 0; break; } if ((num11 & 0x40) == 0) { num8 += array[num10 + 2]; num8 += num2 & InternalInflateConstants.InflateMask[num11]; num10 = (num9 + num8) * 3; if ((num11 = array[num10]) == 0) { num2 >>= array[num10 + 1]; num3 -= array[num10 + 1]; s.window[num4++] = (byte)array[num10 + 2]; num5--; break; } continue; } if ((num11 & 0x20) != 0) { num12 = z.AvailableBytesIn - num; num12 = ((num3 >> 3 < num12) ? (num3 >> 3) : num12); num += num12; nextIn -= num12; num3 -= num12 << 3; s.bitb = num2; s.bitk = num3; z.AvailableBytesIn = num; z.TotalBytesIn += nextIn - z.NextIn; z.NextIn = nextIn; s.writeAt = num4; return 1; } z.Message = "invalid literal/length code"; num12 = z.AvailableBytesIn - num; num12 = ((num3 >> 3 < num12) ? (num3 >> 3) : num12); num += num12; nextIn -= num12; num3 -= num12 << 3; s.bitb = num2; s.bitk = num3; z.AvailableBytesIn = num; z.TotalBytesIn += nextIn - z.NextIn; z.NextIn = nextIn; s.writeAt = num4; return -3; } } if (num5 < 258 || num < 10) { break; } } num12 = z.AvailableBytesIn - num; num12 = ((num3 >> 3 < num12) ? (num3 >> 3) : num12); num += num12; nextIn -= num12; num3 -= num12 << 3; s.bitb = num2; s.bitk = num3; z.AvailableBytesIn = num; z.TotalBytesIn += nextIn - z.NextIn; z.NextIn = nextIn; s.writeAt = num4; return 0; } } internal sealed class InflateManager { private enum InflateManagerMode { METHOD, FLAG, DICT4, DICT3, DICT2, DICT1, DICT0, BLOCKS, CHECK4, CHECK3, CHECK2, CHECK1, DONE, BAD } private const int PRESET_DICT = 32; private const int Z_DEFLATED = 8; private static readonly byte[] mark = new byte[4] { 0, 0, 255, 255 }; internal ZlibCodec _codec; internal InflateBlocks blocks; internal uint computedCheck; internal uint expectedCheck; internal int marker; internal int method; private InflateManagerMode mode; internal int wbits; internal bool HandleRfc1950HeaderBytes { get; set; } = true; public InflateManager() { } public InflateManager(bool expectRfc1950HeaderBytes) { HandleRfc1950HeaderBytes = expectRfc1950HeaderBytes; } internal int Reset() { _codec.TotalBytesIn = (_codec.TotalBytesOut = 0L); _codec.Message = null; mode = ((!HandleRfc1950HeaderBytes) ? InflateManagerMode.BLOCKS : InflateManagerMode.METHOD); blocks.Reset(); return 0; } internal int End() { if (blocks != null) { blocks.Free(); } blocks = null; return 0; } internal int Initialize(ZlibCodec codec, int w) { _codec = codec; _codec.Message = null; blocks = null; if (w < 8 || w > 15) { End(); throw new ZlibException("Bad window size."); } wbits = w; blocks = new InflateBlocks(codec, HandleRfc1950HeaderBytes ? this : null, 1 << w); Reset(); return 0; } internal int Inflate(FlushType flush) { if (_codec.InputBuffer == null) { throw new ZlibException("InputBuffer is null. "); } int num = 0; int num2 = -5; while (true) { switch (mode) { case InflateManagerMode.METHOD: if (_codec.AvailableBytesIn == 0) { return num2; } num2 = num; _codec.AvailableBytesIn--; _codec.TotalBytesIn++; if (((method = _codec.InputBuffer[_codec.NextIn++]) & 0xF) != 8) { mode = InflateManagerMode.BAD; _codec.Message = $"unknown compression method (0x{method:X2})"; marker = 5; } else if ((method >> 4) + 8 > wbits) { mode = InflateManagerMode.BAD; _codec.Message = $"invalid window size ({(method >> 4) + 8})"; marker = 5; } else { mode = InflateManagerMode.FLAG; } break; case InflateManagerMode.FLAG: { if (_codec.AvailableBytesIn == 0) { return num2; } num2 = num; _codec.AvailableBytesIn--; _codec.TotalBytesIn++; int num3 = _codec.InputBuffer[_codec.NextIn++] & 0xFF; if (((method << 8) + num3) % 31 != 0) { mode = InflateManagerMode.BAD; _codec.Message = "incorrect header check"; marker = 5; } else { mode = (((num3 & 0x20) == 0) ? InflateManagerMode.BLOCKS : InflateManagerMode.DICT4); } break; } case InflateManagerMode.DICT4: if (_codec.AvailableBytesIn == 0) { return num2; } num2 = num; _codec.AvailableBytesIn--; _codec.TotalBytesIn++; expectedCheck = (uint)((_codec.InputBuffer[_codec.NextIn++] << 24) & 0xFF000000u); mode = InflateManagerMode.DICT3; break; case InflateManagerMode.DICT3: if (_codec.AvailableBytesIn == 0) { return num2; } num2 = num; _codec.AvailableBytesIn--; _codec.TotalBytesIn++; expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 16) & 0xFF0000); mode = InflateManagerMode.DICT2; break; case InflateManagerMode.DICT2: if (_codec.AvailableBytesIn == 0) { return num2; } num2 = num; _codec.AvailableBytesIn--; _codec.TotalBytesIn++; expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 8) & 0xFF00); mode = InflateManagerMode.DICT1; break; case InflateManagerMode.DICT1: if (_codec.AvailableBytesIn == 0) { return num2; } num2 = num; _codec.AvailableBytesIn--; _codec.TotalBytesIn++; expectedCheck += (uint)(_codec.InputBuffer[_codec.NextIn++] & 0xFF); _codec._Adler32 = expectedCheck; mode = InflateManagerMode.DICT0; return 2; case InflateManagerMode.DICT0: mode = InflateManagerMode.BAD; _codec.Message = "need dictionary"; marker = 0; return -2; case InflateManagerMode.BLOCKS: num2 = blocks.Process(num2); switch (num2) { case -3: mode = InflateManagerMode.BAD; marker = 0; goto end_IL_0025; case 0: num2 = num; break; } if (num2 != 1) { return num2; } num2 = num; computedCheck = blocks.Reset(); if (!HandleRfc1950HeaderBytes) { mode = InflateManagerMode.DONE; return 1; } mode = InflateManagerMode.CHECK4; break; case InflateManagerMode.CHECK4: if (_codec.AvailableBytesIn == 0) { return num2; } num2 = num; _codec.AvailableBytesIn--; _codec.TotalBytesIn++; expectedCheck = (uint)((_codec.InputBuffer[_codec.NextIn++] << 24) & 0xFF000000u); mode = InflateManagerMode.CHECK3; break; case InflateManagerMode.CHECK3: if (_codec.AvailableBytesIn == 0) { return num2; } num2 = num; _codec.AvailableBytesIn--; _codec.TotalBytesIn++; expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 16) & 0xFF0000); mode = InflateManagerMode.CHECK2; break; case InflateManagerMode.CHECK2: if (_codec.AvailableBytesIn == 0) { return num2; } num2 = num; _codec.AvailableBytesIn--; _codec.TotalBytesIn++; expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 8) & 0xFF00); mode = InflateManagerMode.CHECK1; break; case InflateManagerMode.CHECK1: if (_codec.AvailableBytesIn == 0) { return num2; } num2 = num; _codec.AvailableBytesIn--; _codec.TotalBytesIn++; expectedCheck += (uint)(_codec.InputBuffer[_codec.NextIn++] & 0xFF); if (computedCheck != expectedCheck) { mode = InflateManagerMode.BAD; _codec.Message = "incorrect data check"; marker = 5; break; } mode = InflateManagerMode.DONE; return 1; case InflateManagerMode.DONE: return 1; case InflateManagerMode.BAD: throw new ZlibException($"Bad state ({_codec.Message})"); default: { throw new ZlibException("Stream error."); } end_IL_0025: break; } } } internal int SetDictionary(byte[] dictionary) { int start = 0; int num = dictionary.Length; if (mode != InflateManagerMode.DICT0) { throw new ZlibException("Stream error."); } if (Adler.Adler32(1u, dictionary, 0, dictionary.Length) != _codec._Adler32) { return -3; } _codec._Adler32 = Adler.Adler32(0u, null, 0, 0); if (num >= 1 << wbits) { num = (1 << wbits) - 1; start = dictionary.Length - num; } blocks.SetDictionary(dictionary, start, num); mode = InflateManagerMode.BLOCKS; return 0; } internal int Sync() { if (mode != InflateManagerMode.BAD) { mode = InflateManagerMode.BAD; marker = 0; } int num; if ((num = _codec.AvailableBytesIn) == 0) { return -5; } int num2 = _codec.NextIn; int num3 = marker; while (num != 0 && num3 < 4) { num3 = ((_codec.InputBuffer[num2] != mark[num3]) ? ((_codec.InputBuffer[num2] == 0) ? (4 - num3) : 0) : (num3 + 1)); num2++; num--; } _codec.TotalBytesIn += num2 - _codec.NextIn; _codec.NextIn = num2; _codec.AvailableBytesIn = num; marker = num3; if (num3 != 4) { return -3; } long totalBytesIn = _codec.TotalBytesIn; long totalBytesOut = _codec.TotalBytesOut; Reset(); _codec.TotalBytesIn = totalBytesIn; _codec.TotalBytesOut = totalBytesOut; mode = InflateManagerMode.BLOCKS; return 0; } internal int SyncPoint(ZlibCodec z) { return blocks.SyncPoint(); } } internal sealed class InfTree { private const int MANY = 1440; private const int Z_OK = 0; private const int Z_STREAM_END = 1; private const int Z_NEED_DICT = 2; private const int Z_ERRNO = -1; private const int Z_STREAM_ERROR = -2; private const int Z_DATA_ERROR = -3; private const int Z_MEM_ERROR = -4; private const int Z_BUF_ERROR = -5; private const int Z_VERSION_ERROR = -6; internal const int fixed_bl = 9; internal const int fixed_bd = 5; internal const int BMAX = 15; internal static readonly int[] fixed_tl = new int[1536] { 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 192, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 160, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 224, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 144, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 208, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 176, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 240, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 200, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 168, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 232, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 152, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 216, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 184, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 248, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 196, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 164, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 228, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 148, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 212, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 180, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 244, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 204, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 172, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 236, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 156, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 220, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 188, 0, 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 252, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 194, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 162, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 226, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 146, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 210, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 178, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 242, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 202, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 170, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 234, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 154, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 218, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 186, 0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 250, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 198, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 166, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 230, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 150, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 214, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 182, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 246, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 206, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 174, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 238, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 158, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 222, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 190, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 254, 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 193, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 161, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 225, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 145, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 209, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 177, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 241, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 201, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 169, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 233, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 153, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 217, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 185, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 249, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 197, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 165, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 229, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 149, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 213, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 181, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 245, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 205, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 173, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 237, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 157, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 221, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 189, 0, 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 253, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 195, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 163, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 227, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 147, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 211, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 179, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 243, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 203, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 171, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 235, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 155, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 219, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 187, 0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 251, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 199, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 167, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 231, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 151, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 215, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 183, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 247, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 207, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 175, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 239, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 159, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 223, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 191, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 255 }; internal static readonly int[] fixed_td = new int[96] { 80, 5, 1, 87, 5, 257, 83, 5, 17, 91, 5, 4097, 81, 5, 5, 89, 5, 1025, 85, 5, 65, 93, 5, 16385, 80, 5, 3, 88, 5, 513, 84, 5, 33, 92, 5, 8193, 82, 5, 9, 90, 5, 2049, 86, 5, 129, 192, 5, 24577, 80, 5, 2, 87, 5, 385, 83, 5, 25, 91, 5, 6145, 81, 5, 7, 89, 5, 1537, 85, 5, 97, 93, 5, 24577, 80, 5, 4, 88, 5, 769, 84, 5, 49, 92, 5, 12289, 82, 5, 13, 90, 5, 3073, 86, 5, 193, 192, 5, 24577 }; internal static readonly int[] cplens = new int[31] { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; internal static readonly int[] cplext = new int[31] { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112 }; internal static readonly int[] cpdist = new int[30] { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 }; internal static readonly int[] cpdext = new int[30] { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; internal int[] c; internal int[] hn; internal int[] r; internal int[] u; internal int[] v; internal int[] x; private int huft_build(int[] b, int bindex, int n, int s, int[] d, int[] e, int[] t, int[] m, int[] hp, int[] hn, int[] v) { int num = 0; int num2 = n; do { c[b[bindex + num]]++; num++; num2--; } while (num2 != 0); if (c[0] == n) { t[0] = -1; m[0] = 0; return 0; } int num3 = m[0]; int i; for (i = 1; i <= 15 && c[i] == 0; i++) { } int j = i; if (num3 < i) { num3 = i; } num2 = 15; while (num2 != 0 && c[num2] == 0) { num2--; } int num4 = num2; if (num3 > num2) { num3 = num2; } m[0] = num3; int num5 = 1 << i; while (i < num2) { if ((num5 -= c[i]) < 0) { return -3; } i++; num5 <<= 1; } if ((num5 -= c[num2]) < 0) { return -3; } c[num2] += num5; i = (x[1] = 0); num = 1; int num6 = 2; while (--num2 != 0) { i = (x[num6] = i + c[num]); num6++; num++; } num2 = 0; num = 0; do { if ((i = b[bindex + num]) != 0) { v[x[i]++] = num2; } num++; } while (++num2 < n); n = x[num4]; num2 = (x[0] = 0); num = 0; int num7 = -1; int num8 = -num3; u[0] = 0; int num9 = 0; int num10 = 0; for (; j <= num4; j++) { int num11 = c[j]; while (num11-- != 0) { int num12; while (j > num8 + num3) { num7++; num8 += num3; num10 = num4 - num8; num10 = ((num10 > num3) ? num3 : num10); if ((num12 = 1 << (i = j - num8)) > num11 + 1) { num12 -= num11 + 1; num6 = j; if (i < num10) { while (++i < num10 && (num12 <<= 1) > c[++num6]) { num12 -= c[num6]; } } } num10 = 1 << i; if (hn[0] + num10 > 1440) { return -3; } num9 = (u[num7] = hn[0]); hn[0] += num10; if (num7 != 0) { x[num7] = num2; r[0] = (sbyte)i; r[1] = (sbyte)num3; i = SharedUtils.URShift(num2, num8 - num3); r[2] = num9 - u[num7 - 1] - i; Array.Copy(r, 0, hp, (u[num7 - 1] + i) * 3, 3); } else { t[0] = num9; } } r[1] = (sbyte)(j - num8); if (num >= n) { r[0] = 192; } else if (v[num] < s) { r[0] = (sbyte)((v[num] >= 256) ? 96 : 0); r[2] = v[num++]; } else { r[0] = (sbyte)(e[v[num] - s] + 16 + 64); r[2] = d[v[num++] - s]; } num12 = 1 << j - num8; for (i = SharedUtils.URShift(num2, num8); i < num10; i += num12) { Array.Copy(r, 0, hp, (num9 + i) * 3, 3); } i = 1 << j - 1; while ((num2 & i) != 0) { num2 ^= i; i = SharedUtils.URShift(i, 1); } num2 ^= i; int num13 = (1 << num8) - 1; while ((num2 & num13) != x[num7]) { num7--; num8 -= num3; num13 = (1 << num8) - 1; } } } if (num5 == 0 || num4 == 1) { return 0; } return -5; } internal int inflate_trees_bits(int[] c, int[] bb, int[] tb, int[] hp, ZlibCodec z) { initWorkArea(19); hn[0] = 0; int num = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v); if (num == -3) { z.Message = "oversubscribed dynamic bit lengths tree"; } else if (num == -5 || bb[0] == 0) { z.Message = "incomplete dynamic bit lengths tree"; num = -3; } return num; } internal int inflate_trees_dynamic(int nl, int nd, int[] c, int[] bl, int[] bd, int[] tl, int[] td, int[] hp, ZlibCodec z) { initWorkArea(288); hn[0] = 0; int num = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v); if (num != 0 || bl[0] == 0) { switch (num) { case -3: z.Message = "oversubscribed literal/length tree"; break; default: z.Message = "incomplete literal/length tree"; num = -3; break; case -4: break; } return num; } initWorkArea(288); num = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v); if (num != 0 || (bd[0] == 0 && nl > 257)) { switch (num) { case -3: z.Message = "oversubscribed distance tree"; break; case -5: z.Message = "incomplete distance tree"; num = -3; break; default: z.Message = "empty distance tree with lengths"; num = -3; break; case -4: break; } return num; } return 0; } internal static int inflate_trees_fixed(int[] bl, int[] bd, int[][] tl, int[][] td, ZlibCodec z) { bl[0] = 9; bd[0] = 5; tl[0] = fixed_tl; td[0] = fixed_td; return 0; } private void initWorkArea(int vsize) { if (hn == null) { hn = new int[1]; v = new int[vsize]; c = new int[16]; r = new int[3]; u = new int[15]; x = new int[16]; return; } if (v.Length < vsize) { v = new int[vsize]; } Array.Clear(v, 0, vsize); Array.Clear(c, 0, 16); r[0] = 0; r[1] = 0; r[2] = 0; Array.Clear(u, 0, 15); Array.Clear(x, 0, 16); } } public enum CompressionLevel { None = 0, Level0 = 0, BestSpeed = 1, Level1 = 1, Level2 = 2, Level3 = 3, Level4 = 4, Level5 = 5, Default = 6, Level6 = 6, Level7 = 7, Level8 = 8, BestCompression = 9, Level9 = 9 } public enum CompressionStrategy { Default, Filtered, HuffmanOnly } public class ZlibException : Exception { public ZlibException() { } public ZlibException(string s) : base(s) { } } internal class SharedUtils { public static int URShift(int number, int bits) { return number >>> bits; } public static int ReadInput(TextReader sourceTextReader, byte[] target, int start, int count) { if (target.Length == 0) { return 0; } char[] array = new char[target.Length]; int num = sourceTextReader.Read(array, start, count); if (num == 0) { return -1; } for (int i = start; i < start + num; i++) { target[i] = (byte)array[i]; } return num; } } internal static class InternalConstants { internal static readonly int MAX_BITS = 15; internal static readonly int BL_CODES = 19; internal static readonly int D_CODES = 30; internal static readonly int LITERALS = 256; internal static readonly int LENGTH_CODES = 29; internal static readonly int L_CODES = LITERALS + 1 + LENGTH_CODES; internal static readonly int MAX_BL_BITS = 7; internal static readonly int REP_3_6 = 16; internal static readonly int REPZ_3_10 = 17; internal static readonly int REPZ_11_138 = 18; } internal sealed class StaticTree { internal static readonly short[] lengthAndLiteralsTreeCodes; internal static readonly short[] distTreeCodes; internal static readonly int[] extra_blbits; internal static readonly StaticTree Literals; internal static readonly StaticTree Distances; internal static readonly StaticTree BitLengths; internal short[] treeCodes; internal int[] extraBits; internal int extraBase; internal int elems; internal int maxLength; private StaticTree(short[] treeCodes, int[] extraBits, int extraBase, int elems, int maxLength) { this.treeCodes = treeCodes; this.extraBits = extraBits; this.extraBase = extraBase; this.elems = elems; this.maxLength = maxLength; } static StaticTree() { lengthAndLiteralsTreeCodes = new short[576] { 12, 8, 140, 8, 76, 8, 204, 8, 44, 8, 172, 8, 108, 8, 236, 8, 28, 8, 156, 8, 92, 8, 220, 8, 60, 8, 188, 8, 124, 8, 252, 8, 2, 8, 130, 8, 66, 8, 194, 8, 34, 8, 162, 8, 98, 8, 226, 8, 18, 8, 146, 8, 82, 8, 210, 8, 50, 8, 178, 8, 114, 8, 242, 8, 10, 8, 138, 8, 74, 8, 202, 8, 42, 8, 170, 8, 106, 8, 234, 8, 26, 8, 154, 8, 90, 8, 218, 8, 58, 8, 186, 8, 122, 8, 250, 8, 6, 8, 134, 8, 70, 8, 198, 8, 38, 8, 166, 8, 102, 8, 230, 8, 22, 8, 150, 8, 86, 8, 214, 8, 54, 8, 182, 8, 118, 8, 246, 8, 14, 8, 142, 8, 78, 8, 206, 8, 46, 8, 174, 8, 110, 8, 238, 8, 30, 8, 158, 8, 94, 8, 222, 8, 62, 8, 190, 8, 126, 8, 254, 8, 1, 8, 129, 8, 65, 8, 193, 8, 33, 8, 161, 8, 97, 8, 225, 8, 17, 8, 145, 8, 81, 8, 209, 8, 49, 8, 177, 8, 113, 8, 241, 8, 9, 8, 137, 8, 73, 8, 201, 8, 41, 8, 169, 8, 105, 8, 233, 8, 25, 8, 153, 8, 89, 8, 217, 8, 57, 8, 185, 8, 121, 8, 249, 8, 5, 8, 133, 8, 69, 8, 197, 8, 37, 8, 165, 8, 101, 8, 229, 8, 21, 8, 149, 8, 85, 8, 213, 8, 53, 8, 181, 8, 117, 8, 245, 8, 13, 8, 141, 8, 77, 8, 205, 8, 45, 8, 173, 8, 109, 8, 237, 8, 29, 8, 157, 8, 93, 8, 221, 8, 61, 8, 189, 8, 125, 8, 253, 8, 19, 9, 275, 9, 147, 9, 403, 9, 83, 9, 339, 9, 211, 9, 467, 9, 51, 9, 307, 9, 179, 9, 435, 9, 115, 9, 371, 9, 243, 9, 499, 9, 11, 9, 267, 9, 139, 9, 395, 9, 75, 9, 331, 9, 203, 9, 459, 9, 43, 9, 299, 9, 171, 9, 427, 9, 107, 9, 363, 9, 235, 9, 491, 9, 27, 9, 283, 9, 155, 9, 411, 9, 91, 9, 347, 9, 219, 9, 475, 9, 59, 9, 315, 9, 187, 9, 443, 9, 123, 9, 379, 9, 251, 9, 507, 9, 7, 9, 263, 9, 135, 9, 391, 9, 71, 9, 327, 9, 199, 9, 455, 9, 39, 9, 295, 9, 167, 9, 423, 9, 103, 9, 359, 9, 231, 9, 487, 9, 23, 9, 279, 9, 151, 9, 407, 9, 87, 9, 343, 9, 215, 9, 471, 9, 55, 9, 311, 9, 183, 9, 439, 9, 119, 9, 375, 9, 247, 9, 503, 9, 15, 9, 271, 9, 143, 9, 399, 9, 79, 9, 335, 9, 207, 9, 463, 9, 47, 9, 303, 9, 175, 9, 431, 9, 111, 9, 367, 9, 239, 9, 495, 9, 31, 9, 287, 9, 159, 9, 415, 9, 95, 9, 351, 9, 223, 9, 479, 9, 63, 9, 319, 9, 191, 9, 447, 9, 127, 9, 383, 9, 255, 9, 511, 9, 0, 7, 64, 7, 32, 7, 96, 7, 16, 7, 80, 7, 48, 7, 112, 7, 8, 7, 72, 7, 40, 7, 104, 7, 24, 7, 88, 7, 56, 7, 120, 7, 4, 7, 68, 7, 36, 7, 100, 7, 20, 7, 84, 7, 52, 7, 116, 7, 3, 8, 131, 8, 67, 8, 195, 8, 35, 8, 163, 8, 99, 8, 227, 8 }; distTreeCodes = new short[60] { 0, 5, 16, 5, 8, 5, 24, 5, 4, 5, 20, 5, 12, 5, 28, 5, 2, 5, 18, 5, 10, 5, 26, 5, 6, 5, 22, 5, 14, 5, 30, 5, 1, 5, 17, 5, 9, 5, 25, 5, 5, 5, 21, 5, 13, 5, 29, 5, 3, 5, 19, 5, 11, 5, 27, 5, 7, 5, 23, 5 }; extra_blbits = new int[19] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 }; Literals = new StaticTree(lengthAndLiteralsTreeCodes, DeflateManager.ExtraLengthBits, InternalConstants.LITERALS + 1, InternalConstants.L_CODES, InternalConstants.MAX_BITS); Distances = new StaticTree(distTreeCodes, DeflateManager.ExtraDistanceBits, 0, InternalConstants.D_CODES, InternalConstants.MAX_BITS); BitLengths = new StaticTree(null, extra_blbits, 0, InternalConstants.BL_CODES, InternalConstants.MAX_BL_BITS); } } internal sealed class Adler { private static readonly uint BASE = 65521u; private static readonly int NMAX = 5552; internal static uint Adler32(uint adler, byte[] buf, int index, int len) { if (buf == null) { return 1u; } uint num = adler & 0xFFFF; uint num2 = (adler >> 16) & 0xFFFF; while (len > 0) { int num3 = ((len < NMAX) ? len : NMAX); len -= num3; while (num3 >= 16) { num += buf[index++]; num2 += num; num += buf[index++]; num2 += num; num += buf[index++]; num2 += num; num += buf[index++]; num2 += num; num += buf[index++]; num2 += num; num += buf[index++]; num2 += num; num += buf[index++]; num2 += num; num += buf[index++]; num2 += num; num += buf[index++]; num2 += num; num += buf[index++]; num2 += num; num += buf[index++]; num2 += num; num += buf[index++]; num2 += num; num += buf[index++]; num2 += num; num += buf[index++]; num2 += num; num += buf[index++]; num2 += num; num += buf[index++]; num2 += num; num3 -= 16; } if (num3 != 0) { do { num += buf[index++]; num2 += num; } while (--num3 != 0); } num %= BASE; num2 %= BASE; } return (num2 << 16) | num; } } internal enum ZlibStreamFlavor { ZLIB = 1950, DEFLATE, GZIP } internal class ZlibBaseStream : Stream { internal enum StreamMode { Writer, Reader, Undefined } protected internal ZlibCodec _z; protected internal StreamMode _streamMode = StreamMode.Undefined; protected internal FlushType _flushMode; protected internal ZlibStreamFlavor _flavor; protected internal CompressionMode _compressionMode; protected internal CompressionLevel _level; protected internal byte[] _workingBuffer; protected internal int _bufferSize = 16384; protected internal byte[] _buf1 = new byte[1]; protected internal Stream _stream; protected internal CompressionStrategy Strategy; private readonly CRC32 crc; protected internal string _GzipFileName; protected internal string _GzipComment; protected internal DateTime _GzipMtime; protected internal int _gzipHeaderByteCount; private readonly Encoding _encoding; private bool nomoreinput; private bool isDisposed; internal int Crc32 { get { if (crc == null) { return 0; } return crc.Crc32Result; } } protected internal bool _wantCompress => _compressionMode == CompressionMode.Compress; private ZlibCodec z { get { if (_z == null) { bool flag = _flavor == ZlibStreamFlavor.ZLIB; _z = new ZlibCodec(); if (_compressionMode == CompressionMode.Decompress) { _z.InitializeInflate(flag); } else { _z.Strategy = Strategy; _z.InitializeDeflate(_level, flag); } } return _z; } } private byte[] workingBuffer { get { if (_workingBuffer == null) { _workingBuffer = new byte[_bufferSize]; } return _workingBuffer; } } public override bool CanRead => _stream.CanRead; public override bool CanSeek => _stream.CanSeek; public override bool CanWrite => _stream.CanWrite; public override long Length => _stream.Length; public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } public ZlibBaseStream(Stream stream, CompressionMode compressionMode, CompressionLevel level, ZlibStreamFlavor flavor, Encoding encoding) { _flushMode = FlushType.None; _stream = stream; _compressionMode = compressionMode; _flavor = flavor; _level = level; _encoding = encoding; if (flavor == ZlibStreamFlavor.GZIP) { crc = new CRC32(); } } public override void Write(byte[] buffer, int offset, int count) { if (crc != null) { crc.SlurpBlock(buffer, offset, count); } if (_streamMode == StreamMode.Undefined) { _streamMode = StreamMode.Writer; } else if (_streamMode != StreamMode.Writer) { throw new ZlibException("Cannot Write after Reading."); } if (count == 0) { return; } z.InputBuffer = buffer; _z.NextIn = offset; _z.AvailableBytesIn = count; bool flag = false; do { _z.OutputBuffer = workingBuffer; _z.NextOut = 0; _z.AvailableBytesOut = _workingBuffer.Length; int num = (_wantCompress ? _z.Deflate(_flushMode) : _z.Inflate(_flushMode)); if (num != 0 && num != 1) { throw new ZlibException((_wantCompress ? "de" : "in") + "flating: " + _z.Message); } _stream.Write(_workingBuffer, 0, _workingBuffer.Length - _z.AvailableBytesOut); flag = _z.AvailableBytesIn == 0 && _z.AvailableBytesOut != 0; if (_flavor == ZlibStreamFlavor.GZIP && !_wantCompress) { flag = _z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0; } } while (!flag); } private void finish() { if (_z == null) { return; } if (_streamMode == StreamMode.Writer) { bool flag = false; do { _z.OutputBuffer = workingBuffer; _z.NextOut = 0; _z.AvailableBytesOut = _workingBuffer.Length; int num = (_wantCompress ? _z.Deflate(FlushType.Finish) : _z.Inflate(FlushType.Finish)); if (num != 1 && num != 0) { string text = (_wantCompress ? "de" : "in") + "flating"; if (_z.Message == null) { throw new ZlibException($"{text}: (rc = {num})"); } throw new ZlibException(text + ": " + _z.Message); } if (_workingBuffer.Length - _z.AvailableBytesOut > 0) { _stream.Write(_workingBuffer, 0, _workingBuffer.Length - _z.AvailableBytesOut); } flag = _z.AvailableBytesIn == 0 && _z.AvailableBytesOut != 0; if (_flavor == ZlibStreamFlavor.GZIP && !_wantCompress) { flag = _z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0; } } while (!flag); Flush(); if (_flavor == ZlibStreamFlavor.GZIP) { if (!_wantCompress) { throw new ZlibException("Writing with decompression is not supported."); } int crc32Result = crc.Crc32Result; _stream.Write(DataConverter.LittleEndian.GetBytes(crc32Result), 0, 4); int value = (int)(crc.TotalBytesRead & 0xFFFFFFFFu); _stream.Write(DataConverter.LittleEndian.GetBytes(value), 0, 4); } } else { if (_streamMode != StreamMode.Reader || _flavor != ZlibStreamFlavor.GZIP) { return; } if (_wantCompress) { throw new ZlibException("Reading with compression is not supported."); } if (_z.TotalBytesOut == 0L) { return; } byte[] array = new byte[8]; if (_z.AvailableBytesIn != 8) { Array.Copy(_z.InputBuffer, _z.NextIn, array, 0, _z.AvailableBytesIn); int num2 = 8 - _z.AvailableBytesIn; int num3 = _stream.Read(array, _z.AvailableBytesIn, num2); if (num2 != num3) { throw new ZlibException($"Protocol error. AvailableBytesIn={_z.AvailableBytesIn + num3}, expected 8"); } } else { Array.Copy(_z.InputBuffer, _z.NextIn, array, 0, array.Length); } int @int = DataConverter.LittleEndian.GetInt32(array, 0); int crc32Result2 = crc.Crc32Result; int int2 = DataConverter.LittleEndian.GetInt32(array, 4); int num4 = (int)(_z.TotalBytesOut & 0xFFFFFFFFu); if (crc32Result2 != @int) { throw new ZlibException($"Bad CRC32 in GZIP stream. (actual({crc32Result2:X8})!=expected({@int:X8}))"); } if (num4 != int2) { throw new ZlibException($"Bad size in GZIP stream. (actual({num4})!=expected({int2}))"); } } } private void end() { if (z != null) { if (_wantCompress) { _z.EndDeflate(); } else { _z.EndInflate(); } _z = null; } } protected override void Dispose(bool disposing) { if (isDisposed) { return; } isDisposed = true; base.Dispose(disposing); if (!disposing || _stream == null) { return; } try { finish(); } finally { end(); _stream?.Dispose(); _stream = null; } } public override void Flush() { _stream.Flush(); } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { _stream.SetLength(value); } private string ReadZeroTerminatedString() { List list = new List(); bool flag = false; do { if (_stream.Read(_buf1, 0, 1) != 1) { throw new ZlibException("Unexpected EOF reading GZIP header."); } if (_buf1[0] == 0) { flag = true; } else { list.Add(_buf1[0]); } } while (!flag); byte[] array = list.ToArray(); return _encoding.GetString(array, 0, array.Length); } private int _ReadAndValidateGzipHeader() { int num = 0; byte[] array = new byte[10]; int num2 = _stream.Read(array, 0, array.Length); switch (num2) { case 0: return 0; default: throw new ZlibException("Not a valid GZIP stream."); case 10: { if (array[0] != 31 || array[1] != 139 || array[2] != 8) { throw new ZlibException("Bad GZIP header."); } int @int = DataConverter.LittleEndian.GetInt32(array, 4); DateTime ePOCH = TarHeader.EPOCH; _GzipMtime = ePOCH.AddSeconds(@int); num += num2; if ((array[3] & 4) == 4) { num2 = _stream.Read(array, 0, 2); num += num2; short num3 = (short)(array[0] + array[1] * 256); byte[] array2 = new byte[num3]; num2 = _stream.Read(array2, 0, array2.Length); if (num2 != num3) { throw new ZlibException("Unexpected end-of-file reading GZIP header."); } num += num2; } if ((array[3] & 8) == 8) { _GzipFileName = ReadZeroTerminatedString(); } if ((array[3] & 0x10) == 16) { _GzipComment = ReadZeroTerminatedString(); } if ((array[3] & 2) == 2) { Read(_buf1, 0, 1); } return num; } } } public override int Read(byte[] buffer, int offset, int count) { if (_streamMode == StreamMode.Undefined) { if (!_stream.CanRead) { throw new ZlibException("The stream is not readable."); } _streamMode = StreamMode.Reader; z.AvailableBytesIn = 0; if (_flavor == ZlibStreamFlavor.GZIP) { _gzipHeaderByteCount = _ReadAndValidateGzipHeader(); if (_gzipHeaderByteCount == 0) { return 0; } } } if (_streamMode != StreamMode.Reader) { throw new ZlibException("Cannot Read after Writing."); } if (count == 0) { return 0; } if (nomoreinput && _wantCompress) { return 0; } if (buffer == null) { throw new ArgumentNullException("buffer"); } if (count < 0) { throw new ArgumentOutOfRangeException("count"); } if (offset < buffer.GetLowerBound(0)) { throw new ArgumentOutOfRangeException("offset"); } if (offset + count > buffer.GetLength(0)) { throw new ArgumentOutOfRangeException("count"); } int num = 0; _z.OutputBuffer = buffer; _z.NextOut = offset; _z.AvailableBytesOut = count; _z.InputBuffer = workingBuffer; do { if (_z.AvailableBytesIn == 0 && !nomoreinput) { _z.NextIn = 0; _z.AvailableBytesIn = _stream.Read(_workingBuffer, 0, _workingBuffer.Length); if (_z.AvailableBytesIn == 0) { nomoreinput = true; } } num = (_wantCompress ? _z.Deflate(_flushMode) : _z.Inflate(_flushMode)); if (nomoreinput && num == -5) { return 0; } if (num != 0 && num != 1) { throw new ZlibException(string.Format("{0}flating: rc={1} msg={2}", _wantCompress ? "de" : "in", num, _z.Message)); } } while (((!nomoreinput && num != 1) || _z.AvailableBytesOut != count) && _z.AvailableBytesOut > 0 && !nomoreinput && num == 0); if (_z.AvailableBytesOut > 0) { if (num == 0) { _ = _z.AvailableBytesIn; } if (nomoreinput && _wantCompress) { num = _z.Deflate(FlushType.Finish); if (num != 0 && num != 1) { throw new ZlibException($"Deflating: rc={num} msg={_z.Message}"); } } } num = count - _z.AvailableBytesOut; if (crc != null) { crc.SlurpBlock(buffer, offset, num); } return num; } } internal sealed class ZlibCodec { public byte[] InputBuffer; public int NextIn; public int AvailableBytesIn; public long TotalBytesIn; public byte[] OutputBuffer; public int NextOut; public int AvailableBytesOut; public long TotalBytesOut; public string Message; internal DeflateManager dstate; internal InflateManager istate; internal uint _Adler32; public CompressionLevel CompressLevel = CompressionLevel.Default; public int WindowBits = 15; public CompressionStrategy Strategy; public int Adler32 => (int)_Adler32; public ZlibCodec() { } public ZlibCodec(CompressionMode mode) { switch (mode) { case CompressionMode.Compress: if (InitializeDeflate() != 0) { throw new ZlibException("Cannot initialize for deflate."); } break; case CompressionMode.Decompress: if (InitializeInflate() != 0) { throw new ZlibException("Cannot initialize for inflate."); } break; default: throw new ZlibException("Invalid ZlibStreamFlavor."); } } public int InitializeInflate() { return InitializeInflate(WindowBits); } public int InitializeInflate(bool expectRfc1950Header) { return InitializeInflate(WindowBits, expectRfc1950Header); } public int InitializeInflate(int windowBits) { WindowBits = windowBits; return InitializeInflate(windowBits, expectRfc1950Header: true); } public int InitializeInflate(int windowBits, bool expectRfc1950Header) { WindowBits = windowBits; if (dstate != null) { throw new ZlibException("You may not call InitializeInflate() after calling InitializeDeflate()."); } istate = new InflateManager(expectRfc1950Header); return istate.Initialize(this, windowBits); } public int Inflate(FlushType flush) { if (istate == null) { throw new ZlibException("No Inflate State!"); } return istate.Inflate(flush); } public int EndInflate() { if (istate == null) { throw new ZlibException("No Inflate State!"); } int result = istate.End(); istate = null; return result; } public int SyncInflate() { if (istate == null) { throw new ZlibException("No Inflate State!"); } return istate.Sync(); } public int InitializeDeflate() { return _InternalInitializeDeflate(wantRfc1950Header: true); } public int InitializeDeflate(CompressionLevel level) { CompressLevel = level; return _InternalInitializeDeflate(wantRfc1950Header: true); } public int InitializeDeflate(CompressionLevel level, bool wantRfc1950Header) { CompressLevel = level; return _InternalInitializeDeflate(wantRfc1950Header); } public int InitializeDeflate(CompressionLevel level, int bits) { CompressLevel = level; WindowBits = bits; return _InternalInitializeDeflate(wantRfc1950Header: true); } public int InitializeDeflate(CompressionLevel level, int bits, bool wantRfc1950Header) { CompressLevel = level; WindowBits = bits; return _InternalInitializeDeflate(wantRfc1950Header); } private int _InternalInitializeDeflate(bool wantRfc1950Header) { if (istate != null) { throw new ZlibException("You may not call InitializeDeflate() after calling InitializeInflate()."); } dstate = new DeflateManager(); dstate.WantRfc1950HeaderBytes = wantRfc1950Header; return dstate.Initialize(this, CompressLevel, WindowBits, Strategy); } public int Deflate(FlushType flush) { if (dstate == null) { throw new ZlibException("No Deflate State!"); } return dstate.Deflate(flush); } public int EndDeflate() { if (dstate == null) { throw new ZlibException("No Deflate State!"); } dstate = null; return 0; } public void ResetDeflate() { if (dstate == null) { throw new ZlibException("No Deflate State!"); } dstate.Reset(); } public int SetDeflateParams(CompressionLevel level, CompressionStrategy strategy) { if (dstate == null) { throw new ZlibException("No Deflate State!"); } return dstate.SetParams(level, strategy); } public int SetDictionary(byte[] dictionary) { if (istate != null) { return istate.SetDictionary(dictionary); } if (dstate != null) { return dstate.SetDictionary(dictionary); } throw new ZlibException("No Inflate or Deflate state!"); } internal void flush_pending() { int num = dstate.pendingCount; if (num > AvailableBytesOut) { num = AvailableBytesOut; } if (num != 0) { if (dstate.pending.Length <= dstate.nextPending || OutputBuffer.Length <= NextOut || dstate.pending.Length < dstate.nextPending + num || OutputBuffer.Length < NextOut + num) { throw new ZlibException($"Invalid State. (pending.Length={dstate.pending.Length}, pendingCount={dstate.pendingCount})"); } Array.Copy(dstate.pending, dstate.nextPending, OutputBuffer, NextOut, num); NextOut += num; dstate.nextPending += num; TotalBytesOut += num; AvailableBytesOut -= num; dstate.pendingCount -= num; if (dstate.pendingCount == 0) { dstate.nextPending = 0; } } } internal int read_buf(byte[] buf, int start, int size) { int num = AvailableBytesIn; if (num > size) { num = size; } if (num == 0) { return 0; } AvailableBytesIn -= num; if (dstate.WantRfc1950HeaderBytes) { _Adler32 = Adler.Adler32(_Adler32, InputBuffer, NextIn, num); } Array.Copy(InputBuffer, NextIn, buf, start, num); NextIn += num; TotalBytesIn += num; return num; } } internal static class ZlibConstants { public const int WindowBitsMax = 15; public const int WindowBitsDefault = 15; public const int Z_OK = 0; public const int Z_STREAM_END = 1; public const int Z_NEED_DICT = 2; public const int Z_STREAM_ERROR = -2; public const int Z_DATA_ERROR = -3; public const int Z_BUF_ERROR = -5; public const int WorkingBufferSizeDefault = 16384; public const int WorkingBufferSizeMin = 1024; } public class ZlibStream : Stream { private readonly ZlibBaseStream _baseStream; private bool _disposed; public virtual FlushType FlushMode { get { return _baseStream._flushMode; } set { if (_disposed) { throw new ObjectDisposedException("ZlibStream"); } _baseStream._flushMode = value; } } public int BufferSize { get { return _baseStream._bufferSize; } set { if (_disposed) { throw new ObjectDisposedException("ZlibStream"); } if (_baseStream._workingBuffer != null) { throw new ZlibException("The working buffer is already set."); } if (value < 1024) { throw new ZlibException($"Don't be silly. {value} bytes?? Use a bigger buffer, at least {1024}."); } _baseStream._bufferSize = value; } } public virtual long TotalIn => _baseStream._z.TotalBytesIn; public virtual long TotalOut => _baseStream._z.TotalBytesOut; public override bool CanRead { get { if (_disposed) { throw new ObjectDisposedException("ZlibStream"); } return _baseStream._stream.CanRead; } } public override bool CanSeek => false; public override bool CanWrite { get { if (_disposed) { throw new ObjectDisposedException("ZlibStream"); } return _baseStream._stream.CanWrite; } } public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Writer) { return _baseStream._z.TotalBytesOut; } if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Reader) { return _baseStream._z.TotalBytesIn; } return 0L; } set { throw new NotSupportedException(); } } public ZlibStream(Stream stream, CompressionMode mode) : this(stream, mode, CompressionLevel.Default, Encoding.UTF8) { } public ZlibStream(Stream stream, CompressionMode mode, CompressionLevel level) : this(stream, mode, level, Encoding.UTF8) { } public ZlibStream(Stream stream, CompressionMode mode, CompressionLevel level, Encoding encoding) { _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.ZLIB, encoding); } protected override void Dispose(bool disposing) { try { if (!_disposed) { if (disposing) { _baseStream?.Dispose(); } _disposed = true; } } finally { base.Dispose(disposing); } } public override void Flush() { if (_disposed) { throw new ObjectDisposedException("ZlibStream"); } _baseStream.Flush(); } public override int Read(byte[] buffer, int offset, int count) { if (_disposed) { throw new ObjectDisposedException("ZlibStream"); } return _baseStream.Read(buffer, offset, count); } public override int ReadByte() { if (_disposed) { throw new ObjectDisposedException("ZlibStream"); } return _baseStream.ReadByte(); } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { if (_disposed) { throw new ObjectDisposedException("ZlibStream"); } _baseStream.Write(buffer, offset, count); } public override void WriteByte(byte value) { if (_disposed) { throw new ObjectDisposedException("ZlibStream"); } _baseStream.WriteByte(value); } } } namespace SharpCompress.Compressors.Deflate64 { internal enum BlockType { Uncompressed, Static, Dynamic } public sealed class Deflate64Stream : Stream { private const int DEFAULT_BUFFER_SIZE = 8192; private Stream _stream; private CompressionMode _mode; private InflaterManaged _inflater; private byte[] _buffer; public override bool CanRead { get { if (_stream == null) { return false; } if (_mode == CompressionMode.Decompress) { return _stream.CanRead; } return false; } } public override bool CanWrite { get { if (_stream == null) { return false; } if (_mode == CompressionMode.Compress) { return _stream.CanWrite; } return false; } } public override bool CanSeek => false; public override long Length { get { throw new NotSupportedException("Deflate64: not supported"); } } public override long Position { get { throw new NotSupportedException("Deflate64: not supported"); } set { throw new NotSupportedException("Deflate64: not supported"); } } public Deflate64Stream(Stream stream, CompressionMode mode) { if (stream == null) { throw new ArgumentNullException("stream"); } if (mode != CompressionMode.Decompress) { throw new NotImplementedException("Deflate64: this implementation only supports decompression"); } if (!stream.CanRead) { throw new ArgumentException("Deflate64: input stream is not readable", "stream"); } InitializeInflater(stream, ZipCompressionMethod.Deflate64); } private void InitializeInflater(Stream stream, ZipCompressionMethod method = ZipCompressionMethod.Deflate) { if (!stream.CanRead) { throw new ArgumentException("Deflate64: input stream is not readable", "stream"); } _inflater = new InflaterManaged(method == ZipCompressionMethod.Deflate64); _stream = stream; _mode = CompressionMode.Decompress; _buffer = new byte[8192]; } public override void Flush() { EnsureNotDisposed(); } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException("Deflate64: not supported"); } public override void SetLength(long value) { throw new NotSupportedException("Deflate64: not supported"); } public override int Read(byte[] array, int offset, int count) { EnsureDecompressionMode(); ValidateParameters(array, offset, count); EnsureNotDisposed(); int num = offset; int num2 = count; while (true) { int num3 = _inflater.Inflate(array, num, num2); num += num3; num2 -= num3; if (num2 == 0 || _inflater.Finished()) { break; } int num4 = _stream.Read(_buffer, 0, _buffer.Length); if (num4 <= 0) { break; } if (num4 > _buffer.Length) { throw new InvalidDataException("Deflate64: invalid data"); } _inflater.SetInput(_buffer, 0, num4); } return count - num2; } private void ValidateParameters(byte[] array, int offset, int count) { if (array == null) { throw new ArgumentNullException("array"); } if (offset < 0) { throw new ArgumentOutOfRangeException("offset"); } if (count < 0) { throw new ArgumentOutOfRangeException("count"); } if (array.Length - offset < count) { throw new ArgumentException("Deflate64: invalid offset/count combination"); } } private void EnsureNotDisposed() { if (_stream == null) { ThrowStreamClosedException(); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void ThrowStreamClosedException() { throw new ObjectDisposedException(null, "Deflate64: stream has been disposed"); } private void EnsureDecompressionMode() { if (_mode != CompressionMode.Decompress) { ThrowCannotReadFromDeflateManagedStreamException(); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void ThrowCannotReadFromDeflateManagedStreamException() { throw new InvalidOperationException("Deflate64: cannot read from this stream"); } private void EnsureCompressionMode() { if (_mode != CompressionMode.Compress) { ThrowCannotWriteToDeflateManagedStreamException(); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void ThrowCannotWriteToDeflateManagedStreamException() { throw new InvalidOperationException("Deflate64: cannot write to this stream"); } public override void Write(byte[] array, int offset, int count) { ThrowCannotWriteToDeflateManagedStreamException(); } private void PurgeBuffers(bool disposing) { if (disposing && _stream != null) { Flush(); } } protected override void Dispose(bool disposing) { try { PurgeBuffers(disposing); } finally { try { if (disposing) { _stream?.Dispose(); } } finally { _stream = null; try { _inflater?.Dispose(); } finally { _inflater = null; base.Dispose(disposing); } } } } } internal sealed class DeflateInput { internal struct InputState { internal readonly int _count; internal readonly int _startIndex; internal InputState(int count, int startIndex) { _count = count; _startIndex = startIndex; } } internal byte[] Buffer { get; set; } internal int Count { get; set; } internal int StartIndex { get; set; } internal void ConsumeBytes(int n) { StartIndex += n; Count -= n; } internal InputState DumpState() { return new InputState(Count, StartIndex); } internal void RestoreState(InputState state) { Count = state._count; StartIndex = state._startIndex; } } internal static class FastEncoderStatics { internal static readonly byte[] FAST_ENCODER_TREE_STRUCTURE_DATA = new byte[98] { 236, 189, 7, 96, 28, 73, 150, 37, 38, 47, 109, 202, 123, 127, 74, 245, 74, 215, 224, 116, 161, 8, 128, 96, 19, 36, 216, 144, 64, 16, 236, 193, 136, 205, 230, 146, 236, 29, 105, 71, 35, 41, 171, 42, 129, 202, 101, 86, 101, 93, 102, 22, 64, 204, 237, 157, 188, 247, 222, 123, 239, 189, 247, 222, 123, 239, 189, 247, 186, 59, 157, 78, 39, 247, 223, 255, 63, 92, 102, 100, 1, 108, 246, 206, 74, 218, 201, 158, 33, 128, 170, 200, 31, 63, 126, 124, 31, 63 }; internal static readonly byte[] B_FINAL_FAST_ENCODER_TREE_STRUCTURE_DATA = new byte[98] { 237, 189, 7, 96, 28, 73, 150, 37, 38, 47, 109, 202, 123, 127, 74, 245, 74, 215, 224, 116, 161, 8, 128, 96, 19, 36, 216, 144, 64, 16, 236, 193, 136, 205, 230, 146, 236, 29, 105, 71, 35, 41, 171, 42, 129, 202, 101, 86, 101, 93, 102, 22, 64, 204, 237, 157, 188, 247, 222, 123, 239, 189, 247, 222, 123, 239, 189, 247, 186, 59, 157, 78, 39, 247, 223, 255, 63, 92, 102, 100, 1, 108, 246, 206, 74, 218, 201, 158, 33, 128, 170, 200, 31, 63, 126, 124, 31, 63 }; internal static readonly uint[] FAST_ENCODER_LITERAL_CODE_INFO = new uint[513] { 55278u, 317422u, 186350u, 448494u, 120814u, 382958u, 251886u, 514030u, 14318u, 51180u, 294u, 276462u, 145390u, 407534u, 79854u, 341998u, 210926u, 473070u, 47086u, 309230u, 178158u, 440302u, 112622u, 374766u, 243694u, 505838u, 30702u, 292846u, 161774u, 423918u, 6125u, 96238u, 1318u, 358382u, 9194u, 116716u, 227310u, 489454u, 137197u, 25578u, 2920u, 3817u, 23531u, 5098u, 1127u, 7016u, 3175u, 12009u, 1896u, 5992u, 3944u, 7913u, 8040u, 16105u, 21482u, 489u, 232u, 8681u, 4585u, 4328u, 12777u, 13290u, 2280u, 63470u, 325614u, 6376u, 2537u, 1256u, 10729u, 5352u, 6633u, 29674u, 56299u, 3304u, 15339u, 194542u, 14825u, 3050u, 1513u, 19434u, 9705u, 10220u, 5609u, 13801u, 3561u, 11242u, 75756u, 48107u, 456686u, 129006u, 42988u, 31723u, 391150u, 64491u, 260078u, 522222u, 4078u, 806u, 615u, 2663u, 1639u, 1830u, 7400u, 744u, 3687u, 166u, 108524u, 11753u, 1190u, 359u, 2407u, 678u, 1383u, 71661u, 1702u, 422u, 1446u, 3431u, 4840u, 2792u, 7657u, 6888u, 2027u, 202733u, 26604u, 38893u, 169965u, 266222u, 135150u, 397294u, 69614u, 331758u, 200686u, 462830u, 36846u, 298990u, 167918u, 430062u, 102382u, 364526u, 233454u, 495598u, 20462u, 282606u, 151534u, 413678u, 85998u, 348142u, 217070u, 479214u, 53230u, 315374u, 184302u, 446446u, 118766u, 380910u, 249838u, 511982u, 12270u, 274414u, 143342u, 405486u, 77806u, 339950u, 208878u, 471022u, 45038u, 307182u, 176110u, 438254u, 110574u, 372718u, 241646u, 503790u, 28654u, 290798u, 159726u, 421870u, 94190u, 356334u, 225262u, 487406u, 61422u, 323566u, 192494u, 454638u, 126958u, 389102u, 258030u, 520174u, 8174u, 270318u, 139246u, 401390u, 73710u, 335854u, 204782u, 466926u, 40942u, 303086u, 172014u, 434158u, 106478u, 368622u, 237550u, 499694u, 24558u, 286702u, 155630u, 417774u, 90094u, 352238u, 221166u, 483310u, 57326u, 319470u, 188398u, 450542u, 122862u, 385006u, 253934u, 516078u, 16366u, 278510u, 147438u, 409582u, 81902u, 344046u, 212974u, 475118u, 49134u, 311278u, 180206u, 442350u, 114670u, 376814u, 245742u, 507886u, 32750u, 294894u, 163822u, 425966u, 98286u, 104429u, 235501u, 22509u, 360430u, 153581u, 229358u, 88045u, 491502u, 219117u, 65518u, 327662u, 196590u, 458734u, 131054u, 132u, 3u, 388u, 68u, 324u, 197u, 709u, 453u, 966u, 1990u, 38u, 1062u, 935u, 2983u, 1959u, 4007u, 551u, 1575u, 2599u, 3623u, 104u, 2152u, 4200u, 6248u, 873u, 4969u, 9065u, 13161u, 1770u, 9962u, 18154u, 26346u, 5867u, 14059u, 22251u, 30443u, 38635u, 46827u, 55019u, 63211u, 15852u, 32236u, 48620u, 65004u, 81388u, 97772u, 114156u, 130540u, 27629u, 60397u, 93165u, 125933u, 158701u, 191469u, 224237u, 257005u, 1004u, 17388u, 33772u, 50156u, 66540u, 82924u, 99308u, 115692u, 7150u, 39918u, 72686u, 105454u, 138222u, 170990u, 203758u, 236526u, 269294u, 302062u, 334830u, 367598u, 400366u, 433134u, 465902u, 498670u, 92144u, 223216u, 354288u, 485360u, 616432u, 747504u, 878576u, 1009648u, 1140720u, 1271792u, 1402864u, 1533936u, 1665008u, 1796080u, 1927152u, 2058224u, 34799u, 100335u, 165871u, 231407u, 296943u, 362479u, 428015u, 493551u, 559087u, 624623u, 690159u, 755695u, 821231u, 886767u, 952303u, 1017839u, 59376u, 190448u, 321520u, 452592u, 583664u, 714736u, 845808u, 976880u, 1107952u, 1239024u, 1370096u, 1501168u, 1632240u, 1763312u, 1894384u, 2025456u, 393203u, 917491u, 1441779u, 1966067u, 2490355u, 3014643u, 3538931u, 4063219u, 4587507u, 5111795u, 5636083u, 6160371u, 6684659u, 7208947u, 7733235u, 8257523u, 8781811u, 9306099u, 9830387u, 10354675u, 10878963u, 11403251u, 11927539u, 12451827u, 12976115u, 13500403u, 14024691u, 14548979u, 15073267u, 15597555u, 16121843u, 16646131u, 262131u, 786419u, 1310707u, 1834995u, 2359283u, 2883571u, 3407859u, 3932147u, 4456435u, 4980723u, 5505011u, 6029299u, 6553587u, 7077875u, 7602163u, 8126451u, 8650739u, 9175027u, 9699315u, 10223603u, 10747891u, 11272179u, 11796467u, 12320755u, 12845043u, 13369331u, 13893619u, 14417907u, 14942195u, 15466483u, 15990771u, 16515059u, 524275u, 1048563u, 1572851u, 2097139u, 2621427u, 3145715u, 3670003u, 4194291u, 4718579u, 5242867u, 5767155u, 6291443u, 6815731u, 7340019u, 7864307u, 8388595u, 8912883u, 9437171u, 9961459u, 10485747u, 11010035u, 11534323u, 12058611u, 12582899u, 13107187u, 13631475u, 14155763u, 14680051u, 15204339u, 15728627u, 16252915u, 16777203u, 124913u, 255985u, 387057u, 518129u, 649201u, 780273u, 911345u, 1042417u, 1173489u, 1304561u, 1435633u, 1566705u, 1697777u, 1828849u, 1959921u, 2090993u, 2222065u, 2353137u, 2484209u, 2615281u, 2746353u, 2877425u, 3008497u, 3139569u, 3270641u, 3401713u, 3532785u, 3663857u, 3794929u, 3926001u, 4057073u, 18411u }; internal static readonly uint[] FAST_ENCODER_DISTANCE_CODE_INFO = new uint[32] { 3846u, 130826u, 261899u, 524043u, 65305u, 16152u, 48936u, 32552u, 7991u, 24375u, 3397u, 12102u, 84u, 7509u, 2148u, 869u, 1140u, 4981u, 3204u, 644u, 2708u, 1684u, 3748u, 420u, 2484u, 2997u, 1476u, 7109u, 2005u, 6101u, 0u, 256u }; internal static readonly uint[] BIT_MASK = new uint[16] { 0u, 1u, 3u, 7u, 15u, 31u, 63u, 127u, 255u, 511u, 1023u, 2047u, 4095u, 8191u, 16383u, 32767u }; internal static readonly byte[] EXTRA_LENGTH_BITS = new byte[29] { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; internal static readonly byte[] EXTRA_DISTANCE_BITS = new byte[32] { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 0, 0 }; internal const int NUM_CHARS = 256; internal const int NUM_LENGTH_BASE_CODES = 29; internal const int NUM_DIST_BASE_CODES = 30; internal const uint FAST_ENCODER_POST_TREE_BIT_BUF = 34u; internal const int FAST_ENCODER_POST_TREE_BIT_COUNT = 9; internal const uint NO_COMPRESSION_HEADER = 0u; internal const int NO_COMPRESSION_HEADER_BIT_COUNT = 3; internal const uint B_FINAL_NO_COMPRESSION_HEADER = 1u; internal const int B_FINAL_NO_COMPRESSION_HEADER_BIT_COUNT = 3; internal const int MAX_CODE_LEN = 16; private static readonly byte[] S_DIST_LOOKUP = CreateDistanceLookup(); private static byte[] CreateDistanceLookup() { byte[] array = new byte[512]; int num = 0; int i; for (i = 0; i < 16; i++) { for (int j = 0; j < 1 << (int)EXTRA_DISTANCE_BITS[i]; j++) { array[num++] = (byte)i; } } num >>= 7; for (; i < 30; i++) { for (int k = 0; k < 1 << EXTRA_DISTANCE_BITS[i] - 7; k++) { array[256 + num++] = (byte)i; } } return array; } internal static int GetSlot(int pos) { return S_DIST_LOOKUP[(pos < 256) ? pos : (256 + (pos >> 7))]; } public static uint BitReverse(uint code, int length) { uint num = 0u; do { num |= code & 1; num <<= 1; code >>= 1; } while (--length > 0); return num >> 1; } } internal sealed class HuffmanTree { internal const int MAX_LITERAL_TREE_ELEMENTS = 288; internal const int MAX_DIST_TREE_ELEMENTS = 32; internal const int END_OF_BLOCK_CODE = 256; internal const int NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS = 19; private readonly int _tableBits; private readonly short[] _table; private readonly short[] _left; private readonly short[] _right; private readonly byte[] _codeLengthArray; private readonly int _tableMask; public static HuffmanTree StaticLiteralLengthTree { get; } = new HuffmanTree(GetStaticLiteralTreeLength()); public static HuffmanTree StaticDistanceTree { get; } = new HuffmanTree(GetStaticDistanceTreeLength()); public HuffmanTree(byte[] codeLengths) { _codeLengthArray = codeLengths; if (_codeLengthArray.Length == 288) { _tableBits = 9; } else { _tableBits = 7; } _tableMask = (1 << _tableBits) - 1; _table = new short[1 << _tableBits]; _left = new short[2 * _codeLengthArray.Length]; _right = new short[2 * _codeLengthArray.Length]; CreateTable(); } private static byte[] GetStaticLiteralTreeLength() { byte[] array = new byte[288]; for (int i = 0; i <= 143; i++) { array[i] = 8; } for (int j = 144; j <= 255; j++) { array[j] = 9; } for (int k = 256; k <= 279; k++) { array[k] = 7; } for (int l = 280; l <= 287; l++) { array[l] = 8; } return array; } private static byte[] GetStaticDistanceTreeLength() { byte[] array = new byte[32]; for (int i = 0; i < 32; i++) { array[i] = 5; } return array; } private uint[] CalculateHuffmanCode() { uint[] array = new uint[17]; byte[] codeLengthArray = _codeLengthArray; foreach (int num in codeLengthArray) { array[num]++; } array[0] = 0u; uint[] array2 = new uint[17]; uint num2 = 0u; for (int j = 1; j <= 16; j++) { num2 = (array2[j] = num2 + array[j - 1] << 1); } uint[] array3 = new uint[288]; for (int k = 0; k < _codeLengthArray.Length; k++) { int num3 = _codeLengthArray[k]; if (num3 > 0) { array3[k] = FastEncoderStatics.BitReverse(array2[num3], num3); array2[num3]++; } } return array3; } private void CreateTable() { uint[] array = CalculateHuffmanCode(); short num = (short)_codeLengthArray.Length; for (int i = 0; i < _codeLengthArray.Length; i++) { int num2 = _codeLengthArray[i]; if (num2 <= 0) { continue; } int num3 = (int)array[i]; if (num2 <= _tableBits) { int num4 = 1 << num2; if (num3 >= num4) { throw new InvalidDataException("Deflate64: invalid Huffman data"); } int num5 = 1 << _tableBits - num2; for (int j = 0; j < num5; j++) { _table[num3] = (short)i; num3 += num4; } continue; } int num6 = num2 - _tableBits; int num7 = 1 << _tableBits; int num8 = num3 & ((1 << _tableBits) - 1); short[] array2 = _table; do { short num9 = array2[num8]; if (num9 == 0) { array2[num8] = (short)(-num); num9 = (short)(-num); num++; } if (num9 > 0) { throw new InvalidDataException("Deflate64: invalid Huffman data"); } array2 = (((num3 & num7) != 0) ? _right : _left); num8 = -num9; num7 <<= 1; num6--; } while (num6 != 0); array2[num8] = (short)i; } } public int GetNextSymbol(InputBuffer input) { uint num = input.TryLoad16Bits(); if (input.AvailableBits == 0) { return -1; } int num2 = _table[num & _tableMask]; if (num2 < 0) { uint num3 = (uint)(1 << _tableBits); do { num2 = -num2; num2 = (((num & num3) != 0) ? _right[num2] : _left[num2]); num3 <<= 1; } while (num2 < 0); } int num4 = _codeLengthArray[num2]; if (num4 <= 0) { throw new InvalidDataException("Deflate64: invalid Huffman data"); } if (num4 > input.AvailableBits) { return -1; } input.SkipBits(num4); return num2; } } internal sealed class InflaterManaged { private static readonly byte[] S_EXTRA_LENGTH_BITS = new byte[29] { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 16 }; private static readonly int[] S_LENGTH_BASE = new int[29] { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 3 }; private static readonly int[] S_DISTANCE_BASE_POSITION = new int[32] { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 32769, 49153 }; private static readonly byte[] S_CODE_ORDER = new byte[19] { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; private static readonly byte[] S_STATIC_DISTANCE_TREE_TABLE = new byte[32] { 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31 }; private readonly OutputWindow _output; private readonly InputBuffer _input; private HuffmanTree _literalLengthTree; private HuffmanTree _distanceTree; private InflaterState _state; private int _bfinal; private BlockType _blockType; private readonly byte[] _blockLengthBuffer = new byte[4]; private int _blockLength; private int _length; private int _distanceCode; private int _extraBits; private int _loopCounter; private int _literalLengthCodeCount; private int _distanceCodeCount; private int _codeLengthCodeCount; private int _codeArraySize; private int _lengthCode; private readonly byte[] _codeList; private readonly byte[] _codeLengthTreeCodeLength; private readonly bool _deflate64; private HuffmanTree _codeLengthTree; public int AvailableOutput => _output.AvailableBytes; internal InflaterManaged(bool deflate64) { _output = new OutputWindow(); _input = new InputBuffer(); _codeList = new byte[320]; _codeLengthTreeCodeLength = new byte[19]; _deflate64 = deflate64; Reset(); } private void Reset() { _state = InflaterState.ReadingBFinal; } public void SetInput(byte[] inputBytes, int offset, int length) { _input.SetInput(inputBytes, offset, length); } public bool Finished() { if (_state != InflaterState.Done) { return _state == InflaterState.VerifyingFooter; } return true; } public int Inflate(byte[] bytes, int offset, int length) { int num = 0; do { int num2 = _output.CopyTo(bytes, offset, length); if (num2 > 0) { offset += num2; num += num2; length -= num2; } } while (length != 0 && !Finished() && Decode()); if (_state == InflaterState.VerifyingFooter) { _ = _output.AvailableBytes; } return num; } private bool Decode() { bool endOfBlock = false; bool flag = false; if (Finished()) { return true; } if (_state == InflaterState.ReadingBFinal) { if (!_input.EnsureBitsAvailable(1)) { return false; } _bfinal = _input.GetBits(1); _state = InflaterState.ReadingBType; } if (_state == InflaterState.ReadingBType) { if (!_input.EnsureBitsAvailable(2)) { _state = InflaterState.ReadingBType; return false; } _blockType = (BlockType)_input.GetBits(2); if (_blockType == BlockType.Dynamic) { _state = InflaterState.ReadingNumLitCodes; } else if (_blockType == BlockType.Static) { _literalLengthTree = HuffmanTree.StaticLiteralLengthTree; _distanceTree = HuffmanTree.StaticDistanceTree; _state = InflaterState.DecodeTop; } else { if (_blockType != BlockType.Uncompressed) { throw new InvalidDataException("Deflate64: unknown block type"); } _state = InflaterState.UncompressedAligning; } } if (_blockType == BlockType.Dynamic) { flag = ((_state >= InflaterState.DecodeTop) ? DecodeBlock(out endOfBlock) : DecodeDynamicBlockHeader()); } else if (_blockType == BlockType.Static) { flag = DecodeBlock(out endOfBlock); } else { if (_blockType != BlockType.Uncompressed) { throw new InvalidDataException("Deflate64: unknown block type"); } flag = DecodeUncompressedBlock(out endOfBlock); } if (endOfBlock && _bfinal != 0) { _state = InflaterState.Done; } return flag; } private bool DecodeUncompressedBlock(out bool endOfBlock) { endOfBlock = false; while (true) { switch (_state) { case InflaterState.UncompressedAligning: _input.SkipToByteBoundary(); _state = InflaterState.UncompressedByte1; goto case InflaterState.UncompressedByte1; case InflaterState.UncompressedByte1: case InflaterState.UncompressedByte2: case InflaterState.UncompressedByte3: case InflaterState.UncompressedByte4: { int bits = _input.GetBits(8); if (bits < 0) { return false; } _blockLengthBuffer[(int)(_state - 16)] = (byte)bits; if (_state == InflaterState.UncompressedByte4) { _blockLength = _blockLengthBuffer[0] + _blockLengthBuffer[1] * 256; int num2 = _blockLengthBuffer[2] + _blockLengthBuffer[3] * 256; if ((ushort)_blockLength != (ushort)(~num2)) { throw new InvalidDataException("Deflate64: invalid block length"); } } break; } case InflaterState.DecodingUncompressed: { int num = _output.CopyFrom(_input, _blockLength); _blockLength -= num; if (_blockLength == 0) { _state = InflaterState.ReadingBFinal; endOfBlock = true; return true; } if (_output.FreeBytes == 0) { return true; } return false; } default: throw new InvalidDataException("Deflate64: unknown state"); } _state++; } } private bool DecodeBlock(out bool endOfBlockCodeSeen) { endOfBlockCodeSeen = false; int num = _output.FreeBytes; while (num > 65536) { switch (_state) { case InflaterState.DecodeTop: { int nextSymbol = _literalLengthTree.GetNextSymbol(_input); if (nextSymbol < 0) { return false; } if (nextSymbol < 256) { _output.Write((byte)nextSymbol); num--; break; } if (nextSymbol == 256) { endOfBlockCodeSeen = true; _state = InflaterState.ReadingBFinal; return true; } nextSymbol -= 257; if (nextSymbol < 8) { nextSymbol += 3; _extraBits = 0; } else if (!_deflate64 && nextSymbol == 28) { nextSymbol = 258; _extraBits = 0; } else { if (nextSymbol < 0 || nextSymbol >= S_EXTRA_LENGTH_BITS.Length) { throw new InvalidDataException("Deflate64: invalid data"); } _extraBits = S_EXTRA_LENGTH_BITS[nextSymbol]; } _length = nextSymbol; goto case InflaterState.HaveInitialLength; } case InflaterState.HaveInitialLength: if (_extraBits > 0) { _state = InflaterState.HaveInitialLength; int bits2 = _input.GetBits(_extraBits); if (bits2 < 0) { return false; } if (_length < 0 || _length >= S_LENGTH_BASE.Length) { throw new InvalidDataException("Deflate64: invalid data"); } _length = S_LENGTH_BASE[_length] + bits2; } _state = InflaterState.HaveFullLength; goto case InflaterState.HaveFullLength; case InflaterState.HaveFullLength: if (_blockType == BlockType.Dynamic) { _distanceCode = _distanceTree.GetNextSymbol(_input); } else { _distanceCode = _input.GetBits(5); if (_distanceCode >= 0) { _distanceCode = S_STATIC_DISTANCE_TREE_TABLE[_distanceCode]; } } if (_distanceCode < 0) { return false; } _state = InflaterState.HaveDistCode; goto case InflaterState.HaveDistCode; case InflaterState.HaveDistCode: { int distance; if (_distanceCode > 3) { _extraBits = _distanceCode - 2 >> 1; int bits = _input.GetBits(_extraBits); if (bits < 0) { return false; } distance = S_DISTANCE_BASE_POSITION[_distanceCode] + bits; } else { distance = _distanceCode + 1; } _output.WriteLengthDistance(_length, distance); num -= _length; _state = InflaterState.DecodeTop; break; } default: throw new InvalidDataException("Deflate64: unknown state"); } } return true; } private bool DecodeDynamicBlockHeader() { switch (_state) { case InflaterState.ReadingNumLitCodes: _literalLengthCodeCount = _input.GetBits(5); if (_literalLengthCodeCount < 0) { return false; } _literalLengthCodeCount += 257; _state = InflaterState.ReadingNumDistCodes; goto case InflaterState.ReadingNumDistCodes; case InflaterState.ReadingNumDistCodes: _distanceCodeCount = _input.GetBits(5); if (_distanceCodeCount < 0) { return false; } _distanceCodeCount++; _state = InflaterState.ReadingNumCodeLengthCodes; goto case InflaterState.ReadingNumCodeLengthCodes; case InflaterState.ReadingNumCodeLengthCodes: _codeLengthCodeCount = _input.GetBits(4); if (_codeLengthCodeCount < 0) { return false; } _codeLengthCodeCount += 4; _loopCounter = 0; _state = InflaterState.ReadingCodeLengthCodes; goto case InflaterState.ReadingCodeLengthCodes; case InflaterState.ReadingCodeLengthCodes: { while (_loopCounter < _codeLengthCodeCount) { int bits = _input.GetBits(3); if (bits < 0) { return false; } _codeLengthTreeCodeLength[S_CODE_ORDER[_loopCounter]] = (byte)bits; _loopCounter++; } for (int l = _codeLengthCodeCount; l < S_CODE_ORDER.Length; l++) { _codeLengthTreeCodeLength[S_CODE_ORDER[l]] = 0; } _codeLengthTree = new HuffmanTree(_codeLengthTreeCodeLength); _codeArraySize = _literalLengthCodeCount + _distanceCodeCount; _loopCounter = 0; _state = InflaterState.ReadingTreeCodesBefore; goto case InflaterState.ReadingTreeCodesBefore; } case InflaterState.ReadingTreeCodesBefore: case InflaterState.ReadingTreeCodesAfter: { while (_loopCounter < _codeArraySize) { if (_state == InflaterState.ReadingTreeCodesBefore && (_lengthCode = _codeLengthTree.GetNextSymbol(_input)) < 0) { return false; } if (_lengthCode <= 15) { _codeList[_loopCounter++] = (byte)_lengthCode; } else if (_lengthCode == 16) { if (!_input.EnsureBitsAvailable(2)) { _state = InflaterState.ReadingTreeCodesAfter; return false; } if (_loopCounter == 0) { throw new InvalidDataException(); } byte b = _codeList[_loopCounter - 1]; int num = _input.GetBits(2) + 3; if (_loopCounter + num > _codeArraySize) { throw new InvalidDataException(); } for (int i = 0; i < num; i++) { _codeList[_loopCounter++] = b; } } else if (_lengthCode == 17) { if (!_input.EnsureBitsAvailable(3)) { _state = InflaterState.ReadingTreeCodesAfter; return false; } int num = _input.GetBits(3) + 3; if (_loopCounter + num > _codeArraySize) { throw new InvalidDataException(); } for (int j = 0; j < num; j++) { _codeList[_loopCounter++] = 0; } } else { if (!_input.EnsureBitsAvailable(7)) { _state = InflaterState.ReadingTreeCodesAfter; return false; } int num = _input.GetBits(7) + 11; if (_loopCounter + num > _codeArraySize) { throw new InvalidDataException(); } for (int k = 0; k < num; k++) { _codeList[_loopCounter++] = 0; } } _state = InflaterState.ReadingTreeCodesBefore; } byte[] array = new byte[288]; byte[] array2 = new byte[32]; Array.Copy(_codeList, 0, array, 0, _literalLengthCodeCount); Array.Copy(_codeList, _literalLengthCodeCount, array2, 0, _distanceCodeCount); if (array[256] == 0) { throw new InvalidDataException(); } _literalLengthTree = new HuffmanTree(array); _distanceTree = new HuffmanTree(array2); _state = InflaterState.DecodeTop; return true; } default: throw new InvalidDataException("Deflate64: unknown state"); } } public void Dispose() { } } internal enum InflaterState { ReadingHeader = 0, ReadingBFinal = 2, ReadingBType = 3, ReadingNumLitCodes = 4, ReadingNumDistCodes = 5, ReadingNumCodeLengthCodes = 6, ReadingCodeLengthCodes = 7, ReadingTreeCodesBefore = 8, ReadingTreeCodesAfter = 9, DecodeTop = 10, HaveInitialLength = 11, HaveFullLength = 12, HaveDistCode = 13, UncompressedAligning = 15, UncompressedByte1 = 16, UncompressedByte2 = 17, UncompressedByte3 = 18, UncompressedByte4 = 19, DecodingUncompressed = 20, StartReadingFooter = 21, ReadingFooter = 22, VerifyingFooter = 23, Done = 24 } internal sealed class InputBuffer { private byte[] _buffer; private int _start; private int _end; private uint _bitBuffer; private int _bitsInBuffer; public int AvailableBits => _bitsInBuffer; public int AvailableBytes => _end - _start + _bitsInBuffer / 8; public bool EnsureBitsAvailable(int count) { if (_bitsInBuffer < count) { if (NeedsInput()) { return false; } _bitBuffer |= (uint)(_buffer[_start++] << _bitsInBuffer); _bitsInBuffer += 8; if (_bitsInBuffer < count) { if (NeedsInput()) { return false; } _bitBuffer |= (uint)(_buffer[_start++] << _bitsInBuffer); _bitsInBuffer += 8; } } return true; } public uint TryLoad16Bits() { if (_bitsInBuffer < 8) { if (_start < _end) { _bitBuffer |= (uint)(_buffer[_start++] << _bitsInBuffer); _bitsInBuffer += 8; } if (_start < _end) { _bitBuffer |= (uint)(_buffer[_start++] << _bitsInBuffer); _bitsInBuffer += 8; } } else if (_bitsInBuffer < 16 && _start < _end) { _bitBuffer |= (uint)(_buffer[_start++] << _bitsInBuffer); _bitsInBuffer += 8; } return _bitBuffer; } private uint GetBitMask(int count) { return (uint)((1 << count) - 1); } public int GetBits(int count) { if (!EnsureBitsAvailable(count)) { return -1; } uint result = _bitBuffer & GetBitMask(count); _bitBuffer >>= count; _bitsInBuffer -= count; return (int)result; } public int CopyTo(byte[] output, int offset, int length) { int num = 0; while (_bitsInBuffer > 0 && length > 0) { output[offset++] = (byte)_bitBuffer; _bitBuffer >>= 8; _bitsInBuffer -= 8; length--; num++; } if (length == 0) { return num; } int num2 = _end - _start; if (length > num2) { length = num2; } Array.Copy(_buffer, _start, output, offset, length); _start += length; return num + length; } public bool NeedsInput() { return _start == _end; } public void SetInput(byte[] buffer, int offset, int length) { _buffer = buffer; _start = offset; _end = offset + length; } public void SkipBits(int n) { _bitBuffer >>= n; _bitsInBuffer -= n; } public void SkipToByteBoundary() { _bitBuffer >>= _bitsInBuffer % 8; _bitsInBuffer -= _bitsInBuffer % 8; } } internal sealed class Match { internal MatchState State { get; set; } internal int Position { get; set; } internal int Length { get; set; } internal byte Symbol { get; set; } } internal enum MatchState { HasSymbol = 1, HasMatch, HasSymbolAndMatch } internal sealed class OutputWindow { private const int WINDOW_SIZE = 262144; private const int WINDOW_MASK = 262143; private readonly byte[] _window = new byte[262144]; private int _end; private int _bytesUsed; public int FreeBytes => 262144 - _bytesUsed; public int AvailableBytes => _bytesUsed; public void Write(byte b) { _window[_end++] = b; _end &= 262143; _bytesUsed++; } public void WriteLengthDistance(int length, int distance) { _bytesUsed += length; int num = (_end - distance) & 0x3FFFF; int num2 = 262144 - length; if (num <= num2 && _end < num2) { if (length <= distance) { Array.Copy(_window, num, _window, _end, length); _end += length; } else { while (length-- > 0) { _window[_end++] = _window[num++]; } } } else { while (length-- > 0) { _window[_end++] = _window[num++]; _end &= 262143; num &= 0x3FFFF; } } } public int CopyFrom(InputBuffer input, int length) { length = Math.Min(Math.Min(length, 262144 - _bytesUsed), input.AvailableBytes); int num = 262144 - _end; int num2; if (length > num) { num2 = input.CopyTo(_window, _end, num); if (num2 == num) { num2 += input.CopyTo(_window, 0, length - num); } } else { num2 = input.CopyTo(_window, _end, length); } _end = (_end + num2) & 0x3FFFF; _bytesUsed += num2; return num2; } public int CopyTo(byte[] output, int offset, int length) { int num; if (length > _bytesUsed) { num = _end; length = _bytesUsed; } else { num = (_end - _bytesUsed + length) & 0x3FFFF; } int num2 = length; int num3 = length - num; if (num3 > 0) { Array.Copy(_window, 262144 - num3, output, offset, num3); offset += num3; length = num; } Array.Copy(_window, num - length, output, offset, length); _bytesUsed -= num2; return num2; } } } namespace SharpCompress.Compressors.BZip2 { internal class BZip2Constants { public const int baseBlockSize = 100000; public const int MAX_ALPHA_SIZE = 258; public const int MAX_CODE_LEN = 23; public const int RUNA = 0; public const int RUNB = 1; public const int N_GROUPS = 6; public const int G_SIZE = 50; public const int N_ITERS = 4; public const int MAX_SELECTORS = 18002; public const int NUM_OVERSHOOT_BYTES = 20; public static int[] rNums = new int[512] { 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, 936, 638 }; } public class BZip2Stream : Stream { private readonly Stream stream; private bool isDisposed; public CompressionMode Mode { get; } public override bool CanRead => stream.CanRead; public override bool CanSeek => stream.CanSeek; public override bool CanWrite => stream.CanWrite; public override long Length => stream.Length; public override long Position { get { return stream.Position; } set { stream.Position = value; } } public BZip2Stream(Stream stream, CompressionMode compressionMode, bool decompressConcatenated) { Mode = compressionMode; if (Mode == CompressionMode.Compress) { this.stream = new CBZip2OutputStream(stream); } else { this.stream = new CBZip2InputStream(stream, decompressConcatenated); } } public void Finish() { (stream as CBZip2OutputStream)?.Finish(); } protected override void Dispose(bool disposing) { if (!isDisposed) { isDisposed = true; if (disposing) { stream.Dispose(); } } } public override void Flush() { stream.Flush(); } public override int Read(byte[] buffer, int offset, int count) { return stream.Read(buffer, offset, count); } public override int ReadByte() { return stream.ReadByte(); } public override long Seek(long offset, SeekOrigin origin) { return stream.Seek(offset, origin); } public override void SetLength(long value) { stream.SetLength(value); } public override void Write(byte[] buffer, int offset, int count) { stream.Write(buffer, offset, count); } public override void WriteByte(byte value) { stream.WriteByte(value); } public static bool IsBZip2(Stream stream) { byte[] array = new BinaryReader(stream).ReadBytes(2); if (array.Length < 2 || array[0] != 66 || array[1] != 90) { return false; } return true; } } internal class CBZip2InputStream : Stream { private int last; private int origPtr; private int blockSize100k; private bool blockRandomised; private int bsBuff; private int bsLive; private readonly CRC mCrc = new CRC(); private readonly bool[] inUse = new bool[256]; private int nInUse; private readonly char[] seqToUnseq = new char[256]; private readonly char[] unseqToSeq = new char[256]; private readonly char[] selector = new char[18002]; private readonly char[] selectorMtf = new char[18002]; private int[] tt; private char[] ll8; private readonly int[] unzftab = new int[256]; private readonly int[][] limit = InitIntArray(6, 258); private readonly int[][] basev = InitIntArray(6, 258); private readonly int[][] perm = InitIntArray(6, 258); private readonly int[] minLens = new int[6]; private Stream bsStream; private bool streamEnd; private int currentChar = -1; private const int START_BLOCK_STATE = 1; private const int RAND_PART_A_STATE = 2; private const int RAND_PART_B_STATE = 3; private const int RAND_PART_C_STATE = 4; private const int NO_RAND_PART_A_STATE = 5; private const int NO_RAND_PART_B_STATE = 6; private const int NO_RAND_PART_C_STATE = 7; private int currentState = 1; private int storedBlockCRC; private int storedCombinedCRC; private int computedBlockCRC; private int computedCombinedCRC; private readonly bool decompressConcatenated; private int i2; private int count; private int chPrev; private int ch2; private int i; private int tPos; private int rNToGo; private int rTPos; private int j2; private char z; private bool isDisposed; public override bool CanRead => true; public override bool CanSeek => false; public override bool CanWrite => false; public override long Length => 0L; public override long Position { get { return 0L; } set { } } private static void Cadvise() { } private static void BadBGLengths() { Cadvise(); } private static void BitStreamEOF() { Cadvise(); } private static void CompressedStreamEOF() { Cadvise(); } private void MakeMaps() { nInUse = 0; for (int i = 0; i < 256; i++) { if (inUse[i]) { seqToUnseq[nInUse] = (char)i; unseqToSeq[i] = (char)nInUse; nInUse++; } } } public CBZip2InputStream(Stream zStream, bool decompressConcatenated) { this.decompressConcatenated = decompressConcatenated; ll8 = null; tt = null; BsSetStream(zStream); Initialize(isFirstStream: true); InitBlock(); SetupBlock(); } protected override void Dispose(bool disposing) { if (!isDisposed) { isDisposed = true; base.Dispose(disposing); if (bsStream != null) { bsStream.Dispose(); } } } internal static int[][] InitIntArray(int n1, int n2) { int[][] array = new int[n1][]; for (int i = 0; i < n1; i++) { array[i] = new int[n2]; } return array; } internal static char[][] InitCharArray(int n1, int n2) { char[][] array = new char[n1][]; for (int i = 0; i < n1; i++) { array[i] = new char[n2]; } return array; } public override int ReadByte() { if (streamEnd) { return -1; } int result = currentChar; switch (currentState) { case 3: SetupRandPartB(); break; case 4: SetupRandPartC(); break; case 6: SetupNoRandPartB(); break; case 7: SetupNoRandPartC(); break; } return result; } private bool Initialize(bool isFirstStream) { int num = bsStream.ReadByte(); int num2 = bsStream.ReadByte(); int num3 = bsStream.ReadByte(); if (num == -1 && !isFirstStream) { return false; } if (num != 66 || num2 != 90 || num3 != 104) { throw new IOException("Not a BZIP2 marked stream"); } int num4 = bsStream.ReadByte(); if (num4 < 49 || num4 > 57) { BsFinishedWithStream(); streamEnd = true; return false; } SetDecompressStructureSizes(num4 - 48); bsLive = 0; computedCombinedCRC = 0; return true; } private void InitBlock() { char c; char c2; char c3; char c4; char c5; char c6; while (true) { c = BsGetUChar(); c2 = BsGetUChar(); c3 = BsGetUChar(); c4 = BsGetUChar(); c5 = BsGetUChar(); c6 = BsGetUChar(); if (c != '\u0017' || c2 != 'r' || c3 != 'E' || c4 != '8' || c5 != 'P' || c6 != '\u0090') { break; } if (Complete()) { return; } } if (c != '1' || c2 != 'A' || c3 != 'Y' || c4 != '&' || c5 != 'S' || c6 != 'Y') { BadBlockHeader(); streamEnd = true; return; } storedBlockCRC = BsGetInt32(); if (BsR(1) == 1) { blockRandomised = true; } else { blockRandomised = false; } GetAndMoveToFrontDecode(); mCrc.InitialiseCRC(); currentState = 1; } private void EndBlock() { computedBlockCRC = mCrc.GetFinalCRC(); if (storedBlockCRC != computedBlockCRC) { CrcError(); } computedCombinedCRC = (computedCombinedCRC << 1) | (computedCombinedCRC >>> 31); computedCombinedCRC ^= computedBlockCRC; } private bool Complete() { storedCombinedCRC = BsGetInt32(); if (storedCombinedCRC != computedCombinedCRC) { CrcError(); } int num; if (decompressConcatenated) { num = ((!Initialize(isFirstStream: false)) ? 1 : 0); if (num == 0) { goto IL_0044; } } else { num = 1; } BsFinishedWithStream(); streamEnd = true; goto IL_0044; IL_0044: return (byte)num != 0; } private static void BlockOverrun() { Cadvise(); } private static void BadBlockHeader() { Cadvise(); } private static void CrcError() { Cadvise(); } private void BsFinishedWithStream() { bsStream?.Dispose(); bsStream = null; } private void BsSetStream(Stream f) { bsStream = f; bsLive = 0; bsBuff = 0; } private int BsR(int n) { while (bsLive < n) { int num = 0; try { num = (ushort)bsStream.ReadByte(); } catch (IOException) { CompressedStreamEOF(); } if (num == 65535) { CompressedStreamEOF(); } int num2 = num; bsBuff = (bsBuff << 8) | (num2 & 0xFF); bsLive += 8; } int result = (bsBuff >> bsLive - n) & ((1 << n) - 1); bsLive -= n; return result; } private char BsGetUChar() { return (char)BsR(8); } private int BsGetint() { return ((((((0 | BsR(8)) << 8) | BsR(8)) << 8) | BsR(8)) << 8) | BsR(8); } private int BsGetIntVS(int numBits) { return BsR(numBits); } private int BsGetInt32() { return BsGetint(); } private void HbCreateDecodeTables(int[] limit, int[] basev, int[] perm, char[] length, int minLen, int maxLen, int alphaSize) { int num = 0; for (int i = minLen; i <= maxLen; i++) { for (int j = 0; j < alphaSize; j++) { if (length[j] == i) { perm[num] = j; num++; } } } for (int i = 0; i < 23; i++) { basev[i] = 0; } for (int i = 0; i < alphaSize; i++) { basev[length[i] + 1]++; } for (int i = 1; i < 23; i++) { basev[i] += basev[i - 1]; } for (int i = 0; i < 23; i++) { limit[i] = 0; } int num2 = 0; for (int i = minLen; i <= maxLen; i++) { num2 += basev[i + 1] - basev[i]; limit[i] = num2 - 1; num2 <<= 1; } for (int i = minLen + 1; i <= maxLen; i++) { basev[i] = (limit[i - 1] + 1 << 1) - basev[i]; } } private void RecvDecodingTables() { char[][] array = InitCharArray(6, 258); bool[] array2 = new bool[16]; for (int i = 0; i < 16; i++) { if (BsR(1) == 1) { array2[i] = true; } else { array2[i] = false; } } for (int i = 0; i < 256; i++) { inUse[i] = false; } for (int i = 0; i < 16; i++) { if (!array2[i]) { continue; } for (int j = 0; j < 16; j++) { if (BsR(1) == 1) { inUse[i * 16 + j] = true; } } } MakeMaps(); int num = nInUse + 2; int num2 = BsR(3); int num3 = BsR(15); for (int i = 0; i < num3; i++) { int j = 0; while (BsR(1) == 1) { j++; } selectorMtf[i] = (char)j; } char[] array3 = new char[6]; for (char c = '\0'; c < num2; c = (char)(c + 1)) { array3[(uint)c] = c; } for (int i = 0; i < num3; i++) { char c = selectorMtf[i]; char c2 = array3[(uint)c]; while (c > '\0') { array3[(uint)c] = array3[c - 1]; c = (char)(c - 1); } array3[0] = c2; selector[i] = c2; } for (int k = 0; k < num2; k++) { int num4 = BsR(5); for (int i = 0; i < num; i++) { while (BsR(1) == 1) { num4 = ((BsR(1) != 0) ? (num4 - 1) : (num4 + 1)); } array[k][i] = (char)num4; } } for (int k = 0; k < num2; k++) { int num5 = 32; int num6 = 0; for (int i = 0; i < num; i++) { if (array[k][i] > num6) { num6 = array[k][i]; } if (array[k][i] < num5) { num5 = array[k][i]; } } HbCreateDecodeTables(limit[k], basev[k], perm[k], array[k], num5, num6, num); minLens[k] = num5; } } private void GetAndMoveToFrontDecode() { char[] array = new char[256]; int num = 100000 * blockSize100k; origPtr = BsGetIntVS(24); RecvDecodingTables(); int num2 = nInUse + 1; int num3 = -1; int num4 = 0; for (int i = 0; i <= 255; i++) { unzftab[i] = 0; } for (int i = 0; i <= 255; i++) { array[i] = (char)i; } last = -1; if (num4 == 0) { num3++; num4 = 50; } num4--; int num5 = selector[num3]; int num6 = minLens[num5]; int num7 = BsR(num6); while (num7 > limit[num5][num6]) { num6++; while (bsLive < 1) { char c = '\0'; try { c = (char)bsStream.ReadByte(); } catch (IOException) { CompressedStreamEOF(); } if (c == '\uffff') { CompressedStreamEOF(); } int num8 = c; bsBuff = (bsBuff << 8) | (num8 & 0xFF); bsLive += 8; } int num9 = (bsBuff >> bsLive - 1) & 1; bsLive--; num7 = (num7 << 1) | num9; } int num10 = perm[num5][num7 - basev[num5][num6]]; while (num10 != num2) { if (num10 == 0 || num10 == 1) { int num11 = -1; int num12 = 1; do { switch (num10) { case 0: num11 += num12; break; case 1: num11 += 2 * num12; break; } num12 *= 2; if (num4 == 0) { num3++; num4 = 50; } num4--; int num13 = selector[num3]; int num14 = minLens[num13]; int num15 = BsR(num14); while (num15 > limit[num13][num14]) { num14++; while (bsLive < 1) { char c2 = '\0'; try { c2 = (char)bsStream.ReadByte(); } catch (IOException) { CompressedStreamEOF(); } if (c2 == '\uffff') { CompressedStreamEOF(); } int num16 = c2; bsBuff = (bsBuff << 8) | (num16 & 0xFF); bsLive += 8; } int num17 = (bsBuff >> bsLive - 1) & 1; bsLive--; num15 = (num15 << 1) | num17; } num10 = perm[num13][num15 - basev[num13][num14]]; } while (num10 == 0 || num10 == 1); num11++; char c3 = seqToUnseq[(uint)array[0]]; unzftab[(uint)c3] += num11; while (num11 > 0) { last++; ll8[last] = c3; num11--; } if (last >= num) { BlockOverrun(); } continue; } last++; if (last >= num) { BlockOverrun(); } char c4 = array[num10 - 1]; unzftab[(uint)seqToUnseq[(uint)c4]]++; ll8[last] = seqToUnseq[(uint)c4]; int num18; for (num18 = num10 - 1; num18 > 3; num18 -= 4) { array[num18] = array[num18 - 1]; array[num18 - 1] = array[num18 - 2]; array[num18 - 2] = array[num18 - 3]; array[num18 - 3] = array[num18 - 4]; } while (num18 > 0) { array[num18] = array[num18 - 1]; num18--; } array[0] = c4; if (num4 == 0) { num3++; num4 = 50; } num4--; int num19 = selector[num3]; int num20 = minLens[num19]; int num21 = BsR(num20); while (num21 > limit[num19][num20]) { num20++; while (bsLive < 1) { char c5 = '\0'; try { c5 = (char)bsStream.ReadByte(); } catch (IOException) { CompressedStreamEOF(); } int num22 = c5; bsBuff = (bsBuff << 8) | (num22 & 0xFF); bsLive += 8; } int num23 = (bsBuff >> bsLive - 1) & 1; bsLive--; num21 = (num21 << 1) | num23; } num10 = perm[num19][num21 - basev[num19][num20]]; } } private void SetupBlock() { int[] array = new int[257]; array[0] = 0; for (i = 1; i <= 256; i++) { array[i] = unzftab[i - 1]; } for (i = 1; i <= 256; i++) { array[i] += array[i - 1]; } for (i = 0; i <= last; i++) { char c = ll8[i]; tt[array[(uint)c]] = i; array[(uint)c]++; } array = null; tPos = tt[origPtr]; count = 0; i2 = 0; ch2 = 256; if (blockRandomised) { rNToGo = 0; rTPos = 0; SetupRandPartA(); } else { SetupNoRandPartA(); } } private void SetupRandPartA() { if (i2 <= last) { chPrev = ch2; ch2 = ll8[tPos]; tPos = tt[tPos]; if (rNToGo == 0) { rNToGo = BZip2Constants.rNums[rTPos]; rTPos++; if (rTPos == 512) { rTPos = 0; } } rNToGo--; ch2 ^= ((rNToGo == 1) ? 1 : 0); i2++; currentChar = ch2; currentState = 3; mCrc.UpdateCRC(ch2); } else { EndBlock(); InitBlock(); SetupBlock(); } } private void SetupNoRandPartA() { if (i2 <= last) { chPrev = ch2; ch2 = ll8[tPos]; tPos = tt[tPos]; i2++; currentChar = ch2; currentState = 6; mCrc.UpdateCRC(ch2); } else { EndBlock(); InitBlock(); SetupBlock(); } } private void SetupRandPartB() { if (ch2 != chPrev) { currentState = 2; count = 1; SetupRandPartA(); return; } count++; if (count >= 4) { z = ll8[tPos]; tPos = tt[tPos]; if (rNToGo == 0) { rNToGo = BZip2Constants.rNums[rTPos]; rTPos++; if (rTPos == 512) { rTPos = 0; } } rNToGo--; z ^= ((rNToGo == 1) ? '\u0001' : '\0'); j2 = 0; currentState = 4; SetupRandPartC(); } else { currentState = 2; SetupRandPartA(); } } private void SetupRandPartC() { if (j2 < z) { currentChar = ch2; mCrc.UpdateCRC(ch2); j2++; } else { currentState = 2; i2++; count = 0; SetupRandPartA(); } } private void SetupNoRandPartB() { if (ch2 != chPrev) { currentState = 5; count = 1; SetupNoRandPartA(); return; } count++; if (count >= 4) { z = ll8[tPos]; tPos = tt[tPos]; currentState = 7; j2 = 0; SetupNoRandPartC(); } else { currentState = 5; SetupNoRandPartA(); } } private void SetupNoRandPartC() { if (j2 < z) { currentChar = ch2; mCrc.UpdateCRC(ch2); j2++; } else { currentState = 5; i2++; count = 0; SetupNoRandPartA(); } } private void SetDecompressStructureSizes(int newSize100k) { if (0 <= newSize100k && newSize100k <= 9 && 0 <= blockSize100k) { _ = blockSize100k; _ = 9; } blockSize100k = newSize100k; if (newSize100k != 0) { int num = 100000 * newSize100k; ll8 = new char[num]; tt = new int[num]; } } public override void Flush() { } public override int Read(byte[] buffer, int offset, int count) { int num = -1; int i; for (i = 0; i < count; i++) { num = ReadByte(); if (num == -1) { break; } buffer[i + offset] = (byte)num; } return i; } public override long Seek(long offset, SeekOrigin origin) { return 0L; } public override void SetLength(long value) { } public override void Write(byte[] buffer, int offset, int count) { } public override void WriteByte(byte value) { } } internal class CBZip2OutputStream : Stream { internal class StackElem { internal int ll; internal int hh; internal int dd; } protected const int SETMASK = 2097152; protected const int CLEARMASK = -2097153; protected const int GREATER_ICOST = 15; protected const int LESSER_ICOST = 0; protected const int SMALL_THRESH = 20; protected const int DEPTH_THRESH = 10; protected const int QSORT_STACK_SIZE = 1000; private bool finished; private int last; private int origPtr; private readonly int blockSize100k; private bool blockRandomised; private int bytesOut; private int bsBuff; private int bsLive; private readonly CRC mCrc = new CRC(); private readonly bool[] inUse = new bool[256]; private int nInUse; private readonly char[] seqToUnseq = new char[256]; private readonly char[] unseqToSeq = new char[256]; private readonly char[] selector = new char[18002]; private readonly char[] selectorMtf = new char[18002]; private char[] block; private int[] quadrant; private int[] zptr; private short[] szptr; private int[] ftab; private int nMTF; private readonly int[] mtfFreq = new int[258]; private readonly int workFactor; private int workDone; private int workLimit; private bool firstAttempt; private int nBlocksRandomised; private int currentChar = -1; private int runLength; private bool disposed; private int blockCRC; private int combinedCRC; private int allowableBlockSize; private Stream bsStream; private readonly int[] incs = new int[14] { 1, 4, 13, 40, 121, 364, 1093, 3280, 9841, 29524, 88573, 265720, 797161, 2391484 }; public override bool CanRead => false; public override bool CanSeek => false; public override bool CanWrite => true; public override long Length => 0L; public override long Position { get { return 0L; } set { } } private static void Panic() { } private void MakeMaps() { nInUse = 0; for (int i = 0; i < 256; i++) { if (inUse[i]) { seqToUnseq[nInUse] = (char)i; unseqToSeq[i] = (char)nInUse; nInUse++; } } } protected static void HbMakeCodeLengths(char[] len, int[] freq, int alphaSize, int maxLen) { int[] array = new int[260]; int[] array2 = new int[516]; int[] array3 = new int[516]; for (int i = 0; i < alphaSize; i++) { array2[i + 1] = ((freq[i] == 0) ? 1 : freq[i]) << 8; } while (true) { int num = alphaSize; int num2 = 0; array[0] = 0; array2[0] = 0; array3[0] = -2; for (int i = 1; i <= alphaSize; i++) { array3[i] = -1; num2++; array[num2] = i; int num3 = num2; int num4 = array[num3]; while (array2[num4] < array2[array[num3 >> 1]]) { array[num3] = array[num3 >> 1]; num3 >>= 1; } array[num3] = num4; } if (num2 >= 260) { Panic(); } while (num2 > 1) { int num5 = array[1]; array[1] = array[num2]; num2--; int num6 = 0; int num7 = 0; int num8 = 0; num6 = 1; num8 = array[num6]; while (true) { num7 = num6 << 1; if (num7 > num2) { break; } if (num7 < num2 && array2[array[num7 + 1]] < array2[array[num7]]) { num7++; } if (array2[num8] < array2[array[num7]]) { break; } array[num6] = array[num7]; num6 = num7; } array[num6] = num8; int num9 = array[1]; array[1] = array[num2]; num2--; int num10 = 0; int num11 = 0; int num12 = 0; num10 = 1; num12 = array[num10]; while (true) { num11 = num10 << 1; if (num11 > num2) { break; } if (num11 < num2 && array2[array[num11 + 1]] < array2[array[num11]]) { num11++; } if (array2[num12] < array2[array[num11]]) { break; } array[num10] = array[num11]; num10 = num11; } array[num10] = num12; num++; array3[num5] = (array3[num9] = num); array2[num] = (int)((array2[num5] & 0xFFFFFF00u) + (array2[num9] & 0xFFFFFF00u)) | (1 + (((array2[num5] & 0xFF) > (array2[num9] & 0xFF)) ? (array2[num5] & 0xFF) : (array2[num9] & 0xFF))); array3[num] = -1; num2++; array[num2] = num; int num13 = 0; int num14 = 0; num13 = num2; num14 = array[num13]; while (array2[num14] < array2[array[num13 >> 1]]) { array[num13] = array[num13 >> 1]; num13 >>= 1; } array[num13] = num14; } if (num >= 516) { Panic(); } bool flag = false; for (int i = 1; i <= alphaSize; i++) { int num15 = 0; int num16 = i; while (array3[num16] >= 0) { num16 = array3[num16]; num15++; } len[i - 1] = (char)num15; if (num15 > maxLen) { flag = true; } } if (flag) { for (int i = 1; i < alphaSize; i++) { int num15 = array2[i] >> 8; num15 = 1 + num15 / 2; array2[i] = num15 << 8; } continue; } break; } } public CBZip2OutputStream(Stream inStream) : this(inStream, 9) { } public CBZip2OutputStream(Stream inStream, int inBlockSize) { block = null; quadrant = null; zptr = null; ftab = null; inStream.WriteByte(66); inStream.WriteByte(90); BsSetStream(inStream); workFactor = 50; if (inBlockSize > 9) { inBlockSize = 9; } if (inBlockSize < 1) { inBlockSize = 1; } blockSize100k = inBlockSize; AllocateCompressStructures(); Initialize(); InitBlock(); } public override void WriteByte(byte bv) { int num = (256 + bv) % 256; if (currentChar != -1) { if (currentChar == num) { runLength++; if (runLength > 254) { WriteRun(); currentChar = -1; runLength = 0; } } else { WriteRun(); runLength = 1; currentChar = num; } } else { currentChar = num; runLength++; } } private void WriteRun() { if (last < allowableBlockSize) { inUse[currentChar] = true; for (int i = 0; i < runLength; i++) { mCrc.UpdateCRC((ushort)currentChar); } switch (runLength) { case 1: last++; block[last + 1] = (char)currentChar; break; case 2: last++; block[last + 1] = (char)currentChar; last++; block[last + 1] = (char)currentChar; break; case 3: last++; block[last + 1] = (char)currentChar; last++; block[last + 1] = (char)currentChar; last++; block[last + 1] = (char)currentChar; break; default: inUse[runLength - 4] = true; last++; block[last + 1] = (char)currentChar; last++; block[last + 1] = (char)currentChar; last++; block[last + 1] = (char)currentChar; last++; block[last + 1] = (char)currentChar; last++; block[last + 1] = (char)(runLength - 4); break; } } else { EndBlock(); InitBlock(); WriteRun(); } } protected override void Dispose(bool disposing) { if (disposing && !disposed) { Finish(); disposed = true; Dispose(); bsStream?.Dispose(); bsStream = null; } } public void Finish() { if (!finished) { if (runLength > 0) { WriteRun(); } currentChar = -1; EndBlock(); EndCompression(); finished = true; Flush(); } } public override void Flush() { bsStream.Flush(); } private void Initialize() { bytesOut = 0; nBlocksRandomised = 0; BsPutUChar(104); BsPutUChar(48 + blockSize100k); combinedCRC = 0; } private void InitBlock() { mCrc.InitialiseCRC(); last = -1; for (int i = 0; i < 256; i++) { inUse[i] = false; } allowableBlockSize = 100000 * blockSize100k - 20; } private void EndBlock() { blockCRC = mCrc.GetFinalCRC(); combinedCRC = (combinedCRC << 1) | (combinedCRC >>> 31); combinedCRC ^= blockCRC; DoReversibleTransformation(); BsPutUChar(49); BsPutUChar(65); BsPutUChar(89); BsPutUChar(38); BsPutUChar(83); BsPutUChar(89); BsPutint(blockCRC); if (blockRandomised) { BsW(1, 1); nBlocksRandomised++; } else { BsW(1, 0); } MoveToFrontCodeAndSend(); } private void EndCompression() { BsPutUChar(23); BsPutUChar(114); BsPutUChar(69); BsPutUChar(56); BsPutUChar(80); BsPutUChar(144); BsPutint(combinedCRC); BsFinishedWithStream(); } private void HbAssignCodes(int[] code, char[] length, int minLen, int maxLen, int alphaSize) { int num = 0; for (int i = minLen; i <= maxLen; i++) { for (int j = 0; j < alphaSize; j++) { if (length[j] == i) { code[j] = num; num++; } } num <<= 1; } } private void BsSetStream(Stream f) { bsStream = f; bsLive = 0; bsBuff = 0; bytesOut = 0; } private void BsFinishedWithStream() { while (bsLive > 0) { int num = bsBuff >> 24; try { bsStream.WriteByte((byte)num); } catch (IOException ex) { throw ex; } bsBuff <<= 8; bsLive -= 8; bytesOut++; } } private void BsW(int n, int v) { while (bsLive >= 8) { int num = bsBuff >> 24; try { bsStream.WriteByte((byte)num); } catch (IOException ex) { throw ex; } bsBuff <<= 8; bsLive -= 8; bytesOut++; } bsBuff |= v << 32 - bsLive - n; bsLive += n; } private void BsPutUChar(int c) { BsW(8, c); } private void BsPutint(int u) { BsW(8, (u >> 24) & 0xFF); BsW(8, (u >> 16) & 0xFF); BsW(8, (u >> 8) & 0xFF); BsW(8, u & 0xFF); } private void BsPutIntVS(int numBits, int c) { BsW(numBits, c); } private void SendMTFValues() { char[][] array = CBZip2InputStream.InitCharArray(6, 258); int num = 0; int num2 = nInUse + 2; for (int i = 0; i < 6; i++) { for (int j = 0; j < num2; j++) { array[i][j] = '\u000f'; } } if (nMTF <= 0) { Panic(); } int num3 = ((nMTF < 200) ? 2 : ((nMTF < 600) ? 3 : ((nMTF < 1200) ? 4 : ((nMTF >= 2400) ? 6 : 5)))); int num4 = num3; int num5 = nMTF; int num6 = 0; while (num4 > 0) { int num7 = num5 / num4; int num8 = num6 - 1; int k; for (k = 0; k < num7; k += mtfFreq[num8]) { if (num8 >= num2 - 1) { break; } num8++; } if (num8 > num6 && num4 != num3 && num4 != 1 && (num3 - num4) % 2 == 1) { k -= mtfFreq[num8]; num8--; } for (int j = 0; j < num2; j++) { if (j >= num6 && j <= num8) { array[num4 - 1][j] = '\0'; } else { array[num4 - 1][j] = '\u000f'; } } num4--; num6 = num8 + 1; num5 -= k; } int[][] array2 = CBZip2InputStream.InitIntArray(6, 258); int[] array3 = new int[6]; short[] array4 = new short[6]; for (int l = 0; l < 4; l++) { for (int i = 0; i < num3; i++) { array3[i] = 0; } for (int i = 0; i < num3; i++) { for (int j = 0; j < num2; j++) { array2[i][j] = 0; } } num = 0; int num9 = 0; num6 = 0; while (num6 < nMTF) { int num8 = num6 + 50 - 1; if (num8 >= nMTF) { num8 = nMTF - 1; } for (int i = 0; i < num3; i++) { array4[i] = 0; } if (num3 == 6) { short num11; short num12; short num13; short num14; short num15; short num10 = (num11 = (num12 = (num13 = (num14 = (num15 = 0))))); for (int m = num6; m <= num8; m++) { short num16 = szptr[m]; num10 += (short)array[0][num16]; num11 += (short)array[1][num16]; num12 += (short)array[2][num16]; num13 += (short)array[3][num16]; num14 += (short)array[4][num16]; num15 += (short)array[5][num16]; } array4[0] = num10; array4[1] = num11; array4[2] = num12; array4[3] = num13; array4[4] = num14; array4[5] = num15; } else { for (int m = num6; m <= num8; m++) { short num17 = szptr[m]; for (int i = 0; i < num3; i++) { array4[i] += (short)array[i][num17]; } } } int num18 = 999999999; int num19 = -1; for (int i = 0; i < num3; i++) { if (array4[i] < num18) { num18 = array4[i]; num19 = i; } } num9 += num18; array3[num19]++; selector[num] = (char)num19; num++; for (int m = num6; m <= num8; m++) { array2[num19][szptr[m]]++; } num6 = num8 + 1; } for (int i = 0; i < num3; i++) { HbMakeCodeLengths(array[i], array2[i], num2, 20); } } array2 = null; array3 = null; array4 = null; if (num3 >= 8) { Panic(); } if (num >= 32768 || num > 18002) { Panic(); } char[] array5 = new char[6]; for (int m = 0; m < num3; m++) { array5[m] = (char)m; } for (int m = 0; m < num; m++) { char c = selector[m]; int num20 = 0; char c2 = array5[num20]; while (c != c2) { num20++; char c3 = c2; c2 = array5[num20]; array5[num20] = c3; } array5[0] = c2; selectorMtf[m] = (char)num20; } int[][] array6 = CBZip2InputStream.InitIntArray(6, 258); for (int i = 0; i < num3; i++) { int num21 = 32; int num22 = 0; for (int m = 0; m < num2; m++) { if (array[i][m] > num22) { num22 = array[i][m]; } if (array[i][m] < num21) { num21 = array[i][m]; } } if (num22 > 20) { Panic(); } if (num21 < 1) { Panic(); } HbAssignCodes(array6[i], array[i], num21, num22, num2); } bool[] array7 = new bool[16]; for (int m = 0; m < 16; m++) { array7[m] = false; for (int num20 = 0; num20 < 16; num20++) { if (inUse[m * 16 + num20]) { array7[m] = true; } } } for (int m = 0; m < 16; m++) { if (array7[m]) { BsW(1, 1); } else { BsW(1, 0); } } for (int m = 0; m < 16; m++) { if (!array7[m]) { continue; } for (int num20 = 0; num20 < 16; num20++) { if (inUse[m * 16 + num20]) { BsW(1, 1); } else { BsW(1, 0); } } } BsW(3, num3); BsW(15, num); for (int m = 0; m < num; m++) { for (int num20 = 0; num20 < selectorMtf[m]; num20++) { BsW(1, 1); } BsW(1, 0); } for (int i = 0; i < num3; i++) { int n = array[i][0]; BsW(5, n); for (int m = 0; m < num2; m++) { for (; n < array[i][m]; n++) { BsW(2, 2); } while (n > array[i][m]) { BsW(2, 3); n--; } BsW(1, 0); } } int num23 = 0; num6 = 0; while (num6 < nMTF) { int num8 = num6 + 50 - 1; if (num8 >= nMTF) { num8 = nMTF - 1; } for (int m = num6; m <= num8; m++) { BsW(array[(uint)selector[num23]][szptr[m]], array6[(uint)selector[num23]][szptr[m]]); } num6 = num8 + 1; num23++; } if (num23 != num) { Panic(); } } private void MoveToFrontCodeAndSend() { BsPutIntVS(24, origPtr); GenerateMTFValues(); SendMTFValues(); } private void SimpleSort(int lo, int hi, int d) { int num = hi - lo + 1; if (num < 2) { return; } int i; for (i = 0; incs[i] < num; i++) { } for (i--; i >= 0; i--) { int num2 = incs[i]; int num3 = lo + num2; while (num3 <= hi) { int num4 = zptr[num3]; int num5 = num3; while (FullGtU(zptr[num5 - num2] + d, num4 + d)) { zptr[num5] = zptr[num5 - num2]; num5 -= num2; if (num5 <= lo + num2 - 1) { break; } } zptr[num5] = num4; num3++; if (num3 > hi) { break; } num4 = zptr[num3]; num5 = num3; while (FullGtU(zptr[num5 - num2] + d, num4 + d)) { zptr[num5] = zptr[num5 - num2]; num5 -= num2; if (num5 <= lo + num2 - 1) { break; } } zptr[num5] = num4; num3++; if (num3 > hi) { break; } num4 = zptr[num3]; num5 = num3; while (FullGtU(zptr[num5 - num2] + d, num4 + d)) { zptr[num5] = zptr[num5 - num2]; num5 -= num2; if (num5 <= lo + num2 - 1) { break; } } zptr[num5] = num4; num3++; if (workDone > workLimit && firstAttempt) { return; } } } } private void Vswap(int p1, int p2, int n) { int num = 0; while (n > 0) { num = zptr[p1]; zptr[p1] = zptr[p2]; zptr[p2] = num; p1++; p2++; n--; } } private char Med3(char a, char b, char c) { if (a > b) { char num = a; a = b; b = num; } if (b > c) { char num2 = b; b = c; c = num2; } if (a > b) { b = a; } return b; } private void QSort3(int loSt, int hiSt, int dSt) { StackElem[] array = new StackElem[1000]; for (int i = 0; i < 1000; i++) { array[i] = new StackElem(); } int num = 0; array[num].ll = loSt; array[num].hh = hiSt; array[num].dd = dSt; num++; while (num > 0) { if (num >= 1000) { Panic(); } num--; int ll = array[num].ll; int hh = array[num].hh; int dd = array[num].dd; if (hh - ll < 20 || dd > 10) { SimpleSort(ll, hh, dd); if (workDone > workLimit && firstAttempt) { break; } continue; } int num2 = Med3(block[zptr[ll] + dd + 1], block[zptr[hh] + dd + 1], block[zptr[ll + hh >> 1] + dd + 1]); int num4; int num3 = (num4 = ll); int num6; int num5 = (num6 = hh); int num7; while (true) { if (num3 <= num5) { num7 = block[zptr[num3] + dd + 1] - num2; if (num7 == 0) { int num8 = 0; num8 = zptr[num3]; zptr[num3] = zptr[num4]; zptr[num4] = num8; num4++; num3++; continue; } if (num7 <= 0) { num3++; continue; } } while (num3 <= num5) { num7 = block[zptr[num5] + dd + 1] - num2; if (num7 == 0) { int num9 = 0; num9 = zptr[num5]; zptr[num5] = zptr[num6]; zptr[num6] = num9; num6--; num5--; } else { if (num7 < 0) { break; } num5--; } } if (num3 > num5) { break; } int num10 = zptr[num3]; zptr[num3] = zptr[num5]; zptr[num5] = num10; num3++; num5--; } if (num6 < num4) { array[num].ll = ll; array[num].hh = hh; array[num].dd = dd + 1; num++; continue; } num7 = ((num4 - ll < num3 - num4) ? (num4 - ll) : (num3 - num4)); Vswap(ll, num3 - num7, num7); int num11 = ((hh - num6 < num6 - num5) ? (hh - num6) : (num6 - num5)); Vswap(num3, hh - num11 + 1, num11); num7 = ll + num3 - num4 - 1; num11 = hh - (num6 - num5) + 1; array[num].ll = ll; array[num].hh = num7; array[num].dd = dd; num++; array[num].ll = num7 + 1; array[num].hh = num11 - 1; array[num].dd = dd + 1; num++; array[num].ll = num11; array[num].hh = hh; array[num].dd = dd; num++; } } private void MainSort() { int[] array = new int[256]; int[] array2 = new int[256]; bool[] array3 = new bool[256]; for (int i = 0; i < 20; i++) { block[last + i + 2] = block[i % (last + 1) + 1]; } for (int i = 0; i <= last + 20; i++) { quadrant[i] = 0; } block[0] = block[last + 1]; if (last < 4000) { for (int i = 0; i <= last; i++) { zptr[i] = i; } firstAttempt = false; workDone = (workLimit = 0); SimpleSort(0, last, 0); return; } int num = 0; for (int i = 0; i <= 255; i++) { array3[i] = false; } for (int i = 0; i <= 65536; i++) { ftab[i] = 0; } int num2 = block[0]; for (int i = 0; i <= last; i++) { int num3 = block[i + 1]; ftab[(num2 << 8) + num3]++; num2 = num3; } for (int i = 1; i <= 65536; i++) { ftab[i] += ftab[i - 1]; } num2 = block[1]; int num4; for (int i = 0; i < last; i++) { int num3 = block[i + 2]; num4 = (num2 << 8) + num3; num2 = num3; ftab[num4]--; zptr[ftab[num4]] = i; } num4 = (int)(((uint)block[last + 1] << 8) + block[1]); ftab[num4]--; zptr[ftab[num4]] = last; for (int i = 0; i <= 255; i++) { array[i] = i; } int num5 = 1; do { num5 = 3 * num5 + 1; } while (num5 <= 256); do { num5 /= 3; for (int i = num5; i <= 255; i++) { int num6 = array[i]; num4 = i; while (ftab[array[num4 - num5] + 1 << 8] - ftab[array[num4 - num5] << 8] > ftab[num6 + 1 << 8] - ftab[num6 << 8]) { array[num4] = array[num4 - num5]; num4 -= num5; if (num4 <= num5 - 1) { break; } } array[num4] = num6; } } while (num5 != 1); for (int i = 0; i <= 255; i++) { int num7 = array[i]; for (num4 = 0; num4 <= 255; num4++) { int num8 = (num7 << 8) + num4; if ((ftab[num8] & 0x200000) == 2097152) { continue; } int num9 = ftab[num8] & -2097153; int num10 = (ftab[num8 + 1] & -2097153) - 1; if (num10 > num9) { QSort3(num9, num10, 2); num += num10 - num9 + 1; if (workDone > workLimit && firstAttempt) { return; } } ftab[num8] |= 2097152; } array3[num7] = true; if (i < 255) { int num11 = ftab[num7 << 8] & -2097153; int num12 = (ftab[num7 + 1 << 8] & -2097153) - num11; int j; for (j = 0; num12 >> j > 65534; j++) { } for (num4 = 0; num4 < num12; num4++) { int num13 = zptr[num11 + num4]; int num14 = num4 >> j; quadrant[num13] = num14; if (num13 < 20) { quadrant[num13 + last + 1] = num14; } } if (num12 - 1 >> j > 65535) { Panic(); } } for (num4 = 0; num4 <= 255; num4++) { array2[num4] = ftab[(num4 << 8) + num7] & -2097153; } for (num4 = ftab[num7 << 8] & -2097153; num4 < (ftab[num7 + 1 << 8] & -2097153); num4++) { num2 = block[zptr[num4]]; if (!array3[num2]) { zptr[array2[num2]] = ((zptr[num4] == 0) ? last : (zptr[num4] - 1)); array2[num2]++; } } for (num4 = 0; num4 <= 255; num4++) { ftab[(num4 << 8) + num7] |= 2097152; } } } private void RandomiseBlock() { int num = 0; int num2 = 0; for (int i = 0; i < 256; i++) { inUse[i] = false; } for (int i = 0; i <= last; i++) { if (num == 0) { num = (ushort)BZip2Constants.rNums[num2]; num2++; if (num2 == 512) { num2 = 0; } } num--; block[i + 1] ^= ((num == 1) ? '\u0001' : '\0'); block[i + 1] &= 'ÿ'; inUse[(uint)block[i + 1]] = true; } } private void DoReversibleTransformation() { workLimit = workFactor * last; workDone = 0; blockRandomised = false; firstAttempt = true; MainSort(); if (workDone > workLimit && firstAttempt) { RandomiseBlock(); workLimit = (workDone = 0); blockRandomised = true; firstAttempt = false; MainSort(); } origPtr = -1; for (int i = 0; i <= last; i++) { if (zptr[i] == 0) { origPtr = i; break; } } if (origPtr == -1) { Panic(); } } private bool FullGtU(int i1, int i2) { char c = block[i1 + 1]; char c2 = block[i2 + 1]; if (c != c2) { return c > c2; } i1++; i2++; c = block[i1 + 1]; c2 = block[i2 + 1]; if (c != c2) { return c > c2; } i1++; i2++; c = block[i1 + 1]; c2 = block[i2 + 1]; if (c != c2) { return c > c2; } i1++; i2++; c = block[i1 + 1]; c2 = block[i2 + 1]; if (c != c2) { return c > c2; } i1++; i2++; c = block[i1 + 1]; c2 = block[i2 + 1]; if (c != c2) { return c > c2; } i1++; i2++; c = block[i1 + 1]; c2 = block[i2 + 1]; if (c != c2) { return c > c2; } i1++; i2++; int num = last + 1; do { c = block[i1 + 1]; c2 = block[i2 + 1]; if (c != c2) { return c > c2; } int num2 = quadrant[i1]; int num3 = quadrant[i2]; if (num2 != num3) { return num2 > num3; } i1++; i2++; c = block[i1 + 1]; c2 = block[i2 + 1]; if (c != c2) { return c > c2; } num2 = quadrant[i1]; num3 = quadrant[i2]; if (num2 != num3) { return num2 > num3; } i1++; i2++; c = block[i1 + 1]; c2 = block[i2 + 1]; if (c != c2) { return c > c2; } num2 = quadrant[i1]; num3 = quadrant[i2]; if (num2 != num3) { return num2 > num3; } i1++; i2++; c = block[i1 + 1]; c2 = block[i2 + 1]; if (c != c2) { return c > c2; } num2 = quadrant[i1]; num3 = quadrant[i2]; if (num2 != num3) { return num2 > num3; } i1++; i2++; if (i1 > last) { i1 -= last; i1--; } if (i2 > last) { i2 -= last; i2--; } num -= 4; workDone++; } while (num >= 0); return false; } private void AllocateCompressStructures() { int num = 100000 * blockSize100k; block = new char[num + 1 + 20]; quadrant = new int[num + 20]; zptr = new int[num]; ftab = new int[65537]; if (block != null && quadrant != null && zptr != null) { _ = ftab; } szptr = new short[2 * num]; } private void GenerateMTFValues() { char[] array = new char[256]; MakeMaps(); int num = nInUse + 1; for (int i = 0; i <= num; i++) { mtfFreq[i] = 0; } int num2 = 0; int num3 = 0; for (int i = 0; i < nInUse; i++) { array[i] = (char)i; } for (int i = 0; i <= last; i++) { char c = unseqToSeq[(uint)block[zptr[i]]]; int num4 = 0; char c2 = array[num4]; while (c != c2) { num4++; char c3 = c2; c2 = array[num4]; array[num4] = c3; } array[0] = c2; if (num4 == 0) { num3++; continue; } if (num3 > 0) { num3--; while (true) { switch (num3 % 2) { case 0: szptr[num2] = 0; num2++; mtfFreq[0]++; break; case 1: szptr[num2] = 1; num2++; mtfFreq[1]++; break; } if (num3 < 2) { break; } num3 = (num3 - 2) / 2; } num3 = 0; } szptr[num2] = (short)(num4 + 1); num2++; mtfFreq[num4 + 1]++; } if (num3 > 0) { num3--; while (true) { switch (num3 % 2) { case 0: szptr[num2] = 0; num2++; mtfFreq[0]++; break; case 1: szptr[num2] = 1; num2++; mtfFreq[1]++; break; } if (num3 < 2) { break; } num3 = (num3 - 2) / 2; } } szptr[num2] = (short)num; num2++; mtfFreq[num]++; nMTF = num2; } public override int Read(byte[] buffer, int offset, int count) { return 0; } public override int ReadByte() { return -1; } public override long Seek(long offset, SeekOrigin origin) { return 0L; } public override void SetLength(long value) { } public override void Write(byte[] buffer, int offset, int count) { for (int i = 0; i < count; i++) { WriteByte(buffer[i + offset]); } } } internal class CRC { public static int[] crc32Table = new int[256] { 0, 79764919, 159529838, 222504665, 319059676, 398814059, 445009330, 507990021, 638119352, 583659535, 797628118, 726387553, 890018660, 835552979, 1015980042, 944750013, 1276238704, 1221641927, 1167319070, 1095957929, 1595256236, 1540665371, 1452775106, 1381403509, 1780037320, 1859660671, 1671105958, 1733955601, 2031960084, 2111593891, 1889500026, 1952343757, -1742489888, -1662866601, -1851683442, -1788833735, -1960329156, -1880695413, -2103051438, -2040207643, -1104454824, -1159051537, -1213636554, -1284997759, -1389417084, -1444007885, -1532160278, -1603531939, -734892656, -789352409, -575645954, -646886583, -952755380, -1007220997, -827056094, -898286187, -231047128, -151282273, -71779514, -8804623, -515967244, -436212925, -390279782, -327299027, 881225847, 809987520, 1023691545, 969234094, 662832811, 591600412, 771767749, 717299826, 311336399, 374308984, 453813921, 533576470, 25881363, 88864420, 134795389, 214552010, 2023205639, 2086057648, 1897238633, 1976864222, 1804852699, 1867694188, 1645340341, 1724971778, 1587496639, 1516133128, 1461550545, 1406951526, 1302016099, 1230646740, 1142491917, 1087903418, -1398421865, -1469785312, -1524105735, -1578704818, -1079922613, -1151291908, -1239184603, -1293773166, -1968362705, -1905510760, -2094067647, -2014441994, -1716953613, -1654112188, -1876203875, -1796572374, -525066777, -462094256, -382327159, -302564546, -206542021, -143559028, -97365931, -17609246, -960696225, -1031934488, -817968335, -872425850, -709327229, -780559564, -600130067, -654598054, 1762451694, 1842216281, 1619975040, 1682949687, 2047383090, 2127137669, 1938468188, 2001449195, 1325665622, 1271206113, 1183200824, 1111960463, 1543535498, 1489069629, 1434599652, 1363369299, 622672798, 568075817, 748617968, 677256519, 907627842, 853037301, 1067152940, 995781531, 51762726, 131386257, 177728840, 240578815, 269590778, 349224269, 429104020, 491947555, -248556018, -168932423, -122852000, -60002089, -500490030, -420856475, -341238852, -278395381, -685261898, -739858943, -559578920, -630940305, -1004286614, -1058877219, -845023740, -916395085, -1119974018, -1174433591, -1262701040, -1333941337, -1371866206, -1426332139, -1481064244, -1552294533, -1690935098, -1611170447, -1833673816, -1770699233, -2009983462, -1930228819, -2119160460, -2056179517, 1569362073, 1498123566, 1409854455, 1355396672, 1317987909, 1246755826, 1192025387, 1137557660, 2072149281, 2135122070, 1912620623, 1992383480, 1753615357, 1816598090, 1627664531, 1707420964, 295390185, 358241886, 404320391, 483945776, 43990325, 106832002, 186451547, 266083308, 932423249, 861060070, 1041341759, 986742920, 613929101, 542559546, 756411363, 701822548, -978770311, -1050133554, -869589737, -924188512, -693284699, -764654318, -550540341, -605129092, -475935807, -413084042, -366743377, -287118056, -257573603, -194731862, -114850189, -35218492, -1984365303, -1921392450, -2143631769, -2063868976, -1698919467, -1635936670, -1824608069, -1744851700, -1347415887, -1418654458, -1506661409, -1561119128, -1129027987, -1200260134, -1254728445, -1309196108 }; internal int globalCrc; public CRC() { InitialiseCRC(); } internal void InitialiseCRC() { globalCrc = -1; } internal int GetFinalCRC() { return ~globalCrc; } internal int GetGlobalCRC() { return globalCrc; } internal void SetGlobalCRC(int newCrc) { globalCrc = newCrc; } internal void UpdateCRC(int inCh) { int num = (globalCrc >> 24) ^ inCh; if (num < 0) { num = 256 + num; } globalCrc = (globalCrc << 8) ^ crc32Table[num]; } } } namespace SharpCompress.Compressors.ADC { public static class ADCBase { private const int PLAIN = 1; private const int TWO_BYTE = 2; private const int THREE_BYTE = 3; private static int GetChunkType(byte byt) { if ((byt & 0x80) == 128) { return 1; } if ((byt & 0x40) == 64) { return 3; } return 2; } private static int GetChunkSize(byte byt) { return GetChunkType(byt) switch { 1 => (byt & 0x7F) + 1, 2 => ((byt & 0x3F) >> 2) + 3, 3 => (byt & 0x3F) + 4, _ => -1, }; } private static int GetOffset(byte[] chunk, int position) { return GetChunkType(chunk[position]) switch { 1 => 0, 2 => ((chunk[position] & 3) << 8) + chunk[position + 1], 3 => (chunk[position + 1] << 8) + chunk[position + 2], _ => -1, }; } public static int Decompress(byte[] input, out byte[] output, int bufferSize = 262144) { return Decompress(new MemoryStream(input), out output, bufferSize); } public static int Decompress(Stream input, out byte[] output, int bufferSize = 262144) { output = null; if (input == null || input.Length == 0L) { return 0; } int num = (int)input.Position; int num2 = (int)input.Position; byte[] array = new byte[bufferSize]; int num3 = 0; bool flag = false; while (num2 < input.Length) { int num4 = input.ReadByte(); if (num4 == -1) { break; } switch (GetChunkType((byte)num4)) { case 1: { int chunkSize = GetChunkSize((byte)num4); if (num3 + chunkSize > bufferSize) { flag = true; break; } input.Read(array, num3, chunkSize); num3 += chunkSize; num2 += chunkSize + 1; break; } case 2: { MemoryStream memoryStream2 = new MemoryStream(); int chunkSize = GetChunkSize((byte)num4); memoryStream2.WriteByte((byte)num4); memoryStream2.WriteByte((byte)input.ReadByte()); int offset = GetOffset(memoryStream2.ToArray(), 0); if (num3 + chunkSize > bufferSize) { flag = true; } else if (offset == 0) { byte b2 = array[num3 - 1]; for (int k = 0; k < chunkSize; k++) { array[num3] = b2; num3++; } num2 += 2; } else { for (int l = 0; l < chunkSize; l++) { array[num3] = array[num3 - offset - 1]; num3++; } num2 += 2; } break; } case 3: { MemoryStream memoryStream = new MemoryStream(); int chunkSize = GetChunkSize((byte)num4); memoryStream.WriteByte((byte)num4); memoryStream.WriteByte((byte)input.ReadByte()); memoryStream.WriteByte((byte)input.ReadByte()); int offset = GetOffset(memoryStream.ToArray(), 0); if (num3 + chunkSize > bufferSize) { flag = true; } else if (offset == 0) { byte b = array[num3 - 1]; for (int i = 0; i < chunkSize; i++) { array[num3] = b; num3++; } num2 += 3; } else { for (int j = 0; j < chunkSize; j++) { array[num3] = array[num3 - offset - 1]; num3++; } num2 += 3; } break; } } if (flag) { break; } } output = new byte[num3]; Array.Copy(array, 0, output, 0, num3); return num2 - num; } } public class ADCStream : Stream { private readonly Stream _stream; private bool _isDisposed; private long _position; private byte[] _outBuffer; private int _outPosition; public override bool CanRead => _stream.CanRead; public override bool CanSeek => false; public override bool CanWrite => false; public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { return _position; } set { throw new NotSupportedException(); } } public ADCStream(Stream stream, CompressionMode compressionMode = CompressionMode.Decompress) { if (compressionMode == CompressionMode.Compress) { throw new NotSupportedException(); } _stream = stream; } public override void Flush() { } protected override void Dispose(bool disposing) { if (!_isDisposed) { _isDisposed = true; base.Dispose(disposing); } } public override int Read(byte[] buffer, int offset, int count) { if (count == 0) { return 0; } if (buffer == null) { throw new ArgumentNullException("buffer"); } if (count < 0) { throw new ArgumentOutOfRangeException("count"); } if (offset < buffer.GetLowerBound(0)) { throw new ArgumentOutOfRangeException("offset"); } if (offset + count > buffer.GetLength(0)) { throw new ArgumentOutOfRangeException("count"); } if (_outBuffer == null) { ADCBase.Decompress(_stream, out _outBuffer); _outPosition = 0; } int num = offset; int num2 = count; int num3 = 0; while (_outPosition + num2 >= _outBuffer.Length) { int num4 = _outBuffer.Length - _outPosition; Array.Copy(_outBuffer, _outPosition, buffer, num, num4); num += num4; num3 += num4; _position += num4; num2 -= num4; int num5 = ADCBase.Decompress(_stream, out _outBuffer); _outPosition = 0; if (num5 == 0 || _outBuffer == null || _outBuffer.Length == 0) { return num3; } } Array.Copy(_outBuffer, _outPosition, buffer, num, num2); _outPosition += num2; _position += num2; return num3 + num2; } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } } } namespace SharpCompress.Common { public class ArchiveEncoding { public Encoding Default { get; set; } public Encoding Password { get; set; } public Encoding Forced { get; set; } public Func CustomDecoder { get; set; } public ArchiveEncoding() { Default = Encoding.GetEncoding(437); Password = Encoding.GetEncoding(437); } public string Decode(byte[] bytes) { return Decode(bytes, 0, bytes.Length); } public string Decode(byte[] bytes, int start, int length) { return GetDecoder()(bytes, start, length); } public string DecodeUTF8(byte[] bytes) { return Encoding.UTF8.GetString(bytes, 0, bytes.Length); } public byte[] Encode(string str) { return GetEncoding().GetBytes(str); } public Encoding GetEncoding() { return Forced ?? Default ?? Encoding.UTF8; } public Func GetDecoder() { return CustomDecoder ?? ((Func)((byte[] bytes, int index, int count) => GetEncoding().GetString(bytes, index, count))); } } public class ArchiveException : Exception { public ArchiveException(string message) : base(message) { } } public class ArchiveExtractionEventArgs : EventArgs { public T Item { get; } internal ArchiveExtractionEventArgs(T entry) { Item = entry; } } public enum ArchiveType { Rar, Zip, Tar, SevenZip, GZip } public class CompressedBytesReadEventArgs : EventArgs { public long CompressedBytesRead { get; internal set; } public long CurrentFilePartCompressedBytesRead { get; internal set; } } public enum CompressionType { None, GZip, BZip2, PPMd, Deflate, Rar, LZMA, BCJ, BCJ2, LZip, Xz, Unknown, Deflate64 } public class CryptographicException : Exception { public CryptographicException(string message) : base(message) { } } public abstract class Entry : IEntry { public abstract long Crc { get; } public abstract string Key { get; } public abstract string LinkTarget { get; } public abstract long CompressedSize { get; } public abstract CompressionType CompressionType { get; } public abstract long Size { get; } public abstract DateTime? LastModifiedTime { get; } public abstract DateTime? CreatedTime { get; } public abstract DateTime? LastAccessedTime { get; } public abstract DateTime? ArchivedTime { get; } public abstract bool IsEncrypted { get; } public abstract bool IsDirectory { get; } public abstract bool IsSplitAfter { get; } internal abstract IEnumerable Parts { get; } internal bool IsSolid { get; set; } public virtual int? Attrib { get { throw new NotImplementedException(); } } public override string ToString() { return Key; } internal virtual void Close() { } } public class EntryStream : Stream { private readonly IReader _reader; private readonly Stream _stream; private bool _completed; private bool _isDisposed; public override bool CanRead => true; public override bool CanSeek => false; public override bool CanWrite => false; public override long Length => _stream.Length; public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } internal EntryStream(IReader reader, Stream stream) { _reader = reader; _stream = stream; } public void SkipEntry() { this.Skip(); _completed = true; } protected override void Dispose(bool disposing) { if (!_completed && !_reader.Cancelled) { SkipEntry(); } if (!_isDisposed) { _isDisposed = true; base.Dispose(disposing); _stream.Dispose(); } } public override void Flush() { } public override int Read(byte[] buffer, int offset, int count) { int num = _stream.Read(buffer, offset, count); if (num <= 0) { _completed = true; } return num; } public override int ReadByte() { int num = _stream.ReadByte(); if (num == -1) { _completed = true; } return num; } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } } public class ExtractionException : Exception { public ExtractionException(string message) : base(message) { } public ExtractionException(string message, Exception inner) : base(message, inner) { } } internal static class ExtractionMethods { public static void WriteEntryToDirectory(IEntry entry, string destinationDirectory, ExtractionOptions options, Action write) { string fileName = Path.GetFileName(entry.Key); string fullPath = Path.GetFullPath(destinationDirectory); options = options ?? new ExtractionOptions { Overwrite = true }; string path; if (options.ExtractFullPath) { string directoryName = Path.GetDirectoryName(entry.Key); string fullPath2 = Path.GetFullPath(Path.Combine(fullPath, directoryName)); if (!Directory.Exists(fullPath2)) { if (!fullPath2.StartsWith(fullPath)) { throw new ExtractionException("Entry is trying to create a directory outside of the destination directory."); } Directory.CreateDirectory(fullPath2); } path = Path.Combine(fullPath2, fileName); } else { path = Path.Combine(fullPath, fileName); } if (!entry.IsDirectory) { path = Path.GetFullPath(path); if (!path.StartsWith(fullPath)) { throw new ExtractionException("Entry is trying to write a file outside of the destination directory."); } write(path, options); } else if (options.ExtractFullPath && !Directory.Exists(path)) { Directory.CreateDirectory(path); } } public static void WriteEntryToFile(IEntry entry, string destinationFileName, ExtractionOptions options, Action openAndWrite) { if (entry.LinkTarget != null) { if (options.WriteSymbolicLink == null) { throw new ExtractionException("Entry is a symbolic link but ExtractionOptions.WriteSymbolicLink delegate is null"); } options.WriteSymbolicLink(destinationFileName, entry.LinkTarget); return; } FileMode arg = FileMode.Create; options = options ?? new ExtractionOptions { Overwrite = true }; if (!options.Overwrite) { arg = FileMode.CreateNew; } openAndWrite(destinationFileName, arg); entry.PreserveExtractionOptions(destinationFileName, options); } } public class ExtractionOptions { public delegate void SymbolicLinkWriterDelegate(string sourcePath, string targetPath); public SymbolicLinkWriterDelegate WriteSymbolicLink; public bool Overwrite { get; set; } public bool ExtractFullPath { get; set; } public bool PreserveFileTime { get; set; } public bool PreserveAttributes { get; set; } } public abstract class FilePart { internal ArchiveEncoding ArchiveEncoding { get; } internal abstract string FilePartName { get; } internal bool Skipped { get; set; } protected FilePart(ArchiveEncoding archiveEncoding) { ArchiveEncoding = archiveEncoding; } internal abstract Stream GetCompressedStream(); internal abstract Stream GetRawStream(); } public class FilePartExtractionBeginEventArgs : EventArgs { public string Name { get; internal set; } public long Size { get; internal set; } public long CompressedSize { get; internal set; } } internal static class FlagUtility { public static bool HasFlag(long bitField, T flag) where T : struct { return HasFlag(bitField, flag); } public static bool HasFlag(ulong bitField, T flag) where T : struct { return HasFlag(bitField, flag); } public static bool HasFlag(ulong bitField, ulong flag) { return (bitField & flag) == flag; } public static bool HasFlag(short bitField, short flag) { return (bitField & flag) == flag; } public static bool HasFlag(T bitField, T flag) where T : struct { return HasFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag)); } public static bool HasFlag(long bitField, long flag) { return (bitField & flag) == flag; } public static long SetFlag(long bitField, long flag, bool on) { if (on) { return bitField | flag; } return bitField & ~flag; } public static long SetFlag(T bitField, T flag, bool on) where T : struct { return SetFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag), on); } } public interface IEntry { CompressionType CompressionType { get; } DateTime? ArchivedTime { get; } long CompressedSize { get; } long Crc { get; } DateTime? CreatedTime { get; } string Key { get; } string LinkTarget { get; } bool IsDirectory { get; } bool IsEncrypted { get; } bool IsSplitAfter { get; } DateTime? LastAccessedTime { get; } DateTime? LastModifiedTime { get; } long Size { get; } int? Attrib { get; } } internal static class EntryExtensions { internal static void PreserveExtractionOptions(this IEntry entry, string destinationFileName, ExtractionOptions options) { if (!options.PreserveFileTime && !options.PreserveAttributes) { return; } FileInfo fileInfo = new FileInfo(destinationFileName); if (!fileInfo.Exists) { return; } if (options.PreserveFileTime) { if (entry.CreatedTime.HasValue) { fileInfo.CreationTime = entry.CreatedTime.Value; } if (entry.LastModifiedTime.HasValue) { fileInfo.LastWriteTime = entry.LastModifiedTime.Value; } if (entry.LastAccessedTime.HasValue) { fileInfo.LastAccessTime = entry.LastAccessedTime.Value; } } if (options.PreserveAttributes && entry.Attrib.HasValue) { fileInfo.Attributes = (FileAttributes)Enum.ToObject(typeof(FileAttributes), entry.Attrib.Value); } } } internal interface IExtractionListener { void FireFilePartExtractionBegin(string name, long size, long compressedSize); void FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes); } public class IncompleteArchiveException : ArchiveException { public IncompleteArchiveException(string message) : base(message) { } } public class InvalidFormatException : ExtractionException { public InvalidFormatException(string message) : base(message) { } public InvalidFormatException(string message, Exception inner) : base(message, inner) { } } public interface IVolume : IDisposable { } public class MultipartStreamRequiredException : ExtractionException { public MultipartStreamRequiredException(string message) : base(message) { } } public class MultiVolumeExtractionException : ExtractionException { public MultiVolumeExtractionException(string message) : base(message) { } public MultiVolumeExtractionException(string message, Exception inner) : base(message, inner) { } } public class OptionsBase { public bool LeaveStreamOpen { get; set; } = true; public ArchiveEncoding ArchiveEncoding { get; set; } = new ArchiveEncoding(); } public class PasswordProtectedException : ExtractionException { public PasswordProtectedException(string message) : base(message) { } public PasswordProtectedException(string message, Exception inner) : base(message, inner) { } } public class ReaderExtractionEventArgs : EventArgs { public T Item { get; } public ReaderProgress ReaderProgress { get; } internal ReaderExtractionEventArgs(T entry, ReaderProgress readerProgress = null) { Item = entry; ReaderProgress = readerProgress; } } public abstract class Volume : IVolume, IDisposable { private readonly Stream _actualStream; internal Stream Stream => _actualStream; protected ReaderOptions ReaderOptions { get; } public virtual bool IsFirstVolume => true; public virtual bool IsMultiVolume => true; internal Volume(Stream stream, ReaderOptions readerOptions) { ReaderOptions = readerOptions; if (readerOptions.LeaveStreamOpen) { stream = new NonDisposingStream(stream); } _actualStream = stream; } protected virtual void Dispose(bool disposing) { if (disposing) { _actualStream.Dispose(); } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } } } namespace SharpCompress.Common.Zip { internal enum CryptoMode { Encrypt, Decrypt } internal class PkwareTraditionalCryptoStream : Stream { private readonly PkwareTraditionalEncryptionData _encryptor; private readonly CryptoMode _mode; private readonly Stream _stream; private bool _isDisposed; public override bool CanRead => _mode == CryptoMode.Decrypt; public override bool CanSeek => false; public override bool CanWrite => _mode == CryptoMode.Encrypt; public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } public PkwareTraditionalCryptoStream(Stream stream, PkwareTraditionalEncryptionData encryptor, CryptoMode mode) { _encryptor = encryptor; _stream = stream; _mode = mode; } public override int Read(byte[] buffer, int offset, int count) { if (_mode == CryptoMode.Encrypt) { throw new NotSupportedException("This stream does not encrypt via Read()"); } if (buffer == null) { throw new ArgumentNullException("buffer"); } byte[] array = new byte[count]; int num = _stream.Read(array, 0, count); Buffer.BlockCopy(_encryptor.Decrypt(array, num), 0, buffer, offset, num); return num; } public override void Write(byte[] buffer, int offset, int count) { if (_mode == CryptoMode.Decrypt) { throw new NotSupportedException("This stream does not Decrypt via Write()"); } if (count != 0) { byte[] array = null; if (offset != 0) { array = new byte[count]; Buffer.BlockCopy(buffer, offset, array, 0, count); } else { array = buffer; } byte[] array2 = _encryptor.Encrypt(array, count); _stream.Write(array2, 0, array2.Length); } } public override void Flush() { } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } protected override void Dispose(bool disposing) { if (!_isDisposed) { _isDisposed = true; base.Dispose(disposing); _stream.Dispose(); } } } internal class PkwareTraditionalEncryptionData { private static readonly CRC32 CRC32 = new CRC32(); private readonly uint[] _keys = new uint[3] { 305419896u, 591751049u, 878082192u }; private readonly ArchiveEncoding _archiveEncoding; private byte MagicByte { get { ushort num = (ushort)((ushort)(_keys[2] & 0xFFFF) | 2); return (byte)(num * (num ^ 1) >> 8); } } private PkwareTraditionalEncryptionData(string password, ArchiveEncoding archiveEncoding) { _archiveEncoding = archiveEncoding; Initialize(password); } public static PkwareTraditionalEncryptionData ForRead(string password, ZipFileEntry header, byte[] encryptionHeader) { PkwareTraditionalEncryptionData pkwareTraditionalEncryptionData = new PkwareTraditionalEncryptionData(password, header.ArchiveEncoding); byte[] array = pkwareTraditionalEncryptionData.Decrypt(encryptionHeader, encryptionHeader.Length); if (array[11] != (byte)((header.Crc >> 24) & 0xFF)) { if (!FlagUtility.HasFlag(header.Flags, HeaderFlags.UsePostDataDescriptor)) { throw new CryptographicException("The password did not match."); } if (array[11] != (byte)((header.LastModifiedTime >> 8) & 0xFF)) { throw new CryptographicException("The password did not match."); } } return pkwareTraditionalEncryptionData; } public byte[] Decrypt(byte[] cipherText, int length) { if (length > cipherText.Length) { throw new ArgumentOutOfRangeException("length", "Bad length during Decryption: the length parameter must be smaller than or equal to the size of the destination array."); } byte[] array = new byte[length]; for (int i = 0; i < length; i++) { byte b = (byte)(cipherText[i] ^ MagicByte); UpdateKeys(b); array[i] = b; } return array; } public byte[] Encrypt(byte[] plainText, int length) { if (plainText == null) { throw new ArgumentNullException("plaintext"); } if (length > plainText.Length) { throw new ArgumentOutOfRangeException("length", "Bad length during Encryption: The length parameter must be smaller than or equal to the size of the destination array."); } byte[] array = new byte[length]; for (int i = 0; i < length; i++) { byte byteValue = plainText[i]; array[i] = (byte)(plainText[i] ^ MagicByte); UpdateKeys(byteValue); } return array; } private void Initialize(string password) { byte[] array = StringToByteArray(password); for (int i = 0; i < password.Length; i++) { UpdateKeys(array[i]); } } internal byte[] StringToByteArray(string value) { return _archiveEncoding.Password.GetBytes(value); } private void UpdateKeys(byte byteValue) { _keys[0] = (uint)CRC32.ComputeCrc32((int)_keys[0], byteValue); _keys[1] = _keys[1] + (byte)_keys[0]; _keys[1] = _keys[1] * 134775813 + 1; _keys[2] = (uint)CRC32.ComputeCrc32((int)_keys[2], (byte)(_keys[1] >> 24)); } } internal class SeekableZipFilePart : ZipFilePart { private bool _isLocalHeaderLoaded; private readonly SeekableZipHeaderFactory _headerFactory; private readonly DirectoryEntryHeader _directoryEntryHeader; internal string Comment => (base.Header as DirectoryEntryHeader).Comment; internal SeekableZipFilePart(SeekableZipHeaderFactory headerFactory, DirectoryEntryHeader header, Stream stream) : base(header, stream) { _headerFactory = headerFactory; _directoryEntryHeader = header; } internal override Stream GetCompressedStream() { if (!_isLocalHeaderLoaded) { LoadLocalHeader(); _isLocalHeaderLoaded = true; } return base.GetCompressedStream(); } private void LoadLocalHeader() { bool hasData = base.Header.HasData; base.Header = _headerFactory.GetLocalHeader(base.BaseStream, base.Header as DirectoryEntryHeader); base.Header.HasData = hasData; } protected override Stream CreateBaseStream() { base.BaseStream.Position = base.Header.DataStartPosition.Value; if (base.Header.CompressedSize == 0L && FlagUtility.HasFlag(base.Header.Flags, HeaderFlags.UsePostDataDescriptor)) { DirectoryEntryHeader directoryEntryHeader = _directoryEntryHeader; if (directoryEntryHeader != null && directoryEntryHeader.HasData) { DirectoryEntryHeader directoryEntryHeader2 = _directoryEntryHeader; if (directoryEntryHeader2 == null || directoryEntryHeader2.CompressedSize != 0) { return new ReadOnlySubStream(base.BaseStream, _directoryEntryHeader.CompressedSize); } } } return base.BaseStream; } } internal class SeekableZipHeaderFactory : ZipHeaderFactory { private const int MAX_ITERATIONS_FOR_DIRECTORY_HEADER = 4096; private bool _zip64; internal SeekableZipHeaderFactory(string password, ArchiveEncoding archiveEncoding) : base(StreamingMode.Seekable, password, archiveEncoding) { } internal IEnumerable ReadSeekableHeader(Stream stream) { BinaryReader reader = new BinaryReader(stream); SeekBackToHeader(stream, reader, 101010256u); DirectoryEndHeader directoryEndHeader = new DirectoryEndHeader(); directoryEndHeader.Read(reader); if (directoryEndHeader.IsZip64) { _zip64 = true; SeekBackToHeader(stream, reader, 117853008u); Zip64DirectoryEndLocatorHeader zip64DirectoryEndLocatorHeader = new Zip64DirectoryEndLocatorHeader(); zip64DirectoryEndLocatorHeader.Read(reader); stream.Seek(zip64DirectoryEndLocatorHeader.RelativeOffsetOfTheEndOfDirectoryRecord, SeekOrigin.Begin); if (reader.ReadUInt32() != 101075792) { throw new ArchiveException("Failed to locate the Zip64 Header"); } Zip64DirectoryEndHeader zip64DirectoryEndHeader = new Zip64DirectoryEndHeader(); zip64DirectoryEndHeader.Read(reader); stream.Seek(zip64DirectoryEndHeader.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin); } else { stream.Seek(directoryEndHeader.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin); } long position = stream.Position; while (true) { stream.Position = position; uint headerBytes = reader.ReadUInt32(); ZipHeader zipHeader = ReadHeader(headerBytes, reader, _zip64); position = stream.Position; if (zipHeader == null) { break; } if (zipHeader is DirectoryEntryHeader directoryEntryHeader) { directoryEntryHeader.HasData = directoryEntryHeader.CompressedSize != 0; yield return directoryEntryHeader; } else if (zipHeader is DirectoryEndHeader directoryEndHeader2) { yield return directoryEndHeader2; } } } private static void SeekBackToHeader(Stream stream, BinaryReader reader, uint headerSignature) { long num = 0L; int num2 = 0; uint num3; do { if (stream.Length + num - 4 < 0) { throw new ArchiveException("Failed to locate the Zip Header"); } stream.Seek(num - 4, SeekOrigin.End); num3 = reader.ReadUInt32(); num--; num2++; if (num2 > 4096) { throw new ArchiveException("Could not find Zip file Directory at the end of the file. File may be corrupted."); } } while (num3 != headerSignature); } internal LocalEntryHeader GetLocalHeader(Stream stream, DirectoryEntryHeader directoryEntryHeader) { stream.Seek(directoryEntryHeader.RelativeOffsetOfEntryHeader, SeekOrigin.Begin); BinaryReader binaryReader = new BinaryReader(stream); uint headerBytes = binaryReader.ReadUInt32(); return (ReadHeader(headerBytes, binaryReader, _zip64) as LocalEntryHeader) ?? throw new InvalidOperationException(); } } internal class StreamingZipFilePart : ZipFilePart { private Stream _decompressionStream; internal StreamingZipFilePart(ZipFileEntry header, Stream stream) : base(header, stream) { } protected override Stream CreateBaseStream() { return base.Header.PackedStream; } internal override Stream GetCompressedStream() { if (!base.Header.HasData) { return Stream.Null; } _decompressionStream = CreateDecompressionStream(GetCryptoStream(CreateBaseStream()), base.Header.CompressionMethod); if (base.LeaveStreamOpen) { return new NonDisposingStream(_decompressionStream); } return _decompressionStream; } internal BinaryReader FixStreamedFileLocation(ref RewindableStream rewindableStream) { if (base.Header.IsDirectory) { return new BinaryReader(rewindableStream); } if (base.Header.HasData && !base.Skipped) { if (_decompressionStream == null) { _decompressionStream = GetCompressedStream(); } _decompressionStream.Skip(); if (_decompressionStream is DeflateStream deflateStream) { rewindableStream.Rewind(deflateStream.InputBuffer); } base.Skipped = true; } BinaryReader result = new BinaryReader(rewindableStream); _decompressionStream = null; return result; } } internal class StreamingZipHeaderFactory : ZipHeaderFactory { internal StreamingZipHeaderFactory(string password, ArchiveEncoding archiveEncoding) : base(StreamingMode.Streaming, password, archiveEncoding) { } internal IEnumerable ReadStreamHeader(Stream stream) { RewindableStream rewindableStream = ((!(stream is RewindableStream)) ? new RewindableStream(stream) : (stream as RewindableStream)); while (true) { BinaryReader binaryReader = new BinaryReader(rewindableStream); if (_lastEntryHeader != null && (FlagUtility.HasFlag(_lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor) || _lastEntryHeader.IsZip64)) { binaryReader = (_lastEntryHeader.Part as StreamingZipFilePart).FixStreamedFileLocation(ref rewindableStream); long? num = (rewindableStream.CanSeek ? new long?(rewindableStream.Position) : ((long?)null)); uint num2 = binaryReader.ReadUInt32(); if (num2 == 134695760) { num2 = binaryReader.ReadUInt32(); } _lastEntryHeader.Crc = num2; _lastEntryHeader.CompressedSize = binaryReader.ReadUInt32(); _lastEntryHeader.UncompressedSize = binaryReader.ReadUInt32(); if (num.HasValue) { _lastEntryHeader.DataStartPosition = num - _lastEntryHeader.CompressedSize; } } _lastEntryHeader = null; uint headerBytes = binaryReader.ReadUInt32(); ZipHeader zipHeader = ReadHeader(headerBytes, binaryReader); if (zipHeader == null) { break; } if (zipHeader.ZipHeaderType == ZipHeaderType.LocalEntry) { bool isRecording = rewindableStream.IsRecording; if (!isRecording) { rewindableStream.StartRecording(); } uint headerBytes2 = binaryReader.ReadUInt32(); zipHeader.HasData = !ZipHeaderFactory.IsHeader(headerBytes2); rewindableStream.Rewind(!isRecording); } yield return zipHeader; } } } internal class WinzipAesCryptoStream : Stream { private const int BLOCK_SIZE_IN_BYTES = 16; private readonly SymmetricAlgorithm _cipher; private readonly byte[] _counter = new byte[16]; private readonly Stream _stream; private readonly ICryptoTransform _transform; private int _nonce = 1; private byte[] _counterOut = new byte[16]; private bool _isFinalBlock; private long _totalBytesLeftToRead; private bool _isDisposed; public override bool CanRead => true; public override bool CanSeek => false; public override bool CanWrite => false; public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } internal WinzipAesCryptoStream(Stream stream, WinzipAesEncryptionData winzipAesEncryptionData, long length) { _stream = stream; _totalBytesLeftToRead = length; _cipher = CreateCipher(winzipAesEncryptionData); byte[] rgbIV = new byte[16]; _transform = _cipher.CreateEncryptor(winzipAesEncryptionData.KeyBytes, rgbIV); } private SymmetricAlgorithm CreateCipher(WinzipAesEncryptionData winzipAesEncryptionData) { Aes aes = Aes.Create(); aes.BlockSize = 128; aes.KeySize = winzipAesEncryptionData.KeyBytes.Length * 8; aes.Mode = CipherMode.ECB; aes.Padding = PaddingMode.None; return aes; } protected override void Dispose(bool disposing) { if (!_isDisposed) { _isDisposed = true; if (disposing) { byte[] buffer = new byte[10]; _stream.ReadFully(buffer); _stream.Dispose(); } } } public override void Flush() { throw new NotSupportedException(); } public override int Read(byte[] buffer, int offset, int count) { if (_totalBytesLeftToRead == 0L) { return 0; } int count2 = count; if (count > _totalBytesLeftToRead) { count2 = (int)_totalBytesLeftToRead; } int num = _stream.Read(buffer, offset, count2); _totalBytesLeftToRead -= num; ReadTransformBlocks(buffer, offset, num); return num; } private int ReadTransformOneBlock(byte[] buffer, int offset, int last) { if (_isFinalBlock) { throw new InvalidOperationException(); } int num = last - offset; int num2 = ((num > 16) ? 16 : num); DataConverter.LittleEndian.PutBytes(_counter, 0, _nonce++); if (num2 == num && _totalBytesLeftToRead == 0L) { _counterOut = _transform.TransformFinalBlock(_counter, 0, 16); _isFinalBlock = true; } else { _transform.TransformBlock(_counter, 0, 16, _counterOut, 0); } XorInPlace(buffer, offset, num2); return num2; } private void XorInPlace(byte[] buffer, int offset, int count) { for (int i = 0; i < count; i++) { buffer[offset + i] = (byte)(_counterOut[i] ^ buffer[offset + i]); } } private void ReadTransformBlocks(byte[] buffer, int offset, int count) { int i = offset; int num2; for (int num = count + offset; i < buffer.Length && i < num; i += num2) { num2 = ReadTransformOneBlock(buffer, i, num); } } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } } internal class WinzipAesEncryptionData { private const int RFC2898_ITERATIONS = 1000; private readonly byte[] _salt; private readonly WinzipAesKeySize _keySize; private readonly byte[] _passwordVerifyValue; private readonly string _password; private byte[] _generatedVerifyValue; internal byte[] IvBytes { get; set; } internal byte[] KeyBytes { get; set; } private int KeySizeInBytes => KeyLengthInBytes(_keySize); internal WinzipAesEncryptionData(WinzipAesKeySize keySize, byte[] salt, byte[] passwordVerifyValue, string password) { _keySize = keySize; _salt = salt; _passwordVerifyValue = passwordVerifyValue; _password = password; Initialize(); } internal static int KeyLengthInBytes(WinzipAesKeySize keySize) { return keySize switch { WinzipAesKeySize.KeySize128 => 16, WinzipAesKeySize.KeySize192 => 24, WinzipAesKeySize.KeySize256 => 32, _ => throw new InvalidOperationException(), }; } private void Initialize() { Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(_password, _salt, 1000); KeyBytes = rfc2898DeriveBytes.GetBytes(KeySizeInBytes); IvBytes = rfc2898DeriveBytes.GetBytes(KeySizeInBytes); _generatedVerifyValue = rfc2898DeriveBytes.GetBytes(2); short @int = DataConverter.LittleEndian.GetInt16(_passwordVerifyValue, 0); if (_password != null) { short int2 = DataConverter.LittleEndian.GetInt16(_generatedVerifyValue, 0); if (@int != int2) { throw new InvalidFormatException("bad password"); } } } } internal enum WinzipAesKeySize { KeySize128 = 1, KeySize192, KeySize256 } internal enum ZipCompressionMethod { None = 0, Deflate = 8, Deflate64 = 9, BZip2 = 12, LZMA = 14, PPMd = 98, WinzipAes = 99 } public class ZipEntry : Entry { private readonly ZipFilePart _filePart; public override CompressionType CompressionType => _filePart.Header.CompressionMethod switch { ZipCompressionMethod.BZip2 => CompressionType.BZip2, ZipCompressionMethod.Deflate => CompressionType.Deflate, ZipCompressionMethod.Deflate64 => CompressionType.Deflate64, ZipCompressionMethod.LZMA => CompressionType.LZMA, ZipCompressionMethod.PPMd => CompressionType.PPMd, ZipCompressionMethod.None => CompressionType.None, _ => CompressionType.Unknown, }; public override long Crc => _filePart.Header.Crc; public override string Key => _filePart.Header.Name; public override string LinkTarget => null; public override long CompressedSize => _filePart.Header.CompressedSize; public override long Size => _filePart.Header.UncompressedSize; public override DateTime? LastModifiedTime { get; } public override DateTime? CreatedTime => null; public override DateTime? LastAccessedTime => null; public override DateTime? ArchivedTime => null; public override bool IsEncrypted => FlagUtility.HasFlag(_filePart.Header.Flags, HeaderFlags.Encrypted); public override bool IsDirectory => _filePart.Header.IsDirectory; public override bool IsSplitAfter => false; internal override IEnumerable Parts => ((FilePart)_filePart).AsEnumerable(); internal ZipEntry(ZipFilePart filePart) { if (filePart != null) { _filePart = filePart; LastModifiedTime = Utility.DosDateToDateTime(filePart.Header.LastModifiedDate, filePart.Header.LastModifiedTime); } } } internal abstract class ZipFilePart : FilePart { internal Stream BaseStream { get; } internal ZipFileEntry Header { get; set; } internal override string FilePartName => Header.Name; protected bool LeaveStreamOpen { get { if (!FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor)) { return Header.IsZip64; } return true; } } internal ZipFilePart(ZipFileEntry header, Stream stream) : base(header.ArchiveEncoding) { Header = header; header.Part = this; BaseStream = stream; } internal override Stream GetCompressedStream() { if (!Header.HasData) { return Stream.Null; } Stream stream = CreateDecompressionStream(GetCryptoStream(CreateBaseStream()), Header.CompressionMethod); if (LeaveStreamOpen) { return new NonDisposingStream(stream); } return stream; } internal override Stream GetRawStream() { if (!Header.HasData) { return Stream.Null; } return CreateBaseStream(); } protected abstract Stream CreateBaseStream(); protected Stream CreateDecompressionStream(Stream stream, ZipCompressionMethod method) { switch (method) { case ZipCompressionMethod.None: return stream; case ZipCompressionMethod.Deflate: return new DeflateStream(stream, CompressionMode.Decompress); case ZipCompressionMethod.Deflate64: return new Deflate64Stream(stream, CompressionMode.Decompress); case ZipCompressionMethod.BZip2: return new BZip2Stream(stream, CompressionMode.Decompress, decompressConcatenated: false); case ZipCompressionMethod.LZMA: { if (FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted)) { throw new NotSupportedException("LZMA with pkware encryption."); } BinaryReader binaryReader = new BinaryReader(stream); binaryReader.ReadUInt16(); byte[] array = new byte[binaryReader.ReadUInt16()]; binaryReader.Read(array, 0, array.Length); return new LzmaStream(array, stream, (Header.CompressedSize > 0) ? (Header.CompressedSize - 4 - array.Length) : (-1), FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1) ? (-1) : Header.UncompressedSize); } case ZipCompressionMethod.PPMd: { byte[] array2 = new byte[2]; stream.ReadFully(array2); return new PpmdStream(new PpmdProperties(array2), stream, compress: false); } case ZipCompressionMethod.WinzipAes: { ExtraData extraData = Header.Extra.Where((ExtraData x) => x.Type == ExtraDataType.WinZipAes).SingleOrDefault(); if (extraData == null) { throw new InvalidFormatException("No Winzip AES extra data found."); } if (extraData.Length != 7) { throw new InvalidFormatException("Winzip data length is not 7."); } ushort uInt = DataConverter.LittleEndian.GetUInt16(extraData.DataBytes, 0); if (uInt != 1 && uInt != 2) { throw new InvalidFormatException("Unexpected vendor version number for WinZip AES metadata"); } if (DataConverter.LittleEndian.GetUInt16(extraData.DataBytes, 2) != 17729) { throw new InvalidFormatException("Unexpected vendor ID for WinZip AES metadata"); } return CreateDecompressionStream(stream, (ZipCompressionMethod)DataConverter.LittleEndian.GetUInt16(extraData.DataBytes, 5)); } default: throw new NotSupportedException("CompressionMethod: " + Header.CompressionMethod); } } protected Stream GetCryptoStream(Stream plainStream) { bool flag = FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted); if (Header.CompressedSize == 0 && flag) { throw new NotSupportedException("Cannot encrypt file with unknown size at start."); } plainStream = (((Header.CompressedSize != 0L || !FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor)) && !Header.IsZip64) ? new ReadOnlySubStream(plainStream, Header.CompressedSize) : new NonDisposingStream(plainStream)); if (flag) { switch (Header.CompressionMethod) { case ZipCompressionMethod.None: case ZipCompressionMethod.Deflate: case ZipCompressionMethod.Deflate64: case ZipCompressionMethod.BZip2: case ZipCompressionMethod.LZMA: case ZipCompressionMethod.PPMd: return new PkwareTraditionalCryptoStream(plainStream, Header.ComposeEncryptionData(plainStream), CryptoMode.Decrypt); case ZipCompressionMethod.WinzipAes: if (Header.WinzipAesEncryptionData != null) { return new WinzipAesCryptoStream(plainStream, Header.WinzipAesEncryptionData, Header.CompressedSize - 10); } return plainStream; default: throw new ArgumentOutOfRangeException(); } } return plainStream; } } internal class ZipHeaderFactory { internal const uint ENTRY_HEADER_BYTES = 67324752u; internal const uint POST_DATA_DESCRIPTOR = 134695760u; internal const uint DIRECTORY_START_HEADER_BYTES = 33639248u; internal const uint DIRECTORY_END_HEADER_BYTES = 101010256u; internal const uint DIGITAL_SIGNATURE = 84233040u; internal const uint SPLIT_ARCHIVE_HEADER_BYTES = 808471376u; internal const uint ZIP64_END_OF_CENTRAL_DIRECTORY = 101075792u; internal const uint ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR = 117853008u; protected LocalEntryHeader _lastEntryHeader; private readonly string _password; private readonly StreamingMode _mode; private readonly ArchiveEncoding _archiveEncoding; protected ZipHeaderFactory(StreamingMode mode, string password, ArchiveEncoding archiveEncoding) { _mode = mode; _password = password; _archiveEncoding = archiveEncoding; } protected ZipHeader ReadHeader(uint headerBytes, BinaryReader reader, bool zip64 = false) { switch (headerBytes) { case 67324752u: { LocalEntryHeader localEntryHeader = new LocalEntryHeader(_archiveEncoding); localEntryHeader.Read(reader); LoadHeader(localEntryHeader, reader.BaseStream); _lastEntryHeader = localEntryHeader; return localEntryHeader; } case 33639248u: { DirectoryEntryHeader directoryEntryHeader = new DirectoryEntryHeader(_archiveEncoding); directoryEntryHeader.Read(reader); return directoryEntryHeader; } case 134695760u: if (FlagUtility.HasFlag(_lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) { _lastEntryHeader.Crc = reader.ReadUInt32(); _lastEntryHeader.CompressedSize = (long)(zip64 ? reader.ReadUInt64() : reader.ReadUInt32()); _lastEntryHeader.UncompressedSize = (long)(zip64 ? reader.ReadUInt64() : reader.ReadUInt32()); } else { reader.ReadBytes(zip64 ? 20 : 12); } return null; case 84233040u: return null; case 101010256u: { DirectoryEndHeader directoryEndHeader = new DirectoryEndHeader(); directoryEndHeader.Read(reader); return directoryEndHeader; } case 808471376u: return new SplitHeader(); case 101075792u: { Zip64DirectoryEndHeader zip64DirectoryEndHeader = new Zip64DirectoryEndHeader(); zip64DirectoryEndHeader.Read(reader); return zip64DirectoryEndHeader; } case 117853008u: { Zip64DirectoryEndLocatorHeader zip64DirectoryEndLocatorHeader = new Zip64DirectoryEndLocatorHeader(); zip64DirectoryEndLocatorHeader.Read(reader); return zip64DirectoryEndLocatorHeader; } default: return null; } } internal static bool IsHeader(uint headerBytes) { switch (headerBytes) { case 33639248u: case 67324752u: case 84233040u: case 101010256u: case 101075792u: case 117853008u: case 134695760u: case 808471376u: return true; default: return false; } } private void LoadHeader(ZipFileEntry entryHeader, Stream stream) { if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.Encrypted)) { if (!entryHeader.IsDirectory && entryHeader.CompressedSize == 0L && FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) { throw new NotSupportedException("SharpCompress cannot currently read non-seekable Zip Streams with encrypted data that has been written in a non-seekable manner."); } if (_password == null) { throw new CryptographicException("No password supplied for encrypted zip."); } entryHeader.Password = _password; if (entryHeader.CompressionMethod == ZipCompressionMethod.WinzipAes) { ExtraData extraData = entryHeader.Extra.SingleOrDefault((ExtraData x) => x.Type == ExtraDataType.WinZipAes); if (extraData != null) { WinzipAesKeySize keySize = (WinzipAesKeySize)extraData.DataBytes[4]; byte[] array = new byte[WinzipAesEncryptionData.KeyLengthInBytes(keySize) / 2]; byte[] array2 = new byte[2]; stream.Read(array, 0, array.Length); stream.Read(array2, 0, 2); entryHeader.WinzipAesEncryptionData = new WinzipAesEncryptionData(keySize, array, array2, _password); entryHeader.CompressedSize -= (uint)(array.Length + 2); } } } if (!entryHeader.IsDirectory) { switch (_mode) { case StreamingMode.Seekable: entryHeader.DataStartPosition = stream.Position; stream.Position += entryHeader.CompressedSize; break; case StreamingMode.Streaming: entryHeader.PackedStream = stream; break; default: throw new InvalidFormatException("Invalid StreamingMode"); } } } } public class ZipVolume : Volume { public string Comment { get; internal set; } public ZipVolume(Stream stream, ReaderOptions readerOptions) : base(stream, readerOptions) { } } } namespace SharpCompress.Common.Zip.Headers { internal class DirectoryEndHeader : ZipHeader { public ushort VolumeNumber { get; private set; } public ushort FirstVolumeWithDirectory { get; private set; } public ushort TotalNumberOfEntriesInDisk { get; private set; } public uint DirectorySize { get; private set; } public uint DirectoryStartOffsetRelativeToDisk { get; private set; } public ushort CommentLength { get; private set; } public byte[] Comment { get; private set; } public ushort TotalNumberOfEntries { get; private set; } public bool IsZip64 { get { if (TotalNumberOfEntriesInDisk != ushort.MaxValue && DirectorySize != uint.MaxValue) { return DirectoryStartOffsetRelativeToDisk == uint.MaxValue; } return true; } } public DirectoryEndHeader() : base(ZipHeaderType.DirectoryEnd) { } internal override void Read(BinaryReader reader) { VolumeNumber = reader.ReadUInt16(); FirstVolumeWithDirectory = reader.ReadUInt16(); TotalNumberOfEntriesInDisk = reader.ReadUInt16(); TotalNumberOfEntries = reader.ReadUInt16(); DirectorySize = reader.ReadUInt32(); DirectoryStartOffsetRelativeToDisk = reader.ReadUInt32(); CommentLength = reader.ReadUInt16(); Comment = reader.ReadBytes(CommentLength); } } internal class DirectoryEntryHeader : ZipFileEntry { internal ushort Version { get; private set; } public ushort VersionNeededToExtract { get; set; } public long RelativeOffsetOfEntryHeader { get; set; } public uint ExternalFileAttributes { get; set; } public ushort InternalFileAttributes { get; set; } public ushort DiskNumberStart { get; set; } public string Comment { get; private set; } public DirectoryEntryHeader(ArchiveEncoding archiveEncoding) : base(ZipHeaderType.DirectoryEntry, archiveEncoding) { } internal override void Read(BinaryReader reader) { Version = reader.ReadUInt16(); VersionNeededToExtract = reader.ReadUInt16(); base.Flags = (HeaderFlags)reader.ReadUInt16(); base.CompressionMethod = (ZipCompressionMethod)reader.ReadUInt16(); base.LastModifiedTime = reader.ReadUInt16(); base.LastModifiedDate = reader.ReadUInt16(); base.Crc = reader.ReadUInt32(); base.CompressedSize = reader.ReadUInt32(); base.UncompressedSize = reader.ReadUInt32(); ushort count = reader.ReadUInt16(); ushort count2 = reader.ReadUInt16(); ushort count3 = reader.ReadUInt16(); DiskNumberStart = reader.ReadUInt16(); InternalFileAttributes = reader.ReadUInt16(); ExternalFileAttributes = reader.ReadUInt32(); RelativeOffsetOfEntryHeader = reader.ReadUInt32(); byte[] bytes = reader.ReadBytes(count); byte[] extra = reader.ReadBytes(count2); byte[] bytes2 = reader.ReadBytes(count3); if (base.Flags.HasFlag(HeaderFlags.Efs)) { base.Name = base.ArchiveEncoding.DecodeUTF8(bytes); Comment = base.ArchiveEncoding.DecodeUTF8(bytes2); } else { base.Name = base.ArchiveEncoding.Decode(bytes); Comment = base.ArchiveEncoding.Decode(bytes2); } LoadExtra(extra); ExtraData extraData = base.Extra.FirstOrDefault((ExtraData u) => u.Type == ExtraDataType.UnicodePathExtraField); if (extraData != null) { base.Name = ((ExtraUnicodePathExtraField)extraData).UnicodeName; } Zip64ExtendedInformationExtraField zip64ExtendedInformationExtraField = base.Extra.OfType().FirstOrDefault(); if (zip64ExtendedInformationExtraField != null) { if (base.CompressedSize == uint.MaxValue) { base.CompressedSize = zip64ExtendedInformationExtraField.CompressedSize; } if (base.UncompressedSize == uint.MaxValue) { base.UncompressedSize = zip64ExtendedInformationExtraField.UncompressedSize; } if (RelativeOffsetOfEntryHeader == uint.MaxValue) { RelativeOffsetOfEntryHeader = zip64ExtendedInformationExtraField.RelativeOffsetOfEntryHeader; } } } } [Flags] internal enum HeaderFlags : ushort { None = 0, Encrypted = 1, Bit1 = 2, Bit2 = 4, UsePostDataDescriptor = 8, EnhancedDeflate = 0x10, Efs = 0x800 } internal class IgnoreHeader : ZipHeader { public IgnoreHeader(ZipHeaderType type) : base(type) { } internal override void Read(BinaryReader reader) { } } internal class LocalEntryHeader : ZipFileEntry { internal ushort Version { get; private set; } public LocalEntryHeader(ArchiveEncoding archiveEncoding) : base(ZipHeaderType.LocalEntry, archiveEncoding) { } internal override void Read(BinaryReader reader) { Version = reader.ReadUInt16(); base.Flags = (HeaderFlags)reader.ReadUInt16(); base.CompressionMethod = (ZipCompressionMethod)reader.ReadUInt16(); base.LastModifiedTime = reader.ReadUInt16(); base.LastModifiedDate = reader.ReadUInt16(); base.Crc = reader.ReadUInt32(); base.CompressedSize = reader.ReadUInt32(); base.UncompressedSize = reader.ReadUInt32(); ushort count = reader.ReadUInt16(); ushort count2 = reader.ReadUInt16(); byte[] bytes = reader.ReadBytes(count); byte[] extra = reader.ReadBytes(count2); if (base.Flags.HasFlag(HeaderFlags.Efs)) { base.Name = base.ArchiveEncoding.DecodeUTF8(bytes); } else { base.Name = base.ArchiveEncoding.Decode(bytes); } LoadExtra(extra); ExtraData extraData = base.Extra.FirstOrDefault((ExtraData u) => u.Type == ExtraDataType.UnicodePathExtraField); if (extraData != null) { base.Name = ((ExtraUnicodePathExtraField)extraData).UnicodeName; } Zip64ExtendedInformationExtraField zip64ExtendedInformationExtraField = base.Extra.OfType().FirstOrDefault(); if (zip64ExtendedInformationExtraField != null) { if (base.CompressedSize == uint.MaxValue) { base.CompressedSize = zip64ExtendedInformationExtraField.CompressedSize; } if (base.UncompressedSize == uint.MaxValue) { base.UncompressedSize = zip64ExtendedInformationExtraField.UncompressedSize; } } } } internal enum ExtraDataType : ushort { WinZipAes = 39169, NotImplementedExtraData = ushort.MaxValue, UnicodePathExtraField = 28789, Zip64ExtendedInformationExtraField = 1 } internal class ExtraData { internal ExtraDataType Type { get; set; } internal ushort Length { get; set; } internal byte[] DataBytes { get; set; } } internal class ExtraUnicodePathExtraField : ExtraData { internal byte Version => base.DataBytes[0]; internal byte[] NameCrc32 { get { byte[] array = new byte[4]; Buffer.BlockCopy(base.DataBytes, 1, array, 0, 4); return array; } } internal string UnicodeName { get { int count = base.Length - 5; return Encoding.UTF8.GetString(base.DataBytes, 5, count); } } } internal class Zip64ExtendedInformationExtraField : ExtraData { public long UncompressedSize { get; private set; } public long CompressedSize { get; private set; } public long RelativeOffsetOfEntryHeader { get; private set; } public uint VolumeNumber { get; private set; } public Zip64ExtendedInformationExtraField(ExtraDataType type, ushort length, byte[] dataBytes) { base.Type = type; base.Length = length; base.DataBytes = dataBytes; Process(); } private void Process() { switch (base.DataBytes.Length) { case 4: VolumeNumber = DataConverter.LittleEndian.GetUInt32(base.DataBytes, 0); break; case 8: RelativeOffsetOfEntryHeader = (long)DataConverter.LittleEndian.GetUInt64(base.DataBytes, 0); break; case 12: RelativeOffsetOfEntryHeader = (long)DataConverter.LittleEndian.GetUInt64(base.DataBytes, 0); VolumeNumber = DataConverter.LittleEndian.GetUInt32(base.DataBytes, 8); break; case 16: UncompressedSize = (long)DataConverter.LittleEndian.GetUInt64(base.DataBytes, 0); CompressedSize = (long)DataConverter.LittleEndian.GetUInt64(base.DataBytes, 8); break; case 20: UncompressedSize = (long)DataConverter.LittleEndian.GetUInt64(base.DataBytes, 0); CompressedSize = (long)DataConverter.LittleEndian.GetUInt64(base.DataBytes, 8); VolumeNumber = DataConverter.LittleEndian.GetUInt32(base.DataBytes, 16); break; case 24: UncompressedSize = (long)DataConverter.LittleEndian.GetUInt64(base.DataBytes, 0); CompressedSize = (long)DataConverter.LittleEndian.GetUInt64(base.DataBytes, 8); RelativeOffsetOfEntryHeader = (long)DataConverter.LittleEndian.GetUInt64(base.DataBytes, 16); break; case 28: UncompressedSize = (long)DataConverter.LittleEndian.GetUInt64(base.DataBytes, 0); CompressedSize = (long)DataConverter.LittleEndian.GetUInt64(base.DataBytes, 8); RelativeOffsetOfEntryHeader = (long)DataConverter.LittleEndian.GetUInt64(base.DataBytes, 16); VolumeNumber = DataConverter.LittleEndian.GetUInt32(base.DataBytes, 24); break; default: throw new ArchiveException("Unexpected size of of Zip64 extended information extra field"); } } } internal static class LocalEntryHeaderExtraFactory { internal static ExtraData Create(ExtraDataType type, ushort length, byte[] extraData) { return type switch { ExtraDataType.UnicodePathExtraField => new ExtraUnicodePathExtraField { Type = type, Length = length, DataBytes = extraData }, ExtraDataType.Zip64ExtendedInformationExtraField => new Zip64ExtendedInformationExtraField(type, length, extraData), _ => new ExtraData { Type = type, Length = length, DataBytes = extraData }, }; } } internal class SplitHeader : ZipHeader { public SplitHeader() : base(ZipHeaderType.Split) { } internal override void Read(BinaryReader reader) { throw new NotImplementedException(); } } internal class Zip64DirectoryEndHeader : ZipHeader { private const int SIZE_OF_FIXED_HEADER_DATA_EXCEPT_SIGNATURE_AND_SIZE_FIELDS = 44; public long SizeOfDirectoryEndRecord { get; private set; } public ushort VersionMadeBy { get; private set; } public ushort VersionNeededToExtract { get; private set; } public uint VolumeNumber { get; private set; } public uint FirstVolumeWithDirectory { get; private set; } public long TotalNumberOfEntriesInDisk { get; private set; } public long TotalNumberOfEntries { get; private set; } public long DirectorySize { get; private set; } public long DirectoryStartOffsetRelativeToDisk { get; private set; } public byte[] DataSector { get; private set; } public Zip64DirectoryEndHeader() : base(ZipHeaderType.Zip64DirectoryEnd) { } internal override void Read(BinaryReader reader) { SizeOfDirectoryEndRecord = (long)reader.ReadUInt64(); VersionMadeBy = reader.ReadUInt16(); VersionNeededToExtract = reader.ReadUInt16(); VolumeNumber = reader.ReadUInt32(); FirstVolumeWithDirectory = reader.ReadUInt32(); TotalNumberOfEntriesInDisk = (long)reader.ReadUInt64(); TotalNumberOfEntries = (long)reader.ReadUInt64(); DirectorySize = (long)reader.ReadUInt64(); DirectoryStartOffsetRelativeToDisk = (long)reader.ReadUInt64(); DataSector = reader.ReadBytes((int)(SizeOfDirectoryEndRecord - 44)); } } internal class Zip64DirectoryEndLocatorHeader : ZipHeader { public uint FirstVolumeWithDirectory { get; private set; } public long RelativeOffsetOfTheEndOfDirectoryRecord { get; private set; } public uint TotalNumberOfVolumes { get; private set; } public Zip64DirectoryEndLocatorHeader() : base(ZipHeaderType.Zip64DirectoryEndLocator) { } internal override void Read(BinaryReader reader) { FirstVolumeWithDirectory = reader.ReadUInt32(); RelativeOffsetOfTheEndOfDirectoryRecord = (long)reader.ReadUInt64(); TotalNumberOfVolumes = reader.ReadUInt32(); } } internal abstract class ZipFileEntry : ZipHeader { internal bool IsDirectory { get { if (Name.EndsWith("/")) { return true; } if (CompressedSize == 0L && UncompressedSize == 0L) { return Name.EndsWith("\\"); } return false; } } internal Stream PackedStream { get; set; } internal ArchiveEncoding ArchiveEncoding { get; } internal string Name { get; set; } internal HeaderFlags Flags { get; set; } internal ZipCompressionMethod CompressionMethod { get; set; } internal long CompressedSize { get; set; } internal long? DataStartPosition { get; set; } internal long UncompressedSize { get; set; } internal List Extra { get; set; } public string Password { get; set; } internal WinzipAesEncryptionData WinzipAesEncryptionData { get; set; } internal ushort LastModifiedDate { get; set; } internal ushort LastModifiedTime { get; set; } internal uint Crc { get; set; } internal ZipFilePart Part { get; set; } internal bool IsZip64 => CompressedSize == uint.MaxValue; protected ZipFileEntry(ZipHeaderType type, ArchiveEncoding archiveEncoding) : base(type) { Extra = new List(); ArchiveEncoding = archiveEncoding; } internal PkwareTraditionalEncryptionData ComposeEncryptionData(Stream archiveStream) { if (archiveStream == null) { throw new ArgumentNullException("archiveStream"); } byte[] array = new byte[12]; archiveStream.ReadFully(array); return PkwareTraditionalEncryptionData.ForRead(Password, this, array); } protected void LoadExtra(byte[] extra) { ushort uInt; for (int i = 0; i < extra.Length - 4; i += uInt + 4) { ExtraDataType extraDataType = (ExtraDataType)DataConverter.LittleEndian.GetUInt16(extra, i); if (!Enum.IsDefined(typeof(ExtraDataType), extraDataType)) { extraDataType = ExtraDataType.NotImplementedExtraData; } uInt = DataConverter.LittleEndian.GetUInt16(extra, i + 2); if (uInt > extra.Length) { break; } byte[] array = new byte[uInt]; Buffer.BlockCopy(extra, i + 4, array, 0, uInt); Extra.Add(LocalEntryHeaderExtraFactory.Create(extraDataType, uInt, array)); } } } internal abstract class ZipHeader { internal ZipHeaderType ZipHeaderType { get; } internal bool HasData { get; set; } protected ZipHeader(ZipHeaderType type) { ZipHeaderType = type; HasData = true; } internal abstract void Read(BinaryReader reader); } internal enum ZipHeaderType { Ignore, LocalEntry, DirectoryEntry, DirectoryEnd, Split, Zip64DirectoryEnd, Zip64DirectoryEndLocator } } namespace SharpCompress.Common.Tar { public class TarEntry : Entry { private readonly TarFilePart _filePart; public override CompressionType CompressionType { get; } public override long Crc => 0L; public override string Key => _filePart.Header.Name; public override string LinkTarget => _filePart.Header.LinkName; public override long CompressedSize => _filePart.Header.Size; public override long Size => _filePart.Header.Size; public override DateTime? LastModifiedTime => _filePart.Header.LastModifiedTime; public override DateTime? CreatedTime => null; public override DateTime? LastAccessedTime => null; public override DateTime? ArchivedTime => null; public override bool IsEncrypted => false; public override bool IsDirectory => _filePart.Header.EntryType == EntryType.Directory; public override bool IsSplitAfter => false; internal override IEnumerable Parts => ((FilePart)_filePart).AsEnumerable(); internal TarEntry(TarFilePart filePart, CompressionType type) { _filePart = filePart; CompressionType = type; } internal static IEnumerable GetEntries(StreamingMode mode, Stream stream, CompressionType compressionType, ArchiveEncoding archiveEncoding) { foreach (TarHeader item in TarHeaderFactory.ReadHeader(mode, stream, archiveEncoding)) { if (item != null) { if (mode == StreamingMode.Seekable) { yield return new TarEntry(new TarFilePart(item, stream), compressionType); } else { yield return new TarEntry(new TarFilePart(item, null), compressionType); } } } } } internal class TarFilePart : FilePart { private readonly Stream _seekableStream; internal TarHeader Header { get; } internal override string FilePartName => Header.Name; internal TarFilePart(TarHeader header, Stream seekableStream) : base(header.ArchiveEncoding) { _seekableStream = seekableStream; Header = header; } internal override Stream GetCompressedStream() { if (_seekableStream != null) { _seekableStream.Position = Header.DataStartPosition.Value; return new ReadOnlySubStream(_seekableStream, Header.Size); } return Header.PackedStream; } internal override Stream GetRawStream() { return null; } } internal static class TarHeaderFactory { internal static IEnumerable ReadHeader(StreamingMode mode, Stream stream, ArchiveEncoding archiveEncoding) { while (true) { TarHeader tarHeader; try { BinaryReader binaryReader = new BinaryReader(stream); tarHeader = new TarHeader(archiveEncoding); if (!tarHeader.Read(binaryReader)) { break; } switch (mode) { case StreamingMode.Seekable: tarHeader.DataStartPosition = binaryReader.BaseStream.Position; binaryReader.BaseStream.Position += PadTo512(tarHeader.Size); break; case StreamingMode.Streaming: tarHeader.PackedStream = new TarReadOnlySubStream(stream, tarHeader.Size); break; default: throw new InvalidFormatException("Invalid StreamingMode"); } } catch { tarHeader = null; } yield return tarHeader; } } private static long PadTo512(long size) { int num = (int)(size % 512); if (num == 0) { return size; } return 512 - num + size; } } internal class TarReadOnlySubStream : NonDisposingStream { private bool _isDisposed; private long _amountRead; private long BytesLeftToRead { get; set; } public override bool CanRead => true; public override bool CanSeek => false; public override bool CanWrite => false; public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } public TarReadOnlySubStream(Stream stream, long bytesToRead) : base(stream) { BytesLeftToRead = bytesToRead; } protected override void Dispose(bool disposing) { if (_isDisposed) { return; } _isDisposed = true; if (disposing) { long num = _amountRead % 512; if (num == 0L) { return; } num = 512 - num; if (num == 0L) { return; } byte[] buffer = new byte[num]; base.Stream.ReadFully(buffer); } base.Dispose(disposing); } public override void Flush() { throw new NotSupportedException(); } public override int Read(byte[] buffer, int offset, int count) { if (BytesLeftToRead < count) { count = (int)BytesLeftToRead; } int num = base.Stream.Read(buffer, offset, count); if (num > 0) { BytesLeftToRead -= num; _amountRead += num; } return num; } public override int ReadByte() { if (BytesLeftToRead <= 0) { return -1; } int num = base.Stream.ReadByte(); if (num != -1) { long bytesLeftToRead = BytesLeftToRead - 1; BytesLeftToRead = bytesLeftToRead; _amountRead++; } return num; } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } } public class TarVolume : Volume { public TarVolume(Stream stream, ReaderOptions readerOptions) : base(stream, readerOptions) { } } } namespace SharpCompress.Common.Tar.Headers { internal enum EntryType : byte { File = 0, OldFile = 48, HardLink = 49, SymLink = 50, CharDevice = 51, BlockDevice = 52, Directory = 53, Fifo = 54, LongLink = 75, LongName = 76, SparseFile = 83, VolumeHeader = 86, GlobalExtendedHeader = 103 } internal class TarHeader { internal static readonly DateTime EPOCH = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); internal const int BLOCK_SIZE = 512; internal string Name { get; set; } internal string LinkName { get; set; } internal long Size { get; set; } internal DateTime LastModifiedTime { get; set; } internal EntryType EntryType { get; set; } internal Stream PackedStream { get; set; } internal ArchiveEncoding ArchiveEncoding { get; } public long? DataStartPosition { get; set; } public string Magic { get; set; } public TarHeader(ArchiveEncoding archiveEncoding) { ArchiveEncoding = archiveEncoding; } internal void Write(Stream output) { byte[] array = new byte[512]; WriteOctalBytes(511L, array, 100, 8); WriteOctalBytes(0L, array, 108, 8); WriteOctalBytes(0L, array, 116, 8); int byteCount = ArchiveEncoding.GetEncoding().GetByteCount(Name); if (byteCount > 100) { WriteStringBytes("././@LongLink", array, 0, 100); array[156] = 76; WriteOctalBytes(byteCount + 1, array, 124, 12); } else { WriteStringBytes(ArchiveEncoding.Encode(Name), array, 0, 100); WriteOctalBytes(Size, array, 124, 12); WriteOctalBytes((long)(LastModifiedTime.ToUniversalTime() - EPOCH).TotalSeconds, array, 136, 12); array[156] = (byte)EntryType; if (Size >= 8589934591L) { byte[] bytes = DataConverter.BigEndian.GetBytes(Size); byte[] array2 = new byte[12]; bytes.CopyTo(array2, 12 - bytes.Length); array2[0] |= 128; array2.CopyTo(array, 124); } } WriteOctalBytes(RecalculateChecksum(array), array, 148, 8); output.Write(array, 0, array.Length); if (byteCount > 100) { WriteLongFilenameHeader(output); Name = ArchiveEncoding.Decode(ArchiveEncoding.Encode(Name), 0, 100 - ArchiveEncoding.GetEncoding().GetMaxByteCount(1)); Write(output); } } private void WriteLongFilenameHeader(Stream output) { byte[] array = ArchiveEncoding.Encode(Name); output.Write(array, 0, array.Length); int num = 512 - array.Length % 512; if (num == 0) { num = 512; } output.Write(new byte[num], 0, num); } internal bool Read(BinaryReader reader) { byte[] array = ReadBlock(reader); if (array.Length == 0) { return false; } if (ReadEntryType(array) == EntryType.SymLink) { LinkName = ArchiveEncoding.Decode(array, 157, 100).TrimNulls(); } if (ReadEntryType(array) == EntryType.LongName) { Name = ReadLongName(reader, array); array = ReadBlock(reader); } else { Name = ArchiveEncoding.Decode(array, 0, 100).TrimNulls(); } EntryType = ReadEntryType(array); Size = ReadSize(array); long num = ReadAsciiInt64Base8(array, 136, 11); DateTime ePOCH = EPOCH; LastModifiedTime = ePOCH.AddSeconds(num).ToLocalTime(); Magic = ArchiveEncoding.Decode(array, 257, 6).TrimNulls(); if (!string.IsNullOrEmpty(Magic) && "ustar".Equals(Magic)) { string source = ArchiveEncoding.Decode(array, 345, 157); source = source.TrimNulls(); if (!string.IsNullOrEmpty(source)) { Name = source + "/" + Name; } } if (EntryType != EntryType.LongName && Name.Length == 0) { return false; } return true; } private string ReadLongName(BinaryReader reader, byte[] buffer) { int num = (int)ReadSize(buffer); byte[] array = reader.ReadBytes(num); int num2 = 512 - num % 512; if (num2 < 512) { reader.ReadBytes(num2); } return ArchiveEncoding.Decode(array, 0, array.Length).TrimNulls(); } private static EntryType ReadEntryType(byte[] buffer) { return (EntryType)buffer[156]; } private long ReadSize(byte[] buffer) { if ((buffer[124] & 0x80) == 128) { return DataConverter.BigEndian.GetInt64(buffer, 128); } return ReadAsciiInt64Base8(buffer, 124, 11); } private static byte[] ReadBlock(BinaryReader reader) { byte[] array = reader.ReadBytes(512); if (array.Length != 0 && array.Length < 512) { throw new InvalidOperationException("Buffer is invalid size"); } return array; } private static void WriteStringBytes(byte[] name, byte[] buffer, int offset, int length) { int i = Math.Min(length, name.Length); Buffer.BlockCopy(name, 0, buffer, offset, i); for (; i < length; i++) { buffer[offset + i] = 0; } } private static void WriteStringBytes(string name, byte[] buffer, int offset, int length) { int i; for (i = 0; i < length && i < name.Length; i++) { buffer[offset + i] = (byte)name[i]; } for (; i < length; i++) { buffer[offset + i] = 0; } } private static void WriteOctalBytes(long value, byte[] buffer, int offset, int length) { string text = Convert.ToString(value, 8); int num = length - text.Length - 1; for (int i = 0; i < num; i++) { buffer[offset + i] = 32; } for (int j = 0; j < text.Length; j++) { buffer[offset + j + num] = (byte)text[j]; } } private static int ReadAsciiInt32Base8(byte[] buffer, int offset, int count) { string value = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls(); if (string.IsNullOrEmpty(value)) { return 0; } return Convert.ToInt32(value, 8); } private static long ReadAsciiInt64Base8(byte[] buffer, int offset, int count) { string value = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls(); if (string.IsNullOrEmpty(value)) { return 0L; } return Convert.ToInt64(value, 8); } private static long ReadAsciiInt64(byte[] buffer, int offset, int count) { string value = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls(); if (string.IsNullOrEmpty(value)) { return 0L; } return Convert.ToInt64(value); } internal static int RecalculateChecksum(byte[] buf) { Encoding.UTF8.GetBytes(" ").CopyTo(buf, 148); int num = 0; foreach (byte b in buf) { num += b; } return num; } internal static int RecalculateAltChecksum(byte[] buf) { Encoding.UTF8.GetBytes(" ").CopyTo(buf, 148); int num = 0; foreach (byte b in buf) { num = (((b & 0x80) != 128) ? (num + b) : (num - (b ^ 0x80))); } return num; } } } namespace SharpCompress.Common.SevenZip { internal class ArchiveDatabase { internal byte _majorVersion; internal byte _minorVersion; internal long _startPositionAfterHeader; internal long _dataStartPosition; internal List _packSizes = new List(); internal List _packCrCs = new List(); internal List _folders = new List(); internal List _numUnpackStreamsVector; internal List _files = new List(); internal List _packStreamStartPositions = new List(); internal List _folderStartFileIndex = new List(); internal List _fileIndexToFolderIndexMap = new List(); internal IPasswordProvider PasswordProvider { get; } public ArchiveDatabase(IPasswordProvider passwordProvider) { PasswordProvider = passwordProvider; } internal void Clear() { _packSizes.Clear(); _packCrCs.Clear(); _folders.Clear(); _numUnpackStreamsVector = null; _files.Clear(); _packStreamStartPositions.Clear(); _folderStartFileIndex.Clear(); _fileIndexToFolderIndexMap.Clear(); } internal bool IsEmpty() { if (_packSizes.Count == 0 && _packCrCs.Count == 0 && _folders.Count == 0 && _numUnpackStreamsVector.Count == 0) { return _files.Count == 0; } return false; } private void FillStartPos() { _packStreamStartPositions.Clear(); long num = 0L; for (int i = 0; i < _packSizes.Count; i++) { _packStreamStartPositions.Add(num); num += _packSizes[i]; } } private void FillFolderStartFileIndex() { _folderStartFileIndex.Clear(); _fileIndexToFolderIndexMap.Clear(); int num = 0; int num2 = 0; for (int i = 0; i < _files.Count; i++) { bool flag = !_files[i].HasStream; if (flag && num2 == 0) { _fileIndexToFolderIndexMap.Add(-1); continue; } if (num2 == 0) { while (true) { if (num >= _folders.Count) { throw new InvalidOperationException(); } _folderStartFileIndex.Add(i); if (_numUnpackStreamsVector[num] != 0) { break; } num++; } } _fileIndexToFolderIndexMap.Add(num); if (!flag) { num2++; if (num2 >= _numUnpackStreamsVector[num]) { num++; num2 = 0; } } } } public void Fill() { FillStartPos(); FillFolderStartFileIndex(); } internal long GetFolderStreamPos(CFolder folder, int indexInFolder) { int index = folder._firstPackStreamId + indexInFolder; return _dataStartPosition + _packStreamStartPositions[index]; } internal long GetFolderFullPackSize(int folderIndex) { int firstPackStreamId = _folders[folderIndex]._firstPackStreamId; CFolder cFolder = _folders[folderIndex]; long num = 0L; for (int i = 0; i < cFolder._packStreams.Count; i++) { num += _packSizes[firstPackStreamId + i]; } return num; } internal Stream GetFolderStream(Stream stream, CFolder folder, IPasswordProvider pw) { int firstPackStreamId = folder._firstPackStreamId; long folderStreamPos = GetFolderStreamPos(folder, 0); List list = new List(); for (int i = 0; i < folder._packStreams.Count; i++) { list.Add(_packSizes[firstPackStreamId + i]); } return DecoderStreamHelper.CreateDecoderStream(stream, folderStreamPos, list.ToArray(), folder, pw); } private long GetFolderPackStreamSize(int folderIndex, int streamIndex) { return _packSizes[_folders[folderIndex]._firstPackStreamId + streamIndex]; } private long GetFilePackSize(int fileIndex) { int num = _fileIndexToFolderIndexMap[fileIndex]; if (num != -1 && _folderStartFileIndex[num] == fileIndex) { return GetFolderFullPackSize(num); } return 0L; } } internal class ArchiveReader { internal class CExtractFolderInfo { internal int _fileIndex; internal int _folderIndex; internal List _extractStatuses = new List(); internal CExtractFolderInfo(int fileIndex, int folderIndex) { _fileIndex = fileIndex; _folderIndex = folderIndex; if (fileIndex != -1) { _extractStatuses.Add(item: true); } } } private class FolderUnpackStream : Stream { private readonly ArchiveDatabase _db; private readonly int _startIndex; private readonly List _extractStatuses; private Stream _stream; private long _rem; private int _currentIndex; public override bool CanRead => true; public override bool CanSeek => false; public override bool CanWrite => false; public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } public FolderUnpackStream(ArchiveDatabase db, int p, int startIndex, List list) { _db = db; _startIndex = startIndex; _extractStatuses = list; } public override void Flush() { throw new NotSupportedException(); } public override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } private void ProcessEmptyFiles() { while (_currentIndex < _extractStatuses.Count && _db._files[_startIndex + _currentIndex].Size == 0L) { OpenFile(); _stream.Dispose(); _stream = null; _currentIndex++; } } private void OpenFile() { int index = _startIndex + _currentIndex; if (_db._files[index].CrcDefined) { _stream = new CrcCheckStream(_db._files[index].Crc.Value); } else { _stream = new MemoryStream(); } _rem = _db._files[index].Size; } public override void Write(byte[] buffer, int offset, int count) { while (count != 0) { if (_stream != null) { int num = count; if (num > _rem) { num = (int)_rem; } _stream.Write(buffer, offset, num); count -= num; _rem -= num; offset += num; if (_rem == 0L) { _stream.Dispose(); _stream = null; _currentIndex++; ProcessEmptyFiles(); } } else { ProcessEmptyFiles(); if (_currentIndex == _extractStatuses.Count) { Debugger.Break(); throw new NotSupportedException(); } OpenFile(); } } } } internal Stream _stream; internal Stack _readerStack = new Stack(); internal DataReader _currentReader; internal long _streamOrigin; internal long _streamEnding; internal byte[] _header; private readonly Dictionary _cachedStreams = new Dictionary(); internal void AddByteStream(byte[] buffer, int offset, int length) { _readerStack.Push(_currentReader); _currentReader = new DataReader(buffer, offset, length); } internal void DeleteByteStream() { _currentReader = _readerStack.Pop(); } internal byte ReadByte() { return _currentReader.ReadByte(); } private void ReadBytes(byte[] buffer, int offset, int length) { _currentReader.ReadBytes(buffer, offset, length); } private ulong ReadNumber() { return _currentReader.ReadNumber(); } internal int ReadNum() { return _currentReader.ReadNum(); } private uint ReadUInt32() { return _currentReader.ReadUInt32(); } private ulong ReadUInt64() { return _currentReader.ReadUInt64(); } private SharpCompress.Compressors.LZMA.Utilites.BlockType? ReadId() { ulong num = _currentReader.ReadNumber(); if (num > 25) { return null; } return (SharpCompress.Compressors.LZMA.Utilites.BlockType)num; } private void SkipData(long size) { _currentReader.SkipData(size); } private void SkipData() { _currentReader.SkipData(); } private void WaitAttribute(SharpCompress.Compressors.LZMA.Utilites.BlockType attribute) { while (true) { SharpCompress.Compressors.LZMA.Utilites.BlockType? blockType = ReadId(); if (blockType == attribute) { return; } if (blockType == SharpCompress.Compressors.LZMA.Utilites.BlockType.End) { break; } SkipData(); } throw new InvalidOperationException(); } private void ReadArchiveProperties() { while (ReadId() != SharpCompress.Compressors.LZMA.Utilites.BlockType.End) { SkipData(); } } private BitVector ReadBitVector(int length) { BitVector bitVector = new BitVector(length); byte b = 0; byte b2 = 0; for (int i = 0; i < length; i++) { if (b2 == 0) { b = ReadByte(); b2 = 128; } if ((b & b2) != 0) { bitVector.SetBit(i); } b2 >>= 1; } return bitVector; } private BitVector ReadOptionalBitVector(int length) { if (ReadByte() != 0) { return new BitVector(length, initValue: true); } return ReadBitVector(length); } private void ReadNumberVector(List dataVector, int numFiles, Action action) { BitVector bitVector = ReadOptionalBitVector(numFiles); using CStreamSwitch cStreamSwitch = default(CStreamSwitch); cStreamSwitch.Set(this, dataVector); for (int i = 0; i < numFiles; i++) { if (bitVector[i]) { action(i, checked((long)ReadUInt64())); } else { action(i, null); } } } private DateTime TranslateTime(long time) { return DateTime.FromFileTimeUtc(time).ToLocalTime(); } private DateTime? TranslateTime(long? time) { if (time.HasValue && time.Value >= 0 && time.Value <= 2650467743999999999L) { return TranslateTime(time.Value); } return null; } private void ReadDateTimeVector(List dataVector, int numFiles, Action action) { ReadNumberVector(dataVector, numFiles, delegate(int index, long? value) { action(index, TranslateTime(value)); }); } private void ReadAttributeVector(List dataVector, int numFiles, Action action) { BitVector bitVector = ReadOptionalBitVector(numFiles); using CStreamSwitch cStreamSwitch = default(CStreamSwitch); cStreamSwitch.Set(this, dataVector); for (int i = 0; i < numFiles; i++) { if (bitVector[i]) { action(i, ReadUInt32()); } else { action(i, null); } } } private void GetNextFolderItem(CFolder folder) { int num = ReadNum(); folder._coders = new List(num); int num2 = 0; int num3 = 0; for (int i = 0; i < num; i++) { CCoderInfo cCoderInfo = new CCoderInfo(); folder._coders.Add(cCoderInfo); byte b = ReadByte(); int num4 = b & 0xF; byte[] array = new byte[num4]; ReadBytes(array, 0, num4); if (num4 > 8) { throw new NotSupportedException(); } ulong num5 = 0uL; for (int j = 0; j < num4; j++) { num5 |= (ulong)array[num4 - 1 - j] << 8 * j; } cCoderInfo._methodId = new CMethodId(num5); if ((b & 0x10) != 0) { cCoderInfo._numInStreams = ReadNum(); cCoderInfo._numOutStreams = ReadNum(); } else { cCoderInfo._numInStreams = 1; cCoderInfo._numOutStreams = 1; } if ((b & 0x20) != 0) { int num6 = ReadNum(); cCoderInfo._props = new byte[num6]; ReadBytes(cCoderInfo._props, 0, num6); } if ((b & 0x80) != 0) { throw new NotSupportedException(); } num2 += cCoderInfo._numInStreams; num3 += cCoderInfo._numOutStreams; } int num7 = num3 - 1; folder._bindPairs = new List(num7); for (int k = 0; k < num7; k++) { CBindPair cBindPair = new CBindPair(); cBindPair._inIndex = ReadNum(); cBindPair._outIndex = ReadNum(); folder._bindPairs.Add(cBindPair); } if (num2 < num7) { throw new NotSupportedException(); } int num8 = num2 - num7; if (num8 == 1) { for (int l = 0; l < num2; l++) { if (folder.FindBindPairForInStream(l) < 0) { folder._packStreams.Add(l); break; } } if (folder._packStreams.Count != 1) { throw new NotSupportedException(); } } else { for (int m = 0; m < num8; m++) { int item = ReadNum(); folder._packStreams.Add(item); } } } private List ReadHashDigests(int count) { BitVector bitVector = ReadOptionalBitVector(count); List list = new List(count); for (int i = 0; i < count; i++) { if (bitVector[i]) { uint value = ReadUInt32(); list.Add(value); } else { list.Add(null); } } return list; } private void ReadPackInfo(out long dataOffset, out List packSizes, out List packCrCs) { packCrCs = null; dataOffset = checked((long)ReadNumber()); int num = ReadNum(); WaitAttribute(SharpCompress.Compressors.LZMA.Utilites.BlockType.Size); packSizes = new List(num); for (int i = 0; i < num; i++) { long item = checked((long)ReadNumber()); packSizes.Add(item); } while (true) { SharpCompress.Compressors.LZMA.Utilites.BlockType? blockType = ReadId(); if (blockType == SharpCompress.Compressors.LZMA.Utilites.BlockType.End) { break; } if (blockType == SharpCompress.Compressors.LZMA.Utilites.BlockType.Crc) { packCrCs = ReadHashDigests(num); } else { SkipData(); } } if (packCrCs == null) { packCrCs = new List(num); for (int j = 0; j < num; j++) { packCrCs.Add(null); } } } private void ReadUnpackInfo(List dataVector, out List folders) { WaitAttribute(SharpCompress.Compressors.LZMA.Utilites.BlockType.Folder); int num = ReadNum(); using (CStreamSwitch cStreamSwitch = default(CStreamSwitch)) { cStreamSwitch.Set(this, dataVector); folders = new List(num); int num2 = 0; for (int i = 0; i < num; i++) { CFolder cFolder = new CFolder { _firstPackStreamId = num2 }; folders.Add(cFolder); GetNextFolderItem(cFolder); num2 += cFolder._packStreams.Count; } } WaitAttribute(SharpCompress.Compressors.LZMA.Utilites.BlockType.CodersUnpackSize); for (int j = 0; j < num; j++) { CFolder cFolder2 = folders[j]; int numOutStreams = cFolder2.GetNumOutStreams(); for (int k = 0; k < numOutStreams; k++) { long item = checked((long)ReadNumber()); cFolder2._unpackSizes.Add(item); } } while (true) { SharpCompress.Compressors.LZMA.Utilites.BlockType? blockType = ReadId(); if (blockType == SharpCompress.Compressors.LZMA.Utilites.BlockType.End) { break; } if (blockType == SharpCompress.Compressors.LZMA.Utilites.BlockType.Crc) { List list = ReadHashDigests(num); for (int l = 0; l < num; l++) { folders[l]._unpackCrc = list[l]; } } else { SkipData(); } } } private void ReadSubStreamsInfo(List folders, out List numUnpackStreamsInFolders, out List unpackSizes, out List digests) { numUnpackStreamsInFolders = null; SharpCompress.Compressors.LZMA.Utilites.BlockType? blockType; while (true) { blockType = ReadId(); if (blockType == SharpCompress.Compressors.LZMA.Utilites.BlockType.NumUnpackStream) { numUnpackStreamsInFolders = new List(folders.Count); for (int i = 0; i < folders.Count; i++) { int item = ReadNum(); numUnpackStreamsInFolders.Add(item); } } else { if (blockType == SharpCompress.Compressors.LZMA.Utilites.BlockType.Crc || blockType == SharpCompress.Compressors.LZMA.Utilites.BlockType.Size || blockType == SharpCompress.Compressors.LZMA.Utilites.BlockType.End) { break; } SkipData(); } } if (numUnpackStreamsInFolders == null) { numUnpackStreamsInFolders = new List(folders.Count); for (int j = 0; j < folders.Count; j++) { numUnpackStreamsInFolders.Add(1); } } unpackSizes = new List(folders.Count); for (int k = 0; k < numUnpackStreamsInFolders.Count; k++) { int num = numUnpackStreamsInFolders[k]; if (num == 0) { continue; } long num2 = 0L; for (int l = 1; l < num; l++) { if (blockType == SharpCompress.Compressors.LZMA.Utilites.BlockType.Size) { long num3 = checked((long)ReadNumber()); unpackSizes.Add(num3); num2 += num3; } } unpackSizes.Add(folders[k].GetUnpackSize() - num2); } if (blockType == SharpCompress.Compressors.LZMA.Utilites.BlockType.Size) { blockType = ReadId(); } int num4 = 0; int num5 = 0; for (int m = 0; m < folders.Count; m++) { int num6 = numUnpackStreamsInFolders[m]; if (num6 != 1 || !folders[m].UnpackCrcDefined) { num4 += num6; } num5 += num6; } digests = null; while (true) { if (blockType == SharpCompress.Compressors.LZMA.Utilites.BlockType.Crc) { digests = new List(num5); List list = ReadHashDigests(num4); int num7 = 0; for (int n = 0; n < folders.Count; n++) { int num8 = numUnpackStreamsInFolders[n]; CFolder cFolder = folders[n]; if (num8 == 1 && cFolder.UnpackCrcDefined) { digests.Add(cFolder._unpackCrc.Value); continue; } int num9 = 0; while (num9 < num8) { digests.Add(list[num7]); num9++; num7++; } } if (num7 != num4 || num5 != digests.Count) { Debugger.Break(); } } else { if (blockType == SharpCompress.Compressors.LZMA.Utilites.BlockType.End) { break; } SkipData(); } blockType = ReadId(); } if (digests == null) { digests = new List(num5); for (int num10 = 0; num10 < num5; num10++) { digests.Add(null); } } } private void ReadStreamsInfo(List dataVector, out long dataOffset, out List packSizes, out List packCrCs, out List folders, out List numUnpackStreamsInFolders, out List unpackSizes, out List digests) { dataOffset = long.MinValue; packSizes = null; packCrCs = null; folders = null; numUnpackStreamsInFolders = null; unpackSizes = null; digests = null; while (true) { switch (ReadId()) { case SharpCompress.Compressors.LZMA.Utilites.BlockType.End: return; case SharpCompress.Compressors.LZMA.Utilites.BlockType.PackInfo: ReadPackInfo(out dataOffset, out packSizes, out packCrCs); break; case SharpCompress.Compressors.LZMA.Utilites.BlockType.UnpackInfo: ReadUnpackInfo(dataVector, out folders); break; case SharpCompress.Compressors.LZMA.Utilites.BlockType.SubStreamsInfo: ReadSubStreamsInfo(folders, out numUnpackStreamsInFolders, out unpackSizes, out digests); break; default: throw new InvalidOperationException(); } } } private List ReadAndDecodePackedStreams(long baseOffset, IPasswordProvider pass) { ReadStreamsInfo(null, out var dataOffset, out var packSizes, out var _, out var folders, out var _, out var _, out var _); dataOffset += baseOffset; List list = new List(folders.Count); int num = 0; foreach (CFolder item in folders) { long startPos = dataOffset; long[] array = new long[item._packStreams.Count]; for (int i = 0; i < array.Length; i++) { dataOffset += (array[i] = packSizes[num + i]); } Stream stream = DecoderStreamHelper.CreateDecoderStream(_stream, startPos, array, item, pass); int num2 = checked((int)item.GetUnpackSize()); byte[] array2 = new byte[num2]; stream.ReadExact(array2, 0, array2.Length); if (stream.ReadByte() >= 0) { throw new InvalidOperationException("Decoded stream is longer than expected."); } list.Add(array2); if (item.UnpackCrcDefined && Crc.Finish(Crc.Update(uint.MaxValue, array2, 0, num2)) != item._unpackCrc) { throw new InvalidOperationException("Decoded stream does not match expected CRC."); } } return list; } private void ReadHeader(ArchiveDatabase db, IPasswordProvider getTextPassword) { SharpCompress.Compressors.LZMA.Utilites.BlockType? blockType = ReadId(); if (blockType == SharpCompress.Compressors.LZMA.Utilites.BlockType.ArchiveProperties) { ReadArchiveProperties(); blockType = ReadId(); } List dataVector = null; if (blockType == SharpCompress.Compressors.LZMA.Utilites.BlockType.AdditionalStreamsInfo) { dataVector = ReadAndDecodePackedStreams(db._startPositionAfterHeader, getTextPassword); blockType = ReadId(); } List unpackSizes; List digests; if (blockType == SharpCompress.Compressors.LZMA.Utilites.BlockType.MainStreamsInfo) { ReadStreamsInfo(dataVector, out db._dataStartPosition, out db._packSizes, out db._packCrCs, out db._folders, out db._numUnpackStreamsVector, out unpackSizes, out digests); db._dataStartPosition += db._startPositionAfterHeader; blockType = ReadId(); } else { unpackSizes = new List(db._folders.Count); digests = new List(db._folders.Count); db._numUnpackStreamsVector = new List(db._folders.Count); for (int i = 0; i < db._folders.Count; i++) { CFolder cFolder = db._folders[i]; unpackSizes.Add(cFolder.GetUnpackSize()); digests.Add(cFolder._unpackCrc); db._numUnpackStreamsVector.Add(1); } } db._files.Clear(); if (blockType == SharpCompress.Compressors.LZMA.Utilites.BlockType.End) { return; } if (blockType != SharpCompress.Compressors.LZMA.Utilites.BlockType.FilesInfo) { throw new InvalidOperationException(); } int num = ReadNum(); db._files = new List(num); for (int j = 0; j < num; j++) { db._files.Add(new CFileItem()); } BitVector bitVector = new BitVector(num); BitVector bitVector2 = null; BitVector bitVector3 = null; int num2 = 0; while (true) { blockType = ReadId(); if (blockType == SharpCompress.Compressors.LZMA.Utilites.BlockType.End) { break; } long num3 = checked((long)ReadNumber()); int offset = _currentReader.Offset; switch (blockType) { case SharpCompress.Compressors.LZMA.Utilites.BlockType.Name: { using (CStreamSwitch cStreamSwitch = default(CStreamSwitch)) { cStreamSwitch.Set(this, dataVector); for (int num5 = 0; num5 < db._files.Count; num5++) { db._files[num5].Name = _currentReader.ReadString(); } } break; } case SharpCompress.Compressors.LZMA.Utilites.BlockType.WinAttributes: ReadAttributeVector(dataVector, num, delegate(int index, uint? attr) { if (attr.HasValue && attr.Value >> 16 != 0) { attr = attr.Value & 0x7FFF; } db._files[index].Attrib = attr; }); break; case SharpCompress.Compressors.LZMA.Utilites.BlockType.EmptyStream: { bitVector = ReadBitVector(num); for (int num6 = 0; num6 < bitVector.Length; num6++) { if (bitVector[num6]) { num2++; } } bitVector2 = new BitVector(num2); bitVector3 = new BitVector(num2); break; } case SharpCompress.Compressors.LZMA.Utilites.BlockType.EmptyFile: bitVector2 = ReadBitVector(num2); break; case SharpCompress.Compressors.LZMA.Utilites.BlockType.Anti: bitVector3 = ReadBitVector(num2); break; case SharpCompress.Compressors.LZMA.Utilites.BlockType.StartPos: ReadNumberVector(dataVector, num, delegate(int index, long? startPos) { db._files[index].StartPos = startPos; }); break; case SharpCompress.Compressors.LZMA.Utilites.BlockType.CTime: ReadDateTimeVector(dataVector, num, delegate(int index, DateTime? time) { db._files[index].CTime = time; }); break; case SharpCompress.Compressors.LZMA.Utilites.BlockType.ATime: ReadDateTimeVector(dataVector, num, delegate(int index, DateTime? time) { db._files[index].ATime = time; }); break; case SharpCompress.Compressors.LZMA.Utilites.BlockType.MTime: ReadDateTimeVector(dataVector, num, delegate(int index, DateTime? time) { db._files[index].MTime = time; }); break; case SharpCompress.Compressors.LZMA.Utilites.BlockType.Dummy: { for (long num4 = 0L; num4 < num3; num4++) { if (ReadByte() != 0) { throw new InvalidOperationException(); } } break; } default: SkipData(num3); break; } if ((db._majorVersion > 0 || db._minorVersion > 2) && _currentReader.Offset - offset != num3) { throw new InvalidOperationException(); } } int num7 = 0; int num8 = 0; for (int num9 = 0; num9 < num; num9++) { CFileItem cFileItem = db._files[num9]; cFileItem.HasStream = !bitVector[num9]; if (cFileItem.HasStream) { cFileItem.IsDir = false; cFileItem.IsAnti = false; cFileItem.Size = unpackSizes[num8]; cFileItem.Crc = digests[num8]; num8++; } else { cFileItem.IsDir = !bitVector2[num7]; cFileItem.IsAnti = bitVector3[num7]; num7++; cFileItem.Size = 0L; cFileItem.Crc = null; } } } public void Open(Stream stream) { Close(); _streamOrigin = stream.Position; _streamEnding = stream.Length; _header = new byte[32]; int num; for (int i = 0; i < 32; i += num) { num = stream.Read(_header, i, 32 - i); if (num == 0) { throw new EndOfStreamException(); } } _stream = stream; } public void Close() { if (_stream != null) { _stream.Dispose(); } foreach (Stream value in _cachedStreams.Values) { value.Dispose(); } _cachedStreams.Clear(); } public ArchiveDatabase ReadDatabase(IPasswordProvider pass) { ArchiveDatabase archiveDatabase = new ArchiveDatabase(pass); archiveDatabase.Clear(); archiveDatabase._majorVersion = _header[6]; archiveDatabase._minorVersion = _header[7]; if (archiveDatabase._majorVersion != 0) { throw new InvalidOperationException(); } uint num = DataReader.Get32(_header, 8); long num2 = (long)DataReader.Get64(_header, 12); long num3 = (long)DataReader.Get64(_header, 20); uint num4 = DataReader.Get32(_header, 28); if (Crc.Finish(Crc.Update(Crc.Update(Crc.Update(uint.MaxValue, num2), num3), num4)) != num) { throw new InvalidOperationException(); } archiveDatabase._startPositionAfterHeader = _streamOrigin + 32; if (num3 == 0L) { archiveDatabase.Fill(); return archiveDatabase; } if (num2 < 0 || num3 < 0 || num3 > int.MaxValue) { throw new InvalidOperationException(); } if (num2 > _streamEnding - archiveDatabase._startPositionAfterHeader) { throw new IndexOutOfRangeException(); } _stream.Seek(num2, SeekOrigin.Current); byte[] array = new byte[num3]; _stream.ReadExact(array, 0, array.Length); if (Crc.Finish(Crc.Update(uint.MaxValue, array, 0, array.Length)) != num4) { throw new InvalidOperationException(); } using (CStreamSwitch cStreamSwitch = default(CStreamSwitch)) { cStreamSwitch.Set(this, array); SharpCompress.Compressors.LZMA.Utilites.BlockType? blockType = ReadId(); if (blockType != SharpCompress.Compressors.LZMA.Utilites.BlockType.Header) { if (blockType != SharpCompress.Compressors.LZMA.Utilites.BlockType.EncodedHeader) { throw new InvalidOperationException(); } List list = ReadAndDecodePackedStreams(archiveDatabase._startPositionAfterHeader, archiveDatabase.PasswordProvider); if (list.Count == 0) { archiveDatabase.Fill(); return archiveDatabase; } if (list.Count != 1) { throw new InvalidOperationException(); } cStreamSwitch.Set(this, list[0]); if (ReadId() != SharpCompress.Compressors.LZMA.Utilites.BlockType.Header) { throw new InvalidOperationException(); } } ReadHeader(archiveDatabase, archiveDatabase.PasswordProvider); } archiveDatabase.Fill(); return archiveDatabase; } private Stream GetCachedDecoderStream(ArchiveDatabase db, int folderIndex) { if (!_cachedStreams.TryGetValue(folderIndex, out var value)) { CFolder cFolder = db._folders[folderIndex]; int firstPackStreamId = db._folders[folderIndex]._firstPackStreamId; long folderStreamPos = db.GetFolderStreamPos(cFolder, 0); List list = new List(); for (int i = 0; i < cFolder._packStreams.Count; i++) { list.Add(db._packSizes[firstPackStreamId + i]); } value = DecoderStreamHelper.CreateDecoderStream(_stream, folderStreamPos, list.ToArray(), cFolder, db.PasswordProvider); _cachedStreams.Add(folderIndex, value); } return value; } public Stream OpenStream(ArchiveDatabase db, int fileIndex) { int num = db._fileIndexToFolderIndexMap[fileIndex]; int num2 = db._numUnpackStreamsVector[num]; int num3 = db._folderStartFileIndex[num]; if (num3 > fileIndex || fileIndex - num3 >= num2) { throw new InvalidOperationException(); } int num4 = fileIndex - num3; long num5 = 0L; for (int i = 0; i < num4; i++) { num5 += db._files[num3 + i].Size; } Stream cachedDecoderStream = GetCachedDecoderStream(db, num); cachedDecoderStream.Position = num5; return new ReadOnlySubStream(cachedDecoderStream, db._files[fileIndex].Size); } public void Extract(ArchiveDatabase db, int[] indices) { bool flag = indices == null; int num = ((!flag) ? indices.Length : db._files.Count); if (num == 0) { return; } List list = new List(); for (int i = 0; i < num; i++) { int num2 = (flag ? i : indices[i]); int num3 = db._fileIndexToFolderIndexMap[num2]; if (num3 == -1) { list.Add(new CExtractFolderInfo(num2, -1)); continue; } if (list.Count == 0 || num3 != list.Last()._folderIndex) { list.Add(new CExtractFolderInfo(-1, num3)); } CExtractFolderInfo cExtractFolderInfo = list.Last(); int num4 = db._folderStartFileIndex[num3]; for (int j = cExtractFolderInfo._extractStatuses.Count; j <= num2 - num4; j++) { cExtractFolderInfo._extractStatuses.Add(j == num2 - num4); } } foreach (CExtractFolderInfo item in list) { int startIndex = ((item._fileIndex == -1) ? db._folderStartFileIndex[item._folderIndex] : item._fileIndex); FolderUnpackStream folderUnpackStream = new FolderUnpackStream(db, 0, startIndex, item._extractStatuses); if (item._fileIndex != -1) { continue; } int folderIndex = item._folderIndex; CFolder cFolder = db._folders[folderIndex]; int firstPackStreamId = db._folders[folderIndex]._firstPackStreamId; long folderStreamPos = db.GetFolderStreamPos(cFolder, 0); List list2 = new List(); for (int k = 0; k < cFolder._packStreams.Count; k++) { list2.Add(db._packSizes[firstPackStreamId + k]); } Stream stream = DecoderStreamHelper.CreateDecoderStream(_stream, folderStreamPos, list2.ToArray(), cFolder, db.PasswordProvider); byte[] array = new byte[4096]; while (true) { int num5 = stream.Read(array, 0, array.Length); if (num5 == 0) { break; } folderUnpackStream.Write(array, 0, num5); } } } public IEnumerable GetFiles(ArchiveDatabase db) { return db._files; } public int GetFileIndex(ArchiveDatabase db, CFileItem item) { return db._files.IndexOf(item); } } internal class CBindPair { internal int _inIndex; internal int _outIndex; } internal class CCoderInfo { internal CMethodId _methodId; internal byte[] _props; internal int _numInStreams; internal int _numOutStreams; } internal class CFileItem { public long Size { get; internal set; } public uint? Attrib { get; internal set; } public uint? Crc { get; internal set; } public string Name { get; internal set; } public bool HasStream { get; internal set; } public bool IsDir { get; internal set; } public bool CrcDefined => Crc.HasValue; public bool AttribDefined => Attrib.HasValue; public DateTime? CTime { get; internal set; } public DateTime? ATime { get; internal set; } public DateTime? MTime { get; internal set; } public long? StartPos { get; internal set; } public bool IsAnti { get; internal set; } public void SetAttrib(uint attrib) { Attrib = attrib; } internal CFileItem() { HasStream = true; } } internal class CFolder { internal List _coders = new List(); internal List _bindPairs = new List(); internal List _packStreams = new List(); internal int _firstPackStreamId; internal List _unpackSizes = new List(); internal uint? _unpackCrc; internal bool UnpackCrcDefined => _unpackCrc.HasValue; public long GetUnpackSize() { if (_unpackSizes.Count == 0) { return 0L; } for (int num = _unpackSizes.Count - 1; num >= 0; num--) { if (FindBindPairForOutStream(num) < 0) { return _unpackSizes[num]; } } throw new Exception(); } public int GetNumOutStreams() { int num = 0; for (int i = 0; i < _coders.Count; i++) { num += _coders[i]._numOutStreams; } return num; } public int FindBindPairForInStream(int inStreamIndex) { for (int i = 0; i < _bindPairs.Count; i++) { if (_bindPairs[i]._inIndex == inStreamIndex) { return i; } } return -1; } public int FindBindPairForOutStream(int outStreamIndex) { for (int i = 0; i < _bindPairs.Count; i++) { if (_bindPairs[i]._outIndex == outStreamIndex) { return i; } } return -1; } public int FindPackStreamArrayIndex(int inStreamIndex) { for (int i = 0; i < _packStreams.Count; i++) { if (_packStreams[i] == inStreamIndex) { return i; } } return -1; } public bool IsEncrypted() { for (int num = _coders.Count - 1; num >= 0; num--) { if (_coders[num]._methodId == CMethodId.K_AES) { return true; } } return false; } public bool CheckStructure() { if (_coders.Count > 32 || _bindPairs.Count > 32) { return false; } BitVector bitVector = new BitVector(_bindPairs.Count + _packStreams.Count); for (int i = 0; i < _bindPairs.Count; i++) { if (bitVector.GetAndSet(_bindPairs[i]._inIndex)) { return false; } } for (int j = 0; j < _packStreams.Count; j++) { if (bitVector.GetAndSet(_packStreams[j])) { return false; } } BitVector bitVector2 = new BitVector(_unpackSizes.Count); for (int k = 0; k < _bindPairs.Count; k++) { if (bitVector2.GetAndSet(_bindPairs[k]._outIndex)) { return false; } } uint[] array = new uint[32]; List list = new List(); List list2 = new List(); for (int l = 0; l < _coders.Count; l++) { CCoderInfo cCoderInfo = _coders[l]; for (int m = 0; m < cCoderInfo._numInStreams; m++) { list.Add(l); } for (int n = 0; n < cCoderInfo._numOutStreams; n++) { list2.Add(l); } } for (int num = 0; num < _bindPairs.Count; num++) { CBindPair cBindPair = _bindPairs[num]; array[list[cBindPair._inIndex]] |= (uint)(1 << list2[cBindPair._outIndex]); } for (int num2 = 0; num2 < 32; num2++) { for (int num3 = 0; num3 < 32; num3++) { if (((uint)(1 << num3) & array[num2]) != 0) { array[num2] |= array[num3]; } } } for (int num4 = 0; num4 < 32; num4++) { if (((uint)(1 << num4) & array[num4]) != 0) { return false; } } return true; } } internal struct CMethodId { public const ulong K_COPY_ID = 0uL; public const ulong K_LZMA_ID = 196865uL; public const ulong K_LZMA2_ID = 33uL; public const ulong K_AES_ID = 116459265uL; public static readonly CMethodId K_COPY = new CMethodId(0uL); public static readonly CMethodId K_LZMA = new CMethodId(196865uL); public static readonly CMethodId K_LZMA2 = new CMethodId(33uL); public static readonly CMethodId K_AES = new CMethodId(116459265uL); public readonly ulong _id; public CMethodId(ulong id) { _id = id; } public override int GetHashCode() { ulong id = _id; return id.GetHashCode(); } public override bool Equals(object obj) { if (obj is CMethodId) { return (CMethodId)obj == this; } return false; } public bool Equals(CMethodId other) { return _id == other._id; } public static bool operator ==(CMethodId left, CMethodId right) { return left._id == right._id; } public static bool operator !=(CMethodId left, CMethodId right) { return left._id != right._id; } public int GetLength() { int num = 0; for (ulong num2 = _id; num2 != 0L; num2 >>= 8) { num++; } return num; } } internal struct CStreamSwitch : IDisposable { private ArchiveReader _archive; private bool _needRemove; private bool _active; public void Dispose() { if (_active) { _active = false; } if (_needRemove) { _needRemove = false; _archive.DeleteByteStream(); } } public void Set(ArchiveReader archive, byte[] dataVector) { Dispose(); _archive = archive; _archive.AddByteStream(dataVector, 0, dataVector.Length); _needRemove = true; _active = true; } public void Set(ArchiveReader archive, List dataVector) { Dispose(); _active = true; if (archive.ReadByte() != 0) { int num = archive.ReadNum(); if (num < 0 || num >= dataVector.Count) { throw new InvalidOperationException(); } _archive = archive; _archive.AddByteStream(dataVector[num], 0, dataVector[num].Length); _needRemove = true; _active = true; } } } internal class DataReader { private readonly byte[] _buffer; private readonly int _ending; public int Offset { get; private set; } public static uint Get32(byte[] buffer, int offset) { return (uint)(buffer[offset] + (buffer[offset + 1] << 8) + (buffer[offset + 2] << 16) + (buffer[offset + 3] << 24)); } public static ulong Get64(byte[] buffer, int offset) { return buffer[offset] + ((ulong)buffer[offset + 1] << 8) + ((ulong)buffer[offset + 2] << 16) + ((ulong)buffer[offset + 3] << 24) + ((ulong)buffer[offset + 4] << 32) + ((ulong)buffer[offset + 5] << 40) + ((ulong)buffer[offset + 6] << 48) + ((ulong)buffer[offset + 7] << 56); } public DataReader(byte[] buffer, int offset, int length) { _buffer = buffer; Offset = offset; _ending = offset + length; } public byte ReadByte() { if (Offset >= _ending) { throw new EndOfStreamException(); } return _buffer[Offset++]; } public void ReadBytes(byte[] buffer, int offset, int length) { if (length > _ending - Offset) { throw new EndOfStreamException(); } while (length-- > 0) { buffer[offset++] = _buffer[Offset++]; } } public void SkipData(long size) { if (size > _ending - Offset) { throw new EndOfStreamException(); } Offset += (int)size; } public void SkipData() { SkipData(checked((long)ReadNumber())); } public ulong ReadNumber() { if (Offset >= _ending) { throw new EndOfStreamException(); } byte b = _buffer[Offset++]; byte b2 = 128; ulong num = 0uL; for (int i = 0; i < 8; i++) { if ((b & b2) == 0) { ulong num2 = (uint)(b & (b2 - 1)); return num + (num2 << i * 8); } if (Offset >= _ending) { throw new EndOfStreamException(); } num |= (ulong)_buffer[Offset++] << 8 * i; b2 >>= 1; } return num; } public int ReadNum() { ulong num = ReadNumber(); if (num > int.MaxValue) { throw new NotSupportedException(); } return (int)num; } public uint ReadUInt32() { if (Offset + 4 > _ending) { throw new EndOfStreamException(); } uint result = Get32(_buffer, Offset); Offset += 4; return result; } public ulong ReadUInt64() { if (Offset + 8 > _ending) { throw new EndOfStreamException(); } ulong result = Get64(_buffer, Offset); Offset += 8; return result; } public string ReadString() { int num = Offset; while (true) { if (num + 2 > _ending) { throw new EndOfStreamException(); } if (_buffer[num] == 0 && _buffer[num + 1] == 0) { break; } num += 2; } string result = Encoding.Unicode.GetString(_buffer, Offset, num - Offset); Offset = num + 2; return result; } } public class SevenZipEntry : Entry { internal SevenZipFilePart FilePart { get; } public override CompressionType CompressionType => FilePart.CompressionType; public override long Crc => FilePart.Header.Crc ?? 0; public override string Key => FilePart.Header.Name; public override string LinkTarget => null; public override long CompressedSize => 0L; public override long Size => FilePart.Header.Size; public override DateTime? LastModifiedTime => FilePart.Header.MTime; public override DateTime? CreatedTime => null; public override DateTime? LastAccessedTime => null; public override DateTime? ArchivedTime => null; public override bool IsEncrypted => false; public override bool IsDirectory => FilePart.Header.IsDir; public override bool IsSplitAfter => false; public override int? Attrib => (int)FilePart.Header.Attrib.Value; internal override IEnumerable Parts => ((FilePart)FilePart).AsEnumerable(); internal SevenZipEntry(SevenZipFilePart filePart) { FilePart = filePart; } } internal class SevenZipFilePart : FilePart { private CompressionType? _type; private readonly Stream _stream; private readonly ArchiveDatabase _database; private const uint K_COPY = 0u; private const uint K_DELTA = 3u; private const uint K_LZMA2 = 33u; private const uint K_LZMA = 196865u; private const uint K_PPMD = 197633u; private const uint K_BCJ = 50528515u; private const uint K_BCJ2 = 50528539u; private const uint K_DEFLATE = 262408u; private const uint K_B_ZIP2 = 262658u; internal CFileItem Header { get; } internal CFolder Folder { get; } internal int Index { get; } internal override string FilePartName => Header.Name; public CompressionType CompressionType { get { if (!_type.HasValue) { _type = GetCompression(); } return _type.Value; } } internal SevenZipFilePart(Stream stream, ArchiveDatabase database, int index, CFileItem fileEntry, ArchiveEncoding archiveEncoding) : base(archiveEncoding) { _stream = stream; _database = database; Index = index; Header = fileEntry; if (Header.HasStream) { Folder = database._folders[database._fileIndexToFolderIndexMap[index]]; } } internal override Stream GetRawStream() { return null; } internal override Stream GetCompressedStream() { if (!Header.HasStream) { return null; } Stream folderStream = _database.GetFolderStream(_stream, Folder, _database.PasswordProvider); int num = _database._folderStartFileIndex[_database._folders.IndexOf(Folder)]; int num2 = Index - num; long num3 = 0L; for (int i = 0; i < num2; i++) { num3 += _database._files[num + i].Size; } if (num3 > 0) { folderStream.Skip(num3); } return new ReadOnlySubStream(folderStream, Header.Size); } internal CompressionType GetCompression() { switch (Folder._coders.First()._methodId._id) { case 33uL: case 196865uL: return CompressionType.LZMA; case 197633uL: return CompressionType.PPMd; case 262658uL: return CompressionType.BZip2; default: throw new NotImplementedException(); } } } public class SevenZipVolume : Volume { public SevenZipVolume(Stream stream, ReaderOptions readerFactoryOptions) : base(stream, readerFactoryOptions) { } } } namespace SharpCompress.Common.Rar { internal class RarCrcBinaryReader : MarkingBinaryReader { private uint _currentCrc; public RarCrcBinaryReader(Stream stream) : base(stream) { } public uint GetCrc32() { return ~_currentCrc; } public void ResetCrc() { _currentCrc = uint.MaxValue; } protected void UpdateCrc(byte b) { _currentCrc = RarCRC.CheckCrc(_currentCrc, b); } protected byte[] ReadBytesNoCrc(int count) { return base.ReadBytes(count); } public override byte ReadByte() { byte b = base.ReadByte(); _currentCrc = RarCRC.CheckCrc(_currentCrc, b); return b; } public override byte[] ReadBytes(int count) { byte[] array = base.ReadBytes(count); _currentCrc = RarCRC.CheckCrc(_currentCrc, array, 0, array.Length); return array; } } internal class RarCryptoBinaryReader : RarCrcBinaryReader { private RarRijndael _rijndael; private byte[] _salt; private readonly string _password; private readonly Queue _data = new Queue(); private long _readCount; public override long CurrentReadByteCount { get { return _readCount; } protected set { } } private bool UseEncryption => _salt != null; public RarCryptoBinaryReader(Stream stream, string password) : base(stream) { _password = password; byte[] salt = ReadBytes(8); InitializeAes(salt); } public override void Mark() { _readCount = 0L; } internal void InitializeAes(byte[] salt) { _salt = salt; _rijndael = RarRijndael.InitializeFrom(_password, salt); } public override byte ReadByte() { if (UseEncryption) { return ReadAndDecryptBytes(1)[0]; } _readCount++; return base.ReadByte(); } public override byte[] ReadBytes(int count) { if (UseEncryption) { return ReadAndDecryptBytes(count); } _readCount += count; return base.ReadBytes(count); } private byte[] ReadAndDecryptBytes(int count) { int count2 = _data.Count; int num = count - count2; if (num > 0) { int num2 = num + ((~num + 1) & 0xF); for (int i = 0; i < num2 / 16; i++) { byte[] cipherText = ReadBytesNoCrc(16); byte[] array = _rijndael.ProcessBlock(cipherText); foreach (byte item in array) { _data.Enqueue(item); } } } byte[] array2 = new byte[count]; for (int k = 0; k < count; k++) { UpdateCrc(array2[k] = _data.Dequeue()); } _readCount += count; return array2; } public void ClearQueue() { _data.Clear(); } public void SkipQueue() { long position = BaseStream.Position; BaseStream.Position = position + _data.Count; ClearQueue(); } } internal class RarCryptoWrapper : Stream { private readonly Stream _actualStream; private readonly byte[] _salt; private RarRijndael _rijndael; private readonly Queue _data = new Queue(); public override bool CanRead => true; public override bool CanSeek => false; public override bool CanWrite => false; public override long Length { get { throw new NotSupportedException(); } } public override long Position { get; set; } public RarCryptoWrapper(Stream actualStream, string password, byte[] salt) { _actualStream = actualStream; _salt = salt; _rijndael = RarRijndael.InitializeFrom(password, salt); } public override void Flush() { throw new NotSupportedException(); } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override int Read(byte[] buffer, int offset, int count) { if (_salt == null) { return _actualStream.Read(buffer, offset, count); } return ReadAndDecrypt(buffer, offset, count); } public int ReadAndDecrypt(byte[] buffer, int offset, int count) { int count2 = _data.Count; int num = count - count2; if (num > 0) { int num2 = num + ((~num + 1) & 0xF); for (int i = 0; i < num2 / 16; i++) { byte[] array = new byte[16]; _actualStream.Read(array, 0, 16); byte[] array2 = _rijndael.ProcessBlock(array); foreach (byte item in array2) { _data.Enqueue(item); } } for (int k = 0; k < count; k++) { buffer[offset + k] = _data.Dequeue(); } } return count; } public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } protected override void Dispose(bool disposing) { if (_rijndael != null) { _rijndael.Dispose(); _rijndael = null; } base.Dispose(disposing); } } public abstract class RarEntry : Entry { internal abstract FileHeader FileHeader { get; } internal bool IsRarV3 { get { if (FileHeader.CompressionAlgorithm != 29) { return FileHeader.CompressionAlgorithm == 36; } return true; } } public override long Crc => FileHeader.FileCrc; public override string Key => FileHeader.FileName; public override string LinkTarget => null; public override DateTime? LastModifiedTime => FileHeader.FileLastModifiedTime; public override DateTime? CreatedTime => FileHeader.FileCreatedTime; public override DateTime? LastAccessedTime => FileHeader.FileLastAccessedTime; public override DateTime? ArchivedTime => FileHeader.FileArchivedTime; public override bool IsEncrypted => FileHeader.IsEncrypted; public override bool IsDirectory => FileHeader.IsDirectory; public override bool IsSplitAfter => FileHeader.IsSplitAfter; public override string ToString() { return $"Entry Path: {Key} Compressed Size: {CompressedSize} Uncompressed Size: {Size} CRC: {Crc}"; } } internal abstract class RarFilePart : FilePart { internal MarkHeader MarkHeader { get; } internal FileHeader FileHeader { get; } internal RarFilePart(MarkHeader mh, FileHeader fh) : base(fh.ArchiveEncoding) { MarkHeader = mh; FileHeader = fh; } internal override Stream GetRawStream() { return null; } } internal class RarRijndael : IDisposable { internal const int CRYPTO_BLOCK_SIZE = 16; private readonly string _password; private readonly byte[] _salt; private byte[] _aesInitializationVector; private RijndaelEngine _rijndael; private RarRijndael(string password, byte[] salt) { _password = password; _salt = salt; } private void Initialize() { _rijndael = new RijndaelEngine(); _aesInitializationVector = new byte[16]; int num = 2 * _password.Length; byte[] array = new byte[num + 8]; byte[] bytes = Encoding.UTF8.GetBytes(_password); for (int i = 0; i < _password.Length; i++) { array[i * 2] = bytes[i]; array[i * 2 + 1] = 0; } for (int j = 0; j < _salt.Length; j++) { array[j + num] = _salt[j]; } byte[] array2 = new byte[(array.Length + 3) * 262144]; byte[] array3; for (int k = 0; k < 262144; k++) { array.CopyTo(array2, k * (array.Length + 3)); array2[k * (array.Length + 3) + array.Length] = (byte)k; array2[k * (array.Length + 3) + array.Length + 1] = (byte)(k >> 8); array2[k * (array.Length + 3) + array.Length + 2] = (byte)(k >> 16); if (k % 16384 == 0) { array3 = SHA1.Create().ComputeHash(array2, 0, (k + 1) * (array.Length + 3)); _aesInitializationVector[k / 16384] = array3[19]; } } array3 = SHA1.Create().ComputeHash(array2); byte[] array4 = new byte[16]; for (int l = 0; l < 4; l++) { for (int m = 0; m < 4; m++) { array4[l * 4 + m] = (byte)((((array3[l * 4] * 16777216) & 0xFF000000u) | (uint)((array3[l * 4 + 1] * 65536) & 0xFF0000) | (uint)((array3[l * 4 + 2] * 256) & 0xFF00) | (uint)(array3[l * 4 + 3] & 0xFF)) >> m * 8); } } _rijndael.Init(forEncryption: false, new KeyParameter(array4)); } public static RarRijndael InitializeFrom(string password, byte[] salt) { RarRijndael rarRijndael = new RarRijndael(password, salt); rarRijndael.Initialize(); return rarRijndael; } public byte[] ProcessBlock(byte[] cipherText) { byte[] array = new byte[16]; List list = new List(); _rijndael.ProcessBlock(cipherText, 0, array, 0); for (int i = 0; i < array.Length; i++) { list.Add((byte)(array[i] ^ _aesInitializationVector[i % 16])); } for (int j = 0; j < _aesInitializationVector.Length; j++) { _aesInitializationVector[j] = cipherText[j]; } return list.ToArray(); } public void Dispose() { } } public abstract class RarVolume : Volume { private readonly RarHeaderFactory _headerFactory; internal ArchiveHeader ArchiveHeader { get; private set; } internal StreamingMode Mode => _headerFactory.StreamingMode; public override bool IsFirstVolume { get { EnsureArchiveHeaderLoaded(); return ArchiveHeader.IsFirstVolume; } } public override bool IsMultiVolume { get { EnsureArchiveHeaderLoaded(); return ArchiveHeader.IsVolume; } } public bool IsSolidArchive { get { EnsureArchiveHeaderLoaded(); return ArchiveHeader.IsSolid; } } internal RarVolume(StreamingMode mode, Stream stream, ReaderOptions options) : base(stream, options) { _headerFactory = new RarHeaderFactory(mode, options); } internal abstract IEnumerable ReadFileParts(); internal abstract RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader); internal IEnumerable GetVolumeFileParts() { MarkHeader lastMarkHeader = null; foreach (IRarHeader item in _headerFactory.ReadHeaders(base.Stream)) { switch (item.HeaderType) { case HeaderType.Mark: lastMarkHeader = item as MarkHeader; break; case HeaderType.Archive: ArchiveHeader = item as ArchiveHeader; break; case HeaderType.File: { FileHeader fileHeader = item as FileHeader; yield return CreateFilePart(lastMarkHeader, fileHeader); break; } } } } private void EnsureArchiveHeaderLoaded() { if (ArchiveHeader == null) { if (Mode == StreamingMode.Streaming) { throw new InvalidOperationException("ArchiveHeader should never been null in a streaming read."); } GetVolumeFileParts().First(); base.Stream.Position = 0L; } } } } namespace SharpCompress.Common.Rar.Headers { internal class ArchiveCryptHeader : RarHeader { private const int CRYPT_VERSION = 0; private const int SIZE_SALT50 = 16; private const int SIZE_SALT30 = 8; private const int SIZE_INITV = 16; private const int SIZE_PSWCHECK = 8; private const int SIZE_PSWCHECK_CSUM = 4; private const int CRYPT5_KDF_LG2_COUNT = 15; private const int CRYPT5_KDF_LG2_COUNT_MAX = 24; private bool _usePswCheck; private uint _lg2Count; private byte[] _salt; private byte[] _pswCheck; private byte[] _pswCheckCsm; public ArchiveCryptHeader(RarHeader header, RarCrcBinaryReader reader) : base(header, reader, HeaderType.Crypt) { } protected override void ReadFinish(MarkingBinaryReader reader) { if (reader.ReadRarVIntUInt32() != 0) { return; } uint bitField = reader.ReadRarVIntUInt32(); _usePswCheck = FlagUtility.HasFlag(bitField, 1u); _lg2Count = reader.ReadRarVIntByte(1); if (_lg2Count <= 24) { _salt = reader.ReadBytes(16); if (_usePswCheck) { _pswCheck = reader.ReadBytes(8); _pswCheckCsm = reader.ReadBytes(4); } } } } internal class ArchiveHeader : RarHeader { private ushort Flags { get; set; } internal int? VolumeNumber { get; private set; } internal short? HighPosAv { get; private set; } internal int? PosAv { get; private set; } private byte? EncryptionVersion { get; set; } public bool? IsEncrypted { get { if (!base.IsRar5) { return HasFlag(128); } return null; } } public bool OldNumberingFormat { get { if (!base.IsRar5) { return !HasFlag(16); } return false; } } public bool IsVolume => HasFlag((ushort)(base.IsRar5 ? 1 : 1)); public bool IsFirstVolume { get { if (!base.IsRar5) { return HasFlag(256); } return !VolumeNumber.HasValue; } } public bool IsSolid => HasFlag((ushort)(base.IsRar5 ? 4 : 8)); public ArchiveHeader(RarHeader header, RarCrcBinaryReader reader) : base(header, reader, HeaderType.Archive) { } protected override void ReadFinish(MarkingBinaryReader reader) { if (base.IsRar5) { Flags = reader.ReadRarVIntUInt16(); if (HasFlag(2)) { VolumeNumber = (int)reader.ReadRarVIntUInt32(); } return; } Flags = base.HeaderFlags; HighPosAv = reader.ReadInt16(); PosAv = reader.ReadInt32(); if (HasFlag(512)) { EncryptionVersion = reader.ReadByte(); } } private void ReadLocator(MarkingBinaryReader reader) { reader.ReadRarVIntUInt16(); if (reader.ReadRarVIntUInt16() != 1) { throw new InvalidFormatException("expected locator record"); } ushort num = reader.ReadRarVIntUInt16(); if ((num & 1) == 1) { reader.ReadRarVInt(); } if ((num & 2) == 2) { reader.ReadRarVInt(); } } private bool HasFlag(ushort flag) { return (Flags & flag) == flag; } } internal class AvHeader : RarHeader { internal int AvInfoCrc { get; private set; } internal byte UnpackVersion { get; private set; } internal byte Method { get; private set; } internal byte AvVersion { get; private set; } public AvHeader(RarHeader header, RarCrcBinaryReader reader) : base(header, reader, HeaderType.Av) { if (base.IsRar5) { throw new InvalidFormatException("unexpected rar5 record"); } } protected override void ReadFinish(MarkingBinaryReader reader) { UnpackVersion = reader.ReadByte(); Method = reader.ReadByte(); AvVersion = reader.ReadByte(); AvInfoCrc = reader.ReadInt32(); } } internal class CommentHeader : RarHeader { internal short UnpSize { get; private set; } internal byte UnpVersion { get; private set; } internal byte UnpMethod { get; private set; } internal short CommCrc { get; private set; } protected CommentHeader(RarHeader header, RarCrcBinaryReader reader) : base(header, reader, HeaderType.Comment) { if (base.IsRar5) { throw new InvalidFormatException("unexpected rar5 record"); } } protected override void ReadFinish(MarkingBinaryReader reader) { UnpSize = reader.ReadInt16(); UnpVersion = reader.ReadByte(); UnpMethod = reader.ReadByte(); CommCrc = reader.ReadInt16(); } } internal class EndArchiveHeader : RarHeader { private ushort Flags { get; set; } internal int? ArchiveCrc { get; private set; } internal short? VolumeNumber { get; private set; } public EndArchiveHeader(RarHeader header, RarCrcBinaryReader reader) : base(header, reader, HeaderType.EndArchive) { } protected override void ReadFinish(MarkingBinaryReader reader) { if (base.IsRar5) { Flags = reader.ReadRarVIntUInt16(); return; } Flags = base.HeaderFlags; if (HasFlag(2)) { ArchiveCrc = reader.ReadInt32(); } if (HasFlag(8)) { VolumeNumber = reader.ReadInt16(); } } private bool HasFlag(ushort flag) { return (Flags & flag) == flag; } } internal class FileHeader : RarHeader { private uint _fileCrc; private bool isEncryptedRar5; private ushort Flags { get; set; } internal uint FileCrc { get { if (base.IsRar5 && !HasFlag(4)) { throw new InvalidOperationException("TODO rar5"); } return _fileCrc; } private set { _fileCrc = value; } } internal byte CompressionMethod { get; private set; } internal bool IsStored => CompressionMethod == 0; internal byte CompressionAlgorithm { get; private set; } public bool IsSolid { get; private set; } internal uint WindowSize { get; private set; } internal byte[] R4Salt { get; private set; } private byte HostOs { get; set; } internal uint FileAttributes { get; private set; } internal long CompressedSize { get; private set; } internal long UncompressedSize { get; private set; } internal string FileName { get; private set; } internal byte[] SubData { get; private set; } internal int RecoverySectors { get; private set; } internal long DataStartPosition { get; set; } public Stream PackedStream { get; set; } public bool IsSplitAfter { get { if (!base.IsRar5) { return HasFlag(2); } return HasHeaderFlag(16); } } public bool IsDirectory => HasFlag((ushort)(base.IsRar5 ? 1 : 224)); public bool IsEncrypted { get { if (!base.IsRar5) { return HasFlag(4); } return isEncryptedRar5; } } internal DateTime? FileLastModifiedTime { get; private set; } internal DateTime? FileCreatedTime { get; private set; } internal DateTime? FileLastAccessedTime { get; private set; } internal DateTime? FileArchivedTime { get; private set; } public FileHeader(RarHeader header, RarCrcBinaryReader reader, HeaderType headerType) : base(header, reader, headerType) { } protected override void ReadFinish(MarkingBinaryReader reader) { if (base.IsRar5) { ReadFromReaderV5(reader); } else { ReadFromReaderV4(reader); } } private void ReadFromReaderV5(MarkingBinaryReader reader) { Flags = reader.ReadRarVIntUInt16(); long num = checked((long)reader.ReadRarVInt()); UncompressedSize = (HasFlag(8) ? long.MaxValue : num); FileAttributes = reader.ReadRarVIntUInt32(); if (HasFlag(2)) { FileLastModifiedTime = Utility.UnixTimeToDateTime(reader.ReadUInt32()); } if (HasFlag(4)) { FileCrc = reader.ReadUInt32(); } ushort num2 = reader.ReadRarVIntUInt16(); CompressionAlgorithm = (byte)((num2 & 0x3F) + 50); IsSolid = (num2 & 0x40) == 64; CompressionMethod = (byte)((num2 >> 7) & 7); WindowSize = ((!IsDirectory) ? ((uint)(131072 << ((num2 >> 10) & 0xF))) : 0u); HostOs = reader.ReadRarVIntByte(); ushort count = reader.ReadRarVIntUInt16(); byte[] array = reader.ReadBytes(count); FileName = ConvertPathV5(Encoding.UTF8.GetString(array, 0, array.Length)); if (base.ExtraSize != RemainingHeaderBytes(reader)) { throw new InvalidFormatException("rar5 header size / extra size inconsistency"); } isEncryptedRar5 = false; while (RemainingHeaderBytes(reader) > 0) { ushort num3 = reader.ReadRarVIntUInt16(); int num4 = RemainingHeaderBytes(reader); switch (reader.ReadRarVIntUInt16()) { case 1: isEncryptedRar5 = true; break; case 3: { ushort num5 = reader.ReadRarVIntUInt16(); bool isWindowsTime = (num5 & 1) == 0; if ((num5 & 2) == 2) { FileLastModifiedTime = ReadExtendedTimeV5(reader, isWindowsTime); } if ((num5 & 4) == 4) { FileCreatedTime = ReadExtendedTimeV5(reader, isWindowsTime); } if ((num5 & 8) == 8) { FileLastAccessedTime = ReadExtendedTimeV5(reader, isWindowsTime); } break; } } int num6 = num4 - RemainingHeaderBytes(reader); int num7 = num3 - num6; if (num7 > 0) { reader.ReadBytes(num7); } } if (base.AdditionalDataSize != 0L) { CompressedSize = base.AdditionalDataSize; } } private static DateTime ReadExtendedTimeV5(MarkingBinaryReader reader, bool isWindowsTime) { if (isWindowsTime) { return DateTime.FromFileTime(reader.ReadInt64()); } return Utility.UnixTimeToDateTime(reader.ReadUInt32()); } private static string ConvertPathV5(string path) { if (Path.DirectorySeparatorChar == '\\') { return path.Replace('\\', '-').Replace('/', '\\'); } return path; } private void ReadFromReaderV4(MarkingBinaryReader reader) { Flags = base.HeaderFlags; IsSolid = HasFlag(16); WindowSize = ((!IsDirectory) ? ((uint)(65536 << ((Flags & 0xE0) >> 5))) : 0u); uint num = reader.ReadUInt32(); HostOs = reader.ReadByte(); FileCrc = reader.ReadUInt32(); FileLastModifiedTime = Utility.DosDateToDateTime(reader.ReadUInt32()); CompressionAlgorithm = reader.ReadByte(); CompressionMethod = (byte)(reader.ReadByte() - 48); short num2 = reader.ReadInt16(); FileAttributes = reader.ReadUInt32(); uint x = 0u; uint x2 = 0u; if (HasFlag(256)) { x = reader.ReadUInt32(); x2 = reader.ReadUInt32(); } else if (num == uint.MaxValue) { num = uint.MaxValue; x2 = 2147483647u; } CompressedSize = UInt32To64(x, checked((uint)base.AdditionalDataSize)); UncompressedSize = UInt32To64(x2, num); num2 = (short)((num2 > 4096) ? 4096 : num2); byte[] array = reader.ReadBytes(num2); switch (base.HeaderCode) { case 116: if (HasFlag(512)) { int i; for (i = 0; i < array.Length && array[i] != 0; i++) { } if (i != num2) { i++; FileName = FileNameDecoder.Decode(array, i); } else { FileName = base.ArchiveEncoding.Decode(array); } } else { FileName = base.ArchiveEncoding.Decode(array); } FileName = ConvertPathV4(FileName); break; case 122: { int num3 = base.HeaderSize - 32 - num2; if (HasFlag(1024)) { num3 -= 8; } if (num3 > 0) { SubData = reader.ReadBytes(num3); } if (NewSubHeaderType.SUBHEAD_TYPE_RR.Equals(array)) { RecoverySectors = SubData[8] + (SubData[9] << 8) + (SubData[10] << 16) + (SubData[11] << 24); } break; } } if (HasFlag(1024)) { R4Salt = reader.ReadBytes(8); } if (HasFlag(4096) && RemainingHeaderBytes(reader) >= 2) { ushort extendedFlags = reader.ReadUInt16(); FileLastModifiedTime = ProcessExtendedTimeV4(extendedFlags, FileLastModifiedTime, reader, 0); FileCreatedTime = ProcessExtendedTimeV4(extendedFlags, null, reader, 1); FileLastAccessedTime = ProcessExtendedTimeV4(extendedFlags, null, reader, 2); FileArchivedTime = ProcessExtendedTimeV4(extendedFlags, null, reader, 3); } } private static long UInt32To64(uint x, uint y) { return (long)(((ulong)x << 32) + y); } private static DateTime? ProcessExtendedTimeV4(ushort extendedFlags, DateTime? time, MarkingBinaryReader reader, int i) { uint num = (uint)extendedFlags >> (3 - i) * 4; if ((num & 8) == 0) { return null; } if (i != 0) { uint iTime = reader.ReadUInt32(); time = Utility.DosDateToDateTime(iTime); } if ((num & 4) == 0) { time = time.Value.AddSeconds(1.0); } uint num2 = 0u; int num3 = (int)(num & 3); for (int j = 0; j < num3; j++) { byte b = reader.ReadByte(); num2 |= (uint)(b << (j + 3 - num3) * 8); } return time.Value.AddMilliseconds((double)num2 * Math.Pow(10.0, -4.0)); } private static string ConvertPathV4(string path) { if (Path.DirectorySeparatorChar == '/') { return path.Replace('\\', '/'); } if (Path.DirectorySeparatorChar == '\\') { return path.Replace('/', '\\'); } return path; } public override string ToString() { return FileName; } private bool HasFlag(ushort flag) { return (Flags & flag) == flag; } } internal static class FileNameDecoder { internal static int GetChar(byte[] name, int pos) { return name[pos] & 0xFF; } internal static string Decode(byte[] name, int encPos) { int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = GetChar(name, encPos++); StringBuilder stringBuilder = new StringBuilder(); while (encPos < name.Length) { if (num3 == 0) { num2 = GetChar(name, encPos++); num3 = 8; } switch (num2 >> 6) { case 0: stringBuilder.Append((char)GetChar(name, encPos++)); num++; break; case 1: stringBuilder.Append((char)(GetChar(name, encPos++) + (num6 << 8))); num++; break; case 2: num4 = GetChar(name, encPos); num5 = GetChar(name, encPos + 1); stringBuilder.Append((char)((num5 << 8) + num4)); num++; encPos += 2; break; case 3: { int num7 = GetChar(name, encPos++); if ((num7 & 0x80) != 0) { int num8 = GetChar(name, encPos++); num7 = (num7 & 0x7F) + 2; while (num7 > 0 && num < name.Length) { num4 = (GetChar(name, num) + num8) & 0xFF; stringBuilder.Append((char)((num6 << 8) + num4)); num7--; num++; } } else { num7 += 2; while (num7 > 0 && num < name.Length) { stringBuilder.Append((char)GetChar(name, num)); num7--; num++; } } break; } } num2 = (num2 << 2) & 0xFF; num3 -= 2; } return stringBuilder.ToString(); } } internal enum HeaderType : byte { Null, Mark, Archive, File, Service, Comment, Av, Protect, Sign, NewSub, EndArchive, Crypt } internal static class HeaderCodeV { public const byte RAR4_MARK_HEADER = 114; public const byte RAR4_ARCHIVE_HEADER = 115; public const byte RAR4_FILE_HEADER = 116; public const byte RAR4_COMMENT_HEADER = 117; public const byte RAR4_AV_HEADER = 118; public const byte RAR4_SUB_HEADER = 119; public const byte RAR4_PROTECT_HEADER = 120; public const byte RAR4_SIGN_HEADER = 121; public const byte RAR4_NEW_SUB_HEADER = 122; public const byte RAR4_END_ARCHIVE_HEADER = 123; public const byte RAR5_ARCHIVE_HEADER = 1; public const byte RAR5_FILE_HEADER = 2; public const byte RAR5_SERVICE_HEADER = 3; public const byte RAR5_ARCHIVE_ENCRYPTION_HEADER = 4; public const byte RAR5_END_ARCHIVE_HEADER = 5; } internal static class HeaderFlagsV4 { public const ushort HAS_DATA = 32768; } internal static class EncryptionFlagsV5 { public const uint CHFL_CRYPT_PSWCHECK = 1u; public const uint FHEXTRA_CRYPT_PSWCHECK = 1u; public const uint FHEXTRA_CRYPT_HASHMAC = 2u; } internal static class HeaderFlagsV5 { public const ushort HAS_EXTRA = 1; public const ushort HAS_DATA = 2; public const ushort KEEP = 4; public const ushort SPLIT_BEFORE = 8; public const ushort SPLIT_AFTER = 16; public const ushort CHILD = 32; public const ushort PRESERVE_CHILD = 64; } internal static class ArchiveFlagsV4 { public const ushort VOLUME = 1; public const ushort COMMENT = 2; public const ushort LOCK = 4; public const ushort SOLID = 8; public const ushort NEW_NUMBERING = 16; public const ushort AV = 32; public const ushort PROTECT = 64; public const ushort PASSWORD = 128; public const ushort FIRST_VOLUME = 256; public const ushort ENCRYPT_VER = 512; } internal static class ArchiveFlagsV5 { public const ushort VOLUME = 1; public const ushort HAS_VOLUME_NUMBER = 2; public const ushort SOLID = 4; public const ushort PROTECT = 8; public const ushort LOCK = 16; } internal static class HostOsV4 { public const byte MS_DOS = 0; public const byte OS2 = 1; public const byte WIN32 = 2; public const byte UNIX = 3; public const byte MAC_OS = 4; public const byte BE_OS = 5; } internal static class HostOsV5 { public const byte WINDOWS = 0; public const byte UNIX = 1; } internal static class FileFlagsV4 { public const ushort SPLIT_BEFORE = 1; public const ushort SPLIT_AFTER = 2; public const ushort PASSWORD = 4; public const ushort COMMENT = 8; public const ushort SOLID = 16; public const ushort WINDOW_MASK = 224; public const ushort WINDOW64 = 0; public const ushort WINDOW128 = 32; public const ushort WINDOW256 = 64; public const ushort WINDOW512 = 96; public const ushort WINDOW1024 = 128; public const ushort WINDOW2048 = 160; public const ushort WINDOW4096 = 192; public const ushort DIRECTORY = 224; public const ushort LARGE = 256; public const ushort UNICODE = 512; public const ushort SALT = 1024; public const ushort VERSION = 2048; public const ushort EXT_TIME = 4096; public const ushort EXT_FLAGS = 8192; } internal static class FileFlagsV5 { public const ushort DIRECTORY = 1; public const ushort HAS_MOD_TIME = 2; public const ushort HAS_CRC32 = 4; public const ushort UNPACKED_SIZE_UNKNOWN = 8; } internal static class EndArchiveFlagsV4 { public const ushort NEXT_VOLUME = 1; public const ushort DATA_CRC = 2; public const ushort REV_SPACE = 4; public const ushort VOLUME_NUMBER = 8; } internal static class EndArchiveFlagsV5 { public const ushort HAS_NEXT_VOLUME = 1; } internal interface IRarHeader { HeaderType HeaderType { get; } } internal class MarkHeader : IRarHeader { private const int MAX_SFX_SIZE = 524272; internal bool OldNumberingFormat { get; private set; } public bool IsRar5 { get; } public HeaderType HeaderType => HeaderType.Mark; private MarkHeader(bool isRar5) { IsRar5 = isRar5; } private static byte GetByte(Stream stream) { int num = stream.ReadByte(); if (num != -1) { return (byte)num; } throw new EndOfStreamException(); } public static MarkHeader Read(Stream stream, bool leaveStreamOpen, bool lookForHeader) { int num = (lookForHeader ? 524272 : 0); try { int num2 = -1; byte b = GetByte(stream); num2++; while (num2 <= num) { if (b == 82) { b = GetByte(stream); num2++; switch (b) { case 97: b = GetByte(stream); num2++; if (b != 114) { break; } b = GetByte(stream); num2++; if (b != 33) { break; } b = GetByte(stream); num2++; if (b != 26) { break; } b = GetByte(stream); num2++; if (b != 7) { break; } b = GetByte(stream); num2++; switch (b) { case 1: b = GetByte(stream); num2++; if (b == 0) { return new MarkHeader(isRar5: true); } break; case 0: return new MarkHeader(isRar5: false); } break; case 69: b = GetByte(stream); num2++; if (b == 126) { b = GetByte(stream); num2++; if (b == 94) { throw new InvalidFormatException("Rar format version pre-4 is unsupported."); } } break; } } else { b = GetByte(stream); num2++; } } } catch (Exception inner) { if (!leaveStreamOpen) { stream.Dispose(); } throw new InvalidFormatException("Error trying to read rar signature.", inner); } throw new InvalidFormatException("Rar signature not found"); } } internal class NewSubHeaderType : IEquatable { internal static readonly NewSubHeaderType SUBHEAD_TYPE_CMT = new NewSubHeaderType('C', 'M', 'T'); internal static readonly NewSubHeaderType SUBHEAD_TYPE_RR = new NewSubHeaderType('R', 'R'); private readonly byte[] _bytes; private NewSubHeaderType(params char[] chars) { _bytes = new byte[chars.Length]; for (int i = 0; i < chars.Length; i++) { _bytes[i] = (byte)chars[i]; } } internal bool Equals(byte[] bytes) { if (_bytes.Length != bytes.Length) { return false; } for (int i = 0; i < bytes.Length; i++) { if (_bytes[i] != bytes[i]) { return false; } } return true; } public bool Equals(NewSubHeaderType other) { return Equals(other._bytes); } } internal class ProtectHeader : RarHeader { internal uint DataSize => checked((uint)base.AdditionalDataSize); internal byte Version { get; private set; } internal ushort RecSectors { get; private set; } internal uint TotalBlocks { get; private set; } internal byte[] Mark { get; private set; } public ProtectHeader(RarHeader header, RarCrcBinaryReader reader) : base(header, reader, HeaderType.Protect) { if (base.IsRar5) { throw new InvalidFormatException("unexpected rar5 record"); } } protected override void ReadFinish(MarkingBinaryReader reader) { Version = reader.ReadByte(); RecSectors = reader.ReadUInt16(); TotalBlocks = reader.ReadUInt32(); Mark = reader.ReadBytes(8); } } internal class RarHeader : IRarHeader { private readonly HeaderType _headerType; private readonly bool _isRar5; public HeaderType HeaderType => _headerType; protected bool IsRar5 => _isRar5; protected uint HeaderCrc { get; } internal byte HeaderCode { get; } protected ushort HeaderFlags { get; } protected int HeaderSize { get; } internal ArchiveEncoding ArchiveEncoding { get; } protected uint ExtraSize { get; } protected long AdditionalDataSize { get; } internal static RarHeader TryReadBase(RarCrcBinaryReader reader, bool isRar5, ArchiveEncoding archiveEncoding) { try { return new RarHeader(reader, isRar5, archiveEncoding); } catch (EndOfStreamException) { return null; } } private RarHeader(RarCrcBinaryReader reader, bool isRar5, ArchiveEncoding archiveEncoding) { _headerType = HeaderType.Null; _isRar5 = isRar5; ArchiveEncoding = archiveEncoding; if (IsRar5) { HeaderCrc = reader.ReadUInt32(); reader.ResetCrc(); HeaderSize = (int)reader.ReadRarVIntUInt32(3); reader.Mark(); HeaderCode = reader.ReadRarVIntByte(); HeaderFlags = reader.ReadRarVIntUInt16(2); if (HasHeaderFlag(1)) { ExtraSize = reader.ReadRarVIntUInt32(); } if (HasHeaderFlag(2)) { AdditionalDataSize = (long)reader.ReadRarVInt(); } } else { reader.Mark(); HeaderCrc = reader.ReadUInt16(); reader.ResetCrc(); HeaderCode = reader.ReadByte(); HeaderFlags = reader.ReadUInt16(); HeaderSize = reader.ReadInt16(); if (HasHeaderFlag(32768)) { AdditionalDataSize = reader.ReadUInt32(); } } } protected RarHeader(RarHeader header, RarCrcBinaryReader reader, HeaderType headerType) { _headerType = headerType; _isRar5 = header.IsRar5; HeaderCrc = header.HeaderCrc; HeaderCode = header.HeaderCode; HeaderFlags = header.HeaderFlags; HeaderSize = header.HeaderSize; ExtraSize = header.ExtraSize; AdditionalDataSize = header.AdditionalDataSize; ArchiveEncoding = header.ArchiveEncoding; ReadFinish(reader); int num = RemainingHeaderBytes(reader); if (num > 0) { reader.ReadBytes(num); } VerifyHeaderCrc(reader.GetCrc32()); } protected int RemainingHeaderBytes(MarkingBinaryReader reader) { return checked(HeaderSize - (int)reader.CurrentReadByteCount); } protected virtual void ReadFinish(MarkingBinaryReader reader) { throw new NotImplementedException(); } private void VerifyHeaderCrc(uint crc32) { if ((IsRar5 ? crc32 : ((ushort)crc32)) != HeaderCrc) { throw new InvalidFormatException("rar header crc mismatch"); } } protected bool HasHeaderFlag(ushort flag) { return (HeaderFlags & flag) == flag; } } internal class RarHeaderFactory { private bool _isRar5; private ReaderOptions Options { get; } internal StreamingMode StreamingMode { get; } internal bool IsEncrypted { get; private set; } internal RarHeaderFactory(StreamingMode mode, ReaderOptions options) { StreamingMode = mode; Options = options; } internal IEnumerable ReadHeaders(Stream stream) { MarkHeader markHeader = MarkHeader.Read(stream, Options.LeaveStreamOpen, Options.LookForHeader); _isRar5 = markHeader.IsRar5; yield return markHeader; RarHeader header; do { RarHeader rarHeader; header = (rarHeader = TryReadNextHeader(stream)); if (rarHeader != null) { yield return header; continue; } break; } while (header.HeaderType != HeaderType.EndArchive); } private RarHeader TryReadNextHeader(Stream stream) { RarCrcBinaryReader rarCrcBinaryReader; if (!IsEncrypted) { rarCrcBinaryReader = new RarCrcBinaryReader(stream); } else { if (Options.Password == null) { throw new CryptographicException("Encrypted Rar archive has no password specified."); } rarCrcBinaryReader = new RarCryptoBinaryReader(stream, Options.Password); } RarHeader rarHeader = RarHeader.TryReadBase(rarCrcBinaryReader, _isRar5, Options.ArchiveEncoding); if (rarHeader == null) { return null; } switch (rarHeader.HeaderCode) { case 1: case 115: { ArchiveHeader archiveHeader = new ArchiveHeader(rarHeader, rarCrcBinaryReader); if (archiveHeader.IsEncrypted == true) { IsEncrypted = true; } return archiveHeader; } case 120: { ProtectHeader protectHeader = new ProtectHeader(rarHeader, rarCrcBinaryReader); switch (StreamingMode) { case StreamingMode.Seekable: rarCrcBinaryReader.BaseStream.Position += protectHeader.DataSize; break; case StreamingMode.Streaming: rarCrcBinaryReader.BaseStream.Skip(protectHeader.DataSize); break; default: throw new InvalidFormatException("Invalid StreamingMode"); } return protectHeader; } case 3: { FileHeader fileHeader3 = new FileHeader(rarHeader, rarCrcBinaryReader, HeaderType.Service); SkipData(fileHeader3, rarCrcBinaryReader); return fileHeader3; } case 122: { FileHeader fileHeader2 = new FileHeader(rarHeader, rarCrcBinaryReader, HeaderType.NewSub); SkipData(fileHeader2, rarCrcBinaryReader); return fileHeader2; } case 2: case 116: { FileHeader fileHeader = new FileHeader(rarHeader, rarCrcBinaryReader, HeaderType.File); switch (StreamingMode) { case StreamingMode.Seekable: fileHeader.DataStartPosition = rarCrcBinaryReader.BaseStream.Position; rarCrcBinaryReader.BaseStream.Position += fileHeader.CompressedSize; break; case StreamingMode.Streaming: { ReadOnlySubStream readOnlySubStream = new ReadOnlySubStream(rarCrcBinaryReader.BaseStream, fileHeader.CompressedSize); if (fileHeader.R4Salt == null) { fileHeader.PackedStream = readOnlySubStream; } else { fileHeader.PackedStream = new RarCryptoWrapper(readOnlySubStream, Options.Password, fileHeader.R4Salt); } break; } default: throw new InvalidFormatException("Invalid StreamingMode"); } return fileHeader; } case 5: case 123: return new EndArchiveHeader(rarHeader, rarCrcBinaryReader); case 4: { ArchiveCryptHeader result = new ArchiveCryptHeader(rarHeader, rarCrcBinaryReader); IsEncrypted = true; return result; } default: throw new InvalidFormatException("Unknown Rar Header: " + rarHeader.HeaderCode); } } private void SkipData(FileHeader fh, RarCrcBinaryReader reader) { switch (StreamingMode) { case StreamingMode.Seekable: fh.DataStartPosition = reader.BaseStream.Position; reader.BaseStream.Position += fh.CompressedSize; break; case StreamingMode.Streaming: reader.BaseStream.Skip(fh.CompressedSize); break; default: throw new InvalidFormatException("Invalid StreamingMode"); } } } internal class SignHeader : RarHeader { internal int CreationTime { get; private set; } internal short ArcNameSize { get; private set; } internal short UserNameSize { get; private set; } protected SignHeader(RarHeader header, RarCrcBinaryReader reader) : base(header, reader, HeaderType.Sign) { if (base.IsRar5) { throw new InvalidFormatException("unexpected rar5 record"); } } protected override void ReadFinish(MarkingBinaryReader reader) { CreationTime = reader.ReadInt32(); ArcNameSize = reader.ReadInt16(); UserNameSize = reader.ReadInt16(); } } } namespace SharpCompress.Common.GZip { public class GZipEntry : Entry { private readonly GZipFilePart _filePart; public override CompressionType CompressionType => CompressionType.GZip; public override long Crc => 0L; public override string Key => _filePart.FilePartName; public override string LinkTarget => null; public override long CompressedSize => 0L; public override long Size => 0L; public override DateTime? LastModifiedTime => _filePart.DateModified; public override DateTime? CreatedTime => null; public override DateTime? LastAccessedTime => null; public override DateTime? ArchivedTime => null; public override bool IsEncrypted => false; public override bool IsDirectory => false; public override bool IsSplitAfter => false; internal override IEnumerable Parts => ((FilePart)_filePart).AsEnumerable(); internal GZipEntry(GZipFilePart filePart) { _filePart = filePart; } internal static IEnumerable GetEntries(Stream stream, OptionsBase options) { yield return new GZipEntry(new GZipFilePart(stream, options.ArchiveEncoding)); } } internal class GZipFilePart : FilePart { private string _name; private readonly Stream _stream; internal long EntryStartPosition { get; } internal DateTime? DateModified { get; private set; } internal override string FilePartName => _name; internal GZipFilePart(Stream stream, ArchiveEncoding archiveEncoding) : base(archiveEncoding) { ReadAndValidateGzipHeader(stream); EntryStartPosition = stream.Position; _stream = stream; } internal override Stream GetCompressedStream() { return new DeflateStream(_stream, CompressionMode.Decompress); } internal override Stream GetRawStream() { return _stream; } private void ReadAndValidateGzipHeader(Stream stream) { byte[] array = new byte[10]; switch (stream.Read(array, 0, array.Length)) { case 0: break; default: throw new ZlibException("Not a valid GZIP stream."); case 10: { if (array[0] != 31 || array[1] != 139 || array[2] != 8) { throw new ZlibException("Bad GZIP header."); } int @int = DataConverter.LittleEndian.GetInt32(array, 4); DateTime ePOCH = TarHeader.EPOCH; DateModified = ePOCH.AddSeconds(@int); if ((array[3] & 4) == 4) { int num = stream.Read(array, 0, 2); short num2 = (short)(array[0] + array[1] * 256); byte[] buffer = new byte[num2]; if (!stream.ReadFully(buffer)) { throw new ZlibException("Unexpected end-of-file reading GZIP header."); } num = num2; } if ((array[3] & 8) == 8) { _name = ReadZeroTerminatedString(stream); } if ((array[3] & 0x10) == 16) { ReadZeroTerminatedString(stream); } if ((array[3] & 2) == 2) { stream.ReadByte(); } break; } } } private string ReadZeroTerminatedString(Stream stream) { byte[] array = new byte[1]; List list = new List(); bool flag = false; do { if (stream.Read(array, 0, 1) != 1) { throw new ZlibException("Unexpected EOF reading GZIP header."); } if (array[0] == 0) { flag = true; } else { list.Add(array[0]); } } while (!flag); byte[] bytes = list.ToArray(); return base.ArchiveEncoding.Decode(bytes); } } public class GZipVolume : Volume { public override bool IsFirstVolume => true; public override bool IsMultiVolume => true; public GZipVolume(Stream stream, ReaderOptions options) : base(stream, options) { } public GZipVolume(FileInfo fileInfo, ReaderOptions options) : base(fileInfo.OpenRead(), options) { options.LeaveStreamOpen = false; } } } namespace SharpCompress.Archives { public abstract class AbstractArchive : IArchive, IDisposable, IArchiveExtractionListener, IExtractionListener where TEntry : IArchiveEntry where TVolume : IVolume { private readonly LazyReadOnlyCollection lazyVolumes; private readonly LazyReadOnlyCollection lazyEntries; private bool disposed; protected ReaderOptions ReaderOptions { get; } public ArchiveType Type { get; } public virtual ICollection Entries => lazyEntries; public ICollection Volumes => lazyVolumes; public virtual long TotalSize => Entries.Aggregate(0L, (long total, TEntry cf) => total + cf.CompressedSize); public virtual long TotalUncompressSize => Entries.Aggregate(0L, (long total, TEntry cf) => total + cf.Size); IEnumerable IArchive.Entries => Entries.Cast(); IEnumerable IArchive.Volumes => lazyVolumes.Cast(); public virtual bool IsSolid => false; public bool IsComplete { get { ((IArchiveExtractionListener)this).EnsureEntriesLoaded(); return Entries.All((TEntry x) => x.IsComplete); } } public event EventHandler> EntryExtractionBegin; public event EventHandler> EntryExtractionEnd; public event EventHandler CompressedBytesRead; public event EventHandler FilePartExtractionBegin; internal AbstractArchive(ArchiveType type, FileInfo fileInfo, ReaderOptions readerOptions) { Type = type; if (!fileInfo.Exists) { throw new ArgumentException("File does not exist: " + fileInfo.FullName); } ReaderOptions = readerOptions; readerOptions.LeaveStreamOpen = false; lazyVolumes = new LazyReadOnlyCollection(LoadVolumes(fileInfo)); lazyEntries = new LazyReadOnlyCollection(LoadEntries(Volumes)); } protected abstract IEnumerable LoadVolumes(FileInfo file); internal AbstractArchive(ArchiveType type, IEnumerable streams, ReaderOptions readerOptions) { Type = type; ReaderOptions = readerOptions; lazyVolumes = new LazyReadOnlyCollection(LoadVolumes(streams.Select(CheckStreams))); lazyEntries = new LazyReadOnlyCollection(LoadEntries(Volumes)); } internal AbstractArchive(ArchiveType type) { Type = type; lazyVolumes = new LazyReadOnlyCollection(Enumerable.Empty()); lazyEntries = new LazyReadOnlyCollection(Enumerable.Empty()); } void IArchiveExtractionListener.FireEntryExtractionBegin(IArchiveEntry entry) { this.EntryExtractionBegin?.Invoke(this, new ArchiveExtractionEventArgs(entry)); } void IArchiveExtractionListener.FireEntryExtractionEnd(IArchiveEntry entry) { this.EntryExtractionEnd?.Invoke(this, new ArchiveExtractionEventArgs(entry)); } private static Stream CheckStreams(Stream stream) { if (!stream.CanSeek || !stream.CanRead) { throw new ArgumentException("Archive streams must be Readable and Seekable"); } return stream; } protected abstract IEnumerable LoadVolumes(IEnumerable streams); protected abstract IEnumerable LoadEntries(IEnumerable volumes); public virtual void Dispose() { if (!disposed) { lazyVolumes.ForEach(delegate(TVolume v) { v.Dispose(); }); lazyEntries.GetLoaded().Cast().ForEach(delegate(Entry x) { x.Close(); }); disposed = true; } } void IArchiveExtractionListener.EnsureEntriesLoaded() { lazyEntries.EnsureFullyLoaded(); lazyVolumes.EnsureFullyLoaded(); } void IExtractionListener.FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes) { this.CompressedBytesRead?.Invoke(this, new CompressedBytesReadEventArgs { CurrentFilePartCompressedBytesRead = currentPartCompressedBytes, CompressedBytesRead = compressedReadBytes }); } void IExtractionListener.FireFilePartExtractionBegin(string name, long size, long compressedSize) { this.FilePartExtractionBegin?.Invoke(this, new FilePartExtractionBeginEventArgs { CompressedSize = compressedSize, Size = size, Name = name }); } public IReader ExtractAllEntries() { ((IArchiveExtractionListener)this).EnsureEntriesLoaded(); return CreateReaderForSolidExtraction(); } protected abstract IReader CreateReaderForSolidExtraction(); } public abstract class AbstractWritableArchive : AbstractArchive, IWritableArchive, IArchive, IDisposable where TEntry : IArchiveEntry where TVolume : IVolume { private readonly List newEntries = new List(); private readonly List removedEntries = new List(); private readonly List modifiedEntries = new List(); private bool hasModifications; public override ICollection Entries { get { if (hasModifications) { return modifiedEntries; } return base.Entries; } } private IEnumerable OldEntries => base.Entries.Where((TEntry x) => !removedEntries.Contains(x)); internal AbstractWritableArchive(ArchiveType type) : base(type) { } internal AbstractWritableArchive(ArchiveType type, Stream stream, ReaderOptions readerFactoryOptions) : base(type, stream.AsEnumerable(), readerFactoryOptions) { } internal AbstractWritableArchive(ArchiveType type, FileInfo fileInfo, ReaderOptions readerFactoryOptions) : base(type, fileInfo, readerFactoryOptions) { } private void RebuildModifiedCollection() { hasModifications = true; newEntries.RemoveAll((TEntry v) => removedEntries.Contains(v)); modifiedEntries.Clear(); modifiedEntries.AddRange(OldEntries.Concat(newEntries)); } public void RemoveEntry(TEntry entry) { if (!removedEntries.Contains(entry)) { removedEntries.Add(entry); RebuildModifiedCollection(); } } void IWritableArchive.RemoveEntry(IArchiveEntry entry) { RemoveEntry((TEntry)entry); } public TEntry AddEntry(string key, Stream source, long size = 0L, DateTime? modified = null) { return AddEntry(key, source, closeStream: false, size, modified); } IArchiveEntry IWritableArchive.AddEntry(string key, Stream source, bool closeStream, long size, DateTime? modified) { return AddEntry(key, source, closeStream, size, modified); } public TEntry AddEntry(string key, Stream source, bool closeStream, long size = 0L, DateTime? modified = null) { if (key.StartsWith("/") || key.StartsWith("\\")) { key = key.Substring(1); } if (DoesKeyMatchExisting(key)) { throw new ArchiveException("Cannot add entry with duplicate key: " + key); } TEntry val = CreateEntry(key, source, size, modified, closeStream); newEntries.Add(val); RebuildModifiedCollection(); return val; } private bool DoesKeyMatchExisting(string key) { using (IEnumerator enumerator = Entries.Select((TEntry x) => x.Key).GetEnumerator()) { if (enumerator.MoveNext()) { string text = enumerator.Current.Replace('/', '\\'); if (text.StartsWith("\\")) { text = text.Substring(1); } return string.Equals(text, key, StringComparison.OrdinalIgnoreCase); } } return false; } public void SaveTo(Stream stream, WriterOptions options) { newEntries.Cast().ForEach(delegate(IWritableArchiveEntry x) { x.Stream.Seek(0L, SeekOrigin.Begin); }); SaveTo(stream, options, OldEntries, newEntries); } protected TEntry CreateEntry(string key, Stream source, long size, DateTime? modified, bool closeStream) { if (!source.CanRead || !source.CanSeek) { throw new ArgumentException("Streams must be readable and seekable to use the Writing Archive API"); } return CreateEntryInternal(key, source, size, modified, closeStream); } protected abstract TEntry CreateEntryInternal(string key, Stream source, long size, DateTime? modified, bool closeStream); protected abstract void SaveTo(Stream stream, WriterOptions options, IEnumerable oldEntries, IEnumerable newEntries); public override void Dispose() { base.Dispose(); newEntries.Cast().ForEach(delegate(Entry x) { x.Close(); }); removedEntries.Cast().ForEach(delegate(Entry x) { x.Close(); }); modifiedEntries.Cast().ForEach(delegate(Entry x) { x.Close(); }); } } public class ArchiveFactory { public static IArchive Open(Stream stream, ReaderOptions readerOptions = null) { stream.CheckNotNull("stream"); if (!stream.CanRead || !stream.CanSeek) { throw new ArgumentException("Stream should be readable and seekable"); } readerOptions = readerOptions ?? new ReaderOptions(); if (ZipArchive.IsZipFile(stream)) { stream.Seek(0L, SeekOrigin.Begin); return ZipArchive.Open(stream, readerOptions); } stream.Seek(0L, SeekOrigin.Begin); if (SevenZipArchive.IsSevenZipFile(stream)) { stream.Seek(0L, SeekOrigin.Begin); return SevenZipArchive.Open(stream, readerOptions); } stream.Seek(0L, SeekOrigin.Begin); if (GZipArchive.IsGZipFile(stream)) { stream.Seek(0L, SeekOrigin.Begin); return GZipArchive.Open(stream, readerOptions); } stream.Seek(0L, SeekOrigin.Begin); if (RarArchive.IsRarFile(stream, readerOptions)) { stream.Seek(0L, SeekOrigin.Begin); return RarArchive.Open(stream, readerOptions); } stream.Seek(0L, SeekOrigin.Begin); if (TarArchive.IsTarFile(stream)) { stream.Seek(0L, SeekOrigin.Begin); return TarArchive.Open(stream, readerOptions); } throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip, LZip"); } public static IWritableArchive Create(ArchiveType type) { return type switch { ArchiveType.Zip => ZipArchive.Create(), ArchiveType.Tar => TarArchive.Create(), ArchiveType.GZip => GZipArchive.Create(), _ => throw new NotSupportedException("Cannot create Archives of type: " + type), }; } public static IArchive Open(string filePath, ReaderOptions options = null) { filePath.CheckNotNullOrEmpty("filePath"); return Open(new FileInfo(filePath), options); } public static IArchive Open(FileInfo fileInfo, ReaderOptions options = null) { fileInfo.CheckNotNull("fileInfo"); options = options ?? new ReaderOptions { LeaveStreamOpen = false }; using FileStream fileStream = fileInfo.OpenRead(); if (ZipArchive.IsZipFile(fileStream)) { return ZipArchive.Open(fileInfo, options); } fileStream.Seek(0L, SeekOrigin.Begin); if (SevenZipArchive.IsSevenZipFile(fileStream)) { return SevenZipArchive.Open(fileInfo, options); } fileStream.Seek(0L, SeekOrigin.Begin); if (GZipArchive.IsGZipFile(fileStream)) { return GZipArchive.Open(fileInfo, options); } fileStream.Seek(0L, SeekOrigin.Begin); if (RarArchive.IsRarFile(fileStream, options)) { return RarArchive.Open(fileInfo, options); } fileStream.Seek(0L, SeekOrigin.Begin); if (TarArchive.IsTarFile(fileStream)) { return TarArchive.Open(fileInfo, options); } throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip"); } public static void WriteToDirectory(string sourceArchive, string destinationDirectory, ExtractionOptions options = null) { using IArchive archive = Open(sourceArchive); foreach (IArchiveEntry entry in archive.Entries) { entry.WriteToDirectory(destinationDirectory, options); } } } public interface IArchive : IDisposable { IEnumerable Entries { get; } IEnumerable Volumes { get; } ArchiveType Type { get; } bool IsSolid { get; } bool IsComplete { get; } long TotalSize { get; } long TotalUncompressSize { get; } event EventHandler> EntryExtractionBegin; event EventHandler> EntryExtractionEnd; event EventHandler CompressedBytesRead; event EventHandler FilePartExtractionBegin; IReader ExtractAllEntries(); } public interface IArchiveEntry : IEntry { bool IsComplete { get; } IArchive Archive { get; } Stream OpenEntryStream(); } public static class IArchiveEntryExtensions { public static void WriteTo(this IArchiveEntry archiveEntry, Stream streamToWriteTo) { if (archiveEntry.Archive.Type == ArchiveType.Rar && archiveEntry.Archive.IsSolid) { throw new InvalidFormatException("Cannot use Archive random access on SOLID Rar files."); } if (archiveEntry.IsDirectory) { throw new ExtractionException("Entry is a file directory and cannot be extracted."); } IArchiveExtractionListener archiveExtractionListener = archiveEntry.Archive as IArchiveExtractionListener; archiveExtractionListener.EnsureEntriesLoaded(); archiveExtractionListener.FireEntryExtractionBegin(archiveEntry); archiveExtractionListener.FireFilePartExtractionBegin(archiveEntry.Key, archiveEntry.Size, archiveEntry.CompressedSize); Stream stream = archiveEntry.OpenEntryStream(); if (stream == null) { return; } using (stream) { using Stream source = new ListeningStream(archiveExtractionListener, stream); source.TransferTo(streamToWriteTo); } archiveExtractionListener.FireEntryExtractionEnd(archiveEntry); } public static void WriteToDirectory(this IArchiveEntry entry, string destinationDirectory, ExtractionOptions options = null) { ExtractionMethods.WriteEntryToDirectory(entry, destinationDirectory, options, entry.WriteToFile); } public static void WriteToFile(this IArchiveEntry entry, string destinationFileName, ExtractionOptions options = null) { ExtractionMethods.WriteEntryToFile(entry, destinationFileName, options, delegate(string x, FileMode fm) { using FileStream streamToWriteTo = File.Open(destinationFileName, fm); entry.WriteTo(streamToWriteTo); }); } } public static class IArchiveExtensions { public static void WriteToDirectory(this IArchive archive, string destinationDirectory, ExtractionOptions options = null) { foreach (IArchiveEntry item in archive.Entries.Where((IArchiveEntry x) => !x.IsDirectory)) { item.WriteToDirectory(destinationDirectory, options); } } } internal interface IArchiveExtractionListener : IExtractionListener { void EnsureEntriesLoaded(); void FireEntryExtractionBegin(IArchiveEntry entry); void FireEntryExtractionEnd(IArchiveEntry entry); } public interface IWritableArchive : IArchive, IDisposable { void RemoveEntry(IArchiveEntry entry); IArchiveEntry AddEntry(string key, Stream source, bool closeStream, long size = 0L, DateTime? modified = null); void SaveTo(Stream stream, WriterOptions options); } internal interface IWritableArchiveEntry { Stream Stream { get; } } public static class IWritableArchiveExtensions { public static void AddEntry(this IWritableArchive writableArchive, string entryPath, string filePath) { FileInfo fileInfo = new FileInfo(filePath); if (!fileInfo.Exists) { throw new FileNotFoundException("Could not AddEntry: " + filePath); } writableArchive.AddEntry(entryPath, new FileInfo(filePath).OpenRead(), closeStream: true, fileInfo.Length, fileInfo.LastWriteTime); } public static void SaveTo(this IWritableArchive writableArchive, string filePath, WriterOptions options) { writableArchive.SaveTo(new FileInfo(filePath), options); } public static void SaveTo(this IWritableArchive writableArchive, FileInfo fileInfo, WriterOptions options) { using FileStream stream = fileInfo.Open(FileMode.Create, FileAccess.Write); writableArchive.SaveTo(stream, options); } public static void AddAllFromDirectory(this IWritableArchive writableArchive, string filePath, string searchPattern = "*.*", SearchOption searchOption = SearchOption.AllDirectories) { foreach (string item in Directory.EnumerateFiles(filePath, searchPattern, searchOption)) { FileInfo fileInfo = new FileInfo(item); writableArchive.AddEntry(item.Substring(filePath.Length), fileInfo.OpenRead(), closeStream: true, fileInfo.Length, fileInfo.LastWriteTime); } } public static IArchiveEntry AddEntry(this IWritableArchive writableArchive, string key, FileInfo fileInfo) { if (!fileInfo.Exists) { throw new ArgumentException("FileInfo does not exist."); } return writableArchive.AddEntry(key, fileInfo.OpenRead(), closeStream: true, fileInfo.Length, fileInfo.LastWriteTime); } } } namespace SharpCompress.Archives.Zip { public class ZipArchive : AbstractWritableArchive { private readonly SeekableZipHeaderFactory headerFactory; public CompressionLevel DeflateCompressionLevel { get; set; } public static ZipArchive Open(string filePath, ReaderOptions readerOptions = null) { filePath.CheckNotNullOrEmpty("filePath"); return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions()); } public static ZipArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null) { fileInfo.CheckNotNull("fileInfo"); return new ZipArchive(fileInfo, readerOptions ?? new ReaderOptions()); } public static ZipArchive Open(Stream stream, ReaderOptions readerOptions = null) { stream.CheckNotNull("stream"); return new ZipArchive(stream, readerOptions ?? new ReaderOptions()); } public static bool IsZipFile(string filePath, string password = null) { return IsZipFile(new FileInfo(filePath), password); } public static bool IsZipFile(FileInfo fileInfo, string password = null) { if (!fileInfo.Exists) { return false; } using Stream stream = fileInfo.OpenRead(); return IsZipFile(stream, password); } public static bool IsZipFile(Stream stream, string password = null) { StreamingZipHeaderFactory streamingZipHeaderFactory = new StreamingZipHeaderFactory(password, new ArchiveEncoding()); try { ZipHeader zipHeader = streamingZipHeaderFactory.ReadStreamHeader(stream).FirstOrDefault((ZipHeader x) => x.ZipHeaderType != ZipHeaderType.Split); if (zipHeader == null) { return false; } return Enum.IsDefined(typeof(ZipHeaderType), zipHeader.ZipHeaderType); } catch (SharpCompress.Common.CryptographicException) { return true; } catch { return false; } } internal ZipArchive(FileInfo fileInfo, ReaderOptions readerOptions) : base(ArchiveType.Zip, fileInfo, readerOptions) { headerFactory = new SeekableZipHeaderFactory(readerOptions.Password, readerOptions.ArchiveEncoding); } protected override IEnumerable LoadVolumes(FileInfo file) { return new ZipVolume(file.OpenRead(), base.ReaderOptions).AsEnumerable(); } internal ZipArchive() : base(ArchiveType.Zip) { } internal ZipArchive(Stream stream, ReaderOptions readerOptions) : base(ArchiveType.Zip, stream, readerOptions) { headerFactory = new SeekableZipHeaderFactory(readerOptions.Password, readerOptions.ArchiveEncoding); } protected override IEnumerable LoadVolumes(IEnumerable streams) { return new ZipVolume(streams.First(), base.ReaderOptions).AsEnumerable(); } protected override IEnumerable LoadEntries(IEnumerable volumes) { ZipVolume volume = volumes.Single(); Stream stream = volume.Stream; foreach (ZipHeader item in headerFactory.ReadSeekableHeader(stream)) { if (item != null) { switch (item.ZipHeaderType) { case ZipHeaderType.DirectoryEntry: yield return new ZipArchiveEntry(this, new SeekableZipFilePart(headerFactory, item as DirectoryEntryHeader, stream)); break; case ZipHeaderType.DirectoryEnd: { byte[] comment = (item as DirectoryEndHeader).Comment; volume.Comment = base.ReaderOptions.ArchiveEncoding.Decode(comment); yield break; } } } } } public void SaveTo(Stream stream) { SaveTo(stream, new WriterOptions(CompressionType.Deflate)); } protected override void SaveTo(Stream stream, WriterOptions options, IEnumerable oldEntries, IEnumerable newEntries) { using ZipWriter zipWriter = new ZipWriter(stream, new ZipWriterOptions(options)); foreach (ZipArchiveEntry item in from x in oldEntries.Concat(newEntries) where !x.IsDirectory select x) { using Stream source = item.OpenEntryStream(); zipWriter.Write(item.Key, source, item.LastModifiedTime); } } protected override ZipArchiveEntry CreateEntryInternal(string filePath, Stream source, long size, DateTime? modified, bool closeStream) { return new ZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream); } public static ZipArchive Create() { return new ZipArchive(); } protected override IReader CreateReaderForSolidExtraction() { Stream stream = base.Volumes.Single().Stream; stream.Position = 0L; return ZipReader.Open(stream, base.ReaderOptions); } } public class ZipArchiveEntry : ZipEntry, IArchiveEntry, IEntry { public IArchive Archive { get; } public bool IsComplete => true; public string Comment => (Parts.Single() as SeekableZipFilePart).Comment; internal ZipArchiveEntry(ZipArchive archive, SeekableZipFilePart part) : base(part) { Archive = archive; } public virtual Stream OpenEntryStream() { return Parts.Single().GetCompressedStream(); } } internal class ZipWritableArchiveEntry : ZipArchiveEntry, IWritableArchiveEntry { private readonly bool closeStream; private readonly Stream stream; private bool isDisposed; public override long Crc => 0L; public override string Key { get; } public override long CompressedSize => 0L; public override long Size { get; } public override DateTime? LastModifiedTime { get; } public override DateTime? CreatedTime => null; public override DateTime? LastAccessedTime => null; public override DateTime? ArchivedTime => null; public override bool IsEncrypted => false; public override bool IsDirectory => false; public override bool IsSplitAfter => false; internal override IEnumerable Parts { get { throw new NotImplementedException(); } } Stream IWritableArchiveEntry.Stream => stream; internal ZipWritableArchiveEntry(ZipArchive archive, Stream stream, string path, long size, DateTime? lastModified, bool closeStream) : base(archive, null) { this.stream = stream; Key = path; Size = size; LastModifiedTime = lastModified; this.closeStream = closeStream; } public override Stream OpenEntryStream() { stream.Seek(0L, SeekOrigin.Begin); return new NonDisposingStream(stream); } internal override void Close() { if (closeStream && !isDisposed) { stream.Dispose(); isDisposed = true; } } } } namespace SharpCompress.Archives.Tar { public class TarArchive : AbstractWritableArchive { public static TarArchive Open(string filePath, ReaderOptions readerOptions = null) { filePath.CheckNotNullOrEmpty("filePath"); return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions()); } public static TarArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null) { fileInfo.CheckNotNull("fileInfo"); return new TarArchive(fileInfo, readerOptions ?? new ReaderOptions()); } public static TarArchive Open(Stream stream, ReaderOptions readerOptions = null) { stream.CheckNotNull("stream"); return new TarArchive(stream, readerOptions ?? new ReaderOptions()); } public static bool IsTarFile(string filePath) { return IsTarFile(new FileInfo(filePath)); } public static bool IsTarFile(FileInfo fileInfo) { if (!fileInfo.Exists) { return false; } using Stream stream = fileInfo.OpenRead(); return IsTarFile(stream); } public static bool IsTarFile(Stream stream) { try { TarHeader tarHeader = new TarHeader(new ArchiveEncoding()); bool num = tarHeader.Read(new BinaryReader(stream)); bool flag = tarHeader.Name.Length == 0 && tarHeader.Size == 0L && Enum.IsDefined(typeof(EntryType), tarHeader.EntryType); return num || flag; } catch { } return false; } internal TarArchive(FileInfo fileInfo, ReaderOptions readerOptions) : base(ArchiveType.Tar, fileInfo, readerOptions) { } protected override IEnumerable LoadVolumes(FileInfo file) { return new TarVolume(file.OpenRead(), base.ReaderOptions).AsEnumerable(); } internal TarArchive(Stream stream, ReaderOptions readerOptions) : base(ArchiveType.Tar, stream, readerOptions) { } internal TarArchive() : base(ArchiveType.Tar) { } protected override IEnumerable LoadVolumes(IEnumerable streams) { return new TarVolume(streams.First(), base.ReaderOptions).AsEnumerable(); } protected override IEnumerable LoadEntries(IEnumerable volumes) { Stream stream = volumes.Single().Stream; TarHeader previousHeader = null; foreach (TarHeader item in TarHeaderFactory.ReadHeader(StreamingMode.Seekable, stream, base.ReaderOptions.ArchiveEncoding)) { if (item == null) { continue; } if (item.EntryType == EntryType.LongName) { previousHeader = item; continue; } if (previousHeader != null) { TarArchiveEntry tarArchiveEntry = new TarArchiveEntry(this, new TarFilePart(previousHeader, stream), CompressionType.None); long position = stream.Position; using (Stream source = tarArchiveEntry.OpenEntryStream()) { using MemoryStream memoryStream = new MemoryStream(); source.TransferTo(memoryStream); memoryStream.Position = 0L; byte[] bytes = memoryStream.ToArray(); item.Name = base.ReaderOptions.ArchiveEncoding.Decode(bytes).TrimNulls(); } stream.Position = position; previousHeader = null; } yield return new TarArchiveEntry(this, new TarFilePart(item, stream), CompressionType.None); } } public static TarArchive Create() { return new TarArchive(); } protected override TarArchiveEntry CreateEntryInternal(string filePath, Stream source, long size, DateTime? modified, bool closeStream) { return new TarWritableArchiveEntry(this, source, CompressionType.Unknown, filePath, size, modified, closeStream); } protected override void SaveTo(Stream stream, WriterOptions options, IEnumerable oldEntries, IEnumerable newEntries) { using TarWriter tarWriter = new TarWriter(stream, new TarWriterOptions(options)); foreach (TarArchiveEntry item in from x in oldEntries.Concat(newEntries) where !x.IsDirectory select x) { using Stream source = item.OpenEntryStream(); tarWriter.Write(item.Key, source, item.LastModifiedTime, item.Size); } } protected override IReader CreateReaderForSolidExtraction() { Stream stream = base.Volumes.Single().Stream; stream.Position = 0L; return TarReader.Open(stream); } } public class TarArchiveEntry : TarEntry, IArchiveEntry, IEntry { public IArchive Archive { get; } public bool IsComplete => true; internal TarArchiveEntry(TarArchive archive, TarFilePart part, CompressionType compressionType) : base(part, compressionType) { Archive = archive; } public virtual Stream OpenEntryStream() { return Parts.Single().GetCompressedStream(); } } internal class TarWritableArchiveEntry : TarArchiveEntry, IWritableArchiveEntry { private readonly bool closeStream; private readonly Stream stream; public override long Crc => 0L; public override string Key { get; } public override long CompressedSize => 0L; public override long Size { get; } public override DateTime? LastModifiedTime { get; } public override DateTime? CreatedTime => null; public override DateTime? LastAccessedTime => null; public override DateTime? ArchivedTime => null; public override bool IsEncrypted => false; public override bool IsDirectory => false; public override bool IsSplitAfter => false; internal override IEnumerable Parts { get { throw new NotImplementedException(); } } Stream IWritableArchiveEntry.Stream => stream; internal TarWritableArchiveEntry(TarArchive archive, Stream stream, CompressionType compressionType, string path, long size, DateTime? lastModified, bool closeStream) : base(archive, null, compressionType) { this.stream = stream; Key = path; Size = size; LastModifiedTime = lastModified; this.closeStream = closeStream; } public override Stream OpenEntryStream() { stream.Seek(0L, SeekOrigin.Begin); return new NonDisposingStream(stream); } internal override void Close() { if (closeStream) { stream.Dispose(); } } } } namespace SharpCompress.Archives.SevenZip { public class SevenZipArchive : AbstractArchive { private class SevenZipReader : AbstractReader { private readonly SevenZipArchive archive; private CFolder currentFolder; private Stream currentStream; private CFileItem currentItem; public override SevenZipVolume Volume => archive.Volumes.Single(); internal SevenZipReader(ReaderOptions readerOptions, SevenZipArchive archive) : base(readerOptions, ArchiveType.SevenZip) { this.archive = archive; } protected override IEnumerable GetEntries(Stream stream) { List entries = archive.Entries.ToList(); stream.Position = 0L; foreach (SevenZipArchiveEntry item in entries.Where((SevenZipArchiveEntry x) => x.IsDirectory)) { yield return item; } foreach (IGrouping item2 in from x in entries where !x.IsDirectory group x by x.FilePart.Folder) { currentFolder = item2.Key; if (item2.Key == null) { currentStream = Stream.Null; } else { currentStream = archive.database.GetFolderStream(stream, currentFolder, new PasswordProvider(base.Options.Password)); } foreach (SevenZipArchiveEntry item3 in item2) { currentItem = item3.FilePart.Header; yield return item3; } } } protected override EntryStream GetEntryStream() { return CreateEntryStream(new ReadOnlySubStream(currentStream, currentItem.Size)); } } private class PasswordProvider : IPasswordProvider { private readonly string _password; public PasswordProvider(string password) { _password = password; } public string CryptoGetTextPassword() { return _password; } } private ArchiveDatabase database; private static readonly byte[] SIGNATURE = new byte[6] { 55, 122, 188, 175, 39, 28 }; public override bool IsSolid => (from x in Entries where !x.IsDirectory group x by x.FilePart.Folder).Count() > 1; public override long TotalSize { get { _ = Entries.Count; return database._packSizes.Aggregate(0L, (long total, long packSize) => total + packSize); } } public static SevenZipArchive Open(string filePath, ReaderOptions readerOptions = null) { filePath.CheckNotNullOrEmpty("filePath"); return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions()); } public static SevenZipArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null) { fileInfo.CheckNotNull("fileInfo"); return new SevenZipArchive(fileInfo, readerOptions ?? new ReaderOptions()); } public static SevenZipArchive Open(Stream stream, ReaderOptions readerOptions = null) { stream.CheckNotNull("stream"); return new SevenZipArchive(stream, readerOptions ?? new ReaderOptions()); } internal SevenZipArchive(FileInfo fileInfo, ReaderOptions readerOptions) : base(ArchiveType.SevenZip, fileInfo, readerOptions) { } protected override IEnumerable LoadVolumes(FileInfo file) { return new SevenZipVolume(file.OpenRead(), base.ReaderOptions).AsEnumerable(); } public static bool IsSevenZipFile(string filePath) { return IsSevenZipFile(new FileInfo(filePath)); } public static bool IsSevenZipFile(FileInfo fileInfo) { if (!fileInfo.Exists) { return false; } using Stream stream = fileInfo.OpenRead(); return IsSevenZipFile(stream); } internal SevenZipArchive(Stream stream, ReaderOptions readerOptions) : base(ArchiveType.SevenZip, stream.AsEnumerable(), readerOptions) { } internal SevenZipArchive() : base(ArchiveType.SevenZip) { } protected override IEnumerable LoadVolumes(IEnumerable streams) { foreach (Stream stream in streams) { if (!stream.CanRead || !stream.CanSeek) { throw new ArgumentException("Stream is not readable and seekable"); } yield return new SevenZipVolume(stream, base.ReaderOptions); } } protected override IEnumerable LoadEntries(IEnumerable volumes) { Stream stream = volumes.Single().Stream; LoadFactory(stream); for (int i = 0; i < database._files.Count; i++) { CFileItem fileEntry = database._files[i]; yield return new SevenZipArchiveEntry(this, new SevenZipFilePart(stream, database, i, fileEntry, base.ReaderOptions.ArchiveEncoding)); } } private void LoadFactory(Stream stream) { if (database == null) { stream.Position = 0L; ArchiveReader archiveReader = new ArchiveReader(); archiveReader.Open(stream); database = archiveReader.ReadDatabase(new PasswordProvider(base.ReaderOptions.Password)); } } public static bool IsSevenZipFile(Stream stream) { try { return SignatureMatch(stream); } catch { return false; } } private static bool SignatureMatch(Stream stream) { return new BinaryReader(stream).ReadBytes(6).BinaryEquals(SIGNATURE); } protected override IReader CreateReaderForSolidExtraction() { return new SevenZipReader(base.ReaderOptions, this); } } public class SevenZipArchiveEntry : SevenZipEntry, IArchiveEntry, IEntry { public IArchive Archive { get; } public bool IsComplete => true; public bool IsAnti => base.FilePart.Header.IsAnti; internal SevenZipArchiveEntry(SevenZipArchive archive, SevenZipFilePart part) : base(part) { Archive = archive; } public Stream OpenEntryStream() { return base.FilePart.GetCompressedStream(); } } } namespace SharpCompress.Archives.Rar { internal class FileInfoRarArchiveVolume : RarVolume { internal ReadOnlyCollection FileParts { get; } internal FileInfo FileInfo { get; } internal FileInfoRarArchiveVolume(FileInfo fileInfo, ReaderOptions options) : base(StreamingMode.Seekable, fileInfo.OpenRead(), FixOptions(options)) { FileInfo = fileInfo; FileParts = GetVolumeFileParts().ToReadOnly(); } private static ReaderOptions FixOptions(ReaderOptions options) { options.LeaveStreamOpen = false; return options; } internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) { return new FileInfoRarFilePart(this, base.ReaderOptions.Password, markHeader, fileHeader, FileInfo); } internal override IEnumerable ReadFileParts() { return FileParts; } } internal class FileInfoRarFilePart : SeekableFilePart { internal FileInfo FileInfo { get; } internal override string FilePartName => "Rar File: " + FileInfo.FullName + " File Entry: " + base.FileHeader.FileName; internal FileInfoRarFilePart(FileInfoRarArchiveVolume volume, string password, MarkHeader mh, FileHeader fh, FileInfo fi) : base(mh, fh, volume.Stream, password) { FileInfo = fi; } } public class RarArchive : AbstractArchive { internal Lazy UnpackV2017 { get; } = new Lazy(() => new SharpCompress.Compressors.Rar.UnpackV2017.Unpack()); internal Lazy UnpackV1 { get; } = new Lazy(() => new SharpCompress.Compressors.Rar.UnpackV1.Unpack()); public override bool IsSolid => base.Volumes.First().IsSolidArchive; internal RarArchive(FileInfo fileInfo, ReaderOptions options) : base(ArchiveType.Rar, fileInfo, options) { } protected override IEnumerable LoadVolumes(FileInfo file) { return RarArchiveVolumeFactory.GetParts(file, base.ReaderOptions); } internal RarArchive(IEnumerable streams, ReaderOptions options) : base(ArchiveType.Rar, streams, options) { } protected override IEnumerable LoadEntries(IEnumerable volumes) { return RarArchiveEntryFactory.GetEntries(this, volumes); } protected override IEnumerable LoadVolumes(IEnumerable streams) { return RarArchiveVolumeFactory.GetParts(streams, base.ReaderOptions); } protected override IReader CreateReaderForSolidExtraction() { Stream stream = base.Volumes.First().Stream; stream.Position = 0L; return RarReader.Open(stream, base.ReaderOptions); } public static RarArchive Open(string filePath, ReaderOptions options = null) { filePath.CheckNotNullOrEmpty("filePath"); return new RarArchive(new FileInfo(filePath), options ?? new ReaderOptions()); } public static RarArchive Open(FileInfo fileInfo, ReaderOptions options = null) { fileInfo.CheckNotNull("fileInfo"); return new RarArchive(fileInfo, options ?? new ReaderOptions()); } public static RarArchive Open(Stream stream, ReaderOptions options = null) { stream.CheckNotNull("stream"); return Open(stream.AsEnumerable(), options ?? new ReaderOptions()); } public static RarArchive Open(IEnumerable streams, ReaderOptions options = null) { streams.CheckNotNull("streams"); return new RarArchive(streams, options ?? new ReaderOptions()); } public static bool IsRarFile(string filePath) { return IsRarFile(new FileInfo(filePath)); } public static bool IsRarFile(FileInfo fileInfo) { if (!fileInfo.Exists) { return false; } using Stream stream = fileInfo.OpenRead(); return IsRarFile(stream); } public static bool IsRarFile(Stream stream, ReaderOptions options = null) { try { MarkHeader.Read(stream, leaveStreamOpen: true, lookForHeader: false); return true; } catch { return false; } } } public static class RarArchiveExtensions { public static bool IsFirstVolume(this RarArchive archive) { return archive.Volumes.First().IsFirstVolume; } public static bool IsMultipartVolume(this RarArchive archive) { return archive.Volumes.First().IsMultiVolume; } } public class RarArchiveEntry : RarEntry, IArchiveEntry, IEntry { private readonly ICollection parts; private readonly RarArchive archive; public override CompressionType CompressionType => CompressionType.Rar; public IArchive Archive => archive; internal override IEnumerable Parts => parts.Cast(); internal override FileHeader FileHeader => parts.First().FileHeader; public override long Crc { get { CheckIncomplete(); return parts.Select((RarFilePart fp) => fp.FileHeader).Single((FileHeader fh) => !fh.IsSplitAfter).FileCrc; } } public override long Size { get { CheckIncomplete(); return parts.First().FileHeader.UncompressedSize; } } public override long CompressedSize { get { CheckIncomplete(); return parts.Aggregate(0L, (long total, RarFilePart fp) => total + fp.FileHeader.CompressedSize); } } public bool IsComplete => parts.Select((RarFilePart fp) => fp.FileHeader).Any((FileHeader fh) => !fh.IsSplitAfter); internal RarArchiveEntry(RarArchive archive, IEnumerable parts) { this.parts = parts.ToList(); this.archive = archive; } public Stream OpenEntryStream() { if (archive.IsSolid) { throw new InvalidOperationException("Use ExtractAllEntries to extract SOLID archives."); } if (base.IsRarV3) { return new RarStream(archive.UnpackV1.Value, FileHeader, new MultiVolumeReadOnlyStream(Parts.Cast(), archive)); } return new RarStream(archive.UnpackV2017.Value, FileHeader, new MultiVolumeReadOnlyStream(Parts.Cast(), archive)); } private void CheckIncomplete() { if (!IsComplete) { throw new IncompleteArchiveException("ArchiveEntry is incomplete and cannot perform this operation."); } } } internal static class RarArchiveEntryFactory { private static IEnumerable GetFileParts(IEnumerable parts) { foreach (RarVolume part in parts) { foreach (RarFilePart item in part.ReadFileParts()) { yield return item; } } } private static IEnumerable> GetMatchedFileParts(IEnumerable parts) { List list = new List(); foreach (RarFilePart filePart in GetFileParts(parts)) { list.Add(filePart); if (!filePart.FileHeader.IsSplitAfter) { yield return list; list = new List(); } } if (list.Count > 0) { yield return list; } } internal static IEnumerable GetEntries(RarArchive archive, IEnumerable rarParts) { foreach (IEnumerable matchedFilePart in GetMatchedFileParts(rarParts)) { yield return new RarArchiveEntry(archive, matchedFilePart); } } } internal static class RarArchiveVolumeFactory { internal static IEnumerable GetParts(IEnumerable streams, ReaderOptions options) { foreach (Stream stream in streams) { if (!stream.CanRead || !stream.CanSeek) { throw new ArgumentException("Stream is not readable and seekable"); } yield return new StreamRarArchiveVolume(stream, options); } } internal static IEnumerable GetParts(FileInfo fileInfo, ReaderOptions options) { FileInfoRarArchiveVolume part = new FileInfoRarArchiveVolume(fileInfo, options); yield return part; ArchiveHeader ah = part.ArchiveHeader; if (ah.IsVolume) { fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault() as FileInfoRarFilePart); while (fileInfo != null && fileInfo.Exists) { part = new FileInfoRarArchiveVolume(fileInfo, options); fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault() as FileInfoRarFilePart); yield return part; } } } private static FileInfo GetNextFileInfo(ArchiveHeader ah, FileInfoRarFilePart currentFilePart) { if (currentFilePart == null) { return null; } if (ah.OldNumberingFormat || currentFilePart.MarkHeader.OldNumberingFormat) { return FindNextFileWithOldNumbering(currentFilePart.FileInfo); } return FindNextFileWithNewNumbering(currentFilePart.FileInfo); } private static FileInfo FindNextFileWithOldNumbering(FileInfo currentFileInfo) { string extension = currentFileInfo.Extension; StringBuilder stringBuilder = new StringBuilder(currentFileInfo.FullName.Length); stringBuilder.Append(currentFileInfo.FullName.Substring(0, currentFileInfo.FullName.Length - extension.Length)); if (string.Compare(extension, ".rar", StringComparison.OrdinalIgnoreCase) == 0) { stringBuilder.Append(".r00"); } else { int result = 0; if (int.TryParse(extension.Substring(2, 2), out result)) { result++; stringBuilder.Append(".r"); if (result < 10) { stringBuilder.Append('0'); } stringBuilder.Append(result); } else { ThrowInvalidFileName(currentFileInfo); } } return new FileInfo(stringBuilder.ToString()); } private static FileInfo FindNextFileWithNewNumbering(FileInfo currentFileInfo) { if (string.Compare(currentFileInfo.Extension, ".rar", StringComparison.OrdinalIgnoreCase) != 0) { throw new ArgumentException("Invalid extension, expected 'rar': " + currentFileInfo.FullName); } int num = currentFileInfo.FullName.LastIndexOf(".part"); if (num < 0) { ThrowInvalidFileName(currentFileInfo); } StringBuilder stringBuilder = new StringBuilder(currentFileInfo.FullName.Length); stringBuilder.Append(currentFileInfo.FullName, 0, num); int result = 0; string text = currentFileInfo.FullName.Substring(num + 5, currentFileInfo.FullName.IndexOf('.', num + 5) - num - 5); stringBuilder.Append(".part"); if (int.TryParse(text, out result)) { result++; for (int i = 0; i < text.Length - result.ToString().Length; i++) { stringBuilder.Append('0'); } stringBuilder.Append(result); } else { ThrowInvalidFileName(currentFileInfo); } stringBuilder.Append(".rar"); return new FileInfo(stringBuilder.ToString()); } private static void ThrowInvalidFileName(FileInfo fileInfo) { throw new ArgumentException("Filename invalid or next archive could not be found:" + fileInfo.FullName); } } internal class SeekableFilePart : RarFilePart { private readonly Stream stream; private readonly string password; internal override string FilePartName => "Unknown Stream - File Entry: " + base.FileHeader.FileName; internal SeekableFilePart(MarkHeader mh, FileHeader fh, Stream stream, string password) : base(mh, fh) { this.stream = stream; this.password = password; } internal override Stream GetCompressedStream() { stream.Position = base.FileHeader.DataStartPosition; if (base.FileHeader.R4Salt != null) { return new RarCryptoWrapper(stream, password, base.FileHeader.R4Salt); } return stream; } } internal class StreamRarArchiveVolume : RarVolume { internal StreamRarArchiveVolume(Stream stream, ReaderOptions options) : base(StreamingMode.Seekable, stream, options) { } internal override IEnumerable ReadFileParts() { return GetVolumeFileParts(); } internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) { return new SeekableFilePart(markHeader, fileHeader, base.Stream, base.ReaderOptions.Password); } } } namespace SharpCompress.Archives.GZip { public class GZipArchive : AbstractWritableArchive { public static GZipArchive Open(string filePath, ReaderOptions readerOptions = null) { filePath.CheckNotNullOrEmpty("filePath"); return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions()); } public static GZipArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null) { fileInfo.CheckNotNull("fileInfo"); return new GZipArchive(fileInfo, readerOptions ?? new ReaderOptions()); } public static GZipArchive Open(Stream stream, ReaderOptions readerOptions = null) { stream.CheckNotNull("stream"); return new GZipArchive(stream, readerOptions ?? new ReaderOptions()); } public static GZipArchive Create() { return new GZipArchive(); } internal GZipArchive(FileInfo fileInfo, ReaderOptions options) : base(ArchiveType.GZip, fileInfo, options) { } protected override IEnumerable LoadVolumes(FileInfo file) { return new GZipVolume(file, base.ReaderOptions).AsEnumerable(); } public static bool IsGZipFile(string filePath) { return IsGZipFile(new FileInfo(filePath)); } public static bool IsGZipFile(FileInfo fileInfo) { if (!fileInfo.Exists) { return false; } using Stream stream = fileInfo.OpenRead(); return IsGZipFile(stream); } public void SaveTo(string filePath) { SaveTo(new FileInfo(filePath)); } public void SaveTo(FileInfo fileInfo) { using FileStream stream = fileInfo.Open(FileMode.Create, FileAccess.Write); SaveTo(stream, new WriterOptions(CompressionType.GZip)); } public static bool IsGZipFile(Stream stream) { byte[] array = new byte[10]; if (!stream.ReadFully(array)) { return false; } if (array[0] != 31 || array[1] != 139 || array[2] != 8) { return false; } return true; } internal GZipArchive(Stream stream, ReaderOptions options) : base(ArchiveType.GZip, stream, options) { } internal GZipArchive() : base(ArchiveType.GZip) { } protected override GZipArchiveEntry CreateEntryInternal(string filePath, Stream source, long size, DateTime? modified, bool closeStream) { if (Entries.Any()) { throw new InvalidOperationException("Only one entry is allowed in a GZip Archive"); } return new GZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream); } protected override void SaveTo(Stream stream, WriterOptions options, IEnumerable oldEntries, IEnumerable newEntries) { if (Entries.Count > 1) { throw new InvalidOperationException("Only one entry is allowed in a GZip Archive"); } using GZipWriter gZipWriter = new GZipWriter(stream, new GZipWriterOptions(options)); foreach (GZipArchiveEntry item in from x in oldEntries.Concat(newEntries) where !x.IsDirectory select x) { using Stream source = item.OpenEntryStream(); gZipWriter.Write(item.Key, source, item.LastModifiedTime); } } protected override IEnumerable LoadVolumes(IEnumerable streams) { return new GZipVolume(streams.First(), base.ReaderOptions).AsEnumerable(); } protected override IEnumerable LoadEntries(IEnumerable volumes) { Stream stream = volumes.Single().Stream; yield return new GZipArchiveEntry(this, new GZipFilePart(stream, base.ReaderOptions.ArchiveEncoding)); } protected override IReader CreateReaderForSolidExtraction() { Stream stream = base.Volumes.Single().Stream; stream.Position = 0L; return GZipReader.Open(stream); } } public class GZipArchiveEntry : GZipEntry, IArchiveEntry, IEntry { public IArchive Archive { get; } public bool IsComplete => true; internal GZipArchiveEntry(GZipArchive archive, GZipFilePart part) : base(part) { Archive = archive; } public virtual Stream OpenEntryStream() { GZipFilePart gZipFilePart = Parts.Single() as GZipFilePart; if (gZipFilePart.GetRawStream().Position != gZipFilePart.EntryStartPosition) { gZipFilePart.GetRawStream().Position = gZipFilePart.EntryStartPosition; } return Parts.Single().GetCompressedStream(); } } internal class GZipWritableArchiveEntry : GZipArchiveEntry, IWritableArchiveEntry { private readonly bool closeStream; private readonly Stream stream; public override long Crc => 0L; public override string Key { get; } public override long CompressedSize => 0L; public override long Size { get; } public override DateTime? LastModifiedTime { get; } public override DateTime? CreatedTime => null; public override DateTime? LastAccessedTime => null; public override DateTime? ArchivedTime => null; public override bool IsEncrypted => false; public override bool IsDirectory => false; public override bool IsSplitAfter => false; internal override IEnumerable Parts { get { throw new NotImplementedException(); } } Stream IWritableArchiveEntry.Stream => stream; internal GZipWritableArchiveEntry(GZipArchive archive, Stream stream, string path, long size, DateTime? lastModified, bool closeStream) : base(archive, null) { this.stream = stream; Key = path; Size = size; LastModifiedTime = lastModified; this.closeStream = closeStream; } public override Stream OpenEntryStream() { stream.Seek(0L, SeekOrigin.Begin); return new NonDisposingStream(stream); } internal override void Close() { if (closeStream) { stream.Dispose(); } } } }