using System;
using System.IO;
using SharpCompress.IO;
namespace SharpCompress.Common.Rar.Headers
{
// http://www.forensicswiki.org/w/images/5/5b/RARFileStructure.txt
// https://www.rarlab.com/technote.htm
internal class RarHeader : IRarHeader
{
private readonly HeaderType _headerType;
private readonly bool _isRar5;
internal static RarHeader TryReadBase(RarCrcBinaryReader reader, bool isRar5, ArchiveEncoding archiveEncoding)
{
try
{
return new RarHeader(reader, isRar5, archiveEncoding);
}
catch (EndOfStreamException)
{
return null;
}
}
private RarHeader(RarCrcBinaryReader reader, bool isRar5, ArchiveEncoding archiveEncoding)
{
_headerType = HeaderType.Null;
_isRar5 = isRar5;
ArchiveEncoding = archiveEncoding;
if (IsRar5)
{
HeaderCrc = reader.ReadUInt32();
reader.ResetCrc();
HeaderSize = (int)reader.ReadRarVIntUInt32(3);
reader.Mark();
HeaderCode = reader.ReadRarVIntByte();
HeaderFlags = reader.ReadRarVIntUInt16(2);
if (HasHeaderFlag(HeaderFlagsV5.HAS_EXTRA))
{
ExtraSize = reader.ReadRarVIntUInt32();
}
if (HasHeaderFlag(HeaderFlagsV5.HAS_DATA))
{
AdditionalDataSize = (long)reader.ReadRarVInt();
}
} else {
reader.Mark();
HeaderCrc = reader.ReadUInt16();
reader.ResetCrc();
HeaderCode = reader.ReadByte();
HeaderFlags = reader.ReadUInt16();
HeaderSize = reader.ReadInt16();
if (HasHeaderFlag(HeaderFlagsV4.HAS_DATA))
{
AdditionalDataSize = reader.ReadUInt32();
}
}
}
protected RarHeader(RarHeader header, RarCrcBinaryReader reader, HeaderType headerType) {
_headerType = headerType;
_isRar5 = header.IsRar5;
HeaderCrc = header.HeaderCrc;
HeaderCode = header.HeaderCode;
HeaderFlags = header.HeaderFlags;
HeaderSize = header.HeaderSize;
ExtraSize = header.ExtraSize;
AdditionalDataSize = header.AdditionalDataSize;
ArchiveEncoding = header.ArchiveEncoding;
ReadFinish(reader);
int n = RemainingHeaderBytes(reader);
if (n > 0)
{
reader.ReadBytes(n);
}
VerifyHeaderCrc(reader.GetCrc32());
}
protected int RemainingHeaderBytes(MarkingBinaryReader reader) {
return checked(HeaderSize - (int)reader.CurrentReadByteCount);
}
protected virtual void ReadFinish(MarkingBinaryReader reader)
{
throw new NotImplementedException();
}
private void VerifyHeaderCrc(uint crc32)
{
var b = (IsRar5 ? crc32 : (ushort)crc32) == HeaderCrc;
if (!b)
{
throw new InvalidFormatException("rar header crc mismatch");
}
}
public HeaderType HeaderType => _headerType;
protected bool IsRar5 => _isRar5;
protected uint HeaderCrc { get; }
internal byte HeaderCode { get; }
protected ushort HeaderFlags { get; }
protected bool HasHeaderFlag(ushort flag)
{
return (HeaderFlags & flag) == flag;
}
protected int HeaderSize { get; }
internal ArchiveEncoding ArchiveEncoding { get; }
///
/// Extra header size.
///
protected uint ExtraSize { get; }
///
/// Size of additional data (eg file contents)
///
protected long AdditionalDataSize { get; }
}
}