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 /// public ErrorNumber Open(IFilter filter, Encoding encoding) { encoding ??= Encoding.UTF8; if(filter.DataForkLength < Marshal.SizeOf()) return ErrorNumber.InvalidArgument; _stream = filter.GetDataForkStream(); _stream.Position = 0; var hdr = new byte[Marshal.SizeOf()]; _stream.ReadExactly(hdr, 0, hdr.Length); HaHeader header = Marshal.ByteArrayToStructureLittleEndian(hdr); // Not a valid magic if(header.magic != HA_MAGIC) return ErrorNumber.InvalidArgument; _entries = []; int fhLen = Marshal.SizeOf(); var fhBuf = new byte[fhLen]; var pathBuf = new byte[16384]; var nameBuf = new byte[256]; int i; // Guard while(_stream.Position + fhLen < _stream.Length) { _stream.ReadExactly(fhBuf, 0, fhLen); FHeader fh = Marshal.ByteArrayToStructureLittleEndian(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(); var 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(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; } /// public void Close() { // Already closed if(!Opened) return; _stream?.Close(); _stream = null; Opened = false; } #endregion }