Skip to content

Commit d7e5597

Browse files
committed
Normalize extraction methods
This does a few things: - Ensures that all output directories are normalized for the current operating system - Ensures that all output files are flushed in case of systematic issues - Brings MS-CAB extraction up to the same return value quality as other extractors
1 parent a2be40f commit d7e5597

File tree

15 files changed

+192
-102
lines changed

15 files changed

+192
-102
lines changed

SabreTools.Serialization/Wrappers/BFPK.cs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -139,14 +139,28 @@ public bool ExtractFile(int index, string outputDirectory)
139139
compressedSize = file.UncompressedSize;
140140
}
141141

142+
// If we have an invalid output directory
143+
if (string.IsNullOrEmpty(outputDirectory))
144+
return false;
145+
146+
// Ensure directory separators are consistent
147+
string filename = file.Name ?? $"file{index}";
148+
if (Path.DirectorySeparatorChar == '\\')
149+
filename = filename.Replace('/', '\\');
150+
else if (Path.DirectorySeparatorChar == '/')
151+
filename = filename.Replace('\\', '/');
152+
153+
// Ensure the full output directory exists
154+
filename = Path.Combine(outputDirectory, filename);
155+
var directoryName = Path.GetDirectoryName(filename);
156+
if (directoryName != null && !Directory.Exists(directoryName))
157+
Directory.CreateDirectory(directoryName);
158+
159+
// Try to write the data
142160
try
143161
{
144-
// Ensure the output directory exists
145-
Directory.CreateDirectory(outputDirectory);
146-
147-
// Create the output path
148-
string filePath = Path.Combine(outputDirectory, file.Name ?? $"file{index}");
149-
using FileStream fs = File.OpenWrite(filePath);
162+
// Open the output file for writing
163+
using FileStream fs = File.OpenWrite(filename);
150164

151165
// Read the data block
152166
var data = ReadFromDataSource(offset, compressedSize);
@@ -157,20 +171,22 @@ public bool ExtractFile(int index, string outputDirectory)
157171
if (compressedSize == file.UncompressedSize)
158172
{
159173
fs.Write(data, 0, compressedSize);
174+
fs.Flush();
160175
}
161176
else
162177
{
163-
MemoryStream ms = new MemoryStream(data);
164-
ZlibStream zs = new ZlibStream(ms, CompressionMode.Decompress);
178+
using MemoryStream ms = new MemoryStream(data);
179+
using ZlibStream zs = new ZlibStream(ms, CompressionMode.Decompress);
165180
zs.CopyTo(fs);
181+
fs.Flush();
166182
}
167-
168-
return true;
169183
}
170184
catch
171185
{
172186
return false;
173187
}
188+
189+
return true;
174190
}
175191

176192
#endregion

SabreTools.Serialization/Wrappers/BSP.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,16 @@ public bool ExtractLump(int index, string outputDirectory)
137137
if (string.IsNullOrEmpty(outputDirectory))
138138
return false;
139139

140-
// Create the full output path
141-
filename = Path.Combine(outputDirectory, filename);
140+
// Ensure directory separators are consistent
141+
if (Path.DirectorySeparatorChar == '\\')
142+
filename = filename.Replace('/', '\\');
143+
else if (Path.DirectorySeparatorChar == '/')
144+
filename = filename.Replace('\\', '/');
142145

143-
// Ensure the output directory is created
146+
// Ensure the full output directory exists
147+
filename = Path.Combine(outputDirectory, filename);
144148
var directoryName = Path.GetDirectoryName(filename);
145-
if (directoryName != null)
149+
if (directoryName != null && !Directory.Exists(directoryName))
146150
Directory.CreateDirectory(directoryName);
147151

148152
// Try to write the data
@@ -151,6 +155,7 @@ public bool ExtractLump(int index, string outputDirectory)
151155
// Open the output file for writing
152156
using Stream fs = File.OpenWrite(filename);
153157
fs.Write(data, 0, data.Length);
158+
fs.Flush();
154159
}
155160
catch
156161
{

SabreTools.Serialization/Wrappers/GCF.cs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -287,19 +287,21 @@ public bool ExtractFile(int index, string outputDirectory)
287287
}
288288
}
289289

