Module refinery.lib.fast.lzfse_header
Reads the block headers of an LZFSE stream for both LZFSE decoders in refinery.lib.fast.lzfse and
checks that each block lies within the input and that its fields are in range.
Expand source code Browse git
"""
Reads the block headers of an LZFSE stream for both LZFSE decoders in `refinery.lib.fast.lzfse` and
checks that each block lies within the input and that its fields are in range.
"""
from __future__ import annotations
import enum
import struct
from typing import NamedTuple
LITERALS_PER_BLOCK = 40000
MATCHES_PER_BLOCK = 10000
_LITERAL_STATES = 1024
_L_STATES = 64
_M_STATES = 64
_D_STATES = 256
_LONGEST_LZFSE_MATCH = 2359
_LONGEST_LZVN_MATCH = 271
_V2_FIXED_SIZE = 32
_RAW_FIELDS = struct.Struct('<I')
_LZVN_FIELDS = struct.Struct('<II')
_V1_FIELDS = struct.Struct('<6Ii4HiHHH360H2x')
_V2_FIELDS = struct.Struct('<IQQQ')
class BlockKind(enum.IntEnum):
END = 0x24787662
RAW = 0x2D787662
LZFSE_V1 = 0x31787662
LZFSE_V2 = 0x32787662
LZVN = 0x6E787662
class BlockHeader(NamedTuple):
kind: BlockKind
end: int
raw_size: int = 0
payload: int = 0
freq_table: int = 0
literal_payload_size: int = 0
lmd_payload_size: int = 0
n_literals: int = 0
n_matches: int = 0
literal_bits: int = 0
literal_states: tuple[int, ...] = ()
lmd_bits: int = 0
l_state: int = 0
m_state: int = 0
d_state: int = 0
freqs: tuple[int, ...] = ()
def read_block_header(data: memoryview, pos: int) -> BlockHeader:
"""
Read the header of the block at offset `pos`. The compressed frequency table of an LZFSE V2
block is not decoded; it begins at `BlockHeader.freq_table` and ends at `BlockHeader.payload`.
"""
if pos + 4 > len(data):
raise ValueError('the input ends before the end-of-stream block')
magic = int.from_bytes(data[pos:pos + 4], 'little')
try:
kind = BlockKind(magic)
except ValueError:
raise ValueError(F'unknown LZFSE block magic: 0x{magic:08X}') from None
body = pos + 4
if kind is BlockKind.END:
return BlockHeader(kind, body)
if kind is BlockKind.RAW:
raw_size, = _fields(_RAW_FIELDS, data, pos)
payload = body + _RAW_FIELDS.size
header = BlockHeader(kind, payload + raw_size, raw_size, payload)
elif kind is BlockKind.LZVN:
raw_size, size = _fields(_LZVN_FIELDS, data, pos)
payload = body + _LZVN_FIELDS.size
header = BlockHeader(kind, payload + size, raw_size, payload)
elif kind is BlockKind.LZFSE_V1:
fields = _fields(_V1_FIELDS, data, pos)
raw_size, size, n_literals, n_matches, literal_payload_size, lmd_payload_size = fields[:6]
if literal_payload_size + lmd_payload_size > size:
raise ValueError(F'the payloads of the LZFSE block at offset {pos} exceed the block')
payload = body + _V1_FIELDS.size
header = BlockHeader(
kind,
end=payload + size,
raw_size=raw_size,
payload=payload,
literal_payload_size=literal_payload_size,
lmd_payload_size=lmd_payload_size,
n_literals=n_literals,
n_matches=n_matches,
literal_bits=fields[6],
literal_states=fields[7:11],
lmd_bits=fields[11],
l_state=fields[12],
m_state=fields[13],
d_state=fields[14],
freqs=fields[15:],
)
else:
raw_size, v0, v1, v2 = _fields(_V2_FIELDS, data, pos)
header_size = v2 & 0xFFFFFFFF
if header_size <= _V2_FIXED_SIZE:
raise ValueError(F'the LZFSE block at offset {pos} has no frequency table')
payload = pos + header_size
literal_payload_size = (v0 >> 20) & 0xFFFFF
lmd_payload_size = (v1 >> 40) & 0xFFFFF
header = BlockHeader(
kind,
end=payload + literal_payload_size + lmd_payload_size,
raw_size=raw_size,
payload=payload,
freq_table=pos + _V2_FIXED_SIZE,
literal_payload_size=literal_payload_size,
lmd_payload_size=lmd_payload_size,
n_literals=v0 & 0xFFFFF,
n_matches=(v0 >> 40) & 0xFFFFF,
literal_bits=((v0 >> 60) & 7) - 7,
literal_states=(v1 & 0x3FF, (v1 >> 10) & 0x3FF, (v1 >> 20) & 0x3FF, (v1 >> 30) & 0x3FF),
lmd_bits=((v1 >> 60) & 7) - 7,
l_state=(v2 >> 32) & 0x3FF,
m_state=(v2 >> 42) & 0x3FF,
d_state=(v2 >> 52) & 0x3FF,
)
if header.end > len(data):
raise ValueError(F'the LZFSE block at offset {pos} ends after the end of the input')
if kind in (BlockKind.LZFSE_V1, BlockKind.LZFSE_V2) and not _lzfse_fields_in_range(header):
raise ValueError(F'the LZFSE block at offset {pos} has an invalid header')
if header.raw_size > _most_output(header):
raise ValueError(F'the LZFSE block at offset {pos} claims more output than it can produce')
return header
def _most_output(header: BlockHeader) -> int:
"""
The largest output that the payload of the block can decode to. No LZVN instruction produces
more output per payload byte than a match of the longest length, which takes two bytes.
"""
if header.kind is BlockKind.RAW:
return header.raw_size
if header.kind is BlockKind.LZVN:
return (header.end - header.payload + 1) // 2 * _LONGEST_LZVN_MATCH
return header.n_literals + header.n_matches * _LONGEST_LZFSE_MATCH
def _lzfse_fields_in_range(header: BlockHeader) -> bool:
return (
header.n_literals <= LITERALS_PER_BLOCK
and header.n_literals % 4 == 0
and header.n_matches <= MATCHES_PER_BLOCK
and max(header.literal_states) < _LITERAL_STATES
and header.l_state < _L_STATES
and header.m_state < _M_STATES
and header.d_state < _D_STATES
and -7 <= header.literal_bits <= 0
and -7 <= header.lmd_bits <= 0
)
def _fields(layout: struct.Struct, data: memoryview, pos: int) -> tuple[int, ...]:
body = pos + 4
if body + layout.size > len(data):
raise ValueError(F'the header of the LZFSE block at offset {pos} is cut off')
return layout.unpack_from(data, body)
Functions
def read_block_header(data, pos)-
Read the header of the block at offset
pos. The compressed frequency table of an LZFSE V2 block is not decoded; it begins atBlockHeader.freq_tableand ends atBlockHeader.payload.Expand source code Browse git
def read_block_header(data: memoryview, pos: int) -> BlockHeader: """ Read the header of the block at offset `pos`. The compressed frequency table of an LZFSE V2 block is not decoded; it begins at `BlockHeader.freq_table` and ends at `BlockHeader.payload`. """ if pos + 4 > len(data): raise ValueError('the input ends before the end-of-stream block') magic = int.from_bytes(data[pos:pos + 4], 'little') try: kind = BlockKind(magic) except ValueError: raise ValueError(F'unknown LZFSE block magic: 0x{magic:08X}') from None body = pos + 4 if kind is BlockKind.END: return BlockHeader(kind, body) if kind is BlockKind.RAW: raw_size, = _fields(_RAW_FIELDS, data, pos) payload = body + _RAW_FIELDS.size header = BlockHeader(kind, payload + raw_size, raw_size, payload) elif kind is BlockKind.LZVN: raw_size, size = _fields(_LZVN_FIELDS, data, pos) payload = body + _LZVN_FIELDS.size header = BlockHeader(kind, payload + size, raw_size, payload) elif kind is BlockKind.LZFSE_V1: fields = _fields(_V1_FIELDS, data, pos) raw_size, size, n_literals, n_matches, literal_payload_size, lmd_payload_size = fields[:6] if literal_payload_size + lmd_payload_size > size: raise ValueError(F'the payloads of the LZFSE block at offset {pos} exceed the block') payload = body + _V1_FIELDS.size header = BlockHeader( kind, end=payload + size, raw_size=raw_size, payload=payload, literal_payload_size=literal_payload_size, lmd_payload_size=lmd_payload_size, n_literals=n_literals, n_matches=n_matches, literal_bits=fields[6], literal_states=fields[7:11], lmd_bits=fields[11], l_state=fields[12], m_state=fields[13], d_state=fields[14], freqs=fields[15:], ) else: raw_size, v0, v1, v2 = _fields(_V2_FIELDS, data, pos) header_size = v2 & 0xFFFFFFFF if header_size <= _V2_FIXED_SIZE: raise ValueError(F'the LZFSE block at offset {pos} has no frequency table') payload = pos + header_size literal_payload_size = (v0 >> 20) & 0xFFFFF lmd_payload_size = (v1 >> 40) & 0xFFFFF header = BlockHeader( kind, end=payload + literal_payload_size + lmd_payload_size, raw_size=raw_size, payload=payload, freq_table=pos + _V2_FIXED_SIZE, literal_payload_size=literal_payload_size, lmd_payload_size=lmd_payload_size, n_literals=v0 & 0xFFFFF, n_matches=(v0 >> 40) & 0xFFFFF, literal_bits=((v0 >> 60) & 7) - 7, literal_states=(v1 & 0x3FF, (v1 >> 10) & 0x3FF, (v1 >> 20) & 0x3FF, (v1 >> 30) & 0x3FF), lmd_bits=((v1 >> 60) & 7) - 7, l_state=(v2 >> 32) & 0x3FF, m_state=(v2 >> 42) & 0x3FF, d_state=(v2 >> 52) & 0x3FF, ) if header.end > len(data): raise ValueError(F'the LZFSE block at offset {pos} ends after the end of the input') if kind in (BlockKind.LZFSE_V1, BlockKind.LZFSE_V2) and not _lzfse_fields_in_range(header): raise ValueError(F'the LZFSE block at offset {pos} has an invalid header') if header.raw_size > _most_output(header): raise ValueError(F'the LZFSE block at offset {pos} claims more output than it can produce') return header
Classes
class BlockKind (*args, **kwds)-
Enum where members are also (and must be) ints
Expand source code Browse git
class BlockKind(enum.IntEnum): END = 0x24787662 RAW = 0x2D787662 LZFSE_V1 = 0x31787662 LZFSE_V2 = 0x32787662 LZVN = 0x6E787662Ancestors
- enum.IntEnum
- builtins.int
- enum.ReprEnum
- enum.Enum
Class variables
var END-
The type of the None singleton.
var RAW-
The type of the None singleton.
var LZFSE_V1-
The type of the None singleton.
var LZFSE_V2-
The type of the None singleton.
var LZVN-
The type of the None singleton.
class BlockHeader (kind, end, raw_size=0, payload=0, freq_table=0, literal_payload_size=0, lmd_payload_size=0, n_literals=0, n_matches=0, literal_bits=0, literal_states=(), lmd_bits=0, l_state=0, m_state=0, d_state=0, freqs=())-
BlockHeader(kind, end, raw_size, payload, freq_table, literal_payload_size, lmd_payload_size, n_literals, n_matches, literal_bits, literal_states, lmd_bits, l_state, m_state, d_state, freqs)
Expand source code Browse git
class BlockHeader(NamedTuple): kind: BlockKind end: int raw_size: int = 0 payload: int = 0 freq_table: int = 0 literal_payload_size: int = 0 lmd_payload_size: int = 0 n_literals: int = 0 n_matches: int = 0 literal_bits: int = 0 literal_states: tuple[int, ...] = () lmd_bits: int = 0 l_state: int = 0 m_state: int = 0 d_state: int = 0 freqs: tuple[int, ...] = ()Ancestors
- builtins.tuple
Instance variables
var kind-
Alias for field number 0
Expand source code Browse git
class BlockHeader(NamedTuple): kind: BlockKind end: int raw_size: int = 0 payload: int = 0 freq_table: int = 0 literal_payload_size: int = 0 lmd_payload_size: int = 0 n_literals: int = 0 n_matches: int = 0 literal_bits: int = 0 literal_states: tuple[int, ...] = () lmd_bits: int = 0 l_state: int = 0 m_state: int = 0 d_state: int = 0 freqs: tuple[int, ...] = () var end-
Alias for field number 1
Expand source code Browse git
class BlockHeader(NamedTuple): kind: BlockKind end: int raw_size: int = 0 payload: int = 0 freq_table: int = 0 literal_payload_size: int = 0 lmd_payload_size: int = 0 n_literals: int = 0 n_matches: int = 0 literal_bits: int = 0 literal_states: tuple[int, ...] = () lmd_bits: int = 0 l_state: int = 0 m_state: int = 0 d_state: int = 0 freqs: tuple[int, ...] = () var raw_size-
Alias for field number 2
Expand source code Browse git
class BlockHeader(NamedTuple): kind: BlockKind end: int raw_size: int = 0 payload: int = 0 freq_table: int = 0 literal_payload_size: int = 0 lmd_payload_size: int = 0 n_literals: int = 0 n_matches: int = 0 literal_bits: int = 0 literal_states: tuple[int, ...] = () lmd_bits: int = 0 l_state: int = 0 m_state: int = 0 d_state: int = 0 freqs: tuple[int, ...] = () var payload-
Alias for field number 3
Expand source code Browse git
class BlockHeader(NamedTuple): kind: BlockKind end: int raw_size: int = 0 payload: int = 0 freq_table: int = 0 literal_payload_size: int = 0 lmd_payload_size: int = 0 n_literals: int = 0 n_matches: int = 0 literal_bits: int = 0 literal_states: tuple[int, ...] = () lmd_bits: int = 0 l_state: int = 0 m_state: int = 0 d_state: int = 0 freqs: tuple[int, ...] = () var freq_table-
Alias for field number 4
Expand source code Browse git
class BlockHeader(NamedTuple): kind: BlockKind end: int raw_size: int = 0 payload: int = 0 freq_table: int = 0 literal_payload_size: int = 0 lmd_payload_size: int = 0 n_literals: int = 0 n_matches: int = 0 literal_bits: int = 0 literal_states: tuple[int, ...] = () lmd_bits: int = 0 l_state: int = 0 m_state: int = 0 d_state: int = 0 freqs: tuple[int, ...] = () var literal_payload_size-
Alias for field number 5
Expand source code Browse git
class BlockHeader(NamedTuple): kind: BlockKind end: int raw_size: int = 0 payload: int = 0 freq_table: int = 0 literal_payload_size: int = 0 lmd_payload_size: int = 0 n_literals: int = 0 n_matches: int = 0 literal_bits: int = 0 literal_states: tuple[int, ...] = () lmd_bits: int = 0 l_state: int = 0 m_state: int = 0 d_state: int = 0 freqs: tuple[int, ...] = () var lmd_payload_size-
Alias for field number 6
Expand source code Browse git
class BlockHeader(NamedTuple): kind: BlockKind end: int raw_size: int = 0 payload: int = 0 freq_table: int = 0 literal_payload_size: int = 0 lmd_payload_size: int = 0 n_literals: int = 0 n_matches: int = 0 literal_bits: int = 0 literal_states: tuple[int, ...] = () lmd_bits: int = 0 l_state: int = 0 m_state: int = 0 d_state: int = 0 freqs: tuple[int, ...] = () var n_literals-
Alias for field number 7
Expand source code Browse git
class BlockHeader(NamedTuple): kind: BlockKind end: int raw_size: int = 0 payload: int = 0 freq_table: int = 0 literal_payload_size: int = 0 lmd_payload_size: int = 0 n_literals: int = 0 n_matches: int = 0 literal_bits: int = 0 literal_states: tuple[int, ...] = () lmd_bits: int = 0 l_state: int = 0 m_state: int = 0 d_state: int = 0 freqs: tuple[int, ...] = () var n_matches-
Alias for field number 8
Expand source code Browse git
class BlockHeader(NamedTuple): kind: BlockKind end: int raw_size: int = 0 payload: int = 0 freq_table: int = 0 literal_payload_size: int = 0 lmd_payload_size: int = 0 n_literals: int = 0 n_matches: int = 0 literal_bits: int = 0 literal_states: tuple[int, ...] = () lmd_bits: int = 0 l_state: int = 0 m_state: int = 0 d_state: int = 0 freqs: tuple[int, ...] = () var literal_bits-
Alias for field number 9
Expand source code Browse git
class BlockHeader(NamedTuple): kind: BlockKind end: int raw_size: int = 0 payload: int = 0 freq_table: int = 0 literal_payload_size: int = 0 lmd_payload_size: int = 0 n_literals: int = 0 n_matches: int = 0 literal_bits: int = 0 literal_states: tuple[int, ...] = () lmd_bits: int = 0 l_state: int = 0 m_state: int = 0 d_state: int = 0 freqs: tuple[int, ...] = () var literal_states-
Alias for field number 10
Expand source code Browse git
class BlockHeader(NamedTuple): kind: BlockKind end: int raw_size: int = 0 payload: int = 0 freq_table: int = 0 literal_payload_size: int = 0 lmd_payload_size: int = 0 n_literals: int = 0 n_matches: int = 0 literal_bits: int = 0 literal_states: tuple[int, ...] = () lmd_bits: int = 0 l_state: int = 0 m_state: int = 0 d_state: int = 0 freqs: tuple[int, ...] = () var lmd_bits-
Alias for field number 11
Expand source code Browse git
class BlockHeader(NamedTuple): kind: BlockKind end: int raw_size: int = 0 payload: int = 0 freq_table: int = 0 literal_payload_size: int = 0 lmd_payload_size: int = 0 n_literals: int = 0 n_matches: int = 0 literal_bits: int = 0 literal_states: tuple[int, ...] = () lmd_bits: int = 0 l_state: int = 0 m_state: int = 0 d_state: int = 0 freqs: tuple[int, ...] = () var l_state-
Alias for field number 12
Expand source code Browse git
class BlockHeader(NamedTuple): kind: BlockKind end: int raw_size: int = 0 payload: int = 0 freq_table: int = 0 literal_payload_size: int = 0 lmd_payload_size: int = 0 n_literals: int = 0 n_matches: int = 0 literal_bits: int = 0 literal_states: tuple[int, ...] = () lmd_bits: int = 0 l_state: int = 0 m_state: int = 0 d_state: int = 0 freqs: tuple[int, ...] = () var m_state-
Alias for field number 13
Expand source code Browse git
class BlockHeader(NamedTuple): kind: BlockKind end: int raw_size: int = 0 payload: int = 0 freq_table: int = 0 literal_payload_size: int = 0 lmd_payload_size: int = 0 n_literals: int = 0 n_matches: int = 0 literal_bits: int = 0 literal_states: tuple[int, ...] = () lmd_bits: int = 0 l_state: int = 0 m_state: int = 0 d_state: int = 0 freqs: tuple[int, ...] = () var d_state-
Alias for field number 14
Expand source code Browse git
class BlockHeader(NamedTuple): kind: BlockKind end: int raw_size: int = 0 payload: int = 0 freq_table: int = 0 literal_payload_size: int = 0 lmd_payload_size: int = 0 n_literals: int = 0 n_matches: int = 0 literal_bits: int = 0 literal_states: tuple[int, ...] = () lmd_bits: int = 0 l_state: int = 0 m_state: int = 0 d_state: int = 0 freqs: tuple[int, ...] = () var freqs-
Alias for field number 15
Expand source code Browse git
class BlockHeader(NamedTuple): kind: BlockKind end: int raw_size: int = 0 payload: int = 0 freq_table: int = 0 literal_payload_size: int = 0 lmd_payload_size: int = 0 n_literals: int = 0 n_matches: int = 0 literal_bits: int = 0 literal_states: tuple[int, ...] = () lmd_bits: int = 0 l_state: int = 0 m_state: int = 0 d_state: int = 0 freqs: tuple[int, ...] = ()