mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-07-08 18:06:41 +00:00
218 lines
9.2 KiB
C#
218 lines
9.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
using SabreTools.Data.Models.XDVDFS;
|
|
using SabreTools.Numerics.Extensions;
|
|
using SabreTools.Text.Extensions;
|
|
|
|
namespace SabreTools.Wrappers
|
|
{
|
|
public partial class XDVDFS : IPrintable
|
|
{
|
|
#region Printing State
|
|
|
|
/// <summary>
|
|
/// List of printed embedded files by their sector offset
|
|
/// </summary>
|
|
private readonly HashSet<uint> _printedFiles = [];
|
|
|
|
#endregion
|
|
|
|
#if NETCOREAPP
|
|
/// <inheritdoc/>
|
|
public string ExportJSON(bool recursive) => System.Text.Json.JsonSerializer.Serialize(Model, _jsonSerializerOptions);
|
|
#else
|
|
/// <inheritdoc/>
|
|
public string ExportJSON(bool recursive) => Newtonsoft.Json.JsonConvert.SerializeObject(Model, _jsonSerializerOptions);
|
|
#endif
|
|
|
|
/// <inheritdoc/>
|
|
public void PrintInformation(StringBuilder builder, bool recursive)
|
|
{
|
|
_printedFiles.Clear();
|
|
|
|
builder.AppendLine("Xbox DVD Filesystem Information:");
|
|
builder.AppendLine("-------------------------");
|
|
builder.AppendLine();
|
|
|
|
Print(builder, Model.ReservedArea);
|
|
Print(builder, Model.VolumeDescriptor);
|
|
|
|
if (Model.LayoutDescriptor is not null)
|
|
Print(builder, Model.LayoutDescriptor);
|
|
|
|
foreach (var kvp in Model.DirectoryDescriptors)
|
|
{
|
|
Print(builder, kvp.Value, kvp.Key);
|
|
}
|
|
|
|
if (recursive)
|
|
{
|
|
long initialOffset = _dataSource.Position;
|
|
RecursivePrint(builder, Model.VolumeDescriptor.RootOffset, "\\", initialOffset);
|
|
}
|
|
}
|
|
|
|
private void RecursivePrint(StringBuilder builder, uint sectorNumber, string filePath, long initialOffset)
|
|
{
|
|
if (!Model.DirectoryDescriptors.TryGetValue(sectorNumber, out DirectoryDescriptor? dd))
|
|
return;
|
|
|
|
foreach (DirectoryRecord dr in dd.DirectoryRecords)
|
|
{
|
|
string filename = Encoding.UTF8.GetString(dr.Filename);
|
|
string path = Path.Combine(filePath, filename);
|
|
|
|
// Skip already printed files
|
|
if (_printedFiles.Contains(dr.ExtentOffset))
|
|
continue;
|
|
|
|
// Recurse into directory
|
|
if ((dr.FileFlags & FileFlags.DIRECTORY) == FileFlags.DIRECTORY)
|
|
{
|
|
// Add directory extent before recursing
|
|
_printedFiles.Add(dr.ExtentOffset);
|
|
|
|
RecursivePrint(builder, dr.ExtentOffset, path, initialOffset);
|
|
continue;
|
|
}
|
|
|
|
// Parse embedded file
|
|
try
|
|
{
|
|
_dataSource.Seek(initialOffset + (Constants.SectorSize * dr.ExtentOffset), SeekOrigin.Begin);
|
|
|
|
byte[] magic = _dataSource.PeekBytes(16);
|
|
string extension = Path.GetExtension(filename).TrimStart('.');
|
|
|
|
WrapperType ft = WrapperFactory.GetFileType(magic, extension);
|
|
var wrapper = WrapperFactory.CreateWrapper(ft, _dataSource);
|
|
if (wrapper is null || wrapper is not IPrintable printable)
|
|
continue;
|
|
|
|
// Print info for embedded file
|
|
builder.AppendLine($"Information for {path}");
|
|
builder.AppendLine("-------------------------");
|
|
printable.PrintInformation(builder, true);
|
|
|
|
_printedFiles.Add(dr.ExtentOffset);
|
|
}
|
|
catch
|
|
{
|
|
// Ignore the actual error
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void Print(StringBuilder builder, byte[] reservedArea)
|
|
{
|
|
if (reservedArea.Length == 0)
|
|
builder.AppendLine(reservedArea, " Reserved Area");
|
|
else if (Array.TrueForAll(reservedArea, b => b == 0))
|
|
builder.AppendLine("Zeroed", " Reserved Area");
|
|
else
|
|
builder.AppendLine("Not Zeroed", " Reserved Area");
|
|
builder.AppendLine();
|
|
}
|
|
|
|
internal static void Print(StringBuilder builder, VolumeDescriptor vd)
|
|
{
|
|
builder.AppendLine(" Volume Descriptor:");
|
|
builder.AppendLine(" -------------------------");
|
|
|
|
builder.AppendLine(Encoding.ASCII.GetString(vd.StartSignature), " Start Signature");
|
|
builder.AppendLine(vd.RootOffset, " Root Offset");
|
|
builder.AppendLine(vd.RootSize, " Root Size");
|
|
DateTime datetime = DateTime.FromFileTime(vd.MasteringTimestamp);
|
|
builder.AppendLine(datetime.ToString("yyyy-MM-dd HH:mm:ss"), " Mastering Timestamp");
|
|
builder.AppendLine(vd.UnknownByte, " Unknown Byte");
|
|
if (Array.TrueForAll(vd.Reserved, b => b == 0))
|
|
builder.AppendLine("Zeroed", " Reserved Bytes");
|
|
else
|
|
builder.AppendLine("Not Zeroed", " Reserved Bytes");
|
|
builder.AppendLine(Encoding.ASCII.GetString(vd.EndSignature), " End Signature");
|
|
|
|
builder.AppendLine();
|
|
}
|
|
|
|
internal static void Print(StringBuilder builder, LayoutDescriptor ld)
|
|
{
|
|
builder.AppendLine(" Xbox DVD Layout Descriptor:");
|
|
builder.AppendLine(" -------------------------");
|
|
|
|
builder.AppendLine(Encoding.ASCII.GetString(ld.Signature), " Signature");
|
|
builder.AppendLine(ld.Unused8Bytes, " Unusued 8 Bytes");
|
|
builder.AppendLine(GetVersionString(ld.XBLayoutVersion), " xblayout Version");
|
|
builder.AppendLine(GetVersionString(ld.XBPremasterVersion), " xbpremaster Version");
|
|
builder.AppendLine(GetVersionString(ld.XBGameDiscVersion), " xbgamedisc Version");
|
|
builder.AppendLine(GetVersionString(ld.XBOther1Version), " Unknown Tool 1 Version");
|
|
builder.AppendLine(GetVersionString(ld.XBOther2Version), " Unknown Tool 2 Version");
|
|
builder.AppendLine(GetVersionString(ld.XBOther3Version), " Unknown Tool 2 Version");
|
|
if (Array.TrueForAll(ld.Reserved, b => b == 0))
|
|
builder.AppendLine("Zeroed", " Reserved Bytes");
|
|
else
|
|
builder.AppendLine("Not Zeroed", " Reserved Bytes");
|
|
|
|
builder.AppendLine();
|
|
}
|
|
|
|
private static string GetVersionString(FourPartVersionType ver)
|
|
{
|
|
return $"{ver.Major}.{ver.Minor}.{ver.Build}.{ver.Revision}";
|
|
}
|
|
|
|
internal static void Print(StringBuilder builder, DirectoryDescriptor dd, uint sectorNumber)
|
|
{
|
|
builder.AppendLine($" Directory Descriptor (Sector {sectorNumber}):");
|
|
builder.AppendLine(" -------------------------");
|
|
|
|
foreach (DirectoryRecord dr in dd.DirectoryRecords)
|
|
Print(builder, dr);
|
|
|
|
if (dd.Padding is null)
|
|
builder.AppendLine("None", " Padding");
|
|
else if (Array.TrueForAll(dd.Padding, b => b == 0xFF))
|
|
builder.AppendLine("All 0xFF", " Padding");
|
|
else
|
|
builder.AppendLine("Not all 0xFF", " Padding");
|
|
|
|
builder.AppendLine();
|
|
}
|
|
|
|
private static void Print(StringBuilder builder, DirectoryRecord dr)
|
|
{
|
|
builder.AppendLine($" Directory Record:");
|
|
builder.AppendLine(" -------------------------");
|
|
|
|
builder.AppendLine(dr.LeftChildOffset, " Left Child Offset");
|
|
builder.AppendLine(dr.RightChildOffset, " Right Child Offset");
|
|
builder.AppendLine(dr.ExtentOffset, " Extent Offset");
|
|
builder.AppendLine(dr.ExtentSize, " Extent Size");
|
|
|
|
builder.AppendLine(" File Flags:");
|
|
builder.AppendLine((dr.FileFlags & FileFlags.READ_ONLY) == FileFlags.READ_ONLY, " Read-only");
|
|
builder.AppendLine((dr.FileFlags & FileFlags.HIDDEN) == FileFlags.HIDDEN, " Hidden");
|
|
builder.AppendLine((dr.FileFlags & FileFlags.SYSTEM) == FileFlags.SYSTEM, " System");
|
|
builder.AppendLine((dr.FileFlags & FileFlags.VOLUME_ID) == FileFlags.VOLUME_ID, " Volume ID");
|
|
builder.AppendLine((dr.FileFlags & FileFlags.DIRECTORY) == FileFlags.DIRECTORY, " Directory");
|
|
builder.AppendLine((dr.FileFlags & FileFlags.ARCHIVE) == FileFlags.ARCHIVE, " Archive");
|
|
builder.AppendLine((dr.FileFlags & FileFlags.DEVICE) == FileFlags.DEVICE, " Device");
|
|
builder.AppendLine((dr.FileFlags & FileFlags.NORMAL) == FileFlags.NORMAL, " Normal");
|
|
|
|
builder.AppendLine(dr.FilenameLength, " Filename Length");
|
|
builder.AppendLine(Encoding.UTF8.GetString(dr.Filename), " Filename");
|
|
|
|
if (dr.Padding is null)
|
|
builder.AppendLine("None", " Padding");
|
|
else if (Array.TrueForAll(dr.Padding, b => b == 0xFF))
|
|
builder.AppendLine("All 0xFF", " Padding");
|
|
else
|
|
builder.AppendLine("Not all 0xFF", " Padding");
|
|
|
|
builder.AppendLine();
|
|
}
|
|
}
|
|
}
|