mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-07-08 18:06:34 +00:00
Overhaul BD+ to model/builder/wrapper
This commit is contained in:
95
BurnOutSharp.Builders/BDPlus.cs
Normal file
95
BurnOutSharp.Builders/BDPlus.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using BurnOutSharp.Models.BDPlus;
|
||||
using BurnOutSharp.Utilities;
|
||||
using static BurnOutSharp.Models.BDPlus.Constants;
|
||||
|
||||
namespace BurnOutSharp.Builders
|
||||
{
|
||||
public class BDPlus
|
||||
{
|
||||
#region Byte Data
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a BD+ SVM
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>Filled BD+ SVM on success, null on error</returns>
|
||||
public static SVM ParseSVM(byte[] data, int offset)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
// If the offset is out of bounds
|
||||
if (offset < 0 || offset >= data.Length)
|
||||
return null;
|
||||
|
||||
// Create a memory stream and parse that
|
||||
MemoryStream dataStream = new MemoryStream(data, offset, data.Length - offset);
|
||||
return ParseSVM(dataStream);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stream Data
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into an BD+ SVM
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled BD+ SVM on success, null on error</returns>
|
||||
public static SVM ParseSVM(Stream data)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead)
|
||||
return null;
|
||||
|
||||
// If the offset is out of bounds
|
||||
if (data.Position < 0 || data.Position >= data.Length)
|
||||
return null;
|
||||
|
||||
// Cache the current offset
|
||||
int initialOffset = (int)data.Position;
|
||||
|
||||
// Try to parse the SVM
|
||||
return ParseSVMData(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into an SVM
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled SVM on success, null on error</returns>
|
||||
private static SVM ParseSVMData(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var svm = new SVM();
|
||||
|
||||
byte[] signature = data.ReadBytes(8);
|
||||
svm.Signature = Encoding.ASCII.GetString(signature);
|
||||
if (svm.Signature != SignatureString)
|
||||
return null;
|
||||
|
||||
svm.Unknown1 = data.ReadBytes(5);
|
||||
svm.Year = data.ReadUInt16BE();
|
||||
svm.Month = data.ReadByteValue();
|
||||
if (svm.Month < 1 || svm.Month > 12)
|
||||
return null;
|
||||
|
||||
svm.Day = data.ReadByteValue();
|
||||
if (svm.Day < 1 || svm.Day > 31)
|
||||
return null;
|
||||
|
||||
svm.Unknown2 = data.ReadBytes(4);
|
||||
svm.Length = data.ReadUInt32();
|
||||
// if (svm.Length > 0)
|
||||
// svm.Data = data.ReadBytes((int)svm.Length);
|
||||
|
||||
return svm;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
7
BurnOutSharp.Models/BDPlus/Constants.cs
Normal file
7
BurnOutSharp.Models/BDPlus/Constants.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace BurnOutSharp.Models.BDPlus
|
||||
{
|
||||
public static class Constants
|
||||
{
|
||||
public const string SignatureString = "BDSVM_CC";
|
||||
}
|
||||
}
|
||||
46
BurnOutSharp.Models/BDPlus/SVM.cs
Normal file
46
BurnOutSharp.Models/BDPlus/SVM.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
namespace BurnOutSharp.Models.BDPlus
|
||||
{
|
||||
/// <see href="https://github.com/mwgoldsmith/bdplus/blob/master/src/libbdplus/bdsvm/loader.c"/>
|
||||
public sealed class SVM
|
||||
{
|
||||
/// <summary>
|
||||
/// "BDSVM_CC"
|
||||
/// </summary>
|
||||
public string Signature;
|
||||
|
||||
/// <summary>
|
||||
/// 5 bytes of unknown data
|
||||
/// </summary>
|
||||
public byte[] Unknown1;
|
||||
|
||||
/// <summary>
|
||||
/// Version year
|
||||
/// </summary>
|
||||
public ushort Year;
|
||||
|
||||
/// <summary>
|
||||
/// Version month
|
||||
/// </summary>
|
||||
public byte Month;
|
||||
|
||||
/// <summary>
|
||||
/// Version day
|
||||
/// </summary>
|
||||
public byte Day;
|
||||
|
||||
/// <summary>
|
||||
/// 4 bytes of unknown data
|
||||
/// </summary>
|
||||
public byte[] Unknown2;
|
||||
|
||||
/// <summary>
|
||||
/// Length
|
||||
/// </summary>
|
||||
public uint Length;
|
||||
|
||||
/// <summary>
|
||||
/// Length bytes of data
|
||||
/// </summary>
|
||||
public byte[] Data;
|
||||
}
|
||||
}
|
||||
131
BurnOutSharp.Wrappers/BDPlusSVM.cs
Normal file
131
BurnOutSharp.Wrappers/BDPlusSVM.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace BurnOutSharp.Wrappers
|
||||
{
|
||||
public class BDPlusSVM : WrapperBase
|
||||
{
|
||||
#region Pass-Through Properties
|
||||
|
||||
/// <inheritdoc cref="Models.BDPlus.SVM.Signature"/>
|
||||
public string Signature => _svm.Signature;
|
||||
|
||||
/// <inheritdoc cref="Models.BDPlus.SVM.Unknown1"/>
|
||||
public byte[] Unknown1 => _svm.Unknown1;
|
||||
|
||||
/// <inheritdoc cref="Models.BDPlus.SVM.Year"/>
|
||||
public ushort Year => _svm.Year;
|
||||
|
||||
/// <inheritdoc cref="Models.BDPlus.SVM.Month"/>
|
||||
public byte Month => _svm.Month;
|
||||
|
||||
/// <inheritdoc cref="Models.BDPlus.SVM.Day"/>
|
||||
public byte Day => _svm.Day;
|
||||
|
||||
/// <inheritdoc cref="Models.BDPlus.SVM.Unknown2"/>
|
||||
public byte[] Unknown2 => _svm.Unknown2;
|
||||
|
||||
/// <inheritdoc cref="Models.BDPlus.SVM.Length"/>
|
||||
public uint Length => _svm.Length;
|
||||
|
||||
/// <inheritdoc cref="Models.BDPlus.SVM.Data"/>
|
||||
public byte[] Data => _svm.Data;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Instance Variables
|
||||
|
||||
/// <summary>
|
||||
/// Internal representation of the SVM
|
||||
/// </summary>
|
||||
private Models.BDPlus.SVM _svm;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Private constructor
|
||||
/// </summary>
|
||||
private BDPlusSVM() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a BD+ SVM from a byte array and offset
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array representing the archive</param>
|
||||
/// <param name="offset">Offset within the array to parse</param>
|
||||
/// <returns>A BD+ SVM wrapper on success, null on failure</returns>
|
||||
public static BDPlusSVM Create(byte[] data, int offset)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
// If the offset is out of bounds
|
||||
if (offset < 0 || offset >= data.Length)
|
||||
return null;
|
||||
|
||||
// Create a memory stream and use that
|
||||
MemoryStream dataStream = new MemoryStream(data, offset, data.Length - offset);
|
||||
return Create(dataStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a BD+ SVM from a Stream
|
||||
/// </summary>
|
||||
/// <param name="data">Stream representing the archive</param>
|
||||
/// <returns>A BD+ SVM wrapper on success, null on failure</returns>
|
||||
public static BDPlusSVM Create(Stream data)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead)
|
||||
return null;
|
||||
|
||||
var svm = Builders.BDPlus.ParseSVM(data);
|
||||
if (svm == null)
|
||||
return null;
|
||||
|
||||
var wrapper = new BDPlusSVM
|
||||
{
|
||||
_svm = svm,
|
||||
_dataSource = DataSource.Stream,
|
||||
_streamData = data,
|
||||
};
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Printing
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Print()
|
||||
{
|
||||
Console.WriteLine("BD+ Information:");
|
||||
Console.WriteLine("-------------------------");
|
||||
Console.WriteLine();
|
||||
|
||||
PrintSVM();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Print SVM information
|
||||
/// </summary>
|
||||
private void PrintSVM()
|
||||
{
|
||||
Console.WriteLine(" SVM Information:");
|
||||
Console.WriteLine(" -------------------------");
|
||||
Console.WriteLine($" Signature: {Signature}");
|
||||
Console.WriteLine($" Unknown 1: {BitConverter.ToString(Unknown1).Replace('-', ' ')}");
|
||||
Console.WriteLine($" Year: {Year} (0x{Year:X})");
|
||||
Console.WriteLine($" Month: {Month} (0x{Month:X})");
|
||||
Console.WriteLine($" Day: {Day} (0x{Day:X})");
|
||||
Console.WriteLine($" Unknown 2: {BitConverter.ToString(Unknown2).Replace('-', ' ')}");
|
||||
Console.WriteLine($" Length: {Length} (0x{Length:X})");
|
||||
//Console.WriteLine($" Data: {BitConverter.ToString(Data ?? new byte[0]).Replace('-', ' ')}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,11 @@
|
||||
/// </summary>
|
||||
AACSMediaKeyBlock,
|
||||
|
||||
/// <summary>
|
||||
/// BD+ SVM
|
||||
/// </summary>
|
||||
BDPlusSVM,
|
||||
|
||||
/// <summary>
|
||||
/// BFPK custom archive
|
||||
/// </summary>
|
||||
|
||||
58
BurnOutSharp/FileType/BDPlusSVM.cs
Normal file
58
BurnOutSharp/FileType/BDPlusSVM.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Interfaces;
|
||||
|
||||
namespace BurnOutSharp.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// BD+ SVM
|
||||
/// </summary>
|
||||
public class BDPlusSVM : 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 MKB file itself fails
|
||||
try
|
||||
{
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
// Create the wrapper
|
||||
Wrappers.BDPlusSVM svm = Wrappers.BDPlusSVM.Create(stream);
|
||||
if (svm == null)
|
||||
return null;
|
||||
|
||||
// Setup the output
|
||||
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
|
||||
protections[file] = new ConcurrentQueue<string>();
|
||||
|
||||
// Format the date
|
||||
string date = $"{svm.Year:0000}/{svm.Month:00}/{svm.Day:00}";
|
||||
|
||||
// Add and return the protection
|
||||
protections[file].Enqueue($"BD+ {date}");
|
||||
return protections;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class BDPlus : IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet(new List<string>
|
||||
{
|
||||
Path.Combine("BDSVM", "00000.svm").Replace("\\", "/"),
|
||||
Path.Combine("BDSVM", "BACKUP", "00000.svm").Replace("\\", "/"),
|
||||
}, GetVersion, "BD+"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckFilePath(string path)
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet(new PathMatch("00000.svm", useEndsWith: true), GetVersion, "BD+"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(path, matchers, any: true);
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// Version detection logic from libbdplus was used to implement this
|
||||
/// </remarks>
|
||||
public static string GetVersion(string firstMatchedString, IEnumerable<string> files)
|
||||
{
|
||||
if (!File.Exists(firstMatchedString))
|
||||
return "(Unknown Version)";
|
||||
|
||||
try
|
||||
{
|
||||
using (var fs = File.OpenRead(firstMatchedString))
|
||||
{
|
||||
fs.Seek(0x0D, SeekOrigin.Begin);
|
||||
byte[] date = new byte[4];
|
||||
fs.Read(date, 0, 4); //yymd
|
||||
short year = BitConverter.ToInt16(date.Reverse().ToArray(), 2);
|
||||
|
||||
// Do some rudimentary date checking
|
||||
if (year < 2006 || year > 2100 || date[2] < 1 || date[2] > 12 || date[3] < 1 || date[3] > 31)
|
||||
return "(Invalid Version)";
|
||||
|
||||
return $"{year:0000}/{date[2]:00}/{date[3]:00}";
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "(Unknown Version)";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,6 +359,13 @@ namespace BurnOutSharp
|
||||
AppendToDictionary(protections, subProtections);
|
||||
}
|
||||
|
||||
// BD+ SVM
|
||||
if (scannable is BDPlusSVM)
|
||||
{
|
||||
var subProtections = scannable.Scan(this, stream, fileName);
|
||||
AppendToDictionary(protections, subProtections);
|
||||
}
|
||||
|
||||
// Executable
|
||||
if (scannable is Executable)
|
||||
{
|
||||
|
||||
@@ -34,6 +34,13 @@ namespace BurnOutSharp.Tools
|
||||
|
||||
#endregion
|
||||
|
||||
#region BDPlusSVM
|
||||
|
||||
if (magic.StartsWith(new byte?[] { 0x42, 0x44, 0x53, 0x56, 0x4D, 0x5F, 0x43, 0x43 }))
|
||||
return SupportedFileType.BDPlusSVM;
|
||||
|
||||
#endregion
|
||||
|
||||
#region BFPK
|
||||
|
||||
if (magic.StartsWith(new byte?[] { 0x42, 0x46, 0x50, 0x4b }))
|
||||
@@ -369,6 +376,13 @@ namespace BurnOutSharp.Tools
|
||||
|
||||
#endregion
|
||||
|
||||
#region BDPlusSVM
|
||||
|
||||
if (extension.Equals(value: "svm", StringComparison.OrdinalIgnoreCase))
|
||||
return SupportedFileType.BDPlusSVM;
|
||||
|
||||
#endregion
|
||||
|
||||
#region BFPK
|
||||
|
||||
// No extensions registered for BFPK
|
||||
@@ -757,6 +771,7 @@ namespace BurnOutSharp.Tools
|
||||
switch (fileType)
|
||||
{
|
||||
case SupportedFileType.AACSMediaKeyBlock: return new FileType.AACSMediaKeyBlock();
|
||||
case SupportedFileType.BDPlusSVM: return new FileType.BDPlusSVM();
|
||||
case SupportedFileType.BFPK: return new FileType.BFPK();
|
||||
case SupportedFileType.BSP: return new FileType.BSP();
|
||||
case SupportedFileType.BZip2: return new FileType.BZip2();
|
||||
|
||||
@@ -18,6 +18,7 @@ The following projects have influenced this library:
|
||||
|
||||
- [BurnOut](http://burnout.sourceforge.net/) - Project that this library was initially based on. The only thing left from that original port is in the name of the library. This project is fully unaffiliated with the original BurnOut and its authors.
|
||||
- [HLLibSharp](https://github.com/mnadareski/HLLibSharp) - Documentation around Valve package handling, including extraction.
|
||||
- [libbdplus](https://www.videolan.org/developers/libbdplus.html) - Documentation around the BD+ SVM files.
|
||||
- [libmspack](https://github.com/kyz/libmspack) - Documentation around the MS-CAB format and associated compression methods.
|
||||
- [NDecrypt](https://github.com/SabreTools/NDecrypt) - NDS (Nitro) and 3DS cart image file layouts and documentation, though not encrypt/decrypt.
|
||||
|
||||
@@ -31,12 +32,10 @@ Below is a list of protections detected by BurnOutSharp. The two columns explain
|
||||
| --------------- | ------------- | ---------- | ----- |
|
||||
| 3PLock | True | False | |
|
||||
| 321Studios Online Activation | True | False | |
|
||||
| AACS | False | True | BluRay and HD-DVD variants detected |
|
||||
| ActiveMARK | True | False | Version 5 unconfirmed²; version finding incomplete |
|
||||
| AegiSoft License Manager | True | True | |
|
||||
| Alpha-DVD | False | True | Unconfirmed¹ |
|
||||
| Alpha-ROM | True | False | |
|
||||
| BD+ | False | True | |
|
||||
| Bitpool | False | True | |
|
||||
| ByteShield | True | True | |
|
||||
| C-Dilla License Management Solution / CD-Secure / CD-Compress | True | True | |
|
||||
@@ -154,6 +153,8 @@ Below is a list of container formats that are supported in some way:
|
||||
| Format Name | Information Printing | Detection | Extraction | Notes |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 7-zip archive | No | Yes | Yes | Via `SharpCompress` |
|
||||
| AACS Media Key Block | Yes | Yes | N/A | BluRay and HD-DVD variants detected |
|
||||
| BD+ SVM | Yes | Yes | N/A | |
|
||||
| BFPK custom archive format | Yes | Yes | Yes | |
|
||||
| bzip2 archive | No | Yes | Yes | Via `SharpCompress` |
|
||||
| Compound File Binary (CFB) | Yes* | Yes | Yes | Via `OpenMcdf`, only CFB common pieces printable |
|
||||
|
||||
@@ -164,6 +164,25 @@ namespace Test
|
||||
mkb.Print();
|
||||
}
|
||||
|
||||
// BD+ SVM
|
||||
else if (ft == SupportedFileType.BDPlusSVM)
|
||||
{
|
||||
// Build the BD+ SVM information
|
||||
Console.WriteLine("Creating BD+ SVM deserializer");
|
||||
Console.WriteLine();
|
||||
|
||||
var svm = BDPlusSVM.Create(stream);
|
||||
if (svm == null)
|
||||
{
|
||||
Console.WriteLine("Something went wrong parsing BD+ SVM");
|
||||
Console.WriteLine();
|
||||
return;
|
||||
}
|
||||
|
||||
// Print the BD+ SVM info to screen
|
||||
svm.Print();
|
||||
}
|
||||
|
||||
// BFPK archive
|
||||
else if (ft == SupportedFileType.BFPK)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user