From 21087323af2caa5cfb394eee30ecd919b68421c6 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Sat, 9 Jan 2016 13:29:29 +0000 Subject: [PATCH 01/21] Make Tar last in detection as it contains other files --- SharpCompress/Archive/ArchiveFactory.cs | 12 ++++++------ SharpCompress/Reader/ReaderFactory.cs | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/SharpCompress/Archive/ArchiveFactory.cs b/SharpCompress/Archive/ArchiveFactory.cs index 923f7424..db62a2db 100644 --- a/SharpCompress/Archive/ArchiveFactory.cs +++ b/SharpCompress/Archive/ArchiveFactory.cs @@ -31,12 +31,6 @@ namespace SharpCompress.Archive return ZipArchive.Open(stream, options, null); } stream.Seek(0, SeekOrigin.Begin); - if (TarArchive.IsTarFile(stream)) - { - stream.Seek(0, SeekOrigin.Begin); - return TarArchive.Open(stream, options); - } - stream.Seek(0, SeekOrigin.Begin); if (SevenZipArchive.IsSevenZipFile(stream)) { stream.Seek(0, SeekOrigin.Begin); @@ -54,6 +48,12 @@ namespace SharpCompress.Archive stream.Seek(0, SeekOrigin.Begin); return RarArchive.Open(stream, options); } + stream.Seek(0, SeekOrigin.Begin); + if (TarArchive.IsTarFile(stream)) + { + stream.Seek(0, SeekOrigin.Begin); + return TarArchive.Open(stream, options); + } throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip"); } diff --git a/SharpCompress/Reader/ReaderFactory.cs b/SharpCompress/Reader/ReaderFactory.cs index e336f2cb..dbf1756b 100644 --- a/SharpCompress/Reader/ReaderFactory.cs +++ b/SharpCompress/Reader/ReaderFactory.cs @@ -61,12 +61,6 @@ namespace SharpCompress.Reader } } - rewindableStream.Rewind(false); - if (TarArchive.IsTarFile(rewindableStream)) - { - rewindableStream.Rewind(true); - return TarReader.Open(rewindableStream, options); - } rewindableStream.Rewind(false); if (RarArchive.IsRarFile(rewindableStream, options)) { @@ -74,6 +68,12 @@ namespace SharpCompress.Reader return RarReader.Open(rewindableStream, options); } + rewindableStream.Rewind(false); + if (TarArchive.IsTarFile(rewindableStream)) + { + rewindableStream.Rewind(true); + return TarReader.Open(rewindableStream, options); + } throw new InvalidOperationException("Cannot determine compressed stream type. Supported Reader Formats: Zip, GZip, BZip2, Tar, Rar"); } } From 3f2ca67416a747131df13b19b1e9600c69b5d6b3 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Fri, 15 Jan 2016 10:04:28 +0000 Subject: [PATCH 02/21] Forgot the file overload --- SharpCompress/Archive/ArchiveFactory.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/SharpCompress/Archive/ArchiveFactory.cs b/SharpCompress/Archive/ArchiveFactory.cs index db62a2db..278e9e10 100644 --- a/SharpCompress/Archive/ArchiveFactory.cs +++ b/SharpCompress/Archive/ArchiveFactory.cs @@ -126,12 +126,6 @@ namespace SharpCompress.Archive return ZipArchive.Open(fileInfo, options, null); } stream.Seek(0, SeekOrigin.Begin); - if (TarArchive.IsTarFile(stream)) - { - stream.Dispose(); - return TarArchive.Open(fileInfo, options); - } - stream.Seek(0, SeekOrigin.Begin); if (SevenZipArchive.IsSevenZipFile(stream)) { stream.Dispose(); @@ -149,6 +143,12 @@ namespace SharpCompress.Archive stream.Dispose(); return RarArchive.Open(fileInfo, options); } + stream.Seek(0, SeekOrigin.Begin); + if (TarArchive.IsTarFile(stream)) + { + stream.Dispose(); + return TarArchive.Open(fileInfo, options); + } throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip"); } } From 3be7f9da371bcdda18adb7b1709535114de70dc1 Mon Sep 17 00:00:00 2001 From: mpiva Date: Sun, 17 Jan 2016 02:31:55 -0300 Subject: [PATCH 03/21] Adds Non Lineal "Solid Rar" Extraction to RarArchive. --- SharpCompress/Archive/Rar/RarArchive.cs | 3 ++ SharpCompress/Archive/Rar/RarArchiveEntry.cs | 38 ++++++++++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/SharpCompress/Archive/Rar/RarArchive.cs b/SharpCompress/Archive/Rar/RarArchive.cs index f7f88b39..4eaada0a 100644 --- a/SharpCompress/Archive/Rar/RarArchive.cs +++ b/SharpCompress/Archive/Rar/RarArchive.cs @@ -14,6 +14,9 @@ namespace SharpCompress.Archive.Rar { public class RarArchive : AbstractArchive { + internal IEnumerator SolidEntryEnumerator; + internal List SolidReadedEntries=new List(); + private readonly Unpack unpack = new Unpack(); internal Unpack Unpack diff --git a/SharpCompress/Archive/Rar/RarArchiveEntry.cs b/SharpCompress/Archive/Rar/RarArchiveEntry.cs index 17f32170..ab033514 100644 --- a/SharpCompress/Archive/Rar/RarArchiveEntry.cs +++ b/SharpCompress/Archive/Rar/RarArchiveEntry.cs @@ -70,11 +70,45 @@ namespace SharpCompress.Archive.Rar return parts.Aggregate(0L, (total, fp) => { return total + fp.FileHeader.CompressedSize; }); } } + private readonly byte[] skipBuffer = new byte[4096]; + private void Skip(RarArchiveEntry en) + { + using (var s = new RarStream(archive.Unpack, en.FileHeader, new MultiVolumeReadOnlyStream(en.parts, archive))) + { + while (s.Read(skipBuffer, 0, skipBuffer.Length) > 0); + } + } + + private void MoveNext() + { + archive.SolidReadedEntries.Add(archive.SolidEntryEnumerator.Current); + if (!archive.SolidEntryEnumerator.MoveNext()) + { + archive.SolidEntryEnumerator = archive.Entries.GetEnumerator(); + archive.SolidReadedEntries = new List(); + archive.SolidEntryEnumerator.MoveNext(); + } + } public Stream OpenEntryStream() { - return new RarStream(archive.Unpack, FileHeader, - new MultiVolumeReadOnlyStream(Parts.Cast(), archive)); + if (archive.IsSolid) + { + + if ((archive.SolidEntryEnumerator == null) || (archive.SolidReadedEntries.Any(b=>b.FileHeader==FileHeader))) + { + archive.SolidEntryEnumerator = archive.Entries.GetEnumerator(); + archive.SolidReadedEntries = new List(); + archive.SolidEntryEnumerator.MoveNext(); + } + while (archive.SolidEntryEnumerator.Current.FileHeader != FileHeader) + { + Skip(archive.SolidEntryEnumerator.Current); + MoveNext(); + } + MoveNext(); + } + return new RarStream(archive.Unpack, FileHeader, new MultiVolumeReadOnlyStream(Parts.Cast(), archive)); } public bool IsComplete From d5c88ebab3293658f0c1ac331a868227e9353fa4 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Fri, 22 Jan 2016 14:51:05 +0100 Subject: [PATCH 04/21] Bugfix for inflate algorithm cutting of the end of certain blocks --- SharpCompress/Compressor/Deflate/Inflate.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/SharpCompress/Compressor/Deflate/Inflate.cs b/SharpCompress/Compressor/Deflate/Inflate.cs index c4f0889b..dcfcddbf 100644 --- a/SharpCompress/Compressor/Deflate/Inflate.cs +++ b/SharpCompress/Compressor/Deflate/Inflate.cs @@ -895,6 +895,11 @@ namespace SharpCompress.Compressor.Deflate r = ZlibConstants.Z_OK; else { + // Handling missing trailing bit(s) + var tmp_tindex = (tree_index + (b & InternalInflateConstants.InflateMask[k]))*3; + if (k >= tree[tmp_tindex + 1]) + break; + blocks.bitb = b; blocks.bitk = k; z.AvailableBytesIn = n; @@ -998,6 +1003,11 @@ namespace SharpCompress.Compressor.Deflate r = ZlibConstants.Z_OK; else { + // Handling missing trailing bit(s) + var tmp_tindex = (tree_index + (b & InternalInflateConstants.InflateMask[k]))*3; + if (k >= tree[tmp_tindex + 1]) + break; + blocks.bitb = b; blocks.bitk = k; z.AvailableBytesIn = n; From ecceec8e1a9771499931f9ff33518174875ce16f Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Fri, 22 Jan 2016 15:06:55 +0100 Subject: [PATCH 05/21] Tabs -> spaces fix --- SharpCompress/Compressor/Deflate/Inflate.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/SharpCompress/Compressor/Deflate/Inflate.cs b/SharpCompress/Compressor/Deflate/Inflate.cs index dcfcddbf..587a69aa 100644 --- a/SharpCompress/Compressor/Deflate/Inflate.cs +++ b/SharpCompress/Compressor/Deflate/Inflate.cs @@ -895,11 +895,11 @@ namespace SharpCompress.Compressor.Deflate r = ZlibConstants.Z_OK; else { - // Handling missing trailing bit(s) - var tmp_tindex = (tree_index + (b & InternalInflateConstants.InflateMask[k]))*3; - if (k >= tree[tmp_tindex + 1]) - break; - + // Handling missing trailing bit(s) + var tmp_tindex = (tree_index + (b & InternalInflateConstants.InflateMask[k]))*3; + if (k >= tree[tmp_tindex + 1]) + break; + blocks.bitb = b; blocks.bitk = k; z.AvailableBytesIn = n; @@ -1003,10 +1003,10 @@ namespace SharpCompress.Compressor.Deflate r = ZlibConstants.Z_OK; else { - // Handling missing trailing bit(s) - var tmp_tindex = (tree_index + (b & InternalInflateConstants.InflateMask[k]))*3; - if (k >= tree[tmp_tindex + 1]) - break; + // Handling missing trailing bit(s) + var tmp_tindex = (tree_index + (b & InternalInflateConstants.InflateMask[k]))*3; + if (k >= tree[tmp_tindex + 1]) + break; blocks.bitb = b; blocks.bitk = k; From 8ceac9000c2e4867171dab0361cc18bfe8a2d883 Mon Sep 17 00:00:00 2001 From: benshoof Date: Fri, 22 Jan 2016 14:32:35 -0900 Subject: [PATCH 06/21] SharpCompress now endian neutral SharpCompress can now be used on machines with big endian architecture such as powerpc. All byte conversions now run through Mono's DataConverter (or a portable version for builds that don't allow unsafe code) instead of BitConverter, as BitConverter's behavior depends on the host cpu. --- SharpCompress/Common/GZip/GZipFilePart.cs | 3 +- SharpCompress/Common/Tar/Headers/TarHeader.cs | 14 +- .../Common/Zip/Headers/ZipFileEntry.cs | 5 +- .../Zip/WinzipAesCryptoStream.Portable.cs | 3 +- .../Common/Zip/WinzipAesCryptoStream.cs | 3 +- .../Zip/WinzipAesEncryptionData.Portable.cs | 5 +- .../Common/Zip/WinzipAesEncryptionData.cs | 5 +- SharpCompress/Common/Zip/ZipFilePart.cs | 7 +- .../Compressor/Deflate/GZipStream.cs | 3 +- .../Compressor/Deflate/ZlibBaseStream.cs | 11 +- SharpCompress/Compressor/LZMA/LzmaStream.cs | 3 +- SharpCompress/Compressor/PPMd/H/FreqData.cs | 13 +- SharpCompress/Compressor/PPMd/H/PPMContext.cs | 9 +- .../Compressor/PPMd/H/RarMemBlock.cs | 18 +- SharpCompress/Compressor/PPMd/H/RarNode.cs | 5 +- SharpCompress/Compressor/PPMd/H/State.cs | 5 +- .../Compressor/PPMd/PpmdProperties.cs | 7 +- SharpCompress/Compressor/Rar/VM/RarVM.cs | 22 +- .../Converter/DataConverter.Portable.cs | 237 +++ SharpCompress/Converter/DataConverter.cs | 1849 +++++++++++++++++ SharpCompress/Crypto/PBKDF2.cs | 21 +- SharpCompress/IO/MarkingBinaryReader.cs | 32 +- SharpCompress/SharpCompress.Portable.csproj | 1 + .../SharpCompress.PortableTest.csproj | 1 + SharpCompress/SharpCompress.Unsigned.csproj | 1 + .../SharpCompress.WindowsStore.csproj | 1 + SharpCompress/SharpCompress.csproj | 1 + SharpCompress/Utility.cs | 197 -- .../Writer/Zip/ZipCentralDirectoryEntry.cs | 29 +- SharpCompress/Writer/Zip/ZipWriter.cs | 31 +- 30 files changed, 2208 insertions(+), 334 deletions(-) create mode 100644 SharpCompress/Converter/DataConverter.Portable.cs create mode 100644 SharpCompress/Converter/DataConverter.cs diff --git a/SharpCompress/Common/GZip/GZipFilePart.cs b/SharpCompress/Common/GZip/GZipFilePart.cs index 5aab3dba..673e50ea 100644 --- a/SharpCompress/Common/GZip/GZipFilePart.cs +++ b/SharpCompress/Common/GZip/GZipFilePart.cs @@ -3,6 +3,7 @@ using System.IO; using SharpCompress.Common.Tar.Headers; using SharpCompress.Compressor; using SharpCompress.Compressor.Deflate; +using SharpCompress.Converter; namespace SharpCompress.Common.GZip { @@ -50,7 +51,7 @@ namespace SharpCompress.Common.GZip if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8) throw new ZlibException("Bad GZIP header."); - Int32 timet = BitConverter.ToInt32(header, 4); + Int32 timet = DataConverter.LittleEndian.GetInt32(header, 4); DateModified = TarHeader.Epoch.AddSeconds(timet); if ((header[3] & 0x04) == 0x04) { diff --git a/SharpCompress/Common/Tar/Headers/TarHeader.cs b/SharpCompress/Common/Tar/Headers/TarHeader.cs index 8323fc3f..fa59c1c3 100644 --- a/SharpCompress/Common/Tar/Headers/TarHeader.cs +++ b/SharpCompress/Common/Tar/Headers/TarHeader.cs @@ -4,6 +4,7 @@ using System.IO; using System.Net; #endif using System.Text; +using SharpCompress.Converter; namespace SharpCompress.Common.Tar.Headers { @@ -64,11 +65,7 @@ namespace SharpCompress.Common.Tar.Headers if (Size >= 0x1FFFFFFFF) { -#if PORTABLE || NETFX_CORE - byte[] bytes = BitConverter.GetBytes(Utility.HostToNetworkOrder(Size)); -#else - byte[] bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(Size)); -#endif + byte[] bytes = DataConverter.BigEndian.GetBytes(Size); var bytes12 = new byte[12]; bytes.CopyTo(bytes12, 12 - bytes.Length); bytes12[0] |= 0x80; @@ -119,12 +116,7 @@ namespace SharpCompress.Common.Tar.Headers EntryType = (EntryType) buffer[156]; if ((buffer[124] & 0x80) == 0x80) // if size in binary { - long sizeBigEndian = BitConverter.ToInt64(buffer, 0x80); -#if PORTABLE || NETFX_CORE - Size = Utility.NetworkToHostOrder(sizeBigEndian); -#else - Size = IPAddress.NetworkToHostOrder(sizeBigEndian); -#endif + Size = DataConverter.BigEndian.GetInt64(buffer, 0x80); } else { diff --git a/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs b/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs index f5a813ed..08b4772e 100644 --- a/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs +++ b/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Text; +using SharpCompress.Converter; namespace SharpCompress.Common.Zip.Headers { @@ -68,13 +69,13 @@ namespace SharpCompress.Common.Zip.Headers { for (int i = 0; i < extra.Length-4;) { - ExtraDataType type = (ExtraDataType) BitConverter.ToUInt16(extra, i); + ExtraDataType type = (ExtraDataType)DataConverter.LittleEndian.GetUInt16(extra, i); if (!Enum.IsDefined(typeof (ExtraDataType), type)) { type = ExtraDataType.NotImplementedExtraData; } - ushort length = BitConverter.ToUInt16(extra, i + 2); + ushort length = DataConverter.LittleEndian.GetUInt16(extra, i + 2); byte[] data = new byte[length]; Buffer.BlockCopy(extra, i + 4, data, 0, length); Extra.Add(LocalEntryHeaderExtraFactory.Create(type,length,data)); diff --git a/SharpCompress/Common/Zip/WinzipAesCryptoStream.Portable.cs b/SharpCompress/Common/Zip/WinzipAesCryptoStream.Portable.cs index 1acbeefd..8611a76a 100644 --- a/SharpCompress/Common/Zip/WinzipAesCryptoStream.Portable.cs +++ b/SharpCompress/Common/Zip/WinzipAesCryptoStream.Portable.cs @@ -3,6 +3,7 @@ using System.IO; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Parameters; +using SharpCompress.Converter; namespace SharpCompress.Common.Zip { @@ -113,7 +114,7 @@ namespace SharpCompress.Common.Zip : bytesRemaining; // update the counter - Array.Copy(BitConverter.GetBytes(nonce++), 0, counter, 0, 4); + DataConverter.LittleEndian.PutBytes(counter, 0, nonce++); // Determine if this is the final block if ((bytesToRead == bytesRemaining) && (totalBytesLeftToRead == 0)) diff --git a/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs b/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs index 9d8e14ca..ead9d548 100644 --- a/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs +++ b/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Security.Cryptography; +using SharpCompress.Converter; namespace SharpCompress.Common.Zip { @@ -117,7 +118,7 @@ namespace SharpCompress.Common.Zip : bytesRemaining; // update the counter - Array.Copy(BitConverter.GetBytes(nonce++), 0, counter, 0, 4); + DataConverter.LittleEndian.PutBytes(counter, 0, nonce++); // Determine if this is the final block if ((bytesToRead == bytesRemaining) && (totalBytesLeftToRead == 0)) diff --git a/SharpCompress/Common/Zip/WinzipAesEncryptionData.Portable.cs b/SharpCompress/Common/Zip/WinzipAesEncryptionData.Portable.cs index 0fe7050d..79a405cc 100644 --- a/SharpCompress/Common/Zip/WinzipAesEncryptionData.Portable.cs +++ b/SharpCompress/Common/Zip/WinzipAesEncryptionData.Portable.cs @@ -1,5 +1,6 @@ using System; using System.Text; +using SharpCompress.Converter; using SharpCompress.Crypto; namespace SharpCompress.Common.Zip @@ -56,10 +57,10 @@ namespace SharpCompress.Common.Zip generatedVerifyValue = paramz.GetBytes(2); - short verify = BitConverter.ToInt16(passwordVerifyValue, 0); + short verify = DataConverter.LittleEndian.GetInt16(passwordVerifyValue, 0); if (password != null) { - short generated = BitConverter.ToInt16(generatedVerifyValue, 0); + short generated = DataConverter.LittleEndian.GetInt16(generatedVerifyValue, 0); if (verify != generated) throw new InvalidFormatException("bad password"); } diff --git a/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs b/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs index eb37ac98..a5de3294 100644 --- a/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs +++ b/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs @@ -1,4 +1,5 @@ using System; +using SharpCompress.Converter; namespace SharpCompress.Common.Zip { @@ -54,10 +55,10 @@ namespace SharpCompress.Common.Zip IvBytes = rfc2898.GetBytes(KeySizeInBytes); generatedVerifyValue = rfc2898.GetBytes(2); - short verify = BitConverter.ToInt16(passwordVerifyValue, 0); + short verify = DataConverter.LittleEndian.GetInt16(passwordVerifyValue, 0); if (password != null) { - short generated = BitConverter.ToInt16(generatedVerifyValue, 0); + short generated = DataConverter.LittleEndian.GetInt16(generatedVerifyValue, 0); if (verify != generated) throw new InvalidFormatException("bad password"); } diff --git a/SharpCompress/Common/Zip/ZipFilePart.cs b/SharpCompress/Common/Zip/ZipFilePart.cs index 6052d593..43ec7122 100644 --- a/SharpCompress/Common/Zip/ZipFilePart.cs +++ b/SharpCompress/Common/Zip/ZipFilePart.cs @@ -7,6 +7,7 @@ using SharpCompress.Compressor.BZip2; using SharpCompress.Compressor.Deflate; using SharpCompress.Compressor.LZMA; using SharpCompress.Compressor.PPMd; +using SharpCompress.Converter; using SharpCompress.IO; namespace SharpCompress.Common.Zip @@ -108,19 +109,19 @@ namespace SharpCompress.Common.Zip { throw new InvalidFormatException("Winzip data length is not 7."); } - ushort method = BitConverter.ToUInt16(data.DataBytes, 0); + ushort method = DataConverter.LittleEndian.GetUInt16(data.DataBytes, 0); if (method != 0x01 && method != 0x02) { throw new InvalidFormatException("Unexpected vendor version number for WinZip AES metadata"); } - ushort vendorId = BitConverter.ToUInt16(data.DataBytes, 2); + ushort vendorId = DataConverter.LittleEndian.GetUInt16(data.DataBytes, 2); if (vendorId != 0x4541) { throw new InvalidFormatException("Unexpected vendor ID for WinZip AES metadata"); } - Header.CompressionMethod = (ZipCompressionMethod)BitConverter.ToUInt16(data.DataBytes, 5); + Header.CompressionMethod = (ZipCompressionMethod)DataConverter.LittleEndian.GetUInt16(data.DataBytes, 5); return CreateDecompressionStream(stream); } default: diff --git a/SharpCompress/Compressor/Deflate/GZipStream.cs b/SharpCompress/Compressor/Deflate/GZipStream.cs index 7b3215d9..308bc692 100644 --- a/SharpCompress/Compressor/Deflate/GZipStream.cs +++ b/SharpCompress/Compressor/Deflate/GZipStream.cs @@ -30,6 +30,7 @@ using System; using System.IO; using SharpCompress.Common; +using SharpCompress.Converter; namespace SharpCompress.Compressor.Deflate { @@ -417,7 +418,7 @@ namespace SharpCompress.Compressor.Deflate LastModified = DateTime.Now; TimeSpan delta = LastModified.Value - UnixEpoch; var timet = (Int32) delta.TotalSeconds; - Array.Copy(BitConverter.GetBytes(timet), 0, header, i, 4); + DataConverter.LittleEndian.PutBytes(header, i, timet); i += 4; // xflg diff --git a/SharpCompress/Compressor/Deflate/ZlibBaseStream.cs b/SharpCompress/Compressor/Deflate/ZlibBaseStream.cs index 1bfe1f6e..7d753dff 100644 --- a/SharpCompress/Compressor/Deflate/ZlibBaseStream.cs +++ b/SharpCompress/Compressor/Deflate/ZlibBaseStream.cs @@ -27,6 +27,7 @@ using System; using SharpCompress.Common; using SharpCompress.Common.Tar.Headers; +using SharpCompress.Converter; namespace SharpCompress.Compressor.Deflate { @@ -221,9 +222,9 @@ namespace SharpCompress.Compressor.Deflate { // Emit the GZIP trailer: CRC32 and size mod 2^32 int c1 = crc.Crc32Result; - _stream.Write(BitConverter.GetBytes(c1), 0, 4); + _stream.Write(DataConverter.LittleEndian.GetBytes(c1), 0, 4); int c2 = (Int32)(crc.TotalBytesRead & 0x00000000FFFFFFFF); - _stream.Write(BitConverter.GetBytes(c2), 0, 4); + _stream.Write(DataConverter.LittleEndian.GetBytes(c2), 0, 4); } else { @@ -267,9 +268,9 @@ namespace SharpCompress.Compressor.Deflate } - Int32 crc32_expected = BitConverter.ToInt32(trailer, 0); + Int32 crc32_expected = DataConverter.LittleEndian.GetInt32(trailer, 0); Int32 crc32_actual = crc.Crc32Result; - Int32 isize_expected = BitConverter.ToInt32(trailer, 4); + Int32 isize_expected = DataConverter.LittleEndian.GetInt32(trailer, 4); Int32 isize_actual = (Int32)(_z.TotalBytesOut & 0x00000000FFFFFFFF); if (crc32_actual != crc32_expected) @@ -405,7 +406,7 @@ namespace SharpCompress.Compressor.Deflate if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8) throw new ZlibException("Bad GZIP header."); - Int32 timet = BitConverter.ToInt32(header, 4); + Int32 timet = DataConverter.LittleEndian.GetInt32(header, 4); _GzipMtime = TarHeader.Epoch.AddSeconds(timet); totalBytesRead += n; if ((header[3] & 0x04) == 0x04) diff --git a/SharpCompress/Compressor/LZMA/LzmaStream.cs b/SharpCompress/Compressor/LZMA/LzmaStream.cs index 22522f9d..bc046e70 100644 --- a/SharpCompress/Compressor/LZMA/LzmaStream.cs +++ b/SharpCompress/Compressor/LZMA/LzmaStream.cs @@ -1,6 +1,7 @@ using System; using System.IO; using SharpCompress.Compressor.LZMA.LZ; +using SharpCompress.Converter; namespace SharpCompress.Compressor.LZMA { @@ -56,7 +57,7 @@ namespace SharpCompress.Compressor.LZMA if (!isLZMA2) { - dictionarySize = BitConverter.ToInt32(properties, 1); + dictionarySize = DataConverter.LittleEndian.GetInt32(properties, 1); outWindow.Create(dictionarySize); if (presetDictionary != null) outWindow.Train(presetDictionary); diff --git a/SharpCompress/Compressor/PPMd/H/FreqData.cs b/SharpCompress/Compressor/PPMd/H/FreqData.cs index a37ea93a..b94e01dd 100644 --- a/SharpCompress/Compressor/PPMd/H/FreqData.cs +++ b/SharpCompress/Compressor/PPMd/H/FreqData.cs @@ -1,4 +1,5 @@ using System.Text; +using SharpCompress.Converter; namespace SharpCompress.Compressor.PPMd.H { @@ -19,9 +20,9 @@ namespace SharpCompress.Compressor.PPMd.H internal int SummFreq { - get { return Utility.readShortLittleEndian(Memory, Address) & 0xffff; } + get { return DataConverter.LittleEndian.GetInt16(Memory, Address) & 0xffff; } - set { Utility.WriteLittleEndian(Memory, Address, (short) value); } + set { DataConverter.LittleEndian.PutBytes(Memory, Address, (short)value); } } internal FreqData Initialize(byte[] mem) @@ -31,12 +32,14 @@ namespace SharpCompress.Compressor.PPMd.H internal void IncrementSummFreq(int dSummFreq) { - Utility.incShortLittleEndian(Memory, Address, (short) dSummFreq); + short summFreq = DataConverter.LittleEndian.GetInt16(Memory, Address); + summFreq += (short)dSummFreq; + DataConverter.LittleEndian.PutBytes(Memory, Address, summFreq); } internal int GetStats() { - return Utility.readIntLittleEndian(Memory, Address + 2); + return DataConverter.LittleEndian.GetInt32(Memory, Address + 2); } internal virtual void SetStats(State state) @@ -46,7 +49,7 @@ namespace SharpCompress.Compressor.PPMd.H internal void SetStats(int state) { - Utility.WriteLittleEndian(Memory, Address + 2, state); + DataConverter.LittleEndian.PutBytes(Memory, Address + 2, state); } public override System.String ToString() diff --git a/SharpCompress/Compressor/PPMd/H/PPMContext.cs b/SharpCompress/Compressor/PPMd/H/PPMContext.cs index 8b36bf6d..f2029f96 100644 --- a/SharpCompress/Compressor/PPMd/H/PPMContext.cs +++ b/SharpCompress/Compressor/PPMd/H/PPMContext.cs @@ -1,4 +1,5 @@ using System.Text; +using SharpCompress.Converter; namespace SharpCompress.Compressor.PPMd.H { @@ -21,7 +22,7 @@ namespace SharpCompress.Compressor.PPMd.H { if (Memory != null) { - numStats = Utility.readShortLittleEndian(Memory, Address) & 0xffff; + numStats = DataConverter.LittleEndian.GetInt16(Memory, Address) & 0xffff; } return numStats; } @@ -31,7 +32,7 @@ namespace SharpCompress.Compressor.PPMd.H this.numStats = value & 0xffff; if (Memory != null) { - Utility.WriteLittleEndian(Memory, Address, (short) value); + DataConverter.LittleEndian.PutBytes(Memory, Address, (short) value); } } } @@ -103,7 +104,7 @@ namespace SharpCompress.Compressor.PPMd.H { if (Memory != null) { - suffix = Utility.readIntLittleEndian(Memory, Address + 8); + suffix = DataConverter.LittleEndian.GetInt32(Memory, Address + 8); } return suffix; } @@ -118,7 +119,7 @@ namespace SharpCompress.Compressor.PPMd.H this.suffix = suffix; if (Memory != null) { - Utility.WriteLittleEndian(Memory, Address + 8, suffix); + DataConverter.LittleEndian.PutBytes(Memory, Address + 8, suffix); } } diff --git a/SharpCompress/Compressor/PPMd/H/RarMemBlock.cs b/SharpCompress/Compressor/PPMd/H/RarMemBlock.cs index 52f601d8..0a71c529 100644 --- a/SharpCompress/Compressor/PPMd/H/RarMemBlock.cs +++ b/SharpCompress/Compressor/PPMd/H/RarMemBlock.cs @@ -1,3 +1,5 @@ +using SharpCompress.Converter; + namespace SharpCompress.Compressor.PPMd.H { internal class RarMemBlock : Pointer @@ -19,7 +21,7 @@ namespace SharpCompress.Compressor.PPMd.H { if (Memory != null) { - stamp = Utility.readShortLittleEndian(Memory, Address) & 0xffff; + stamp = DataConverter.LittleEndian.GetInt16(Memory, Address) & 0xffff; } return stamp; } @@ -29,7 +31,7 @@ namespace SharpCompress.Compressor.PPMd.H this.stamp = value; if (Memory != null) { - Utility.WriteLittleEndian(Memory, Address, (short) value); + DataConverter.LittleEndian.PutBytes(Memory, Address, (short)value); } } } @@ -60,7 +62,7 @@ namespace SharpCompress.Compressor.PPMd.H { if (Memory != null) { - next = Utility.readIntLittleEndian(Memory, Address + 4); + next = DataConverter.LittleEndian.GetInt32(Memory, Address + 4); } return next; } @@ -75,7 +77,7 @@ namespace SharpCompress.Compressor.PPMd.H this.next = next; if (Memory != null) { - Utility.WriteLittleEndian(Memory, Address + 4, next); + DataConverter.LittleEndian.PutBytes(Memory, Address + 4, next); } } @@ -83,7 +85,7 @@ namespace SharpCompress.Compressor.PPMd.H { if (Memory != null) { - NU = Utility.readShortLittleEndian(Memory, Address + 2) & 0xffff; + NU = DataConverter.LittleEndian.GetInt16(Memory, Address + 2) & 0xffff; } return NU; } @@ -93,7 +95,7 @@ namespace SharpCompress.Compressor.PPMd.H NU = nu & 0xffff; if (Memory != null) { - Utility.WriteLittleEndian(Memory, Address + 2, (short) nu); + DataConverter.LittleEndian.PutBytes(Memory, Address + 2, (short)nu); } } @@ -101,7 +103,7 @@ namespace SharpCompress.Compressor.PPMd.H { if (Memory != null) { - prev = Utility.readIntLittleEndian(Memory, Address + 8); + prev = DataConverter.LittleEndian.GetInt32(Memory, Address + 8); } return prev; } @@ -116,7 +118,7 @@ namespace SharpCompress.Compressor.PPMd.H this.prev = prev; if (Memory != null) { - Utility.WriteLittleEndian(Memory, Address + 8, prev); + DataConverter.LittleEndian.PutBytes(Memory, Address + 8, prev); } } } diff --git a/SharpCompress/Compressor/PPMd/H/RarNode.cs b/SharpCompress/Compressor/PPMd/H/RarNode.cs index 2369fb5a..ffb75c50 100644 --- a/SharpCompress/Compressor/PPMd/H/RarNode.cs +++ b/SharpCompress/Compressor/PPMd/H/RarNode.cs @@ -1,4 +1,5 @@ using System.Text; +using SharpCompress.Converter; namespace SharpCompress.Compressor.PPMd.H { @@ -17,7 +18,7 @@ namespace SharpCompress.Compressor.PPMd.H { if (Memory != null) { - next = Utility.readIntLittleEndian(Memory, Address); + next = DataConverter.LittleEndian.GetInt32(Memory, Address); } return next; } @@ -32,7 +33,7 @@ namespace SharpCompress.Compressor.PPMd.H this.next = next; if (Memory != null) { - Utility.WriteLittleEndian(Memory, Address, next); + DataConverter.LittleEndian.PutBytes(Memory, Address, next); } } diff --git a/SharpCompress/Compressor/PPMd/H/State.cs b/SharpCompress/Compressor/PPMd/H/State.cs index a459321e..687883c4 100644 --- a/SharpCompress/Compressor/PPMd/H/State.cs +++ b/SharpCompress/Compressor/PPMd/H/State.cs @@ -1,5 +1,6 @@ using System; using System.Text; +using SharpCompress.Converter; namespace SharpCompress.Compressor.PPMd.H { @@ -38,7 +39,7 @@ namespace SharpCompress.Compressor.PPMd.H internal int GetSuccessor() { - return Utility.readIntLittleEndian(Memory, Address + 2); + return DataConverter.LittleEndian.GetInt32(Memory, Address + 2); } internal void SetSuccessor(PPMContext successor) @@ -48,7 +49,7 @@ namespace SharpCompress.Compressor.PPMd.H internal void SetSuccessor(int successor) { - Utility.WriteLittleEndian(Memory, Address + 2, successor); + DataConverter.LittleEndian.PutBytes(Memory, Address + 2, successor); } internal void SetValues(StateRef state) diff --git a/SharpCompress/Compressor/PPMd/PpmdProperties.cs b/SharpCompress/Compressor/PPMd/PpmdProperties.cs index 9527835b..5875bcac 100644 --- a/SharpCompress/Compressor/PPMd/PpmdProperties.cs +++ b/SharpCompress/Compressor/PPMd/PpmdProperties.cs @@ -1,4 +1,5 @@ using System; +using SharpCompress.Converter; namespace SharpCompress.Compressor.PPMd { @@ -39,7 +40,7 @@ namespace SharpCompress.Compressor.PPMd { if (properties.Length == 2) { - ushort props = BitConverter.ToUInt16(properties, 0); + ushort props = DataConverter.LittleEndian.GetUInt16(properties, 0); AllocatorSize = (((props >> 4) & 0xff) + 1) << 20; ModelOrder = (props & 0x0f) + 1; ModelRestorationMethod = (I1.ModelRestorationMethod) (props >> 12); @@ -47,7 +48,7 @@ namespace SharpCompress.Compressor.PPMd else if (properties.Length == 5) { Version = PpmdVersion.H7z; - AllocatorSize = BitConverter.ToInt32(properties, 1); + AllocatorSize = DataConverter.LittleEndian.GetInt32(properties, 1); ModelOrder = properties[0]; } } @@ -72,7 +73,7 @@ namespace SharpCompress.Compressor.PPMd get { return - BitConverter.GetBytes( + DataConverter.LittleEndian.GetBytes( (ushort) ((ModelOrder - 1) + (((AllocatorSize >> 20) - 1) << 4) + ((ushort) ModelRestorationMethod << 12))); } diff --git a/SharpCompress/Compressor/Rar/VM/RarVM.cs b/SharpCompress/Compressor/Rar/VM/RarVM.cs index f1f25d34..27990a33 100644 --- a/SharpCompress/Compressor/Rar/VM/RarVM.cs +++ b/SharpCompress/Compressor/Rar/VM/RarVM.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using SharpCompress.Converter; namespace SharpCompress.Compressor.Rar.VM { @@ -77,11 +78,12 @@ namespace SharpCompress.Compressor.Rar.VM { if (IsVMMem(mem)) { - return Utility.readIntLittleEndian(mem, offset); + return DataConverter.LittleEndian.GetInt32(mem, offset); } else { - return Utility.readIntBigEndian(mem, offset); + return DataConverter.BigEndian.GetInt32(mem, offset); + } } } @@ -103,19 +105,11 @@ namespace SharpCompress.Compressor.Rar.VM { if (IsVMMem(mem)) { - Utility.WriteLittleEndian(mem, offset, value); - // Mem[offset + 0] = (byte) value; - // Mem[offset + 1] = (byte) (value >>> 8); - // Mem[offset + 2] = (byte) (value >>> 16); - // Mem[offset + 3] = (byte) (value >>> 24); + DataConverter.LittleEndian.PutBytes(mem, offset, value); } else { - Utility.writeIntBigEndian(mem, offset, value); - // Mem[offset + 3] = (byte) value; - // Mem[offset + 2] = (byte) (value >>> 8); - // Mem[offset + 1] = (byte) (value >>> 16); - // Mem[offset + 0] = (byte) (value >>> 24); + DataConverter.BigEndian.PutBytes(mem, offset, value); } } // #define SET_VALUE(ByteMode,Addr,Value) SetValue(ByteMode,(uint @@ -136,12 +130,12 @@ namespace SharpCompress.Compressor.Rar.VM if (cmdOp.Type == VMOpType.VM_OPREGMEM) { int pos = (cmdOp.Offset + cmdOp.Base) & VM_MEMMASK; - ret = Utility.readIntLittleEndian(Mem, pos); + ret = DataConverter.LittleEndian.GetInt32(Mem, pos); } else { int pos = cmdOp.Offset; - ret = Utility.readIntLittleEndian(Mem, pos); + ret = DataConverter.LittleEndian.GetInt32(Mem, pos); } return ret; } diff --git a/SharpCompress/Converter/DataConverter.Portable.cs b/SharpCompress/Converter/DataConverter.Portable.cs new file mode 100644 index 00000000..eec9846b --- /dev/null +++ b/SharpCompress/Converter/DataConverter.Portable.cs @@ -0,0 +1,237 @@ +using System; + +namespace SharpCompress.Converter +{ + // This is a portable version of Mono's DataConverter class with just the small subset of functionality + // needed by SharpCompress. Portable in this case means that it contains no unsafe code. + // + // This class simply wraps BitConverter and reverses byte arrays when endianess doesn't match the host's. + // + // Everything public in this class must match signatures in Mono's DataConverter. + + abstract class DataConverter + { + static readonly DataConverter copyConverter = new CopyConverter(); + static readonly DataConverter swapConverter = new SwapConverter(); + + static readonly bool isLittleEndian = BitConverter.IsLittleEndian; + + public static DataConverter LittleEndian + { + get { return isLittleEndian ? copyConverter : swapConverter; } + } + + public static DataConverter BigEndian + { + get { return isLittleEndian ? swapConverter : copyConverter; } + } + + public abstract Int16 GetInt16(byte[] data, int index); + public abstract UInt16 GetUInt16(byte[] data, int index); + public abstract Int32 GetInt32(byte[] data, int index); + public abstract UInt32 GetUInt32(byte[] data, int index); + public abstract Int64 GetInt64(byte[] data, int index); + public abstract UInt64 GetUInt64(byte[] data, int index); + + public abstract byte[] GetBytes(Int16 value); + public abstract byte[] GetBytes(UInt16 value); + public abstract byte[] GetBytes(Int32 value); + public abstract byte[] GetBytes(UInt32 value); + public abstract byte[] GetBytes(Int64 value); + public abstract byte[] GetBytes(UInt64 value); + + public void PutBytes(byte[] data, int index, Int16 value) + { + byte[] temp = GetBytes(value); + Array.Copy(temp, 0, data, index, 2); + } + + public void PutBytes(byte[] data, int index, UInt16 value) + { + byte[] temp = GetBytes(value); + Array.Copy(temp, 0, data, index, 2); + } + + public void PutBytes(byte[] data, int index, Int32 value) + { + byte[] temp = GetBytes(value); + Array.Copy(temp, 0, data, index, 4); + } + + public void PutBytes(byte[] data, int index, UInt32 value) + { + byte[] temp = GetBytes(value); + Array.Copy(temp, 0, data, index, 4); + } + + public void PutBytes(byte[] data, int index, Int64 value) + { + byte[] temp = GetBytes(value); + Array.Copy(temp, 0, data, index, 8); + } + + public void PutBytes(byte[] data, int index, UInt64 value) + { + byte[] temp = GetBytes(value); + Array.Copy(temp, 0, data, index, 8); + } + + // CopyConverter wraps BitConverter making all conversions host endian + class CopyConverter : DataConverter + { + public override Int16 GetInt16(byte[] data, int index) + { + return BitConverter.ToInt16(data, index); + } + + public override UInt16 GetUInt16(byte[] data, int index) + { + return BitConverter.ToUInt16(data, index); + } + + public override Int32 GetInt32(byte[] data, int index) + { + return BitConverter.ToInt32(data, index); + } + + public override UInt32 GetUInt32(byte[] data, int index) + { + return BitConverter.ToUInt32(data, index); + } + + public override Int64 GetInt64(byte[] data, int index) + { + return BitConverter.ToInt64(data, index); + } + + public override UInt64 GetUInt64(byte[] data, int index) + { + return BitConverter.ToUInt64(data, index); + } + + public override byte[] GetBytes(Int16 value) + { + return BitConverter.GetBytes(value); + } + + public override byte[] GetBytes(UInt16 value) + { + return BitConverter.GetBytes(value); + } + + public override byte[] GetBytes(Int32 value) + { + return BitConverter.GetBytes(value); + } + + public override byte[] GetBytes(UInt32 value) + { + return BitConverter.GetBytes(value); + } + + public override byte[] GetBytes(Int64 value) + { + return BitConverter.GetBytes(value); + } + + public override byte[] GetBytes(UInt64 value) + { + return BitConverter.GetBytes(value); + } + } + + // SwapConverter wraps and reverses BitConverter making all conversions the opposite of host endian + class SwapConverter : DataConverter + { + public override Int16 GetInt16(byte[] data, int index) + { + byte[] temp = new byte[2]; + Array.Copy(data, index, temp, 0, 2); + Array.Reverse(temp); + return BitConverter.ToInt16(temp, 0); + } + + public override UInt16 GetUInt16(byte[] data, int index) + { + byte[] temp = new byte[2]; + Array.Copy(data, index, temp, 0, 2); + Array.Reverse(temp); + return BitConverter.ToUInt16(temp, 0); + } + + public override Int32 GetInt32(byte[] data, int index) + { + byte[] temp = new byte[4]; + Array.Copy(data, index, temp, 0, 4); + Array.Reverse(temp); + return BitConverter.ToInt32(temp, 0); + } + + public override UInt32 GetUInt32(byte[] data, int index) + { + byte[] temp = new byte[4]; + Array.Copy(data, index, temp, 0, 4); + Array.Reverse(temp); + return BitConverter.ToUInt32(temp, 0); + } + + public override Int64 GetInt64(byte[] data, int index) + { + byte[] temp = new byte[8]; + Array.Copy(data, index, temp, 0, 8); + Array.Reverse(temp); + return BitConverter.ToInt64(temp, 0); + } + + public override UInt64 GetUInt64(byte[] data, int index) + { + byte[] temp = new byte[8]; + Array.Copy(data, index, temp, 0, 8); + Array.Reverse(temp); + return BitConverter.ToUInt64(temp, 0); + } + + public override byte[] GetBytes(Int16 value) + { + byte[] ret = BitConverter.GetBytes(value); + Array.Reverse(ret); + return ret; + } + + public override byte[] GetBytes(UInt16 value) + { + byte[] ret = BitConverter.GetBytes(value); + Array.Reverse(ret); + return ret; + } + + public override byte[] GetBytes(Int32 value) + { + byte[] ret = BitConverter.GetBytes(value); + Array.Reverse(ret); + return ret; + } + + public override byte[] GetBytes(UInt32 value) + { + byte[] ret = BitConverter.GetBytes(value); + Array.Reverse(ret); + return ret; + } + + public override byte[] GetBytes(Int64 value) + { + byte[] ret = BitConverter.GetBytes(value); + Array.Reverse(ret); + return ret; + } + + public override byte[] GetBytes(UInt64 value) + { + byte[] ret = BitConverter.GetBytes(value); + Array.Reverse(ret); + return ret; + } + } + } +} \ No newline at end of file diff --git a/SharpCompress/Converter/DataConverter.cs b/SharpCompress/Converter/DataConverter.cs new file mode 100644 index 00000000..0b2acd9f --- /dev/null +++ b/SharpCompress/Converter/DataConverter.cs @@ -0,0 +1,1849 @@ +// +// Authors: +// Miguel de Icaza (miguel@novell.com) +// +// See the following url for documentation: +// http://www.mono-project.com/Mono_DataConvert +// +// Compilation Options: +// MONO_DATACONVERTER_PUBLIC: +// Makes the class public instead of the default internal. +// +// MONO_DATACONVERTER_STATIC_METHODS: +// Exposes the public static methods. +// +// TODO: +// Support for "DoubleWordsAreSwapped" for ARM devices +// +// Copyright (C) 2006 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +using System; +using System.Collections; +using System.Text; +using System.Collections.Generic; + +#pragma warning disable 3021 + +namespace SharpCompress.Converter { + +#if MONO_DATACONVERTER_PUBLIC + public +#endif + unsafe abstract class DataConverter { + +// Disables the warning: CLS compliance checking will not be performed on +// `XXXX' because it is not visible from outside this assembly +#pragma warning disable 3019 + static readonly DataConverter SwapConv = new SwapConverter (); + static readonly DataConverter CopyConv = new CopyConverter (); + + public static readonly bool IsLittleEndian = BitConverter.IsLittleEndian; + + 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 [] ret = new byte [8]; + PutBytes (ret, 0, value); + return ret; + } + + public byte[] GetBytes (float value) + { + byte [] ret = new byte [4]; + PutBytes (ret, 0, value); + return ret; + } + + public byte[] GetBytes (int value) + { + byte [] ret = new byte [4]; + PutBytes (ret, 0, value); + return ret; + } + + public byte[] GetBytes (long value) + { + byte [] ret = new byte [8]; + PutBytes (ret, 0, value); + return ret; + } + + public byte[] GetBytes (short value) + { + byte [] ret = new byte [2]; + PutBytes (ret, 0, value); + return ret; + } + + [CLSCompliant (false)] + public byte[] GetBytes (ushort value) + { + byte [] ret = new byte [2]; + PutBytes (ret, 0, value); + return ret; + } + + [CLSCompliant (false)] + public byte[] GetBytes (uint value) + { + byte [] ret = new byte [4]; + PutBytes (ret, 0, value); + return ret; + } + + [CLSCompliant (false)] + public byte[] GetBytes (ulong value) + { + byte [] ret = new byte [8]; + PutBytes (ret, 0, value); + return ret; + } + + static public DataConverter LittleEndian { + get { + return BitConverter.IsLittleEndian ? CopyConv : SwapConv; + } + } + + static public DataConverter BigEndian { + get { + return BitConverter.IsLittleEndian ? SwapConv : CopyConv; + } + } + + static public DataConverter Native { + get { + return CopyConv; + } + } + + static int Align (int current, int align) + { + return ((current + align - 1) / align) * align; + } + + class PackContext { + // Buffer + public byte [] buffer; + int next; + + public string description; + public int i; // position in the description + public DataConverter conv; + public int repeat; + + // + // if align == -1, auto align to the size of the byte array + // if align == 0, do not do alignment + // Any other values aligns to that particular size + // + public int align; + + public void Add (byte [] group) + { + //Console.WriteLine ("Adding {0} bytes to {1} (next={2}", group.Length, + // buffer == null ? "null" : buffer.Length.ToString (), next); + + if (buffer == null){ + buffer = group; + next = group.Length; + return; + } + if (align != 0){ + if (align == -1) + next = Align (next, group.Length); + else + next = Align (next, align); + align = 0; + } + + if (next + group.Length > buffer.Length){ + byte [] nb = new byte [System.Math.Max (next, 16) * 2 + group.Length]; + Array.Copy (buffer, nb, buffer.Length); + Array.Copy (group, 0, nb, next, group.Length); + next = next + group.Length; + buffer = nb; + } else { + Array.Copy (group, 0, buffer, next, group.Length); + next += group.Length; + } + } + + public byte [] Get () + { + if (buffer == null) + return new byte [0]; + + if (buffer.Length != next){ + byte [] b = new byte [next]; + Array.Copy (buffer, b, next); + return b; + } + return buffer; + } + } + + // + // Format includes: + // Control: + // ^ Switch to big endian encoding + // _ Switch to little endian encoding + // % Switch to host (native) encoding + // ! aligns the next data type to its natural boundary (for strings this is 4). + // + // Types: + // s Int16 + // S UInt16 + // i Int32 + // I UInt32 + // l Int64 + // L UInt64 + // f float + // d double + // b byte + // c 1-byte signed character + // C 1-byte unsigned character + // z8 string encoded as UTF8 with 1-byte null terminator + // z6 string encoded as UTF16 with 2-byte null terminator + // z7 string encoded as UTF7 with 1-byte null terminator + // zb string encoded as BigEndianUnicode with 2-byte null terminator + // z3 string encoded as UTF32 with 4-byte null terminator + // z4 string encoded as UTF32 big endian with 4-byte null terminator + // $8 string encoded as UTF8 + // $6 string encoded as UTF16 + // $7 string encoded as UTF7 + // $b string encoded as BigEndianUnicode + // $3 string encoded as UTF32 + // $4 string encoded as UTF-32 big endian encoding + // x null byte + // + // Repeats, these are prefixes: + // N a number between 1 and 9, indicates a repeat count (process N items + // with the following datatype + // [N] For numbers larger than 9, use brackets, for example [20] + // * Repeat the next data type until the arguments are exhausted + // + static public byte [] Pack (string description, params object [] args) + { + int argn = 0; + PackContext b = new PackContext (); + b.conv = CopyConv; + b.description = description; + + for (b.i = 0; b.i < description.Length; ){ + object oarg; + + if (argn < args.Length) + oarg = args [argn]; + else { + if (b.repeat != 0) + break; + + oarg = null; + } + + int save = b.i; + + if (PackOne (b, oarg)){ + argn++; + if (b.repeat > 0){ + if (--b.repeat > 0) + b.i = save; + else + b.i++; + } else + b.i++; + } else + b.i++; + } + return b.Get (); + } + + static public byte [] PackEnumerable (string description, IEnumerable args) + { + PackContext b = new PackContext (); + b.conv = CopyConv; + b.description = description; + + IEnumerator enumerator = args.GetEnumerator (); + bool ok = enumerator.MoveNext (); + + for (b.i = 0; b.i < description.Length; ){ + object oarg; + + if (ok) + oarg = enumerator.Current; + else { + if (b.repeat != 0) + break; + oarg = null; + } + + int save = b.i; + + if (PackOne (b, oarg)){ + ok = enumerator.MoveNext (); + if (b.repeat > 0){ + if (--b.repeat > 0) + b.i = save; + else + b.i++; + } else + b.i++; + } else + b.i++; + } + return b.Get (); + } + + // + // Packs one datum `oarg' into the buffer `b', using the string format + // in `description' at position `i' + // + // Returns: true if we must pick the next object from the list + // + static bool PackOne (PackContext b, object oarg) + { + int n; + + switch (b.description [b.i]){ + case '^': + b.conv = BigEndian; + return false; + case '_': + b.conv = LittleEndian; + return false; + case '%': + b.conv = Native; + return false; + + case '!': + b.align = -1; + return false; + + case 'x': + b.Add (new byte [] { 0 }); + return false; + + // Type Conversions + case 'i': + b.Add (b.conv.GetBytes (Convert.ToInt32 (oarg))); + break; + + case 'I': + b.Add (b.conv.GetBytes (Convert.ToUInt32 (oarg))); + break; + + case 's': + b.Add (b.conv.GetBytes (Convert.ToInt16 (oarg))); + break; + + case 'S': + b.Add (b.conv.GetBytes (Convert.ToUInt16 (oarg))); + break; + + case 'l': + b.Add (b.conv.GetBytes (Convert.ToInt64 (oarg))); + break; + + case 'L': + b.Add (b.conv.GetBytes (Convert.ToUInt64 (oarg))); + break; + + case 'f': + b.Add (b.conv.GetBytes (Convert.ToSingle (oarg))); + break; + + case 'd': + b.Add (b.conv.GetBytes (Convert.ToDouble (oarg))); + break; + + case 'b': + b.Add (new byte [] { Convert.ToByte (oarg) }); + break; + + case 'c': + b.Add (new byte [] { (byte) (Convert.ToSByte (oarg)) }); + break; + + case 'C': + b.Add (new byte [] { Convert.ToByte (oarg) }); + break; + + // Repeat acount; + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + b.repeat = ((short) b.description [b.i]) - ((short) '0'); + return false; + + case '*': + b.repeat = Int32.MaxValue; + return false; + + case '[': + int count = -1, j; + + for (j = b.i+1; j < b.description.Length; j++){ + if (b.description [j] == ']') + break; + n = ((short) b.description [j]) - ((short) '0'); + if (n >= 0 && n <= 9){ + if (count == -1) + count = n; + else + count = count * 10 + n; + } + } + if (count == -1) + throw new ArgumentException ("invalid size specification"); + b.i = j; + b.repeat = count; + return false; + + case '$': case 'z': + bool add_null = b.description [b.i] == 'z'; + b.i++; + if (b.i >= b.description.Length) + throw new ArgumentException ("$ description needs a type specified", "description"); + char d = b.description [b.i]; + Encoding e; + + switch (d){ + case '8': + e = Encoding.UTF8; + n = 1; + break; + case '6': + e = Encoding.Unicode; + n = 2; + break; + case '7': +#if PCL + e = Encoding.GetEncoding ("utf-7"); +#else + e = Encoding.UTF7; +#endif + n = 1; + break; + case 'b': + e = Encoding.BigEndianUnicode; + n = 2; + break; + case '3': +#if PCL + e = Encoding.GetEncoding ("utf-32"); +#else + e = Encoding.GetEncoding (12000); +#endif + n = 4; + break; + case '4': +#if PCL + e = Encoding.GetEncoding ("utf-32BE"); +#else + e = Encoding.GetEncoding (12001); +#endif + n = 4; + break; + + default: + throw new ArgumentException ("Invalid format for $ specifier", "description"); + } + if (b.align == -1) + b.align = 4; + b.Add (e.GetBytes (Convert.ToString (oarg))); + if (add_null) + b.Add (new byte [n]); + break; + default: + throw new ArgumentException (String.Format ("invalid format specified `{0}'", + b.description [b.i])); + } + return true; + } + + static bool Prepare (byte [] buffer, ref int idx, int size, ref bool align) + { + if (align){ + idx = Align (idx, size); + align = false; + } + if (idx + size > buffer.Length){ + idx = buffer.Length; + return false; + } + return true; + } + + static public IList Unpack (string description, byte [] buffer, int startIndex) + { + DataConverter conv = CopyConv; + var result = new List (); + int idx = startIndex; + bool align = false; + int repeat = 0, n; + + for (int i = 0; i < description.Length && idx < buffer.Length; ){ + int save = i; + + switch (description [i]){ + case '^': + conv = BigEndian; + break; + case '_': + conv = LittleEndian; + break; + case '%': + conv = Native; + break; + case 'x': + idx++; + break; + + case '!': + align = true; + break; + + // Type Conversions + case 'i': + if (Prepare (buffer, ref idx, 4, ref align)){ + result.Add (conv.GetInt32 (buffer, idx)); + idx += 4; + } + break; + + case 'I': + if (Prepare (buffer, ref idx, 4, ref align)){ + result.Add (conv.GetUInt32 (buffer, idx)); + idx += 4; + } + break; + + case 's': + if (Prepare (buffer, ref idx, 2, ref align)){ + result.Add (conv.GetInt16 (buffer, idx)); + idx += 2; + } + break; + + case 'S': + if (Prepare (buffer, ref idx, 2, ref align)){ + result.Add (conv.GetUInt16 (buffer, idx)); + idx += 2; + } + break; + + case 'l': + if (Prepare (buffer, ref idx, 8, ref align)){ + result.Add (conv.GetInt64 (buffer, idx)); + idx += 8; + } + break; + + case 'L': + if (Prepare (buffer, ref idx, 8, ref align)){ + result.Add (conv.GetUInt64 (buffer, idx)); + idx += 8; + } + break; + + case 'f': + if (Prepare (buffer, ref idx, 4, ref align)){ + result.Add (conv.GetFloat (buffer, idx)); + idx += 4; + } + break; + + case 'd': + if (Prepare (buffer, ref idx, 8, ref align)){ + result.Add (conv.GetDouble (buffer, idx)); + idx += 8; + } + break; + + case 'b': + if (Prepare (buffer, ref idx, 1, ref align)){ + result.Add (buffer [idx]); + idx++; + } + break; + + case 'c': case 'C': + if (Prepare (buffer, ref idx, 1, ref align)){ + char c; + + if (description [i] == 'c') + c = ((char) ((sbyte)buffer [idx])); + else + c = ((char) ((byte)buffer [idx])); + + result.Add (c); + idx++; + } + break; + + // Repeat acount; + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + repeat = ((short) description [i]) - ((short) '0'); + save = i + 1; + break; + + case '*': + repeat = Int32.MaxValue; + break; + + case '[': + int count = -1, j; + + for (j = i+1; j < description.Length; j++){ + if (description [j] == ']') + break; + n = ((short) description [j]) - ((short) '0'); + if (n >= 0 && n <= 9){ + if (count == -1) + count = n; + else + count = count * 10 + n; + } + } + if (count == -1) + throw new ArgumentException ("invalid size specification"); + i = j; + save = i + 1; + repeat = count; + break; + + case '$': case 'z': + // bool with_null = description [i] == 'z'; + i++; + if (i >= description.Length) + throw new ArgumentException ("$ description needs a type specified", "description"); + char d = description [i]; + Encoding e; + if (align){ + idx = Align (idx, 4); + align = false; + } + if (idx >= buffer.Length) + break; + + switch (d){ + case '8': + e = Encoding.UTF8; + n = 1; + break; + case '6': + e = Encoding.Unicode; + n = 2; + break; + case '7': + e = Encoding.UTF7; + n = 1; + break; + case 'b': + e = Encoding.BigEndianUnicode; + n = 2; + break; + case '3': + e = Encoding.GetEncoding (12000); + n = 4; + break; + case '4': + e = Encoding.GetEncoding (12001); + n = 4; + break; + + default: + throw new ArgumentException ("Invalid format for $ specifier", "description"); + } + int k = idx; + switch (n){ + case 1: + for (; k < buffer.Length && buffer [k] != 0; k++) + ; + result.Add (e.GetChars (buffer, idx, k-idx)); + if (k == buffer.Length) + idx = k; + else + idx = k+1; + break; + + case 2: + for (; k < buffer.Length; k++){ + if (k+1 == buffer.Length){ + k++; + break; + } + if (buffer [k] == 0 && buffer [k+1] == 0) + break; + } + result.Add (e.GetChars (buffer, idx, k-idx)); + if (k == buffer.Length) + idx = k; + else + idx = k+2; + break; + + case 4: + for (; k < buffer.Length; k++){ + if (k+3 >= buffer.Length){ + k = buffer.Length; + break; + } + if (buffer[k]==0 && buffer[k+1] == 0 && buffer[k+2] == 0 && buffer[k+3]== 0) + break; + } + result.Add (e.GetChars (buffer, idx, k-idx)); + if (k == buffer.Length) + idx = k; + else + idx = k+4; + break; + } + break; + default: + throw new ArgumentException (String.Format ("invalid format specified `{0}'", + description [i])); + } + + if (repeat > 0){ + if (--repeat > 0) + i = save; + } else + i++; + } + return result; + } + + 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"); + } + + class CopyConverter : DataConverter { + public 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 ret; + byte *b = (byte *)&ret; + + for (int i = 0; i < 8; i++) + b [i] = data [index+i]; + + return ret; + } + + public 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 ret; + byte *b = (byte *)&ret; + + for (int i = 0; i < 8; i++) + b [i] = data [index+i]; + + return ret; + } + + public 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 ret; + byte *b = (byte *)&ret; + + for (int i = 0; i < 8; i++) + b [i] = data [index+i]; + + return ret; + } + + public 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 ret; + byte *b = (byte *)&ret; + + for (int i = 0; i < 4; i++) + b [i] = data [index+i]; + + return ret; + } + + public 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 ret; + byte *b = (byte *)&ret; + + for (int i = 0; i < 4; i++) + b [i] = data [index+i]; + + return ret; + } + + public 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 ret; + byte *b = (byte *)&ret; + + for (int i = 0; i < 4; i++) + b [i] = data [index+i]; + + return ret; + } + + public 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 ret; + byte *b = (byte *)&ret; + + for (int i = 0; i < 2; i++) + b [i] = data [index+i]; + + return ret; + } + + public 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 ret; + byte *b = (byte *)&ret; + + for (int i = 0; i < 2; i++) + b [i] = data [index+i]; + + return ret; + } + + public override void PutBytes (byte [] dest, int destIdx, double value) + { + Check (dest, destIdx, 8); + fixed (byte *target = &dest [destIdx]){ + long *source = (long *) &value; + + *((long *)target) = *source; + } + } + + public override void PutBytes (byte [] dest, int destIdx, float value) + { + Check (dest, destIdx, 4); + fixed (byte *target = &dest [destIdx]){ + uint *source = (uint *) &value; + + *((uint *)target) = *source; + } + } + + public override void PutBytes (byte [] dest, int destIdx, int value) + { + Check (dest, destIdx, 4); + fixed (byte *target = &dest [destIdx]){ + uint *source = (uint *) &value; + + *((uint *)target) = *source; + } + } + + public override void PutBytes (byte [] dest, int destIdx, uint value) + { + Check (dest, destIdx, 4); + fixed (byte *target = &dest [destIdx]){ + uint *source = (uint *) &value; + + *((uint *)target) = *source; + } + } + + public override void PutBytes (byte [] dest, int destIdx, long value) + { + Check (dest, destIdx, 8); + fixed (byte *target = &dest [destIdx]){ + long *source = (long *) &value; + + *((long*)target) = *source; + } + } + + public override void PutBytes (byte [] dest, int destIdx, ulong value) + { + Check (dest, destIdx, 8); + fixed (byte *target = &dest [destIdx]){ + ulong *source = (ulong *) &value; + + *((ulong *) target) = *source; + } + } + + public override void PutBytes (byte [] dest, int destIdx, short value) + { + Check (dest, destIdx, 2); + fixed (byte *target = &dest [destIdx]){ + ushort *source = (ushort *) &value; + + *((ushort *)target) = *source; + } + } + + public override void PutBytes (byte [] dest, int destIdx, ushort value) + { + Check (dest, destIdx, 2); + fixed (byte *target = &dest [destIdx]){ + ushort *source = (ushort *) &value; + + *((ushort *)target) = *source; + } + } + } + + class SwapConverter : DataConverter { + public 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 ret; + byte *b = (byte *)&ret; + + for (int i = 0; i < 8; i++) + b [7-i] = data [index+i]; + + return ret; + } + + public 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 ret; + byte *b = (byte *)&ret; + + for (int i = 0; i < 8; i++) + b [7-i] = data [index+i]; + + return ret; + } + + public 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 ret; + byte *b = (byte *)&ret; + + for (int i = 0; i < 8; i++) + b [7-i] = data [index+i]; + + return ret; + } + + public 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 ret; + byte *b = (byte *)&ret; + + for (int i = 0; i < 4; i++) + b [3-i] = data [index+i]; + + return ret; + } + + public 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 ret; + byte *b = (byte *)&ret; + + for (int i = 0; i < 4; i++) + b [3-i] = data [index+i]; + + return ret; + } + + public 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 ret; + byte *b = (byte *)&ret; + + for (int i = 0; i < 4; i++) + b [3-i] = data [index+i]; + + return ret; + } + + public 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 ret; + byte *b = (byte *)&ret; + + for (int i = 0; i < 2; i++) + b [1-i] = data [index+i]; + + return ret; + } + + public 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 ret; + byte *b = (byte *)&ret; + + for (int i = 0; i < 2; i++) + b [1-i] = data [index+i]; + + return ret; + } + + public override void PutBytes (byte [] dest, int destIdx, double value) + { + Check (dest, destIdx, 8); + + fixed (byte *target = &dest [destIdx]){ + byte *source = (byte *) &value; + + for (int i = 0; i < 8; i++) + target [i] = source [7-i]; + } + } + + public override void PutBytes (byte [] dest, int destIdx, float value) + { + Check (dest, destIdx, 4); + + fixed (byte *target = &dest [destIdx]){ + byte *source = (byte *) &value; + + for (int i = 0; i < 4; i++) + target [i] = source [3-i]; + } + } + + public override void PutBytes (byte [] dest, int destIdx, int value) + { + Check (dest, destIdx, 4); + + fixed (byte *target = &dest [destIdx]){ + byte *source = (byte *) &value; + + for (int i = 0; i < 4; i++) + target [i] = source [3-i]; + } + } + + public override void PutBytes (byte [] dest, int destIdx, uint value) + { + Check (dest, destIdx, 4); + + fixed (byte *target = &dest [destIdx]){ + byte *source = (byte *) &value; + + for (int i = 0; i < 4; i++) + target [i] = source [3-i]; + } + } + + public override void PutBytes (byte [] dest, int destIdx, long value) + { + Check (dest, destIdx, 8); + + fixed (byte *target = &dest [destIdx]){ + byte *source = (byte *) &value; + + for (int i = 0; i < 8; i++) + target [i] = source [7-i]; + } + } + + public override void PutBytes (byte [] dest, int destIdx, ulong value) + { + Check (dest, destIdx, 8); + + fixed (byte *target = &dest [destIdx]){ + byte *source = (byte *) &value; + + for (int i = 0; i < 8; i++) + target [i] = source [7-i]; + } + } + + public override void PutBytes (byte [] dest, int destIdx, short value) + { + Check (dest, destIdx, 2); + + fixed (byte *target = &dest [destIdx]){ + byte *source = (byte *) &value; + + for (int i = 0; i < 2; i++) + target [i] = source [1-i]; + } + } + + public override void PutBytes (byte [] dest, int destIdx, ushort value) + { + Check (dest, destIdx, 2); + + fixed (byte *target = &dest [destIdx]){ + byte *source = (byte *) &value; + + for (int i = 0; i < 2; i++) + target [i] = source [1-i]; + } + } + } + +#if MONO_DATACONVERTER_STATIC_METHODS + static unsafe void PutBytesLE (byte *dest, byte *src, int count) + { + int i = 0; + + if (BitConverter.IsLittleEndian){ + for (; i < count; i++) + *dest++ = *src++; + } else { + dest += count; + for (; i < count; i++) + *(--dest) = *src++; + } + } + + static unsafe void PutBytesBE (byte *dest, byte *src, int count) + { + int i = 0; + + if (BitConverter.IsLittleEndian){ + dest += count; + for (; i < count; i++) + *(--dest) = *src++; + } else { + for (; i < count; i++) + *dest++ = *src++; + } + } + + static unsafe void PutBytesNative (byte *dest, byte *src, int count) + { + int i = 0; + + for (; i < count; i++) + dest [i-count] = *src++; + } + + static public unsafe double DoubleFromLE (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 ret; + fixed (byte *src = &data[index]){ + PutBytesLE ((byte *) &ret, src, 8); + } + return ret; + } + + static public unsafe float FloatFromLE (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 ret; + fixed (byte *src = &data[index]){ + PutBytesLE ((byte *) &ret, src, 4); + } + return ret; + } + + static public unsafe long Int64FromLE (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 ret; + fixed (byte *src = &data[index]){ + PutBytesLE ((byte *) &ret, src, 8); + } + return ret; + } + + static public unsafe ulong UInt64FromLE (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 ret; + fixed (byte *src = &data[index]){ + PutBytesLE ((byte *) &ret, src, 8); + } + return ret; + } + + static public unsafe int Int32FromLE (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 ret; + fixed (byte *src = &data[index]){ + PutBytesLE ((byte *) &ret, src, 4); + } + return ret; + } + + static public unsafe uint UInt32FromLE (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 ret; + fixed (byte *src = &data[index]){ + PutBytesLE ((byte *) &ret, src, 4); + } + return ret; + } + + static public unsafe short Int16FromLE (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 ret; + fixed (byte *src = &data[index]){ + PutBytesLE ((byte *) &ret, src, 2); + } + return ret; + } + + static public unsafe ushort UInt16FromLE (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 ret; + fixed (byte *src = &data[index]){ + PutBytesLE ((byte *) &ret, src, 2); + } + return ret; + } + + static public unsafe double DoubleFromBE (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 ret; + fixed (byte *src = &data[index]){ + PutBytesBE ((byte *) &ret, src, 8); + } + return ret; + } + + static public unsafe float FloatFromBE (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 ret; + fixed (byte *src = &data[index]){ + PutBytesBE ((byte *) &ret, src, 4); + } + return ret; + } + + static public unsafe long Int64FromBE (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 ret; + fixed (byte *src = &data[index]){ + PutBytesBE ((byte *) &ret, src, 8); + } + return ret; + } + + static public unsafe ulong UInt64FromBE (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 ret; + fixed (byte *src = &data[index]){ + PutBytesBE ((byte *) &ret, src, 8); + } + return ret; + } + + static public unsafe int Int32FromBE (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 ret; + fixed (byte *src = &data[index]){ + PutBytesBE ((byte *) &ret, src, 4); + } + return ret; + } + + static public unsafe uint UInt32FromBE (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 ret; + fixed (byte *src = &data[index]){ + PutBytesBE ((byte *) &ret, src, 4); + } + return ret; + } + + static public unsafe short Int16FromBE (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 ret; + fixed (byte *src = &data[index]){ + PutBytesBE ((byte *) &ret, src, 2); + } + return ret; + } + + static public unsafe ushort UInt16FromBE (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 ret; + fixed (byte *src = &data[index]){ + PutBytesBE ((byte *) &ret, src, 2); + } + return ret; + } + + static public unsafe double DoubleFromNative (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 ret; + fixed (byte *src = &data[index]){ + PutBytesNative ((byte *) &ret, src, 8); + } + return ret; + } + + static public unsafe float FloatFromNative (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 ret; + fixed (byte *src = &data[index]){ + PutBytesNative ((byte *) &ret, src, 4); + } + return ret; + } + + static public unsafe long Int64FromNative (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 ret; + fixed (byte *src = &data[index]){ + PutBytesNative ((byte *) &ret, src, 8); + } + return ret; + } + + static public unsafe ulong UInt64FromNative (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 ret; + fixed (byte *src = &data[index]){ + PutBytesNative ((byte *) &ret, src, 8); + } + return ret; + } + + static public unsafe int Int32FromNative (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 ret; + fixed (byte *src = &data[index]){ + PutBytesNative ((byte *) &ret, src, 4); + } + return ret; + } + + static public unsafe uint UInt32FromNative (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 ret; + fixed (byte *src = &data[index]){ + PutBytesNative ((byte *) &ret, src, 4); + } + return ret; + } + + static public unsafe short Int16FromNative (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 ret; + fixed (byte *src = &data[index]){ + PutBytesNative ((byte *) &ret, src, 2); + } + return ret; + } + + static public unsafe ushort UInt16FromNative (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 ret; + fixed (byte *src = &data[index]){ + PutBytesNative ((byte *) &ret, src, 2); + } + return ret; + } + + unsafe static byte[] GetBytesPtr (byte *ptr, int count) + { + byte [] ret = new byte [count]; + + for (int i = 0; i < count; i++) { + ret [i] = ptr [i]; + } + + return ret; + } + + unsafe static byte[] GetBytesSwap (bool swap, byte *ptr, int count) + { + byte [] ret = new byte [count]; + + if (swap){ + int t = count-1; + for (int i = 0; i < count; i++) { + ret [t-i] = ptr [i]; + } + } else { + for (int i = 0; i < count; i++) { + ret [i] = ptr [i]; + } + } + return ret; + } + + unsafe public static byte[] GetBytesNative (bool value) + { + return GetBytesPtr ((byte *) &value, 1); + } + + unsafe public static byte[] GetBytesNative (char value) + { + return GetBytesPtr ((byte *) &value, 2); + } + + unsafe public static byte[] GetBytesNative (short value) + { + return GetBytesPtr ((byte *) &value, 2); + } + + unsafe public static byte[] GetBytesNative (int value) + { + return GetBytesPtr ((byte *) &value, 4); + } + + unsafe public static byte[] GetBytesNative (long value) + { + return GetBytesPtr ((byte *) &value, 8); + } + + [CLSCompliant (false)] + unsafe public static byte[] GetBytesNative (ushort value) + { + return GetBytesPtr ((byte *) &value, 2); + } + + [CLSCompliant (false)] + unsafe public static byte[] GetBytesNative (uint value) + { + return GetBytesPtr ((byte *) &value, 4); + } + + [CLSCompliant (false)] + unsafe public static byte[] GetBytesNative (ulong value) + { + return GetBytesPtr ((byte *) &value, 8); + } + + unsafe public static byte[] GetBytesNative (float value) + { + return GetBytesPtr ((byte *) &value, 4); + } + + unsafe public static byte[] GetBytesNative (double value) + { + return GetBytesPtr ((byte *) &value, 8); + } + + unsafe public static byte[] GetBytesLE (bool value) + { + return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 1); + } + + unsafe public static byte[] GetBytesLE (char value) + { + return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 2); + } + + unsafe public static byte[] GetBytesLE (short value) + { + return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 2); + } + + unsafe public static byte[] GetBytesLE (int value) + { + return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 4); + } + + unsafe public static byte[] GetBytesLE (long value) + { + return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 8); + } + + [CLSCompliant (false)] + unsafe public static byte[] GetBytesLE (ushort value) + { + return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 2); + } + + [CLSCompliant (false)] + unsafe public static byte[] GetBytesLE (uint value) + { + return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 4); + } + + [CLSCompliant (false)] + unsafe public static byte[] GetBytesLE (ulong value) + { + return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 8); + } + + unsafe public static byte[] GetBytesLE (float value) + { + return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 4); + } + + unsafe public static byte[] GetBytesLE (double value) + { + return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 8); + } + + unsafe public static byte[] GetBytesBE (bool value) + { + return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 1); + } + + unsafe public static byte[] GetBytesBE (char value) + { + return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 2); + } + + unsafe public static byte[] GetBytesBE (short value) + { + return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 2); + } + + unsafe public static byte[] GetBytesBE (int value) + { + return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 4); + } + + unsafe public static byte[] GetBytesBE (long value) + { + return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 8); + } + + [CLSCompliant (false)] + unsafe public static byte[] GetBytesBE (ushort value) + { + return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 2); + } + + [CLSCompliant (false)] + unsafe public static byte[] GetBytesBE (uint value) + { + return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 4); + } + + [CLSCompliant (false)] + unsafe public static byte[] GetBytesBE (ulong value) + { + return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 8); + } + + unsafe public static byte[] GetBytesBE (float value) + { + return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 4); + } + + unsafe public static byte[] GetBytesBE (double value) + { + return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 8); + } +#endif + + } +} diff --git a/SharpCompress/Crypto/PBKDF2.cs b/SharpCompress/Crypto/PBKDF2.cs index 7cb772ef..ae7f2c99 100644 --- a/SharpCompress/Crypto/PBKDF2.cs +++ b/SharpCompress/Crypto/PBKDF2.cs @@ -3,6 +3,7 @@ using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Macs; using Org.BouncyCastle.Crypto.Parameters; +using SharpCompress.Converter; namespace SharpCompress.Crypto { @@ -68,7 +69,7 @@ namespace SharpCompress.Crypto private byte[] Hash() { - byte[] array = UIntToOctet(block); + byte[] array = DataConverter.BigEndian.GetBytes(block); ICipherParameters param = new KeyParameter(password); hMac.Init(param); @@ -96,24 +97,6 @@ namespace SharpCompress.Crypto block += 1u; return array3; } - - internal static byte[] UIntToOctet(uint i) - { - byte[] bytes = BitConverter.GetBytes(i); - byte[] result = new[] - { - bytes[3], - bytes[2], - bytes[1], - bytes[0] - }; - if (!BitConverter.IsLittleEndian) - { - return bytes; - } - return result; - } - } } diff --git a/SharpCompress/IO/MarkingBinaryReader.cs b/SharpCompress/IO/MarkingBinaryReader.cs index a9a5d1be..07ddd16e 100644 --- a/SharpCompress/IO/MarkingBinaryReader.cs +++ b/SharpCompress/IO/MarkingBinaryReader.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Linq; +using SharpCompress.Converter; namespace SharpCompress.IO { @@ -36,7 +37,7 @@ namespace SharpCompress.IO public override bool ReadBoolean() { - return BitConverter.ToBoolean(ReadBytes(1), 0); + return ReadBytes(1).Single() != 0; } public override byte ReadByte() @@ -68,39 +69,28 @@ namespace SharpCompress.IO #if !PORTABLE public override decimal ReadDecimal() { - return ByteArrayToDecimal(ReadBytes(16), 0); - } - - private decimal ByteArrayToDecimal(byte[] src, int offset) - { - //http://stackoverflow.com/a/16984356/385387 - var i1 = BitConverter.ToInt32(src, offset); - var i2 = BitConverter.ToInt32(src, offset + 4); - var i3 = BitConverter.ToInt32(src, offset + 8); - var i4 = BitConverter.ToInt32(src, offset + 12); - - return new decimal(new[] { i1, i2, i3, i4 }); + throw new NotSupportedException(); } #endif public override double ReadDouble() { - return BitConverter.ToDouble(ReadBytes(8), 0); + throw new NotSupportedException(); } public override short ReadInt16() { - return BitConverter.ToInt16(ReadBytes(2), 0); + return DataConverter.LittleEndian.GetInt16(ReadBytes(2), 0); } public override int ReadInt32() { - return BitConverter.ToInt32(ReadBytes(4), 0); + return DataConverter.LittleEndian.GetInt32(ReadBytes(4), 0); } public override long ReadInt64() { - return BitConverter.ToInt64(ReadBytes(8), 0); + return DataConverter.LittleEndian.GetInt64(ReadBytes(8), 0); } public override sbyte ReadSByte() @@ -110,7 +100,7 @@ namespace SharpCompress.IO public override float ReadSingle() { - return BitConverter.ToSingle(ReadBytes(4), 0); + throw new NotSupportedException(); } public override string ReadString() @@ -120,17 +110,17 @@ namespace SharpCompress.IO public override ushort ReadUInt16() { - return BitConverter.ToUInt16(ReadBytes(2), 0); + return DataConverter.LittleEndian.GetUInt16(ReadBytes(2), 0); } public override uint ReadUInt32() { - return BitConverter.ToUInt32(ReadBytes(4), 0); + return DataConverter.LittleEndian.GetUInt32(ReadBytes(4), 0); } public override ulong ReadUInt64() { - return BitConverter.ToUInt64(ReadBytes(8), 0); + return DataConverter.LittleEndian.GetUInt64(ReadBytes(8), 0); } } } \ No newline at end of file diff --git a/SharpCompress/SharpCompress.Portable.csproj b/SharpCompress/SharpCompress.Portable.csproj index 49e43055..608308d5 100644 --- a/SharpCompress/SharpCompress.Portable.csproj +++ b/SharpCompress/SharpCompress.Portable.csproj @@ -270,6 +270,7 @@ + diff --git a/SharpCompress/SharpCompress.PortableTest.csproj b/SharpCompress/SharpCompress.PortableTest.csproj index 71281f16..948bc9e9 100644 --- a/SharpCompress/SharpCompress.PortableTest.csproj +++ b/SharpCompress/SharpCompress.PortableTest.csproj @@ -240,6 +240,7 @@ + diff --git a/SharpCompress/SharpCompress.Unsigned.csproj b/SharpCompress/SharpCompress.Unsigned.csproj index bfb80856..58412400 100644 --- a/SharpCompress/SharpCompress.Unsigned.csproj +++ b/SharpCompress/SharpCompress.Unsigned.csproj @@ -244,6 +244,7 @@ + Code diff --git a/SharpCompress/SharpCompress.WindowsStore.csproj b/SharpCompress/SharpCompress.WindowsStore.csproj index b5c5547b..ddd85bb8 100644 --- a/SharpCompress/SharpCompress.WindowsStore.csproj +++ b/SharpCompress/SharpCompress.WindowsStore.csproj @@ -256,6 +256,7 @@ + diff --git a/SharpCompress/SharpCompress.csproj b/SharpCompress/SharpCompress.csproj index fd033f1a..568ba3be 100644 --- a/SharpCompress/SharpCompress.csproj +++ b/SharpCompress/SharpCompress.csproj @@ -244,6 +244,7 @@ + Code diff --git a/SharpCompress/Utility.cs b/SharpCompress/Utility.cs index 6a7c4d72..d6599187 100644 --- a/SharpCompress/Utility.cs +++ b/SharpCompress/Utility.cs @@ -2,9 +2,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using SharpCompress.Archive; -using SharpCompress.Common; -using SharpCompress.IO; namespace SharpCompress { @@ -29,17 +26,6 @@ namespace SharpCompress return (number >> bits) + (2 << ~bits); } - /// - /// Performs an unsigned bitwise right shift with the specified number - /// - /// Number to operate on - /// Ammount of bits to shift - /// The resulting number from the shift operation - public static int URShift(int number, long bits) - { - return URShift(number, (int)bits); - } - /// /// Performs an unsigned bitwise right shift with the specified number /// @@ -54,17 +40,6 @@ namespace SharpCompress return (number >> bits) + (2L << ~bits); } - /// - /// Performs an unsigned bitwise right shift with the specified number - /// - /// Number to operate on - /// Ammount of bits to shift - /// The resulting number from the shift operation - public static long URShift(long number, long bits) - { - return URShift(number, (int)bits); - } - /// /// Fills the array with an specific value from an specific index to an specific index. /// @@ -120,139 +95,6 @@ namespace SharpCompress } } - /// Read a int value from the byte array at the given position (Big Endian) - /// - /// - /// the array to read from - /// - /// the offset - /// - /// the value - /// - public static int readIntBigEndian(byte[] array, int pos) - { - int temp = 0; - temp |= array[pos] & 0xff; - temp <<= 8; - temp |= array[pos + 1] & 0xff; - temp <<= 8; - temp |= array[pos + 2] & 0xff; - temp <<= 8; - temp |= array[pos + 3] & 0xff; - return temp; - } - - /// Read a short value from the byte array at the given position (little - /// Endian) - /// - /// - /// the array to read from - /// - /// the offset - /// - /// the value - /// - public static short readShortLittleEndian(byte[] array, int pos) - { - return BitConverter.ToInt16(array, pos); - } - - /// Read an int value from the byte array at the given position (little - /// Endian) - /// - /// - /// the array to read from - /// - /// the offset - /// - /// the value - /// - public static int readIntLittleEndian(byte[] array, int pos) - { - return BitConverter.ToInt32(array, pos); - } - - /// Write an int value into the byte array at the given position (Big endian) - /// - /// - /// the array - /// - /// the offset - /// - /// the value to write - /// - public static void writeIntBigEndian(byte[] array, int pos, int value) - { - array[pos] = (byte)((Utility.URShift(value, 24)) & 0xff); - array[pos + 1] = (byte)((Utility.URShift(value, 16)) & 0xff); - array[pos + 2] = (byte)((Utility.URShift(value, 8)) & 0xff); - array[pos + 3] = (byte)((value) & 0xff); - } - - /// Write a short value into the byte array at the given position (little - /// endian) - /// - /// - /// the array - /// - /// the offset - /// - /// the value to write - /// - public static void WriteLittleEndian(byte[] array, int pos, short value) - { - byte[] newBytes = BitConverter.GetBytes(value); - - if (!BitConverter.IsLittleEndian) - Array.Reverse(newBytes); - - Array.Copy(newBytes, 0, array, pos, newBytes.Length); - } - - /// Increment a short value at the specified position by the specified amount - /// (little endian). - /// - public static void incShortLittleEndian(byte[] array, int pos, short incrementValue) - { - short existingValue = BitConverter.ToInt16(array, pos); - existingValue += incrementValue; - WriteLittleEndian(array, pos, existingValue); - //int c = Utility.URShift(((array[pos] & 0xff) + (dv & 0xff)), 8); - //array[pos] = (byte)(array[pos] + (dv & 0xff)); - //if ((c > 0) || ((dv & 0xff00) != 0)) - //{ - // array[pos + 1] = (byte)(array[pos + 1] + ((Utility.URShift(dv, 8)) & 0xff) + c); - //} - } - - /// Write an int value into the byte array at the given position (little - /// endian) - /// - /// - /// the array - /// - /// the offset - /// - /// the value to write - /// - public static void WriteLittleEndian(byte[] array, int pos, int value) - { - byte[] newBytes = BitConverter.GetBytes(value); - - if (!BitConverter.IsLittleEndian) - Array.Reverse(newBytes); - - Array.Copy(newBytes, 0, array, pos, newBytes.Length); - } - - public static void Initialize(this T[] array, Func func) - { - for (int i = 0; i < array.Length; i++) - { - array[i] = func(); - } - } - public static void AddRange(this ICollection destination, IEnumerable source) { foreach (T item in source) @@ -324,18 +166,6 @@ namespace SharpCompress } while (source.Read(buffer, 0, buffer.Length) == buffer.Length); } - - public static byte[] UInt32ToBigEndianBytes(uint x) - { - return new byte[] - { - (byte) ((x >> 24) & 0xff), - (byte) ((x >> 16) & 0xff), - (byte) ((x >> 8) & 0xff), - (byte) (x & 0xff) - }; - } - public static DateTime DosDateToDateTime(UInt16 iDate, UInt16 iTime) { int year = iDate / 512 + 1980; @@ -450,33 +280,6 @@ namespace SharpCompress { Array.Copy(array, 0, destination, index, array.Length); } - - public static long HostToNetworkOrder(long host) - { - return (int)((long)HostToNetworkOrder((int)host) - & unchecked((long)(unchecked((ulong)-1))) << 32 - | ((long)HostToNetworkOrder((int)((int)host >> 32)) & unchecked((long)(unchecked((ulong)-1))))); - } - public static int HostToNetworkOrder(int host) - { - return (int)((int)(HostToNetworkOrder((short)host) & -1) << 16 | (HostToNetworkOrder((short)(host >> 16)) & -1)); - } - public static short HostToNetworkOrder(short host) - { - return (short)((int)(host & 255) << 8 | ((int)host >> 8 & 255)); - } - public static long NetworkToHostOrder(long network) - { - return HostToNetworkOrder(network); - } - public static int NetworkToHostOrder(int network) - { - return HostToNetworkOrder(network); - } - public static short NetworkToHostOrder(short network) - { - return HostToNetworkOrder(network); - } #endif } } \ No newline at end of file diff --git a/SharpCompress/Writer/Zip/ZipCentralDirectoryEntry.cs b/SharpCompress/Writer/Zip/ZipCentralDirectoryEntry.cs index c1a4c1e8..1448d3fd 100644 --- a/SharpCompress/Writer/Zip/ZipCentralDirectoryEntry.cs +++ b/SharpCompress/Writer/Zip/ZipCentralDirectoryEntry.cs @@ -3,6 +3,7 @@ using System.IO; using System.Text; using SharpCompress.Common.Zip; using SharpCompress.Common.Zip.Headers; +using SharpCompress.Converter; namespace SharpCompress.Writer.Zip { @@ -32,23 +33,23 @@ namespace SharpCompress.Writer.Zip flags |= HeaderFlags.Bit1; // eos marker } } - outputStream.Write(BitConverter.GetBytes((ushort) flags), 0, 2); - outputStream.Write(BitConverter.GetBytes((ushort) compression), 0, 2); // zipping method - outputStream.Write(BitConverter.GetBytes(ModificationTime.DateTimeToDosTime()), 0, 4); + outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) flags), 0, 2); + outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) compression), 0, 2); // zipping method + outputStream.Write(DataConverter.LittleEndian.GetBytes(ModificationTime.DateTimeToDosTime()), 0, 4); // zipping date and time - outputStream.Write(BitConverter.GetBytes(Crc), 0, 4); // file CRC - outputStream.Write(BitConverter.GetBytes(Compressed), 0, 4); // compressed file size - outputStream.Write(BitConverter.GetBytes(Decompressed), 0, 4); // uncompressed file size - outputStream.Write(BitConverter.GetBytes((ushort) encodedFilename.Length), 0, 2); // Filename in zip - outputStream.Write(BitConverter.GetBytes((ushort) 0), 0, 2); // extra length - outputStream.Write(BitConverter.GetBytes((ushort) encodedComment.Length), 0, 2); + outputStream.Write(DataConverter.LittleEndian.GetBytes(Crc), 0, 4); // file CRC + outputStream.Write(DataConverter.LittleEndian.GetBytes(Compressed), 0, 4); // compressed file size + outputStream.Write(DataConverter.LittleEndian.GetBytes(Decompressed), 0, 4); // uncompressed file size + outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) encodedFilename.Length), 0, 2); // Filename in zip + outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) 0), 0, 2); // extra length + outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) encodedComment.Length), 0, 2); - outputStream.Write(BitConverter.GetBytes((ushort) 0), 0, 2); // disk=0 - outputStream.Write(BitConverter.GetBytes((ushort) 0), 0, 2); // file type: binary - outputStream.Write(BitConverter.GetBytes((ushort) 0), 0, 2); // Internal file attributes - outputStream.Write(BitConverter.GetBytes((ushort) 0x8100), 0, 2); + outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) 0), 0, 2); // disk=0 + outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) 0), 0, 2); // file type: binary + outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) 0), 0, 2); // Internal file attributes + outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) 0x8100), 0, 2); // External file attributes (normal/readable) - outputStream.Write(BitConverter.GetBytes(HeaderOffset), 0, 4); // Offset of header + outputStream.Write(DataConverter.LittleEndian.GetBytes(HeaderOffset), 0, 4); // Offset of header outputStream.Write(encodedFilename, 0, encodedFilename.Length); outputStream.Write(encodedComment, 0, encodedComment.Length); diff --git a/SharpCompress/Writer/Zip/ZipWriter.cs b/SharpCompress/Writer/Zip/ZipWriter.cs index 4f44fe5d..1831db22 100644 --- a/SharpCompress/Writer/Zip/ZipWriter.cs +++ b/SharpCompress/Writer/Zip/ZipWriter.cs @@ -10,6 +10,7 @@ using SharpCompress.Compressor.BZip2; using SharpCompress.Compressor.Deflate; using SharpCompress.Compressor.LZMA; using SharpCompress.Compressor.PPMd; +using SharpCompress.Converter; using SharpCompress.IO; using DeflateStream = SharpCompress.Compressor.Deflate.DeflateStream; @@ -93,7 +94,7 @@ namespace SharpCompress.Writer.Zip var explicitZipCompressionInfo = compressionInfo != null ? new ZipCompressionInfo(compressionInfo) : this.zipCompressionInfo; byte[] encodedFilename = ArchiveEncoding.Default.GetBytes(filename); - OutputStream.Write(BitConverter.GetBytes(ZipHeaderFactory.ENTRY_HEADER_BYTES), 0, 4); + OutputStream.Write(DataConverter.LittleEndian.GetBytes(ZipHeaderFactory.ENTRY_HEADER_BYTES), 0, 4); if (explicitZipCompressionInfo.Compression == ZipCompressionMethod.Deflate) { OutputStream.Write(new byte[] {20, 0}, 0, 2); //older version which is more compatible @@ -111,14 +112,14 @@ namespace SharpCompress.Writer.Zip flags |= HeaderFlags.Bit1; // eos marker } } - OutputStream.Write(BitConverter.GetBytes((ushort) flags), 0, 2); - OutputStream.Write(BitConverter.GetBytes((ushort)explicitZipCompressionInfo.Compression), 0, 2); // zipping method - OutputStream.Write(BitConverter.GetBytes(modificationTime.DateTimeToDosTime()), 0, 4); + OutputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) flags), 0, 2); + OutputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)explicitZipCompressionInfo.Compression), 0, 2); // zipping method + OutputStream.Write(DataConverter.LittleEndian.GetBytes(modificationTime.DateTimeToDosTime()), 0, 4); // zipping date and time OutputStream.Write(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 12); // unused CRC, un/compressed size, updated later - OutputStream.Write(BitConverter.GetBytes((ushort) encodedFilename.Length), 0, 2); // filename length - OutputStream.Write(BitConverter.GetBytes((ushort) 0), 0, 2); // extra length + OutputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) encodedFilename.Length), 0, 2); // filename length + OutputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) 0), 0, 2); // extra length OutputStream.Write(encodedFilename, 0, encodedFilename.Length); return 6 + 2 + 2 + 4 + 12 + 2 + 2 + encodedFilename.Length; @@ -126,9 +127,9 @@ namespace SharpCompress.Writer.Zip private void WriteFooter(uint crc, uint compressed, uint uncompressed) { - OutputStream.Write(BitConverter.GetBytes(crc), 0, 4); - OutputStream.Write(BitConverter.GetBytes(compressed), 0, 4); - OutputStream.Write(BitConverter.GetBytes(uncompressed), 0, 4); + OutputStream.Write(DataConverter.LittleEndian.GetBytes(crc), 0, 4); + OutputStream.Write(DataConverter.LittleEndian.GetBytes(compressed), 0, 4); + OutputStream.Write(DataConverter.LittleEndian.GetBytes(uncompressed), 0, 4); } private void WriteEndRecord(uint size) @@ -136,11 +137,11 @@ namespace SharpCompress.Writer.Zip byte[] encodedComment = ArchiveEncoding.Default.GetBytes(zipComment); OutputStream.Write(new byte[] {80, 75, 5, 6, 0, 0, 0, 0}, 0, 8); - OutputStream.Write(BitConverter.GetBytes((ushort) entries.Count), 0, 2); - OutputStream.Write(BitConverter.GetBytes((ushort) entries.Count), 0, 2); - OutputStream.Write(BitConverter.GetBytes(size), 0, 4); - OutputStream.Write(BitConverter.GetBytes((uint) streamPosition), 0, 4); - OutputStream.Write(BitConverter.GetBytes((ushort) encodedComment.Length), 0, 2); + OutputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) entries.Count), 0, 2); + OutputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) entries.Count), 0, 2); + OutputStream.Write(DataConverter.LittleEndian.GetBytes(size), 0, 4); + OutputStream.Write(DataConverter.LittleEndian.GetBytes((uint) streamPosition), 0, 4); + OutputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) encodedComment.Length), 0, 2); OutputStream.Write(encodedComment, 0, encodedComment.Length); } @@ -254,7 +255,7 @@ namespace SharpCompress.Writer.Zip } else { - originalStream.Write(BitConverter.GetBytes(ZipHeaderFactory.POST_DATA_DESCRIPTOR), 0, 4); + originalStream.Write(DataConverter.LittleEndian.GetBytes(ZipHeaderFactory.POST_DATA_DESCRIPTOR), 0, 4); writer.WriteFooter(entry.Crc, counting.Count, decompressed); writer.streamPosition += entry.Compressed + 16; } From e5ab9dc8832ce0695b8fb6d9d687353e05fe74d7 Mon Sep 17 00:00:00 2001 From: benshoof Date: Mon, 25 Jan 2016 08:03:40 -0900 Subject: [PATCH 07/21] Fix false positives in Rar file detection --- SharpCompress.Test/Tar/TarArchiveTests.cs | 11 ++++ SharpCompress.Test/Tar/TarReaderTests.cs | 12 +++++ SharpCompress/Archive/ArchiveFactory.cs | 4 +- SharpCompress/Archive/Rar/RarArchive.cs | 8 +-- .../Common/Rar/Headers/MarkHeader.cs | 49 +++--------------- TestArchives/Archives/Tar.ContainsRar.tar | Bin 0 -> 61952 bytes 6 files changed, 35 insertions(+), 49 deletions(-) create mode 100644 TestArchives/Archives/Tar.ContainsRar.tar diff --git a/SharpCompress.Test/Tar/TarArchiveTests.cs b/SharpCompress.Test/Tar/TarArchiveTests.cs index b7a8124c..72a1e1ab 100644 --- a/SharpCompress.Test/Tar/TarArchiveTests.cs +++ b/SharpCompress.Test/Tar/TarArchiveTests.cs @@ -145,5 +145,16 @@ namespace SharpCompress.Test } CompareArchivesByPath(modified, scratchPath); } + + [TestMethod] + public void Tar_Containing_Rar_Archive() + { + string archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.ContainsRar.tar"); + using (Stream stream = File.OpenRead(archiveFullPath)) + using (IArchive archive = ArchiveFactory.Open(stream)) + { + Assert.IsTrue(archive.Type == ArchiveType.Tar); + } + } } } diff --git a/SharpCompress.Test/Tar/TarReaderTests.cs b/SharpCompress.Test/Tar/TarReaderTests.cs index 69963df5..af8e63bd 100644 --- a/SharpCompress.Test/Tar/TarReaderTests.cs +++ b/SharpCompress.Test/Tar/TarReaderTests.cs @@ -2,6 +2,7 @@ using System.IO; using Microsoft.VisualStudio.TestTools.UnitTesting; using SharpCompress.Common; +using SharpCompress.Reader; using SharpCompress.Reader.Tar; namespace SharpCompress.Test @@ -88,5 +89,16 @@ namespace SharpCompress.Test Assert.AreEqual(names.Count, 3); } } + + [TestMethod] + public void Tar_Containing_Rar_Reader() + { + string archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.ContainsRar.tar"); + using (Stream stream = File.OpenRead(archiveFullPath)) + using (IReader reader = ReaderFactory.Open(stream)) + { + Assert.IsTrue(reader.ArchiveType == ArchiveType.Tar); + } + } } } diff --git a/SharpCompress/Archive/ArchiveFactory.cs b/SharpCompress/Archive/ArchiveFactory.cs index 278e9e10..8dddbe82 100644 --- a/SharpCompress/Archive/ArchiveFactory.cs +++ b/SharpCompress/Archive/ArchiveFactory.cs @@ -43,7 +43,7 @@ namespace SharpCompress.Archive return GZipArchive.Open(stream, options); } stream.Seek(0, SeekOrigin.Begin); - if(RarArchive.IsRarFile(stream, Options.LookForHeader | Options.KeepStreamsOpen)) + if (RarArchive.IsRarFile(stream, options)) { stream.Seek(0, SeekOrigin.Begin); return RarArchive.Open(stream, options); @@ -138,7 +138,7 @@ namespace SharpCompress.Archive return GZipArchive.Open(fileInfo, options); } stream.Seek(0, SeekOrigin.Begin); - if(RarArchive.IsRarFile(stream, Options.LookForHeader | Options.KeepStreamsOpen)) + if (RarArchive.IsRarFile(stream, options)) { stream.Dispose(); return RarArchive.Open(fileInfo, options); diff --git a/SharpCompress/Archive/Rar/RarArchive.cs b/SharpCompress/Archive/Rar/RarArchive.cs index 4eaada0a..2289a8cc 100644 --- a/SharpCompress/Archive/Rar/RarArchive.cs +++ b/SharpCompress/Archive/Rar/RarArchive.cs @@ -155,12 +155,8 @@ namespace SharpCompress.Archive.Rar try { var headerFactory = new RarHeaderFactory(StreamingMode.Seekable, options); - RarHeader header = headerFactory.ReadHeaders(stream).FirstOrDefault(); - if (header == null) - { - return false; - } - return Enum.IsDefined(typeof (HeaderType), header.HeaderType); + var markHeader = headerFactory.ReadHeaders(stream).FirstOrDefault() as MarkHeader; + return markHeader != null && markHeader.IsValid(); } catch { diff --git a/SharpCompress/Common/Rar/Headers/MarkHeader.cs b/SharpCompress/Common/Rar/Headers/MarkHeader.cs index 41214b46..9df32170 100644 --- a/SharpCompress/Common/Rar/Headers/MarkHeader.cs +++ b/SharpCompress/Common/Rar/Headers/MarkHeader.cs @@ -10,48 +10,15 @@ namespace SharpCompress.Common.Rar.Headers internal bool IsValid() { - if (!(HeadCRC == 0x6152)) - { - return false; - } - if (!(HeaderType == HeaderType.MarkHeader)) - { - return false; - } - if (!(Flags == 0x1a21)) - { - return false; - } - if (!(HeaderSize == BaseBlockSize)) - { - return false; - } - return true; - } + // Rar old signature: 52 45 7E 5E (not supported) - internal bool IsSignature() - { - bool valid = false; - /*byte[] d = new byte[BaseBlock.BaseBlockSize]; - BinaryWriter writer = new BinaryWriter(); - writer.Write(HeadCRC); - writer.Write((byte)HeaderType); - writer.Write(flags); - writer.Write(HeaderSize); - writer.Flush - - if (d[0] == 0x52) { - if (d[1]==0x45 && d[2]==0x7e && d[3]==0x5e) { - oldFormat=true; - valid=true; - } - else if (d[1]==0x61 && d[2]==0x72 && d[3]==0x21 && d[4]==0x1a && - d[5]==0x07 && d[6]==0x00) { - oldFormat=false; - valid=true; - } - }*/ - return valid; + // Rar4 signature: 52 61 72 21 1A 07 00 + return HeadCRC == 0x6152 && + HeaderType == HeaderType.MarkHeader && + Flags == 0x1A21 && + HeaderSize == 0x07; + + // Rar5 signature: 52 61 72 21 1A 07 10 00 (not supported yet) } internal bool OldFormat { get; private set; } diff --git a/TestArchives/Archives/Tar.ContainsRar.tar b/TestArchives/Archives/Tar.ContainsRar.tar new file mode 100644 index 0000000000000000000000000000000000000000..621ab2ab979cb5e9c840aa9f2035bd7fb1f5e3d5 GIT binary patch literal 61952 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 at!8jw2b(oYjE2By2#kinXb22Q2mk=;C#hHf literal 0 HcmV?d00001 From 1661b7ec363c98420ac5b4e114e65a396fbc8410 Mon Sep 17 00:00:00 2001 From: benshoof Date: Mon, 25 Jan 2016 09:02:19 -0900 Subject: [PATCH 08/21] Added support for .NET 3.5 SharpCompress can now be compiled for .NET 3.5 by defining symbol NET35 --- SharpCompress/Archive/IWritableArchive.Extensions.cs | 2 +- SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs | 2 +- SharpCompress/EnumExtensions.cs | 6 ++++-- SharpCompress/SharpCompress.Portable.csproj | 1 + SharpCompress/SharpCompress.PortableTest.csproj | 3 ++- SharpCompress/SharpCompress.Unsigned.csproj | 3 ++- SharpCompress/SharpCompress.WindowsStore.csproj | 1 + SharpCompress/SharpCompress.csproj | 3 ++- SharpCompress/Writer/IWriter.Extensions.cs | 2 +- 9 files changed, 15 insertions(+), 8 deletions(-) diff --git a/SharpCompress/Archive/IWritableArchive.Extensions.cs b/SharpCompress/Archive/IWritableArchive.Extensions.cs index 83d45d40..2b577caa 100644 --- a/SharpCompress/Archive/IWritableArchive.Extensions.cs +++ b/SharpCompress/Archive/IWritableArchive.Extensions.cs @@ -60,7 +60,7 @@ namespace SharpCompress.Archive this IWritableArchive writableArchive, string filePath, string searchPattern = "*.*", SearchOption searchOption = SearchOption.AllDirectories) { -#if NET2 +#if NET35 foreach (var path in Directory.GetFiles(filePath, searchPattern, searchOption)) #else foreach (var path in Directory.EnumerateFiles(filePath, searchPattern, searchOption)) diff --git a/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs b/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs index 216d8652..66c9aca4 100644 --- a/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs +++ b/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs @@ -93,7 +93,7 @@ namespace SharpCompress.Common.Rar.Headers { if (!Options.HasFlag(Options.KeepStreamsOpen)) { -#if NET2 +#if NET35 reader.Close(); #else reader.Dispose(); diff --git a/SharpCompress/EnumExtensions.cs b/SharpCompress/EnumExtensions.cs index e72da2a6..a41fbaed 100644 --- a/SharpCompress/EnumExtensions.cs +++ b/SharpCompress/EnumExtensions.cs @@ -1,4 +1,5 @@ -using System; +#if NET35 +using System; namespace SharpCompress { @@ -12,4 +13,5 @@ namespace SharpCompress return (value & flagVal) == flagVal; } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/SharpCompress/SharpCompress.Portable.csproj b/SharpCompress/SharpCompress.Portable.csproj index 49e43055..2f331a30 100644 --- a/SharpCompress/SharpCompress.Portable.csproj +++ b/SharpCompress/SharpCompress.Portable.csproj @@ -287,6 +287,7 @@ + diff --git a/SharpCompress/SharpCompress.PortableTest.csproj b/SharpCompress/SharpCompress.PortableTest.csproj index 71281f16..523e6901 100644 --- a/SharpCompress/SharpCompress.PortableTest.csproj +++ b/SharpCompress/SharpCompress.PortableTest.csproj @@ -129,7 +129,7 @@ - + @@ -257,6 +257,7 @@ + Code diff --git a/SharpCompress/SharpCompress.Unsigned.csproj b/SharpCompress/SharpCompress.Unsigned.csproj index bfb80856..86c4aa0f 100644 --- a/SharpCompress/SharpCompress.Unsigned.csproj +++ b/SharpCompress/SharpCompress.Unsigned.csproj @@ -131,7 +131,7 @@ - + @@ -244,6 +244,7 @@ + Code diff --git a/SharpCompress/SharpCompress.WindowsStore.csproj b/SharpCompress/SharpCompress.WindowsStore.csproj index b5c5547b..02f9e09b 100644 --- a/SharpCompress/SharpCompress.WindowsStore.csproj +++ b/SharpCompress/SharpCompress.WindowsStore.csproj @@ -273,6 +273,7 @@ + diff --git a/SharpCompress/SharpCompress.csproj b/SharpCompress/SharpCompress.csproj index fd033f1a..0fd10026 100644 --- a/SharpCompress/SharpCompress.csproj +++ b/SharpCompress/SharpCompress.csproj @@ -131,7 +131,7 @@ - + @@ -244,6 +244,7 @@ + Code diff --git a/SharpCompress/Writer/IWriter.Extensions.cs b/SharpCompress/Writer/IWriter.Extensions.cs index 6ccdbc68..75029f6f 100644 --- a/SharpCompress/Writer/IWriter.Extensions.cs +++ b/SharpCompress/Writer/IWriter.Extensions.cs @@ -35,7 +35,7 @@ namespace SharpCompress.Writer { throw new ArgumentException("Directory does not exist: " + directory); } -#if NET2 +#if NET35 foreach (var file in Directory.GetFiles(directory, searchPattern, option)) #else foreach (var file in Directory.EnumerateFiles(directory, searchPattern, option)) From 7b91b6e7c8528f2d76374cfc5cfb532a75ef5cf5 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Tue, 26 Jan 2016 09:48:00 +0100 Subject: [PATCH 09/21] Commented out various unused fields that cause warnings and makes the WarningsAsErrors directive abort the build --- SharpCompress/Archive/Rar/FileInfoRarFilePart.cs | 4 ++-- SharpCompress/Common/GZip/GZipVolume.cs | 4 ++-- SharpCompress/Common/SevenZip/ArchiveReader.cs | 8 ++++---- SharpCompress/Common/SevenZip/DataReader.cs | 4 ++-- SharpCompress/Compressor/LZMA/Bcj2DecoderStream.cs | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/SharpCompress/Archive/Rar/FileInfoRarFilePart.cs b/SharpCompress/Archive/Rar/FileInfoRarFilePart.cs index 558cd14a..b871aeec 100644 --- a/SharpCompress/Archive/Rar/FileInfoRarFilePart.cs +++ b/SharpCompress/Archive/Rar/FileInfoRarFilePart.cs @@ -6,12 +6,12 @@ namespace SharpCompress.Archive.Rar { internal class FileInfoRarFilePart : SeekableFilePart { - private readonly FileInfoRarArchiveVolume volume; + //private readonly FileInfoRarArchiveVolume volume; internal FileInfoRarFilePart(FileInfoRarArchiveVolume volume, MarkHeader mh, FileHeader fh, FileInfo fi) : base(mh, fh, volume.Stream, volume.Password) { - this.volume = volume; + //this.volume = volume; FileInfo = fi; } diff --git a/SharpCompress/Common/GZip/GZipVolume.cs b/SharpCompress/Common/GZip/GZipVolume.cs index 82c7fd7f..4d83b4bd 100644 --- a/SharpCompress/Common/GZip/GZipVolume.cs +++ b/SharpCompress/Common/GZip/GZipVolume.cs @@ -5,7 +5,7 @@ namespace SharpCompress.Common.GZip public class GZipVolume : Volume { #if !PORTABLE && !NETFX_CORE - private readonly FileInfo fileInfo; + //private readonly FileInfo fileInfo; #endif public GZipVolume(Stream stream, Options options) @@ -17,7 +17,7 @@ namespace SharpCompress.Common.GZip public GZipVolume(FileInfo fileInfo, Options options) : base(fileInfo.OpenRead(), options) { - this.fileInfo = fileInfo; + //this.fileInfo = fileInfo; } #endif diff --git a/SharpCompress/Common/SevenZip/ArchiveReader.cs b/SharpCompress/Common/SevenZip/ArchiveReader.cs index 31455ca3..ea478445 100644 --- a/SharpCompress/Common/SevenZip/ArchiveReader.cs +++ b/SharpCompress/Common/SevenZip/ArchiveReader.cs @@ -1198,14 +1198,14 @@ namespace SharpCompress.Common.SevenZip private class FolderUnpackStream : Stream { private ArchiveDatabase _db; - private int _otherIndex; + //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._otherIndex = p; this._startIndex = startIndex; this._extractStatuses = list; } @@ -1275,9 +1275,9 @@ namespace SharpCompress.Common.SevenZip private void OpenFile() { - bool skip = !_extractStatuses[_currentIndex]; + //bool skip = !_extractStatuses[_currentIndex]; int index = _startIndex + _currentIndex; - int realIndex = _otherIndex + index; + //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); diff --git a/SharpCompress/Common/SevenZip/DataReader.cs b/SharpCompress/Common/SevenZip/DataReader.cs index 2b6f27cd..e99da390 100644 --- a/SharpCompress/Common/SevenZip/DataReader.cs +++ b/SharpCompress/Common/SevenZip/DataReader.cs @@ -34,7 +34,7 @@ namespace SharpCompress.Common.SevenZip #region Variables private byte[] _buffer; - private int _origin; + //private int _origin; private int _offset; private int _ending; @@ -45,7 +45,7 @@ namespace SharpCompress.Common.SevenZip public DataReader(byte[] buffer, int offset, int length) { _buffer = buffer; - _origin = offset; + //_origin = offset; _offset = offset; _ending = offset + length; } diff --git a/SharpCompress/Compressor/LZMA/Bcj2DecoderStream.cs b/SharpCompress/Compressor/LZMA/Bcj2DecoderStream.cs index c13f34b6..16e75235 100644 --- a/SharpCompress/Compressor/LZMA/Bcj2DecoderStream.cs +++ b/SharpCompress/Compressor/LZMA/Bcj2DecoderStream.cs @@ -99,7 +99,7 @@ namespace SharpCompress.Compressor.LZMA private RangeDecoder mRangeDecoder; private StatusDecoder[] mStatusDecoder; private long mWritten; - private long mLimit; + //private long mLimit; private IEnumerator mIter; private bool mFinished; private bool isDisposed; @@ -112,7 +112,7 @@ namespace SharpCompress.Compressor.LZMA if (streams.Length != 4) throw new NotSupportedException(); - mLimit = limit; + //mLimit = limit; mMainStream = streams[0]; mCallStream = streams[1]; mJumpStream = streams[2]; From 08b899fdac28492ced6c237200020598f013a229 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Tue, 26 Jan 2016 10:18:13 +0100 Subject: [PATCH 10/21] Deleted unused variables --- SharpCompress/Archive/Rar/FileInfoRarFilePart.cs | 3 --- SharpCompress/Common/GZip/GZipVolume.cs | 5 ----- SharpCompress/Common/SevenZip/ArchiveReader.cs | 3 --- SharpCompress/Common/SevenZip/DataReader.cs | 2 -- SharpCompress/Compressor/LZMA/Bcj2DecoderStream.cs | 2 -- 5 files changed, 15 deletions(-) diff --git a/SharpCompress/Archive/Rar/FileInfoRarFilePart.cs b/SharpCompress/Archive/Rar/FileInfoRarFilePart.cs index b871aeec..8c64e3b3 100644 --- a/SharpCompress/Archive/Rar/FileInfoRarFilePart.cs +++ b/SharpCompress/Archive/Rar/FileInfoRarFilePart.cs @@ -6,12 +6,9 @@ namespace SharpCompress.Archive.Rar { internal class FileInfoRarFilePart : SeekableFilePart { - //private readonly FileInfoRarArchiveVolume volume; - internal FileInfoRarFilePart(FileInfoRarArchiveVolume volume, MarkHeader mh, FileHeader fh, FileInfo fi) : base(mh, fh, volume.Stream, volume.Password) { - //this.volume = volume; FileInfo = fi; } diff --git a/SharpCompress/Common/GZip/GZipVolume.cs b/SharpCompress/Common/GZip/GZipVolume.cs index 4d83b4bd..0b49f649 100644 --- a/SharpCompress/Common/GZip/GZipVolume.cs +++ b/SharpCompress/Common/GZip/GZipVolume.cs @@ -4,10 +4,6 @@ namespace SharpCompress.Common.GZip { public class GZipVolume : Volume { -#if !PORTABLE && !NETFX_CORE - //private readonly FileInfo fileInfo; -#endif - public GZipVolume(Stream stream, Options options) : base(stream, options) { @@ -17,7 +13,6 @@ namespace SharpCompress.Common.GZip public GZipVolume(FileInfo fileInfo, Options options) : base(fileInfo.OpenRead(), options) { - //this.fileInfo = fileInfo; } #endif diff --git a/SharpCompress/Common/SevenZip/ArchiveReader.cs b/SharpCompress/Common/SevenZip/ArchiveReader.cs index ea478445..59e544a7 100644 --- a/SharpCompress/Common/SevenZip/ArchiveReader.cs +++ b/SharpCompress/Common/SevenZip/ArchiveReader.cs @@ -1198,14 +1198,12 @@ namespace SharpCompress.Common.SevenZip 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; } @@ -1277,7 +1275,6 @@ namespace SharpCompress.Common.SevenZip { //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); diff --git a/SharpCompress/Common/SevenZip/DataReader.cs b/SharpCompress/Common/SevenZip/DataReader.cs index e99da390..fe8d6435 100644 --- a/SharpCompress/Common/SevenZip/DataReader.cs +++ b/SharpCompress/Common/SevenZip/DataReader.cs @@ -34,7 +34,6 @@ namespace SharpCompress.Common.SevenZip #region Variables private byte[] _buffer; - //private int _origin; private int _offset; private int _ending; @@ -45,7 +44,6 @@ namespace SharpCompress.Common.SevenZip public DataReader(byte[] buffer, int offset, int length) { _buffer = buffer; - //_origin = offset; _offset = offset; _ending = offset + length; } diff --git a/SharpCompress/Compressor/LZMA/Bcj2DecoderStream.cs b/SharpCompress/Compressor/LZMA/Bcj2DecoderStream.cs index 16e75235..8034cd7a 100644 --- a/SharpCompress/Compressor/LZMA/Bcj2DecoderStream.cs +++ b/SharpCompress/Compressor/LZMA/Bcj2DecoderStream.cs @@ -99,7 +99,6 @@ namespace SharpCompress.Compressor.LZMA private RangeDecoder mRangeDecoder; private StatusDecoder[] mStatusDecoder; private long mWritten; - //private long mLimit; private IEnumerator mIter; private bool mFinished; private bool isDisposed; @@ -112,7 +111,6 @@ namespace SharpCompress.Compressor.LZMA if (streams.Length != 4) throw new NotSupportedException(); - //mLimit = limit; mMainStream = streams[0]; mCallStream = streams[1]; mJumpStream = streams[2]; From f20274aac7a9bd5f45bb8bed771289bfe8dc93ed Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Tue, 26 Jan 2016 10:18:23 +0100 Subject: [PATCH 11/21] Removed debug comments --- SharpCompress/Common/SevenZip/ArchiveReader.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/SharpCompress/Common/SevenZip/ArchiveReader.cs b/SharpCompress/Common/SevenZip/ArchiveReader.cs index 59e544a7..0196120b 100644 --- a/SharpCompress/Common/SevenZip/ArchiveReader.cs +++ b/SharpCompress/Common/SevenZip/ArchiveReader.cs @@ -1273,11 +1273,7 @@ namespace SharpCompress.Common.SevenZip private void OpenFile() { - //bool skip = !_extractStatuses[_currentIndex]; int index = _startIndex + _currentIndex; - //string filename = @"D:\_testdump\" + _db.Files[index].Name; - //Directory.CreateDirectory(Path.GetDirectoryName(filename)); - //_stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Delete); #if DEBUG Log.WriteLine(_db.Files[index].Name); #endif From 0de64b1551ff1f00bc422072303e6d2fceeff8d3 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 26 Jan 2016 11:49:57 +0000 Subject: [PATCH 12/21] Use ExtractAllEntries if archives are SOLID types --- SharpCompress/Archive/Rar/RarArchive.cs | 3 -- SharpCompress/Archive/Rar/RarArchiveEntry.cs | 34 ++----------------- .../Archive/SevenZip/SevenZipArchiveEntry.cs | 7 +++- 3 files changed, 8 insertions(+), 36 deletions(-) diff --git a/SharpCompress/Archive/Rar/RarArchive.cs b/SharpCompress/Archive/Rar/RarArchive.cs index 4eaada0a..f7f88b39 100644 --- a/SharpCompress/Archive/Rar/RarArchive.cs +++ b/SharpCompress/Archive/Rar/RarArchive.cs @@ -14,9 +14,6 @@ namespace SharpCompress.Archive.Rar { public class RarArchive : AbstractArchive { - internal IEnumerator SolidEntryEnumerator; - internal List SolidReadedEntries=new List(); - private readonly Unpack unpack = new Unpack(); internal Unpack Unpack diff --git a/SharpCompress/Archive/Rar/RarArchiveEntry.cs b/SharpCompress/Archive/Rar/RarArchiveEntry.cs index ab033514..9b69100b 100644 --- a/SharpCompress/Archive/Rar/RarArchiveEntry.cs +++ b/SharpCompress/Archive/Rar/RarArchiveEntry.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -70,43 +71,12 @@ namespace SharpCompress.Archive.Rar return parts.Aggregate(0L, (total, fp) => { return total + fp.FileHeader.CompressedSize; }); } } - private readonly byte[] skipBuffer = new byte[4096]; - private void Skip(RarArchiveEntry en) - { - using (var s = new RarStream(archive.Unpack, en.FileHeader, new MultiVolumeReadOnlyStream(en.parts, archive))) - { - while (s.Read(skipBuffer, 0, skipBuffer.Length) > 0); - } - } - - private void MoveNext() - { - archive.SolidReadedEntries.Add(archive.SolidEntryEnumerator.Current); - if (!archive.SolidEntryEnumerator.MoveNext()) - { - archive.SolidEntryEnumerator = archive.Entries.GetEnumerator(); - archive.SolidReadedEntries = new List(); - archive.SolidEntryEnumerator.MoveNext(); - } - } public Stream OpenEntryStream() { if (archive.IsSolid) { - - if ((archive.SolidEntryEnumerator == null) || (archive.SolidReadedEntries.Any(b=>b.FileHeader==FileHeader))) - { - archive.SolidEntryEnumerator = archive.Entries.GetEnumerator(); - archive.SolidReadedEntries = new List(); - archive.SolidEntryEnumerator.MoveNext(); - } - while (archive.SolidEntryEnumerator.Current.FileHeader != FileHeader) - { - Skip(archive.SolidEntryEnumerator.Current); - MoveNext(); - } - MoveNext(); + throw new InvalidOperationException("Use ExtractAllEntries to extract SOLID archives."); } return new RarStream(archive.Unpack, FileHeader, new MultiVolumeReadOnlyStream(Parts.Cast(), archive)); } diff --git a/SharpCompress/Archive/SevenZip/SevenZipArchiveEntry.cs b/SharpCompress/Archive/SevenZip/SevenZipArchiveEntry.cs index ca893e22..7f60328a 100644 --- a/SharpCompress/Archive/SevenZip/SevenZipArchiveEntry.cs +++ b/SharpCompress/Archive/SevenZip/SevenZipArchiveEntry.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using SharpCompress.Common.SevenZip; namespace SharpCompress.Archive.SevenZip @@ -13,6 +14,10 @@ namespace SharpCompress.Archive.SevenZip public Stream OpenEntryStream() { + if (Archive.IsSolid) + { + throw new InvalidOperationException("Use ExtractAllEntries to extract SOLID archives."); + } return FilePart.GetCompressedStream(); } public IArchive Archive { get; private set; } From 2e8844c896bea4b422a98fd888ca4fcd20b7ff9c Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 26 Jan 2016 11:57:40 +0000 Subject: [PATCH 13/21] This doesn't work :) --- SharpCompress/Archive/SevenZip/SevenZipArchiveEntry.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/SharpCompress/Archive/SevenZip/SevenZipArchiveEntry.cs b/SharpCompress/Archive/SevenZip/SevenZipArchiveEntry.cs index 7f60328a..c5c2aaba 100644 --- a/SharpCompress/Archive/SevenZip/SevenZipArchiveEntry.cs +++ b/SharpCompress/Archive/SevenZip/SevenZipArchiveEntry.cs @@ -14,10 +14,6 @@ namespace SharpCompress.Archive.SevenZip public Stream OpenEntryStream() { - if (Archive.IsSolid) - { - throw new InvalidOperationException("Use ExtractAllEntries to extract SOLID archives."); - } return FilePart.GetCompressedStream(); } public IArchive Archive { get; private set; } From a4b594121e34a9ffa589b9205b7ee0a9b9b4b229 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Thu, 4 Feb 2016 10:35:36 +0100 Subject: [PATCH 14/21] Added code to forward the compression info to the stream, such that it is possible to override the compression level and method on a per-stream basis. --- SharpCompress/Writer/Zip/ZipWriter.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/SharpCompress/Writer/Zip/ZipWriter.cs b/SharpCompress/Writer/Zip/ZipWriter.cs index 1831db22..989a2922 100644 --- a/SharpCompress/Writer/Zip/ZipWriter.cs +++ b/SharpCompress/Writer/Zip/ZipWriter.cs @@ -75,7 +75,7 @@ namespace SharpCompress.Writer.Zip var headersize = (uint)WriteHeader(entryPath, modificationTime, compressionInfo); streamPosition += headersize; - return new ZipWritingStream(this, OutputStream, entry); + return new ZipWritingStream(this, OutputStream, entry, compressionInfo); } private string NormalizeFilename(string filename) @@ -154,16 +154,18 @@ namespace SharpCompress.Writer.Zip private readonly Stream originalStream; private readonly Stream writeStream; private readonly ZipWriter writer; + private readonly ZipCompressionInfo compressionInfo; private CountingWritableSubStream counting; private uint decompressed; - internal ZipWritingStream(ZipWriter writer, Stream originalStream, ZipCentralDirectoryEntry entry) + internal ZipWritingStream(ZipWriter writer, Stream originalStream, ZipCentralDirectoryEntry entry, CompressionInfo compressionInfo = null) { this.writer = writer; this.originalStream = originalStream; writeStream = GetWriteStream(originalStream); this.writer = writer; this.entry = entry; + this.compressionInfo = compressionInfo == null ? writer.zipCompressionInfo : new ZipCompressionInfo(compressionInfo); } public override bool CanRead @@ -196,7 +198,7 @@ namespace SharpCompress.Writer.Zip { counting = new CountingWritableSubStream(writeStream); Stream output = counting; - switch (writer.zipCompressionInfo.Compression) + switch (compressionInfo.Compression) { case ZipCompressionMethod.None: { @@ -204,7 +206,7 @@ namespace SharpCompress.Writer.Zip } case ZipCompressionMethod.Deflate: { - return new DeflateStream(counting, CompressionMode.Compress, writer.zipCompressionInfo.DeflateCompressionLevel, + return new DeflateStream(counting, CompressionMode.Compress, compressionInfo.DeflateCompressionLevel, true); } case ZipCompressionMethod.BZip2: @@ -230,7 +232,7 @@ namespace SharpCompress.Writer.Zip } default: { - throw new NotSupportedException("CompressionMethod: " + writer.zipCompressionInfo.Compression); + throw new NotSupportedException("CompressionMethod: " + compressionInfo.Compression); } } } From ed7f140364b72925783f08d444ec2d368773aab1 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Thu, 4 Feb 2016 10:39:02 +0100 Subject: [PATCH 15/21] Whitespace fix --- SharpCompress/Writer/Zip/ZipWriter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SharpCompress/Writer/Zip/ZipWriter.cs b/SharpCompress/Writer/Zip/ZipWriter.cs index 989a2922..ce69be1e 100644 --- a/SharpCompress/Writer/Zip/ZipWriter.cs +++ b/SharpCompress/Writer/Zip/ZipWriter.cs @@ -75,7 +75,7 @@ namespace SharpCompress.Writer.Zip var headersize = (uint)WriteHeader(entryPath, modificationTime, compressionInfo); streamPosition += headersize; - return new ZipWritingStream(this, OutputStream, entry, compressionInfo); + return new ZipWritingStream(this, OutputStream, entry, compressionInfo); } private string NormalizeFilename(string filename) @@ -158,7 +158,7 @@ namespace SharpCompress.Writer.Zip private CountingWritableSubStream counting; private uint decompressed; - internal ZipWritingStream(ZipWriter writer, Stream originalStream, ZipCentralDirectoryEntry entry, CompressionInfo compressionInfo = null) + internal ZipWritingStream(ZipWriter writer, Stream originalStream, ZipCentralDirectoryEntry entry, CompressionInfo compressionInfo = null) { this.writer = writer; this.originalStream = originalStream; From a05b692fc3594eb2f6143a1e5ce21a58f2230139 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Thu, 4 Feb 2016 10:39:58 +0100 Subject: [PATCH 16/21] More whitespace fix --- SharpCompress/Writer/Zip/ZipWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharpCompress/Writer/Zip/ZipWriter.cs b/SharpCompress/Writer/Zip/ZipWriter.cs index ce69be1e..96067796 100644 --- a/SharpCompress/Writer/Zip/ZipWriter.cs +++ b/SharpCompress/Writer/Zip/ZipWriter.cs @@ -154,7 +154,7 @@ namespace SharpCompress.Writer.Zip private readonly Stream originalStream; private readonly Stream writeStream; private readonly ZipWriter writer; - private readonly ZipCompressionInfo compressionInfo; + private readonly ZipCompressionInfo compressionInfo; private CountingWritableSubStream counting; private uint decompressed; From b3a5204e74cc221466269b9a811c165aaed0ba79 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Sun, 7 Feb 2016 10:14:07 +0000 Subject: [PATCH 17/21] Bug fix for previous PR --- SharpCompress/Writer/Zip/ZipWriter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SharpCompress/Writer/Zip/ZipWriter.cs b/SharpCompress/Writer/Zip/ZipWriter.cs index 96067796..1b4c929f 100644 --- a/SharpCompress/Writer/Zip/ZipWriter.cs +++ b/SharpCompress/Writer/Zip/ZipWriter.cs @@ -158,14 +158,14 @@ namespace SharpCompress.Writer.Zip private CountingWritableSubStream counting; private uint decompressed; - internal ZipWritingStream(ZipWriter writer, Stream originalStream, ZipCentralDirectoryEntry entry, CompressionInfo compressionInfo = null) + internal ZipWritingStream(ZipWriter writer, Stream originalStream, ZipCentralDirectoryEntry entry, CompressionInfo compressionInfo) { this.writer = writer; this.originalStream = originalStream; - writeStream = GetWriteStream(originalStream); this.writer = writer; this.entry = entry; this.compressionInfo = compressionInfo == null ? writer.zipCompressionInfo : new ZipCompressionInfo(compressionInfo); + writeStream = GetWriteStream(originalStream); } public override bool CanRead From 1fc14e10755a251615aa94f596ffcd676b6ae3b7 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Sun, 7 Feb 2016 10:17:45 +0000 Subject: [PATCH 18/21] Update to 0.11.4 --- NuGet/sharpcompress.nuspec | 2 +- README.md | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/NuGet/sharpcompress.nuspec b/NuGet/sharpcompress.nuspec index b445f0c2..a77d4357 100644 --- a/NuGet/sharpcompress.nuspec +++ b/NuGet/sharpcompress.nuspec @@ -2,7 +2,7 @@ sharpcompress - 0.11.3 + 0.11.4 SharpCompress - Pure C# Decompression/Compression Adam Hathcock Adam Hathcock diff --git a/README.md b/README.md index d3a2e211..47611fcd 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ A Simple Request Hi everyone. I hope you're using SharpCompress and finding it useful. Please give me feedback on what you'd like to see changed especially as far as usability goes. New feature suggestions are always welcome as well. I would also like to know what projects SharpCompress is being used in. I like seeing how it is used to give me ideas for future versions. Thanks! +Please do not email me directly to ask for help. If you think there is a real issue, please report it here. + Want to contribute? I'm always looking for help or ideas. Please submit code or email with ideas. Unfortunately, just letting me know you'd like to help is not enough because I really have no overall plan of what needs to be done. I'll definitely accept code submissions and add you as a member of the project! @@ -25,6 +27,12 @@ In-Progress: - DNX/NET Core support - xproj targeting +Version 0.11.4: +============== +- SharpCompress is now endian neutral (matters for Mono platforms) +- Fix for Inflate (need to change implementation) +- Fixes for RAR detection + Version 0.11.1: ============== - Added Cancel on IReader From 9b8ddda191d7939ec684b44991d27fbe6e262954 Mon Sep 17 00:00:00 2001 From: Josef Eklann Date: Wed, 10 Feb 2016 14:56:05 +0100 Subject: [PATCH 19/21] Fixed bug triggered by incomplete rar file. --- SharpCompress/Utility.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharpCompress/Utility.cs b/SharpCompress/Utility.cs index d6599187..0417c654 100644 --- a/SharpCompress/Utility.cs +++ b/SharpCompress/Utility.cs @@ -146,7 +146,7 @@ namespace SharpCompress readCount = (int)advanceAmount; } read = source.Read(buffer, 0, readCount); - if (read < 0) + if (read == 0) { break; } From d13b2ad073654db2c338f1dcdcfed5082db7b027 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Sat, 13 Feb 2016 09:16:43 +0000 Subject: [PATCH 20/21] Do less than equals --- SharpCompress/Utility.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharpCompress/Utility.cs b/SharpCompress/Utility.cs index 0417c654..03d5cc84 100644 --- a/SharpCompress/Utility.cs +++ b/SharpCompress/Utility.cs @@ -146,7 +146,7 @@ namespace SharpCompress readCount = (int)advanceAmount; } read = source.Read(buffer, 0, readCount); - if (read == 0) + if (read <= 0) { break; } From ee5e3fbc1d05d84af4645aad935fbef4aadb4226 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Sat, 13 Feb 2016 09:17:29 +0000 Subject: [PATCH 21/21] Update to 0.11.5 --- NuGet/sharpcompress.nuspec | 2 +- README.md | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/NuGet/sharpcompress.nuspec b/NuGet/sharpcompress.nuspec index a77d4357..1ec39a31 100644 --- a/NuGet/sharpcompress.nuspec +++ b/NuGet/sharpcompress.nuspec @@ -2,7 +2,7 @@ sharpcompress - 0.11.4 + 0.11.5 SharpCompress - Pure C# Decompression/Compression Adam Hathcock Adam Hathcock diff --git a/README.md b/README.md index 47611fcd..2c1be0f3 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,10 @@ In-Progress: - DNX/NET Core support - xproj targeting +Version 0.11.5: +============== +- Bug fix in Skip method + Version 0.11.4: ============== - SharpCompress is now endian neutral (matters for Mono platforms)