Add branching and specific SharpCompress calls for solid vs non-solid archives in order to extract solid archives properly. (#375)

* Add branching for solid vs non-solid archives in order to extract solid archives properly.

* Change comments on sevenzip, reuse archive-level solid flag for rar

* Fully simplify identifying if archive is solid.

* Finish implementing first round of feedback.

* Fix second round of formatting issues.

* Final formatting fixes.
This commit is contained in:
HeroponRikiBestest
2025-07-11 23:13:00 -04:00
committed by GitHub
parent dff15ef799
commit 249a17be1f
2 changed files with 145 additions and 61 deletions

View File

@@ -4,6 +4,7 @@ using BinaryObjectScanner.Interfaces;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives;
using SharpCompress.Archives.Rar;
using SharpCompress.Common;
using SharpCompress.Readers;
#endif
@@ -51,36 +52,11 @@ namespace BinaryObjectScanner.FileType
if (!rarFile.IsComplete)
return false;
foreach (var entry in rarFile.Entries)
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
if (rarFile.IsSolid)
return ExtractSolid(rarFile, outDir, includeDebug);
else
return ExtractNonSolid(rarFile, outDir, includeDebug);
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
string tempFile = Path.Combine(outDir, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
return true;
}
catch (Exception ex)
{
@@ -91,5 +67,71 @@ namespace BinaryObjectScanner.FileType
return false;
#endif
}
#if NET462_OR_GREATER || NETCOREAPP
/// <summary>
/// Extraction method for non-solid archives. This iterates over each entry in the archive to extract every
/// file individually, in order to extract all valid files from the archive.
/// </summary>
private bool ExtractNonSolid(RarArchive rarFile, string outDir, bool includeDebug)
{
foreach (var entry in rarFile.Entries)
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
string tempFile = Path.Combine(outDir, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
return true;
}
/// <summary>
/// Extraction method for solid archives. Uses ExtractAllEntries because extraction for solid archives must be
/// done sequentially, and files beyond a corrupted point in a solid archive will be unreadable anyways.
/// </summary>
private bool ExtractSolid(RarArchive rarFile, string outDir, bool includeDebug)
{
try
{
if (!Directory.Exists(outDir))
Directory.CreateDirectory(outDir);
rarFile.WriteToDirectory(outDir, new ExtractionOptions()
{
ExtractFullPath = true,
Overwrite = true,
});
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
return true;
}
#endif
}
}
}

View File

@@ -4,6 +4,7 @@ using BinaryObjectScanner.Interfaces;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives;
using SharpCompress.Archives.SevenZip;
using SharpCompress.Common;
using SharpCompress.Readers;
#endif
@@ -43,41 +44,17 @@ namespace BinaryObjectScanner.FileType
{
var readerOptions = new ReaderOptions() { LookForHeader = lookForHeader };
var sevenZip = SevenZipArchive.Open(stream, readerOptions);
// Try to read the file path if no entries are found
if (sevenZip.Entries.Count == 0 && !string.IsNullOrEmpty(file) && File.Exists(file))
sevenZip = SevenZipArchive.Open(file, readerOptions);
foreach (var entry in sevenZip.Entries)
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// Currently doesn't flag solid 7z archives with only 1 solid block as solid, but practically speaking
// this is not much of a concern.
if (sevenZip.IsSolid)
return ExtractSolid(sevenZip, outDir, includeDebug);
else
return ExtractNonSolid(sevenZip, outDir, includeDebug);
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
string tempFile = Path.Combine(outDir, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
return true;
}
catch (Exception ex)
{
@@ -88,5 +65,70 @@ namespace BinaryObjectScanner.FileType
return false;
#endif
}
#if NET462_OR_GREATER || NETCOREAPP
/// <summary>
/// Extraction method for non-solid archives. This iterates over each entry in the archive to extract every
/// file individually, in order to extract all valid files from the archive.
/// </summary>
private bool ExtractNonSolid(SevenZipArchive sevenZip, string outDir, bool includeDebug)
{
foreach (var entry in sevenZip.Entries)
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
string tempFile = Path.Combine(outDir, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
return true;
}
/// <summary>
/// Extraction method for solid archives. Uses ExtractAllEntries because extraction for solid archives must be
/// done sequentially, and files beyond a corrupted point in a solid archive will be unreadable anyways.
/// </summary>
private bool ExtractSolid(SevenZipArchive sevenZip, string outDir, bool includeDebug)
{
try
{
if (!Directory.Exists(outDir))
Directory.CreateDirectory(outDir);
sevenZip.WriteToDirectory(outDir, new ExtractionOptions()
{
ExtractFullPath = true,
Overwrite = true,
});
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
return true;
}
#endif
}
}
}