From 2aabd8d0e170d8929f90ba4739366dde826590d8 Mon Sep 17 00:00:00 2001 From: Twan van Dongen Date: Tue, 28 Oct 2025 20:38:29 +0100 Subject: [PATCH 1/5] Initial implementation of the ARJ (Archived by Robert Jung) format, supporting 'store' for single file archives. Multi-file archives and all compression algorithms still require implementations. --- src/SharpCompress/Common/ArchiveType.cs | 1 + src/SharpCompress/Common/Arj/ArjEntry.cs | 48 +++++ src/SharpCompress/Common/Arj/ArjFilePart.cs | 52 ++++++ src/SharpCompress/Common/Arj/ArjVolume.cs | 16 ++ .../Common/Arj/Headers/ArjHeader.cs | 115 ++++++++++++ .../Common/Arj/Headers/ArjLocalHeader.cs | 175 ++++++++++++++++++ .../Common/Arj/Headers/ArjMainHeader.cs | 150 +++++++++++++++ .../Common/Arj/Headers/CompressionMethod.cs | 20 ++ .../Common/Arj/Headers/DosDateTime.cs | 37 ++++ .../Common/Arj/Headers/FileType.cs | 13 ++ .../Common/Arj/Headers/HostOS.cs | 19 ++ src/SharpCompress/Factories/ArjFactory.cs | 42 +++++ src/SharpCompress/Factories/Factory.cs | 1 + src/SharpCompress/Readers/Arj/ArjReader.cs | 50 +++++ src/SharpCompress/Readers/ReaderFactory.cs | 2 +- src/SharpCompress/packages.lock.json | 6 +- .../SharpCompress.Test/Arj/ArjReaderTests.cs | 46 +++++ tests/TestArchives/Archives/Arj.store.arj | Bin 0 -> 101138 bytes 18 files changed, 789 insertions(+), 4 deletions(-) create mode 100644 src/SharpCompress/Common/Arj/ArjEntry.cs create mode 100644 src/SharpCompress/Common/Arj/ArjFilePart.cs create mode 100644 src/SharpCompress/Common/Arj/ArjVolume.cs create mode 100644 src/SharpCompress/Common/Arj/Headers/ArjHeader.cs create mode 100644 src/SharpCompress/Common/Arj/Headers/ArjLocalHeader.cs create mode 100644 src/SharpCompress/Common/Arj/Headers/ArjMainHeader.cs create mode 100644 src/SharpCompress/Common/Arj/Headers/CompressionMethod.cs create mode 100644 src/SharpCompress/Common/Arj/Headers/DosDateTime.cs create mode 100644 src/SharpCompress/Common/Arj/Headers/FileType.cs create mode 100644 src/SharpCompress/Common/Arj/Headers/HostOS.cs create mode 100644 src/SharpCompress/Factories/ArjFactory.cs create mode 100644 src/SharpCompress/Readers/Arj/ArjReader.cs create mode 100644 tests/SharpCompress.Test/Arj/ArjReaderTests.cs create mode 100644 tests/TestArchives/Archives/Arj.store.arj diff --git a/src/SharpCompress/Common/ArchiveType.cs b/src/SharpCompress/Common/ArchiveType.cs index 503804c8..9d943895 100644 --- a/src/SharpCompress/Common/ArchiveType.cs +++ b/src/SharpCompress/Common/ArchiveType.cs @@ -8,4 +8,5 @@ public enum ArchiveType SevenZip, GZip, Arc, + Arj, } diff --git a/src/SharpCompress/Common/Arj/ArjEntry.cs b/src/SharpCompress/Common/Arj/ArjEntry.cs new file mode 100644 index 00000000..2e83190c --- /dev/null +++ b/src/SharpCompress/Common/Arj/ArjEntry.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SharpCompress.Common.Arc; +using SharpCompress.Common.Arj.Headers; + +namespace SharpCompress.Common.Arj +{ + public class ArjEntry : Entry + { + private readonly ArjFilePart _filePart; + + internal ArjEntry(ArjFilePart filePart) + { + _filePart = filePart; + } + + public override long Crc => _filePart.Header.OriginalCrc32; + + public override string? Key => _filePart?.Header.Name; + + public override string? LinkTarget => null; + + public override long CompressedSize => _filePart?.Header.CompressedSize ?? 0; + + public override CompressionType CompressionType => CompressionType.None; + + public override long Size => _filePart?.Header.OriginalSize ?? 0; + + public override DateTime? LastModifiedTime => _filePart.Header.DateTimeModified.DateTime; + + public override DateTime? CreatedTime => _filePart.Header.DateTimeCreated.DateTime; + + public override DateTime? LastAccessedTime => _filePart.Header.DateTimeAccessed.DateTime; + + public override DateTime? ArchivedTime => null; + + public override bool IsEncrypted => false; + + public override bool IsDirectory => _filePart.Header.FileType == (int)FileType.Directory; + + public override bool IsSplitAfter => false; + + internal override IEnumerable Parts => _filePart.Empty(); + } +} diff --git a/src/SharpCompress/Common/Arj/ArjFilePart.cs b/src/SharpCompress/Common/Arj/ArjFilePart.cs new file mode 100644 index 00000000..24dbbab5 --- /dev/null +++ b/src/SharpCompress/Common/Arj/ArjFilePart.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SharpCompress.Common.Arj.Headers; +using SharpCompress.IO; + +namespace SharpCompress.Common.Arj +{ + public class ArjFilePart : FilePart + { + private readonly Stream _stream; + internal ArjLocalHeader Header { get; set; } + + internal ArjFilePart(ArjLocalHeader localArjHeader, Stream seekableStream) + : base(localArjHeader.ArchiveEncoding) + { + _stream = seekableStream; + Header = localArjHeader; + } + + internal override string? FilePartName => Header.Name; + + internal override Stream GetCompressedStream() + { + if (_stream != null) + { + Stream compressedStream; + switch (Header.CompressionMethod) + { + case CompressionMethod.Stored: + compressedStream = new ReadOnlySubStream( + _stream, + Header.DataStartPosition, + Header.CompressedSize + ); + break; + default: + throw new NotSupportedException( + "CompressionMethod: " + Header.CompressionMethod + ); + } + return compressedStream; + } + return _stream.NotNull(); + } + + internal override Stream GetRawStream() => _stream; + } +} diff --git a/src/SharpCompress/Common/Arj/ArjVolume.cs b/src/SharpCompress/Common/Arj/ArjVolume.cs new file mode 100644 index 00000000..bf3ba109 --- /dev/null +++ b/src/SharpCompress/Common/Arj/ArjVolume.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SharpCompress.Readers; + +namespace SharpCompress.Common.Arj +{ + public class ArjVolume : Volume + { + public ArjVolume(Stream stream, ReaderOptions readerOptions, int index = 0) + : base(stream, readerOptions, index) { } + } +} diff --git a/src/SharpCompress/Common/Arj/Headers/ArjHeader.cs b/src/SharpCompress/Common/Arj/Headers/ArjHeader.cs new file mode 100644 index 00000000..cb8fc479 --- /dev/null +++ b/src/SharpCompress/Common/Arj/Headers/ArjHeader.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SharpCompress.Common.Zip.Headers; +using SharpCompress.Crypto; + +namespace SharpCompress.Common.Arj.Headers +{ + public enum ArjHeaderType + { + MainHeader, + LocalHeader, + } + + public abstract class ArjHeader + { + private const int FIRST_HDR_SIZE = 34; + private const ushort ARJ_MAGIC = 0xEA60; + + public ArjHeader(ArjHeaderType type) + { + ArjHeaderType = type; + } + + public ArjHeaderType ArjHeaderType { get; } + + public abstract ArjHeader? Read(Stream reader); + + public byte[] ReadHeader(Stream stream) + { + // check for magic bytes + Span magic = stackalloc byte[2]; + if (stream.Read(magic) != 2) + return Array.Empty(); + + var magicValue = (ushort)(magic[0] | magic[1] << 8); + if (magicValue != ARJ_MAGIC) + throw new InvalidDataException("Not an ARJ file (wrong magic bytes)"); + + // read header_size + byte[] headerBytes = new byte[2]; + stream.Read(headerBytes, 0, 2); + var headerSize = (ushort)(headerBytes[0] | headerBytes[1] << 8); + if (headerSize < 1) + return Array.Empty(); + + var body = new byte[headerSize]; + var read = stream.Read(body, 0, headerSize); + if (read < headerSize) + return Array.Empty(); + + byte[] crc = new byte[4]; + read = stream.Read(crc, 0, 4); + var checksum = Crc32Stream.Compute(body); + // Compute the hash value + if (checksum != BitConverter.ToUInt32(crc, 0)) + { + throw new InvalidDataException("Header checksum is invalid"); + } + return body; + } + + protected List ReadExtendedHeaders(Stream reader) + { + List extendedHeader = new List(); + byte[] buffer = new byte[2]; + + while (true) + { + int bytesRead = reader.Read(buffer, 0, 2); + if (bytesRead < 2) + { + throw new EndOfStreamException( + "Unexpected end of stream while reading extended header size." + ); + } + + var extHeaderSize = (ushort)(buffer[0] | (buffer[1] << 8)); + if (extHeaderSize == 0) + { + return extendedHeader; + } + + byte[] header = new byte[extHeaderSize]; + bytesRead = reader.Read(header, 0, extHeaderSize); + if (bytesRead < extHeaderSize) + { + throw new EndOfStreamException( + "Unexpected end of stream while reading extended header data." + ); + } + + byte[] crc = new byte[4]; + bytesRead = reader.Read(crc, 0, 4); + if (bytesRead < 4) + { + throw new EndOfStreamException( + "Unexpected end of stream while reading extended header CRC." + ); + } + + var checksum = Crc32Stream.Compute(header); + if (checksum != BitConverter.ToUInt32(crc, 0)) + { + throw new InvalidDataException("Extended header checksum is invalid"); + } + + extendedHeader.Add(header); + } + } + } +} diff --git a/src/SharpCompress/Common/Arj/Headers/ArjLocalHeader.cs b/src/SharpCompress/Common/Arj/Headers/ArjLocalHeader.cs new file mode 100644 index 00000000..595037f5 --- /dev/null +++ b/src/SharpCompress/Common/Arj/Headers/ArjLocalHeader.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace SharpCompress.Common.Arj.Headers +{ + public class ArjLocalHeader : ArjHeader + { + public ArchiveEncoding ArchiveEncoding { get; } + public long DataStartPosition { get; protected set; } + + public byte ArchiverVersionNumber { get; set; } + public byte MinVersionToExtract { get; set; } + public HostOS HostOS { get; set; } + public byte ArjFlags { get; set; } + public CompressionMethod CompressionMethod { get; set; } + public int FileType { get; set; } + public DosDateTime DateTimeModified { get; set; } = new DosDateTime(0); + public long CompressedSize { get; set; } + public long OriginalSize { get; set; } + public long OriginalCrc32 { get; set; } + public int FileSpecPosition { get; set; } + public int FileAccessMode { get; set; } + public byte FirstChapter { get; set; } + public byte LastChapter { get; set; } + public long ExtendedFilePosition { get; set; } + public DosDateTime DateTimeAccessed { get; set; } = new DosDateTime(0); + public DosDateTime DateTimeCreated { get; set; } = new DosDateTime(0); + public long OriginalSizeEvenForVolumes { get; set; } + public string Name { get; set; } = string.Empty; + public string Comment { get; set; } = string.Empty; + + private const byte StdHdrSize = 30; + private const byte R9HdrSize = 46; + public bool IsGarbled => (ArjFlags & 0x01) != 0; + public bool IsVolume => (ArjFlags & 0x04) != 0; + public bool IsExtFile => (ArjFlags & 0x08) != 0; + public bool IsPathSym => (ArjFlags & 0x10) != 0; + public bool IsBackup => (ArjFlags & 0x20) != 0; + + public ArjLocalHeader(ArchiveEncoding archiveEncoding) + : base(ArjHeaderType.LocalHeader) + { + ArchiveEncoding = + archiveEncoding ?? throw new ArgumentNullException(nameof(archiveEncoding)); + } + + public override ArjHeader? Read(Stream stream) + { + var body = ReadHeader(stream); + if (body.Length > 0) + { + ReadExtendedHeaders(stream); + var header = LoadFrom(body); + header.DataStartPosition = stream.Position; + return header; + } + return null; + } + + public ArjLocalHeader LoadFrom(byte[] headerBytes) + { + int offset = 0; + + int ReadInt16() + { + if (offset + 1 >= headerBytes.Length) + { + throw new EndOfStreamException(); + } + var v = headerBytes[offset] & 0xFF | (headerBytes[offset + 1] & 0xFF) << 8; + offset += 2; + return v; + } + long ReadInt32() + { + if (offset + 3 >= headerBytes.Length) + { + throw new EndOfStreamException(); + } + long v = + headerBytes[offset] & 0xFF + | (headerBytes[offset + 1] & 0xFF) << 8 + | (headerBytes[offset + 2] & 0xFF) << 16 + | (headerBytes[offset + 3] & 0xFF) << 24; + offset += 4; + return v; + } + + byte headerSize = headerBytes[offset++]; + byte archiverVersionNumber = headerBytes[offset++]; + byte minVersionToExtract = headerBytes[offset++]; + HostOS hostOS = (HostOS)headerBytes[offset++]; + byte arjFlags = headerBytes[offset++]; + CompressionMethod compressionMethod = CompressionMethodFromByte(headerBytes[offset++]); + FileType fileType = FileTypeFromByte(headerBytes[offset++]); + + offset++; // Skip 1 byte + + var rawTimestamp = ReadInt32(); + DateTimeModified = + rawTimestamp != 0 ? new DosDateTime(rawTimestamp) : new DosDateTime(0); + + CompressedSize = ReadInt32(); + OriginalSize = ReadInt32(); + OriginalCrc32 = ReadInt32(); + FileSpecPosition = ReadInt16(); + FileAccessMode = ReadInt16(); + + FirstChapter = headerBytes[offset++]; + LastChapter = headerBytes[offset++]; + + ExtendedFilePosition = 0; + OriginalSizeEvenForVolumes = 0; + + if (headerSize > StdHdrSize) + { + ExtendedFilePosition = ReadInt32(); + + if (headerSize >= R9HdrSize) + { + rawTimestamp = ReadInt32(); + DateTimeAccessed = + rawTimestamp != 0 ? new DosDateTime(rawTimestamp) : new DosDateTime(0); + rawTimestamp = ReadInt32(); + DateTimeCreated = + rawTimestamp != 0 ? new DosDateTime(rawTimestamp) : new DosDateTime(0); + OriginalSizeEvenForVolumes = ReadInt32(); + } + } + + Name = Encoding.ASCII.GetString( + headerBytes, + offset, + Array.IndexOf(headerBytes, (byte)0, offset) - offset + ); + offset += Name.Length + 1; + + Comment = Encoding.ASCII.GetString( + headerBytes, + offset, + Array.IndexOf(headerBytes, (byte)0, offset) - offset + ); + offset += Comment.Length + 1; + + return this; + } + + public static CompressionMethod CompressionMethodFromByte(byte value) + { + return value switch + { + 0 => CompressionMethod.Stored, + 1 => CompressionMethod.CompressedMost, + 2 => CompressionMethod.Compressed, + 3 => CompressionMethod.CompressedFaster, + 4 => CompressionMethod.CompressedFastest, + 8 => CompressionMethod.NoDataNoCrc, + 9 => CompressionMethod.NoData, + _ => CompressionMethod.Unknown, + }; + } + + public static FileType FileTypeFromByte(byte value) + { + return Enum.IsDefined(typeof(FileType), value) + ? (FileType)value + : Headers.FileType.Unknown; + } + } +} diff --git a/src/SharpCompress/Common/Arj/Headers/ArjMainHeader.cs b/src/SharpCompress/Common/Arj/Headers/ArjMainHeader.cs new file mode 100644 index 00000000..f050837c --- /dev/null +++ b/src/SharpCompress/Common/Arj/Headers/ArjMainHeader.cs @@ -0,0 +1,150 @@ +using System; +using System.IO; +using System.Text; +using SharpCompress.Compressors.Deflate; +using SharpCompress.Crypto; + +namespace SharpCompress.Common.Arj.Headers +{ + public class ArjMainHeader : ArjHeader + { + private const int FIRST_HDR_SIZE = 34; + private const ushort ARJ_MAGIC = 0xEA60; + + public ArchiveEncoding ArchiveEncoding { get; } + + public int ArchiverVersionNumber { get; private set; } + public int MinVersionToExtract { get; private set; } + public HostOS HostOs { get; private set; } + public int Flags { get; private set; } + public int SecurityVersion { get; private set; } + public int FileType { get; private set; } + public DosDateTime CreationDateTime { get; private set; } = new DosDateTime(0); + public long CompressedSize { get; private set; } + public long ArchiveSize { get; private set; } + public long SecurityEnvelope { get; private set; } + public int FileSpecPosition { get; private set; } + public int SecurityEnvelopeLength { get; private set; } + public int EncryptionVersion { get; private set; } + public int LastChapter { get; private set; } + + public int ArjProtectionFactor { get; private set; } + public int Flags2 { get; private set; } + public string Name { get; private set; } = string.Empty; + public string Comment { get; private set; } = string.Empty; + + public ArjMainHeader(ArchiveEncoding archiveEncoding) + : base(ArjHeaderType.MainHeader) + { + ArchiveEncoding = + archiveEncoding ?? throw new ArgumentNullException(nameof(archiveEncoding)); + } + + public override ArjHeader? Read(Stream stream) + { + var body = ReadHeader(stream); + ReadExtendedHeaders(stream); + return LoadFrom(body); + } + + public ArjMainHeader LoadFrom(byte[] headerBytes) + { + var offset = 1; + + int ReadByte() + { + if (offset >= headerBytes.Length) + { + throw new EndOfStreamException(); + } + return headerBytes[offset++] & 0xFF; + } + + int ReadInt16() + { + if (offset + 1 >= headerBytes.Length) + { + throw new EndOfStreamException(); + } + var v = headerBytes[offset] & 0xFF | (headerBytes[offset + 1] & 0xFF) << 8; + offset += 2; + return v; + } + + long ReadInt32() + { + if (offset + 3 >= headerBytes.Length) + { + throw new EndOfStreamException(); + } + long v = + headerBytes[offset] & 0xFF + | (headerBytes[offset + 1] & 0xFF) << 8 + | (headerBytes[offset + 2] & 0xFF) << 16 + | (headerBytes[offset + 3] & 0xFF) << 24; + offset += 4; + return v; + } + string ReadNullTerminatedString(byte[] x, int startIndex) + { + var result = new StringBuilder(); + int i = startIndex; + + while (i < x.Length && x[i] != 0) + { + result.Append((char)x[i]); + i++; + } + + // Skip the null terminator + i++; + if (i < x.Length) + { + byte[] remainder = new byte[x.Length - i]; + Array.Copy(x, i, remainder, 0, remainder.Length); + x = remainder; + } + + return result.ToString(); + } + + ArchiverVersionNumber = ReadByte(); + MinVersionToExtract = ReadByte(); + + var hostOsByte = ReadByte(); + HostOs = hostOsByte <= 11 ? (HostOS)hostOsByte : HostOS.Unknown; + + Flags = ReadByte(); + SecurityVersion = ReadByte(); + FileType = ReadByte(); + + offset++; // skip reserved + + CreationDateTime = new DosDateTime((int)ReadInt32()); + CompressedSize = ReadInt32(); + ArchiveSize = ReadInt32(); + + SecurityEnvelope = ReadInt32(); + FileSpecPosition = ReadInt16(); + SecurityEnvelopeLength = ReadInt16(); + + EncryptionVersion = ReadByte(); + LastChapter = ReadByte(); + + Name = ReadNullTerminatedString(headerBytes, offset); + Comment = ReadNullTerminatedString(headerBytes, offset + 1 + Name.Length); + + return this; + } + + // Flag helpers + public bool IsGabled => (Flags & 0x01) != 0; + public bool IsAnsiPage => (Flags & 0x02) != 0; + public bool IsVolume => (Flags & 0x04) != 0; + public bool IsArjProtected => (Flags & 0x08) != 0; + public bool IsPathSym => (Flags & 0x10) != 0; + public bool IsBackup => (Flags & 0x20) != 0; + public bool IsSecured => (Flags & 0x40) != 0; + public bool IsAltName => (Flags & 0x80) != 0; + } +} diff --git a/src/SharpCompress/Common/Arj/Headers/CompressionMethod.cs b/src/SharpCompress/Common/Arj/Headers/CompressionMethod.cs new file mode 100644 index 00000000..acdf2ce9 --- /dev/null +++ b/src/SharpCompress/Common/Arj/Headers/CompressionMethod.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpCompress.Common.Arj.Headers +{ + public enum CompressionMethod + { + Stored = 0, + CompressedMost = 1, + Compressed = 2, + CompressedFaster = 3, + CompressedFastest = 4, + NoDataNoCrc = 8, + NoData = 9, + Unknown, + } +} diff --git a/src/SharpCompress/Common/Arj/Headers/DosDateTime.cs b/src/SharpCompress/Common/Arj/Headers/DosDateTime.cs new file mode 100644 index 00000000..d51045ad --- /dev/null +++ b/src/SharpCompress/Common/Arj/Headers/DosDateTime.cs @@ -0,0 +1,37 @@ +using System; + +namespace SharpCompress.Common.Arj.Headers +{ + public class DosDateTime + { + public DateTime DateTime { get; } + + public DosDateTime(long dosValue) + { + // Ensure only the lower 32 bits are used + int value = unchecked((int)(dosValue & 0xFFFFFFFF)); + + var date = (value >> 16) & 0xFFFF; + var time = value & 0xFFFF; + + var day = date & 0x1F; + var month = (date >> 5) & 0x0F; + var year = ((date >> 9) & 0x7F) + 1980; + + var second = (time & 0x1F) * 2; + var minute = (time >> 5) & 0x3F; + var hour = (time >> 11) & 0x1F; + + try + { + DateTime = new DateTime(year, month, day, hour, minute, second); + } + catch + { + DateTime = DateTime.MinValue; + } + } + + public override string ToString() => DateTime.ToString("yyyy-MM-dd HH:mm:ss"); + } +} diff --git a/src/SharpCompress/Common/Arj/Headers/FileType.cs b/src/SharpCompress/Common/Arj/Headers/FileType.cs new file mode 100644 index 00000000..39c529f0 --- /dev/null +++ b/src/SharpCompress/Common/Arj/Headers/FileType.cs @@ -0,0 +1,13 @@ +namespace SharpCompress.Common.Arj.Headers +{ + public enum FileType : byte + { + Binary = 0, + Text7Bit = 1, + CommentHeader = 2, + Directory = 3, + VolumeLabel = 4, + ChapterLabel = 5, + Unknown = 255, + } +} diff --git a/src/SharpCompress/Common/Arj/Headers/HostOS.cs b/src/SharpCompress/Common/Arj/Headers/HostOS.cs new file mode 100644 index 00000000..a74e7b0f --- /dev/null +++ b/src/SharpCompress/Common/Arj/Headers/HostOS.cs @@ -0,0 +1,19 @@ +namespace SharpCompress.Common.Arj.Headers +{ + public enum HostOS + { + MsDos = 0, + PrimOS = 1, + Unix = 2, + Amiga = 3, + MacOs = 4, + OS2 = 5, + AppleGS = 6, + AtariST = 7, + NeXT = 8, + VaxVMS = 9, + Win95 = 10, + Win32 = 11, + Unknown = 255, + } +} diff --git a/src/SharpCompress/Factories/ArjFactory.cs b/src/SharpCompress/Factories/ArjFactory.cs new file mode 100644 index 00000000..597393a6 --- /dev/null +++ b/src/SharpCompress/Factories/ArjFactory.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SharpCompress.Common; +using SharpCompress.Common.Arj.Headers; +using SharpCompress.Readers; +using SharpCompress.Readers.Arc; + +namespace SharpCompress.Factories +{ + public class ArjFactory : Factory, IReaderFactory + { + public override string Name => "Arj"; + + public override ArchiveType? KnownArchiveType => ArchiveType.Arj; + + public override IEnumerable GetSupportedExtensions() + { + yield return "arj"; + } + + public override bool IsArchive( + Stream stream, + string? password = null, + int bufferSize = ReaderOptions.DefaultBufferSize + ) + { + var arjHeader = new ArjMainHeader(new ArchiveEncoding()); + if (arjHeader.Read(stream) == null) + { + return false; + } + return true; + } + + public IReader OpenReader(Stream stream, ReaderOptions? options) => + ArjReader.Open(stream, options); + } +} diff --git a/src/SharpCompress/Factories/Factory.cs b/src/SharpCompress/Factories/Factory.cs index 2462f614..dba20177 100644 --- a/src/SharpCompress/Factories/Factory.cs +++ b/src/SharpCompress/Factories/Factory.cs @@ -18,6 +18,7 @@ public abstract class Factory : IFactory RegisterFactory(new GZipFactory()); RegisterFactory(new TarFactory()); RegisterFactory(new ArcFactory()); + RegisterFactory(new ArjFactory()); } private static readonly HashSet _factories = new(); diff --git a/src/SharpCompress/Readers/Arj/ArjReader.cs b/src/SharpCompress/Readers/Arj/ArjReader.cs new file mode 100644 index 00000000..37bde917 --- /dev/null +++ b/src/SharpCompress/Readers/Arj/ArjReader.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SharpCompress.Common; +using SharpCompress.Common.Arj; +using SharpCompress.Common.Arj.Headers; +using SharpCompress.Common.Zip; +using SharpCompress.Common.Zip.Headers; + +namespace SharpCompress.Readers.Arc +{ + public class ArjReader : AbstractReader + { + private ArjReader(Stream stream, ReaderOptions options) + : base(options, ArchiveType.Arj) => Volume = new ArjVolume(stream, options, 0); + + public override ArjVolume Volume { get; } + + /// + /// Opens an ArjReader for Non-seeking usage with a single volume + /// + /// + /// + /// + public static ArjReader Open(Stream stream, ReaderOptions? options = null) + { + stream.NotNull(nameof(stream)); + return new ArjReader(stream, options ?? new ReaderOptions()); + } + + protected override IEnumerable GetEntries(Stream stream) + { + var headerReader = new ArjMainHeader(new ArchiveEncoding()); + var mainHeader = headerReader.Read(stream); + + while (true) + { + var localReader = new ArjLocalHeader(new ArchiveEncoding()); + var localHeader = localReader.Read(stream); + if (localHeader == null) + break; + + yield return new ArjEntry(new ArjFilePart((ArjLocalHeader)localHeader, stream)); + } + } + } +} diff --git a/src/SharpCompress/Readers/ReaderFactory.cs b/src/SharpCompress/Readers/ReaderFactory.cs index 97846380..80995e41 100644 --- a/src/SharpCompress/Readers/ReaderFactory.cs +++ b/src/SharpCompress/Readers/ReaderFactory.cs @@ -70,7 +70,7 @@ public static class ReaderFactory } throw new InvalidFormatException( - "Cannot determine compressed stream type. Supported Reader Formats: Arc, Zip, GZip, BZip2, Tar, Rar, LZip, XZ, ZStandard" + "Cannot determine compressed stream type. Supported Reader Formats: Arc, Arj, Zip, GZip, BZip2, Tar, Rar, LZip, XZ, ZStandard" ); } } diff --git a/src/SharpCompress/packages.lock.json b/src/SharpCompress/packages.lock.json index 9ebb1677..3d0d443d 100644 --- a/src/SharpCompress/packages.lock.json +++ b/src/SharpCompress/packages.lock.json @@ -335,9 +335,9 @@ "net8.0": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[8.0.17, )", - "resolved": "8.0.17", - "contentHash": "x5/y4l8AtshpBOrCZdlE4txw8K3e3s9meBFeZeR3l8hbbku2V7kK6ojhXvrbjg1rk3G+JqL1BI26gtgc1ZrdUw==" + "requested": "[8.0.21, )", + "resolved": "8.0.21", + "contentHash": "s8H5PZQs50OcNkaB6Si54+v3GWM7vzs6vxFRMlD3aXsbM+aPCtod62gmK0BYWou9diGzmo56j8cIf/PziijDqQ==" }, "Microsoft.SourceLink.GitHub": { "type": "Direct", diff --git a/tests/SharpCompress.Test/Arj/ArjReaderTests.cs b/tests/SharpCompress.Test/Arj/ArjReaderTests.cs new file mode 100644 index 00000000..84a5e437 --- /dev/null +++ b/tests/SharpCompress.Test/Arj/ArjReaderTests.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SharpCompress.Common; +using SharpCompress.Readers; +using SharpCompress.Readers.Arc; +using Xunit; + +namespace SharpCompress.Test.Arj +{ + public class ArjReaderTests : ReaderTests + { + public ArjReaderTests() + { + UseExtensionInsteadOfNameToVerify = true; + UseCaseInsensitiveToVerify = true; + } + + [Fact] + public void Arj_Uncompressed_Read() => Read("Arj.store.arj", CompressionType.None); + + private void ProcessArchive(string archiveName) + { + // Process a given archive by its name + using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, archiveName))) + using (IReader reader = ArjReader.Open(stream)) + { + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions { ExtractFullPath = true, Overwrite = true } + ); + } + } + } + + VerifyFilesByExtension(); + } + } +} diff --git a/tests/TestArchives/Archives/Arj.store.arj b/tests/TestArchives/Archives/Arj.store.arj new file mode 100644 index 0000000000000000000000000000000000000000..b6fa515c8282199092c6cc1199aa4d33f5103025 GIT binary patch literal 101138 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 literal 0 HcmV?d00001 From ad5c655c4587240d02b50f084226a254fd2c06a7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 13:09:05 +0000 Subject: [PATCH 2/5] Initial plan From df59c5cb9d3aa7e0ff1efdf88ae47327b3dcb6fa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 13:26:00 +0000 Subject: [PATCH 3/5] Plan: Fix potential ZipArchive.IsZipFile failure on Linux Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- src/SharpCompress/packages.lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SharpCompress/packages.lock.json b/src/SharpCompress/packages.lock.json index 9ebb1677..b85a38f7 100644 --- a/src/SharpCompress/packages.lock.json +++ b/src/SharpCompress/packages.lock.json @@ -335,9 +335,9 @@ "net8.0": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[8.0.17, )", - "resolved": "8.0.17", - "contentHash": "x5/y4l8AtshpBOrCZdlE4txw8K3e3s9meBFeZeR3l8hbbku2V7kK6ojhXvrbjg1rk3G+JqL1BI26gtgc1ZrdUw==" + "requested": "[8.0.20, )", + "resolved": "8.0.20", + "contentHash": "Rhcto2AjGvTO62+/VTmBpumBOmqIGp7nYEbTbmEXkCq4yPGxV8whju3/HsIA/bKyo2+DggaYk5+/8sxb1AbPTw==" }, "Microsoft.SourceLink.GitHub": { "type": "Direct", From db98e5f39ba7dd4eae5c9de04628fccafd10eed3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 13:34:53 +0000 Subject: [PATCH 4/5] Fix ArchiveFactory.Open to avoid double-wrapping SharpCompressStream Use SharpCompressStream.Create instead of constructor to properly handle streams that are already wrapped. This prevents potential buffering issues when opening ZIP files, particularly on Linux systems. Added tests to verify both raw FileStream and pre-wrapped stream scenarios. Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- src/SharpCompress/Archives/ArchiveFactory.cs | 2 +- tests/SharpCompress.Test/ArchiveTests.cs | 32 ++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/SharpCompress/Archives/ArchiveFactory.cs b/src/SharpCompress/Archives/ArchiveFactory.cs index 870092f1..94368ece 100644 --- a/src/SharpCompress/Archives/ArchiveFactory.cs +++ b/src/SharpCompress/Archives/ArchiveFactory.cs @@ -20,7 +20,7 @@ public static class ArchiveFactory public static IArchive Open(Stream stream, ReaderOptions? readerOptions = null) { readerOptions ??= new ReaderOptions(); - stream = new SharpCompressStream(stream, bufferSize: readerOptions.BufferSize); + stream = SharpCompressStream.Create(stream, bufferSize: readerOptions.BufferSize); return FindFactory(stream).Open(stream, readerOptions); } diff --git a/tests/SharpCompress.Test/ArchiveTests.cs b/tests/SharpCompress.Test/ArchiveTests.cs index 2849a71f..2f47e121 100644 --- a/tests/SharpCompress.Test/ArchiveTests.cs +++ b/tests/SharpCompress.Test/ArchiveTests.cs @@ -622,4 +622,36 @@ public class ArchiveTests : ReaderTests VerifyFiles(); } } + + [Fact] + public void ArchiveFactory_Open_WithPreWrappedStream() + { + // Test that ArchiveFactory.Open works correctly with a stream that's already wrapped + // This addresses the issue where ZIP files fail to open on Linux + var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.noEmptyDirs.zip"); + + // Open with a pre-wrapped stream + using (var fileStream = File.OpenRead(testArchive)) + using (var wrappedStream = SharpCompressStream.Create(fileStream, bufferSize: 32768)) + using (var archive = ArchiveFactory.Open(wrappedStream)) + { + Assert.Equal(ArchiveType.Zip, archive.Type); + Assert.Equal(3, archive.Entries.Count()); + } + } + + [Fact] + public void ArchiveFactory_Open_WithRawFileStream() + { + // Test that ArchiveFactory.Open works correctly with a raw FileStream + // This is the common use case reported in the issue + var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.noEmptyDirs.zip"); + + using (var stream = File.OpenRead(testArchive)) + using (var archive = ArchiveFactory.Open(stream)) + { + Assert.Equal(ArchiveType.Zip, archive.Type); + Assert.Equal(3, archive.Entries.Count()); + } + } } From ea77666b4a42b974b21d388cf6e1dd55c1bc0c56 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 13:38:38 +0000 Subject: [PATCH 5/5] Final verification: All tests pass, no security issues Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- src/SharpCompress/packages.lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SharpCompress/packages.lock.json b/src/SharpCompress/packages.lock.json index b85a38f7..904860ce 100644 --- a/src/SharpCompress/packages.lock.json +++ b/src/SharpCompress/packages.lock.json @@ -335,9 +335,9 @@ "net8.0": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[8.0.20, )", - "resolved": "8.0.20", - "contentHash": "Rhcto2AjGvTO62+/VTmBpumBOmqIGp7nYEbTbmEXkCq4yPGxV8whju3/HsIA/bKyo2+DggaYk5+/8sxb1AbPTw==" + "requested": "[8.0.0, )", + "resolved": "8.0.0", + "contentHash": "B3etT5XQ2nlWkZGO2m/ytDYrOmSsQG1XNBaM6ZYlX5Ch/tDrMFadr0/mK6gjZwaQc55g+5+WZMw4Cz3m8VEF7g==" }, "Microsoft.SourceLink.GitHub": { "type": "Direct",