mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-07 21:22:04 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1aa0498e5d | ||
|
|
1ce5e15fd2 | ||
|
|
b40131736a | ||
|
|
c2b15b9c09 | ||
|
|
27a4f78712 | ||
|
|
2b5ee6e8cb | ||
|
|
cd8ea28576 | ||
|
|
b2b6934499 | ||
|
|
0f12a073af | ||
|
|
18bd810228 | ||
|
|
13bbb202c7 | ||
|
|
9a638e7aa5 | ||
|
|
7a11dc4385 | ||
|
|
66816ce390 | ||
|
|
5d8bd7b69b | ||
|
|
0132c85ec7 | ||
|
|
9bf5df72a6 | ||
|
|
91fc241358 | ||
|
|
35a8b444b8 | ||
|
|
2e928e86fd | ||
|
|
6648f33c4e | ||
|
|
2a70ec8100 | ||
|
|
05e0d591a5 | ||
|
|
1d30a1b51d | ||
|
|
b0c514d87c |
@@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>sharpcompress</id>
|
||||
<version>0.11.1</version>
|
||||
<version>0.11.2</version>
|
||||
<title>SharpCompress - Pure C# Decompression/Compression</title>
|
||||
<authors>Adam Hathcock</authors>
|
||||
<owners>Adam Hathcock</owners>
|
||||
|
||||
@@ -21,6 +21,11 @@ TODOs (always lots):
|
||||
* Zip64
|
||||
* Multi-volume Zip support.
|
||||
|
||||
Version 0.11.1:
|
||||
==============
|
||||
- Added Cancel on IReader
|
||||
- Removed .NET 2.0 support and LinqBridge dependency
|
||||
|
||||
Version 0.11:
|
||||
==============
|
||||
- Been over a year, contains mainly fixes from contributors!
|
||||
|
||||
@@ -125,6 +125,55 @@ namespace SharpCompress.Test
|
||||
|
||||
private long? entryTotal;
|
||||
private long partTotal;
|
||||
private long totalSize;
|
||||
|
||||
protected void ArchiveFileReadEx(string testArchive)
|
||||
{
|
||||
testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive);
|
||||
ArchiveFileReadEx(testArchive.AsEnumerable());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrate the TotalUncompressSize property, and the ExtractOptions.PreserveFileTime and ExtractOptions.PreserveAttributes extract options
|
||||
/// </summary>
|
||||
protected void ArchiveFileReadEx(IEnumerable<string> testArchives)
|
||||
{
|
||||
foreach (var path in testArchives)
|
||||
{
|
||||
ResetScratch();
|
||||
using (var archive = ArchiveFactory.Open(path))
|
||||
{
|
||||
this.totalSize = archive.TotalUncompressSize;
|
||||
archive.EntryExtractionBegin += Archive_EntryExtractionBeginEx;
|
||||
archive.EntryExtractionEnd += Archive_EntryExtractionEndEx;
|
||||
archive.CompressedBytesRead += Archive_CompressedBytesReadEx;
|
||||
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH,
|
||||
ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite | ExtractOptions.PreserveFileTime | ExtractOptions.PreserveAttributes);
|
||||
}
|
||||
}
|
||||
VerifyFilesEx();
|
||||
}
|
||||
}
|
||||
|
||||
private void Archive_EntryExtractionEndEx(object sender, ArchiveExtractionEventArgs<IArchiveEntry> e)
|
||||
{
|
||||
this.partTotal += e.Item.Size;
|
||||
}
|
||||
|
||||
private void Archive_CompressedBytesReadEx(object sender, CompressedBytesReadEventArgs e)
|
||||
{
|
||||
string percentage = this.entryTotal.HasValue ? this.CreatePercentage(e.CompressedBytesRead, this.entryTotal.Value).ToString() : "-";
|
||||
string tortalPercentage = this.CreatePercentage(this.partTotal + e.CompressedBytesRead, this.totalSize).ToString();
|
||||
Console.WriteLine(@"Read Compressed File Progress: {0}% Total Progress {1}%", percentage, tortalPercentage);
|
||||
}
|
||||
|
||||
private void Archive_EntryExtractionBeginEx(object sender, ArchiveExtractionEventArgs<IArchiveEntry> e)
|
||||
{
|
||||
this.entryTotal = e.Item.Size;
|
||||
}
|
||||
|
||||
private int CreatePercentage(long n, long d)
|
||||
{
|
||||
|
||||
@@ -61,6 +61,11 @@ namespace SharpCompress.Test
|
||||
ArchiveFileRead("7Zip.BZip2.7z");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SevenZipArchive_LZMA_Time_Attributes_PathRead()
|
||||
{
|
||||
ArchiveFileReadEx("7Zip.LZMA.7z");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(IndexOutOfRangeException))]
|
||||
|
||||
@@ -78,6 +78,21 @@ namespace SharpCompress.Test
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the files also check modified time and attributes.
|
||||
/// </summary>
|
||||
public void VerifyFilesEx()
|
||||
{
|
||||
if (UseExtensionInsteadOfNameToVerify)
|
||||
{
|
||||
VerifyFilesByExtensionEx();
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyFilesByNameEx();
|
||||
}
|
||||
}
|
||||
|
||||
protected void VerifyFilesByName()
|
||||
{
|
||||
var extracted =
|
||||
@@ -97,6 +112,52 @@ namespace SharpCompress.Test
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the files by name also check modified time and attributes.
|
||||
/// </summary>
|
||||
protected void VerifyFilesByNameEx()
|
||||
{
|
||||
var extracted =
|
||||
Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories)
|
||||
.ToLookup(path => path.Substring(SCRATCH_FILES_PATH.Length));
|
||||
var original =
|
||||
Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories)
|
||||
.ToLookup(path => path.Substring(ORIGINAL_FILES_PATH.Length));
|
||||
|
||||
Assert.AreEqual(extracted.Count, original.Count);
|
||||
|
||||
foreach (var orig in original)
|
||||
{
|
||||
Assert.IsTrue(extracted.Contains(orig.Key));
|
||||
|
||||
CompareFilesByPath(orig.Single(), extracted[orig.Key].Single());
|
||||
CompareFilesByTimeAndAttribut(orig.Single(), extracted[orig.Key].Single());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the files by extension also check modified time and attributes.
|
||||
/// </summary>
|
||||
protected void VerifyFilesByExtensionEx()
|
||||
{
|
||||
var extracted =
|
||||
Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories)
|
||||
.ToLookup(path => Path.GetExtension(path));
|
||||
var original =
|
||||
Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories)
|
||||
.ToLookup(path => Path.GetExtension(path));
|
||||
|
||||
Assert.AreEqual(extracted.Count, original.Count);
|
||||
|
||||
foreach (var orig in original)
|
||||
{
|
||||
Assert.IsTrue(extracted.Contains(orig.Key));
|
||||
|
||||
CompareFilesByPath(orig.Single(), extracted[orig.Key].Single());
|
||||
CompareFilesByTimeAndAttribut(orig.Single(), extracted[orig.Key].Single());
|
||||
}
|
||||
}
|
||||
|
||||
protected bool UseExtensionInsteadOfNameToVerify { get; set; }
|
||||
|
||||
protected void VerifyFilesByExtension()
|
||||
@@ -137,6 +198,14 @@ namespace SharpCompress.Test
|
||||
}
|
||||
}
|
||||
|
||||
protected void CompareFilesByTimeAndAttribut(string file1, string file2)
|
||||
{
|
||||
FileInfo fi1 = new FileInfo(file1);
|
||||
FileInfo fi2 = new FileInfo(file2);
|
||||
Assert.AreNotEqual(fi1.LastWriteTime, fi2.LastWriteTime);
|
||||
Assert.AreEqual(fi1.Attributes, fi2.Attributes);
|
||||
}
|
||||
|
||||
protected void CompareArchivesByPath(string file1, string file2)
|
||||
{
|
||||
using (var archive1 = ReaderFactory.Open(File.OpenRead(file1), Options.None))
|
||||
|
||||
@@ -84,7 +84,6 @@ namespace SharpCompress.Archive
|
||||
/// <summary>
|
||||
/// Returns an ReadOnlyCollection of all the RarArchiveEntries across the one or many parts of the RarArchive.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual ICollection<TEntry> Entries
|
||||
{
|
||||
get { return lazyEntries; }
|
||||
@@ -93,7 +92,6 @@ namespace SharpCompress.Archive
|
||||
/// <summary>
|
||||
/// Returns an ReadOnlyCollection of all the RarArchiveVolumes across the one or many parts of the RarArchive.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ICollection<TVolume> Volumes
|
||||
{
|
||||
get { return lazyVolumes; }
|
||||
@@ -102,11 +100,19 @@ namespace SharpCompress.Archive
|
||||
/// <summary>
|
||||
/// The total size of the files compressed in the archive.
|
||||
/// </summary>
|
||||
public long TotalSize
|
||||
public virtual long TotalSize
|
||||
{
|
||||
get { return Entries.Aggregate(0L, (total, cf) => total + cf.CompressedSize); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The total size of the files as uncompressed in the archive.
|
||||
/// </summary>
|
||||
public virtual long TotalUncompressSize
|
||||
{
|
||||
get { return Entries.Aggregate(0L, (total, cf) => total + cf.Size); }
|
||||
}
|
||||
|
||||
protected abstract IEnumerable<TVolume> LoadVolumes(IEnumerable<Stream> streams, Options options);
|
||||
protected abstract IEnumerable<TEntry> LoadEntries(IEnumerable<TVolume> volumes);
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ namespace SharpCompress.Archive
|
||||
event EventHandler<FilePartExtractionBeginEventArgs> FilePartExtractionBegin;
|
||||
|
||||
IEnumerable<IArchiveEntry> Entries { get; }
|
||||
long TotalSize { get; }
|
||||
IEnumerable<IVolume> Volumes { get; }
|
||||
|
||||
ArchiveType Type { get; }
|
||||
@@ -24,7 +23,6 @@ namespace SharpCompress.Archive
|
||||
/// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be
|
||||
/// extracted sequentially for the best performance.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IReader ExtractAllEntries();
|
||||
|
||||
/// <summary>
|
||||
@@ -37,5 +35,15 @@ namespace SharpCompress.Archive
|
||||
/// This checks to see if all the known entries have IsComplete = true
|
||||
/// </summary>
|
||||
bool IsComplete { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The total size of the files compressed in the archive.
|
||||
/// </summary>
|
||||
long TotalSize { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The total size of the files as uncompressed in the archive.
|
||||
/// </summary>
|
||||
long TotalUncompressSize { get; }
|
||||
}
|
||||
}
|
||||
@@ -83,6 +83,40 @@ namespace SharpCompress.Archive
|
||||
{
|
||||
entry.WriteTo(fs);
|
||||
}
|
||||
|
||||
if (options.HasFlag(ExtractOptions.PreserveFileTime) || options.HasFlag(ExtractOptions.PreserveAttributes))
|
||||
{
|
||||
// update file time to original packed time
|
||||
FileInfo nf = new FileInfo(destinationFileName);
|
||||
if (nf.Exists)
|
||||
{
|
||||
if (options.HasFlag(ExtractOptions.PreserveFileTime))
|
||||
{
|
||||
if (entry.CreatedTime.HasValue)
|
||||
{
|
||||
nf.CreationTime = entry.CreatedTime.Value;
|
||||
}
|
||||
|
||||
if (entry.LastModifiedTime.HasValue)
|
||||
{
|
||||
nf.LastWriteTime = entry.LastModifiedTime.Value;
|
||||
}
|
||||
|
||||
if (entry.LastAccessedTime.HasValue)
|
||||
{
|
||||
nf.LastAccessTime = entry.CreatedTime.Value;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.HasFlag(ExtractOptions.PreserveAttributes))
|
||||
{
|
||||
if (entry.Attrib.HasValue)
|
||||
{
|
||||
nf.Attributes = (FileAttributes)System.Enum.ToObject(typeof(FileAttributes), entry.Attrib.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -188,6 +188,15 @@ namespace SharpCompress.Archive.SevenZip
|
||||
get { return Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() > 1; }
|
||||
}
|
||||
|
||||
public override long TotalSize
|
||||
{
|
||||
get
|
||||
{
|
||||
int i = Entries.Count;
|
||||
return database.PackSizes.Aggregate(0L, (total, packSize) => total + packSize);
|
||||
}
|
||||
}
|
||||
|
||||
private class SevenZipReader : AbstractReader<SevenZipEntry, SevenZipVolume>
|
||||
{
|
||||
private readonly SevenZipArchive archive;
|
||||
|
||||
@@ -116,7 +116,7 @@ namespace SharpCompress.Archive.Zip
|
||||
try
|
||||
{
|
||||
ZipHeader header =
|
||||
headerFactory.ReadStreamHeader(stream).FirstOrDefault(x => x.ZipHeaderType != ZipHeaderType.Split);
|
||||
headerFactory.ReadStreamHeader(stream).FirstOrDefault(x => x != null && x.ZipHeaderType != ZipHeaderType.Split);
|
||||
if (header == null)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace SharpCompress.Common
|
||||
public abstract DateTime? LastAccessedTime { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The entry time whend archived, if recorded
|
||||
/// The entry time when archived, if recorded
|
||||
/// </summary>
|
||||
public abstract DateTime? ArchivedTime { get; }
|
||||
|
||||
@@ -70,7 +70,16 @@ namespace SharpCompress.Common
|
||||
|
||||
internal virtual void Close()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Entry file attribute.
|
||||
/// </summary>
|
||||
public virtual int? Attrib
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,16 +5,26 @@ namespace SharpCompress.Common
|
||||
[Flags]
|
||||
public enum ExtractOptions
|
||||
{
|
||||
None,
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// overwrite target if it exists
|
||||
/// </summary>
|
||||
Overwrite,
|
||||
Overwrite = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// extract with internal directory structure
|
||||
/// </summary>
|
||||
ExtractFullPath,
|
||||
ExtractFullPath = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// preserve file time
|
||||
/// </summary>
|
||||
PreserveFileTime = 1 << 2,
|
||||
|
||||
/// <summary>
|
||||
/// preserve windows file attributes
|
||||
/// </summary>
|
||||
PreserveAttributes = 1 << 3,
|
||||
}
|
||||
}
|
||||
@@ -16,5 +16,6 @@ namespace SharpCompress.Common
|
||||
DateTime? LastAccessedTime { get; }
|
||||
DateTime? LastModifiedTime { get; }
|
||||
long Size { get; }
|
||||
int? Attrib { get; }
|
||||
}
|
||||
}
|
||||
@@ -67,8 +67,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
ulong id = _currentReader.ReadNumber();
|
||||
if (id > 25)
|
||||
return null;
|
||||
|
||||
#if DEBUG
|
||||
Log.WriteLine("ReadId: {0}", (BlockType)id);
|
||||
#endif
|
||||
return (BlockType)id;
|
||||
}
|
||||
|
||||
@@ -197,20 +198,25 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
private void GetNextFolderItem(CFolder folder)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- GetNextFolderItem --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
int numCoders = ReadNum();
|
||||
#if DEBUG
|
||||
Log.WriteLine("NumCoders: " + numCoders);
|
||||
|
||||
#endif
|
||||
folder.Coders = new List<CCoderInfo>(numCoders);
|
||||
int numInStreams = 0;
|
||||
int numOutStreams = 0;
|
||||
for (int i = 0; i < numCoders; i++)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- Coder --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
CCoderInfo coder = new CCoderInfo();
|
||||
@@ -220,11 +226,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
int idSize = (mainByte & 0xF);
|
||||
byte[] longID = new byte[idSize];
|
||||
ReadBytes(longID, 0, idSize);
|
||||
Log.WriteLine("MethodId: " +
|
||||
String.Join("",
|
||||
Enumerable.Range(0, idSize)
|
||||
.Select(x => longID[x].ToString("x2"))
|
||||
.ToArray()));
|
||||
#if DEBUG
|
||||
Log.WriteLine("MethodId: " + String.Join("", Enumerable.Range(0, idSize).Select(x => longID[x].ToString("x2")).ToArray()));
|
||||
#endif
|
||||
if (idSize > 8)
|
||||
throw new NotSupportedException();
|
||||
ulong id = 0;
|
||||
@@ -236,12 +240,15 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
coder.NumInStreams = ReadNum();
|
||||
coder.NumOutStreams = ReadNum();
|
||||
Log.WriteLine("Complex Stream (In: " + coder.NumInStreams + " - Out: " + coder.NumOutStreams +
|
||||
")");
|
||||
#if DEBUG
|
||||
Log.WriteLine("Complex Stream (In: " + coder.NumInStreams + " - Out: " + coder.NumOutStreams + ")");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("Simple Stream (In: 1 - Out: 1)");
|
||||
#endif
|
||||
coder.NumInStreams = 1;
|
||||
coder.NumOutStreams = 1;
|
||||
}
|
||||
@@ -251,8 +258,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
int propsSize = ReadNum();
|
||||
coder.Props = new byte[propsSize];
|
||||
ReadBytes(coder.Props, 0, propsSize);
|
||||
Log.WriteLine("Settings: " +
|
||||
String.Join("", coder.Props.Select(bt => bt.ToString("x2")).ToArray()));
|
||||
#if DEBUG
|
||||
Log.WriteLine("Settings: " + String.Join("", coder.Props.Select(bt => bt.ToString("x2")).ToArray()));
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((mainByte & 0x80) != 0)
|
||||
@@ -263,23 +271,31 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int numBindPairs = numOutStreams - 1;
|
||||
folder.BindPairs = new List<CBindPair>(numBindPairs);
|
||||
#if DEBUG
|
||||
Log.WriteLine("BindPairs: " + numBindPairs);
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
for (int i = 0; i < numBindPairs; i++)
|
||||
{
|
||||
CBindPair bp = new CBindPair();
|
||||
bp.InIndex = ReadNum();
|
||||
bp.OutIndex = ReadNum();
|
||||
folder.BindPairs.Add(bp);
|
||||
#if DEBUG
|
||||
Log.WriteLine("#" + i + " - In: " + bp.InIndex + " - Out: " + bp.OutIndex);
|
||||
#endif
|
||||
}
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
|
||||
if (numInStreams < numBindPairs)
|
||||
throw new NotSupportedException();
|
||||
@@ -292,7 +308,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
if (folder.FindBindPairForInStream(i) < 0)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("Single PackStream: #" + i);
|
||||
#endif
|
||||
folder.PackStreams.Add(i);
|
||||
break;
|
||||
}
|
||||
@@ -303,26 +321,36 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("Multiple PackStreams ...");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
for (int i = 0; i < numPackStreams; i++)
|
||||
{
|
||||
var num = ReadNum();
|
||||
#if DEBUG
|
||||
Log.WriteLine("#" + i + " - " + num);
|
||||
#endif
|
||||
folder.PackStreams.Add(num);
|
||||
}
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private List<uint?> ReadHashDigests(int count)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.Write("ReadHashDigests:");
|
||||
#endif
|
||||
|
||||
var defined = ReadOptionalBitVector(count);
|
||||
var digests = new List<uint?>(count);
|
||||
@@ -331,44 +359,62 @@ namespace SharpCompress.Common.SevenZip
|
||||
if (defined[i])
|
||||
{
|
||||
uint crc = ReadUInt32();
|
||||
#if DEBUG
|
||||
Log.Write(" " + crc.ToString("x8"));
|
||||
#endif
|
||||
digests.Add(crc);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
Log.Write(" ########");
|
||||
#endif
|
||||
digests.Add(null);
|
||||
}
|
||||
}
|
||||
#if DEBUG
|
||||
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
return digests;
|
||||
}
|
||||
|
||||
private void ReadPackInfo(out long dataOffset, out List<long> packSizes, out List<uint?> packCRCs)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadPackInfo --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
packCRCs = null;
|
||||
|
||||
dataOffset = checked((long)ReadNumber());
|
||||
#if DEBUG
|
||||
Log.WriteLine("DataOffset: " + dataOffset);
|
||||
#endif
|
||||
|
||||
int numPackStreams = ReadNum();
|
||||
#if DEBUG
|
||||
Log.WriteLine("NumPackStreams: " + numPackStreams);
|
||||
#endif
|
||||
|
||||
WaitAttribute(BlockType.Size);
|
||||
packSizes = new List<long>(numPackStreams);
|
||||
#if DEBUG
|
||||
Log.Write("Sizes:");
|
||||
#endif
|
||||
for (int i = 0; i < numPackStreams; i++)
|
||||
{
|
||||
var size = checked((long)ReadNumber());
|
||||
#if DEBUG
|
||||
Log.Write(" " + size);
|
||||
#endif
|
||||
packSizes.Add(size);
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
|
||||
BlockType? type;
|
||||
for (; ; )
|
||||
@@ -393,19 +439,25 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadUnpackInfo(List<byte[]> dataVector, out List<CFolder> folders)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadUnpackInfo --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
WaitAttribute(BlockType.Folder);
|
||||
int numFolders = ReadNum();
|
||||
#if DEBUG
|
||||
Log.WriteLine("NumFolders: {0}", numFolders);
|
||||
#endif
|
||||
|
||||
using (CStreamSwitch streamSwitch = new CStreamSwitch())
|
||||
{
|
||||
@@ -424,20 +476,27 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
|
||||
WaitAttribute(BlockType.CodersUnpackSize);
|
||||
|
||||
#if DEBUG
|
||||
Log.WriteLine("UnpackSizes:");
|
||||
#endif
|
||||
for (int i = 0; i < numFolders; i++)
|
||||
{
|
||||
CFolder folder = folders[i];
|
||||
#if DEBUG
|
||||
Log.Write(" #" + i + ":");
|
||||
#endif
|
||||
int numOutStreams = folder.GetNumOutStreams();
|
||||
for (int j = 0; j < numOutStreams; j++)
|
||||
{
|
||||
long size = checked((long)ReadNumber());
|
||||
#if DEBUG
|
||||
Log.Write(" " + size);
|
||||
#endif
|
||||
folder.UnpackSizes.Add(size);
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
}
|
||||
|
||||
for (; ; )
|
||||
@@ -459,15 +518,19 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadSubStreamsInfo(List<CFolder> folders, out List<int> numUnpackStreamsInFolders,
|
||||
out List<long> unpackSizes, out List<uint?> digests)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadSubStreamsInfo --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
numUnpackStreamsInFolders = null;
|
||||
@@ -479,14 +542,20 @@ namespace SharpCompress.Common.SevenZip
|
||||
if (type == BlockType.NumUnpackStream)
|
||||
{
|
||||
numUnpackStreamsInFolders = new List<int>(folders.Count);
|
||||
#if DEBUG
|
||||
Log.Write("NumUnpackStreams:");
|
||||
#endif
|
||||
for (int i = 0; i < folders.Count; i++)
|
||||
{
|
||||
var num = ReadNum();
|
||||
#if DEBUG
|
||||
Log.Write(" " + num);
|
||||
#endif
|
||||
numUnpackStreamsInFolders.Add(num);
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
if (type == BlockType.CRC || type == BlockType.Size)
|
||||
@@ -511,21 +580,26 @@ namespace SharpCompress.Common.SevenZip
|
||||
int numSubstreams = numUnpackStreamsInFolders[i];
|
||||
if (numSubstreams == 0)
|
||||
continue;
|
||||
|
||||
#if DEBUG
|
||||
Log.Write("#{0} StreamSizes:", i);
|
||||
#endif
|
||||
long sum = 0;
|
||||
for (int j = 1; j < numSubstreams; j++)
|
||||
{
|
||||
if (type == BlockType.Size)
|
||||
{
|
||||
long size = checked((long)ReadNumber());
|
||||
#if DEBUG
|
||||
Log.Write(" " + size);
|
||||
#endif
|
||||
unpackSizes.Add(size);
|
||||
sum += size;
|
||||
}
|
||||
}
|
||||
unpackSizes.Add(folders[i].GetUnpackSize() - sum);
|
||||
#if DEBUG
|
||||
Log.WriteLine(" - rest: " + unpackSizes.Last());
|
||||
#endif
|
||||
}
|
||||
if (type == BlockType.Size)
|
||||
type = ReadId();
|
||||
@@ -589,7 +663,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -603,8 +679,10 @@ namespace SharpCompress.Common.SevenZip
|
||||
out List<long> unpackSizes,
|
||||
out List<uint?> digests)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadStreamsInfo --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
dataOffset = long.MinValue;
|
||||
@@ -637,14 +715,18 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private List<byte[]> ReadAndDecodePackedStreams(long baseOffset, IPasswordProvider pass)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadAndDecodePackedStreams --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
long dataStartPos;
|
||||
@@ -697,14 +779,18 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadHeader(ArchiveDatabase db, IPasswordProvider getTextPassword)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadHeader --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
BlockType? type = ReadId();
|
||||
@@ -762,7 +848,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
throw new InvalidOperationException();
|
||||
|
||||
int numFiles = ReadNum();
|
||||
#if DEBUG
|
||||
Log.WriteLine("NumFiles: " + numFiles);
|
||||
#endif
|
||||
db.Files = new List<CFileItem>(numFiles);
|
||||
for (int i = 0; i < numFiles; i++)
|
||||
db.Files.Add(new CFileItem());
|
||||
@@ -786,112 +874,147 @@ namespace SharpCompress.Common.SevenZip
|
||||
using (var streamSwitch = new CStreamSwitch())
|
||||
{
|
||||
streamSwitch.Set(this, dataVector);
|
||||
#if DEBUG
|
||||
Log.Write("FileNames:");
|
||||
#endif
|
||||
for (int i = 0; i < db.Files.Count; i++)
|
||||
{
|
||||
db.Files[i].Name = _currentReader.ReadString();
|
||||
#if DEBUG
|
||||
Log.Write(" " + db.Files[i].Name);
|
||||
#endif
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case BlockType.WinAttributes:
|
||||
#if DEBUG
|
||||
Log.Write("WinAttributes:");
|
||||
#endif
|
||||
ReadAttributeVector(dataVector, numFiles, delegate(int i, uint? attr)
|
||||
{
|
||||
db.Files[i].Attrib = attr;
|
||||
Log.Write(" " +
|
||||
(attr.HasValue
|
||||
? attr.Value.ToString("x8")
|
||||
: "n/a"));
|
||||
#if DEBUG
|
||||
Log.Write(" " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a"));
|
||||
#endif
|
||||
});
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.EmptyStream:
|
||||
emptyStreamVector = ReadBitVector(numFiles);
|
||||
#if DEBUG
|
||||
|
||||
Log.Write("EmptyStream: ");
|
||||
#endif
|
||||
for (int i = 0; i < emptyStreamVector.Length; i++)
|
||||
{
|
||||
if (emptyStreamVector[i])
|
||||
{
|
||||
#if DEBUG
|
||||
Log.Write("x");
|
||||
#endif
|
||||
numEmptyStreams++;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
Log.Write(".");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
|
||||
emptyFileVector = new BitVector(numEmptyStreams);
|
||||
antiFileVector = new BitVector(numEmptyStreams);
|
||||
break;
|
||||
case BlockType.EmptyFile:
|
||||
emptyFileVector = ReadBitVector(numEmptyStreams);
|
||||
#if DEBUG
|
||||
Log.Write("EmptyFile: ");
|
||||
for (int i = 0; i < numEmptyStreams; i++)
|
||||
Log.Write(emptyFileVector[i] ? "x" : ".");
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.Anti:
|
||||
antiFileVector = ReadBitVector(numEmptyStreams);
|
||||
#if DEBUG
|
||||
Log.Write("Anti: ");
|
||||
for (int i = 0; i < numEmptyStreams; i++)
|
||||
Log.Write(antiFileVector[i] ? "x" : ".");
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.StartPos:
|
||||
#if DEBUG
|
||||
Log.Write("StartPos:");
|
||||
#endif
|
||||
ReadNumberVector(dataVector, numFiles, delegate(int i, long? startPos)
|
||||
{
|
||||
db.Files[i].StartPos = startPos;
|
||||
Log.Write(" " +
|
||||
(startPos.HasValue
|
||||
? startPos.Value.ToString()
|
||||
: "n/a"));
|
||||
#if DEBUG
|
||||
Log.Write(" " + (startPos.HasValue ? startPos.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
});
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.CTime:
|
||||
#if DEBUG
|
||||
Log.Write("CTime:");
|
||||
#endif
|
||||
ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time)
|
||||
{
|
||||
db.Files[i].CTime = time;
|
||||
Log.Write(" " +
|
||||
(time.HasValue
|
||||
? time.Value.ToString()
|
||||
: "n/a"));
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
});
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.ATime:
|
||||
#if DEBUG
|
||||
Log.Write("ATime:");
|
||||
#endif
|
||||
ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time)
|
||||
{
|
||||
db.Files[i].ATime = time;
|
||||
Log.Write(" " +
|
||||
(time.HasValue
|
||||
? time.Value.ToString()
|
||||
: "n/a"));
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
});
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.MTime:
|
||||
#if DEBUG
|
||||
Log.Write("MTime:");
|
||||
#endif
|
||||
ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time)
|
||||
{
|
||||
db.Files[i].MTime = time;
|
||||
Log.Write(" " +
|
||||
(time.HasValue
|
||||
? time.Value.ToString()
|
||||
: "n/a"));
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
});
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.Dummy:
|
||||
#if DEBUG
|
||||
Log.Write("Dummy: " + size);
|
||||
#endif
|
||||
for (long j = 0; j < size; j++)
|
||||
if (ReadByte() != 0)
|
||||
throw new InvalidOperationException();
|
||||
@@ -933,7 +1056,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1156,7 +1281,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
//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
|
||||
if (_db.Files[index].CrcDefined)
|
||||
_stream = new CrcCheckStream(_db.Files[index].Crc.Value);
|
||||
else
|
||||
|
||||
@@ -16,7 +16,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
if (_active)
|
||||
{
|
||||
_active = false;
|
||||
#if DEBUG
|
||||
Log.WriteLine("[end of switch]");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_needRemove)
|
||||
@@ -47,7 +49,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
if (dataIndex < 0 || dataIndex >= dataVector.Count)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
#if DEBUG
|
||||
Log.WriteLine("[switch to stream {0}]", dataIndex);
|
||||
#endif
|
||||
_archive = archive;
|
||||
_archive.AddByteStream(dataVector[dataIndex], 0, dataVector[dataIndex].Length);
|
||||
_needRemove = true;
|
||||
@@ -55,7 +59,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("[inline data]");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
throw new EndOfStreamException();
|
||||
|
||||
_offset += (int) size;
|
||||
#if DEBUG
|
||||
Log.WriteLine("SkipData {0}", size);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void SkipData()
|
||||
|
||||
@@ -72,6 +72,11 @@ namespace SharpCompress.Common.SevenZip
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override int? Attrib
|
||||
{
|
||||
get { return (int) FilePart.Header.Attrib; }
|
||||
}
|
||||
|
||||
internal override IEnumerable<FilePart> Parts
|
||||
{
|
||||
get { return FilePart.AsEnumerable<FilePart>(); }
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace SharpCompress.Common.Zip
|
||||
{
|
||||
internal class SeekableZipHeaderFactory : ZipHeaderFactory
|
||||
{
|
||||
private const int MAX_ITERATIONS_FOR_DIRECTORY_HEADER = 1000;
|
||||
private const int MAX_ITERATIONS_FOR_DIRECTORY_HEADER = 4096;
|
||||
|
||||
internal SeekableZipHeaderFactory(string password)
|
||||
: base(StreamingMode.Seekable, password)
|
||||
|
||||
@@ -45,18 +45,17 @@ namespace SharpCompress.Common.Zip
|
||||
lastEntryHeader = null;
|
||||
uint headerBytes = reader.ReadUInt32();
|
||||
header = ReadHeader(headerBytes, reader);
|
||||
|
||||
//entry could be zero bytes so we need to know that.
|
||||
if (header.ZipHeaderType == ZipHeaderType.LocalEntry)
|
||||
{
|
||||
bool isRecording = rewindableStream.IsRecording;
|
||||
if (!isRecording)
|
||||
{
|
||||
rewindableStream.StartRecording();
|
||||
if (header != null) {
|
||||
// entry could be zero bytes so we need to know that.
|
||||
if(header.ZipHeaderType == ZipHeaderType.LocalEntry) {
|
||||
bool isRecording = rewindableStream.IsRecording;
|
||||
if (!isRecording) {
|
||||
rewindableStream.StartRecording();
|
||||
}
|
||||
uint nextHeaderBytes = reader.ReadUInt32();
|
||||
header.HasData = !IsHeader(nextHeaderBytes);
|
||||
rewindableStream.Rewind(!isRecording);
|
||||
}
|
||||
uint nextHeaderBytes = reader.ReadUInt32();
|
||||
header.HasData = !IsHeader(nextHeaderBytes);
|
||||
rewindableStream.Rewind(!isRecording);
|
||||
}
|
||||
yield return header;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace SharpCompress.Common.Zip
|
||||
return entry;
|
||||
}
|
||||
default:
|
||||
throw new NotSupportedException("Unknown header: " + headerBytes);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -677,10 +677,10 @@ namespace SharpCompress.Compressor.Deflate
|
||||
{
|
||||
if (bi_valid > (int) Buf_size - len)
|
||||
{
|
||||
//int val = value;
|
||||
// bi_buf |= (val << bi_valid);
|
||||
int x = (value << bi_valid) & 0xffff;
|
||||
bi_buf = (short)((int)bi_buf | x);
|
||||
|
||||
bi_buf |= (short) ((value << bi_valid) & 0xffff);
|
||||
//put_short(bi_buf);
|
||||
pending[pendingCount++] = (byte) bi_buf;
|
||||
pending[pendingCount++] = (byte) (bi_buf >> 8);
|
||||
@@ -691,8 +691,10 @@ namespace SharpCompress.Compressor.Deflate
|
||||
}
|
||||
else
|
||||
{
|
||||
// bi_buf |= (value) << bi_valid;
|
||||
bi_buf |= (short) ((value << bi_valid) & 0xffff);
|
||||
// bi_buf |= (val << bi_valid);
|
||||
int x = (value << bi_valid) & 0xffff;
|
||||
bi_buf = (short)((int)bi_buf | x);
|
||||
|
||||
bi_valid += len;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,33 +79,5 @@ namespace SharpCompress.Compressor.LZMA
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
public static unsafe uint Update(uint crc, byte* buffer, int length)
|
||||
{
|
||||
while (length > 0 && ((int) buffer & 3) != 0)
|
||||
{
|
||||
crc = Update(crc, *buffer);
|
||||
buffer++;
|
||||
length--;
|
||||
}
|
||||
|
||||
while (length >= 4)
|
||||
{
|
||||
crc = Update(crc, *(uint*) buffer);
|
||||
buffer += 4;
|
||||
length -= 4;
|
||||
}
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
crc = Update(crc, *buffer);
|
||||
length--;
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -321,6 +321,7 @@
|
||||
<Compile Include="Writer\Tar\TarWriter.cs" />
|
||||
<Compile Include="Writer\WriterFactory.cs" />
|
||||
<Compile Include="Writer\Zip\ZipCentralDirectoryEntry.cs" />
|
||||
<Compile Include="Writer\Zip\ZipCompressionInfo.cs" />
|
||||
<Compile Include="Writer\Zip\ZipWriter.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -371,6 +371,7 @@
|
||||
<Compile Include="Writer\Tar\TarWriter.cs" />
|
||||
<Compile Include="Writer\WriterFactory.cs" />
|
||||
<Compile Include="Writer\Zip\ZipCentralDirectoryEntry.cs" />
|
||||
<Compile Include="Writer\Zip\ZipCompressionInfo.cs" />
|
||||
<Compile Include="Writer\Zip\ZipWriter.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -359,6 +359,7 @@
|
||||
<Compile Include="Writer\Tar\TarWriter.cs" />
|
||||
<Compile Include="Writer\WriterFactory.cs" />
|
||||
<Compile Include="Writer\Zip\ZipCentralDirectoryEntry.cs" />
|
||||
<Compile Include="Writer\Zip\ZipCompressionInfo.cs" />
|
||||
<Compile Include="Writer\Zip\ZipWriter.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -306,6 +306,7 @@
|
||||
<Compile Include="Writer\Tar\TarWriter.cs" />
|
||||
<Compile Include="Writer\WriterFactory.cs" />
|
||||
<Compile Include="Writer\Zip\ZipCentralDirectoryEntry.cs" />
|
||||
<Compile Include="Writer\Zip\ZipCompressionInfo.cs" />
|
||||
<Compile Include="Writer\Zip\ZipWriter.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -359,6 +359,7 @@
|
||||
<Compile Include="Writer\Tar\TarWriter.cs" />
|
||||
<Compile Include="Writer\WriterFactory.cs" />
|
||||
<Compile Include="Writer\Zip\ZipCentralDirectoryEntry.cs" />
|
||||
<Compile Include="Writer\Zip\ZipCompressionInfo.cs" />
|
||||
<Compile Include="Writer\Zip\ZipWriter.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -199,21 +199,15 @@ namespace SharpCompress
|
||||
/// </param>
|
||||
/// <param name="value">the value to write
|
||||
/// </param>
|
||||
#if PORTABLE || NETFX_CORE
|
||||
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);
|
||||
}
|
||||
#else
|
||||
public static unsafe void WriteLittleEndian(byte[] array, int pos, short value)
|
||||
{
|
||||
fixed (byte* numRef = &(array[pos]))
|
||||
{
|
||||
*((short*)numRef) = value;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary> Increment a short value at the specified position by the specified amount
|
||||
/// (little endian).
|
||||
@@ -241,21 +235,15 @@ namespace SharpCompress
|
||||
/// </param>
|
||||
/// <param name="value">the value to write
|
||||
/// </param>
|
||||
#if PORTABLE || NETFX_CORE
|
||||
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);
|
||||
}
|
||||
#else
|
||||
public static unsafe void WriteLittleEndian(byte[] array, int pos, int value)
|
||||
{
|
||||
fixed (byte* numRef = &(array[pos]))
|
||||
{
|
||||
*((int*)numRef) = value;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public static void Initialize<T>(this T[] array, Func<T> func)
|
||||
{
|
||||
|
||||
@@ -11,5 +11,5 @@ using System.Runtime.InteropServices;
|
||||
[assembly: AssemblyCopyright("Copyright © Adam Hathcock")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: AssemblyVersion("0.10.3.0")]
|
||||
[assembly: AssemblyFileVersion("0.10.3.0")]
|
||||
[assembly: AssemblyVersion("0.11.2.0")]
|
||||
[assembly: AssemblyFileVersion("0.11.2.0")]
|
||||
47
SharpCompress/Writer/Zip/ZipCompressionInfo.cs
Normal file
47
SharpCompress/Writer/Zip/ZipCompressionInfo.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Zip;
|
||||
using SharpCompress.Compressor.Deflate;
|
||||
|
||||
namespace SharpCompress.Writer.Zip
|
||||
{
|
||||
internal class ZipCompressionInfo
|
||||
{
|
||||
internal CompressionLevel DeflateCompressionLevel { get; private set; }
|
||||
internal ZipCompressionMethod Compression { get; private set; }
|
||||
|
||||
public ZipCompressionInfo(CompressionInfo compressionInfo)
|
||||
{
|
||||
switch (compressionInfo.Type)
|
||||
{
|
||||
case CompressionType.None:
|
||||
{
|
||||
this.Compression = ZipCompressionMethod.None;
|
||||
}
|
||||
break;
|
||||
case CompressionType.Deflate:
|
||||
{
|
||||
this.DeflateCompressionLevel = compressionInfo.DeflateCompressionLevel;
|
||||
this.Compression = ZipCompressionMethod.Deflate;
|
||||
}
|
||||
break;
|
||||
case CompressionType.BZip2:
|
||||
{
|
||||
this.Compression = ZipCompressionMethod.BZip2;
|
||||
}
|
||||
break;
|
||||
case CompressionType.LZMA:
|
||||
{
|
||||
this.Compression = ZipCompressionMethod.LZMA;
|
||||
}
|
||||
break;
|
||||
case CompressionType.PPMd:
|
||||
{
|
||||
this.Compression = ZipCompressionMethod.PPMd;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new InvalidFormatException("Invalid compression method: " + compressionInfo.Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,52 +17,18 @@ namespace SharpCompress.Writer.Zip
|
||||
{
|
||||
public class ZipWriter : AbstractWriter
|
||||
{
|
||||
private readonly ZipCompressionMethod compression;
|
||||
private readonly CompressionLevel deflateCompressionLevel;
|
||||
|
||||
private readonly ZipCompressionInfo zipCompressionInfo;
|
||||
private readonly PpmdProperties ppmdProperties = new PpmdProperties(); // Caching properties to speed up PPMd
|
||||
private readonly List<ZipCentralDirectoryEntry> entries = new List<ZipCentralDirectoryEntry>();
|
||||
private readonly string zipComment;
|
||||
private long streamPosition;
|
||||
|
||||
private readonly PpmdProperties ppmdProperties; // Caching properties to speed up PPMd.
|
||||
|
||||
public ZipWriter(Stream destination, CompressionInfo compressionInfo, string zipComment)
|
||||
: base(ArchiveType.Zip)
|
||||
{
|
||||
this.zipComment = zipComment ?? string.Empty;
|
||||
|
||||
switch (compressionInfo.Type)
|
||||
{
|
||||
case CompressionType.None:
|
||||
{
|
||||
compression = ZipCompressionMethod.None;
|
||||
}
|
||||
break;
|
||||
case CompressionType.Deflate:
|
||||
{
|
||||
compression = ZipCompressionMethod.Deflate;
|
||||
deflateCompressionLevel = compressionInfo.DeflateCompressionLevel;
|
||||
}
|
||||
break;
|
||||
case CompressionType.BZip2:
|
||||
{
|
||||
compression = ZipCompressionMethod.BZip2;
|
||||
}
|
||||
break;
|
||||
case CompressionType.LZMA:
|
||||
{
|
||||
compression = ZipCompressionMethod.LZMA;
|
||||
}
|
||||
break;
|
||||
case CompressionType.PPMd:
|
||||
{
|
||||
ppmdProperties = new PpmdProperties();
|
||||
compression = ZipCompressionMethod.PPMd;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new InvalidFormatException("Invalid compression method: " + compressionInfo.Type);
|
||||
}
|
||||
this.zipCompressionInfo = new ZipCompressionInfo(compressionInfo);
|
||||
InitalizeStream(destination, false);
|
||||
}
|
||||
|
||||
@@ -73,7 +39,7 @@ namespace SharpCompress.Writer.Zip
|
||||
uint size = 0;
|
||||
foreach (ZipCentralDirectoryEntry entry in entries)
|
||||
{
|
||||
size += entry.Write(OutputStream, compression);
|
||||
size += entry.Write(OutputStream, zipCompressionInfo.Compression);
|
||||
}
|
||||
WriteEndRecord(size);
|
||||
}
|
||||
@@ -85,15 +51,15 @@ namespace SharpCompress.Writer.Zip
|
||||
Write(entryPath, source, modificationTime, null);
|
||||
}
|
||||
|
||||
public void Write(string entryPath, Stream source, DateTime? modificationTime, string comment)
|
||||
public void Write(string entryPath, Stream source, DateTime? modificationTime, string comment, CompressionInfo compressionInfo = null)
|
||||
{
|
||||
using (Stream output = WriteToStream(entryPath, modificationTime, comment))
|
||||
using (Stream output = WriteToStream(entryPath, modificationTime, comment, compressionInfo))
|
||||
{
|
||||
source.TransferTo(output);
|
||||
}
|
||||
}
|
||||
|
||||
public Stream WriteToStream(string entryPath, DateTime? modificationTime, string comment)
|
||||
public Stream WriteToStream(string entryPath, DateTime? modificationTime, string comment, CompressionInfo compressionInfo = null)
|
||||
{
|
||||
entryPath = NormalizeFilename(entryPath);
|
||||
modificationTime = modificationTime ?? DateTime.Now;
|
||||
@@ -105,7 +71,8 @@ namespace SharpCompress.Writer.Zip
|
||||
ModificationTime = modificationTime,
|
||||
HeaderOffset = (uint) streamPosition,
|
||||
};
|
||||
var headersize = (uint) WriteHeader(entryPath, modificationTime);
|
||||
|
||||
var headersize = (uint)WriteHeader(entryPath, modificationTime, compressionInfo);
|
||||
streamPosition += headersize;
|
||||
return new ZipWritingStream(this, OutputStream, entry);
|
||||
}
|
||||
@@ -121,23 +88,31 @@ namespace SharpCompress.Writer.Zip
|
||||
return filename.Trim('/');
|
||||
}
|
||||
|
||||
private int WriteHeader(string filename, DateTime? modificationTime)
|
||||
private int WriteHeader(string filename, DateTime? modificationTime, CompressionInfo compressionInfo = null)
|
||||
{
|
||||
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(new byte[] {63, 0}, 0, 2); //version
|
||||
if (explicitZipCompressionInfo.Compression == ZipCompressionMethod.Deflate)
|
||||
{
|
||||
OutputStream.Write(new byte[] {20, 0}, 0, 2); //older version which is more compatible
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputStream.Write(new byte[] {63, 0}, 0, 2); //version says we used PPMd or LZMA
|
||||
}
|
||||
HeaderFlags flags = ArchiveEncoding.Default == Encoding.UTF8 ? HeaderFlags.UTF8 : (HeaderFlags)0;
|
||||
if (!OutputStream.CanSeek)
|
||||
{
|
||||
flags |= HeaderFlags.UsePostDataDescriptor;
|
||||
if (compression == ZipCompressionMethod.LZMA)
|
||||
if (explicitZipCompressionInfo.Compression == ZipCompressionMethod.LZMA)
|
||||
{
|
||||
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((ushort)explicitZipCompressionInfo.Compression), 0, 2); // zipping method
|
||||
OutputStream.Write(BitConverter.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);
|
||||
@@ -220,7 +195,7 @@ namespace SharpCompress.Writer.Zip
|
||||
{
|
||||
counting = new CountingWritableSubStream(writeStream);
|
||||
Stream output = counting;
|
||||
switch (writer.compression)
|
||||
switch (writer.zipCompressionInfo.Compression)
|
||||
{
|
||||
case ZipCompressionMethod.None:
|
||||
{
|
||||
@@ -228,7 +203,7 @@ namespace SharpCompress.Writer.Zip
|
||||
}
|
||||
case ZipCompressionMethod.Deflate:
|
||||
{
|
||||
return new DeflateStream(counting, CompressionMode.Compress, writer.deflateCompressionLevel,
|
||||
return new DeflateStream(counting, CompressionMode.Compress, writer.zipCompressionInfo.DeflateCompressionLevel,
|
||||
true);
|
||||
}
|
||||
case ZipCompressionMethod.BZip2:
|
||||
@@ -254,7 +229,7 @@ namespace SharpCompress.Writer.Zip
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new NotSupportedException("CompressionMethod: " + writer.compression);
|
||||
throw new NotSupportedException("CompressionMethod: " + writer.zipCompressionInfo.Compression);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,5 +128,7 @@
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/VBNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/VBNaming/PredefinedNamingRules/=TypeParameters/@EntryIndexedValue"><Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/VBNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002EJavaScript_002ECodeStyle_002ESettingsUpgrade_002EJsCodeFormatterSettingsUpgrader/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
Reference in New Issue
Block a user