mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-07-09 02:16:46 +00:00
Add Microsoft LZ-compressed files support
This commit is contained in:
@@ -85,6 +85,44 @@ namespace BurnOutSharp.Compression
|
||||
return decompressed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reconstructs the full filename of the compressed file
|
||||
/// </summary>
|
||||
public static string GetExpandedName(string input, out LZERROR error)
|
||||
{
|
||||
// Try to open the file as a compressed stream
|
||||
var fileStream = File.Open(input, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
var state = new LZ().Open(fileStream, out error);
|
||||
if (state?.Window == null)
|
||||
return null;
|
||||
|
||||
// Get the extension for modification
|
||||
string inputExtension = Path.GetExtension(input).TrimStart('.');
|
||||
|
||||
// If we have no extension
|
||||
if (string.IsNullOrWhiteSpace(inputExtension))
|
||||
return Path.GetFileNameWithoutExtension(input);
|
||||
|
||||
// If we have an extension of length 1
|
||||
if (inputExtension.Length == 1)
|
||||
{
|
||||
if (inputExtension == "_")
|
||||
return $"{Path.GetFileNameWithoutExtension(input)}.{char.ToLower(state.LastChar)}";
|
||||
else
|
||||
return Path.GetFileNameWithoutExtension(input);
|
||||
}
|
||||
|
||||
// If we have an extension that doesn't end in an underscore
|
||||
if (!inputExtension.EndsWith("_"))
|
||||
return Path.GetFileNameWithoutExtension(input);
|
||||
|
||||
// Build the new filename
|
||||
bool isLowerCase = char.IsUpper(input[0]);
|
||||
char replacementChar = isLowerCase ? char.ToLower(state.LastChar) : char.ToUpper(state.LastChar);
|
||||
string outputExtension = inputExtension.Substring(0, inputExtension.Length - 1) + replacementChar;
|
||||
return $"{Path.GetFileNameWithoutExtension(input)}.{outputExtension}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region State Management
|
||||
@@ -175,48 +213,6 @@ namespace BurnOutSharp.Compression
|
||||
|
||||
#endregion
|
||||
|
||||
#region File Name Handling
|
||||
|
||||
/// <summary>
|
||||
/// Reconstructs the full filename of the compressed file
|
||||
/// </summary>
|
||||
public string GetExpandedName(string input, out LZERROR error)
|
||||
{
|
||||
// Try to open the file as a compressed stream
|
||||
var fileStream = File.Open(input, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
var state = Open(fileStream, out error);
|
||||
if (state?.Window == null)
|
||||
return null;
|
||||
|
||||
// Get the extension for modification
|
||||
string inputExtension = Path.GetExtension(input).TrimStart('.');
|
||||
|
||||
// If we have no extension
|
||||
if (string.IsNullOrWhiteSpace(inputExtension))
|
||||
return Path.GetFileNameWithoutExtension(input);
|
||||
|
||||
// If we have an extension of length 1
|
||||
if (inputExtension.Length == 1)
|
||||
{
|
||||
if (inputExtension == "_")
|
||||
return $"{Path.GetFileNameWithoutExtension(input)}.{char.ToLower(state.LastChar)}";
|
||||
else
|
||||
return Path.GetFileNameWithoutExtension(input);
|
||||
}
|
||||
|
||||
// If we have an extension that doesn't end in an underscore
|
||||
if (!inputExtension.EndsWith("_"))
|
||||
return Path.GetFileNameWithoutExtension(input);
|
||||
|
||||
// Build the new filename
|
||||
bool isLowerCase = char.IsUpper(input[0]);
|
||||
char replacementChar = isLowerCase ? char.ToLower(state.LastChar) : char.ToUpper(state.LastChar);
|
||||
string outputExtension = inputExtension.Substring(0, inputExtension.Length - 1) + replacementChar;
|
||||
return $"{Path.GetFileNameWithoutExtension(input)}.{outputExtension}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stream Functionality
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -60,6 +60,11 @@
|
||||
/// </summary>
|
||||
MicrosoftCAB,
|
||||
|
||||
/// <summary>
|
||||
/// Microsoft LZ-compressed file
|
||||
/// </summary>
|
||||
MicrosoftLZ,
|
||||
|
||||
/// <summary>
|
||||
/// MPQ game data archive
|
||||
/// </summary>
|
||||
|
||||
85
BurnOutSharp/FileType/MicrosoftLZ.cs
Normal file
85
BurnOutSharp/FileType/MicrosoftLZ.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Compression;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using static BurnOutSharp.Utilities.Dictionary;
|
||||
|
||||
namespace BurnOutSharp.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Microsoft LZ-compressed Files (LZ32)
|
||||
/// </summary>
|
||||
/// <remarks>This is treated like an archive type due to the packing style</remarks>
|
||||
public class MicrosoftLZ : IScannable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
{
|
||||
// If the LZ file itself fails
|
||||
try
|
||||
{
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
byte[] data = LZ.Decompress(stream);
|
||||
|
||||
// Create the temp filename
|
||||
string tempFile = "temp.bin";
|
||||
if (!string.IsNullOrEmpty(file))
|
||||
{
|
||||
string expandedFilePath = LZ.GetExpandedName(file, out _);
|
||||
tempFile = Path.GetFileName(expandedFilePath).TrimEnd('\0');
|
||||
if (tempFile.EndsWith(".ex"))
|
||||
tempFile += "e";
|
||||
else if (tempFile.EndsWith(".dl"))
|
||||
tempFile += "l";
|
||||
}
|
||||
|
||||
tempFile = Path.Combine(tempPath, tempFile);
|
||||
|
||||
// Write the file data to a temp file
|
||||
using (Stream tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
|
||||
{
|
||||
tempStream.Write(data, 0, data.Length);
|
||||
}
|
||||
|
||||
// Collect and format all found protections
|
||||
var protections = scanner.GetProtections(tempPath);
|
||||
|
||||
// If temp directory cleanup fails
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
// Remove temporary path references
|
||||
StripFromKeys(protections, tempPath);
|
||||
|
||||
return protections;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -433,6 +433,14 @@ namespace BurnOutSharp
|
||||
AppendToDictionary(protections, subProtections);
|
||||
}
|
||||
|
||||
// Microsoft LZ
|
||||
if (fileName != null && scannable is MicrosoftLZ)
|
||||
{
|
||||
var subProtections = scannable.Scan(this, fileName);
|
||||
PrependToKeys(subProtections, fileName);
|
||||
AppendToDictionary(protections, subProtections);
|
||||
}
|
||||
|
||||
// MSI
|
||||
if (fileName != null && scannable is MSI)
|
||||
{
|
||||
|
||||
@@ -120,6 +120,13 @@ namespace BurnOutSharp.Tools
|
||||
|
||||
#endregion
|
||||
|
||||
#region MicrosoftLZ
|
||||
|
||||
if (magic.StartsWith(new byte?[] { 0x53, 0x5a, 0x44, 0x44, 0x88, 0xf0, 0x27, 0x33 }))
|
||||
return SupportedFileType.MicrosoftLZ;
|
||||
|
||||
#endregion
|
||||
|
||||
#region MPQ
|
||||
|
||||
if (magic.StartsWith(new byte?[] { 0x4d, 0x50, 0x51, 0x1a }))
|
||||
@@ -633,6 +640,7 @@ namespace BurnOutSharp.Tools
|
||||
case SupportedFileType.InstallShieldArchiveV3: return new FileType.InstallShieldArchiveV3();
|
||||
case SupportedFileType.InstallShieldCAB: return new FileType.InstallShieldCAB();
|
||||
case SupportedFileType.MicrosoftCAB: return new FileType.MicrosoftCAB();
|
||||
case SupportedFileType.MicrosoftLZ: return new FileType.MicrosoftLZ();
|
||||
case SupportedFileType.MPQ: return new FileType.MPQ();
|
||||
case SupportedFileType.MSI: return new FileType.MSI();
|
||||
case SupportedFileType.PAK: return new FileType.PAK();
|
||||
|
||||
@@ -158,6 +158,7 @@ Below is a list of container formats that are supported in some way:
|
||||
| InstallShield CAB | No | Yes | Yes | Via `UnshieldSharp` |
|
||||
| Linear Executable | No | No | No | Skeleton only |
|
||||
| Microsoft cabinet file | Yes | Yes | Yes | Via `WixToolset.Dtf` / ~~`LibMSPackSharp`~~ (Currently disabled) |
|
||||
| Microsoft LZ-compressed files | No | Yes | Yes | |
|
||||
| MoPaQ game data archive (MPQ) | No | Yes | Yes | Via `StormLibSharp` |
|
||||
| Microsoft installation package (MSI) | No | Yes | Yes | Via `OpenMcdf` |
|
||||
| MS-DOS Executable | Yes | Yes | No | Incomplete |
|
||||
|
||||
Reference in New Issue
Block a user