mirror of
https://github.com/SabreTools/MPF.git
synced 2026-07-02 17:24:48 +00:00
Attempt to more accurately parse layerbreaks
This commit is contained in:
@@ -36,6 +36,7 @@
|
||||
- Support single digit subs
|
||||
- Fix info tool hash finding
|
||||
- Fix missing size for ISO data
|
||||
- Attempt to more accurately parse layerbreaks
|
||||
|
||||
### 2.5 (2023-03-12)
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
/// <summary>
|
||||
/// Should be 0x00
|
||||
/// </summary>
|
||||
public byte Reserved2 { get; set; }
|
||||
public byte Reserved0 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// DI unit Sequence Number
|
||||
@@ -42,7 +42,7 @@
|
||||
/// <summary>
|
||||
/// Should be 0x00
|
||||
/// </summary>
|
||||
public byte Reserved3 { get; set; }
|
||||
public byte Reserved1 { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1160,6 +1160,126 @@ namespace MPF.Modules
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets disc information from a PIC file
|
||||
/// </summary>
|
||||
/// <param name="pic">Path to a PIC.bin file</param>
|
||||
/// <returns>Filled PICDiscInformation on success, null on error</returns>
|
||||
/// <remarks>This omits the emergency brake information, if it exists</remarks>
|
||||
protected static PICDiscInformation GetDiscInformation(string pic)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(File.OpenRead(pic)))
|
||||
{
|
||||
var di = new PICDiscInformation();
|
||||
|
||||
// Read the initial disc information
|
||||
di.DataStructureLength = br.ReadUInt16BigEndian();
|
||||
di.Reserved0 = br.ReadByte();
|
||||
di.Reserved1 = br.ReadByte();
|
||||
|
||||
// Create a list for the units
|
||||
var diUnits = new List<PICDiscInformationUnit>();
|
||||
|
||||
// Loop and read all available units
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
var unit = new PICDiscInformationUnit();
|
||||
|
||||
// We only accept Disc Information units, not Emergency Brake or other
|
||||
unit.DiscInformationIdentifier = Encoding.ASCII.GetString(br.ReadBytes(2));
|
||||
if (unit.DiscInformationIdentifier != "DI")
|
||||
break;
|
||||
|
||||
unit.DiscInformationFormat = br.ReadByte();
|
||||
unit.NumberOfUnitsInBlock = br.ReadByte();
|
||||
unit.Reserved0 = br.ReadByte();
|
||||
unit.SequenceNumber = br.ReadByte();
|
||||
unit.BytesInUse = br.ReadByte();
|
||||
unit.Reserved1 = br.ReadByte();
|
||||
|
||||
unit.DiscTypeIdentifier = Encoding.ASCII.GetString(br.ReadBytes(3));
|
||||
unit.DiscSizeClassVersion = br.ReadByte();
|
||||
switch (unit.DiscTypeIdentifier)
|
||||
{
|
||||
case PICDiscInformationUnit.DiscTypeIdentifierROM:
|
||||
unit.FormatDependentContents = br.ReadBytes(52);
|
||||
break;
|
||||
case PICDiscInformationUnit.DiscTypeIdentifierReWritable:
|
||||
case PICDiscInformationUnit.DiscTypeIdentifierRecordable:
|
||||
unit.FormatDependentContents = br.ReadBytes(100);
|
||||
unit.DiscManufacturerID = br.ReadBytes(6);
|
||||
unit.MediaTypeID = br.ReadBytes(3);
|
||||
unit.TimeStamp = br.ReadUInt16();
|
||||
unit.ProductRevisionNumber = br.ReadByte();
|
||||
break;
|
||||
}
|
||||
|
||||
diUnits.Add(unit);
|
||||
}
|
||||
|
||||
// Assign the units and return
|
||||
di.Units = diUnits.ToArray();
|
||||
return di;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error was
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the layerbreak info associated from the disc information
|
||||
/// </summary>
|
||||
/// <param name="di">Disc information containing unformatted data</param>
|
||||
/// <returns>True if layerbreak info was set, false otherwise</returns>
|
||||
protected static bool GetLayerbreaks(PICDiscInformation di, out long? layerbreak1, out long? layerbreak2, out long? layerbreak3)
|
||||
{
|
||||
// Set the default values
|
||||
layerbreak1 = null; layerbreak2 = null; layerbreak3 = null;
|
||||
|
||||
// If we don't have valid disc information, we can't do anything
|
||||
if (di?.Units == null || di.Units.Length <= 1)
|
||||
return false;
|
||||
|
||||
int ReadFromArrayBigEndian(byte[] bytes, int offset)
|
||||
{
|
||||
var span = new ReadOnlySpan<byte>(bytes, offset, 0x04);
|
||||
byte[] rev = span.ToArray();
|
||||
Array.Reverse(rev);
|
||||
return BitConverter.ToInt32(rev, 0);
|
||||
}
|
||||
|
||||
// Layerbreak 1 (2+ layers)
|
||||
if (di.Units.Length >= 2)
|
||||
{
|
||||
long offset = ReadFromArrayBigEndian(di.Units[0].FormatDependentContents, 0x0C);
|
||||
long value = ReadFromArrayBigEndian(di.Units[0].FormatDependentContents, 0x10);
|
||||
layerbreak1 = value - offset + 2;
|
||||
}
|
||||
|
||||
// Layerbreak 2 (3+ layers)
|
||||
if (di.Units.Length >= 3)
|
||||
{
|
||||
long offset = ReadFromArrayBigEndian(di.Units[1].FormatDependentContents, 0x0C);
|
||||
long value = ReadFromArrayBigEndian(di.Units[1].FormatDependentContents, 0x10);
|
||||
layerbreak2 = layerbreak1 + value - offset + 2;
|
||||
}
|
||||
|
||||
// Layerbreak 3 (4 layers)
|
||||
if (di.Units.Length >= 4)
|
||||
{
|
||||
long offset = ReadFromArrayBigEndian(di.Units[2].FormatDependentContents, 0x0C);
|
||||
long value = ReadFromArrayBigEndian(di.Units[2].FormatDependentContents, 0x10);
|
||||
layerbreak3 = layerbreak2 + value - offset + 2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input file path
|
||||
/// </summary>
|
||||
|
||||
@@ -461,7 +461,8 @@ namespace MPF.Modules.DiscImageCreator
|
||||
}
|
||||
else if (this.Type == MediaType.BluRay)
|
||||
{
|
||||
if (GetLayerbreak($"{basePath}_PIC.bin", out long? layerbreak1, out long? layerbreak2, out long? layerbreak3))
|
||||
var di = GetDiscInformation($"{basePath}_PIC.bin");
|
||||
if (GetLayerbreaks(di, out long? layerbreak1, out long? layerbreak2, out long? layerbreak3))
|
||||
{
|
||||
if (layerbreak1 != null && layerbreak1 * 2048 < info.SizeAndChecksums.Size)
|
||||
info.SizeAndChecksums.Layerbreak = layerbreak1.Value;
|
||||
@@ -2978,79 +2979,6 @@ namespace MPF.Modules.DiscImageCreator
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the layerbreak info associated with the dump
|
||||
/// </summary>
|
||||
/// <param name="picPath">Path to the PIC.bin file associated with the dump</param>
|
||||
/// <returns>True if layerbreak info was set, false otherwise</returns>
|
||||
/// <remarks>https://stackoverflow.com/questions/9932096/add-separator-to-string-at-every-n-characters</remarks>
|
||||
private static bool GetLayerbreak(string picPath, out long? layerbreak1, out long? layerbreak2, out long? layerbreak3)
|
||||
{
|
||||
// Set the default values
|
||||
layerbreak1 = null; layerbreak2 = null; layerbreak3 = null;
|
||||
|
||||
// If the file doesn't exist, we can't get the info
|
||||
if (!File.Exists(picPath))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(File.OpenRead(picPath)))
|
||||
{
|
||||
// Disc type
|
||||
int infoLength;
|
||||
br.BaseStream.Seek(0x0C, SeekOrigin.Begin);
|
||||
string identifier = Encoding.ASCII.GetString(br.ReadBytes(3));
|
||||
switch (identifier)
|
||||
{
|
||||
case "BDO":
|
||||
infoLength = 0x40;
|
||||
break;
|
||||
case "BDW":
|
||||
case "BDR":
|
||||
infoLength = 0x74;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// Layerbreak 1
|
||||
br.BaseStream.Seek((0 * infoLength) + 0x1C, SeekOrigin.Begin);
|
||||
long layerbreak1Offset = br.ReadInt32BigEndian();
|
||||
long layerbreak1Value = br.ReadInt32BigEndian();
|
||||
if (layerbreak1Value == 0)
|
||||
return false;
|
||||
|
||||
layerbreak1 = layerbreak1Value - layerbreak1Offset + 2;
|
||||
|
||||
// Layerbreak 2
|
||||
br.BaseStream.Seek((1 * infoLength) + 0x1C, SeekOrigin.Begin);
|
||||
long layerbreak2Offset = br.ReadInt32BigEndian();
|
||||
long layerbreak2Value = br.ReadInt32BigEndian();
|
||||
if (layerbreak2Value == 0)
|
||||
return true;
|
||||
|
||||
layerbreak2 = layerbreak1 + layerbreak2Value - layerbreak2Offset + 2;
|
||||
|
||||
// Layerbreak 3
|
||||
br.BaseStream.Seek((2 * infoLength) + 0x1C, SeekOrigin.Begin);
|
||||
long layerbreak3Offset = br.ReadInt32BigEndian();
|
||||
long layerbreak3Value = br.ReadInt32BigEndian();
|
||||
if (layerbreak3Value == 0)
|
||||
return true;
|
||||
|
||||
layerbreak3 = layerbreak2 + layerbreak3Value - layerbreak3Offset + 2;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error was
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get multisession information from the input file, if possible
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user