diff --git a/BinaryObjectScanner/FileType/RAR.cs b/BinaryObjectScanner/FileType/RAR.cs index 3a33c19e..277534c0 100644 --- a/BinaryObjectScanner/FileType/RAR.cs +++ b/BinaryObjectScanner/FileType/RAR.cs @@ -4,6 +4,7 @@ #if NET462_OR_GREATER || NETCOREAPP using SharpCompress.Archives; using SharpCompress.Archives.Rar; +using SharpCompress.Common; using SharpCompress.Readers; #endif @@ -51,36 +52,11 @@ public bool Extract(Stream? stream, string file, string outDir, bool lookForHead if (!rarFile.IsComplete) return false; - 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); - } - } + if (rarFile.IsSolid) + return ExtractSolid(rarFile, outDir, includeDebug); + else + return ExtractNonSolid(rarFile, outDir, includeDebug); - return true; } catch (Exception ex) { @@ -91,5 +67,71 @@ public bool Extract(Stream? stream, string file, string outDir, bool lookForHead return false; #endif } + +#if NET462_OR_GREATER || NETCOREAPP + + /// + /// 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. + /// + 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; + } + + /// + /// 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. + /// + 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 } -} +} \ No newline at end of file diff --git a/BinaryObjectScanner/FileType/SevenZip.cs b/BinaryObjectScanner/FileType/SevenZip.cs index 850ad250..04fcfab2 100644 --- a/BinaryObjectScanner/FileType/SevenZip.cs +++ b/BinaryObjectScanner/FileType/SevenZip.cs @@ -4,6 +4,7 @@ #if NET462_OR_GREATER || NETCOREAPP using SharpCompress.Archives; using SharpCompress.Archives.SevenZip; +using SharpCompress.Common; using SharpCompress.Readers; #endif @@ -43,50 +44,91 @@ public bool Extract(Stream? stream, string file, string outDir, bool lookForHead { 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) + // 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); + + } + catch (Exception ex) + { + if (includeDebug) Console.WriteLine(ex); + return false; + } +#else + return false; +#endif + } + +#if NET462_OR_GREATER || NETCOREAPP + /// + /// 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. + /// + private bool ExtractNonSolid(SevenZipArchive sevenZip, string outDir, bool includeDebug) + { + foreach (var entry in sevenZip.Entries) + { + try { - try - { - // If the entry is a directory - if (entry.IsDirectory) - continue; + // If the entry is a directory + if (entry.IsDirectory) + continue; - // If the entry has an invalid key - if (entry.Key == null) - 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; + // 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); + 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); - } + entry.WriteToFile(tempFile); + } + catch (Exception ex) + { + if (includeDebug) Console.WriteLine(ex); } - - return true; + } + return true; + } + + /// + /// 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. + /// + 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 false; } -#else - return false; -#endif + + return true; } +#endif } -} +} \ No newline at end of file