290-
// Create the filename
291-
var filename = file.Path;
292-
293290
// If we have an invalid output directory
294291
if (string.IsNullOrEmpty(outputDirectory))
295292
return false;
296293

297-
// Create the full output path
298-
filename = Path.Combine(outputDirectory, filename ?? $"file{index}");
294+
// Ensure directory separators are consistent
295+
string filename = file.Path ?? $"file{index}";
296+
if (Path.DirectorySeparatorChar == '\\')
297+
filename = filename.Replace('/', '\\');
298+
else if (Path.DirectorySeparatorChar == '/')
299+
filename = filename.Replace('\\', '/');
299300

300-
// Ensure the output directory is created
301+
// Ensure the full output directory exists
302+
filename = Path.Combine(outputDirectory, filename);
301303
var directoryName = Path.GetDirectoryName(filename);
302-
if (directoryName != null)
304+
if (directoryName != null && !Directory.Exists(directoryName))
303305
Directory.CreateDirectory(directoryName);
304306

305307
// Try to write the data
@@ -318,6 +320,7 @@ public bool ExtractFile(int index, string outputDirectory)
318320
return false;
319321

320322
fs.Write(data, 0, data.Length);
323+
fs.Flush();
321324
}
322325
}
323326
catch

SabreTools.Serialization/Wrappers/InstallShieldArchiveV3.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ public bool ExtractFile(int index, string outputDirectory)
250250
{
251251
// Decompress the data
252252
var decomp = Decompressor.Create();
253-
var outData = new MemoryStream();
253+
using var outData = new MemoryStream();
254254
decomp.CopyTo(compressedData, outData);
255255
data = outData.ToArray();
256256
}
@@ -259,12 +259,16 @@ public bool ExtractFile(int index, string outputDirectory)
259259
if (string.IsNullOrEmpty(outputDirectory))
260260
return false;
261261

262-
// Create the full output path
263-
filename = Path.Combine(outputDirectory, filename);
262+
// Ensure directory separators are consistent
263+
if (Path.DirectorySeparatorChar == '\\')
264+
filename = filename.Replace('/', '\\');
265+
else if (Path.DirectorySeparatorChar == '/')
266+
filename = filename.Replace('\\', '/');
264267

265-
// Ensure the output directory is created
268+
// Ensure the full output directory exists
269+
filename = Path.Combine(outputDirectory, filename);
266270
var directoryName = Path.GetDirectoryName(filename);
267-
if (directoryName != null)
271+
if (directoryName != null && !System.IO.Directory.Exists(directoryName))
268272
System.IO.Directory.CreateDirectory(directoryName);
269273

