From 2fe769afbb2fc029639f30f970b19e6d7b82b593 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Sun, 28 Apr 2013 12:30:18 +0100 Subject: [PATCH] Cleaned up public facing API --- .../Common/SevenZip/ArchiveDatabase.cs | 38 +- .../Common/SevenZip/ArchiveReader.cs | 2327 +++++++++-------- SharpCompress/Common/SevenZip/CFileItem.cs | 48 +- .../Compressor/Filters/BCJ2Filter.cs | 11 +- SharpCompress/Compressor/Filters/BCJFilter.cs | 39 +- SharpCompress/Compressor/Filters/Filter.cs | 9 +- SharpCompress/Compressor/LZMA/BitVector.cs | 20 +- SharpCompress/Compressor/LZMA/Registry.cs | 40 +- .../LZMA/Utilites/IPasswordProvider.cs | 2 +- 9 files changed, 1270 insertions(+), 1264 deletions(-) diff --git a/SharpCompress/Common/SevenZip/ArchiveDatabase.cs b/SharpCompress/Common/SevenZip/ArchiveDatabase.cs index d119f7b5..0fe624f2 100644 --- a/SharpCompress/Common/SevenZip/ArchiveDatabase.cs +++ b/SharpCompress/Common/SevenZip/ArchiveDatabase.cs @@ -6,7 +6,7 @@ using SharpCompress.Compressor.LZMA.Utilites; namespace SharpCompress.Common.SevenZip { - public class ArchiveDatabase + internal class ArchiveDatabase { internal byte MajorVersion; internal byte MinorVersion; @@ -50,7 +50,7 @@ namespace SharpCompress.Common.SevenZip PackStreamStartPositions.Clear(); long startPos = 0; - for(int i = 0; i < PackSizes.Count; i++) + for (int i = 0; i < PackSizes.Count; i++) { PackStreamStartPositions.Add(startPos); startPos += PackSizes[i]; @@ -64,30 +64,30 @@ namespace SharpCompress.Common.SevenZip int folderIndex = 0; int indexInFolder = 0; - for(int i = 0; i < Files.Count; i++) + for (int i = 0; i < Files.Count; i++) { CFileItem file = Files[i]; bool emptyStream = !file.HasStream; - if(emptyStream && indexInFolder == 0) + if (emptyStream && indexInFolder == 0) { FileIndexToFolderIndexMap.Add(-1); continue; } - if(indexInFolder == 0) + if (indexInFolder == 0) { // v3.13 incorrectly worked with empty folders // v4.07: Loop for skipping empty folders - for(; ; ) + for (; ; ) { - if(folderIndex >= Folders.Count) + if (folderIndex >= Folders.Count) throw new InvalidOperationException(); FolderStartFileIndex.Add(i); // check it - if(NumUnpackStreamsVector[folderIndex] != 0) + if (NumUnpackStreamsVector[folderIndex] != 0) break; folderIndex++; @@ -96,12 +96,12 @@ namespace SharpCompress.Common.SevenZip FileIndexToFolderIndexMap.Add(folderIndex); - if(emptyStream) + if (emptyStream) continue; indexInFolder++; - if(indexInFolder >= NumUnpackStreamsVector[folderIndex]) + if (indexInFolder >= NumUnpackStreamsVector[folderIndex]) { folderIndex++; indexInFolder = 0; @@ -127,7 +127,7 @@ namespace SharpCompress.Common.SevenZip CFolder folder = Folders[folderIndex]; long size = 0; - for(int i = 0; i < folder.PackStreams.Count; i++) + for (int i = 0; i < folder.PackStreams.Count; i++) size += PackSizes[packStreamIndex + i]; return size; @@ -135,13 +135,13 @@ namespace SharpCompress.Common.SevenZip internal Stream GetFolderStream(Stream stream, CFolder folder, IPasswordProvider pw) { - int packStreamIndex = folder.FirstPackStreamId; - long folderStartPackPos = GetFolderStreamPos(folder, 0); - List packSizes = new List(); - for (int j = 0; j < folder.PackStreams.Count; j++) - packSizes.Add(PackSizes[packStreamIndex + j]); + int packStreamIndex = folder.FirstPackStreamId; + long folderStartPackPos = GetFolderStreamPos(folder, 0); + List packSizes = new List(); + for (int j = 0; j < folder.PackStreams.Count; j++) + packSizes.Add(PackSizes[packStreamIndex + j]); - return DecoderStreamHelper.CreateDecoderStream(stream, folderStartPackPos, packSizes.ToArray(), folder, pw); + return DecoderStreamHelper.CreateDecoderStream(stream, folderStartPackPos, packSizes.ToArray(), folder, pw); } private long GetFolderPackStreamSize(int folderIndex, int streamIndex) @@ -152,8 +152,8 @@ namespace SharpCompress.Common.SevenZip private long GetFilePackSize(int fileIndex) { int folderIndex = FileIndexToFolderIndexMap[fileIndex]; - if(folderIndex != -1) - if(FolderStartFileIndex[folderIndex] == fileIndex) + if (folderIndex != -1) + if (FolderStartFileIndex[folderIndex] == fileIndex) return GetFolderFullPackSize(folderIndex); return 0; } diff --git a/SharpCompress/Common/SevenZip/ArchiveReader.cs b/SharpCompress/Common/SevenZip/ArchiveReader.cs index 630a2b2b..3b45cef7 100644 --- a/SharpCompress/Common/SevenZip/ArchiveReader.cs +++ b/SharpCompress/Common/SevenZip/ArchiveReader.cs @@ -5,1273 +5,1278 @@ using System.Linq; using SharpCompress.Compressor.LZMA; using SharpCompress.Compressor.LZMA.Utilites; using SharpCompress.IO; -using CRC = SharpCompress.Compressor.LZMA.CRC; namespace SharpCompress.Common.SevenZip { - public class ArchiveReader - { - internal Stream _stream; - internal Stack _readerStack = new Stack(); - internal DataReader _currentReader; - internal long _streamOrigin; - internal long _streamEnding; - internal byte[] _header; + internal class ArchiveReader + { + internal Stream _stream; + internal Stack _readerStack = new Stack(); + internal DataReader _currentReader; + internal long _streamOrigin; + internal long _streamEnding; + internal byte[] _header; - private Dictionary _cachedStreams = new Dictionary(); + private Dictionary _cachedStreams = new Dictionary(); - internal void AddByteStream(byte[] buffer, int offset, int length) - { - _readerStack.Push(_currentReader); - _currentReader = new DataReader(buffer, offset, length); - } + 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 void DeleteByteStream() + { + _currentReader = _readerStack.Pop(); + } - #region Private Methods - Data Reader + #region Private Methods - Data Reader - internal Byte ReadByte() - { - return _currentReader.ReadByte(); - } + internal Byte ReadByte() + { + return _currentReader.ReadByte(); + } - private void ReadBytes(byte[] buffer, int offset, int length) - { - _currentReader.ReadBytes(buffer, offset, length); - } + private void ReadBytes(byte[] buffer, int offset, int length) + { + _currentReader.ReadBytes(buffer, offset, length); + } - private ulong ReadNumber() - { - return _currentReader.ReadNumber(); - } + private ulong ReadNumber() + { + return _currentReader.ReadNumber(); + } - internal int ReadNum() - { - return _currentReader.ReadNum(); - } + internal int ReadNum() + { + return _currentReader.ReadNum(); + } - private uint ReadUInt32() - { - return _currentReader.ReadUInt32(); - } + private uint ReadUInt32() + { + return _currentReader.ReadUInt32(); + } - private ulong ReadUInt64() - { - return _currentReader.ReadUInt64(); - } + private ulong ReadUInt64() + { + return _currentReader.ReadUInt64(); + } - private BlockType? ReadId() - { - ulong id = _currentReader.ReadNumber(); - if(id > 25) - return null; + private BlockType? ReadId() + { + ulong id = _currentReader.ReadNumber(); + if (id > 25) + return null; - Log.WriteLine("ReadId: {0}", (BlockType)id); - return (BlockType)id; - } + Log.WriteLine("ReadId: {0}", (BlockType)id); + return (BlockType)id; + } - private void SkipData(long size) - { - _currentReader.SkipData(size); - } + private void SkipData(long size) + { + _currentReader.SkipData(size); + } - private void SkipData() - { - _currentReader.SkipData(); - } + private void SkipData() + { + _currentReader.SkipData(); + } - private void WaitAttribute(BlockType attribute) - { - for(; ; ) - { - BlockType? type = ReadId(); - if(type == attribute) - return; - if(type == BlockType.End) - throw new InvalidOperationException(); - SkipData(); - } - } - - private void ReadArchiveProperties() - { - while(ReadId() != BlockType.End) - SkipData(); - } - - #endregion - - #region Private Methods - Reader Utilities - - private BitVector ReadBitVector(int length) - { - var bits = new BitVector(length); - - byte data = 0; - byte mask = 0; - - for(int i = 0; i < length; i++) - { - if(mask == 0) + private void WaitAttribute(BlockType attribute) + { + for (; ; ) { - data = ReadByte(); - mask = 0x80; + BlockType? type = ReadId(); + if (type == attribute) + return; + if (type == BlockType.End) + throw new InvalidOperationException(); + SkipData(); + } + } + + private void ReadArchiveProperties() + { + while (ReadId() != BlockType.End) + SkipData(); + } + + #endregion + + #region Private Methods - Reader Utilities + + private BitVector ReadBitVector(int length) + { + var bits = new BitVector(length); + + byte data = 0; + byte mask = 0; + + for (int i = 0; i < length; i++) + { + if (mask == 0) + { + data = ReadByte(); + mask = 0x80; + } + + if ((data & mask) != 0) + bits.SetBit(i); + + mask >>= 1; } - if((data & mask) != 0) - bits.SetBit(i); + return bits; + } - mask >>= 1; - } + private BitVector ReadOptionalBitVector(int length) + { + byte allTrue = ReadByte(); + if (allTrue != 0) + return new BitVector(length, true); - return bits; - } + return ReadBitVector(length); + } - private BitVector ReadOptionalBitVector(int length) - { - byte allTrue = ReadByte(); - if(allTrue != 0) - return new BitVector(length, true); + private void ReadNumberVector(List dataVector, int numFiles, Action action) + { + var defined = ReadOptionalBitVector(numFiles); - return ReadBitVector(length); - } - - private void ReadNumberVector(List dataVector, int numFiles, Action action) - { - var defined = ReadOptionalBitVector(numFiles); - - using(CStreamSwitch streamSwitch = new CStreamSwitch()) - { - streamSwitch.Set(this, dataVector); - - for(int i = 0; i < numFiles; i++) + using (CStreamSwitch streamSwitch = new CStreamSwitch()) { - if(defined[i]) - action(i, checked((long)ReadUInt64())); - else - action(i, null); + streamSwitch.Set(this, dataVector); + + for (int i = 0; i < numFiles; i++) + { + if (defined[i]) + action(i, checked((long)ReadUInt64())); + else + action(i, null); + } } - } - } + } - private DateTime TranslateTime(long time) - { - // FILETIME = 100-nanosecond intervals since January 1, 1601 (UTC) - return DateTime.FromFileTimeUtc(time); - } + private DateTime TranslateTime(long time) + { + // FILETIME = 100-nanosecond intervals since January 1, 1601 (UTC) + return DateTime.FromFileTimeUtc(time); + } - private DateTime? TranslateTime(long? time) - { - if(time.HasValue) - return TranslateTime(time.Value); - else - return null; - } + private DateTime? TranslateTime(long? time) + { + if (time.HasValue) + return TranslateTime(time.Value); + else + return null; + } - private void ReadDateTimeVector(List dataVector, int numFiles, Action action) - { - ReadNumberVector(dataVector, numFiles, (index, value) => action(index, TranslateTime(value))); - } + private void ReadDateTimeVector(List dataVector, int numFiles, Action action) + { + ReadNumberVector(dataVector, numFiles, (index, value) => action(index, TranslateTime(value))); + } - private void ReadAttributeVector(List dataVector, int numFiles, Action action) - { - BitVector boolVector = ReadOptionalBitVector(numFiles); - using(var streamSwitch = new CStreamSwitch()) - { - streamSwitch.Set(this, dataVector); - for(int i = 0; i < numFiles; i++) + private void ReadAttributeVector(List dataVector, int numFiles, Action action) + { + BitVector boolVector = ReadOptionalBitVector(numFiles); + using (var streamSwitch = new CStreamSwitch()) { - if(boolVector[i]) - action(i, ReadUInt32()); - else - action(i, null); + streamSwitch.Set(this, dataVector); + for (int i = 0; i < numFiles; i++) + { + if (boolVector[i]) + action(i, ReadUInt32()); + else + action(i, null); + } } - } - } + } - #endregion + #endregion - #region Private Methods + #region Private Methods - private void GetNextFolderItem(CFolder folder) - { - Log.WriteLine("-- GetNextFolderItem --"); - Log.PushIndent(); - try - { - int numCoders = ReadNum(); - Log.WriteLine("NumCoders: " + numCoders); - - folder.Coders = new List(numCoders); - int numInStreams = 0; - int numOutStreams = 0; - for(int i = 0; i < numCoders; i++) - { - Log.WriteLine("-- Coder --"); - Log.PushIndent(); - try - { - CCoderInfo coder = new CCoderInfo(); - folder.Coders.Add(coder); - - byte mainByte = ReadByte(); - int idSize = (mainByte & 0xF); - byte[] longID = new byte[idSize]; - ReadBytes(longID, 0, idSize); - Log.WriteLine("MethodId: " + String.Join("", Enumerable.Range(0, idSize).Select(x => longID[x].ToString("x2")).ToArray())); - if(idSize > 8) - throw new NotSupportedException(); - ulong id = 0; - for(int j = 0; j < idSize; j++) - id |= (ulong)longID[idSize - 1 - j] << (8 * j); - coder.MethodId = new CMethodId(id); - - if((mainByte & 0x10) != 0) - { - coder.NumInStreams = ReadNum(); - coder.NumOutStreams = ReadNum(); - Log.WriteLine("Complex Stream (In: " + coder.NumInStreams + " - Out: " + coder.NumOutStreams + ")"); - } - else - { - Log.WriteLine("Simple Stream (In: 1 - Out: 1)"); - coder.NumInStreams = 1; - coder.NumOutStreams = 1; - } - - if((mainByte & 0x20) != 0) - { - int propsSize = ReadNum(); - coder.Props = new byte[propsSize]; - ReadBytes(coder.Props, 0, propsSize); - Log.WriteLine("Settings: " + String.Join("", coder.Props.Select(bt => bt.ToString("x2")).ToArray())); - } - - if((mainByte & 0x80) != 0) - throw new NotSupportedException(); - - numInStreams += coder.NumInStreams; - numOutStreams += coder.NumOutStreams; - } - finally { Log.PopIndent(); } - } - - int numBindPairs = numOutStreams - 1; - folder.BindPairs = new List(numBindPairs); - Log.WriteLine("BindPairs: " + numBindPairs); + private void GetNextFolderItem(CFolder folder) + { + Log.WriteLine("-- GetNextFolderItem --"); Log.PushIndent(); - for(int i = 0; i < numBindPairs; i++) + try { - CBindPair bp = new CBindPair(); - bp.InIndex = ReadNum(); - bp.OutIndex = ReadNum(); - folder.BindPairs.Add(bp); - Log.WriteLine("#" + i + " - In: " + bp.InIndex + " - Out: " + bp.OutIndex); - } - Log.PopIndent(); + int numCoders = ReadNum(); + Log.WriteLine("NumCoders: " + numCoders); - if(numInStreams < numBindPairs) - throw new NotSupportedException(); + folder.Coders = new List(numCoders); + int numInStreams = 0; + int numOutStreams = 0; + for (int i = 0; i < numCoders; i++) + { + Log.WriteLine("-- Coder --"); + Log.PushIndent(); + try + { + CCoderInfo coder = new CCoderInfo(); + folder.Coders.Add(coder); - int numPackStreams = numInStreams - numBindPairs; - //folder.PackStreams.Reserve(numPackStreams); - if(numPackStreams == 1) - { - for(int i = 0; i < numInStreams; i++) - { - if(folder.FindBindPairForInStream(i) < 0) - { - Log.WriteLine("Single PackStream: #" + i); - folder.PackStreams.Add(i); - break; - } - } + byte mainByte = ReadByte(); + int idSize = (mainByte & 0xF); + byte[] longID = new byte[idSize]; + ReadBytes(longID, 0, idSize); + Log.WriteLine("MethodId: " + String.Join("", Enumerable.Range(0, idSize).Select(x => longID[x].ToString("x2")).ToArray())); + if (idSize > 8) + throw new NotSupportedException(); + ulong id = 0; + for (int j = 0; j < idSize; j++) + id |= (ulong)longID[idSize - 1 - j] << (8 * j); + coder.MethodId = new CMethodId(id); - if(folder.PackStreams.Count != 1) - throw new NotSupportedException(); - } - else - { - Log.WriteLine("Multiple PackStreams ..."); - Log.PushIndent(); - for(int i = 0; i < numPackStreams; i++) - { - var num = ReadNum(); - Log.WriteLine("#" + i + " - " + num); - folder.PackStreams.Add(num); - } - Log.PopIndent(); - } - } - finally - { - Log.PopIndent(); - } - } - - private List ReadHashDigests(int count) - { - Log.Write("ReadHashDigests:"); - - var defined = ReadOptionalBitVector(count); - var digests = new List(count); - for(int i = 0; i < count; i++) - { - if(defined[i]) - { - uint crc = ReadUInt32(); - Log.Write(" " + crc.ToString("x8")); - digests.Add(crc); - } - else - { - Log.Write(" ########"); - digests.Add(null); - } - } - - Log.WriteLine(); - return digests; - } - - private void ReadPackInfo(out long dataOffset, out List packSizes, out List packCRCs) - { - Log.WriteLine("-- ReadPackInfo --"); - Log.PushIndent(); - try - { - packCRCs = null; - - dataOffset = checked((long)ReadNumber()); - Log.WriteLine("DataOffset: " + dataOffset); - - int numPackStreams = ReadNum(); - Log.WriteLine("NumPackStreams: " + numPackStreams); - - WaitAttribute(BlockType.Size); - packSizes = new List(numPackStreams); - Log.Write("Sizes:"); - for(int i = 0; i < numPackStreams; i++) - { - var size = checked((long)ReadNumber()); - Log.Write(" " + size); - packSizes.Add(size); - } - Log.WriteLine(); - - BlockType? type; - for(; ; ) - { - type = ReadId(); - if(type == BlockType.End) - break; - if(type == BlockType.CRC) - { - packCRCs = ReadHashDigests(numPackStreams); - continue; - } - SkipData(); - } - - if(packCRCs == null) - { - packCRCs = new List(numPackStreams); - for(int i = 0; i < numPackStreams; i++) - packCRCs.Add(null); - } - } - finally { Log.PopIndent(); } - } - - private void ReadUnpackInfo(List dataVector, out List folders) - { - Log.WriteLine("-- ReadUnpackInfo --"); - Log.PushIndent(); - try - { - WaitAttribute(BlockType.Folder); - int numFolders = ReadNum(); - Log.WriteLine("NumFolders: {0}", numFolders); - - using(CStreamSwitch streamSwitch = new CStreamSwitch()) - { - streamSwitch.Set(this, dataVector); - //folders.Clear(); - //folders.Reserve(numFolders); - folders = new List(numFolders); - int index = 0; - for(int i = 0; i < numFolders; i++) - { - var f = new CFolder { FirstPackStreamId = index }; - folders.Add(f); - GetNextFolderItem(f); - index += f.PackStreams.Count; - } - } - - WaitAttribute(BlockType.CodersUnpackSize); - - Log.WriteLine("UnpackSizes:"); - for(int i = 0; i < numFolders; i++) - { - CFolder folder = folders[i]; - Log.Write(" #" + i + ":"); - int numOutStreams = folder.GetNumOutStreams(); - for(int j = 0; j < numOutStreams; j++) - { - long size = checked((long)ReadNumber()); - Log.Write(" " + size); - folder.UnpackSizes.Add(size); - } - Log.WriteLine(); - } - - for(; ; ) - { - BlockType? type = ReadId(); - if(type == BlockType.End) - return; - - if(type == BlockType.CRC) - { - List crcs = ReadHashDigests(numFolders); - for(int i = 0; i < numFolders; i++) - folders[i].UnpackCRC = crcs[i]; - continue; - } - - SkipData(); - } - } - finally { Log.PopIndent(); } - } - - private void ReadSubStreamsInfo(List folders, out List numUnpackStreamsInFolders, out List unpackSizes, out List digests) - { - Log.WriteLine("-- ReadSubStreamsInfo --"); - Log.PushIndent(); - try - { - numUnpackStreamsInFolders = null; - - BlockType? type; - for(; ; ) - { - type = ReadId(); - if(type == BlockType.NumUnpackStream) - { - numUnpackStreamsInFolders = new List(folders.Count); - Log.Write("NumUnpackStreams:"); - for(int i = 0; i < folders.Count; i++) - { - var num = ReadNum(); - Log.Write(" " + num); - numUnpackStreamsInFolders.Add(num); - } - Log.WriteLine(); - continue; - } - if(type == BlockType.CRC || type == BlockType.Size) - break; - if(type == BlockType.End) - break; - SkipData(); - } - - if(numUnpackStreamsInFolders == null) - { - numUnpackStreamsInFolders = new List(folders.Count); - for(int i = 0; i < folders.Count; i++) - numUnpackStreamsInFolders.Add(1); - } - - unpackSizes = new List(folders.Count); - for(int i = 0; i < numUnpackStreamsInFolders.Count; i++) - { - // v3.13 incorrectly worked with empty folders - // v4.07: we check that folder is empty - int numSubstreams = numUnpackStreamsInFolders[i]; - if(numSubstreams == 0) - continue; - - Log.Write("#{0} StreamSizes:", i); - long sum = 0; - for(int j = 1; j < numSubstreams; j++) - { - if(type == BlockType.Size) - { - long size = checked((long)ReadNumber()); - Log.Write(" " + size); - unpackSizes.Add(size); - sum += size; - } - } - unpackSizes.Add(folders[i].GetUnpackSize() - sum); - Log.WriteLine(" - rest: " + unpackSizes.Last()); - } - if(type == BlockType.Size) - type = ReadId(); - - int numDigests = 0; - int numDigestsTotal = 0; - for(int i = 0; i < folders.Count; i++) - { - int numSubstreams = numUnpackStreamsInFolders[i]; - if(numSubstreams != 1 || !folders[i].UnpackCRCDefined) - numDigests += numSubstreams; - numDigestsTotal += numSubstreams; - } - - digests = null; - - for(; ; ) - { - if(type == BlockType.CRC) - { - digests = new List(numDigestsTotal); - - List digests2 = ReadHashDigests(numDigests); - - int digestIndex = 0; - for(int i = 0; i < folders.Count; i++) - { - int numSubstreams = numUnpackStreamsInFolders[i]; - CFolder folder = folders[i]; - if(numSubstreams == 1 && folder.UnpackCRCDefined) - { - digests.Add(folder.UnpackCRC.Value); - } - else - { - for(int j = 0; j < numSubstreams; j++, digestIndex++) - digests.Add(digests2[digestIndex]); - } - } - - if(digestIndex != numDigests || numDigestsTotal != digests.Count) - System.Diagnostics.Debugger.Break(); - } - else if(type == BlockType.End) - { - if(digests == null) - { - digests = new List(numDigestsTotal); - for(int i = 0; i < numDigestsTotal; i++) - digests.Add(null); - } - return; - } - else - { - SkipData(); - } - - type = ReadId(); - } - } - finally { Log.PopIndent(); } - } - - 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) - { - Log.WriteLine("-- ReadStreamsInfo --"); - Log.PushIndent(); - try - { - dataOffset = long.MinValue; - packSizes = null; - packCRCs = null; - folders = null; - numUnpackStreamsInFolders = null; - unpackSizes = null; - digests = null; - - for(; ; ) - { - switch(ReadId()) - { - case BlockType.End: - return; - case BlockType.PackInfo: - ReadPackInfo(out dataOffset, out packSizes, out packCRCs); - break; - case BlockType.UnpackInfo: - ReadUnpackInfo(dataVector, out folders); - break; - case BlockType.SubStreamsInfo: - ReadSubStreamsInfo(folders, out numUnpackStreamsInFolders, out unpackSizes, out digests); - break; - default: - throw new InvalidOperationException(); - } - } - } - finally { Log.PopIndent(); } - } - - private List ReadAndDecodePackedStreams(long baseOffset, IPasswordProvider pass) - { - Log.WriteLine("-- ReadAndDecodePackedStreams --"); - Log.PushIndent(); - try - { - long dataStartPos; - List packSizes; - List packCRCs; - List folders; - List numUnpackStreamsInFolders; - List unpackSizes; - List digests; - - ReadStreamsInfo(null, - out dataStartPos, - out packSizes, - out packCRCs, - out folders, - out numUnpackStreamsInFolders, - out unpackSizes, - out digests); - - dataStartPos += baseOffset; - - var dataVector = new List(folders.Count); - int packIndex = 0; - foreach(var folder in folders) - { - long oldDataStartPos = dataStartPos; - long[] myPackSizes = new long[folder.PackStreams.Count]; - for(int i = 0; i < myPackSizes.Length; i++) - { - long packSize = packSizes[packIndex + i]; - myPackSizes[i] = packSize; - dataStartPos += packSize; - } - - var outStream = DecoderStreamHelper.CreateDecoderStream(_stream, oldDataStartPos, myPackSizes, folder, pass); - - int unpackSize = checked((int)folder.GetUnpackSize()); - byte[] data = new byte[unpackSize]; - outStream.ReadExact(data, 0, data.Length); - if(outStream.ReadByte() >= 0) - throw new InvalidOperationException("Decoded stream is longer than expected."); - dataVector.Add(data); - - if(folder.UnpackCRCDefined) - if(CRC.Finish(CRC.Update(CRC.kInitCRC, data, 0, unpackSize)) != folder.UnpackCRC) - throw new InvalidOperationException("Decoded stream does not match expected CRC."); - } - return dataVector; - } - finally { Log.PopIndent(); } - } - - private void ReadHeader(ArchiveDatabase db, IPasswordProvider getTextPassword) - { - Log.WriteLine("-- ReadHeader --"); - Log.PushIndent(); - try - { - BlockType? type = ReadId(); - - if(type == BlockType.ArchiveProperties) - { - ReadArchiveProperties(); - type = ReadId(); - } - - List dataVector = null; - if(type == BlockType.AdditionalStreamsInfo) - { - dataVector = ReadAndDecodePackedStreams(db.StartPositionAfterHeader, getTextPassword); - type = ReadId(); - } - - List unpackSizes; - List digests; - - if(type == 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; - type = 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++) - { - var folder = db.Folders[i]; - unpackSizes.Add(folder.GetUnpackSize()); - digests.Add(folder.UnpackCRC); - db.NumUnpackStreamsVector.Add(1); - } - } - - db.Files.Clear(); - - if(type == BlockType.End) - return; - - if(type != BlockType.FilesInfo) - throw new InvalidOperationException(); - - int numFiles = ReadNum(); - Log.WriteLine("NumFiles: " + numFiles); - db.Files = new List(numFiles); - for(int i = 0; i < numFiles; i++) - db.Files.Add(new CFileItem()); - - BitVector emptyStreamVector = new BitVector(numFiles); - BitVector emptyFileVector = null; - BitVector antiFileVector = null; - int numEmptyStreams = 0; - - for(; ; ) - { - type = ReadId(); - if(type == BlockType.End) - break; - - long size = checked((long)ReadNumber()); // TODO: throw invalid data on negative - int oldPos = _currentReader.Offset; - switch(type) - { - case BlockType.Name: - using(var streamSwitch = new CStreamSwitch()) - { - streamSwitch.Set(this, dataVector); - Log.Write("FileNames:"); - for(int i = 0; i < db.Files.Count; i++) + if ((mainByte & 0x10) != 0) { - db.Files[i].Name = _currentReader.ReadString(); - Log.Write(" " + db.Files[i].Name); - } - Log.WriteLine(); - } - break; - case BlockType.WinAttributes: - Log.Write("WinAttributes:"); - ReadAttributeVector(dataVector, numFiles, delegate(int i, uint? attr) { - db.Files[i].Attrib = attr; - Log.Write(" " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a")); - }); - Log.WriteLine(); - break; - case BlockType.EmptyStream: - emptyStreamVector = ReadBitVector(numFiles); - - Log.Write("EmptyStream: "); - for(int i = 0; i < emptyStreamVector.Length; i++) - { - if(emptyStreamVector[i]) - { - Log.Write("x"); - numEmptyStreams++; + coder.NumInStreams = ReadNum(); + coder.NumOutStreams = ReadNum(); + Log.WriteLine("Complex Stream (In: " + coder.NumInStreams + " - Out: " + coder.NumOutStreams + ")"); } else { - Log.Write("."); + Log.WriteLine("Simple Stream (In: 1 - Out: 1)"); + coder.NumInStreams = 1; + coder.NumOutStreams = 1; } - } - Log.WriteLine(); - emptyFileVector = new BitVector(numEmptyStreams); - antiFileVector = new BitVector(numEmptyStreams); - break; - case BlockType.EmptyFile: - emptyFileVector = ReadBitVector(numEmptyStreams); - Log.Write("EmptyFile: "); - for(int i = 0; i < numEmptyStreams; i++) - Log.Write(emptyFileVector[i] ? "x" : "."); - Log.WriteLine(); - break; - case BlockType.Anti: - antiFileVector = ReadBitVector(numEmptyStreams); - Log.Write("Anti: "); - for(int i = 0; i < numEmptyStreams; i++) - Log.Write(antiFileVector[i] ? "x" : "."); - Log.WriteLine(); - break; - case BlockType.StartPos: - Log.Write("StartPos:"); - ReadNumberVector(dataVector, numFiles, delegate(int i, long? startPos) { - db.Files[i].StartPos = startPos; - Log.Write(" " + (startPos.HasValue ? startPos.Value.ToString() : "n/a")); - }); - Log.WriteLine(); - break; - case BlockType.CTime: - Log.Write("CTime:"); - ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time) { - db.Files[i].CTime = time; - Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); - }); - Log.WriteLine(); - break; - case BlockType.ATime: - Log.Write("ATime:"); - ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time) { - db.Files[i].ATime = time; - Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); - }); - Log.WriteLine(); - break; - case BlockType.MTime: - Log.Write("MTime:"); - ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time) { - db.Files[i].MTime = time; - Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); - }); - Log.WriteLine(); - break; - case BlockType.Dummy: - Log.Write("Dummy: " + size); - for(long j = 0; j < size; j++) - if(ReadByte() != 0) - throw new InvalidOperationException(); - break; - default: - SkipData(size); - break; - } + if ((mainByte & 0x20) != 0) + { + int propsSize = ReadNum(); + coder.Props = new byte[propsSize]; + ReadBytes(coder.Props, 0, propsSize); + Log.WriteLine("Settings: " + String.Join("", coder.Props.Select(bt => bt.ToString("x2")).ToArray())); + } - // since 0.3 record sizes must be correct - bool checkRecordsSize = (db.MajorVersion > 0 || db.MinorVersion > 2); - if(checkRecordsSize && _currentReader.Offset - oldPos != size) - throw new InvalidOperationException(); + if ((mainByte & 0x80) != 0) + throw new NotSupportedException(); + + numInStreams += coder.NumInStreams; + numOutStreams += coder.NumOutStreams; + } + finally { Log.PopIndent(); } + } + + int numBindPairs = numOutStreams - 1; + folder.BindPairs = new List(numBindPairs); + Log.WriteLine("BindPairs: " + numBindPairs); + Log.PushIndent(); + for (int i = 0; i < numBindPairs; i++) + { + CBindPair bp = new CBindPair(); + bp.InIndex = ReadNum(); + bp.OutIndex = ReadNum(); + folder.BindPairs.Add(bp); + Log.WriteLine("#" + i + " - In: " + bp.InIndex + " - Out: " + bp.OutIndex); + } + Log.PopIndent(); + + if (numInStreams < numBindPairs) + throw new NotSupportedException(); + + int numPackStreams = numInStreams - numBindPairs; + //folder.PackStreams.Reserve(numPackStreams); + if (numPackStreams == 1) + { + for (int i = 0; i < numInStreams; i++) + { + if (folder.FindBindPairForInStream(i) < 0) + { + Log.WriteLine("Single PackStream: #" + i); + folder.PackStreams.Add(i); + break; + } + } + + if (folder.PackStreams.Count != 1) + throw new NotSupportedException(); + } + else + { + Log.WriteLine("Multiple PackStreams ..."); + Log.PushIndent(); + for (int i = 0; i < numPackStreams; i++) + { + var num = ReadNum(); + Log.WriteLine("#" + i + " - " + num); + folder.PackStreams.Add(num); + } + Log.PopIndent(); + } } - - int emptyFileIndex = 0; - int sizeIndex = 0; - for(int i = 0; i < numFiles; i++) + finally { - CFileItem file = db.Files[i]; - file.HasStream = !emptyStreamVector[i]; - if(file.HasStream) - { - file.IsDir = false; - file.IsAnti = false; - file.Size = unpackSizes[sizeIndex]; - file.Crc = digests[sizeIndex]; - sizeIndex++; - } - else - { - file.IsDir = !emptyFileVector[emptyFileIndex]; - file.IsAnti = antiFileVector[emptyFileIndex]; - emptyFileIndex++; - file.Size = 0; - file.Crc = null; - } + Log.PopIndent(); } - } - finally { Log.PopIndent(); } - } + } - #endregion + private List ReadHashDigests(int count) + { + Log.Write("ReadHashDigests:"); - #region Public Methods + var defined = ReadOptionalBitVector(count); + var digests = new List(count); + for (int i = 0; i < count; i++) + { + if (defined[i]) + { + uint crc = ReadUInt32(); + Log.Write(" " + crc.ToString("x8")); + digests.Add(crc); + } + else + { + Log.Write(" ########"); + digests.Add(null); + } + } - public void Open(Stream stream) - { - Close(); + Log.WriteLine(); + return digests; + } - _streamOrigin = stream.Position; - _streamEnding = stream.Length; + private void ReadPackInfo(out long dataOffset, out List packSizes, out List packCRCs) + { + Log.WriteLine("-- ReadPackInfo --"); + Log.PushIndent(); + try + { + packCRCs = null; - // TODO: Check Signature! - _header = new byte[0x20]; - for(int offset = 0; offset < 0x20; ) - { - int delta = stream.Read(_header, offset, 0x20 - offset); - if(delta == 0) - throw new EndOfStreamException(); - offset += delta; - } + dataOffset = checked((long)ReadNumber()); + Log.WriteLine("DataOffset: " + dataOffset); - _stream = stream; - } + int numPackStreams = ReadNum(); + Log.WriteLine("NumPackStreams: " + numPackStreams); - public void Close() - { - if(_stream != null) - _stream.Dispose(); + WaitAttribute(BlockType.Size); + packSizes = new List(numPackStreams); + Log.Write("Sizes:"); + for (int i = 0; i < numPackStreams; i++) + { + var size = checked((long)ReadNumber()); + Log.Write(" " + size); + packSizes.Add(size); + } + Log.WriteLine(); - foreach(var stream in _cachedStreams.Values) - stream.Dispose(); + BlockType? type; + for (; ; ) + { + type = ReadId(); + if (type == BlockType.End) + break; + if (type == BlockType.CRC) + { + packCRCs = ReadHashDigests(numPackStreams); + continue; + } + SkipData(); + } - _cachedStreams.Clear(); - } + if (packCRCs == null) + { + packCRCs = new List(numPackStreams); + for (int i = 0; i < numPackStreams; i++) + packCRCs.Add(null); + } + } + finally { Log.PopIndent(); } + } - public ArchiveDatabase ReadDatabase(IPasswordProvider pass) - { - var db = new ArchiveDatabase(); - db.Clear(); + private void ReadUnpackInfo(List dataVector, out List folders) + { + Log.WriteLine("-- ReadUnpackInfo --"); + Log.PushIndent(); + try + { + WaitAttribute(BlockType.Folder); + int numFolders = ReadNum(); + Log.WriteLine("NumFolders: {0}", numFolders); - db.MajorVersion = _header[6]; - db.MinorVersion = _header[7]; + using (CStreamSwitch streamSwitch = new CStreamSwitch()) + { + streamSwitch.Set(this, dataVector); + //folders.Clear(); + //folders.Reserve(numFolders); + folders = new List(numFolders); + int index = 0; + for (int i = 0; i < numFolders; i++) + { + var f = new CFolder { FirstPackStreamId = index }; + folders.Add(f); + GetNextFolderItem(f); + index += f.PackStreams.Count; + } + } - if(db.MajorVersion != 0) - throw new InvalidOperationException(); + WaitAttribute(BlockType.CodersUnpackSize); - uint crcFromArchive = DataReader.Get32(_header, 8); - long nextHeaderOffset = (long)DataReader.Get64(_header, 0xC); - long nextHeaderSize = (long)DataReader.Get64(_header, 0x14); - uint nextHeaderCrc = DataReader.Get32(_header, 0x1C); + Log.WriteLine("UnpackSizes:"); + for (int i = 0; i < numFolders; i++) + { + CFolder folder = folders[i]; + Log.Write(" #" + i + ":"); + int numOutStreams = folder.GetNumOutStreams(); + for (int j = 0; j < numOutStreams; j++) + { + long size = checked((long)ReadNumber()); + Log.Write(" " + size); + folder.UnpackSizes.Add(size); + } + Log.WriteLine(); + } - uint crc = CRC.kInitCRC; - crc = CRC.Update(crc, nextHeaderOffset); - crc = CRC.Update(crc, nextHeaderSize); - crc = CRC.Update(crc, nextHeaderCrc); - crc = CRC.Finish(crc); + for (; ; ) + { + BlockType? type = ReadId(); + if (type == BlockType.End) + return; - if(crc != crcFromArchive) - throw new InvalidOperationException(); + if (type == BlockType.CRC) + { + List crcs = ReadHashDigests(numFolders); + for (int i = 0; i < numFolders; i++) + folders[i].UnpackCRC = crcs[i]; + continue; + } - db.StartPositionAfterHeader = _streamOrigin + 0x20; + SkipData(); + } + } + finally { Log.PopIndent(); } + } - // empty header is ok - if(nextHeaderSize == 0) - { + private void ReadSubStreamsInfo(List folders, out List numUnpackStreamsInFolders, out List unpackSizes, out List digests) + { + Log.WriteLine("-- ReadSubStreamsInfo --"); + Log.PushIndent(); + try + { + numUnpackStreamsInFolders = null; + + BlockType? type; + for (; ; ) + { + type = ReadId(); + if (type == BlockType.NumUnpackStream) + { + numUnpackStreamsInFolders = new List(folders.Count); + Log.Write("NumUnpackStreams:"); + for (int i = 0; i < folders.Count; i++) + { + var num = ReadNum(); + Log.Write(" " + num); + numUnpackStreamsInFolders.Add(num); + } + Log.WriteLine(); + continue; + } + if (type == BlockType.CRC || type == BlockType.Size) + break; + if (type == BlockType.End) + break; + SkipData(); + } + + if (numUnpackStreamsInFolders == null) + { + numUnpackStreamsInFolders = new List(folders.Count); + for (int i = 0; i < folders.Count; i++) + numUnpackStreamsInFolders.Add(1); + } + + unpackSizes = new List(folders.Count); + for (int i = 0; i < numUnpackStreamsInFolders.Count; i++) + { + // v3.13 incorrectly worked with empty folders + // v4.07: we check that folder is empty + int numSubstreams = numUnpackStreamsInFolders[i]; + if (numSubstreams == 0) + continue; + + Log.Write("#{0} StreamSizes:", i); + long sum = 0; + for (int j = 1; j < numSubstreams; j++) + { + if (type == BlockType.Size) + { + long size = checked((long)ReadNumber()); + Log.Write(" " + size); + unpackSizes.Add(size); + sum += size; + } + } + unpackSizes.Add(folders[i].GetUnpackSize() - sum); + Log.WriteLine(" - rest: " + unpackSizes.Last()); + } + if (type == BlockType.Size) + type = ReadId(); + + int numDigests = 0; + int numDigestsTotal = 0; + for (int i = 0; i < folders.Count; i++) + { + int numSubstreams = numUnpackStreamsInFolders[i]; + if (numSubstreams != 1 || !folders[i].UnpackCRCDefined) + numDigests += numSubstreams; + numDigestsTotal += numSubstreams; + } + + digests = null; + + for (; ; ) + { + if (type == BlockType.CRC) + { + digests = new List(numDigestsTotal); + + List digests2 = ReadHashDigests(numDigests); + + int digestIndex = 0; + for (int i = 0; i < folders.Count; i++) + { + int numSubstreams = numUnpackStreamsInFolders[i]; + CFolder folder = folders[i]; + if (numSubstreams == 1 && folder.UnpackCRCDefined) + { + digests.Add(folder.UnpackCRC.Value); + } + else + { + for (int j = 0; j < numSubstreams; j++, digestIndex++) + digests.Add(digests2[digestIndex]); + } + } + + if (digestIndex != numDigests || numDigestsTotal != digests.Count) + System.Diagnostics.Debugger.Break(); + } + else if (type == BlockType.End) + { + if (digests == null) + { + digests = new List(numDigestsTotal); + for (int i = 0; i < numDigestsTotal; i++) + digests.Add(null); + } + return; + } + else + { + SkipData(); + } + + type = ReadId(); + } + } + finally { Log.PopIndent(); } + } + + 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) + { + Log.WriteLine("-- ReadStreamsInfo --"); + Log.PushIndent(); + try + { + dataOffset = long.MinValue; + packSizes = null; + packCRCs = null; + folders = null; + numUnpackStreamsInFolders = null; + unpackSizes = null; + digests = null; + + for (; ; ) + { + switch (ReadId()) + { + case BlockType.End: + return; + case BlockType.PackInfo: + ReadPackInfo(out dataOffset, out packSizes, out packCRCs); + break; + case BlockType.UnpackInfo: + ReadUnpackInfo(dataVector, out folders); + break; + case BlockType.SubStreamsInfo: + ReadSubStreamsInfo(folders, out numUnpackStreamsInFolders, out unpackSizes, out digests); + break; + default: + throw new InvalidOperationException(); + } + } + } + finally { Log.PopIndent(); } + } + + private List ReadAndDecodePackedStreams(long baseOffset, IPasswordProvider pass) + { + Log.WriteLine("-- ReadAndDecodePackedStreams --"); + Log.PushIndent(); + try + { + long dataStartPos; + List packSizes; + List packCRCs; + List folders; + List numUnpackStreamsInFolders; + List unpackSizes; + List digests; + + ReadStreamsInfo(null, + out dataStartPos, + out packSizes, + out packCRCs, + out folders, + out numUnpackStreamsInFolders, + out unpackSizes, + out digests); + + dataStartPos += baseOffset; + + var dataVector = new List(folders.Count); + int packIndex = 0; + foreach (var folder in folders) + { + long oldDataStartPos = dataStartPos; + long[] myPackSizes = new long[folder.PackStreams.Count]; + for (int i = 0; i < myPackSizes.Length; i++) + { + long packSize = packSizes[packIndex + i]; + myPackSizes[i] = packSize; + dataStartPos += packSize; + } + + var outStream = DecoderStreamHelper.CreateDecoderStream(_stream, oldDataStartPos, myPackSizes, folder, pass); + + int unpackSize = checked((int)folder.GetUnpackSize()); + byte[] data = new byte[unpackSize]; + outStream.ReadExact(data, 0, data.Length); + if (outStream.ReadByte() >= 0) + throw new InvalidOperationException("Decoded stream is longer than expected."); + dataVector.Add(data); + + if (folder.UnpackCRCDefined) + if (CRC.Finish(CRC.Update(CRC.kInitCRC, data, 0, unpackSize)) != folder.UnpackCRC) + throw new InvalidOperationException("Decoded stream does not match expected CRC."); + } + return dataVector; + } + finally { Log.PopIndent(); } + } + + private void ReadHeader(ArchiveDatabase db, IPasswordProvider getTextPassword) + { + Log.WriteLine("-- ReadHeader --"); + Log.PushIndent(); + try + { + BlockType? type = ReadId(); + + if (type == BlockType.ArchiveProperties) + { + ReadArchiveProperties(); + type = ReadId(); + } + + List dataVector = null; + if (type == BlockType.AdditionalStreamsInfo) + { + dataVector = ReadAndDecodePackedStreams(db.StartPositionAfterHeader, getTextPassword); + type = ReadId(); + } + + List unpackSizes; + List digests; + + if (type == 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; + type = 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++) + { + var folder = db.Folders[i]; + unpackSizes.Add(folder.GetUnpackSize()); + digests.Add(folder.UnpackCRC); + db.NumUnpackStreamsVector.Add(1); + } + } + + db.Files.Clear(); + + if (type == BlockType.End) + return; + + if (type != BlockType.FilesInfo) + throw new InvalidOperationException(); + + int numFiles = ReadNum(); + Log.WriteLine("NumFiles: " + numFiles); + db.Files = new List(numFiles); + for (int i = 0; i < numFiles; i++) + db.Files.Add(new CFileItem()); + + BitVector emptyStreamVector = new BitVector(numFiles); + BitVector emptyFileVector = null; + BitVector antiFileVector = null; + int numEmptyStreams = 0; + + for (; ; ) + { + type = ReadId(); + if (type == BlockType.End) + break; + + long size = checked((long)ReadNumber()); // TODO: throw invalid data on negative + int oldPos = _currentReader.Offset; + switch (type) + { + case BlockType.Name: + using (var streamSwitch = new CStreamSwitch()) + { + streamSwitch.Set(this, dataVector); + Log.Write("FileNames:"); + for (int i = 0; i < db.Files.Count; i++) + { + db.Files[i].Name = _currentReader.ReadString(); + Log.Write(" " + db.Files[i].Name); + } + Log.WriteLine(); + } + break; + case BlockType.WinAttributes: + Log.Write("WinAttributes:"); + ReadAttributeVector(dataVector, numFiles, delegate(int i, uint? attr) + { + db.Files[i].Attrib = attr; + Log.Write(" " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a")); + }); + Log.WriteLine(); + break; + case BlockType.EmptyStream: + emptyStreamVector = ReadBitVector(numFiles); + + Log.Write("EmptyStream: "); + for (int i = 0; i < emptyStreamVector.Length; i++) + { + if (emptyStreamVector[i]) + { + Log.Write("x"); + numEmptyStreams++; + } + else + { + Log.Write("."); + } + } + Log.WriteLine(); + + emptyFileVector = new BitVector(numEmptyStreams); + antiFileVector = new BitVector(numEmptyStreams); + break; + case BlockType.EmptyFile: + emptyFileVector = ReadBitVector(numEmptyStreams); + Log.Write("EmptyFile: "); + for (int i = 0; i < numEmptyStreams; i++) + Log.Write(emptyFileVector[i] ? "x" : "."); + Log.WriteLine(); + break; + case BlockType.Anti: + antiFileVector = ReadBitVector(numEmptyStreams); + Log.Write("Anti: "); + for (int i = 0; i < numEmptyStreams; i++) + Log.Write(antiFileVector[i] ? "x" : "."); + Log.WriteLine(); + break; + case BlockType.StartPos: + Log.Write("StartPos:"); + ReadNumberVector(dataVector, numFiles, delegate(int i, long? startPos) + { + db.Files[i].StartPos = startPos; + Log.Write(" " + (startPos.HasValue ? startPos.Value.ToString() : "n/a")); + }); + Log.WriteLine(); + break; + case BlockType.CTime: + Log.Write("CTime:"); + ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time) + { + db.Files[i].CTime = time; + Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); + }); + Log.WriteLine(); + break; + case BlockType.ATime: + Log.Write("ATime:"); + ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time) + { + db.Files[i].ATime = time; + Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); + }); + Log.WriteLine(); + break; + case BlockType.MTime: + Log.Write("MTime:"); + ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time) + { + db.Files[i].MTime = time; + Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); + }); + Log.WriteLine(); + break; + case BlockType.Dummy: + Log.Write("Dummy: " + size); + for (long j = 0; j < size; j++) + if (ReadByte() != 0) + throw new InvalidOperationException(); + break; + default: + SkipData(size); + break; + } + + // since 0.3 record sizes must be correct + bool checkRecordsSize = (db.MajorVersion > 0 || db.MinorVersion > 2); + if (checkRecordsSize && _currentReader.Offset - oldPos != size) + throw new InvalidOperationException(); + } + + int emptyFileIndex = 0; + int sizeIndex = 0; + for (int i = 0; i < numFiles; i++) + { + CFileItem file = db.Files[i]; + file.HasStream = !emptyStreamVector[i]; + if (file.HasStream) + { + file.IsDir = false; + file.IsAnti = false; + file.Size = unpackSizes[sizeIndex]; + file.Crc = digests[sizeIndex]; + sizeIndex++; + } + else + { + file.IsDir = !emptyFileVector[emptyFileIndex]; + file.IsAnti = antiFileVector[emptyFileIndex]; + emptyFileIndex++; + file.Size = 0; + file.Crc = null; + } + } + } + finally { Log.PopIndent(); } + } + + #endregion + + #region Public Methods + + public void Open(Stream stream) + { + Close(); + + _streamOrigin = stream.Position; + _streamEnding = stream.Length; + + // TODO: Check Signature! + _header = new byte[0x20]; + for (int offset = 0; offset < 0x20; ) + { + int delta = stream.Read(_header, offset, 0x20 - offset); + if (delta == 0) + throw new EndOfStreamException(); + offset += delta; + } + + _stream = stream; + } + + public void Close() + { + if (_stream != null) + _stream.Dispose(); + + foreach (var stream in _cachedStreams.Values) + stream.Dispose(); + + _cachedStreams.Clear(); + } + + public ArchiveDatabase ReadDatabase(IPasswordProvider pass) + { + var db = new ArchiveDatabase(); + db.Clear(); + + db.MajorVersion = _header[6]; + db.MinorVersion = _header[7]; + + if (db.MajorVersion != 0) + throw new InvalidOperationException(); + + uint crcFromArchive = DataReader.Get32(_header, 8); + long nextHeaderOffset = (long)DataReader.Get64(_header, 0xC); + long nextHeaderSize = (long)DataReader.Get64(_header, 0x14); + uint nextHeaderCrc = DataReader.Get32(_header, 0x1C); + + uint crc = CRC.kInitCRC; + crc = CRC.Update(crc, nextHeaderOffset); + crc = CRC.Update(crc, nextHeaderSize); + crc = CRC.Update(crc, nextHeaderCrc); + crc = CRC.Finish(crc); + + if (crc != crcFromArchive) + throw new InvalidOperationException(); + + db.StartPositionAfterHeader = _streamOrigin + 0x20; + + // empty header is ok + if (nextHeaderSize == 0) + { + db.Fill(); + return db; + } + + + if (nextHeaderOffset < 0 || nextHeaderSize < 0 || nextHeaderSize > Int32.MaxValue) + throw new InvalidOperationException(); + + if (nextHeaderOffset > _streamEnding - db.StartPositionAfterHeader) + throw new IndexOutOfRangeException(); + + _stream.Seek(nextHeaderOffset, SeekOrigin.Current); + + byte[] header = new byte[nextHeaderSize]; + _stream.ReadExact(header, 0, header.Length); + + if (CRC.Finish(CRC.Update(CRC.kInitCRC, header, 0, header.Length)) != nextHeaderCrc) + throw new InvalidOperationException(); + + using (CStreamSwitch streamSwitch = new CStreamSwitch()) + { + streamSwitch.Set(this, header); + + BlockType? type = ReadId(); + if (type != BlockType.Header) + { + if (type != BlockType.EncodedHeader) + throw new InvalidOperationException(); + + var dataVector = ReadAndDecodePackedStreams(db.StartPositionAfterHeader, pass); + + // compressed header without content is odd but ok + if (dataVector.Count == 0) + { + db.Fill(); + return db; + } + + if (dataVector.Count != 1) + throw new InvalidOperationException(); + + streamSwitch.Set(this, dataVector[0]); + + if (ReadId() != BlockType.Header) + throw new InvalidOperationException(); + } + + ReadHeader(db, pass); + } db.Fill(); return db; - } + } - - if(nextHeaderOffset < 0 || nextHeaderSize < 0 || nextHeaderSize > Int32.MaxValue) - throw new InvalidOperationException(); - - if(nextHeaderOffset > _streamEnding - db.StartPositionAfterHeader) - throw new IndexOutOfRangeException(); - - _stream.Seek(nextHeaderOffset, SeekOrigin.Current); - - byte[] header = new byte[nextHeaderSize]; - _stream.ReadExact(header, 0, header.Length); - - if(CRC.Finish(CRC.Update(CRC.kInitCRC, header, 0, header.Length)) != nextHeaderCrc) - throw new InvalidOperationException(); - - using(CStreamSwitch streamSwitch = new CStreamSwitch()) - { - streamSwitch.Set(this, header); - - BlockType? type = ReadId(); - if(type != BlockType.Header) + internal class CExtractFolderInfo + { + internal int FileIndex; + internal int FolderIndex; + internal List ExtractStatuses = new List(); + internal CExtractFolderInfo(int fileIndex, int folderIndex) { - if(type != BlockType.EncodedHeader) - throw new InvalidOperationException(); + FileIndex = fileIndex; + FolderIndex = folderIndex; + if (fileIndex != -1) + ExtractStatuses.Add(true); + } + } - var dataVector = ReadAndDecodePackedStreams(db.StartPositionAfterHeader, pass); + private class FolderUnpackStream : Stream + { + private ArchiveDatabase _db; + private int _otherIndex; + private int _startIndex; + private List _extractStatuses; - // compressed header without content is odd but ok - if (dataVector.Count == 0) - { - db.Fill(); - return db; - } - - if(dataVector.Count != 1) - throw new InvalidOperationException(); - - streamSwitch.Set(this, dataVector[0]); - - if(ReadId() != BlockType.Header) - throw new InvalidOperationException(); + public FolderUnpackStream(ArchiveDatabase db, int p, int startIndex, List list) + { + this._db = db; + this._otherIndex = p; + this._startIndex = startIndex; + this._extractStatuses = list; } - ReadHeader(db, pass); - } - db.Fill(); - return db; - } + #region Stream - 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(true); - } - } - - private class FolderUnpackStream: Stream - { - private ArchiveDatabase _db; - private int _otherIndex; - private int _startIndex; - private List _extractStatuses; - - public FolderUnpackStream(ArchiveDatabase db, int p, int startIndex, List list) - { - this._db = db; - this._otherIndex = p; - this._startIndex = startIndex; - this._extractStatuses = list; - } - - #region Stream - - public override bool CanRead - { - get { throw new NotImplementedException(); } - } - - public override bool CanSeek - { - get { throw new NotImplementedException(); } - } - - public override bool CanWrite - { - get { throw new NotImplementedException(); } - } - - public override void Flush() - { - throw new NotImplementedException(); - } - - public override long Length - { - get { throw new NotImplementedException(); } - } - - public override long Position - { - get + public override bool CanRead { - throw new NotImplementedException(); + get { throw new NotImplementedException(); } } - set + + public override bool CanSeek { - throw new NotImplementedException(); + get { throw new NotImplementedException(); } } - } - public override int Read(byte[] buffer, int offset, int count) - { - throw new NotImplementedException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotImplementedException(); - } - - public override void SetLength(long value) - { - throw new NotImplementedException(); - } - - private Stream _stream; - private long _rem; - private int _currentIndex; - private void ProcessEmptyFiles() - { - while(_currentIndex < _extractStatuses.Count && _db.Files[_startIndex + _currentIndex].Size == 0) + public override bool CanWrite { - OpenFile(); - _stream.Dispose(); - _stream = null; - _currentIndex++; + get { throw new NotImplementedException(); } } - } - private void OpenFile() - { - bool skip = !_extractStatuses[_currentIndex]; - int index = _startIndex + _currentIndex; - int realIndex = _otherIndex + index; - //string filename = @"D:\_testdump\" + _db.Files[index].Name; - //Directory.CreateDirectory(Path.GetDirectoryName(filename)); - //_stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Delete); - Log.WriteLine(_db.Files[index].Name); - 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) + + public override void Flush() { - if(_stream != null) - { - int write = count; - if(write > _rem) - write = (int)_rem; - _stream.Write(buffer, offset, write); - count -= write; - _rem -= write; - offset += write; - if(_rem == 0) - { - _stream.Dispose(); - _stream = null; - _currentIndex++; - ProcessEmptyFiles(); - } - } - else - { - ProcessEmptyFiles(); - if(_currentIndex == _extractStatuses.Count) - { - // we support partial extracting - System.Diagnostics.Debugger.Break(); - throw new NotImplementedException(); - } - OpenFile(); - } + throw new NotImplementedException(); } - } - #endregion - } + public override long Length + { + get { throw new NotImplementedException(); } + } - private Stream GetCachedDecoderStream(ArchiveDatabase _db, int folderIndex, IPasswordProvider pw) - { - Stream s; - if(!_cachedStreams.TryGetValue(folderIndex, out s)) - { - CFolder folderInfo = _db.Folders[folderIndex]; - int packStreamIndex = _db.Folders[folderIndex].FirstPackStreamId; - long folderStartPackPos = _db.GetFolderStreamPos(folderInfo, 0); - List packSizes = new List(); - for(int j = 0; j < folderInfo.PackStreams.Count; j++) - packSizes.Add(_db.PackSizes[packStreamIndex + j]); + public override long Position + { + get + { + throw new NotImplementedException(); + } + set + { + throw new NotImplementedException(); + } + } - s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes.ToArray(), folderInfo, pw); - _cachedStreams.Add(folderIndex, s); - } - return s; - } + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotImplementedException(); + } - public Stream OpenStream(ArchiveDatabase _db, int fileIndex, IPasswordProvider pw) - { - int folderIndex = _db.FileIndexToFolderIndexMap[fileIndex]; - int numFilesInFolder = _db.NumUnpackStreamsVector[folderIndex]; - int firstFileIndex = _db.FolderStartFileIndex[folderIndex]; - if(firstFileIndex > fileIndex || fileIndex - firstFileIndex >= numFilesInFolder) - throw new InvalidOperationException(); + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } - int skipCount = fileIndex - firstFileIndex; - long skipSize = 0; - for(int i = 0; i < skipCount; i++) - skipSize += _db.Files[firstFileIndex + i].Size; + public override void SetLength(long value) + { + throw new NotImplementedException(); + } - Stream s = GetCachedDecoderStream(_db, folderIndex, pw); - s.Position = skipSize; - return new ReadOnlySubStream(s, _db.Files[fileIndex].Size); - } + private Stream _stream; + private long _rem; + private int _currentIndex; + private void ProcessEmptyFiles() + { + while (_currentIndex < _extractStatuses.Count && _db.Files[_startIndex + _currentIndex].Size == 0) + { + OpenFile(); + _stream.Dispose(); + _stream = null; + _currentIndex++; + } + } + private void OpenFile() + { + bool skip = !_extractStatuses[_currentIndex]; + int index = _startIndex + _currentIndex; + int realIndex = _otherIndex + index; + //string filename = @"D:\_testdump\" + _db.Files[index].Name; + //Directory.CreateDirectory(Path.GetDirectoryName(filename)); + //_stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Delete); + Log.WriteLine(_db.Files[index].Name); + 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 write = count; + if (write > _rem) + write = (int)_rem; + _stream.Write(buffer, offset, write); + count -= write; + _rem -= write; + offset += write; + if (_rem == 0) + { + _stream.Dispose(); + _stream = null; + _currentIndex++; + ProcessEmptyFiles(); + } + } + else + { + ProcessEmptyFiles(); + if (_currentIndex == _extractStatuses.Count) + { + // we support partial extracting + System.Diagnostics.Debugger.Break(); + throw new NotImplementedException(); + } + OpenFile(); + } + } + } - public void Extract(ArchiveDatabase _db, int[] indices, IPasswordProvider pw) - { - int numItems; - bool allFilesMode = (indices == null); - if(allFilesMode) - numItems = _db.Files.Count; - else - numItems = indices.Length; + #endregion + } - if(numItems == 0) - return; + private Stream GetCachedDecoderStream(ArchiveDatabase _db, int folderIndex, IPasswordProvider pw) + { + Stream s; + if (!_cachedStreams.TryGetValue(folderIndex, out s)) + { + CFolder folderInfo = _db.Folders[folderIndex]; + int packStreamIndex = _db.Folders[folderIndex].FirstPackStreamId; + long folderStartPackPos = _db.GetFolderStreamPos(folderInfo, 0); + List packSizes = new List(); + for (int j = 0; j < folderInfo.PackStreams.Count; j++) + packSizes.Add(_db.PackSizes[packStreamIndex + j]); - List extractFolderInfoVector = new List(); - for(int i = 0; i < numItems; i++) - { - int fileIndex = allFilesMode ? i : indices[i]; + s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes.ToArray(), folderInfo, pw); + _cachedStreams.Add(folderIndex, s); + } + return s; + } + public Stream OpenStream(ArchiveDatabase _db, int fileIndex, IPasswordProvider pw) + { int folderIndex = _db.FileIndexToFolderIndexMap[fileIndex]; - if(folderIndex == -1) - { - extractFolderInfoVector.Add(new CExtractFolderInfo(fileIndex, -1)); - continue; - } + int numFilesInFolder = _db.NumUnpackStreamsVector[folderIndex]; + int firstFileIndex = _db.FolderStartFileIndex[folderIndex]; + if (firstFileIndex > fileIndex || fileIndex - firstFileIndex >= numFilesInFolder) + throw new InvalidOperationException(); - if(extractFolderInfoVector.Count == 0 || folderIndex != extractFolderInfoVector.Last().FolderIndex) - extractFolderInfoVector.Add(new CExtractFolderInfo(-1, folderIndex)); + int skipCount = fileIndex - firstFileIndex; + long skipSize = 0; + for (int i = 0; i < skipCount; i++) + skipSize += _db.Files[firstFileIndex + i].Size; - CExtractFolderInfo efi = extractFolderInfoVector.Last(); + Stream s = GetCachedDecoderStream(_db, folderIndex, pw); + s.Position = skipSize; + return new ReadOnlySubStream(s, _db.Files[fileIndex].Size); + } - int startIndex = _db.FolderStartFileIndex[folderIndex]; - for(int index = efi.ExtractStatuses.Count; index <= fileIndex - startIndex; index++) - efi.ExtractStatuses.Add(index == fileIndex - startIndex); - } - - foreach(CExtractFolderInfo efi in extractFolderInfoVector) - { - int startIndex; - if(efi.FileIndex != -1) - startIndex = efi.FileIndex; + public void Extract(ArchiveDatabase _db, int[] indices, IPasswordProvider pw) + { + int numItems; + bool allFilesMode = (indices == null); + if (allFilesMode) + numItems = _db.Files.Count; else - startIndex = _db.FolderStartFileIndex[efi.FolderIndex]; + numItems = indices.Length; - var outStream = new FolderUnpackStream(_db, 0, startIndex, efi.ExtractStatuses); + if (numItems == 0) + return; - if(efi.FileIndex != -1) - continue; - - int folderIndex = efi.FolderIndex; - CFolder folderInfo = _db.Folders[folderIndex]; - - int packStreamIndex = _db.Folders[folderIndex].FirstPackStreamId; - long folderStartPackPos = _db.GetFolderStreamPos(folderInfo, 0); - - List packSizes = new List(); - for(int j = 0; j < folderInfo.PackStreams.Count; j++) - packSizes.Add(_db.PackSizes[packStreamIndex + j]); - - // TODO: If the decoding fails the last file may be extracted incompletely. Delete it? - - Stream s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes.ToArray(), folderInfo, pw); - byte[] buffer = new byte[4 << 10]; - for(; ; ) + List extractFolderInfoVector = new List(); + for (int i = 0; i < numItems; i++) { - int processed = s.Read(buffer, 0, buffer.Length); - if(processed == 0) break; - outStream.Write(buffer, 0, processed); + int fileIndex = allFilesMode ? i : indices[i]; + + int folderIndex = _db.FileIndexToFolderIndexMap[fileIndex]; + if (folderIndex == -1) + { + extractFolderInfoVector.Add(new CExtractFolderInfo(fileIndex, -1)); + continue; + } + + if (extractFolderInfoVector.Count == 0 || folderIndex != extractFolderInfoVector.Last().FolderIndex) + extractFolderInfoVector.Add(new CExtractFolderInfo(-1, folderIndex)); + + CExtractFolderInfo efi = extractFolderInfoVector.Last(); + + int startIndex = _db.FolderStartFileIndex[folderIndex]; + for (int index = efi.ExtractStatuses.Count; index <= fileIndex - startIndex; index++) + efi.ExtractStatuses.Add(index == fileIndex - startIndex); } - } - } - public IEnumerable GetFiles(ArchiveDatabase db) - { - return db.Files; - } + foreach (CExtractFolderInfo efi in extractFolderInfoVector) + { + int startIndex; + if (efi.FileIndex != -1) + startIndex = efi.FileIndex; + else + startIndex = _db.FolderStartFileIndex[efi.FolderIndex]; - public int GetFileIndex(ArchiveDatabase db, CFileItem item) - { - return db.Files.IndexOf(item); - } + var outStream = new FolderUnpackStream(_db, 0, startIndex, efi.ExtractStatuses); - #endregion - } + if (efi.FileIndex != -1) + continue; + + int folderIndex = efi.FolderIndex; + CFolder folderInfo = _db.Folders[folderIndex]; + + int packStreamIndex = _db.Folders[folderIndex].FirstPackStreamId; + long folderStartPackPos = _db.GetFolderStreamPos(folderInfo, 0); + + List packSizes = new List(); + for (int j = 0; j < folderInfo.PackStreams.Count; j++) + packSizes.Add(_db.PackSizes[packStreamIndex + j]); + + // TODO: If the decoding fails the last file may be extracted incompletely. Delete it? + + Stream s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes.ToArray(), folderInfo, pw); + byte[] buffer = new byte[4 << 10]; + for (; ; ) + { + int processed = s.Read(buffer, 0, buffer.Length); + if (processed == 0) + break; + outStream.Write(buffer, 0, processed); + } + } + } + + public IEnumerable GetFiles(ArchiveDatabase db) + { + return db.Files; + } + + public int GetFileIndex(ArchiveDatabase db, CFileItem item) + { + return db.Files.IndexOf(item); + } + + #endregion + } } \ No newline at end of file diff --git a/SharpCompress/Common/SevenZip/CFileItem.cs b/SharpCompress/Common/SevenZip/CFileItem.cs index 3940302a..fca9d3db 100644 --- a/SharpCompress/Common/SevenZip/CFileItem.cs +++ b/SharpCompress/Common/SevenZip/CFileItem.cs @@ -2,33 +2,33 @@ namespace SharpCompress.Common.SevenZip { - public 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; } + 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 { get { return Crc != null; } } - public bool AttribDefined { get { return Attrib != null; } } + public bool HasStream { get; internal set; } + public bool IsDir { get; internal set; } + public bool CrcDefined { get { return Crc != null; } } + public bool AttribDefined { get { return Attrib != null; } } - public void SetAttrib(uint attrib) - { - this.Attrib = attrib; - } + public void SetAttrib(uint attrib) + { + this.Attrib = attrib; + } - public DateTime? CTime { get; internal set; } - public DateTime? ATime { get; internal set; } - public DateTime? MTime { get; internal set; } + 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 long? StartPos { get; internal set; } + public bool IsAnti { get; internal set; } - internal CFileItem() - { - HasStream = true; - } - } + internal CFileItem() + { + HasStream = true; + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Filters/BCJ2Filter.cs b/SharpCompress/Compressor/Filters/BCJ2Filter.cs index f68b4c45..c6bf2db4 100644 --- a/SharpCompress/Compressor/Filters/BCJ2Filter.cs +++ b/SharpCompress/Compressor/Filters/BCJ2Filter.cs @@ -1,15 +1,12 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.IO; namespace SharpCompress.Compressor.Filters { - public class BCJ2Filter : Stream + internal class BCJ2Filter : Stream { - private Stream baseStream; - private byte[] input = new byte[4096]; + private readonly Stream baseStream; + private readonly byte[] input = new byte[4096]; private int inputOffset = 0; private int inputCount = 0; private bool endReached = false; @@ -136,7 +133,7 @@ namespace SharpCompress.Compressor.Filters buffer[offset++] = b; size++; position++; - + if (!IsJ(prevByte, b)) prevByte = b; else diff --git a/SharpCompress/Compressor/Filters/BCJFilter.cs b/SharpCompress/Compressor/Filters/BCJFilter.cs index 5a010e0c..a6861434 100644 --- a/SharpCompress/Compressor/Filters/BCJFilter.cs +++ b/SharpCompress/Compressor/Filters/BCJFilter.cs @@ -1,20 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.IO; +using System.IO; namespace SharpCompress.Compressor.Filters { - public class BCJFilter : Filter + internal class BCJFilter : Filter { - private static readonly bool[] MASK_TO_ALLOWED_STATUS = new bool[] {true, true, true, false, true, false, false, false}; + private static readonly bool[] MASK_TO_ALLOWED_STATUS = new bool[] { true, true, true, false, true, false, false, false }; private static readonly int[] MASK_TO_BIT_NUMBER = new int[] { 0, 1, 2, 2, 3, 3, 3, 3 }; private int pos; private int prevMask = 0; - public BCJFilter(bool isEncoder, Stream baseStream) : base(isEncoder, baseStream, 5) + public BCJFilter(bool isEncoder, Stream baseStream) + : base(isEncoder, baseStream, 5) { pos = 5; } @@ -30,18 +27,24 @@ namespace SharpCompress.Compressor.Filters int end = offset + count - 5; int i; - for (i = offset; i <= end; ++i) { + for (i = offset; i <= end; ++i) + { if ((buffer[i] & 0xFE) != 0xE8) continue; prevPos = i - prevPos; - if ((prevPos & ~3) != 0) { // (unsigned)prevPos > 3 + if ((prevPos & ~3) != 0) + { // (unsigned)prevPos > 3 prevMask = 0; - } else { + } + else + { prevMask = (prevMask << (prevPos - 1)) & 7; - if (prevMask != 0) { + if (prevMask != 0) + { if (!MASK_TO_ALLOWED_STATUS[prevMask] || test86MSByte( - buffer[i + 4 - MASK_TO_BIT_NUMBER[prevMask]])) { + buffer[i + 4 - MASK_TO_BIT_NUMBER[prevMask]])) + { prevPos = i; prevMask = (prevMask << 1) | 1; continue; @@ -51,13 +54,15 @@ namespace SharpCompress.Compressor.Filters prevPos = i; - if (test86MSByte(buffer[i + 4])) { + if (test86MSByte(buffer[i + 4])) + { int src = buffer[i + 1] | (buffer[i + 2] << 8) | (buffer[i + 3] << 16) | (buffer[i + 4] << 24); int dest; - while (true) { + while (true) + { if (isEncoder) dest = src + (pos + i - offset); else @@ -78,7 +83,9 @@ namespace SharpCompress.Compressor.Filters buffer[i + 3] = (byte)(dest >> 16); buffer[i + 4] = (byte)(~(((dest >> 24) & 1) - 1)); i += 4; - } else { + } + else + { prevMask = (prevMask << 1) | 1; } } diff --git a/SharpCompress/Compressor/Filters/Filter.cs b/SharpCompress/Compressor/Filters/Filter.cs index 448e89da..f0d10e79 100644 --- a/SharpCompress/Compressor/Filters/Filter.cs +++ b/SharpCompress/Compressor/Filters/Filter.cs @@ -1,12 +1,9 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.IO; namespace SharpCompress.Compressor.Filters { - public abstract class Filter : Stream + internal abstract class Filter : Stream { protected bool isEncoder; protected Stream baseStream; @@ -22,7 +19,7 @@ namespace SharpCompress.Compressor.Filters this.isEncoder = isEncoder; this.baseStream = baseStream; tail = new byte[lookahead - 1]; - window = new byte[tail.Length*2]; + window = new byte[tail.Length * 2]; } public override bool CanRead @@ -66,7 +63,7 @@ namespace SharpCompress.Compressor.Filters { int size = 0; - if (transformed > 0) + if (transformed > 0) { int copySize = transformed; if (copySize > count) diff --git a/SharpCompress/Compressor/LZMA/BitVector.cs b/SharpCompress/Compressor/LZMA/BitVector.cs index 350efbea..fa4ffa2b 100644 --- a/SharpCompress/Compressor/LZMA/BitVector.cs +++ b/SharpCompress/Compressor/LZMA/BitVector.cs @@ -4,7 +4,7 @@ using System.Text; namespace SharpCompress.Compressor.LZMA { - public class BitVector + internal class BitVector { private uint[] mBits; private int mLength; @@ -20,23 +20,23 @@ namespace SharpCompress.Compressor.LZMA mLength = length; mBits = new uint[(length + 31) >> 5]; - if(initValue) - for(int i = 0; i < mBits.Length; i++) + if (initValue) + for (int i = 0; i < mBits.Length; i++) mBits[i] = ~0u; } public BitVector(List bits) : this(bits.Count) { - for(int i = 0; i < bits.Count; i++) - if(bits[i]) + for (int i = 0; i < bits.Count; i++) + if (bits[i]) SetBit(i); } public bool[] ToArray() { bool[] bits = new bool[mLength]; - for(int i = 0; i < bits.Length; i++) + for (int i = 0; i < bits.Length; i++) bits[i] = this[i]; return bits; } @@ -50,7 +50,7 @@ namespace SharpCompress.Compressor.LZMA { get { - if(index < 0 || index >= mLength) + if (index < 0 || index >= mLength) throw new ArgumentOutOfRangeException("index"); return (mBits[index >> 5] & (1u << (index & 31))) != 0; @@ -59,7 +59,7 @@ namespace SharpCompress.Compressor.LZMA public void SetBit(int index) { - if(index < 0 || index >= mLength) + if (index < 0 || index >= mLength) throw new ArgumentOutOfRangeException("index"); mBits[index >> 5] |= 1u << (index & 31); @@ -67,7 +67,7 @@ namespace SharpCompress.Compressor.LZMA internal bool GetAndSet(int index) { - if(index < 0 || index >= mLength) + if (index < 0 || index >= mLength) throw new ArgumentOutOfRangeException("index"); uint bits = mBits[index >> 5]; @@ -79,7 +79,7 @@ namespace SharpCompress.Compressor.LZMA public override string ToString() { StringBuilder sb = new StringBuilder(mLength); - for(int i = 0; i < mLength; i++) + for (int i = 0; i < mLength; i++) sb.Append(this[i] ? 'x' : '.'); return sb.ToString(); } diff --git a/SharpCompress/Compressor/LZMA/Registry.cs b/SharpCompress/Compressor/LZMA/Registry.cs index b2e038da..afdacad3 100644 --- a/SharpCompress/Compressor/LZMA/Registry.cs +++ b/SharpCompress/Compressor/LZMA/Registry.cs @@ -23,29 +23,29 @@ namespace SharpCompress.Compressor.LZMA internal static Stream CreateDecoderStream(CMethodId id, Stream[] inStreams, byte[] info, IPasswordProvider pass, long limit) { - switch(id.Id) + switch (id.Id) { - case k_Copy: - if(info != null) - throw new NotSupportedException(); - return inStreams.Single(); - case k_LZMA: - case k_LZMA2: - return new LzmaStream(info, inStreams.Single(), -1, limit); + case k_Copy: + if (info != null) + throw new NotSupportedException(); + return inStreams.Single(); + case k_LZMA: + case k_LZMA2: + return new LzmaStream(info, inStreams.Single(), -1, limit); #if !SILVERLIGHT && !PORTABLE - case CMethodId.kAESId: - return new AesDecoderStream(inStreams.Single(), info, pass, limit); + case CMethodId.kAESId: + return new AesDecoderStream(inStreams.Single(), info, pass, limit); #endif - case k_BCJ: - return new BCJFilter(false, inStreams.Single()); - case k_BCJ2: - return new Bcj2DecoderStream(inStreams, info, limit); - case k_BZip2: - return new BZip2Stream(inStreams.Single(), CompressionMode.Decompress, true); - case k_PPMD: - return new PpmdStream(new PpmdProperties(info), inStreams.Single(), false ); - default: - throw new NotSupportedException(); + case k_BCJ: + return new BCJFilter(false, inStreams.Single()); + case k_BCJ2: + return new Bcj2DecoderStream(inStreams, info, limit); + case k_BZip2: + return new BZip2Stream(inStreams.Single(), CompressionMode.Decompress, true); + case k_PPMD: + return new PpmdStream(new PpmdProperties(info), inStreams.Single(), false); + default: + throw new NotSupportedException(); } } } diff --git a/SharpCompress/Compressor/LZMA/Utilites/IPasswordProvider.cs b/SharpCompress/Compressor/LZMA/Utilites/IPasswordProvider.cs index 83431c0a..07a696a1 100644 --- a/SharpCompress/Compressor/LZMA/Utilites/IPasswordProvider.cs +++ b/SharpCompress/Compressor/LZMA/Utilites/IPasswordProvider.cs @@ -1,6 +1,6 @@ namespace SharpCompress.Compressor.LZMA.Utilites { - public interface IPasswordProvider + internal interface IPasswordProvider { string CryptoGetTextPassword(); }