Skip to content
This repository has been archived by the owner on Apr 9, 2024. It is now read-only.

Solid archives #164

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions SevenZip.Tests/SevenZip.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,16 @@
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NUnit.ConsoleRunner" Version="3.10.0" />
<PackageReference Include="OpenCover" Version="4.7.922" />
<PackageReference Include="NUnit.ConsoleRunner" Version="3.15.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="OpenCover" Version="4.7.1221" />
<PackageReference Include="System.Data.DataSetExtensions" Version="4.*" />
<PackageReference Include="Microsoft.CSharp" Version="4.*" />
<PackageReference Include="System.Net.Http" Version="4.*" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="coveralls.io" Version="1.4.2" />
<PackageReference Include="NUnit" Version="3.10.1" />
<PackageReference Include="NUnit" Version="3.13.3" />
</ItemGroup>
<ItemGroup>
<None Include="SevenZipTests.snk" />
Expand Down Expand Up @@ -75,6 +76,24 @@
<None Include="TestData_LongerDirectoryName\emptyfile.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="TestData_solid\testFiles.zip">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="TestData_solid\testFiles.7z">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="TestData_solid\testFiles.rar">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="TestData_solid\testFiles.solid.7z">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="TestData_solid\testFiles.solid.rar">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="TestData_solid\testFiles.tar">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SevenZip\SevenZip.csproj" />
Expand Down
142 changes: 130 additions & 12 deletions SevenZip.Tests/SevenZipExtractorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ public static List<TestFile> TestFiles
return result;
}
}
/// <summary>
/// TestCaseSource for ReadSolidArchive test
/// </summary>
public static List<TestFile> SolidArchivesFiles
{
get
{
var result = new List<TestFile>();
foreach (var file in Directory.GetFiles(Path.Combine(TestContext.CurrentContext.TestDirectory, "TestData_solid")))
{
result.Add(new TestFile(file));
}

return result;
}
}

[Test]
public void ExtractFilesTest()
Expand Down Expand Up @@ -85,7 +101,7 @@ public void ExtractionWithCancellationTest()
e.Cancel = true;
}
};

tmp.ExtractArchive(OutputDirectory);

Assert.AreEqual(2, Directory.GetFiles(OutputDirectory).Length);
Expand Down Expand Up @@ -160,10 +176,10 @@ public void DetectMultiVolumeIndexTest()
[Test]
public void ThreadedExtractionTest()
{
var destination1 = Path.Combine(OutputDirectory, "t1");
var destination2 = Path.Combine(OutputDirectory, "t2");
var destination1 = Path.Combine(OutputDirectory, "t1");
var destination2 = Path.Combine(OutputDirectory, "t2");

var t1 = new Thread(() =>
var t1 = new Thread(() =>
{
using (var tmp = new SevenZipExtractor(@"TestData\multiple_files.7z"))
{
Expand All @@ -172,8 +188,8 @@ public void ThreadedExtractionTest()
});
var t2 = new Thread(() =>
{
using (var tmp = new SevenZipExtractor(@"TestData\multiple_files.7z"))
{
using (var tmp = new SevenZipExtractor(@"TestData\multiple_files.7z"))
{
tmp.ExtractArchive(destination2);
}
});
Expand All @@ -183,11 +199,11 @@ public void ThreadedExtractionTest()
t1.Join();
t2.Join();

Assert.IsTrue(Directory.Exists(destination1));
Assert.IsTrue(Directory.Exists(destination2));
Assert.AreEqual(3, Directory.GetFiles(destination1).Length);
Assert.AreEqual(3, Directory.GetFiles(destination2).Length);
}
Assert.IsTrue(Directory.Exists(destination1));
Assert.IsTrue(Directory.Exists(destination2));
Assert.AreEqual(3, Directory.GetFiles(destination1).Length);
Assert.AreEqual(3, Directory.GetFiles(destination2).Length);
}

[Test]
public void ExtractArchiveWithLongPath()
Expand All @@ -211,7 +227,7 @@ public void ReadArchivedFileNames()
Assert.AreEqual("file3.txt", fileNames[2]);
}
}

[Test]
public void ReadArchivedFileData()
{
Expand All @@ -235,6 +251,108 @@ public void ExtractDifferentFormatsTest(TestFile file)
Assert.AreEqual(1, Directory.GetFiles(OutputDirectory).Length);
}
}

[Test, TestCaseSource(nameof(SolidArchivesFiles))]
public void ReadStreamFromSolidArchiveTest(TestFile file)
{
using (var extractor = new SevenZipExtractor(file.FilePath))
{
bool isSolid = Path.GetFileName(file.FilePath).ToLowerInvariant().Contains("solid");

var fileData = extractor.ArchiveFileData;
Assert.AreEqual(isSolid, extractor.IsSolid);
Assert.AreEqual(5, fileData.Count);

// extract files in non-sequential order
foreach (int index in new int[] { 2, 4, 1, 3, 0 })
{
string content = string.Empty;
using (var stream = new MemoryStream())
{
extractor.ExtractFile(index, stream);
stream.Seek(0, SeekOrigin.Begin);

using (TextReader reader = new StreamReader(stream))
{
content = reader.ReadToEnd();
}
}
Assert.AreEqual("test file", content);
}
}
}

[Test, TestCaseSource(nameof(SolidArchivesFiles))]
public void ExtractSpecificFilesFromSolidArchiveTest(TestFile file)
{
using (var extractor = new SevenZipExtractor(file.FilePath))
{
extractor.ExtractFiles(OutputDirectory, 2, 4);
Assert.AreEqual(2, Directory.GetFiles(OutputDirectory).Length);
}

Assert.AreEqual(2, Directory.GetFiles(OutputDirectory).Length);
Assert.Contains(Path.Combine(OutputDirectory, "test3.txt"), Directory.GetFiles(OutputDirectory));
Assert.Contains(Path.Combine(OutputDirectory, "test5.txt"), Directory.GetFiles(OutputDirectory));
}

