mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-07-08 18:06:41 +00:00
137 lines
5.0 KiB
C#
137 lines
5.0 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Text;
|
|
using SabreTools.Data.Models.XDVDFS;
|
|
using SabreTools.Numerics.Extensions;
|
|
|
|
namespace SabreTools.Serialization.Writers
|
|
{
|
|
public class XDVDFS : IFileWriter<Volume>
|
|
{
|
|
/// <inheritdoc/>
|
|
public bool Debug { get; set; } = false;
|
|
|
|
/// <inheritdoc/>
|
|
public bool SerializeFile(Volume? obj, string? path)
|
|
{
|
|
if (string.IsNullOrEmpty(path))
|
|
return false;
|
|
|
|
if (obj is null || !ValidateVolume(obj))
|
|
return false;
|
|
|
|
// Create the file stream
|
|
using var fs = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None);
|
|
|
|
fs.Write(obj.ReservedArea);
|
|
SerializeVolumeDescriptor(fs, obj.VolumeDescriptor);
|
|
if (obj.LayoutDescriptor is not null)
|
|
SerializeLayoutDescriptor(fs, obj.LayoutDescriptor);
|
|
|
|
// Loop over all directory descriptors in order of offset
|
|
uint[] keys = new uint[obj.DirectoryDescriptors.Count];
|
|
obj.DirectoryDescriptors.Keys.CopyTo(keys, 0);
|
|
Array.Sort(keys);
|
|
|
|
// Write directory descriptors
|
|
for (int i = 0; i < keys.Length; i++)
|
|
{
|
|
uint sectorOffset = keys[i];
|
|
fs.Seek(sectorOffset * Constants.SectorSize, SeekOrigin.Begin);
|
|
SerializeDirectoryDescriptor(fs, obj.DirectoryDescriptors[sectorOffset]);
|
|
}
|
|
|
|
fs.Flush();
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validate that Volume is writable
|
|
/// </summary>
|
|
public static bool ValidateVolume(Volume? obj)
|
|
{
|
|
// If the data is invalid
|
|
if (obj?.VolumeDescriptor?.StartSignature is null)
|
|
return false;
|
|
|
|
// If the magic doesn't match
|
|
string magic = Encoding.ASCII.GetString(obj.VolumeDescriptor.StartSignature);
|
|
if (magic != Constants.VolumeDescriptorSignature)
|
|
return false;
|
|
|
|
// Validate model
|
|
if (obj.ReservedArea.Length != 0x10000)
|
|
return false;
|
|
if (obj.VolumeDescriptor.Reserved.Length != 1991)
|
|
return false;
|
|
if (obj.VolumeDescriptor.EndSignature.Length != 20)
|
|
return false;
|
|
if (obj.LayoutDescriptor is not null)
|
|
{
|
|
if (obj.LayoutDescriptor.Signature.Length != 24)
|
|
return false;
|
|
if (obj.LayoutDescriptor.Unused8Bytes.Length != 8)
|
|
return false;
|
|
if (obj.LayoutDescriptor.Reserved.Length != 1968)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static void SerializeVolumeDescriptor(Stream stream, VolumeDescriptor obj)
|
|
{
|
|
stream.Write(obj.StartSignature);
|
|
stream.WriteLittleEndian(obj.RootOffset);
|
|
stream.WriteLittleEndian(obj.RootSize);
|
|
stream.WriteLittleEndian(obj.MasteringTimestamp);
|
|
stream.Write(obj.UnknownByte);
|
|
stream.Write(obj.Reserved);
|
|
stream.Write(obj.EndSignature);
|
|
}
|
|
|
|
public static void SerializeLayoutDescriptor(Stream stream, LayoutDescriptor obj)
|
|
{
|
|
stream.Write(obj.Signature);
|
|
stream.Write(obj.Unused8Bytes);
|
|
SerializeFourPartVersionType(stream, obj.XBLayoutVersion);
|
|
SerializeFourPartVersionType(stream, obj.XBPremasterVersion);
|
|
SerializeFourPartVersionType(stream, obj.XBGameDiscVersion);
|
|
SerializeFourPartVersionType(stream, obj.XBOther1Version);
|
|
SerializeFourPartVersionType(stream, obj.XBOther2Version);
|
|
SerializeFourPartVersionType(stream, obj.XBOther3Version);
|
|
stream.Write(obj.Reserved);
|
|
}
|
|
|
|
public static void SerializeFourPartVersionType(Stream stream, FourPartVersionType obj)
|
|
{
|
|
stream.WriteLittleEndian(obj.Major);
|
|
stream.WriteLittleEndian(obj.Minor);
|
|
stream.WriteLittleEndian(obj.Build);
|
|
stream.WriteLittleEndian(obj.Revision);
|
|
}
|
|
|
|
public static void SerializeDirectoryDescriptor(Stream stream, DirectoryDescriptor obj)
|
|
{
|
|
foreach (var dr in obj.DirectoryRecords)
|
|
SerializeDirectoryRecord(stream, dr);
|
|
if (obj.Padding is not null && obj.Padding.Length > 0)
|
|
stream.Write(obj.Padding);
|
|
}
|
|
|
|
public static void SerializeDirectoryRecord(Stream stream, DirectoryRecord obj)
|
|
{
|
|
stream.WriteLittleEndian(obj.LeftChildOffset);
|
|
stream.WriteLittleEndian(obj.RightChildOffset);
|
|
stream.WriteLittleEndian(obj.ExtentOffset);
|
|
stream.WriteLittleEndian(obj.ExtentSize);
|
|
stream.Write((byte)obj.FileFlags);
|
|
stream.Write(obj.FilenameLength);
|
|
stream.Write(obj.Filename);
|
|
if (obj.Padding is not null && obj.Padding.Length > 0)
|
|
stream.Write(obj.Padding);
|
|
}
|
|
}
|
|
}
|