[AMG] Implement Open and Close.

This commit is contained in:
2025-09-05 03:07:50 +01:00
parent 8f8bdf3c8e
commit 527d6fc743
5 changed files with 165 additions and 13 deletions

View File

@@ -1,10 +1,15 @@
using System;
using System.Collections.Generic;
using System.IO;
using Aaru.CommonTypes.Interfaces;
namespace Aaru.Archives;
public sealed partial class Amg : IArchive
{
List<FileEntry> _files;
Stream _stream;
#region IArchive Members
/// <inheritdoc />
@@ -14,14 +19,14 @@ public sealed partial class Amg : IArchive
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
/// <inheritdoc />
public bool Opened { get; }
public bool Opened { get; private set; }
/// <inheritdoc />
public ArchiveSupportedFeature ArchiveFeatures => ArchiveSupportedFeature.HasEntryTimestamp |
ArchiveSupportedFeature.SupportsCompression |
ArchiveSupportedFeature.SupportsFilenames |
ArchiveSupportedFeature.SupportsSubdirectories;
/// <inheritdoc />
public int NumberOfEntries { get; }
public int NumberOfEntries => Opened ? _files.Count : -1;
#endregion
}

View File

@@ -2,5 +2,6 @@ namespace Aaru.Archives;
public sealed partial class Amg
{
const ushort ARC_MAGIC = 0x36AD;
const ushort ARC_MAGIC = 0x36AD;
const ushort FILE_MAGIC = 0x1C94;
}

109
Aaru.Archives/Amg/Open.cs Normal file
View File

@@ -0,0 +1,109 @@
using System.IO;
using System.Text;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
namespace Aaru.Archives;
public sealed partial class Amg
{
#region IArchive Members
/// <inheritdoc />
public ErrorNumber Open(IFilter filter, Encoding encoding)
{
encoding ??= Encoding.ASCII;
if(filter.DataForkLength < Marshal.SizeOf<ArcHeader>()) return ErrorNumber.InvalidArgument;
_stream = filter.GetDataForkStream();
_stream.Position = 0;
byte[] hdr = new byte[Marshal.SizeOf<ArcHeader>()];
_stream.ReadExactly(hdr, 0, hdr.Length);
ArcHeader header = Marshal.ByteArrayToStructureLittleEndian<ArcHeader>(hdr);
// Not a valid magic
if(header.magic != ARC_MAGIC) return ErrorNumber.InvalidArgument;
// Skip comment
_stream.Position += header.commentLength;
int fileHeaderLen = Marshal.SizeOf<FileHeader>();
_files = [];
while(_stream.Position + fileHeaderLen < _stream.Length)
{
byte[] fileHdr = new byte[fileHeaderLen];
_stream.ReadExactly(fileHdr, 0, fileHdr.Length);
FileHeader fh = Marshal.ByteArrayToStructureLittleEndian<FileHeader>(fileHdr);
// Not a valid file magic
if(fh.magic != FILE_MAGIC) break;
var entry = new FileEntry
{
Attributes = (FileAttributes)fh.attr,
Compressed = (uint)(fh.compressed - fh.pathLength - fh.commentLength - fileHeaderLen),
Crc = fh.crc,
Flags = fh.flags,
LastWrite = DateHandlers.DosToDateTime(fh.date, fh.time),
Uncompressed = fh.uncompressed,
Filename = StringHandlers.CToString(fh.filename, encoding)
};
string extension = StringHandlers.CToString(fh.extension, encoding);
if(!string.IsNullOrEmpty(extension)) entry.Filename += "." + extension;
if(fh.pathLength > 0)
{
byte[] buffer = new byte[fh.pathLength];
_stream.ReadExactly(buffer, 0, buffer.Length);
string path = StringHandlers.CToString(buffer, encoding);
path = path.Replace('\\', Path.DirectorySeparatorChar);
entry.Filename = Path.Combine(path, entry.Filename);
}
if(fh.commentLength > 0)
{
byte[] buffer = new byte[fh.commentLength];
_stream.ReadExactly(buffer, 0, buffer.Length);
entry.Comment = StringHandlers.CToString(buffer, encoding);
}
entry.Offset = _stream.Position;
_files.Add(entry);
// Skip compressed data
_stream.Position += entry.Compressed;
}
Opened = true;
return ErrorNumber.NoError;
}
/// <inheritdoc />
public void Close()
{
// Already closed
if(!Opened) return;
_stream?.Close();
_files?.Clear();
_stream = null;
Opened = false;
}
#endregion
}

View File

@@ -1,3 +1,5 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace Aaru.Archives;
@@ -17,5 +19,50 @@ public sealed partial class Amg
public readonly ushort commentLength;
}
#endregion
#region Nested type: FileEntry
struct FileEntry
{
public uint Uncompressed;
public uint Compressed;
public DateTime LastWrite;
public FileAttributes Attributes;
public byte Flags;
public uint Crc;
public string Filename;
public string Comment;
public long Offset;
public override string ToString() => Filename;
}
#endregion
#region Nested type: FileHeader
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
readonly struct FileHeader
{
public readonly ushort magic;
public readonly uint compressed;
public readonly uint uncompressed;
public readonly ushort time;
public readonly ushort date;
public readonly byte attr;
public readonly byte flags;
// Something changes in processing when 0x80 is set
public readonly byte unknown;
public readonly uint crc;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public readonly byte[] filename;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public readonly byte[] extension;
public readonly byte pathLength;
public readonly ushort commentLength;
}
#endregion
}

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
using Aaru.CommonTypes.Structs;
@@ -12,15 +11,6 @@ public sealed partial class Amg
{
#region IArchive Members
/// <inheritdoc />
public ErrorNumber Open(IFilter filter, Encoding encoding) => throw new NotImplementedException();
/// <inheritdoc />
public void Close()
{
throw new NotImplementedException();
}
/// <inheritdoc />
public ErrorNumber GetFilename(int entryNumber, out string fileName) => throw new NotImplementedException();