Files
SabreTools.Serialization/SabreTools.Wrappers/WiseOverlayHeader.Extraction.cs
Matt Nadareski 8f49e190d8 Fix everything
2026-03-24 19:17:25 -04:00

315 lines
15 KiB
C#

using System;
using System.IO;
using SabreTools.Data.Models.WiseInstaller.Actions;
using SabreTools.IO;
using SabreTools.IO.Compression.Deflate;
using SabreTools.IO.Extensions;
namespace SabreTools.Wrappers
{
public partial class WiseOverlayHeader
{
/// <summary>
/// Extract the predefined, static files defined in the header
/// </summary>
/// <param name="outputDirectory">Output directory to write to</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>True if the files extracted successfully, false otherwise</returns>
/// <remarks>On success, this sets <see cref="InstallerDataOffset"/></remarks>
public bool ExtractHeaderDefinedFiles(string outputDirectory, bool includeDebug)
{
lock (_dataSourceLock)
{
// Seek to the compressed data offset
_dataSource.SeekIfPossible(CompressedDataOffset, SeekOrigin.Begin);
if (includeDebug) Console.WriteLine($"Beginning of header-defined files: {CompressedDataOffset}");
// Extract WiseColors.dib, if it exists
var expected = new DeflateInfo { InputSize = DibDeflatedSize, OutputSize = DibInflatedSize, Crc32 = 0 };
if (InflateWrapper.ExtractFile(_dataSource, "WiseColors.dib", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
return false;
// Extract WiseScript.bin
expected = new DeflateInfo { InputSize = WiseScriptDeflatedSize, OutputSize = WiseScriptInflatedSize, Crc32 = 0 };
if (InflateWrapper.ExtractFile(_dataSource, "WiseScript.bin", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
return false;
// Extract WISE0001.DLL, if it exists
expected = new DeflateInfo { InputSize = WiseDllDeflatedSize, OutputSize = -1, Crc32 = 0 };
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "WISE0001.DLL", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
return false;
// Extract CTL3D32.DLL, if it exists
expected = new DeflateInfo { InputSize = Ctl3d32DeflatedSize, OutputSize = -1, Crc32 = 0 };
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "CTL3D32.DLL", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
return false;
// Extract FILE0004, if it exists
expected = new DeflateInfo { InputSize = SomeData4DeflatedSize, OutputSize = -1, Crc32 = 0 };
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "FILE0004", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
return false;
// Extract Ocxreg32.EXE, if it exists
expected = new DeflateInfo { InputSize = RegToolDeflatedSize, OutputSize = -1, Crc32 = 0 };
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "Ocxreg32.EXE", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
return false;
// Extract PROGRESS.DLL, if it exists
expected = new DeflateInfo { InputSize = ProgressDllDeflatedSize, OutputSize = -1, Crc32 = 0 };
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "PROGRESS.DLL", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
return false;
// Extract FILE0007, if it exists
expected = new DeflateInfo { InputSize = SomeData7DeflatedSize, OutputSize = -1, Crc32 = 0 };
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "FILE0007", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
return false;
// Extract FILE0008, if it exists
expected = new DeflateInfo { InputSize = SomeData8DeflatedSize, OutputSize = -1, Crc32 = 0 };
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "FILE0008", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
return false;
// Extract FILE0009, if it exists
expected = new DeflateInfo { InputSize = SomeData9DeflatedSize, OutputSize = -1, Crc32 = 0 };
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "FILE0009", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
return false;
// Extract FILE000A, if it exists
expected = new DeflateInfo { InputSize = SomeData10DeflatedSize, OutputSize = -1, Crc32 = 0 };
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "FILE000A", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
return false;
// Extract install script, if it exists
expected = new DeflateInfo { InputSize = InstallScriptDeflatedSize, OutputSize = -1, Crc32 = 0 };
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "INSTALL_SCRIPT", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
return false;
// Extract FILE000{n}.DAT, if it exists
expected = new DeflateInfo { InputSize = FinalFileDeflatedSize, OutputSize = FinalFileInflatedSize, Crc32 = 0 };
if (InflateWrapper.ExtractFile(_dataSource, IsPKZIP ? null : "FILE00XX.DAT", outputDirectory, expected, IsPKZIP, includeDebug) == ExtractionStatus.FAIL)
return false;
InstallerDataOffset = _dataSource.Position;
}
return true;
}
/// <summary>
/// Attempt to extract a file defined by a file header
/// </summary>
/// <param name="obj">Deflate information</param>
/// <param name="index">File index for automatic naming</param>
/// <param name="outputDirectory">Output directory to write to</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>True if the file extracted successfully, false otherwise</returns>
/// <remarks>Requires <see cref="InstallerDataOffset"/> to be set</remarks>
public ExtractionStatus ExtractFile(InstallFile obj, int index, string outputDirectory, bool includeDebug)
{
// Get expected values
var expected = new DeflateInfo
{
InputSize = obj.DeflateEnd - obj.DeflateStart,
OutputSize = obj.InflatedSize,
Crc32 = obj.Crc32,
};
// Perform path replacements
string filename = obj.DestinationPathname ?? $"WISE{index:X4}";
filename = filename.Replace("%", string.Empty);
lock (_dataSourceLock)
{
_dataSource.SeekIfPossible(InstallerDataOffset + obj.DeflateStart, SeekOrigin.Begin);
return InflateWrapper.ExtractFile(_dataSource,
filename,
outputDirectory,
expected,
IsPKZIP,
includeDebug);
}
}
/// <summary>
/// Attempt to extract a file defined by a file header
/// </summary>
/// <param name="obj">Deflate information</param>
/// <param name="outputDirectory">Output directory to write to</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>True if the file extracted successfully, false otherwise</returns>
/// <remarks>Requires <see cref="InstallerDataOffset"/> to be set</remarks>
public ExtractionStatus ExtractFile(DisplayBillboard obj, string outputDirectory, bool includeDebug)
{
// Get the generated base name
string baseName = $"CustomBillboardSet_{obj.Flags:X4}-{obj.Operand_2}-{obj.Operand_3}";
// If there are no deflate objects
if (obj.DeflateInfo is null)
{
if (includeDebug) Console.WriteLine($"Skipping {baseName} because the deflate object array is null!");
return ExtractionStatus.FAIL;
}
// Loop through the values
for (int i = 0; i < obj.DeflateInfo.Length; i++)
{
// Get the deflate info object
var info = obj.DeflateInfo[i];
// Get expected values
var expected = new DeflateInfo
{
InputSize = info.DeflateEnd - info.DeflateStart,
OutputSize = info.InflatedSize,
Crc32 = 0,
};
// Perform path replacements
string filename = $"{baseName}{i:X4}";
lock (_dataSourceLock)
{
_dataSource.SeekIfPossible(InstallerDataOffset + info.DeflateStart, SeekOrigin.Begin);
_ = InflateWrapper.ExtractFile(_dataSource, filename, outputDirectory, expected, IsPKZIP, includeDebug);
}
}
// Always return good -- TODO: Fix this
return ExtractionStatus.GOOD;
}
/// <summary>
/// Attempt to extract a file defined by a file header
/// </summary>
/// <param name="obj">Deflate information</param>
/// <param name="outputDirectory">Output directory to write to</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>True if the file extracted successfully, false otherwise</returns>
/// <remarks>Requires <see cref="InstallerDataOffset"/> to be set</remarks>
public ExtractionStatus ExtractFile(CustomDialogSet obj, string outputDirectory, bool includeDebug)
{
// Get expected values
var expected = new DeflateInfo
{
InputSize = obj.DeflateEnd - obj.DeflateStart,
OutputSize = obj.InflatedSize,
Crc32 = 0,
};
// Perform path replacements
string filename = $"CustomDialogSet_{obj.DisplayVariable}-{obj.Name}";
filename = filename.Replace("%", string.Empty);
lock (_dataSourceLock)
{
_dataSource.SeekIfPossible(InstallerDataOffset + obj.DeflateStart, SeekOrigin.Begin);
return InflateWrapper.ExtractFile(_dataSource, filename, outputDirectory, expected, IsPKZIP, includeDebug);
}
}
/// <summary>
/// Open a potential WISE installer file and any additional files
/// </summary>
/// <param name="filename">Input filename or base name to read from</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>True if the file could be opened, false otherwise</returns>
public static bool OpenFile(string filename, bool includeDebug, out ReadOnlyCompositeStream? stream)
{
// If the file exists as-is
if (File.Exists(filename))
{
var fileStream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
stream = new ReadOnlyCompositeStream([fileStream]);
// Debug statement
if (includeDebug) Console.WriteLine($"File {filename} was found and opened");
// Strip the extension and rebuild
string? directory = Path.GetDirectoryName(filename);
filename = Path.GetFileNameWithoutExtension(filename);
if (directory is not null)
filename = Path.Combine(directory, filename);
}
// If the base name was provided, try to open the associated exe
else if (File.Exists($"{filename}.EXE"))
{
var fileStream = File.Open($"{filename}.EXE", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
stream = new ReadOnlyCompositeStream([fileStream]);
// Debug statement
if (includeDebug) Console.WriteLine($"File {filename}.EXE was found and opened");
}
else if (File.Exists($"{filename}.exe"))
{
var fileStream = File.Open($"{filename}.exe", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
stream = new ReadOnlyCompositeStream([fileStream]);
// Debug statement
if (includeDebug) Console.WriteLine($"File {filename}.exe was found and opened");
}
// Otherwise, the file cannot be opened
else
{
stream = null;
return false;
}
// Get the pattern for file naming
string filePattern = string.Empty;
bool longDigits = false;
byte fileno = 0;
bool foundStart = false;
for (; fileno < 3; fileno++)
{
if (File.Exists($"{filename}.W0{fileno}"))
{
foundStart = true;
filePattern = $"{filename}.W";
longDigits = false;
break;
}
else if (File.Exists($"{filename}.w0{fileno}"))
{
foundStart = true;
filePattern = $"{filename}.w";
longDigits = false;
break;
}
else if (File.Exists($"{filename}.00{fileno}"))
{
foundStart = true;
filePattern = $"{filename}.";
longDigits = true;
break;
}
}
// If no starting part has been found
if (!foundStart)
return true;
// Loop through and try to read all additional files
for (; ; fileno++)
{
string nextPart = longDigits ? $"{filePattern}{fileno:D3}" : $"{filePattern}{fileno:D2}";
if (!File.Exists(nextPart))
{
if (includeDebug) Console.WriteLine($"Part {nextPart} was not found");
break;
}
// Debug statement
if (includeDebug) Console.WriteLine($"Part {nextPart} was found and appended");
var fileStream = File.Open(nextPart, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
stream.AddStream(fileStream);
}
return true;
}
}
}