using System; using System.Collections.Generic; using System.IO; using System.Linq; using SharpCompress.Common.Rar.Headers; using SharpCompress.IO; using SharpCompress.Readers; namespace SharpCompress.Common.Rar { /// /// A RarArchiveVolume is a single rar file that may or may not be a split RarArchive. A Rar Archive is one to many Rar Parts /// public abstract class RarVolume : Volume { private readonly RarHeaderFactory _headerFactory; internal RarVolume(StreamingMode mode, Stream stream, ReaderOptions options) : base(stream, options) { _headerFactory = new RarHeaderFactory(mode, options); } internal ArchiveHeader ArchiveHeader { get; private set; } internal StreamingMode Mode => _headerFactory.StreamingMode; internal abstract IEnumerable ReadFileParts(); internal abstract RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader); internal IEnumerable GetVolumeFileParts() { MarkHeader lastMarkHeader = null; foreach (var header in _headerFactory.ReadHeaders(Stream)) { switch (header.HeaderType) { case HeaderType.Mark: { lastMarkHeader = header as MarkHeader; } break; case HeaderType.Archive: { ArchiveHeader = header as ArchiveHeader; } break; case HeaderType.File: { var fh = header as FileHeader; yield return CreateFilePart(lastMarkHeader, fh); } break; } } } private void EnsureArchiveHeaderLoaded() { if (ArchiveHeader == null) { if (Mode == StreamingMode.Streaming) { throw new InvalidOperationException("ArchiveHeader should never been null in a streaming read."); } // we only want to load the archive header to avoid overhead but have to do the nasty thing and reset the stream GetVolumeFileParts().First(); Stream.Position = 0; } } /// /// RarArchive is the first volume of a multi-part archive. /// Only Rar 3.0 format and higher /// public override bool IsFirstVolume { get { EnsureArchiveHeaderLoaded(); return ArchiveHeader.IsFirstVolume; } } /// /// RarArchive is part of a multi-part archive. /// public override bool IsMultiVolume { get { EnsureArchiveHeaderLoaded(); return ArchiveHeader.IsVolume; } } /// /// RarArchive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files). /// Currently, SharpCompress cannot decompress SOLID archives. /// public bool IsSolidArchive { get { EnsureArchiveHeaderLoaded(); return ArchiveHeader.IsSolid; } } } }