270274
// Try to write the data
@@ -273,6 +277,7 @@ public bool ExtractFile(int index, string outputDirectory)
273277
// Open the output file for writing
274278
using Stream fs = System.IO.File.OpenWrite(filename);
275279
fs.Write(data, 0, data.Length);
280+
fs.Flush();
276281
}
277282
catch
278283
{

SabreTools.Serialization/Wrappers/LZKWAJ.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,16 @@ public bool Extract(string outputDirectory)
112112
if (Model.HeaderExtensions?.FileExtension != null)
113113
filename += $".{Model.HeaderExtensions.FileExtension}";
114114

115-
filename = Path.Combine(outputDirectory, filename);
115+
// Ensure directory separators are consistent
116+
if (Path.DirectorySeparatorChar == '\\')
117+
filename = filename.Replace('/', '\\');
118+
else if (Path.DirectorySeparatorChar == '/')
119+
filename = filename.Replace('\\', '/');
116120

117-
// Ensure the output directory is created
121+
// Ensure the full output directory exists
122+
filename = Path.Combine(outputDirectory, filename);
118123
var directoryName = Path.GetDirectoryName(filename);
119-
if (directoryName != null)
124+
if (directoryName != null && !Directory.Exists(directoryName))
120125
Directory.CreateDirectory(directoryName);
121126

122127
// Try to write the data
@@ -125,6 +130,7 @@ public bool Extract(string outputDirectory)
125130
// Open the output file for writing
126131
using Stream fs = File.OpenWrite(filename);
127132
decompressor.CopyTo(fs);
133+
fs.Flush();
128134
}
129135
catch
130136
{

SabreTools.Serialization/Wrappers/LZQBasic.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,17 @@ public bool Extract(string outputDirectory)
106106
if (string.IsNullOrEmpty(outputDirectory))
107107
return false;
108108

109-
// Create the full output path
110-
string filename = Path.Combine(outputDirectory, "tempfile.bin");
111-
112-
// Ensure the output directory is created
109+
// Ensure directory separators are consistent
110+
string filename = "tempfile.bin";
111+
if (Path.DirectorySeparatorChar == '\\')
112+
filename = filename.Replace('/', '\\');
113+
else if (Path.DirectorySeparatorChar == '/')
114+
filename = filename.Replace('\\', '/');
115+
116+
// Ensure the full output directory exists
117+
filename = Path.Combine(outputDirectory, filename);
113118
var directoryName = Path.GetDirectoryName(filename);
114-
if (directoryName != null)
119+
if (directoryName != null && !Directory.Exists(directoryName))
115120
Directory.CreateDirectory(directoryName);
116121

117122
// Try to write the data
@@ -120,6 +125,7 @@ public bool Extract(string outputDirectory)
120125
// Open the output file for writing
121126
using Stream fs = File.OpenWrite(filename);
122127
decompressor.CopyTo(fs);
128+
fs.Flush();
123129
}
124130
catch
125131
{

SabreTools.Serialization/Wrappers/LZSZDD.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,16 @@ public bool Extract(string filename, string outputDirectory)
109109
if (string.IsNullOrEmpty(outputDirectory))
110110
return false;
111111

112-
// Create the full output path
113-
filename = Path.Combine(outputDirectory, filename);
112+
// Ensure directory separators are consistent
113+
if (Path.DirectorySeparatorChar == '\\')
114+
filename = filename.Replace('/', '\\');
115+
else if (Path.DirectorySeparatorChar == '/')
116+
filename = filename.Replace('\\', '/');
114117

115-
// Ensure the output directory is created
118+
// Ensure the full output directory exists
119+
filename = Path.Combine(outputDirectory, filename);
116120
var directoryName = Path.GetDirectoryName(filename);
117-
if (directoryName != null)
121+
if (directoryName != null && !Directory.Exists(directoryName))
118122
Directory.CreateDirectory(directoryName);
119123

120124
// Try to write the data
@@ -123,6 +127,7 @@ public bool Extract(string filename, string outputDirectory)
123127
// Open the output file for writing
124128
using Stream fs = File.OpenWrite(filename);
125129
decompressor.CopyTo(fs);
130+
fs.Flush();
126131
}
127132
catch
128133
{

SabreTools.Serialization/Wrappers/MicrosoftCabinet.cs

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -148,20 +148,21 @@ public static bool ExtractSet(Stream? stream, string filename, string outDir, bo
148148
try
149149
{
150150
// Loop through the cabinets
151+
bool allExtracted = true;
151152
do
152153
{
153-
current.Extract(filename, outDir, includeDebug);
154+
allExtracted &= current.Extract(filename, outDir, includeDebug);
154155
current = current.Next ?? current.OpenNext(filename);
155156
}
156157
while (current?.Header != null);
158+
159+
return allExtracted;
157160
}
158161
catch (Exception ex)
159162
{
160163
if (includeDebug) Console.WriteLine(ex);
161164
return false;
162165
}
163-
164-
return true;
165166
}
166167

167168
/// <summary>
@@ -180,13 +181,14 @@ public bool Extract(string? filename, string outDir, bool includeDebug)
180181
try
181182
{
182183
// Loop through the folders
184+
bool allExtracted = true;
183185
for (int f = 0; f < Folders.Length; f++)
184186
{
185187
var folder = Folders[f];
186-
ExtractFolder(filename, outDir, folder, f, includeDebug);
188+
allExtracted &= ExtractFolder(filename, outDir, folder, f, includeDebug);
187189
}
188190

189-
return true;
191+
return allExtracted;
190192
}
191193
catch (Exception ex)
192194
{
@@ -203,7 +205,8 @@ public bool Extract(string? filename, string outDir, bool includeDebug)
203205
/// <param name="folder">Folder containing the blocks to decompress</param>
204206
/// <param name="folderIndex">Index of the folder in the cabinet</param>
205207
/// <param name="includeDebug">True to include debug data, false otherwise</param>
206-
private void ExtractFolder(string? filename,
208+
/// <returns>True if all files extracted, false otherwise</returns>
209+
private bool ExtractFolder(string? filename,
207210
string outDir,
208211
CFFOLDER? folder,
209212
int folderIndex,
@@ -212,15 +215,18 @@ private void ExtractFolder(string? filename,
212215
// Decompress the blocks, if possible
213216
using var blockStream = DecompressBlocks(filename, folder, folderIndex);
214217
if (blockStream == null || blockStream.Length == 0)
215-
return;
218+
return false;
216219

217220
// Loop through the files
221+
bool allExtracted = true;
218222
var files = GetFiles(folderIndex);
219223
for (int i = 0; i < files.Length; i++)
220224
{
221225
var file = files[i];
222-
ExtractFile(outDir, blockStream, file, includeDebug);
226+
allExtracted &= ExtractFile(outDir, blockStream, file, includeDebug);
223227
}
228+
229+
return allExtracted;
224230
}
225231

226232
/// <summary>
@@ -230,33 +236,39 @@ private void ExtractFolder(string? filename,
230236
/// <param name="blockStream">Stream representing the uncompressed block data</param>
231237
/// <param name="file">File information</param>
232238
/// <param name="includeDebug">True to include debug data, false otherwise</param>
233-
private static void ExtractFile(string outDir, Stream blockStream, CFFILE file, bool includeDebug)
239+
/// <returns>True if the file extracted, false otherwise</returns>
240+
private static bool ExtractFile(string outDir, Stream blockStream, CFFILE file, bool includeDebug)
234241
{
235242
try
236243
{
237244
blockStream.Seek(file.FolderStartOffset, SeekOrigin.Begin);
238245
byte[] fileData = blockStream.ReadBytes((int)file.FileSize);
239246

240247
// Ensure directory separators are consistent
241-
string fileName = file.Name!;
248+
string filename = file.Name!;
242249
if (Path.DirectorySeparatorChar == '\\')
243-
fileName = fileName.Replace('/', '\\');
250+
filename = filename.Replace('/', '\\');
244251
else if (Path.DirectorySeparatorChar == '/')
245-
fileName = fileName.Replace('\\', '/');
252+
filename = filename.Replace('\\', '/');
246253

247-
string tempFile = Path.Combine(outDir, fileName);
248-
var directoryName = Path.GetDirectoryName(tempFile);
254+
// Ensure the full output directory exists
255+
filename = Path.Combine(outDir, filename);
256+
var directoryName = Path.GetDirectoryName(filename);
249257
if (directoryName != null && !Directory.Exists(directoryName))
250258
Directory.CreateDirectory(directoryName);
251259

252-
using var of = File.OpenWrite(tempFile);
253-
of.Write(fileData, 0, fileData.Length);
254-
of.Flush();
260+
// Open the output file for writing
261+
using var fs = File.OpenWrite(filename);
262+
fs.Write(fileData, 0, fileData.Length);
263+
fs.Flush();
255264
}
256265
catch (Exception ex)
257266
{
258267
if (includeDebug) Console.WriteLine(ex);
268+
return false;
259269
}
270+
271+
return true;
260272
}
261273

262274
#endregion

0 commit comments

Comments
 (0)