[CoreRarArchive] Add more structures for reading

This commit is contained in:
Matt Nadareski
2018-01-16 11:10:50 -08:00
parent 8c01fa6dbf
commit 50a59a616c

View File

@@ -1,10 +1,119 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using SabreTools.Library.Data; using SabreTools.Library.Data;
/// <summary> /// <summary>
/// http://www.rarlab.com/technote.htm#srvheaders /// This code is based on the header format described at http://www.rarlab.com/technote.htm#srvheaders
/// </summary> /// </summary>
/// <remarks>
/// ---------------------------------------------
/// vint
///
/// Variable length integer. Can include one or more bytes, where lower 7 bits of every byte contain integer data
/// and highest bit in every byte is the continuation flag.If highest bit is 0, this is the last byte in sequence.
/// So first byte contains 7 least significant bits of integer and continuation flag. Second byte, if present,
/// contains next 7 bits and so on.
///
/// Currently RAR format uses vint to store up to 64 bit integers, resulting in 10 bytes maximum. This value may
/// be increased in the future if necessary for some reason.
///
/// Sometimes RAR needs to pre-allocate space for vint before knowing its exact value. In such situation it can
/// allocate more space than really necessary and then fill several leading bytes with 0x80 hexadecimal, which means
/// 0 with continuation flag set.
/// ----------------------------------------------
/// General archive layout:
///
/// Self-extracting module(optional) (RAR assumes the maximum SFX module size to not exceed 1 MB, but this value
/// can be increased in the future.
/// RAR 5.0 signature (RAR 5.0 signature consists of 8 bytes: 0x52 0x61 0x72 0x21 0x1A 0x07 0x01 0x00.
/// You need to search for this signature in supposed archive from beginning and up to maximum SFX
/// module size. Just for comparison this is RAR 4.x 7 byte length signature: 0x52 0x61 0x72 0x21 0x1A 0x07 0x00.)
/// Archive encryption header(optional)
/// Main archive header
/// Archive comment service header(optional)
/// File header 1
/// Service headers(NTFS ACL, streams, etc.) for preceding file(optional).
/// ...
/// File header N
/// Service headers(NTFS ACL, streams, etc.) for preceding file(optional).
/// Recovery record(optional).
/// End of archive header.
/// ----------------------------------------------
/// General archive block format:
///
/// Header CRC32: uint32 (CRC32 of header data starting from Header size field and up to and including the optional extra area.)
/// Header size: vint (Size of header data starting from Header type field and up to and including the optional extra area.
/// This field must not be longer than 3 bytes in current implementation, resulting in 2 MB maximum header size.)
/// Header type: vint (Type of archive header. Possible values are: )
/// 1 Main archive header.
/// 2 File header.
/// 3 Service header.
/// 4 Archive encryption header.
/// 5 End of archive header.
/// Header flags: vint (Flags common for all headers:)
/// 0x0001 Extra area is present in the end of header.
/// 0x0002 Data area is present in the end of header.
/// 0x0004 Blocks with unknown type and this flag must be skipped when updating an archive.
/// 0x0008 Data area is continuing from previous volume.
/// 0x0010 Data area is continuing in next volume.
/// 0x0020 Block depends on preceding file block.
/// 0x0040 Preserve a child block if host block is modified.
/// Extra area size: vint (Size of extra area. Optional field, present only if 0x0001 header flag is set.)
/// Data size: vint (Size of data area. Optional field, present only if 0x0002 header flag is set.)
/// ...: ... (Fields specific for current block type. See concrete block type descriptions for details)
/// Extra data: ... (Optional area containing additional header fields, present only if 0x0001 header flag is set.)
/// Data area: vint (Optional data area, present only if 0x0002 header flag is set. Used to store large data amounts, such as
/// compressed file data. Not counted in Header CRC and Header size fields.
/// ----------------------------------------------
/// General extra area format
///
/// Size: vint (Size of record data starting from Type.)
/// Type: vint (Record type. Different archive blocks have different associated extra area record types. Read the
/// concrete archive block description for details. New record types can be added in the future, so unknown
/// record types need to be skipped without interrupting an operation.)
/// Data: ... (Record dependent data. May be missing if record consists only from size and type.)
/// ----------------------------------------------
/// Archive encryption header:
///
/// Header CRC32: uint32
/// Header size: vint
/// Header type: vint (4)
/// Header flags: vint
/// Encryption version: vint (Version of encryption algorithm. Now only 0 version(AES-256) is supported.)
/// Encryption flags: vint
/// 0x0001 Password check data is present.
/// KDF count: 1 byte (Binary logarithm of iteration number for PBKDF2 function.RAR can refuse to process
/// KDF count exceeding some threshold. Concrete value of threshold is a version dependent.)
/// Salt: 16 bytes (Salt value used globally for all encrypted archive headers.)
/// Check value: 12 bytes (Value used to verify the password validity. Present only if 0x0001 encryption
/// flag is set.First 8 bytes are calculated using additional PBKDF2 rounds, 4 last bytes is the additional
/// checksum. Together with the standard header CRC32 we have 64 bit checksum to reliably verify this field
/// integrity and distinguish invalid password and damaged data. Further details can be found in UnRAR source code.)
/// ----------------------------------------------
/// Main archive header:
///
/// Header CRC32: uint32 (CRC32 of header data starting from Header size field and up to and including the optional extra area.)
/// Header size: vint (Size of header data starting from Header type field and up to and including the optional extra area. This field must not be longer than 3 bytes in current implementation, resulting in 2 MB maximum header size.)
/// Header type: vint (1)
/// Header flags: vint (Flags common for all headers)
/// Extra area size: vint (Size of extra area. Optional field, present only if 0x0001 header flag is set.)
/// Archive flags: vint
/// 0x0001 Volume.Archive is a part of multivolume set.
/// 0x0002 Volume number field is present.This flag is present in all volumes except first.
/// 0x0004 Solid archive.
/// 0x0008 Recovery record is present.
/// 0x0010 Locked archive.
/// Volume number: vint (Optional field, present only if 0x0002 archive flag is set. Not present for first volume,
/// 1 for second volume, 2 for third and so on.)
/// Extra area: ... (Optional area containing additional header fields, present only if 0x0001 header flag is set.)
/// [Extra area of main archive header can contain following record types
/// Type Name Description
/// 0x01 Locator Contains positions of different service blocks, so they can be accessed quickly, without scanning
/// the entire archive.This record is optional.If it is missing, it is still necessary to scan the entire archive
/// to verify presence of service blocks.]
/// ----------------------------------------------
/// </remarks>
namespace SabreTools.Library.FileTypes namespace SabreTools.Library.FileTypes
{ {
public class CoreRarArchive public class CoreRarArchive
@@ -110,4 +219,71 @@ namespace SabreTools.Library.FileTypes
public uint ServiceSize; // vint public uint ServiceSize; // vint
public byte[] ServiceData; public byte[] ServiceData;
} }
// BELOW ARE CONCRETE IMPLEMENTATIONS OF HEADER DETAILS
/// <summary>
/// General archive block format used by all RAR block types
/// </summary>
public class GeneralArchiveBlockFormat
{
public uint HeaderCRC32;
public uint HeaderSize; // vint
public HeaderType HeaderType;
public HeaderFlags HeaderFlags;
public ulong ExtraAreaSize; // vint
public ulong DataAreaSize; // vint
public byte[] ExtraArea;
public byte[] DataArea;
}
/// <summary>
/// General extra area format used by all RAR extra area records
/// </summary>
public class GeneralExtraAreaFormat
{
public ulong Size; // vint
public ulong Type; // vint
public byte[] Data;
}
/// <summary>
/// Encryption header only present in encrypted archives
///
/// Every proceeding header is started from 16 byte AES-256
/// initialization vectors followed by encrypted header data
/// </summary>
public class ArchiveEncryptionHeader : GeneralArchiveBlockFormat
{
public new HeaderType HeaderType = HeaderType.ArchiveEncryptionHeader;
public ulong EncryptionVersion; // vint
public ulong EncryptionFlags; // vint
}
/// <summary>
/// Types of archive header
/// </summary>
public enum HeaderType : ulong // vint
{
MainArchiveHeader = 1,
FileHeader = 2,
ServiceHeader = 3,
ArchiveEncryptionHeader = 4,
EndOfArchiveHeader = 5,
}
/// <summary>
/// Flags common for all headers
/// </summary>
[Flags]
public enum HeaderFlags : ulong // vint
{
ExtraAreaIsPresentInEndOfHeader = 0x0001,
DataAreaIsPresentInEndOfHeader = 0x0002,
BlocksWithUnknownType = 0x0004, // this flag must be skipped when updating an archive
DataAreaIsContinuingFromPreviousVolume = 0x0008,
DataAreaIsContinuingInNextVolume = 0x0010,
BlockDependsOnPrecedingFileBlock = 0x0020,
PreserveChildBlockIfHostBlockIsModified = 0x0040,
}
} }