using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Common.Rar.Headers;
using SharpCompress.IO;
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, Options options)
: base(stream, options)
{
headerFactory = new RarHeaderFactory(mode, options);
}
internal StreamingMode Mode
{
get
{
return headerFactory.StreamingMode;
}
}
internal abstract IEnumerable ReadFileParts();
internal abstract RarFilePart CreateFilePart(FileHeader fileHeader, MarkHeader markHeader);
internal IEnumerable GetVolumeFileParts()
{
MarkHeader previousMarkHeader = null;
foreach (RarHeader header in headerFactory.ReadHeaders(this.Stream))
{
switch (header.HeaderType)
{
case HeaderType.ArchiveHeader:
{
ArchiveHeader = header as ArchiveHeader;
}
break;
case HeaderType.MarkHeader:
{
previousMarkHeader = header as MarkHeader;
}
break;
case HeaderType.FileHeader:
{
FileHeader fh = header as FileHeader;
RarFilePart fp = CreateFilePart(fh, previousMarkHeader);
yield return fp;
}
break;
}
}
}
internal ArchiveHeader ArchiveHeader
{
get;
private set;
}
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.ArchiveHeaderFlags.HasFlag(ArchiveFlags.FIRSTVOLUME);
}
}
///
/// RarArchive is part of a multi-part archive.
///
public override bool IsMultiVolume
{
get
{
EnsureArchiveHeaderLoaded();
return ArchiveHeader.ArchiveHeaderFlags.HasFlag(ArchiveFlags.VOLUME);
}
}
///
/// 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.ArchiveHeaderFlags.HasFlag(ArchiveFlags.SOLID);
}
}
}
}