mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-09-22 14:55:11 +00:00
Add XZ models
This commit is contained in:
@@ -45,6 +45,7 @@ Not all of this information was able to be gathered directly from the files in q
|
||||
| [Technical Committee T10](https://www.t10.org/) | PIC |
|
||||
| [The Go tools for Windows + Assembler](https://www.godevtool.com/) | PortableExecutable |
|
||||
| [The Whole Half-Life](https://twhl.info/wiki/page/Specification:_WAD3) | WAD3 |
|
||||
| [Tukaani](https://tukaani.org/xz/format.html) | XZ |
|
||||
| [Unshield](https://github.com/twogood/unshield) | InstallShieldCabinet |
|
||||
| [unshieldv3](https://github.com/wfr/unshieldv3) | InstallShieldArchiveV3 |
|
||||
| [Valve Developer Community](https://developer.valvesoftware.com/wiki/Main_Page) | BSP, VPK |
|
||||
|
||||
@@ -1,10 +1,26 @@
|
||||
namespace SabreTools.Data.Models.XZ
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a placeholder model for future work
|
||||
/// </summary>
|
||||
/// <see href="https://tukaani.org/xz/xz-file-format.txt"/>
|
||||
public class Archive
|
||||
{
|
||||
/// <summary>
|
||||
/// Pre-blocks header
|
||||
/// </summary>
|
||||
public Header? Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sequence of 0 or more blocks
|
||||
/// </summary>
|
||||
public Block[]? Blocks { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Index structure
|
||||
/// </summary>
|
||||
public Index? Index { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Post-blocks footer
|
||||
/// </summary>
|
||||
public Footer? Footer { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
80
SabreTools.Serialization/Models/XZ/Block.cs
Normal file
80
SabreTools.Serialization/Models/XZ/Block.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
namespace SabreTools.Data.Models.XZ
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single compressed block in the stream
|
||||
/// </summary>
|
||||
public class Block
|
||||
{
|
||||
/// <summary>
|
||||
/// Size of the header
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The real header size can be calculated by the following:
|
||||
/// (HeaderSize + 1) * 4
|
||||
/// </remarks>
|
||||
public byte HeaderSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Block Flags field is a bit field
|
||||
/// </summary>
|
||||
public BlockFlags Flags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the compressed data
|
||||
/// Present if <see cref="BlockFlags.CompressedSize"/> is set.
|
||||
/// </summary>
|
||||
/// <remarks>Stored as a variable-length integer</remarks>
|
||||
public byte[]? CompressedSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the block after decompression
|
||||
/// Present if <see cref="BlockFlags.UncompressedSize"/> is set.
|
||||
/// </summary>
|
||||
/// <remarks>Stored as a variable-length integer</remarks>
|
||||
public byte[]? UncompressedSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of filter flags
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The number of filter flags is given by the first two
|
||||
/// bits of <see cref="Flags"/>
|
||||
/// </remarks>
|
||||
public FilterFlag[]? FilterFlags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This field contains as many null byte as it is needed to make
|
||||
/// the Block Header have the size specified in Block Header Size.
|
||||
/// </summary>
|
||||
public byte[]? HeaderPadding { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The CRC32 is calculated over everything in the Block Header
|
||||
/// field except the CRC32 field itself. It is stored as an
|
||||
/// unsigned 32-bit little endian integer.
|
||||
/// </summary>
|
||||
public uint Crc32 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The format of Compressed Data depends on Block Flags and List
|
||||
/// of Filter Flags
|
||||
/// </summary>
|
||||
public byte[]? CompressedData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Block Padding MUST contain 0-3 null bytes to make the size of
|
||||
/// the Block a multiple of four bytes. This can be needed when
|
||||
/// the size of Compressed Data is not a multiple of four.
|
||||
/// </summary>
|
||||
public byte[]? BlockPadding { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type and size of the Check field depends on which bits
|
||||
/// are set in the Stream Flags field.
|
||||
///
|
||||
/// The Check, when used, is calculated from the original
|
||||
/// uncompressed data.
|
||||
/// </summary>
|
||||
public byte[]? Check { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@ namespace SabreTools.Data.Models.XZ
|
||||
{
|
||||
public static class Constants
|
||||
{
|
||||
public static readonly byte[] SignatureBytes = [0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00];
|
||||
public static readonly byte[] HeaderSignatureBytes = [0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00];
|
||||
|
||||
public static readonly byte[] FooterSignatureBytes = [0x59, 0x5A];
|
||||
}
|
||||
}
|
||||
47
SabreTools.Serialization/Models/XZ/Enums.cs
Normal file
47
SabreTools.Serialization/Models/XZ/Enums.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Data.Models.XZ
|
||||
{
|
||||
[Flags]
|
||||
public enum BlockFlags : byte
|
||||
{
|
||||
#region Bits 0-1 - Number of filters
|
||||
|
||||
OneFilter = 0x00,
|
||||
TwoFilters = 0x01,
|
||||
ThreeFiltrs = 0x02,
|
||||
FourFilters = 0x03,
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Compressed size field present
|
||||
/// </summary>
|
||||
CompressedSize = 0x40,
|
||||
|
||||
/// <summary>
|
||||
/// Uncompressed size field present
|
||||
/// </summary>
|
||||
UncompressedSize = 0x80,
|
||||
}
|
||||
|
||||
public enum HeaderFlags : ushort
|
||||
{
|
||||
None = 0x0000,
|
||||
Crc32 = 0x0001,
|
||||
Reserved0x02 = 0x0002,
|
||||
Reserved0x03 = 0x0003,
|
||||
Crc64 = 0x0004,
|
||||
Reserved0x05 = 0x0005,
|
||||
Reserved0x06 = 0x0006,
|
||||
Reserved0x07 = 0x0007,
|
||||
Reserved0x08 = 0x0008,
|
||||
Reserved0x09 = 0x0009,
|
||||
Sha256 = 0x000A,
|
||||
Reserved0x0B = 0x000B,
|
||||
Reserved0x0C = 0x000C,
|
||||
Reserved0x0D = 0x000D,
|
||||
Reserved0x0E = 0x000E,
|
||||
Reserved0x0F = 0x000F,
|
||||
}
|
||||
}
|
||||
23
SabreTools.Serialization/Models/XZ/FilterFlags.cs
Normal file
23
SabreTools.Serialization/Models/XZ/FilterFlags.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace SabreTools.Data.Models.XZ
|
||||
{
|
||||
public class FilterFlag
|
||||
{
|
||||
/// <summary>
|
||||
/// Filter ID
|
||||
/// </summary>
|
||||
/// <remarks>Stored as a variable-length integer</remarks>
|
||||
public byte[]? FilterID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Filter ID
|
||||
/// </summary>
|
||||
/// <remarks>Stored as a variable-length integer</remarks>
|
||||
public byte[]? SizeOfProperties { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Properties of the filter whose length is given by
|
||||
/// <see cref="SizeOfProperties"/>
|
||||
/// </summary>
|
||||
public byte[]? Properties { get; set; }
|
||||
}
|
||||
}
|
||||
39
SabreTools.Serialization/Models/XZ/Footer.cs
Normal file
39
SabreTools.Serialization/Models/XZ/Footer.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
namespace SabreTools.Data.Models.XZ
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the post-block data in the stream
|
||||
/// </summary>
|
||||
public class Footer
|
||||
{
|
||||
/// <summary>
|
||||
/// The CRC32 is calculated from the Backward Size and Stream Flags
|
||||
/// fields. It is stored as an unsigned 32-bit little endian
|
||||
/// integer.
|
||||
/// </summary>
|
||||
public uint Crc32 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Backward Size is stored as a 32-bit little endian integer,
|
||||
/// which indicates the size of the Index field as multiple of
|
||||
/// four bytes, minimum value being four bytes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The real index size can be calculated by the following:
|
||||
/// (BackwardSize + 1) * 4
|
||||
/// </remarks>
|
||||
public uint BackwardSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This is a copy of the Stream Flags field from the Stream
|
||||
/// Header. The information stored to Stream Flags is needed
|
||||
/// when parsing the Stream backwards.
|
||||
/// </summary>
|
||||
public HeaderFlags Flags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Header magic number ("YZ")
|
||||
/// </summary>
|
||||
/// <remarks>2 bytes</remarks>
|
||||
public byte[]? Signature { get; set; }
|
||||
}
|
||||
}
|
||||
27
SabreTools.Serialization/Models/XZ/Header.cs
Normal file
27
SabreTools.Serialization/Models/XZ/Header.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
namespace SabreTools.Data.Models.XZ
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the pre-block data in the stream
|
||||
/// </summary>
|
||||
public class Header
|
||||
{
|
||||
/// <summary>
|
||||
/// Header magic number (0xFD, '7', 'z', 'X', 'Z', 0x00)
|
||||
/// </summary>
|
||||
/// <remarks>6 bytes</remarks>
|
||||
public byte[]? Signature { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The first byte of Stream Flags is always a null byte. In the
|
||||
/// future, this byte may be used to indicate a new Stream version
|
||||
/// or other Stream properties.
|
||||
/// </summary>
|
||||
public HeaderFlags Flags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The CRC32 is calculated from the Stream Flags field. It is
|
||||
/// stored as an unsigned 32-bit little endian integer.
|
||||
/// </summary>
|
||||
public uint Crc32 { get; set; }
|
||||
}
|
||||
}
|
||||
36
SabreTools.Serialization/Models/XZ/Index.cs
Normal file
36
SabreTools.Serialization/Models/XZ/Index.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
namespace SabreTools.Data.Models.XZ
|
||||
{
|
||||
public class Index
|
||||
{
|
||||
/// <summary>
|
||||
/// The value of Index Indicator is always 0x00
|
||||
/// </summary>
|
||||
public byte IndexIndicator { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This field indicates how many Records there are in the List
|
||||
/// of Records field, and thus how many Blocks there are in the
|
||||
/// Stream
|
||||
/// </summary>
|
||||
/// <remarks>Stored as a variable-length integer</remarks>
|
||||
public byte[]? NumberOfRecords { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// One record per block
|
||||
/// </summary>
|
||||
public Record[]? Records { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This field MUST contain 0-3 null bytes to pad the Index to
|
||||
/// a multiple of four bytes.
|
||||
/// </summary>
|
||||
public byte[]? Padding { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The CRC32 is calculated over everything in the Index field
|
||||
/// except the CRC32 field itself. The CRC32 is stored as an
|
||||
/// unsigned 32-bit little endian integer.
|
||||
/// </summary>
|
||||
public uint Crc32 { get; set; }
|
||||
}
|
||||
}
|
||||
17
SabreTools.Serialization/Models/XZ/Record.cs
Normal file
17
SabreTools.Serialization/Models/XZ/Record.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace SabreTools.Data.Models.XZ
|
||||
{
|
||||
public class Record
|
||||
{
|
||||
/// <summary>
|
||||
/// Unpadded size of the block
|
||||
/// </summary>
|
||||
/// <remarks>Stored as a variable-length integer</remarks>
|
||||
public byte UnpaddedSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Uncompressed size of the block
|
||||
/// </summary>
|
||||
/// <remarks>Stored as a variable-length integer</remarks>
|
||||
public byte[]? NumberOfRecords { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -788,7 +788,7 @@ namespace SabreTools.Serialization
|
||||
|
||||
#region XZ
|
||||
|
||||
if (magic.StartsWith(Data.Models.XZ.Constants.SignatureBytes))
|
||||
if (magic.StartsWith(Data.Models.XZ.Constants.HeaderSignatureBytes))
|
||||
return WrapperType.XZ;
|
||||
|
||||
if (extension.Equals("xz", StringComparison.OrdinalIgnoreCase))
|
||||
|
||||
@@ -132,7 +132,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
extension = "xml";
|
||||
break;
|
||||
}
|
||||
else if (overlaySample.StartsWith(Data.Models.XZ.Constants.SignatureBytes))
|
||||
else if (overlaySample.StartsWith(Data.Models.XZ.Constants.HeaderSignatureBytes))
|
||||
{
|
||||
extension = "xz";
|
||||
break;
|
||||
|
||||
@@ -271,7 +271,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
extension = "xml";
|
||||
break;
|
||||
}
|
||||
else if (overlaySample.StartsWith(Data.Models.XZ.Constants.SignatureBytes))
|
||||
else if (overlaySample.StartsWith(Data.Models.XZ.Constants.HeaderSignatureBytes))
|
||||
{
|
||||
extension = "xz";
|
||||
break;
|
||||
@@ -474,7 +474,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
extension = "xml";
|
||||
break;
|
||||
}
|
||||
else if (resourceSample.StartsWith(Data.Models.XZ.Constants.SignatureBytes))
|
||||
else if (resourceSample.StartsWith(Data.Models.XZ.Constants.HeaderSignatureBytes))
|
||||
{
|
||||
extension = "xz";
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user