Skip to content

Commit 8ff2058

Browse files
committed
Enable partial decompression of MS-ZIP on all platforms
1 parent a781fff commit 8ff2058

File tree

2 files changed

+116
-13
lines changed

2 files changed

+116
-13
lines changed

BinaryObjectScanner/FileType/MicrosoftCAB.cs

Lines changed: 113 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
using System.IO;
1+
using System;
2+
using System.IO;
23
using BinaryObjectScanner.Interfaces;
34
#if (NET40_OR_GREATER || NETCOREAPP) && WIN
45
using LibMSPackN;
6+
#else
7+
using SabreTools.Models.MicrosoftCabinet;
58
#endif
69

710
namespace BinaryObjectScanner.FileType
@@ -27,9 +30,111 @@ public bool Extract(string file, string outDir, bool includeDebug)
2730
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
2831
{
2932
#if NET20 || NET35 || !WIN
30-
// Not supported for old .NET due to feature requirements
31-
// Not supported in non-Windows builds due to DLL requirements
32-
return false;
33+
try
34+
{
35+
if (!File.Exists(file))
36+
return false;
37+
38+
// Create the wrapper
39+
var cabArchive = SabreTools.Serialization.Wrappers.MicrosoftCabinet.Create(stream);
40+
if (cabArchive?.Model?.Folders == null || cabArchive.Model.Folders.Length == 0)
41+
return false;
42+
43+
// Loop through the folders
44+
for (int f = 0; f < cabArchive!.Model.Folders.Length; f++)
45+
{
46+
// Ensure data blocks
47+
var folder = cabArchive.Model.Folders[f];
48+
if (folder?.DataBlocks == null || folder.DataBlocks.Length == 0)
49+
continue;
50+
51+
// Loop through the data blocks
52+
var ms = new MemoryStream();
53+
foreach (var db in folder.DataBlocks)
54+
{
55+
if (db?.CompressedData == null)
56+
continue;
57+
58+
// Uncompressed data
59+
if ((folder.CompressionType & CompressionType.TYPE_NONE) != 0)
60+
{
61+
ms.Write(db.CompressedData);
62+
ms.Flush();
63+
}
64+
65+
// MS-ZIP
66+
else if ((folder.CompressionType & CompressionType.TYPE_MSZIP) != 0)
67+
{
68+
var decomp = SabreTools.Compression.MSZIP.Decompressor.Create();
69+
decomp.CopyTo(db.CompressedData, ms);
70+
}
71+
72+
// Quantum
73+
else if ((folder.CompressionType & CompressionType.TYPE_QUANTUM) != 0)
74+
{
75+
uint windowBits = (uint)(((ushort)folder.CompressionType >> 8) & 0x1f);
76+
var decomp = SabreTools.Compression.Quantum.Decompressor.Create(db.CompressedData, windowBits);
77+
byte[] data = decomp.Process();
78+
ms.Write(data);
79+
ms.Flush();
80+
}
81+
82+
// LZX
83+
else if ((folder.CompressionType & CompressionType.TYPE_LZX) != 0)
84+
{
85+
// TODO: Unsupported
86+
continue;
87+
}
88+
89+
// Unknown
90+
else
91+
{
92+
continue;
93+
}
94+
}
95+
96+
// If no data was read
97+
if (ms.Length == 0)
98+
continue;
99+
100+
// Ensure files
101+
if (cabArchive?.Model?.Files == null || cabArchive.Model.Files.Length == 0)
102+
continue;
103+
104+
// Loop through the files
105+
foreach (var compressedFile in cabArchive.Model.Files)
106+
{
107+
if (compressedFile?.Name == null || compressedFile.FolderIndex != (FolderIndex)f)
108+
continue;
109+
110+
try
111+
{
112+
byte[] fileData = new byte[compressedFile.FileSize];
113+
Array.Copy(ms.ToArray(), compressedFile.FolderStartOffset, fileData, 0, compressedFile.FileSize);
114+
115+
string tempFile = Path.Combine(outDir, compressedFile.Name);
116+
var directoryName = Path.GetDirectoryName(tempFile);
117+
if (directoryName != null && !Directory.Exists(directoryName))
118+
Directory.CreateDirectory(directoryName);
119+
120+
using var of = File.OpenWrite(tempFile);
121+
of.Write(fileData);
122+
of.Flush();
123+
}
124+
catch (Exception ex)
125+
{
126+
if (includeDebug) Console.WriteLine(ex);
127+
}
128+
}
129+
}
130+
131+
return true;
132+
}
133+
catch (Exception ex)
134+
{
135+
if (includeDebug) Console.WriteLine(ex);
136+
return false;
137+
}
33138
#else
34139
try
35140
{
@@ -49,17 +154,17 @@ public bool Extract(Stream? stream, string file, string outDir, bool includeDebu
49154

50155
compressedFile.ExtractTo(tempFile);
51156
}
52-
catch (System.Exception ex)
157+
catch (Exception ex)
53158
{
54-
if (includeDebug) System.Console.WriteLine(ex);
159+
if (includeDebug) Console.WriteLine(ex);
55160
}
56161
}
57162

58163
return true;
59164
}
60-
catch (System.Exception ex)
165+
catch (Exception ex)
61166
{
62-
if (includeDebug) System.Console.WriteLine(ex);
167+
if (includeDebug) Console.WriteLine(ex);
63168
return false;
64169
}
65170
#endif

ExtractionTool/Program.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -300,16 +300,14 @@ private static void ExtractFile(string file, string outputDirectory, bool includ
300300
{
301301
// Build the cabinet information
302302
Console.WriteLine("Extracting MS-CAB contents");
303-
Console.WriteLine();
304-
305303
#if NET20 || NET35 || !WIN
306-
Console.WriteLine("Extraction is not supported for this framework!");
304+
Console.WriteLine("WARNING: LZX compression not supported so some files may be skipped!");
305+
#endif
307306
Console.WriteLine();
308-
#else
307+
309308
// Extract using the FileType
310309
var mscab = new MicrosoftCAB();
311310
mscab.Extract(stream, file, outputDirectory, includeDebug: true);
312-
#endif
313311
}
314312

315313
// MoPaQ (MPQ) archive

0 commit comments

Comments
 (0)