[Test, TestCaseSource(nameof(SolidArchivesFiles))]
public void ExtractFileCallbackFromSolidArchiveTest(TestFile file)
{
using (var extractor = new SevenZipExtractor(file.FilePath))
{
extractor.ExtractFiles(args =>
{
if (args.Reason == ExtractFileCallbackReason.Start &&
(args.ArchiveFileInfo.Index == 2 || args.ArchiveFileInfo.Index == 4))
{
args.ExtractToFile = Path.Combine(OutputDirectory, args.ArchiveFileInfo.FileName);
}
});
}

Assert.AreEqual(2, Directory.GetFiles(OutputDirectory).Length);
Assert.Contains(Path.Combine(OutputDirectory, "test3.txt"), Directory.GetFiles(OutputDirectory));
Assert.Contains(Path.Combine(OutputDirectory, "test5.txt"), Directory.GetFiles(OutputDirectory));
}

[Test, TestCaseSource(nameof(SolidArchivesFiles))]
public void ReadStreamCallbackFromSolidArchiveTest(TestFile file)
{
using (var extractor = new SevenZipExtractor(file.FilePath))
{
extractor.ExtractFiles(args =>
{
if (args.Reason == ExtractFileCallbackReason.Start)
{
if (args.ArchiveFileInfo.Index == 2 || args.ArchiveFileInfo.Index == 4)
{
args.ExtractToStream = new MemoryStream();
}
}
else if (args.Reason == ExtractFileCallbackReason.Done)
{
if (args.ExtractToStream != null)
{
string content = string.Empty;
args.ExtractToStream.Seek(0, SeekOrigin.Begin);
using (TextReader reader = new StreamReader(args.ExtractToStream))
{
content = reader.ReadToEnd();
}
Assert.AreEqual("test file", content);

args.ExtractToStream.Dispose();
args.ExtractToStream = null;
}
}
else
{
Assert.Fail("Extract file failed " + args.Exception?.Message);
}
});
}
}
}

/// <summary>
Expand Down
Binary file added SevenZip.Tests/TestData_solid/testFiles.7z
Binary file not shown.
Binary file added SevenZip.Tests/TestData_solid/testFiles.rar
Binary file not shown.
Binary file added SevenZip.Tests/TestData_solid/testFiles.solid.7z
Binary file not shown.
Binary file added SevenZip.Tests/TestData_solid/testFiles.solid.rar
Binary file not shown.
Binary file added SevenZip.Tests/TestData_solid/testFiles.tar
Binary file not shown.
Binary file added SevenZip.Tests/TestData_solid/testFiles.zip
Binary file not shown.
2 changes: 1 addition & 1 deletion SevenZip/EventArguments/ExtractFileCallbackArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public Stream ExtractToStream
get => _extractToStream;
set
{
if (_extractToStream != null && !_extractToStream.CanWrite)
if (value != null && !value.CanWrite)
{
throw new ExtractionFailedException("The specified stream is not writable!");
}
Expand Down
48 changes: 1 addition & 47 deletions SevenZip/SevenZipExtractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -574,14 +574,9 @@ private void GetArchiveInfo(bool disposeStream)

_archiveProperties = new ReadOnlyCollection<ArchiveProperty>(archProps);

if (!_isSolid.HasValue && _format == InArchiveFormat.Zip)
{
_isSolid = false;
}

if (!_isSolid.HasValue)
{
_isSolid = true;
_isSolid = false;
}

#endregion
Expand Down Expand Up @@ -618,31 +613,6 @@ private void InitArchiveFileData(bool disposeStream)
}
}

/// <summary>
/// Produces an array of indexes from 0 to the maximum value in the specified array
/// </summary>
/// <param name="indexes">The source array</param>
/// <returns>The array of indexes from 0 to the maximum value in the specified array</returns>
private static uint[] SolidIndexes(uint[] indexes)
{
var max = indexes.Aggregate(0, (current, i) => Math.Max(current, (int) i));

if (max > 0)
{
max++;
var res = new uint[max];

for (var i = 0; i < max; i++)
{
res[i] = (uint)i;
}

return res;
}

return indexes;
}

/// <summary>
/// Checks whether all the indexes are valid.
/// </summary>
Expand Down Expand Up @@ -1085,12 +1055,6 @@ public void ExtractFile(int index, Stream stream)
try
{
var indexes = new[] { (uint)index };
var entry = _archiveFileData[index];

if (_isSolid.Value && !entry.Method.Equals("Copy", StringComparison.InvariantCultureIgnoreCase))
{
indexes = SolidIndexes(indexes);
}

using (var aec = GetArchiveExtractCallback(stream, (uint) index, indexes.Length))
{
Expand Down Expand Up @@ -1163,11 +1127,6 @@ public void ExtractFiles(string directory, params int[] indexes)
origIndexes.Sort();
uindexes = origIndexes.ToArray();

if (_isSolid.Value)
{
uindexes = SolidIndexes(uindexes);
}

#endregion

try
Expand Down Expand Up @@ -1272,11 +1231,6 @@ public void ExtractFiles(ExtractFileCallback extractFileCallback)
DisposedCheck();
InitArchiveFileData(false);

if (IsSolid)
{
throw new SevenZipExtractionFailedException("Solid archives are not supported.");
}

foreach (var archiveFileInfo in ArchiveFileData)
{
var extractFileCallbackArgs = new ExtractFileCallbackArgs(archiveFileInfo);
Expand Down