mirror of
https://github.com/SabreTools/SabreTools.Models.git
synced 2026-02-08 21:31:54 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c000e581c8 | ||
|
|
465cef4224 | ||
|
|
87cadbfd2b | ||
|
|
648ee2eaa5 | ||
|
|
daa814728d | ||
|
|
68aac36623 | ||
|
|
0c95cfcde4 | ||
|
|
6d6361c153 | ||
|
|
e4be402052 | ||
|
|
182c9bc756 | ||
|
|
cc62b3ffae | ||
|
|
7d34f486cd | ||
|
|
9c68cfc0c1 | ||
|
|
9a5d681ad2 | ||
|
|
afb20e00be | ||
|
|
5a055a98c7 | ||
|
|
793a4e2fdd |
@@ -5,17 +5,8 @@ namespace SabreTools.Models.Compression.LZX
|
||||
/// tree preceding the other trees.
|
||||
/// </summary>
|
||||
/// <see href="https://interoperability.blob.core.windows.net/files/MS-PATCH/%5bMS-PATCH%5d.pdf"/>
|
||||
public class AlignedOffsetBlock
|
||||
public class AlignedOffsetBlockData : BlockData
|
||||
{
|
||||
/// <summary>
|
||||
/// Generic block header
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public BlockHeader Header { get; set; }
|
||||
#else
|
||||
public BlockHeader? Header { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Aligned offset tree
|
||||
/// </summary>
|
||||
@@ -86,8 +77,14 @@ namespace SabreTools.Models.Compression.LZX
|
||||
public int[]? PathLengthsLengthTree { get; set; }
|
||||
#endif
|
||||
|
||||
// Entry Comments Size
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Token sequence (matches and literals) Specified in section 2.6 Variable
|
||||
/// <summary>
|
||||
/// Token sequence (matches and literals)
|
||||
/// </summary>
|
||||
/// <remarks>Variable</remarks>
|
||||
#if NET48
|
||||
public byte[] TokenSequence { get; set; }
|
||||
#else
|
||||
public byte[]? TokenSequence { get; set; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
32
Compression/LZX/Block.cs
Normal file
32
Compression/LZX/Block.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
namespace SabreTools.Models.Compression.LZX
|
||||
{
|
||||
/// <summary>
|
||||
/// An LZXD block represents a sequence of compressed data that is encoded with the same set of
|
||||
/// Huffman trees, or a sequence of uncompressed data. There can be one or more LZXD blocks in a
|
||||
/// compressed stream, each with its own set of Huffman trees. Blocks do not have to start or end on a
|
||||
/// chunk boundary; blocks can span multiple chunks, or a single chunk can contain multiple blocks. The
|
||||
/// number of chunks is related to the size of the data being compressed, while the number of blocks is
|
||||
/// related to how well the data is compressed.
|
||||
/// </summary>
|
||||
/// <see href="https://interoperability.blob.core.windows.net/files/MS-PATCH/%5bMS-PATCH%5d.pdf"/>
|
||||
public class Block
|
||||
{
|
||||
/// <summary>
|
||||
/// Block header
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public BlockHeader Header { get; set; }
|
||||
#else
|
||||
public BlockHeader? Header { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Block data
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public BlockData BlockData { get; set; }
|
||||
#else
|
||||
public BlockData? BlockData { get; set; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
8
Compression/LZX/BlockData.cs
Normal file
8
Compression/LZX/BlockData.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace SabreTools.Models.Compression.LZX
|
||||
{
|
||||
/// <see href="https://interoperability.blob.core.windows.net/files/MS-PATCH/%5bMS-PATCH%5d.pdf"/>
|
||||
public abstract class BlockData
|
||||
{
|
||||
// No common fields between all block data
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,9 @@
|
||||
namespace SabreTools.Models.Compression.LZX
|
||||
{
|
||||
/// <summary>
|
||||
/// An LZXD block represents a sequence of compressed data that is encoded with the same set of
|
||||
/// Huffman trees, or a sequence of uncompressed data. There can be one or more LZXD blocks in a
|
||||
/// compressed stream, each with its own set of Huffman trees. Blocks do not have to start or end on a
|
||||
/// chunk boundary; blocks can span multiple chunks, or a single chunk can contain multiple blocks. The
|
||||
/// number of chunks is related to the size of the data being compressed, while the number of blocks is
|
||||
/// related to how well the data is compressed. The Block Type field, as specified in section 2.3.1.1,
|
||||
/// indicates which type of block follows, and the Block Size field, as specified in section 2.3.1.2,
|
||||
/// indicates the number of uncompressed bytes represented by the block. Following the generic block
|
||||
/// The Block Type field, as specified in section 2.3.1.1, indicates which type of block follows,
|
||||
/// and the Block Size field, as specified in section 2.3.1.2, indicates the number of
|
||||
/// uncompressed bytes represented by the block. Following the generic block
|
||||
/// header is a type-specific header that describes the remainder of the block.
|
||||
/// </summary>
|
||||
/// <see href="https://interoperability.blob.core.windows.net/files/MS-PATCH/%5bMS-PATCH%5d.pdf"/>
|
||||
|
||||
25
Compression/LZX/Chunk.cs
Normal file
25
Compression/LZX/Chunk.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
namespace SabreTools.Models.Compression.LZX
|
||||
{
|
||||
/// <summary>
|
||||
/// The LZXD compressor emits chunks of compressed data. A chunk represents exactly 32 KB of
|
||||
/// uncompressed data until the last chunk in the stream, which can represent less than 32 KB. To
|
||||
/// ensure that an exact number of input bytes represent an exact number of output bytes for each
|
||||
/// chunk, after each 32 KB of uncompressed data is represented in the output compressed bitstream, the
|
||||
/// output bitstream is padded with up to 15 bits of zeros to realign the bitstream on a 16-bit boundary
|
||||
/// (even byte boundary) for the next 32 KB of data. This results in a compressed chunk of a byte-aligned
|
||||
/// size. The compressed chunk could be smaller than 32 KB or larger than 32 KB if the data is
|
||||
/// incompressible when the chunk is not the last one.
|
||||
/// </summary>
|
||||
public class Chunk
|
||||
{
|
||||
/// <summary>
|
||||
/// Chunk header
|
||||
/// </summary>
|
||||
public ChunkHeader Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Block headers and data
|
||||
/// </summary>
|
||||
public Block[] Blocks { get; set; }
|
||||
}
|
||||
}
|
||||
46
Compression/LZX/ChunkHeader.cs
Normal file
46
Compression/LZX/ChunkHeader.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
namespace SabreTools.Models.Compression.LZX
|
||||
{
|
||||
/// <summary>
|
||||
/// The LZXD compressor emits chunks of compressed data. A chunk represents exactly 32 KB of
|
||||
/// uncompressed data until the last chunk in the stream, which can represent less than 32 KB. To
|
||||
/// ensure that an exact number of input bytes represent an exact number of output bytes for each
|
||||
/// chunk, after each 32 KB of uncompressed data is represented in the output compressed bitstream, the
|
||||
/// output bitstream is padded with up to 15 bits of zeros to realign the bitstream on a 16-bit boundary
|
||||
/// (even byte boundary) for the next 32 KB of data. This results in a compressed chunk of a byte-aligned
|
||||
/// size. The compressed chunk could be smaller than 32 KB or larger than 32 KB if the data is
|
||||
/// incompressible when the chunk is not the last one.
|
||||
/// </summary>
|
||||
public class ChunkHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// The LZXD engine encodes a compressed, chunk-size prefix field preceding each compressed chunk in
|
||||
/// the compressed byte stream. The compressed, chunk-size prefix field is a byte aligned, little-endian,
|
||||
/// 16-bit field. The chunk prefix chain could be followed in the compressed stream without
|
||||
/// decompressing any data. The next chunk prefix is at a location computed by the absolute byte offset
|
||||
/// location of this chunk prefix plus 2 (for the size of the chunk-size prefix field) plus the current chunk
|
||||
/// size.
|
||||
/// </summary>
|
||||
public ushort ChunkSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The first bit in the first chunk in the LZXD bitstream (following the 2-byte, chunk-size prefix described
|
||||
/// in section 2.2.1) indicates the presence or absence of two 16-bit fields immediately following the
|
||||
/// single bit. If the bit is set, E8 translation is enabled for all the following chunks in the stream using the
|
||||
/// 32-bit value derived from the two 16-bit fields as the E8_file_size provided to the compressor when E8
|
||||
/// translation was enabled. Note that E8_file_size is completely independent of the length of the
|
||||
/// uncompressed data. E8 call translation is disabled after the 32,768th chunk (after 1 gigabyte (GB) of
|
||||
/// uncompressed data).
|
||||
/// </summary>
|
||||
public byte E8Translation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// E8 translation size, high WORD
|
||||
/// </summary>
|
||||
public ushort? TranslationSizeHighWord { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// E8 translation size, low WORD
|
||||
/// </summary>
|
||||
public ushort? TranslationSizeLowWord { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -3,44 +3,36 @@ namespace SabreTools.Models.Compression.LZX
|
||||
public static class Constants
|
||||
{
|
||||
/* some constants defined by the LZX specification */
|
||||
public const int LZX_MIN_MATCH = (2);
|
||||
public const int LZX_MAX_MATCH = (257);
|
||||
public const int LZX_NUM_CHARS = (256);
|
||||
|
||||
/// <summary>
|
||||
/// also blocktypes 4-7 invalid
|
||||
/// </summary>
|
||||
public const int LZX_BLOCKTYPE_INVALID = (0);
|
||||
public const int LZX_BLOCKTYPE_VERBATIM = (1);
|
||||
public const int LZX_BLOCKTYPE_ALIGNED = (2);
|
||||
public const int LZX_BLOCKTYPE_UNCOMPRESSED = (3);
|
||||
public const int LZX_PRETREE_NUM_ELEMENTS = (20);
|
||||
public const int LZX_MIN_MATCH = 2;
|
||||
public const int LZX_MAX_MATCH = 257;
|
||||
public const int LZX_NUM_CHARS = 256;
|
||||
public const int LZX_PRETREE_NUM_ELEMENTS = 20;
|
||||
|
||||
/// <summary>
|
||||
/// aligned offset tree #elements
|
||||
/// </summary>
|
||||
public const int LZX_ALIGNED_NUM_ELEMENTS = (8);
|
||||
public const int LZX_ALIGNED_NUM_ELEMENTS = 8;
|
||||
|
||||
/// <summary>
|
||||
/// this one missing from spec!
|
||||
/// </summary>
|
||||
public const int LZX_NUM_PRIMARY_LENGTHS = (7);
|
||||
public const int LZX_NUM_PRIMARY_LENGTHS = 7;
|
||||
|
||||
/// <summary>
|
||||
/// length tree #elements
|
||||
/// </summary>
|
||||
public const int LZX_NUM_SECONDARY_LENGTHS = (249);
|
||||
public const int LZX_NUM_SECONDARY_LENGTHS = 249;
|
||||
|
||||
/* LZX huffman defines: tweak tablebits as desired */
|
||||
public const int LZX_PRETREE_MAXSYMBOLS = (LZX_PRETREE_NUM_ELEMENTS);
|
||||
public const int LZX_PRETREE_TABLEBITS = (6);
|
||||
public const int LZX_MAINTREE_MAXSYMBOLS = (LZX_NUM_CHARS + 50 * 8);
|
||||
public const int LZX_MAINTREE_TABLEBITS = (12);
|
||||
public const int LZX_LENGTH_MAXSYMBOLS = (LZX_NUM_SECONDARY_LENGTHS + 1);
|
||||
public const int LZX_LENGTH_TABLEBITS = (12);
|
||||
public const int LZX_ALIGNED_MAXSYMBOLS = (LZX_ALIGNED_NUM_ELEMENTS);
|
||||
public const int LZX_ALIGNED_TABLEBITS = (7);
|
||||
public const int LZX_PRETREE_MAXSYMBOLS = LZX_PRETREE_NUM_ELEMENTS;
|
||||
public const int LZX_PRETREE_TABLEBITS = 6;
|
||||
public const int LZX_MAINTREE_MAXSYMBOLS = LZX_NUM_CHARS + 50 * 8;
|
||||
public const int LZX_MAINTREE_TABLEBITS = 12;
|
||||
public const int LZX_LENGTH_MAXSYMBOLS = LZX_NUM_SECONDARY_LENGTHS + 1;
|
||||
public const int LZX_LENGTH_TABLEBITS = 12;
|
||||
public const int LZX_ALIGNED_MAXSYMBOLS = LZX_ALIGNED_NUM_ELEMENTS;
|
||||
public const int LZX_ALIGNED_TABLEBITS = 7;
|
||||
|
||||
public const int LZX_LENTABLE_SAFETY = (64); /* we allow length table decoding overruns */
|
||||
public const int LZX_LENTABLE_SAFETY = 64; /* we allow length table decoding overruns */
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
namespace SabreTools.Models.Compression.LZX
|
||||
{
|
||||
public class Header
|
||||
{
|
||||
/*
|
||||
2.2 Header
|
||||
|
||||
2.2.1 Chunk Size
|
||||
|
||||
The LZXD compressor emits chunks of compressed data. A chunk represents exactly 32 KB of
|
||||
uncompressed data until the last chunk in the stream, which can represent less than 32 KB. To
|
||||
ensure that an exact number of input bytes represent an exact number of output bytes for each
|
||||
chunk, after each 32 KB of uncompressed data is represented in the output compressed bitstream, the
|
||||
output bitstream is padded with up to 15 bits of zeros to realign the bitstream on a 16-bit boundary
|
||||
(even byte boundary) for the next 32 KB of data. This results in a compressed chunk of a byte-aligned
|
||||
size. The compressed chunk could be smaller than 32 KB or larger than 32 KB if the data is
|
||||
incompressible when the chunk is not the last one.
|
||||
|
||||
The LZXD engine encodes a compressed, chunk-size prefix field preceding each compressed chunk in
|
||||
the compressed byte stream. The compressed, chunk-size prefix field is a byte aligned, little-endian,
|
||||
16-bit field. The chunk prefix chain could be followed in the compressed stream without
|
||||
decompressing any data. The next chunk prefix is at a location computed by the absolute byte offset
|
||||
location of this chunk prefix plus 2 (for the size of the chunk-size prefix field) plus the current chunk
|
||||
size.
|
||||
|
||||
2.2.2 E8 Call Translation
|
||||
|
||||
E8 call translation is an optional feature that can be used when the data to compress contains x86
|
||||
instruction sequences. E8 translation operates as a preprocessing stage before compressing each
|
||||
chunk, and the compressed stream header contains a bit that indicates whether the decoder shall
|
||||
reverse the translation as a postprocessing step after decompressing each chunk.
|
||||
|
||||
The x86 instruction beginning with a byte value of 0xE8 is followed by a 32-bit, little-endian relative
|
||||
displacement to the call target. When E8 call translation is enabled, the following preprocessing steps
|
||||
are performed on the uncompressed input before compression (assuming little-endian byte ordering):
|
||||
|
||||
Let chunk_offset refer to the total number of uncompressed bytes preceding this chunk.
|
||||
|
||||
Let E8_file_size refer to the caller-specified value given to the compressor or decoded from the header
|
||||
of the compressed stream during decompression.
|
||||
|
||||
The following example shows how E8 translation is performed for each 32-KB chunk of uncompressed
|
||||
data (or less than 32 KB if last chunk to compress).
|
||||
|
||||
if (( chunk_offset < 0x40000000 ) && ( chunk_size > 10 ))
|
||||
for ( i = 0; i < (chunk_size – 10); i++ )
|
||||
if ( chunk_byte[ i ] == 0xE8 )
|
||||
long current_pointer = chunk_offset + i;
|
||||
long displacement = chunk_byte[ i+1 ] |
|
||||
chunk_byte[ i+2 ] << 8 |
|
||||
chunk_byte[ i+3 ] << 16 |
|
||||
chunk_byte[ i+4 ] << 24;
|
||||
long target = current_pointer + displacement;
|
||||
if (( target >= 0 ) && ( target < E8_file_size+current_pointer))
|
||||
if ( target >= E8_file_size )
|
||||
target = displacement – E8_file_size;
|
||||
endif
|
||||
chunk_byte[ i+1 ] = (byte)( target );
|
||||
chunk_byte[ i+2 ] = (byte)( target >> 8 );
|
||||
chunk_byte[ i+3 ] = (byte)( target >> 16 );
|
||||
chunk_byte[ i+4 ] = (byte)( target >> 24 );
|
||||
endif
|
||||
i += 4;
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
|
||||
After decompression, the E8 scanning algorithm is the same. The following example shows how E8
|
||||
translation reversal is performed.
|
||||
|
||||
long value = chunk_byte[ i+1 ] |
|
||||
chunk_byte[ i+2 ] << 8 |
|
||||
chunk_byte[ i+3 ] << 16 |
|
||||
chunk_byte[ i+4 ] << 24;
|
||||
if (( value >= -current_pointer ) && ( value < E8_file_size ))
|
||||
if ( value >= 0 )
|
||||
displacement = value – current_pointer;
|
||||
else
|
||||
displacement = value + E8_file_size;
|
||||
endif
|
||||
chunk_byte[ i+1 ] = (byte)( displacement );
|
||||
chunk_byte[ i+2 ] = (byte)( displacement >> 8 );
|
||||
chunk_byte[ i+3 ] = (byte)( displacement >> 16 );
|
||||
chunk_byte[ i+4 ] = (byte)( displacement >> 24 );
|
||||
endif
|
||||
|
||||
The first bit in the first chunk in the LZXD bitstream (following the 2-byte, chunk-size prefix described
|
||||
in section 2.2.1) indicates the presence or absence of two 16-bit fields immediately following the
|
||||
single bit. If the bit is set, E8 translation is enabled for all the following chunks in the stream using the
|
||||
32-bit value derived from the two 16-bit fields as the E8_file_size provided to the compressor when E8
|
||||
translation was enabled. Note that E8_file_size is completely independent of the length of the
|
||||
uncompressed data. E8 call translation is disabled after the 32,768th chunk (after 1 gigabyte (GB) of
|
||||
uncompressed data).
|
||||
|
||||
Field Comments Size
|
||||
----------------------------------------------------------------
|
||||
E8 translation 0-disabled, 1-enabled 1 bit
|
||||
Translation size high word Only present if enabled 0 or 16 bits
|
||||
Translation size low word Only present if enabled 0 or 16 bits
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -14,17 +14,8 @@ namespace SabreTools.Models.Compression.LZX
|
||||
/// subsequent compressed block if present.
|
||||
/// </summary>
|
||||
/// <see href="https://interoperability.blob.core.windows.net/files/MS-PATCH/%5bMS-PATCH%5d.pdf"/>
|
||||
public class UncompressedBlock
|
||||
public class UncompressedBlockData : BlockData
|
||||
{
|
||||
/// <summary>
|
||||
/// Generic block header
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public BlockHeader Header { get; set; }
|
||||
#else
|
||||
public BlockHeader? Header { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Padding to align following field on 16-bit boundary
|
||||
/// </summary>
|
||||
@@ -4,17 +4,8 @@ namespace SabreTools.Models.Compression.LZX
|
||||
/// The fields of a verbatim block that follow the generic block header
|
||||
/// </summary>
|
||||
/// <see href="https://interoperability.blob.core.windows.net/files/MS-PATCH/%5bMS-PATCH%5d.pdf"/>
|
||||
public class VerbatimBlock
|
||||
public class VerbatimBlockData : BlockData
|
||||
{
|
||||
/// <summary>
|
||||
/// Generic block header
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public BlockHeader Header { get; set; }
|
||||
#else
|
||||
public BlockHeader? Header { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Pretree for first 256 elements of main tree
|
||||
/// </summary>
|
||||
@@ -75,8 +66,14 @@ namespace SabreTools.Models.Compression.LZX
|
||||
public int[]? PathLengthsLengthTree { get; set; }
|
||||
#endif
|
||||
|
||||
// Entry Comments Size
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Token sequence (matches and literals) Specified in section 2.6 Variable
|
||||
/// <summary>
|
||||
/// Token sequence (matches and literals)
|
||||
/// </summary>
|
||||
/// <remarks>Variable</remarks>
|
||||
#if NET48
|
||||
public byte[] TokenSequence { get; set; }
|
||||
#else
|
||||
public byte[]? TokenSequence { get; set; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
41
Compression/MSZIP/Block.cs
Normal file
41
Compression/MSZIP/Block.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
namespace SabreTools.Models.Compression.MSZIP
|
||||
{
|
||||
/// <summary>
|
||||
/// Each MSZIP block MUST consist of a 2-byte MSZIP signature and one or more RFC 1951 blocks. The
|
||||
/// 2-byte MSZIP signature MUST consist of the bytes 0x43 and 0x4B. The MSZIP signature MUST be
|
||||
/// the first 2 bytes in the MSZIP block. The MSZIP signature is shown in the following packet diagram.
|
||||
///
|
||||
/// Each MSZIP block is the result of a single deflate compression operation, as defined in [RFC1951].
|
||||
/// The compressor that performs the compression operation MUST generate one or more RFC 1951
|
||||
/// blocks, as defined in [RFC1951]. The number, deflation mode, and type of RFC 1951 blocks in each
|
||||
/// MSZIP block is determined by the compressor, as defined in [RFC1951]. The last RFC 1951 block in
|
||||
/// each MSZIP block MUST be marked as the "end" of the stream(1), as defined by [RFC1951]
|
||||
/// section 3.2.3. Decoding trees MUST be discarded after each RFC 1951 block, but the history buffer
|
||||
/// MUST be maintained.Each MSZIP block MUST represent no more than 32 KB of uncompressed data.
|
||||
///
|
||||
/// The maximum compressed size of each MSZIP block is 32 KB + 12 bytes. This enables the MSZIP
|
||||
/// block to contain 32 KB of data split between two noncompressed RFC 1951 blocks, each of which
|
||||
/// has a value of BTYPE = 00.
|
||||
/// </summary>
|
||||
/// <see href="https://interoperability.blob.core.windows.net/files/MS-MCI/%5bMS-MCI%5d.pdf"/>
|
||||
public class Block
|
||||
{
|
||||
/// <summary>
|
||||
/// Block header
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public BlockHeader BlockHeader { get; set; }
|
||||
#else
|
||||
public BlockHeader? BlockHeader { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Compressed blocks
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public DeflateBlock[] CompressedBlocks { get; set; }
|
||||
#else
|
||||
public DeflateBlock[]? CompressedBlocks { get; set; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -4,18 +4,6 @@ namespace SabreTools.Models.Compression.MSZIP
|
||||
/// Each MSZIP block MUST consist of a 2-byte MSZIP signature and one or more RFC 1951 blocks. The
|
||||
/// 2-byte MSZIP signature MUST consist of the bytes 0x43 and 0x4B. The MSZIP signature MUST be
|
||||
/// the first 2 bytes in the MSZIP block. The MSZIP signature is shown in the following packet diagram.
|
||||
///
|
||||
/// Each MSZIP block is the result of a single deflate compression operation, as defined in [RFC1951].
|
||||
/// The compressor that performs the compression operation MUST generate one or more RFC 1951
|
||||
/// blocks, as defined in [RFC1951]. The number, deflation mode, and type of RFC 1951 blocks in each
|
||||
/// MSZIP block is determined by the compressor, as defined in [RFC1951]. The last RFC 1951 block in
|
||||
/// each MSZIP block MUST be marked as the "end" of the stream(1), as defined by [RFC1951]
|
||||
/// section 3.2.3. Decoding trees MUST be discarded after each RFC 1951 block, but the history buffer
|
||||
/// MUST be maintained.Each MSZIP block MUST represent no more than 32 KB of uncompressed data.
|
||||
///
|
||||
/// The maximum compressed size of each MSZIP block is 32 KB + 12 bytes. This enables the MSZIP
|
||||
/// block to contain 32 KB of data split between two noncompressed RFC 1951 blocks, each of which
|
||||
/// has a value of BTYPE = 00.
|
||||
/// </summary>
|
||||
/// <see href="https://interoperability.blob.core.windows.net/files/MS-MCI/%5bMS-MCI%5d.pdf"/>
|
||||
public class BlockHeader
|
||||
|
||||
28
Compression/MSZIP/CompressedBlockHeader.cs
Normal file
28
Compression/MSZIP/CompressedBlockHeader.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
namespace SabreTools.Models.Compression.MSZIP
|
||||
{
|
||||
/// <summary>
|
||||
/// Compression with Huffman codes (BTYPE=01 or BTYPE=02)
|
||||
/// </summary>
|
||||
/// <see href="https://interoperability.blob.core.windows.net/files/MS-MCI/%5bMS-MCI%5d.pdf"/>
|
||||
/// <see href="https://www.rfc-editor.org/rfc/rfc1951"/>
|
||||
public abstract class CompressedDataHeader : DataHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Huffman code lengths for the literal / length alphabet
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public virtual uint[] LiteralLengths { get; set; }
|
||||
#else
|
||||
public virtual uint[]? LiteralLengths { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Huffman distance codes for the literal / length alphabet
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public virtual uint[] DistanceCodes { get; set; }
|
||||
#else
|
||||
public virtual uint[]? DistanceCodes { get; set; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
11
Compression/MSZIP/DataHeader.cs
Normal file
11
Compression/MSZIP/DataHeader.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace SabreTools.Models.Compression.MSZIP
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all data headers (BTYPE=00, BTYPE=01, or BTYPE=02)
|
||||
/// </summary>
|
||||
/// <see href="https://www.rfc-editor.org/rfc/rfc1951"/>
|
||||
public abstract class DataHeader
|
||||
{
|
||||
// No common fields between all data headers
|
||||
}
|
||||
}
|
||||
47
Compression/MSZIP/DeflateBlock.cs
Normal file
47
Compression/MSZIP/DeflateBlock.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
namespace SabreTools.Models.Compression.MSZIP
|
||||
{
|
||||
/// <summary>
|
||||
/// Each MSZIP block is the result of a single deflate compression operation, as defined in [RFC1951].
|
||||
/// The compressor that performs the compression operation MUST generate one or more RFC 1951
|
||||
/// blocks, as defined in [RFC1951]. The number, deflation mode, and type of RFC 1951 blocks in each
|
||||
/// MSZIP block is determined by the compressor, as defined in [RFC1951]. The last RFC 1951 block in
|
||||
/// each MSZIP block MUST be marked as the "end" of the stream(1), as defined by [RFC1951]
|
||||
/// section 3.2.3. Decoding trees MUST be discarded after each RFC 1951 block, but the history buffer
|
||||
/// MUST be maintained.Each MSZIP block MUST represent no more than 32 KB of uncompressed data.
|
||||
/// </summary>
|
||||
/// <see href="https://interoperability.blob.core.windows.net/files/MS-MCI/%5bMS-MCI%5d.pdf"/>
|
||||
public class DeflateBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Deflate block (RFC-1951) header
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public DeflateBlockHeader Header { get; set; }
|
||||
#else
|
||||
public DeflateBlockHeader? Header { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Compression-specific data header
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public DataHeader DataHeader { get; set; }
|
||||
#else
|
||||
public DataHeader? DataHeader { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// MSZIP data
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Depending on the implementation of these models, this property could either be
|
||||
/// compressed or uncompressed data. Keep this in mind when using the built
|
||||
/// versions of this model.
|
||||
/// </remarks>
|
||||
#if NET48
|
||||
public byte[] Data { get; set; }
|
||||
#else
|
||||
public byte[]? Data { get; set; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
11
Compression/MSZIP/DynamicCompressedDataHeader.cs
Normal file
11
Compression/MSZIP/DynamicCompressedDataHeader.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace SabreTools.Models.Compression.MSZIP
|
||||
{
|
||||
/// <summary>
|
||||
/// Compression with dynamic Huffman codes (BTYPE=10)
|
||||
/// </summary>
|
||||
/// <see href="https://www.rfc-editor.org/rfc/rfc1951"/>
|
||||
public class DynamicCompressedDataHeader : CompressedDataHeader
|
||||
{
|
||||
// Codes are provided externally
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
namespace SabreTools.Models.Compression.MSZIP
|
||||
{
|
||||
/// <summary>
|
||||
/// Compression with dynamic Huffman codes (BTYPE=10)
|
||||
/// </summary>
|
||||
/// <see href="https://www.rfc-editor.org/rfc/rfc1951"/>
|
||||
public class DynamicHuffmanCompressedBlockHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Huffman code lengths for the literal / length alphabet
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public int[] LiteralLengths { get; set; }
|
||||
#else
|
||||
public int[]? LiteralLengths { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Huffman distance codes for the literal / length alphabet
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public int[] DistanceCodes { get; set; }
|
||||
#else
|
||||
public int[]? DistanceCodes { get; set; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ namespace SabreTools.Models.Compression.MSZIP
|
||||
/// </summary>
|
||||
/// <see href="https://interoperability.blob.core.windows.net/files/MS-MCI/%5bMS-MCI%5d.pdf"/>
|
||||
/// <see href="https://www.rfc-editor.org/rfc/rfc1951"/>
|
||||
public class FixedHuffmanCompressedBlockHeader
|
||||
public class FixedCompressedDataHeader : CompressedDataHeader
|
||||
{
|
||||
#region Properties
|
||||
|
||||
@@ -15,9 +15,9 @@ namespace SabreTools.Models.Compression.MSZIP
|
||||
/// Huffman code lengths for the literal / length alphabet
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public uint[] LiteralLengths
|
||||
public override uint[] LiteralLengths
|
||||
#else
|
||||
public uint[]? LiteralLengths
|
||||
public override uint[]? LiteralLengths
|
||||
#endif
|
||||
{
|
||||
get
|
||||
@@ -57,9 +57,9 @@ namespace SabreTools.Models.Compression.MSZIP
|
||||
/// Huffman distance codes for the literal / length alphabet
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public uint[] DistanceCodes
|
||||
public override uint[] DistanceCodes
|
||||
#else
|
||||
public uint[]? DistanceCodes
|
||||
public override uint[]? DistanceCodes
|
||||
#endif
|
||||
{
|
||||
get
|
||||
@@ -4,7 +4,7 @@ namespace SabreTools.Models.Compression.MSZIP
|
||||
/// Non-compressed blocks (BTYPE=00)
|
||||
/// </summary>
|
||||
/// <see href="https://www.rfc-editor.org/rfc/rfc1951"/>
|
||||
public class NonCompressedBlockHeader
|
||||
public class NonCompressedBlockHeader : DataHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of data bytes in the block
|
||||
@@ -1,45 +1,50 @@
|
||||
namespace SabreTools.Models.Compression.Quantum
|
||||
{
|
||||
/// <see href="www.russotto.net/quantumcomp.html"/>
|
||||
public static class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Mask for Quantum Compression Level
|
||||
/// </summary>
|
||||
public const ushort MASK_QUANTUM_LEVEL = 0x00F0;
|
||||
public static readonly int[] PositionSlot = new int[]
|
||||
{
|
||||
0x00000, 0x00001, 0x00002, 0x00003, 0x00004, 0x00006, 0x00008, 0x0000c,
|
||||
0x00010, 0x00018, 0x00020, 0x00030, 0x00040, 0x00060, 0x00080, 0x000c0,
|
||||
0x00100, 0x00180, 0x00200, 0x00300, 0x00400, 0x00600, 0x00800, 0x00c00,
|
||||
0x01000, 0x01800, 0x02000, 0x03000, 0x04000, 0x06000, 0x08000, 0x0c000,
|
||||
0x10000, 0x18000, 0x20000, 0x30000, 0x40000, 0x60000, 0x80000, 0xc0000,
|
||||
0x100000, 0x180000
|
||||
};
|
||||
|
||||
public static readonly int[] PositionExtraBits = new int[]
|
||||
{
|
||||
0, 0, 0, 0, 1, 1, 2, 2,
|
||||
3, 3, 4, 4, 5, 5, 6, 6,
|
||||
7, 7, 8, 8, 9, 9, 10, 10,
|
||||
11, 11, 12, 12, 13, 13, 14, 14,
|
||||
15, 15, 16, 16, 17, 17, 18, 18,
|
||||
19, 19
|
||||
};
|
||||
|
||||
public static readonly int[] LengthSlot = new int[]
|
||||
{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08,
|
||||
0x0a, 0x0c, 0x0e, 0x12, 0x16, 0x1a, 0x1e, 0x26,
|
||||
0x2e, 0x36, 0x3e, 0x4e, 0x5e, 0x6e, 0x7e, 0x9e,
|
||||
0xbe, 0xde, 0xfe
|
||||
};
|
||||
|
||||
public static readonly int[] LengthExtraBits = new int[]
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 1, 1,
|
||||
1, 1, 2, 2, 2, 2, 3, 3,
|
||||
3, 3, 4, 4, 4, 4, 5, 5,
|
||||
5, 5, 0
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Lowest Quantum Level (1)
|
||||
/// Number of position slots for (tsize - 10)
|
||||
/// </summary>
|
||||
public const ushort QUANTUM_LEVEL_LO = 0x0010;
|
||||
|
||||
/// <summary>
|
||||
/// Highest Quantum Level (7)
|
||||
/// </summary>
|
||||
public const ushort QUANTUM_LEVEL_HI = 0x0070;
|
||||
|
||||
/// <summary>
|
||||
/// Amount to shift over to get int
|
||||
/// </summary>
|
||||
public const ushort SHIFT_QUANTUM_LEVEL = 4;
|
||||
|
||||
/// <summary>
|
||||
/// Mask for Quantum Compression Memory
|
||||
/// </summary>
|
||||
public const ushort MASK_QUANTUM_MEM = 0x1F00;
|
||||
|
||||
/// <summary>
|
||||
/// Lowest Quantum Memory (10)
|
||||
/// </summary>
|
||||
public const ushort QUANTUM_MEM_LO = 0x0A00;
|
||||
|
||||
/// <summary>
|
||||
/// Highest Quantum Memory (21)
|
||||
/// </summary>
|
||||
public const ushort QUANTUM_MEM_HI = 0x1500;
|
||||
|
||||
/// <summary>
|
||||
/// Amount to shift over to get int
|
||||
/// </summary>
|
||||
public const ushort SHIFT_QUANTUM_MEM = 8;
|
||||
public static readonly int[] NumPositionSlots = new int[]
|
||||
{
|
||||
20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,28 @@
|
||||
namespace SabreTools.Models.Compression.Quantum
|
||||
{
|
||||
/// <see href="https://github.com/wine-mirror/wine/blob/master/dlls/cabinet/cabinet.h"/>
|
||||
/// <see href="http://www.russotto.net/quantumcomp.html"/>
|
||||
public sealed class Model
|
||||
{
|
||||
public int TimeToReorder { get; set; }
|
||||
|
||||
public int Entries { get; set; }
|
||||
|
||||
/// <remarks>
|
||||
/// All the models are initialized with the symbols in symbol
|
||||
/// order in the table, and with every symbol in the table
|
||||
/// having a frequency of 1
|
||||
/// </remarks>
|
||||
#if NET48
|
||||
public ModelSymbol[] Symbols { get; set; }
|
||||
#else
|
||||
public ModelSymbol?[]? Symbols { get; set; }
|
||||
#endif
|
||||
|
||||
#if NET48
|
||||
public ushort[] LookupTable { get; set; } = new ushort[256];
|
||||
#else
|
||||
public ushort[]? LookupTable { get; set; } = new ushort[256];
|
||||
#endif
|
||||
/// <remarks>
|
||||
/// The initial total frequency is equal to the number of entries
|
||||
/// in the table
|
||||
/// </remarks>
|
||||
public int TotalFrequency { get; set; }
|
||||
|
||||
/// <remarks>The initial time_to_reorder value is 4</remarks>
|
||||
public int TimeToReorder { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,15 @@
|
||||
namespace SabreTools.Models.Compression.Quantum
|
||||
{
|
||||
/// <see href="https://github.com/wine-mirror/wine/blob/master/dlls/cabinet/cabinet.h"/>
|
||||
/// <see href="http://www.russotto.net/quantumcomp.html"/>
|
||||
public sealed class ModelSymbol
|
||||
{
|
||||
public ushort Symbol { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The cumulative frequency is the frequency of all the symbols
|
||||
/// which are at a higher index in the table than that symbol —
|
||||
/// thus the last entry in the table has a cumulative frequency of 0.
|
||||
/// </summary>
|
||||
public ushort CumulativeFrequency { get; set; }
|
||||
}
|
||||
}
|
||||
38
CueSheets/CueFile.cs
Normal file
38
CueSheets/CueFile.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace SabreTools.Models.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single FILE in a cuesheet
|
||||
/// </summary>
|
||||
public class CueFile
|
||||
{
|
||||
/// <summary>
|
||||
/// filename
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string FileName { get; set; }
|
||||
#else
|
||||
public string? FileName { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// filetype
|
||||
/// </summary>
|
||||
public CueFileType FileType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of TRACK in FILE
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public CueTrack[] Tracks { get; set; }
|
||||
#else
|
||||
public CueTrack?[]? Tracks { get; set; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
33
CueSheets/CueIndex.cs
Normal file
33
CueSheets/CueIndex.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace SabreTools.Models.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single INDEX in a TRACK
|
||||
/// </summary>
|
||||
public class CueIndex
|
||||
{
|
||||
/// <summary>
|
||||
/// INDEX number, between 0 and 99
|
||||
/// </summary>
|
||||
public int Index { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Starting time of INDEX in minutes
|
||||
/// </summary>
|
||||
public int Minutes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Starting time of INDEX in seconds
|
||||
/// </summary>
|
||||
/// <remarks>There are 60 seconds in a minute</remarks>
|
||||
public int Seconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Starting time of INDEX in frames.
|
||||
/// </summary>
|
||||
/// <remarks>There are 75 frames per second</remarks>
|
||||
public int Frames { get; set; }
|
||||
}
|
||||
}
|
||||
65
CueSheets/CueSheet.cs
Normal file
65
CueSheets/CueSheet.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace SabreTools.Models.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single cuesheet
|
||||
/// </summary>
|
||||
public class CueSheet
|
||||
{
|
||||
/// <summary>
|
||||
/// CATALOG
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string Catalog { get; set; }
|
||||
#else
|
||||
public string? Catalog { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// CDTEXTFILE
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string CdTextFile { get; set; }
|
||||
#else
|
||||
public string? CdTextFile { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// PERFORMER
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string Performer { get; set; }
|
||||
#else
|
||||
public string? Performer { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// SONGWRITER
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string Songwriter { get; set; }
|
||||
#else
|
||||
public string? Songwriter { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// TITLE
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string Title { get; set; }
|
||||
#else
|
||||
public string? Title { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// List of FILE in cuesheet
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public CueFile[] Files { get; set; }
|
||||
#else
|
||||
public CueFile?[]? Files { get; set; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
91
CueSheets/CueTrack.cs
Normal file
91
CueSheets/CueTrack.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace SabreTools.Models.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single TRACK in a FILE
|
||||
/// </summary>
|
||||
public class CueTrack
|
||||
{
|
||||
/// <summary>
|
||||
/// Track number. The range is 1 to 99.
|
||||
/// </summary>
|
||||
public int Number { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Track datatype
|
||||
/// </summary>
|
||||
public CueTrackDataType DataType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// FLAGS
|
||||
/// </summary>
|
||||
public CueTrackFlag Flags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ISRC
|
||||
/// </summary>
|
||||
/// <remarks>12 characters in length</remarks>
|
||||
#if NET48
|
||||
public string ISRC { get; set; }
|
||||
#else
|
||||
public string? ISRC { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// PERFORMER
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string Performer { get; set; }
|
||||
#else
|
||||
public string? Performer { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// SONGWRITER
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string Songwriter { get; set; }
|
||||
#else
|
||||
public string? Songwriter { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// TITLE
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string Title { get; set; }
|
||||
#else
|
||||
public string? Title { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// PREGAP
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public PreGap PreGap { get; set; }
|
||||
#else
|
||||
public PreGap? PreGap { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// List of INDEX in TRACK
|
||||
/// </summary>
|
||||
/// <remarks>Must start with 0 or 1 and then sequential</remarks>
|
||||
#if NET48
|
||||
public CueIndex[] Indices { get; set; }
|
||||
#else
|
||||
public CueIndex?[]? Indices { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// POSTGAP
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public PostGap PostGap { get; set; }
|
||||
#else
|
||||
public PostGap? PostGap { get; set; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
116
CueSheets/Enums.cs
Normal file
116
CueSheets/Enums.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
using System;
|
||||
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace SabreTools.Models.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// The audio or data file’s filetype
|
||||
/// </summary>
|
||||
public enum CueFileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Intel binary file (least significant byte first). Use for data files.
|
||||
/// </summary>
|
||||
BINARY,
|
||||
|
||||
/// <summary>
|
||||
/// Motorola binary file (most significant byte first). Use for data files.
|
||||
/// </summary>
|
||||
MOTOROLA,
|
||||
|
||||
/// <summary>
|
||||
/// Audio AIFF file (44.1KHz 16-bit stereo)
|
||||
/// </summary>
|
||||
AIFF,
|
||||
|
||||
/// <summary>
|
||||
/// Audio WAVE file (44.1KHz 16-bit stereo)
|
||||
/// </summary>
|
||||
WAVE,
|
||||
|
||||
/// <summary>
|
||||
/// Audio MP3 file (44.1KHz 16-bit stereo)
|
||||
/// </summary>
|
||||
MP3,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Track datatype
|
||||
/// </summary>
|
||||
public enum CueTrackDataType
|
||||
{
|
||||
/// <summary>
|
||||
/// AUDIO, Audio/Music (2352)
|
||||
/// </summary>
|
||||
AUDIO,
|
||||
|
||||
/// <summary>
|
||||
/// CDG, Karaoke CD+G (2448)
|
||||
/// </summary>
|
||||
CDG,
|
||||
|
||||
/// <summary>
|
||||
/// MODE1/2048, CD-ROM Mode1 Data (cooked)
|
||||
/// </summary>
|
||||
MODE1_2048,
|
||||
|
||||
/// <summary>
|
||||
/// MODE1/2352 CD-ROM Mode1 Data (raw)
|
||||
/// </summary>
|
||||
MODE1_2352,
|
||||
|
||||
/// <summary>
|
||||
/// MODE2/2336, CD-ROM XA Mode2 Data
|
||||
/// </summary>
|
||||
MODE2_2336,
|
||||
|
||||
/// <summary>
|
||||
/// MODE2/2352, CD-ROM XA Mode2 Data
|
||||
/// </summary>
|
||||
MODE2_2352,
|
||||
|
||||
/// <summary>
|
||||
/// CDI/2336, CD-I Mode2 Data
|
||||
/// </summary>
|
||||
CDI_2336,
|
||||
|
||||
/// <summary>
|
||||
/// CDI/2352, CD-I Mode2 Data
|
||||
/// </summary>
|
||||
CDI_2352,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Special subcode flags within a track
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum CueTrackFlag
|
||||
{
|
||||
/// <summary>
|
||||
/// DCP, Digital copy permitted
|
||||
/// </summary>
|
||||
DCP = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// 4CH, Four channel audio
|
||||
/// </summary>
|
||||
FourCH = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// PRE, Pre-emphasis enabled (audio tracks only)
|
||||
/// </summary>
|
||||
PRE = 1 << 2,
|
||||
|
||||
/// <summary>
|
||||
/// SCMS, Serial Copy Management System (not supported by all recorders)
|
||||
/// </summary>
|
||||
SCMS = 1 << 3,
|
||||
|
||||
/// <summary>
|
||||
/// DATA, set for data files. This flag is set automatically based on the track’s filetype
|
||||
/// </summary>
|
||||
DATA = 1 << 4,
|
||||
}
|
||||
}
|
||||
28
CueSheets/PostGap.cs
Normal file
28
CueSheets/PostGap.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace SabreTools.Models.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents POSTGAP information of a track
|
||||
/// </summary>
|
||||
public class PostGap
|
||||
{
|
||||
/// <summary>
|
||||
/// Length of POSTGAP in minutes
|
||||
/// </summary>
|
||||
public int Minutes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of POSTGAP in seconds
|
||||
/// </summary>
|
||||
/// <remarks>There are 60 seconds in a minute</remarks>
|
||||
public int Seconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of POSTGAP in frames.
|
||||
/// </summary>
|
||||
/// <remarks>There are 75 frames per second</remarks>
|
||||
public int Frames { get; set; }
|
||||
}
|
||||
}
|
||||
28
CueSheets/PreGap.cs
Normal file
28
CueSheets/PreGap.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
/// <remarks>
|
||||
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
|
||||
/// </remarks>
|
||||
namespace SabreTools.Models.CueSheets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents PREGAP information of a track
|
||||
/// </summary>
|
||||
public class PreGap
|
||||
{
|
||||
/// <summary>
|
||||
/// Length of PREGAP in minutes
|
||||
/// </summary>
|
||||
public int Minutes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of PREGAP in seconds
|
||||
/// </summary>
|
||||
/// <remarks>There are 60 seconds in a minute</remarks>
|
||||
public int Seconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of PREGAP in frames.
|
||||
/// </summary>
|
||||
/// <remarks>There are 75 frames per second</remarks>
|
||||
public int Frames { get; set; }
|
||||
}
|
||||
}
|
||||
17
PIC/Constants.cs
Normal file
17
PIC/Constants.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace SabreTools.Models.PIC
|
||||
{
|
||||
/// <see href="https://www.t10.org/ftp/t10/document.05/05-206r0.pdf"/>
|
||||
/// <see href="https://github.com/aaru-dps/Aaru.Decoders/blob/devel/Bluray/DI.cs"/>
|
||||
public class Constants
|
||||
{
|
||||
public const string DiscTypeIdentifierROM = "BDO";
|
||||
|
||||
public const string DiscTypeIdentifierROMUltra = "BDU";
|
||||
|
||||
public const string DiscTypeIdentifierReWritable = "BDW";
|
||||
|
||||
public const string DiscTypeIdentifierRecordable = "BDR";
|
||||
|
||||
public const string DiscTypeIdentifierXGD4 = "XG4";
|
||||
}
|
||||
}
|
||||
38
PIC/DiscInformation.cs
Normal file
38
PIC/DiscInformation.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
namespace SabreTools.Models.PIC
|
||||
{
|
||||
/// <summary>
|
||||
/// Disc Information and Emergency Brake data shall be read from the PIC zone. DI units that
|
||||
/// contain physical information shall be returned.Emergency Brake data shall be returned.The
|
||||
/// information shall be collected from the layer specified in the Layer field of the CDB. If any data
|
||||
/// can be returned, 4 100 bytes shall be returned.
|
||||
/// </summary>
|
||||
/// <see href="https://www.t10.org/ftp/t10/document.05/05-206r0.pdf"/>
|
||||
/// <see href="https://github.com/aaru-dps/Aaru.Decoders/blob/devel/Bluray/DI.cs"/>
|
||||
public class DiscInformation
|
||||
{
|
||||
/// <summary>
|
||||
/// 2048 bytes for BD-ROM, 3584 bytes for BD-R/RE
|
||||
/// </summary>
|
||||
/// <remarks>Big-endian format</remarks>
|
||||
public ushort DataStructureLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Should be 0x00
|
||||
/// </summary>
|
||||
public byte Reserved0 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Should be 0x00
|
||||
/// </summary>
|
||||
public byte Reserved1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Disc information and emergency brake units
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public DiscInformationUnit[] Units { get; set; }
|
||||
#else
|
||||
public DiscInformationUnit?[]? Units { get; set; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
34
PIC/DiscInformationUnit.cs
Normal file
34
PIC/DiscInformationUnit.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
namespace SabreTools.Models.PIC
|
||||
{
|
||||
/// <see href="https://www.t10.org/ftp/t10/document.05/05-206r0.pdf"/>
|
||||
/// <see href="https://github.com/aaru-dps/Aaru.Decoders/blob/devel/Bluray/DI.cs"/>
|
||||
public class DiscInformationUnit
|
||||
{
|
||||
/// <summary>
|
||||
/// Unit header
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public DiscInformationUnitHeader Header { get; set; }
|
||||
#else
|
||||
public DiscInformationUnitHeader? Header { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Unit body
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public DiscInformationUnitBody Body { get; set; }
|
||||
#else
|
||||
public DiscInformationUnitBody? Body { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Unit trailer (BD-R/RE only)
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public DiscInformationUnitTrailer Trailer { get; set; }
|
||||
#else
|
||||
public DiscInformationUnitTrailer? Trailer { get; set; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
36
PIC/DiscInformationUnitBody.cs
Normal file
36
PIC/DiscInformationUnitBody.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
namespace SabreTools.Models.PIC
|
||||
{
|
||||
/// <see href="https://www.t10.org/ftp/t10/document.05/05-206r0.pdf"/>
|
||||
/// <see href="https://github.com/aaru-dps/Aaru.Decoders/blob/devel/Bluray/DI.cs"/>
|
||||
/// TODO: Write models for the dependent contents, if possible
|
||||
public class DiscInformationUnitBody
|
||||
{
|
||||
/// <summary>
|
||||
/// Disc Type Identifier
|
||||
/// = "BDO" for BD-ROM
|
||||
/// = "BDU" for BD-ROM Ultra
|
||||
/// = "BDW" for BD-RE
|
||||
/// = "BDR" for BD-R
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string DiscTypeIdentifier { get; set; }
|
||||
#else
|
||||
public string? DiscTypeIdentifier { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Disc Size/Class/Version
|
||||
/// </summary>
|
||||
public byte DiscSizeClassVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// DI Unit Format dependent contents
|
||||
/// </summary>
|
||||
/// <remarks>52 bytes for BD-ROM, 100 bytes for BD-R/RE</remarks>
|
||||
#if NET48
|
||||
public byte[] FormatDependentContents { get; set; }
|
||||
#else
|
||||
public byte[]? FormatDependentContents { get; set; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
47
PIC/DiscInformationUnitHeader.cs
Normal file
47
PIC/DiscInformationUnitHeader.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
namespace SabreTools.Models.PIC
|
||||
{
|
||||
/// <see href="https://www.t10.org/ftp/t10/document.05/05-206r0.pdf"/>
|
||||
/// <see href="https://github.com/aaru-dps/Aaru.Decoders/blob/devel/Bluray/DI.cs"/>
|
||||
public class DiscInformationUnitHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Disc Information Identifier "DI"
|
||||
/// Emergency Brake Identifier "EB"
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string DiscInformationIdentifier { get; set; }
|
||||
#else
|
||||
public string? DiscInformationIdentifier { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Disc Information Format
|
||||
/// </summary>
|
||||
public byte DiscInformationFormat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of DI units in each DI block
|
||||
/// </summary>
|
||||
public byte NumberOfUnitsInBlock { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Should be 0x00
|
||||
/// </summary>
|
||||
public byte Reserved0 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// DI unit Sequence Number
|
||||
/// </summary>
|
||||
public byte SequenceNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of bytes in use in this DI unit
|
||||
/// </summary>
|
||||
public byte BytesInUse { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Should be 0x00
|
||||
/// </summary>
|
||||
public byte Reserved1 { get; set; }
|
||||
}
|
||||
}
|
||||
40
PIC/DiscInformationUnitTrailer.cs
Normal file
40
PIC/DiscInformationUnitTrailer.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
namespace SabreTools.Models.PIC
|
||||
{
|
||||
/// <summary>
|
||||
/// BD-R/RE only
|
||||
/// </summary>
|
||||
/// <see href="https://www.t10.org/ftp/t10/document.05/05-206r0.pdf"/>
|
||||
/// <see href="https://github.com/aaru-dps/Aaru.Decoders/blob/devel/Bluray/DI.cs"/>
|
||||
public class DiscInformationUnitTrailer
|
||||
{
|
||||
/// <summary>
|
||||
/// Disc Manufacturer ID
|
||||
/// </summary>
|
||||
/// <remarks>6 bytes</remarks>
|
||||
#if NET48
|
||||
public byte[] DiscManufacturerID { get; set; } = new byte[6];
|
||||
#else
|
||||
public byte[]? DiscManufacturerID { get; set; } = new byte[6];
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Media Type ID
|
||||
/// </summary>
|
||||
/// <remarks>3 bytes</remarks>
|
||||
#if NET48
|
||||
public byte[] MediaTypeID { get; set; } = new byte[3];
|
||||
#else
|
||||
public byte[]? MediaTypeID { get; set; } = new byte[3];
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Time Stamp
|
||||
/// </summary>
|
||||
public ushort TimeStamp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Product Revision Number
|
||||
/// </summary>
|
||||
public byte ProductRevisionNumber { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net48;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Version>1.1.1</Version>
|
||||
<Version>1.1.4</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
|
||||
49
Xbox/XMID.cs
Normal file
49
Xbox/XMID.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
namespace SabreTools.Models.Xbox
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains information specific to an XGD disc
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// XGD1 XMID Format Information:
|
||||
///
|
||||
/// AABBBCCD
|
||||
/// - AA => The two-ASCII-character publisher identifier (see GetPublisher for details)
|
||||
/// - BBB => Game ID
|
||||
/// - CC => Version number
|
||||
/// - D => Region identifier (see GetRegion for details)
|
||||
/// </remarks>
|
||||
public class XMID
|
||||
{
|
||||
/// <summary>
|
||||
/// 2-character publisher identifier
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string PublisherIdentifier { get; set; }
|
||||
#else
|
||||
public string? PublisherIdentifier { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 3-character Game ID
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string GameID { get; set; }
|
||||
#else
|
||||
public string? GameID { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 2-character Internal version number
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string VersionNumber { get; set; }
|
||||
#else
|
||||
public string? VersionNumber { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 1-character Region identifier character
|
||||
/// </summary
|
||||
public char RegionIdentifier { get; set; }
|
||||
}
|
||||
}
|
||||
91
Xbox/XeMID.cs
Normal file
91
Xbox/XeMID.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
namespace SabreTools.Models.Xbox
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains information specific to an XGD disc
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// XGD2/3 XeMID Format Information:
|
||||
///
|
||||
/// AABCCCDDEFFGHH(IIIIIIII)
|
||||
/// - AA => The two-ASCII-character publisher identifier (see GetPublisher for details)
|
||||
/// - B => Platform identifier; 2 indicates Xbox 360.
|
||||
/// - CCC => Game ID
|
||||
/// - DD => SKU number (unique per SKU of a title)
|
||||
/// - E => Region identifier (see GetRegion for details)
|
||||
/// - FF => Base version; usually starts at 01 (can be 1 or 2 characters)
|
||||
/// - G => Media type identifier (see GetMediaSubtype for details)
|
||||
/// - HH => Disc number stored in [disc number][total discs] format
|
||||
/// - IIIIIIII => 8-hex-digit certification submission identifier; usually on test discs only
|
||||
/// </remarks>
|
||||
public class XeMID
|
||||
{
|
||||
/// <summary>
|
||||
/// 2-character publisher identifier
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string PublisherIdentifier { get; set; }
|
||||
#else
|
||||
public string? PublisherIdentifier { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 1-character Platform disc is made for, 2 indicates Xbox 360
|
||||
/// </summary>
|
||||
public char PlatformIdentifier { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 3-character Game ID
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string GameID { get; set; }
|
||||
#else
|
||||
public string? GameID { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 2-character Title-specific SKU
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string SKU { get; set; }
|
||||
#else
|
||||
public string? SKU { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 1-character Region identifier character
|
||||
/// </summary>
|
||||
public char RegionIdentifier { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 2-character Base version of executables, usually starts at 01
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string BaseVersion { get; set; }
|
||||
#else
|
||||
public string? BaseVersion { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 1-character Media subtype identifier
|
||||
/// </summary>
|
||||
public char MediaSubtypeIdentifier { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 2-character Disc number stored in [disc number][total discs] format
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string DiscNumberIdentifier { get; set; }
|
||||
#else
|
||||
public string? DiscNumberIdentifier { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 8-hex-digit certification submission identifier; usually on test discs only
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string CertificationSubmissionIdentifier { get; set; }
|
||||
#else
|
||||
public string? CertificationSubmissionIdentifier { get; set; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user