mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-09-22 23:05:03 +00:00
Add MoPaQ models
This commit is contained in:
61
BurnOutSharp.Models/MoPaQ/Archive.cs
Normal file
61
BurnOutSharp.Models/MoPaQ/Archive.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
namespace BurnOutSharp.Models.MoPaQ
|
||||
{
|
||||
/// <summary>
|
||||
/// MPQ (MoPaQ) is an archive format developed by Blizzard Entertainment,
|
||||
/// purposed for storing data files, images, sounds, music and videos for
|
||||
/// their games. The name MoPaQ comes from the author of the format,
|
||||
/// Mike O'Brien (Mike O'brien PaCK).
|
||||
/// </summary>
|
||||
/// <see href="http://zezula.net/en/mpq/mpqformat.html"/>
|
||||
public class Archive
|
||||
{
|
||||
// TODO: Data before archive, ignored
|
||||
|
||||
/// <summary>
|
||||
/// MPQ User Data (optional)
|
||||
/// </summary>
|
||||
public UserData UserData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// MPQ Header (required)
|
||||
/// </summary>
|
||||
public ArchiveHeader ArchiveHeader { get; set; }
|
||||
|
||||
// TODO: Files (optional)
|
||||
// TODO: Special files (optional)
|
||||
|
||||
/// <summary>
|
||||
/// HET Table (optional)
|
||||
/// </summary>
|
||||
public HetTable HetTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// BET Table (optional)
|
||||
/// </summary>
|
||||
public BetTable BetTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Hash Table (optional)
|
||||
/// </summary>
|
||||
public HashEntry[] HashTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Block Table (optional)
|
||||
/// </summary>
|
||||
public BlockEntry[] BlockTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Hi-Block Table (optional)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Since World of Warcraft - The Burning Crusade, Blizzard extended
|
||||
/// the MPQ format to support archives larger than 4GB. The hi-block
|
||||
/// table holds the higher 16-bits of the file position in the MPQ.
|
||||
/// Hi-block table is plain array of 16-bit values. This table is
|
||||
/// not encrypted.
|
||||
/// </remarks>
|
||||
public short[] HiBlockTable { get; set; }
|
||||
|
||||
// TODO: Strong digital signature
|
||||
}
|
||||
}
|
||||
180
BurnOutSharp.Models/MoPaQ/ArchiveHeader.cs
Normal file
180
BurnOutSharp.Models/MoPaQ/ArchiveHeader.cs
Normal file
@@ -0,0 +1,180 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BurnOutSharp.Models.MoPaQ
|
||||
{
|
||||
/// <summary>
|
||||
/// MoPaQ archive header
|
||||
/// </summary>
|
||||
/// <see href="http://zezula.net/en/mpq/mpqformat.html"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class ArchiveHeader
|
||||
{
|
||||
#region V1 Properties
|
||||
|
||||
/// <summary>
|
||||
/// The MPQ archive signature
|
||||
/// </summary>
|
||||
public uint Signature;
|
||||
|
||||
/// <summary>
|
||||
/// Size of the archive header
|
||||
/// </summary>
|
||||
public uint HeaderSize;
|
||||
|
||||
/// <summary>
|
||||
/// Size of MPQ archive
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field is deprecated in the Burning Crusade MoPaQ format, and the size of the archive
|
||||
/// is calculated as the size from the beginning of the archive to the end of the hash table,
|
||||
/// block table, or extended block table (whichever is largest).
|
||||
/// </remarks>
|
||||
public uint ArchiveSize;
|
||||
|
||||
/// <summary>
|
||||
/// 0 = Format 1 (up to The Burning Crusade)
|
||||
/// 1 = Format 2 (The Burning Crusade and newer)
|
||||
/// 2 = Format 3 (WoW - Cataclysm beta or newer)
|
||||
/// 3 = Format 4 (WoW - Cataclysm beta or newer)
|
||||
/// </summary>
|
||||
public ushort FormatVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Power of two exponent specifying the number of 512-byte disk sectors in each logical sector
|
||||
/// in the archive. The size of each logical sector in the archive is 512 * 2 ^ BlockSize.
|
||||
/// </summary>
|
||||
public ushort BlockSize;
|
||||
|
||||
/// <summary>
|
||||
/// Offset to the beginning of the hash table, relative to the beginning of the archive.
|
||||
/// </summary>
|
||||
public uint HashTablePosition;
|
||||
|
||||
/// <summary>
|
||||
/// Offset to the beginning of the block table, relative to the beginning of the archive.
|
||||
/// </summary>
|
||||
public uint BlockTablePosition;
|
||||
|
||||
/// <summary>
|
||||
/// Number of entries in the hash table. Must be a power of two, and must be less than 2^16 for
|
||||
/// the original MoPaQ format, or less than 2^20 for the Burning Crusade format.
|
||||
/// </summary>
|
||||
public uint HashTableSize;
|
||||
|
||||
/// <summary>
|
||||
/// Number of entries in the block table
|
||||
/// </summary>
|
||||
public uint BlockTableSize;
|
||||
|
||||
#endregion
|
||||
|
||||
#region V2 Properties
|
||||
|
||||
/// <summary>
|
||||
/// Offset to the beginning of array of 16-bit high parts of file offsets.
|
||||
/// </summary>
|
||||
public ulong HiBlockTablePosition;
|
||||
|
||||
/// <summary>
|
||||
/// High 16 bits of the hash table offset for large archives.
|
||||
/// </summary>
|
||||
public ushort HashTablePositionHi;
|
||||
|
||||
/// <summary>
|
||||
/// High 16 bits of the block table offset for large archives.
|
||||
/// </summary>
|
||||
public ushort BlockTablePositionHi;
|
||||
|
||||
#endregion
|
||||
|
||||
#region V3 Properties
|
||||
|
||||
/// <summary>
|
||||
/// 64-bit version of the archive size
|
||||
/// </summary>
|
||||
public ulong ArchiveSizeLong;
|
||||
|
||||
/// <summary>
|
||||
/// 64-bit position of the BET table
|
||||
/// </summary>
|
||||
public ulong BetTablePosition;
|
||||
|
||||
/// <summary>
|
||||
/// 64-bit position of the HET table
|
||||
/// </summary>
|
||||
public ulong HetTablePosition;
|
||||
|
||||
#endregion
|
||||
|
||||
#region V4 Properties
|
||||
|
||||
/// <summary>
|
||||
/// Compressed size of the hash table
|
||||
/// </summary>
|
||||
public ulong HashTableSizeLong;
|
||||
|
||||
/// <summary>
|
||||
/// Compressed size of the block table
|
||||
/// </summary>
|
||||
public ulong BlockTableSizeLong;
|
||||
|
||||
/// <summary>
|
||||
/// Compressed size of the hi-block table
|
||||
/// </summary>
|
||||
public ulong HiBlockTableSize;
|
||||
|
||||
/// <summary>
|
||||
/// Compressed size of the HET block
|
||||
/// </summary>
|
||||
public ulong HetTableSize;
|
||||
|
||||
/// <summary>
|
||||
/// Compressed size of the BET block
|
||||
/// </summary>
|
||||
public ulong BetTablesize;
|
||||
|
||||
/// <summary>
|
||||
/// Size of raw data chunk to calculate MD5.
|
||||
/// </summary>
|
||||
/// <remarks>MD5 of each data chunk follows the raw file data.</remarks>
|
||||
public uint RawChunkSize;
|
||||
|
||||
/// <summary>
|
||||
/// MD5 of the block table before decryption
|
||||
/// </summary>
|
||||
/// <remarks>0x10 bytes</remarks>
|
||||
public byte[] BlockTableMD5;
|
||||
|
||||
/// <summary>
|
||||
/// MD5 of the hash table before decryption
|
||||
/// </summary>
|
||||
/// <remarks>0x10 bytes</remarks>
|
||||
public byte[] HashTableMD5;
|
||||
|
||||
/// <summary>
|
||||
/// MD5 of the hi-block table
|
||||
/// </summary>
|
||||
/// <remarks>0x10 bytes</remarks>
|
||||
public byte[] HiBlockTableMD5;
|
||||
|
||||
/// <summary>
|
||||
/// MD5 of the BET table before decryption
|
||||
/// </summary>
|
||||
/// <remarks>0x10 bytes</remarks>
|
||||
public byte[] BetTableMD5;
|
||||
|
||||
/// <summary>
|
||||
/// MD5 of the HET table before decryption
|
||||
/// </summary>
|
||||
/// <remarks>0x10 bytes</remarks>
|
||||
public byte[] HetTableMD5;
|
||||
|
||||
/// <summary>
|
||||
/// MD5 of the MPQ header from signature to (including) HetTableMD5
|
||||
/// </summary>
|
||||
/// <remarks>0x10 bytes</remarks>
|
||||
public byte[] MpqHeaderMD5;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
140
BurnOutSharp.Models/MoPaQ/BetTable.cs
Normal file
140
BurnOutSharp.Models/MoPaQ/BetTable.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BurnOutSharp.Models.MoPaQ
|
||||
{
|
||||
/// <summary>
|
||||
/// The BET table is present if the BetTablePos64 member of MPQ header is set
|
||||
/// to nonzero. BET table is a successor of classic block table, and can fully
|
||||
/// replace it. It is also supposed to be more effective.
|
||||
/// </summary>
|
||||
/// <see href="http://zezula.net/en/mpq/mpqformat.html"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class BetTable
|
||||
{
|
||||
// TODO: Extract this out and make in common between HET and BET
|
||||
#region Common Table Headers
|
||||
|
||||
/// <summary>
|
||||
/// 'BET\x1A'
|
||||
/// </summary>
|
||||
public uint Signature;
|
||||
|
||||
/// <summary>
|
||||
/// Version. Seems to be always 1
|
||||
/// </summary>
|
||||
public uint Version;
|
||||
|
||||
/// <summary>
|
||||
/// Size of the contained table
|
||||
/// </summary>
|
||||
public uint DataSize;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Size of the entire hash table, including the header (in bytes)
|
||||
/// </summary>
|
||||
public uint TableSize;
|
||||
|
||||
/// <summary>
|
||||
/// Number of files in the BET table
|
||||
/// </summary>
|
||||
public uint FileCount;
|
||||
|
||||
/// <summary>
|
||||
/// Unknown, set to 0x10
|
||||
/// </summary>
|
||||
public uint Unknown;
|
||||
|
||||
/// <summary>
|
||||
/// Size of one table entry (in bits)
|
||||
/// </summary>
|
||||
public uint TableEntrySize;
|
||||
|
||||
/// <summary>
|
||||
/// Bit index of the file position (within the entry record)
|
||||
/// </summary>
|
||||
public uint FilePositionBitIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Bit index of the file size (within the entry record)
|
||||
/// </summary>
|
||||
public uint FileSizeBitIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Bit index of the compressed size (within the entry record)
|
||||
/// </summary>
|
||||
public uint CompressedSizeBitIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Bit index of the flag index (within the entry record)
|
||||
/// </summary>
|
||||
public uint FlagIndexBitIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Bit index of the ??? (within the entry record)
|
||||
/// </summary>
|
||||
public uint UnknownBitIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Bit size of file position (in the entry record)
|
||||
/// </summary>
|
||||
public uint FilePositionBitCount;
|
||||
|
||||
/// <summary>
|
||||
/// Bit size of file size (in the entry record)
|
||||
/// </summary>
|
||||
public uint FileSizeBitCount;
|
||||
|
||||
/// <summary>
|
||||
/// Bit size of compressed file size (in the entry record)
|
||||
/// </summary>
|
||||
public uint CompressedSizeBitCount;
|
||||
|
||||
/// <summary>
|
||||
/// Bit size of flags index (in the entry record)
|
||||
/// </summary>
|
||||
public uint FlagIndexBitCount;
|
||||
|
||||
/// <summary>
|
||||
/// Bit size of ??? (in the entry record)
|
||||
/// </summary>
|
||||
public uint UnknownBitCount;
|
||||
|
||||
/// <summary>
|
||||
/// Total size of the BET hash
|
||||
/// </summary>
|
||||
public uint TotalBetHashSize;
|
||||
|
||||
/// <summary>
|
||||
/// Extra bits in the BET hash
|
||||
/// </summary>
|
||||
public uint BetHashSizeExtra;
|
||||
|
||||
/// <summary>
|
||||
/// Effective size of BET hash (in bits)
|
||||
/// </summary>
|
||||
public uint BetHashSize;
|
||||
|
||||
/// <summary>
|
||||
/// Size of BET hashes array, in bytes
|
||||
/// </summary>
|
||||
public uint BetHashArraySize;
|
||||
|
||||
/// <summary>
|
||||
/// Number of flags in the following array
|
||||
/// </summary>
|
||||
public uint FlagCount;
|
||||
|
||||
/// <summary>
|
||||
/// Followed by array of file flags. Each entry is 32-bit size and its meaning is the same like
|
||||
/// </summary>
|
||||
/// <remarks>Size from <see cref="FlagCount"/></remarks>
|
||||
public uint[] FlagsArray;
|
||||
|
||||
// File table. Size of each entry is taken from dwTableEntrySize.
|
||||
// Size of the table is (dwTableEntrySize * dwMaxFileCount), round up to 8.
|
||||
|
||||
// Array of BET hashes. Table size is taken from dwMaxFileCount from HET table
|
||||
}
|
||||
}
|
||||
34
BurnOutSharp.Models/MoPaQ/BlockEntry.cs
Normal file
34
BurnOutSharp.Models/MoPaQ/BlockEntry.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BurnOutSharp.Models.MoPaQ
|
||||
{
|
||||
/// <summary>
|
||||
/// Block table contains informations about file sizes and way of their storage within
|
||||
/// the archive. It also contains the position of file content in the archive. Size
|
||||
/// of block table entry is (like hash table entry). The block table is also encrypted.
|
||||
/// </summary>
|
||||
/// <see href="http://zezula.net/en/mpq/mpqformat.html"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class BlockEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Offset of the beginning of the file data, relative to the beginning of the archive.
|
||||
/// </summary>
|
||||
public uint FilePosition;
|
||||
|
||||
/// <summary>
|
||||
/// Compressed file size
|
||||
/// </summary>
|
||||
public uint CompressedSize;
|
||||
|
||||
/// <summary>
|
||||
/// Size of uncompressed file
|
||||
/// </summary>
|
||||
public uint UncompressedSize;
|
||||
|
||||
/// <summary>
|
||||
/// Flags for the file.
|
||||
/// </summary>
|
||||
public MoPaQFileFlags Flags;
|
||||
}
|
||||
}
|
||||
106
BurnOutSharp.Models/MoPaQ/Enums.cs
Normal file
106
BurnOutSharp.Models/MoPaQ/Enums.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
|
||||
namespace BurnOutSharp.Models.MoPaQ
|
||||
{
|
||||
[Flags]
|
||||
public enum MoPaQFileFlags : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// File is compressed using PKWARE Data compression library
|
||||
/// </summary>
|
||||
MPQ_FILE_IMPLODE = 0x00000100,
|
||||
|
||||
/// <summary>
|
||||
/// File is compressed using combination of compression methods
|
||||
/// </summary>
|
||||
MPQ_FILE_COMPRESS = 0x00000200,
|
||||
|
||||
/// <summary>
|
||||
/// The file is encrypted
|
||||
/// </summary>
|
||||
MPQ_FILE_ENCRYPTED = 0x00010000,
|
||||
|
||||
/// <summary>
|
||||
/// The decryption key for the file is altered according to the
|
||||
/// position of the file in the archive
|
||||
/// </summary>
|
||||
MPQ_FILE_FIX_KEY = 0x00020000,
|
||||
|
||||
/// <summary>
|
||||
/// The file contains incremental patch for an existing file in base MPQ
|
||||
/// </summary>
|
||||
MPQ_FILE_PATCH_FILE = 0x00100000,
|
||||
|
||||
/// <summary>
|
||||
/// Instead of being divided to 0x1000-bytes blocks, the file is stored
|
||||
/// as single unit
|
||||
/// </summary>
|
||||
MPQ_FILE_SINGLE_UNIT = 0x01000000,
|
||||
|
||||
/// <summary>
|
||||
/// File is a deletion marker, indicating that the file no longer exists.
|
||||
/// This is used to allow patch archives to delete files present in
|
||||
/// lower-priority archives in the search chain. The file usually has
|
||||
/// length of 0 or 1 byte and its name is a hash
|
||||
/// </summary>
|
||||
MPQ_FILE_DELETE_MARKER = 0x02000000,
|
||||
|
||||
/// <summary>
|
||||
/// File has checksums for each sector (explained in the File Data section).
|
||||
/// Ignored if file is not compressed or imploded.
|
||||
/// </summary>
|
||||
MPQ_FILE_SECTOR_CRC = 0x04000000,
|
||||
|
||||
/// <summary>
|
||||
/// Set if file exists, reset when the file was deleted
|
||||
/// </summary>
|
||||
MPQ_FILE_EXISTS = 0x80000000,
|
||||
}
|
||||
|
||||
public enum Locale : short
|
||||
{
|
||||
Neutral = 0,
|
||||
AmericanEnglish = 0,
|
||||
ChineseTaiwan = 0x404,
|
||||
Czech = 0x405,
|
||||
German = 0x407,
|
||||
English = 0x409,
|
||||
Spanish = 0x40A,
|
||||
French = 0x40C,
|
||||
Italian = 0x410,
|
||||
Japanese = 0x411,
|
||||
Korean = 0x412,
|
||||
Polish = 0x415,
|
||||
Portuguese = 0x416,
|
||||
Russian = 0x419,
|
||||
EnglishUK = 0x809,
|
||||
}
|
||||
|
||||
public enum MoPaQPatchType : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// Blizzard-modified version of BSDIFF40 incremental patch
|
||||
/// </summary>
|
||||
BSD0 = 0x30445342,
|
||||
|
||||
/// <summary>
|
||||
/// Unknown
|
||||
/// </summary>
|
||||
BSDP = 0x50445342,
|
||||
|
||||
/// <summary>
|
||||
/// Plain replace
|
||||
/// </summary>
|
||||
COPY = 0x59504F43,
|
||||
|
||||
/// <summary>
|
||||
/// Unknown
|
||||
/// </summary>
|
||||
COUP = 0x50554F43,
|
||||
|
||||
/// <summary>
|
||||
/// Unknown
|
||||
/// </summary>
|
||||
CPOG = 0x474F5043,
|
||||
}
|
||||
}
|
||||
48
BurnOutSharp.Models/MoPaQ/HashEntry.cs
Normal file
48
BurnOutSharp.Models/MoPaQ/HashEntry.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BurnOutSharp.Models.MoPaQ
|
||||
{
|
||||
/// <summary>
|
||||
/// Hash table is used for searching files by name. The file name is converted to
|
||||
/// two 32-bit hash values, which are then used for searching in the table. The size
|
||||
/// of the hash table must always be a power of two. Each entry in the hash table
|
||||
/// also contains file locale and offset into block table. Size of one entry of hash
|
||||
/// table is 16 bytes.
|
||||
/// </summary>
|
||||
/// <see href="http://zezula.net/en/mpq/mpqformat.html"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class HashEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// The hash of the full file name (part A)
|
||||
/// </summary>
|
||||
public uint NameHashPartA;
|
||||
|
||||
/// <summary>
|
||||
/// The hash of the full file name (part B)
|
||||
/// </summary>
|
||||
public uint NameHashPartB;
|
||||
|
||||
/// <summary>
|
||||
/// The language of the file. This is a Windows LANGID data type, and uses the same values.
|
||||
/// 0 indicates the default language (American English), or that the file is language-neutral.
|
||||
/// </summary>
|
||||
public Locale Locale;
|
||||
|
||||
/// <summary>
|
||||
/// The platform the file is used for. 0 indicates the default platform.
|
||||
/// No other values have been observed.
|
||||
/// </summary>
|
||||
public ushort Platform;
|
||||
|
||||
/// <summary>
|
||||
/// If the hash table entry is valid, this is the index into the block table of the file.
|
||||
/// Otherwise, one of the following two values:
|
||||
/// - FFFFFFFFh: Hash table entry is empty, and has always been empty.
|
||||
/// Terminates searches for a given file.
|
||||
/// - FFFFFFFEh: Hash table entry is empty, but was valid at some point (a deleted file).
|
||||
/// Does not terminate searches for a given file.
|
||||
/// </summary>
|
||||
public uint BlockIndex;
|
||||
}
|
||||
}
|
||||
87
BurnOutSharp.Models/MoPaQ/HetTable.cs
Normal file
87
BurnOutSharp.Models/MoPaQ/HetTable.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BurnOutSharp.Models.MoPaQ
|
||||
{
|
||||
/// <summary>
|
||||
/// The HET table is present if the HetTablePos64 member of MPQ header is
|
||||
/// set to nonzero. This table can fully replace hash table. Depending on
|
||||
/// MPQ size, the pair of HET&BET table can be more efficient than Hash&Block
|
||||
/// table. HET table can be encrypted and compressed.
|
||||
/// </summary>
|
||||
/// <see href="http://zezula.net/en/mpq/mpqformat.html"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class HetTable
|
||||
{
|
||||
// TODO: Extract this out and make in common between HET and BET
|
||||
#region Common Table Headers
|
||||
|
||||
/// <summary>
|
||||
/// 'HET\x1A'
|
||||
/// </summary>
|
||||
public uint Signature;
|
||||
|
||||
/// <summary>
|
||||
/// Version. Seems to be always 1
|
||||
/// </summary>
|
||||
public uint Version;
|
||||
|
||||
/// <summary>
|
||||
/// Size of the contained table
|
||||
/// </summary>
|
||||
public uint DataSize;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Size of the entire hash table, including the header (in bytes)
|
||||
/// </summary>
|
||||
public uint TableSize;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of files in the MPQ
|
||||
/// </summary>
|
||||
public uint MaxFileCount;
|
||||
|
||||
/// <summary>
|
||||
/// Size of the hash table (in bytes)
|
||||
/// </summary>
|
||||
public uint HashTableSize;
|
||||
|
||||
/// <summary>
|
||||
/// Effective size of the hash entry (in bits)
|
||||
/// </summary>
|
||||
public uint HashEntrySize;
|
||||
|
||||
/// <summary>
|
||||
/// Total size of file index (in bits)
|
||||
/// </summary>
|
||||
public uint TotalIndexSize;
|
||||
|
||||
/// <summary>
|
||||
/// Extra bits in the file index
|
||||
/// </summary>
|
||||
public uint IndexSizeExtra;
|
||||
|
||||
/// <summary>
|
||||
/// Effective size of the file index (in bits)
|
||||
/// </summary>
|
||||
public uint IndexSize;
|
||||
|
||||
/// <summary>
|
||||
/// Size of the block index subtable (in bytes)
|
||||
/// </summary>
|
||||
public uint BlockTableSize;
|
||||
|
||||
/// <summary>
|
||||
/// HET hash table. Each entry is 8 bits.
|
||||
/// </summary>
|
||||
/// <remarks>Size is derived from HashTableSize</remarks>
|
||||
public byte[] HashTable;
|
||||
|
||||
/// <summary>
|
||||
/// Array of file indexes. Bit size of each entry is taken from dwTotalIndexSize.
|
||||
/// Table size is taken from dwHashTableSize.
|
||||
/// </summary>
|
||||
public byte[][] FileIndexes;
|
||||
}
|
||||
}
|
||||
118
BurnOutSharp.Models/MoPaQ/PatchHeader.cs
Normal file
118
BurnOutSharp.Models/MoPaQ/PatchHeader.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BurnOutSharp.Models.MoPaQ
|
||||
{
|
||||
/// <summary>
|
||||
/// Each incremental patch file in a patch MPQ starts with a header. It is supposed
|
||||
/// to be a structure with variable length.
|
||||
/// </summary>
|
||||
/// <see href="http://zezula.net/en/mpq/mpqformat.html"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class PatchHeader
|
||||
{
|
||||
#region PATCH Header
|
||||
|
||||
/// <summary>
|
||||
/// 'PTCH'
|
||||
/// </summary>
|
||||
public uint PatchSignature { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the entire patch (decompressed)
|
||||
/// </summary>
|
||||
public int SizeOfPatchData { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the file before patch
|
||||
/// </summary>
|
||||
public int SizeBeforePatch { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of file after patch
|
||||
/// </summary>
|
||||
public int SizeAfterPatch { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region MD5 Block
|
||||
|
||||
/// <summary>
|
||||
/// 'MD5_'
|
||||
/// </summary>
|
||||
public uint Md5Signature { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the MD5 block, including the signature and size itself
|
||||
/// </summary>
|
||||
public int Md5BlockSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// MD5 of the original (unpached) file
|
||||
/// </summary>
|
||||
public byte[] Md5BeforePatch { get; private set; } = new byte[0x10];
|
||||
|
||||
/// <summary>
|
||||
/// MD5 of the patched file
|
||||
/// </summary>
|
||||
public byte[] Md5AfterPatch { get; private set; } = new byte[0x10];
|
||||
|
||||
#endregion
|
||||
|
||||
#region XFRM Block
|
||||
|
||||
/// <summary>
|
||||
/// 'XFRM'
|
||||
/// </summary>
|
||||
public uint XfrmSignature { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the XFRM block, includes XFRM header and patch data
|
||||
/// </summary>
|
||||
public int XfrmBlockSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Type of patch ('BSD0' or 'COPY')
|
||||
/// </summary>
|
||||
public MoPaQPatchType PatchType { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Patch Data - BSD0
|
||||
|
||||
/// <summary>
|
||||
/// 'BSDIFF40' signature
|
||||
/// </summary>
|
||||
public ulong BsdiffSignature { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of CTRL block (in bytes)
|
||||
/// </summary>
|
||||
public long CtrlBlockSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of DATA block (in bytes)
|
||||
/// </summary>
|
||||
public long DataBlockSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of file after applying the patch (in bytes)
|
||||
/// </summary>
|
||||
public long NewFileSize { get; private set; }
|
||||
|
||||
// TODO: Fill rest of data from http://zezula.net/en/mpq/patchfiles.html
|
||||
// CTRL block
|
||||
// DATA block
|
||||
// EXTRA block
|
||||
|
||||
#endregion
|
||||
|
||||
#region Patch Data - COPY
|
||||
|
||||
/// <summary>
|
||||
/// File data are simply replaced by the data in the patch.
|
||||
/// </summary>
|
||||
public byte[] PatchDataCopy { get; private set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
38
BurnOutSharp.Models/MoPaQ/PatchInfo.cs
Normal file
38
BurnOutSharp.Models/MoPaQ/PatchInfo.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BurnOutSharp.Models.MoPaQ
|
||||
{
|
||||
/// <summary>
|
||||
/// This structure contains size of the patch, flags and also MD5 of the patch.
|
||||
/// </summary>
|
||||
/// <see href="http://zezula.net/en/mpq/mpqformat.html"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class PatchInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Length of patch info header, in bytes
|
||||
/// </summary>
|
||||
public uint Length;
|
||||
|
||||
/// <summary>
|
||||
/// Flags. 0x80000000 = MD5 (?)
|
||||
/// </summary>
|
||||
public uint Flags;
|
||||
|
||||
/// <summary>
|
||||
/// Uncompressed size of the patch file
|
||||
/// </summary>
|
||||
public uint DataSize;
|
||||
|
||||
/// <summary>
|
||||
/// MD5 of the entire patch file after decompression
|
||||
/// </summary>
|
||||
/// <remarks>0x10 bytes</remarks>
|
||||
public byte[] MD5;
|
||||
|
||||
/// <summary>
|
||||
/// The sector offset table (variable length)
|
||||
/// </summary>
|
||||
public uint[] SectorOffsetTable;
|
||||
}
|
||||
}
|
||||
37
BurnOutSharp.Models/MoPaQ/UserData.cs
Normal file
37
BurnOutSharp.Models/MoPaQ/UserData.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BurnOutSharp.Models.MoPaQ
|
||||
{
|
||||
/// <summary>
|
||||
/// MPQ User Data are optional, and is commonly used in custom maps for
|
||||
/// Starcraft II. If MPQ User Data header is present, it contains an offset,
|
||||
/// from where the MPQ header should be searched.
|
||||
/// </summary>
|
||||
/// <see href="http://zezula.net/en/mpq/mpqformat.html"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class UserData
|
||||
{
|
||||
/// <summary>
|
||||
/// The user data signature
|
||||
/// </summary>
|
||||
/// <see cref="SignatureValue"/>
|
||||
public uint Signature;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum size of the user data
|
||||
/// </summary>
|
||||
public uint UserDataSize;
|
||||
|
||||
/// <summary>
|
||||
/// Offset of the MPQ header, relative to the beginning of this header
|
||||
/// </summary>
|
||||
public uint HeaderOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Appears to be size of user data header (Starcraft II maps)
|
||||
/// </summary>
|
||||
public uint UserDataHeaderSize;
|
||||
|
||||
// TODO: Does this area contain extra data that should be read in?
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user