factory the headers instead of creating

This commit is contained in:
Adam Hathcock
2026-01-19 14:19:15 +00:00
parent f359f553b3
commit 2e95832bea
10 changed files with 71 additions and 56 deletions

View File

@@ -4,13 +4,14 @@ namespace SharpCompress.Common.Rar.Headers;
internal class AvHeader : RarHeader
{
public AvHeader(RarHeader header, RarCrcBinaryReader reader)
: base(header, reader, HeaderType.Av)
public static AvHeader Create(RarHeader header, RarCrcBinaryReader reader)
{
if (IsRar5)
var c = CreateChild<AvHeader>(header, reader, HeaderType.Av);
if (c.IsRar5)
{
throw new InvalidFormatException("unexpected rar5 record");
}
return c;
}
protected override void ReadFinish(MarkingBinaryReader reader)

View File

@@ -6,8 +6,8 @@ namespace SharpCompress.Common.Rar.Headers;
internal class ArchiveCryptHeader : RarHeader
{
public ArchiveCryptHeader(RarHeader header, RarCrcBinaryReader reader)
: base(header, reader, HeaderType.Crypt) { }
public static ArchiveCryptHeader Create(RarHeader header, RarCrcBinaryReader reader) =>
CreateChild<ArchiveCryptHeader>(header, reader, HeaderType.Crypt);
public Rar5CryptoInfo CryptInfo = new();

View File

@@ -4,9 +4,8 @@ namespace SharpCompress.Common.Rar.Headers;
internal sealed class ArchiveHeader : RarHeader
{
public ArchiveHeader(RarHeader header, RarCrcBinaryReader reader)
: base(header, reader, HeaderType.Archive) { }
public static ArchiveHeader Create(RarHeader header, RarCrcBinaryReader reader) =>
CreateChild<ArchiveHeader>(header, reader, HeaderType.Archive);
protected override void ReadFinish(MarkingBinaryReader reader)
{
if (IsRar5)

View File

@@ -4,13 +4,14 @@ namespace SharpCompress.Common.Rar.Headers;
internal class CommentHeader : RarHeader
{
protected CommentHeader(RarHeader header, RarCrcBinaryReader reader)
: base(header, reader, HeaderType.Comment)
public static CommentHeader Create(RarHeader header, RarCrcBinaryReader reader)
{
if (IsRar5)
var c = CreateChild<CommentHeader>(header, reader, HeaderType.Comment);
if (c.IsRar5)
{
throw new InvalidFormatException("unexpected rar5 record");
}
return c;
}
protected override void ReadFinish(MarkingBinaryReader reader)

View File

@@ -4,8 +4,8 @@ namespace SharpCompress.Common.Rar.Headers;
internal class EndArchiveHeader : RarHeader
{
public EndArchiveHeader(RarHeader header, RarCrcBinaryReader reader)
: base(header, reader, HeaderType.EndArchive) { }
public static EndArchiveHeader Create(RarHeader header, RarCrcBinaryReader reader) =>
CreateChild<EndArchiveHeader>(header, reader, HeaderType.EndArchive);
protected override void ReadFinish(MarkingBinaryReader reader)
{

View File

@@ -17,8 +17,8 @@ internal class FileHeader : RarHeader
{
private byte[]? _hash;
public FileHeader(RarHeader header, RarCrcBinaryReader reader, HeaderType headerType)
: base(header, reader, headerType) { }
public static FileHeader Create(RarHeader header, RarCrcBinaryReader reader, HeaderType headerType) =>
CreateChild<FileHeader>(header, reader, headerType);
protected override void ReadFinish(MarkingBinaryReader reader)
{

View File

@@ -5,13 +5,14 @@ namespace SharpCompress.Common.Rar.Headers;
// ProtectHeader is part of the Recovery Record feature
internal sealed class ProtectHeader : RarHeader
{
public ProtectHeader(RarHeader header, RarCrcBinaryReader reader)
: base(header, reader, HeaderType.Protect)
public static ProtectHeader Create(RarHeader header, RarCrcBinaryReader reader)
{
if (IsRar5)
var c = CreateChild<ProtectHeader>(header, reader, HeaderType.Protect);
if (c.IsRar5)
{
throw new InvalidFormatException("unexpected rar5 record");
}
return c;
}
protected override void ReadFinish(MarkingBinaryReader reader)

View File

@@ -7,8 +7,13 @@ namespace SharpCompress.Common.Rar.Headers;
// https://www.rarlab.com/technote.htm
internal class RarHeader : IRarHeader
{
private readonly HeaderType _headerType;
private readonly bool _isRar5;
private HeaderType _headerType;
private bool _isRar5;
protected RarHeader()
{
ArchiveEncoding = new ArchiveEncoding();
}
internal static RarHeader? TryReadBase(
RarCrcBinaryReader reader,
@@ -18,7 +23,9 @@ internal class RarHeader : IRarHeader
{
try
{
return new RarHeader(reader, isRar5, archiveEncoding);
var header = new RarHeader();
header.Initialize(reader, isRar5, archiveEncoding);
return header;
}
catch (InvalidFormatException)
{
@@ -26,7 +33,7 @@ internal class RarHeader : IRarHeader
}
}
private RarHeader(RarCrcBinaryReader reader, bool isRar5, IArchiveEncoding archiveEncoding)
private void Initialize(RarCrcBinaryReader reader, bool isRar5, IArchiveEncoding archiveEncoding)
{
_headerType = HeaderType.Null;
_isRar5 = isRar5;
@@ -64,26 +71,31 @@ internal class RarHeader : IRarHeader
}
}
protected RarHeader(RarHeader header, RarCrcBinaryReader reader, HeaderType headerType)
internal static T CreateChild<T>(RarHeader header, RarCrcBinaryReader reader, HeaderType headerType)
where T : RarHeader, new()
{
_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);
var child = new T()
{
ArchiveEncoding = header.ArchiveEncoding
};
child. _headerType = headerType;
child. _isRar5 = header.IsRar5;
child. HeaderCrc = header.HeaderCrc;
child. HeaderCode = header.HeaderCode;
child. HeaderFlags = header.HeaderFlags;
child.HeaderSize = header.HeaderSize;
child.ExtraSize = header.ExtraSize;
child. AdditionalDataSize = header.AdditionalDataSize;
child.ReadFinish(reader);
var n = RemainingHeaderBytes(reader);
var n = child.RemainingHeaderBytes(reader);
if (n > 0)
{
reader.ReadBytes(n);
}
VerifyHeaderCrc(reader.GetCrc32());
child. VerifyHeaderCrc(reader.GetCrc32());
return child;
}
protected int RemainingHeaderBytes(MarkingBinaryReader reader) =>
@@ -103,27 +115,27 @@ internal class RarHeader : IRarHeader
public HeaderType HeaderType => _headerType;
protected bool IsRar5 => _isRar5;
internal bool IsRar5 => _isRar5;
protected uint HeaderCrc { get; }
protected uint HeaderCrc { get;private set; }
internal byte HeaderCode { get; }
internal byte HeaderCode { get;private set; }
protected ushort HeaderFlags { get; }
protected ushort HeaderFlags { get;private set; }
protected bool HasHeaderFlag(ushort flag) => (HeaderFlags & flag) == flag;
protected int HeaderSize { get; }
protected int HeaderSize { get;private set; }
internal IArchiveEncoding ArchiveEncoding { get; }
internal IArchiveEncoding ArchiveEncoding { get; private set; }
/// <summary>
/// Extra header size.
/// </summary>
protected uint ExtraSize { get; }
protected uint ExtraSize { get;private set; }
/// <summary>
/// Size of additional data (eg file contents)
/// </summary>
protected long AdditionalDataSize { get; }
protected long AdditionalDataSize { get;private set; }
}

View File

@@ -80,7 +80,7 @@ public class RarHeaderFactory
case HeaderCodeV.RAR5_ARCHIVE_HEADER:
case HeaderCodeV.RAR4_ARCHIVE_HEADER:
{
var ah = new ArchiveHeader(header, reader);
var ah = ArchiveHeader.Create(header, reader);
if (ah.IsEncrypted == true)
{
//!!! rar5 we don't know yet
@@ -91,7 +91,7 @@ public class RarHeaderFactory
case HeaderCodeV.RAR4_PROTECT_HEADER:
{
var ph = new ProtectHeader(header, reader);
var ph = ProtectHeader.Create(header, reader);
// skip the recovery record data, we do not use it.
switch (StreamingMode)
{
@@ -116,7 +116,7 @@ public class RarHeaderFactory
case HeaderCodeV.RAR5_SERVICE_HEADER:
{
var fh = new FileHeader(header, reader, HeaderType.Service);
var fh = FileHeader.Create(header, reader, HeaderType.Service);
if (fh.FileName == "CMT")
{
fh.PackedStream = new ReadOnlySubStream(reader.BaseStream, fh.CompressedSize);
@@ -130,7 +130,7 @@ public class RarHeaderFactory
case HeaderCodeV.RAR4_NEW_SUB_HEADER:
{
var fh = new FileHeader(header, reader, HeaderType.NewSub);
var fh = FileHeader.Create(header, reader, HeaderType.NewSub);
SkipData(fh, reader);
return fh;
}
@@ -138,7 +138,7 @@ public class RarHeaderFactory
case HeaderCodeV.RAR5_FILE_HEADER:
case HeaderCodeV.RAR4_FILE_HEADER:
{
var fh = new FileHeader(header, reader, HeaderType.File);
var fh = FileHeader.Create(header, reader, HeaderType.File);
switch (StreamingMode)
{
case StreamingMode.Seekable:
@@ -181,11 +181,11 @@ public class RarHeaderFactory
case HeaderCodeV.RAR5_END_ARCHIVE_HEADER:
case HeaderCodeV.RAR4_END_ARCHIVE_HEADER:
{
return new EndArchiveHeader(header, reader);
return EndArchiveHeader.Create(header, reader);
}
case HeaderCodeV.RAR5_ARCHIVE_ENCRYPTION_HEADER:
{
var cryptoHeader = new ArchiveCryptHeader(header, reader);
var cryptoHeader = ArchiveCryptHeader.Create(header, reader);
IsEncrypted = true;
_cryptInfo = cryptoHeader.CryptInfo;

View File

@@ -4,13 +4,14 @@ namespace SharpCompress.Common.Rar.Headers;
internal class SignHeader : RarHeader
{
protected SignHeader(RarHeader header, RarCrcBinaryReader reader)
: base(header, reader, HeaderType.Sign)
public static SignHeader Create(RarHeader header, RarCrcBinaryReader reader)
{
if (IsRar5)
{
throw new InvalidFormatException("unexpected rar5 record");
}
var c = CreateChild<SignHeader>(header, reader, HeaderType.Sign);
if (c.IsRar5)
{
throw new InvalidFormatException("unexpected rar5 record");
}
return c;
}
protected override void ReadFinish(MarkingBinaryReader reader)