mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
[HA] Implement Open and Close.
This commit is contained in:
27
Aaru.Archives/Ha/Enums.cs
Normal file
27
Aaru.Archives/Ha/Enums.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
namespace Aaru.Archives;
|
||||
|
||||
public sealed partial class Ha
|
||||
{
|
||||
#region Nested type: MdiSource
|
||||
|
||||
enum MdiSource : byte
|
||||
{
|
||||
MSDOS = 1,
|
||||
UNIX = 2
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: Method
|
||||
|
||||
enum Method : byte
|
||||
{
|
||||
Copy = 0,
|
||||
ASC = 1,
|
||||
HSC = 2,
|
||||
Directory = 14,
|
||||
Special = 15
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,10 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Aaru.CommonTypes.Interfaces;
|
||||
|
||||
namespace Aaru.Archives;
|
||||
|
||||
public sealed partial class Ha : IArchive
|
||||
{
|
||||
List<Entry> _entries;
|
||||
Stream _stream;
|
||||
|
||||
#region IArchive Members
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -14,7 +19,7 @@ public sealed partial class Ha : 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 |
|
||||
@@ -22,7 +27,7 @@ public sealed partial class Ha : IArchive
|
||||
ArchiveSupportedFeature.SupportsSubdirectories |
|
||||
ArchiveSupportedFeature.HasExplicitDirectories;
|
||||
/// <inheritdoc />
|
||||
public int NumberOfEntries { get; }
|
||||
public int NumberOfEntries => Opened ? _entries.Count : -1;
|
||||
|
||||
#endregion
|
||||
}
|
||||
159
Aaru.Archives/Ha/Open.cs
Normal file
159
Aaru.Archives/Ha/Open.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
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 Ha
|
||||
{
|
||||
#region IArchive Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber Open(IFilter filter, Encoding encoding)
|
||||
{
|
||||
encoding ??= Encoding.UTF8;
|
||||
|
||||
if(filter.DataForkLength < Marshal.SizeOf<HaHeader>()) return ErrorNumber.InvalidArgument;
|
||||
|
||||
_stream = filter.GetDataForkStream();
|
||||
_stream.Position = 0;
|
||||
|
||||
byte[] hdr = new byte[Marshal.SizeOf<HaHeader>()];
|
||||
|
||||
_stream.ReadExactly(hdr, 0, hdr.Length);
|
||||
|
||||
HaHeader header = Marshal.ByteArrayToStructureLittleEndian<HaHeader>(hdr);
|
||||
|
||||
// Not a valid magic
|
||||
if(header.magic != HA_MAGIC) return ErrorNumber.InvalidArgument;
|
||||
|
||||
_entries = [];
|
||||
|
||||
int fhLen = Marshal.SizeOf<FHeader>();
|
||||
byte[] fhBuf = new byte[fhLen];
|
||||
byte[] pathBuf = new byte[16384];
|
||||
byte[] nameBuf = new byte[256];
|
||||
int i; // Guard
|
||||
|
||||
while(_stream.Position + fhLen < _stream.Length)
|
||||
{
|
||||
_stream.ReadExactly(fhBuf, 0, fhLen);
|
||||
FHeader fh = Marshal.ByteArrayToStructureLittleEndian<FHeader>(fhBuf);
|
||||
|
||||
for(i = 0; i < pathBuf.Length; i++)
|
||||
{
|
||||
int b = _stream.ReadByte();
|
||||
|
||||
if(b < 0) return ErrorNumber.InvalidArgument; // Makes no sense here
|
||||
|
||||
if(b == 0xFF)
|
||||
{
|
||||
pathBuf[i] = 0x2F;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(b == 0)
|
||||
{
|
||||
pathBuf[i] = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
pathBuf[i] = (byte)b;
|
||||
}
|
||||
|
||||
if(i == pathBuf.Length) return ErrorNumber.InvalidArgument; // Got beyond the buffer length
|
||||
|
||||
for(i = 0; i < nameBuf.Length; i++)
|
||||
{
|
||||
int b = _stream.ReadByte();
|
||||
|
||||
if(b < 0) return ErrorNumber.InvalidArgument; // Makes no sense here
|
||||
|
||||
if(b == 0)
|
||||
{
|
||||
nameBuf[i] = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
nameBuf[i] = (byte)b;
|
||||
}
|
||||
|
||||
if(i == nameBuf.Length) return ErrorNumber.InvalidArgument; // Got beyond the buffer length
|
||||
|
||||
int mdiLen = _stream.ReadByte();
|
||||
|
||||
byte[] mdi = new byte[mdiLen];
|
||||
_stream.ReadExactly(mdi, 0, mdiLen);
|
||||
|
||||
string path = StringHandlers.CToString(pathBuf, encoding);
|
||||
string name = StringHandlers.CToString(nameBuf, encoding);
|
||||
|
||||
// Remove drive letter
|
||||
if(path.Length > 3 && path[1] == ':') path = path[2..];
|
||||
|
||||
// ... or leading slash
|
||||
if(path.Length > 0 && path[0] == '/') path = path[1..];
|
||||
|
||||
// replace slash with system separator
|
||||
path = path.Replace('/', Path.DirectorySeparatorChar);
|
||||
|
||||
var entry = new Entry
|
||||
{
|
||||
Method = (Method)(fh.VerType & 0x0F),
|
||||
Compressed = fh.clen,
|
||||
Uncompressed = fh.olen,
|
||||
LastWrite = DateHandlers.UnixToDateTime(fh.time),
|
||||
DataOffset = _stream.Position,
|
||||
Filename = Path.Combine(path, name)
|
||||
};
|
||||
|
||||
switch((MdiSource)mdi[0])
|
||||
{
|
||||
case MdiSource.MSDOS:
|
||||
entry.Attributes = (FileAttributes)mdi[1];
|
||||
|
||||
break;
|
||||
case MdiSource.UNIX:
|
||||
{
|
||||
UnixMdi unixMdi = Marshal.ByteArrayToStructureLittleEndian<UnixMdi>(mdi);
|
||||
entry.Mode = unixMdi.attr;
|
||||
entry.Uid = unixMdi.user;
|
||||
entry.Gid = unixMdi.group;
|
||||
|
||||
if(entry.Method == Method.Directory) entry.Attributes = FileAttributes.Directory;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_entries.Add(entry);
|
||||
|
||||
_stream.Position += entry.Compressed;
|
||||
}
|
||||
|
||||
Opened = true;
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Close()
|
||||
{
|
||||
// Already closed
|
||||
if(!Opened) return;
|
||||
|
||||
_stream?.Close();
|
||||
|
||||
_stream = null;
|
||||
Opened = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,9 +1,29 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Aaru.Archives;
|
||||
|
||||
public sealed partial class Ha
|
||||
{
|
||||
#region Nested type: Entry
|
||||
|
||||
struct Entry
|
||||
{
|
||||
public Method Method;
|
||||
public uint Compressed;
|
||||
public uint Uncompressed;
|
||||
public DateTime LastWrite;
|
||||
public FileAttributes Attributes;
|
||||
public long DataOffset;
|
||||
public string Filename;
|
||||
public ushort Mode;
|
||||
public ushort Uid;
|
||||
public ushort Gid;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: FHeader
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
|
||||
@@ -13,14 +33,12 @@ public sealed partial class Ha
|
||||
public readonly byte VerType;
|
||||
|
||||
// Compressed length
|
||||
public readonly ushort clen;
|
||||
public readonly uint clen;
|
||||
|
||||
// Original length
|
||||
public readonly ushort olen;
|
||||
public readonly uint olen;
|
||||
|
||||
// Unclear if DOS packed date or what
|
||||
public readonly ushort date;
|
||||
public readonly ushort time;
|
||||
public readonly int time;
|
||||
|
||||
// CRC32
|
||||
public readonly uint crc;
|
||||
@@ -43,5 +61,18 @@ public sealed partial class Ha
|
||||
public readonly ushort count;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: UnixMdi
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
|
||||
readonly struct UnixMdi
|
||||
{
|
||||
public readonly byte type;
|
||||
public readonly ushort attr;
|
||||
public readonly ushort user;
|
||||
public readonly ushort group;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -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 Ha
|
||||
{
|
||||
#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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user