Files
Aaru/Aaru.Archives/Stfs/Open.cs

127 lines
4.7 KiB
C#
Raw Normal View History

2025-09-03 02:40:16 +01:00
using System.Collections.Generic;
using System.IO;
using System.Text;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
namespace Aaru.Archives;
public sealed partial class Stfs
{
#region IArchive Members
/// <inheritdoc />
public ErrorNumber Open(IFilter filter, Encoding encoding)
{
if(filter.DataForkLength < Marshal.SizeOf<RemotePackage>()) return ErrorNumber.InvalidArgument;
_stream = filter.GetDataForkStream();
_stream.Position = 0;
var hdr = new byte[Marshal.SizeOf<RemotePackage>()];
2025-09-03 02:40:16 +01:00
_stream.ReadExactly(hdr, 0, hdr.Length);
RemotePackage header = Marshal.ByteArrayToStructureBigEndian<RemotePackage>(hdr);
2025-09-03 02:40:16 +01:00
if(header.Magic is not (PackageMagic.Console or PackageMagic.Live or PackageMagic.Microsoft))
return ErrorNumber.InvalidArgument;
// SVOD is managed as a media image
if(header.Metadata.DescriptorType != 0) return ErrorNumber.InvalidArgument;
VolumeDescriptor vd =
Marshal.ByteArrayToStructureLittleEndian<VolumeDescriptor>(header.Metadata.VolumeDescriptor);
// Convert big endian int24 to int32
int fileTableBlockNumber = vd.FileTableBlockNumber[0] << 16 |
vd.FileTableBlockNumber[1] << 8 |
vd.FileTableBlockNumber[2];
fileTableBlockNumber = ComputeBlockNumber(fileTableBlockNumber,
(int)header.Metadata.HeaderSize,
vd.BlockSeparation,
header.Magic == PackageMagic.Console);
int fileTablePosition = BlockToPosition(fileTableBlockNumber, (int)header.Metadata.HeaderSize);
var buffer = new byte[4096 * vd.FileTableBlockCount];
2025-09-03 02:40:16 +01:00
_stream.Position = fileTablePosition;
_stream.ReadExactly(buffer, 0, buffer.Length);
List<FileTableEntry> entries = [];
int entrySize = Marshal.SizeOf<FileTableEntry>();
var in_pos = 0;
2025-09-03 02:40:16 +01:00
do
{
FileTableEntry entry = Marshal.ByteArrayToStructureBigEndian<FileTableEntry>(buffer, in_pos, entrySize);
2025-09-03 02:40:16 +01:00
if(entry.FilenameLength == 0) break;
entries.Add(entry);
in_pos += entrySize;
} while(in_pos + entrySize < buffer.Length);
_entries = new FileEntry[entries.Count];
for(var i = 0; i < entries.Count; i++)
2025-09-03 02:40:16 +01:00
{
// While entries[i].PathIndicator > 0 recursively inversely prepend entries[PathIndicator].Filename to entries[i].Filename
int pathIndicator = entries[i].PathIndicator;
var path = "";
2025-09-03 02:40:16 +01:00
while(pathIndicator > 0)
{
path = Path.Combine(StringHandlers.CToString(entries[pathIndicator].Filename, Encoding.ASCII), path);
pathIndicator = entries[pathIndicator].PathIndicator;
}
_entries[i].Filename = path != ""
? Path.Combine(path,
StringHandlers.CToString(entries[i].Filename, Encoding.ASCII))
: StringHandlers.CToString(entries[i].Filename, Encoding.ASCII);
_entries[i].FileSize = entries[i].FileSize;
_entries[i].StartingBlock = entries[i].StartingBlock[2] << 16 |
entries[i].StartingBlock[1] << 8 |
entries[i].StartingBlock[0];
_entries[i].StartingBlock = ComputeBlockNumber(_entries[i].StartingBlock,
(int)header.Metadata.HeaderSize,
vd.BlockSeparation,
header.Magic == PackageMagic.Console);
_entries[i].LastWrite = DateHandlers.DosToDateTime(entries[i].LastWriteDate, entries[i].LastWriteTime);
_entries[i].LastAccess = DateHandlers.DosToDateTime(entries[i].LastAccessDate, entries[i].LastAccessTime);
_entries[i].IsDirectory = (entries[i].FilenameLength & 0x80) > 0;
}
2025-09-03 14:52:40 +01:00
_headerSize = (int)header.Metadata.HeaderSize;
_blockSeparation = vd.BlockSeparation;
_isConsole = header.Magic == PackageMagic.Console;
2025-09-03 02:40:16 +01:00
Opened = true;
return ErrorNumber.NoError;
}
/// <inheritdoc />
public void Close()
{
// Already closed
if(!Opened) return;
_stream?.Close();
_stream = null;
Opened = false;
}
#endregion
}