mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-06 05:27:05 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84704e5ce2 | ||
|
|
059fe1f545 | ||
|
|
fe8c6aec5f | ||
|
|
3ab38fbfc2 | ||
|
|
b4bfde77d2 |
@@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>sharpcompress</id>
|
||||
<version>0.10.1.3</version>
|
||||
<version>0.10.3</version>
|
||||
<title>SharpCompress - Pure C# Decompression/Compression</title>
|
||||
<authors>Adam Hathcock</authors>
|
||||
<owners>Adam Hathcock</owners>
|
||||
@@ -12,11 +12,11 @@
|
||||
<description>SharpCompress is a compression library for .NET/Mono/Silverlight/WP7/WindowsStore that can unrar, decompress 7zip, zip/unzip, tar/untar bzip2/unbzip2 and gzip/ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip is implemented.</description>
|
||||
<releaseNotes />
|
||||
<language>en-US</language>
|
||||
<tags>rar unrar zip unzip bzip2 gzip tar 7zip .net40 .net35 sl4</tags>
|
||||
<tags>rar unrar zip unzip bzip2 gzip tar 7zip</tags>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\bin\Full\SharpCompress.dll" target="lib\net40\SharpCompress.dll" />
|
||||
<file src="..\bin\WindowsStore\SharpCompress.dll" target="lib\netcore45\SharpCompress.dll" />
|
||||
<file src="..\bin\Portable\SharpCompress.dll" target="lib\portable-net4+sl4+wp7+win8\SharpCompress.dll" />
|
||||
<file src="..\bin\Portable\SharpCompress.dll" target="lib\portable-net4+sl5+wp8+win8\SharpCompress.dll" />
|
||||
</files>
|
||||
</package>
|
||||
12
README.md
12
README.md
@@ -21,6 +21,18 @@ TODOs (always lots):
|
||||
* Zip64
|
||||
* Multi-volume Zip support.
|
||||
|
||||
Version 0.10.3:
|
||||
==============
|
||||
- Finally fixed Disposal issue when creating a new archive with the Archive API
|
||||
|
||||
Version 0.10.2:
|
||||
==============
|
||||
- Fixed Rar Header reading for invalid extended time headers.
|
||||
- Windows Store assembly is now strong named
|
||||
- Known issues with Long Tar names being worked on
|
||||
- Updated to VS2013
|
||||
- Portable targets SL5 and Windows Phone 8 (up from SL4 and WP7)
|
||||
|
||||
Version 0.10.1:
|
||||
==============
|
||||
- Fixed 7Zip extraction performance problem
|
||||
|
||||
@@ -54,22 +54,6 @@ namespace SharpCompress.Test
|
||||
}
|
||||
CompareArchivesByPath(unmodified, scratchPath);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Tar_Create_New_Long_FileName()
|
||||
{
|
||||
string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename.tar");
|
||||
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar");
|
||||
|
||||
base.ResetScratch();
|
||||
using (var archive = TarArchive.Create())
|
||||
{
|
||||
archive.AddAllFromDirectory(ORIGINAL_FILES_PATH);
|
||||
archive.SaveTo(scratchPath, CompressionType.None);
|
||||
}
|
||||
CompareArchivesByPath(unmodified, scratchPath);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Tar_Random_Write_Add()
|
||||
{
|
||||
@@ -87,23 +71,6 @@ namespace SharpCompress.Test
|
||||
CompareArchivesByPath(modified, scratchPath);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Tar_Random_Write_Add_Long_name()
|
||||
{
|
||||
string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg\\test.jpg");
|
||||
string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.mod.tar");
|
||||
|
||||
base.ResetScratch();
|
||||
using (var archive = TarArchive.Create())
|
||||
{
|
||||
archive.AddEntry(@"very long filename/very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename.jpg", jpg);
|
||||
archive.SaveTo(scratchPath, CompressionType.None);
|
||||
}
|
||||
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "very long filename.tar");
|
||||
|
||||
|
||||
CompareArchivesByPath(unmodified, scratchPath);
|
||||
}
|
||||
[TestMethod]
|
||||
public void Tar_Random_Write_Remove()
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
@@ -184,16 +185,32 @@ namespace SharpCompress.Test
|
||||
[TestMethod]
|
||||
public void Zip_Create_New()
|
||||
{
|
||||
string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.noEmptyDirs.zip");
|
||||
base.ResetScratch();
|
||||
foreach (var file in Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories))
|
||||
{
|
||||
var newFileName = file.Substring(ORIGINAL_FILES_PATH.Length);
|
||||
if (newFileName.StartsWith(Path.DirectorySeparatorChar.ToString()))
|
||||
{
|
||||
newFileName = newFileName.Substring(1);
|
||||
}
|
||||
newFileName = Path.Combine(SCRATCH_FILES_PATH, newFileName);
|
||||
var newDir = Path.GetDirectoryName(newFileName);
|
||||
if (!Directory.Exists(newDir))
|
||||
{
|
||||
Directory.CreateDirectory(newDir);
|
||||
}
|
||||
File.Copy(file, newFileName);
|
||||
}
|
||||
string scratchPath = Path.Combine(SCRATCH2_FILES_PATH, "Zip.deflate.noEmptyDirs.zip");
|
||||
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip");
|
||||
|
||||
base.ResetScratch();
|
||||
using (var archive = ZipArchive.Create())
|
||||
{
|
||||
archive.AddAllFromDirectory(ORIGINAL_FILES_PATH);
|
||||
archive.AddAllFromDirectory(SCRATCH_FILES_PATH);
|
||||
archive.SaveTo(scratchPath, CompressionType.Deflate);
|
||||
}
|
||||
CompareArchivesByPath(unmodified, scratchPath);
|
||||
Directory.Delete(SCRATCH_FILES_PATH, true);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace SharpCompress.Archive
|
||||
|
||||
private bool disposed;
|
||||
|
||||
public void Dispose()
|
||||
public virtual void Dispose()
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
|
||||
@@ -117,5 +117,13 @@ namespace SharpCompress.Archive
|
||||
|
||||
protected abstract void SaveTo(Stream stream, CompressionInfo compressionType,
|
||||
IEnumerable<TEntry> oldEntries, IEnumerable<TEntry> newEntries);
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
newEntries.Cast<Entry>().ForEach(x => x.Close());
|
||||
removedEntries.Cast<Entry>().ForEach(x => x.Close());
|
||||
modifiedEntries.Cast<Entry>().ForEach(x => x.Close());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,7 +100,7 @@ namespace SharpCompress.Archive.Tar
|
||||
{
|
||||
try
|
||||
{
|
||||
TarHeader tar = new TarHeader(EntryType.File);
|
||||
TarHeader tar = new TarHeader();
|
||||
tar.Read(new BinaryReader(stream));
|
||||
return tar.Name.Length > 0 && Enum.IsDefined(typeof (EntryType), tar.EntryType);
|
||||
}
|
||||
|
||||
@@ -8,16 +8,17 @@ namespace SharpCompress.Archive.Zip
|
||||
{
|
||||
internal class ZipWritableArchiveEntry : ZipArchiveEntry
|
||||
{
|
||||
private string path;
|
||||
private long size;
|
||||
private DateTime? lastModified;
|
||||
private bool closeStream;
|
||||
private readonly string path;
|
||||
private readonly long size;
|
||||
private readonly DateTime? lastModified;
|
||||
private readonly bool closeStream;
|
||||
private bool isDisposed;
|
||||
|
||||
internal ZipWritableArchiveEntry(ZipArchive archive, Stream stream, string path, long size,
|
||||
DateTime? lastModified, bool closeStream)
|
||||
: base(archive, null)
|
||||
{
|
||||
this.Stream = stream;
|
||||
Stream = stream;
|
||||
this.path = path;
|
||||
this.size = size;
|
||||
this.lastModified = lastModified;
|
||||
@@ -93,9 +94,10 @@ namespace SharpCompress.Archive.Zip
|
||||
|
||||
internal override void Close()
|
||||
{
|
||||
if (closeStream)
|
||||
if (closeStream && !isDisposed)
|
||||
{
|
||||
Stream.Dispose();
|
||||
isDisposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
|
||||
namespace SharpCompress.Common
|
||||
{
|
||||
public abstract class Entry : SharpCompress.Common.IEntry
|
||||
public abstract class Entry : IEntry
|
||||
{
|
||||
internal bool IsSolid { get; set; }
|
||||
|
||||
|
||||
@@ -27,11 +27,6 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
{
|
||||
internal static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0);
|
||||
|
||||
internal TarHeader(EntryType entryType)
|
||||
{
|
||||
EntryType = entryType;
|
||||
}
|
||||
|
||||
internal string Name { get; set; }
|
||||
//internal int Mode { get; set; }
|
||||
//internal int UserId { get; set; }
|
||||
@@ -42,10 +37,7 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
internal DateTime LastModifiedTime { get; set; }
|
||||
internal EntryType EntryType { get; set; }
|
||||
internal Stream PackedStream { get; set; }
|
||||
internal static bool IsPathSeparator(char ch)
|
||||
{
|
||||
return (ch == '\\' || ch == '/' || ch == '|'); // All the path separators I ever met.
|
||||
}
|
||||
|
||||
internal void Write(Stream output)
|
||||
{
|
||||
if (Name.Length > 255)
|
||||
@@ -54,29 +46,12 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
}
|
||||
byte[] buffer = new byte[512];
|
||||
string name = Name;
|
||||
string namePrefix = null;
|
||||
if (name.Length > 100)
|
||||
{
|
||||
int position = Name.Length - 100;
|
||||
|
||||
// Find first path separator in the remaining 100 chars of the file name
|
||||
while (!IsPathSeparator(Name[position]))
|
||||
{
|
||||
++position;
|
||||
if (position == Name.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (position == Name.Length)
|
||||
{
|
||||
position = Name.Length - 100;
|
||||
}
|
||||
namePrefix = Name.Substring(0, position);
|
||||
name = Name.Substring(position, Name.Length - position);
|
||||
name = Name.Substring(0, 100);
|
||||
}
|
||||
WriteStringBytes(name, buffer, 0, 100);
|
||||
|
||||
Encoding.ASCII.GetBytes(name.PadRight(100, '\0')).CopyTo(buffer, 0);
|
||||
WriteOctalBytes(511, buffer, 100, 8);
|
||||
WriteOctalBytes(0, buffer, 108, 8);
|
||||
WriteOctalBytes(0, buffer, 116, 8);
|
||||
@@ -84,16 +59,13 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
var time = (long) (LastModifiedTime - Epoch).TotalSeconds;
|
||||
WriteOctalBytes(time, buffer, 136, 12);
|
||||
|
||||
buffer[156] = (byte) EntryType;
|
||||
|
||||
if (namePrefix != null)
|
||||
//Encoding.UTF8.GetBytes("magic").CopyTo(buffer, 257);
|
||||
if (Name.Length > 100)
|
||||
{
|
||||
Encoding.ASCII.GetBytes(namePrefix).CopyTo(buffer, 347);
|
||||
Encoding.ASCII.GetBytes("ustar").CopyTo(buffer, 0x101);
|
||||
Encoding.ASCII.GetBytes(" ").CopyTo(buffer, 0x106);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[156] = (byte)EntryType;
|
||||
name = Name.Substring(101, Name.Length);
|
||||
ArchiveEncoding.Default.GetBytes(name).CopyTo(buffer, 345);
|
||||
}
|
||||
if (Size >= 0x1FFFFFFFF)
|
||||
{
|
||||
@@ -123,7 +95,7 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
Name = Encoding.ASCII.GetString(buffer, 0, 100).TrimNulls();
|
||||
Name = ArchiveEncoding.Default.GetString(buffer, 0, 100).TrimNulls();
|
||||
|
||||
//Mode = ReadASCIIInt32Base8(buffer, 100, 7);
|
||||
//UserId = ReadASCIIInt32Base8(buffer, 108, 7);
|
||||
@@ -146,20 +118,39 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
LastModifiedTime = Epoch.AddSeconds(unixTimeStamp);
|
||||
|
||||
|
||||
Magic = Encoding.ASCII.GetString(buffer, 257, 5).TrimNulls();
|
||||
Magic = ArchiveEncoding.Default.GetString(buffer, 257, 6).TrimNulls();
|
||||
|
||||
if (!string.IsNullOrEmpty(Magic) && "ustar".Equals(Magic))
|
||||
if (!string.IsNullOrEmpty(Magic) && "ustar ".Equals(Magic))
|
||||
{
|
||||
string namePrefix = ArchiveEncoding.Default.GetString(buffer, 345, 157);
|
||||
namePrefix = namePrefix.TrimNulls();
|
||||
if (!string.IsNullOrEmpty(namePrefix))
|
||||
{
|
||||
Name = namePrefix + Name;
|
||||
Name = namePrefix + "/" + Name;
|
||||
}
|
||||
}
|
||||
if (EntryType != EntryType.LongName && Name.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private static void WriteStringBytes(string name, byte[] buffer, int offset, int length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < length - 1 && i < name.Length; ++i)
|
||||
{
|
||||
buffer[offset + i] = (byte) name[i];
|
||||
}
|
||||
|
||||
for (; i < length; ++i)
|
||||
{
|
||||
buffer[offset + i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteOctalBytes(long value, byte[] buffer, int offset, int length)
|
||||
{
|
||||
string val = Convert.ToString(value, 8);
|
||||
@@ -175,6 +166,16 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
buffer[offset + length] = 0;
|
||||
}
|
||||
|
||||
private static int ReadASCIIInt32Base8(byte[] buffer, int offset, int count)
|
||||
{
|
||||
string s = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls();
|
||||
if (string.IsNullOrEmpty(s))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return Convert.ToInt32(s, 8);
|
||||
}
|
||||
|
||||
private static long ReadASCIIInt64Base8(byte[] buffer, int offset, int count)
|
||||
{
|
||||
string s = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls();
|
||||
@@ -185,6 +186,16 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
return Convert.ToInt64(s, 8);
|
||||
}
|
||||
|
||||
private static long ReadASCIIInt64(byte[] buffer, int offset, int count)
|
||||
{
|
||||
string s = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls();
|
||||
if (string.IsNullOrEmpty(s))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return Convert.ToInt64(s);
|
||||
}
|
||||
|
||||
internal static int RecalculateChecksum(byte[] buf)
|
||||
{
|
||||
// Set default value for checksum. That is 8 spaces.
|
||||
|
||||
@@ -85,34 +85,17 @@ namespace SharpCompress.Common.Tar
|
||||
internal static IEnumerable<TarEntry> GetEntries(StreamingMode mode, Stream stream,
|
||||
CompressionType compressionType)
|
||||
{
|
||||
string nextHeaderName = null;
|
||||
foreach (TarHeader h in TarHeaderFactory.ReadHeader(mode, stream))
|
||||
{
|
||||
if (h != null)
|
||||
{
|
||||
if (h.EntryType == EntryType.LongName)
|
||||
if (mode == StreamingMode.Seekable)
|
||||
{
|
||||
var memoryStream = new MemoryStream();
|
||||
h.PackedStream.CopyTo(memoryStream);
|
||||
memoryStream.Position = 0;
|
||||
var bytes = memoryStream.ToArray();
|
||||
nextHeaderName = ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length).TrimNulls();
|
||||
yield return new TarEntry(new TarFilePart(h, stream), compressionType);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nextHeaderName != null)
|
||||
{
|
||||
h.Name = nextHeaderName;
|
||||
nextHeaderName = null;
|
||||
}
|
||||
if (mode == StreamingMode.Seekable)
|
||||
{
|
||||
yield return new TarEntry(new TarFilePart(h, stream), compressionType);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new TarEntry(new TarFilePart(h, null), compressionType);
|
||||
}
|
||||
yield return new TarEntry(new TarFilePart(h, null), compressionType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace SharpCompress.Common.Tar
|
||||
try
|
||||
{
|
||||
BinaryReader reader = new BinaryReader(stream);
|
||||
header = new TarHeader(EntryType.File);
|
||||
header = new TarHeader();
|
||||
if (!header.Read(reader))
|
||||
{
|
||||
yield break;
|
||||
|
||||
@@ -21,14 +21,12 @@ namespace SharpCompress.IO
|
||||
|
||||
public override int Read()
|
||||
{
|
||||
CurrentReadByteCount += 4;
|
||||
return base.Read();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int index, int count)
|
||||
{
|
||||
CurrentReadByteCount += count;
|
||||
return base.Read(buffer, index, count);
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override int Read(char[] buffer, int index, int count)
|
||||
@@ -38,8 +36,7 @@ namespace SharpCompress.IO
|
||||
|
||||
public override bool ReadBoolean()
|
||||
{
|
||||
CurrentReadByteCount++;
|
||||
return base.ReadBoolean();
|
||||
return BitConverter.ToBoolean(ReadBytes(1), 0);
|
||||
}
|
||||
|
||||
public override byte ReadByte()
|
||||
@@ -50,7 +47,12 @@ namespace SharpCompress.IO
|
||||
public override byte[] ReadBytes(int count)
|
||||
{
|
||||
CurrentReadByteCount += count;
|
||||
return base.ReadBytes(count);
|
||||
var bytes = base.ReadBytes(count);
|
||||
if (bytes.Length != count)
|
||||
{
|
||||
throw new EndOfStreamException(string.Format("Could not read the requested amount of bytes. End of stream reached. Requested: {0} Read: {1}", count, bytes.Length));
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public override char ReadChar()
|
||||
|
||||
@@ -11,5 +11,5 @@ using System.Runtime.InteropServices;
|
||||
[assembly: AssemblyCopyright("Copyright © Adam Hathcock")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: AssemblyVersion("0.10.1.3")]
|
||||
[assembly: AssemblyFileVersion("0.10.1.3")]
|
||||
[assembly: AssemblyVersion("0.10.3.0")]
|
||||
[assembly: AssemblyFileVersion("0.10.3.0")]
|
||||
@@ -65,7 +65,7 @@ namespace SharpCompress.Writer.Tar
|
||||
long realSize = size ?? source.Length;
|
||||
|
||||
|
||||
TarHeader header = new TarHeader(EntryType.File);
|
||||
TarHeader header = new TarHeader();
|
||||
header.LastModifiedTime = modificationTime ?? TarHeader.Epoch;
|
||||
header.Name = NormalizeFilename(filename);
|
||||
header.Size = realSize;
|
||||
|
||||
Reference in New Issue
Block a user