pub struct SqpkCompressedBlock { /* private fields */ }Expand description
One block of a SqpkFile AddFile payload, which may be DEFLATE-compressed
or stored raw.
SqpkFile payloads are split into a sequence of these blocks. Each block
begins with a 16-byte little-endian header that describes the compressed
and decompressed sizes, followed by the data bytes padded to a 128-byte
boundary.
§Compression sentinel
The compressed_size field in the wire header uses the value 0x7d00
(decimal 32000) as a sentinel meaning “this block is not compressed”.
Any other value means the data bytes are a raw DEFLATE stream
(no zlib wrapper, no gzip header — just RFC 1951 raw deflate).
§Wire format of one block (all little-endian)
┌─────────────────────────────────────────────────────────────────────┐
│ header_size : i32 LE always 16 in practice │ bytes 0–3
│ <pad> : u32 LE always zero │ bytes 4–7
│ compressed_size : i32 LE byte count of DEFLATE data │ bytes 8–11
│ OR 0x7d00 (32000) if uncompressed │
│ decompressed_size : i32 LE byte count of decompressed output │ bytes 12–15
│ data : [u8] compressed or raw bytes │ bytes 16–…
│ <alignment> : [u8] zero-padding to 128-byte boundary │
└─────────────────────────────────────────────────────────────────────┘§128-byte alignment formula
The total byte count to read for a block’s data + alignment is:
block_len = (data_len + 143) & !127where data_len is compressed_size if compressed, or decompressed_size
if uncompressed. The constant 143 is 128 - 1 + 16 (subtract the 16-byte
header that is not included in data_len, then round up to the next
128-byte boundary). The number of data bytes actually read is
block_len - header_size; the alignment padding is consumed but discarded.
§pub(crate) visibility
SqpkCompressedBlock is pub so that it appears in rustdoc and can be
named in SqpkFile::blocks, but it can only be constructed via
new (for tests) or by parsing a SqpkFile.
See SqpkFile.cs / ZiPatchConfig.cs in the XIVLauncher reference implementation.
Implementations§
Source§impl SqpkCompressedBlock
impl SqpkCompressedBlock
Sourcepub fn new(is_compressed: bool, decompressed_size: usize, data: Vec<u8>) -> Self
pub fn new(is_compressed: bool, decompressed_size: usize, data: Vec<u8>) -> Self
Construct a block directly from its component parts.
This constructor exists primarily for unit tests. Production code
creates blocks by parsing a SqpkFile from a patch byte stream.
is_compressed:trueifdatais a raw DEFLATE stream.decompressed_size: the expected number of bytes after decompression; used to pre-allocate the output buffer indecompress.data: raw compressed bytes or exact uncompressed bytes, depending onis_compressed.
Sourcepub fn decompress_into(&self, w: &mut impl Write) -> Result<()>
pub fn decompress_into(&self, w: &mut impl Write) -> Result<()>
Stream the block’s decompressed bytes into w.
For uncompressed blocks, w.write_all(&self.data) is called directly.
For compressed blocks, the data is piped through DeflateDecoder (raw
DEFLATE, RFC 1951 — no zlib or gzip wrapper) before being written.
This is the primary write path used by the apply layer: each block in a
SqpkFile AddFile operation is streamed into the target file handle
in sequence.
§Errors
ZiPatchError::Decompress— the DEFLATE stream is malformed or truncated.ZiPatchError::Io—w.write_allfailed.
Sourcepub fn decompress_into_with(
&self,
decompressor: &mut Decompress,
w: &mut impl Write,
) -> Result<()>
pub fn decompress_into_with( &self, decompressor: &mut Decompress, w: &mut impl Write, ) -> Result<()>
Stream the block’s decompressed bytes into w, reusing a caller-owned
Decompress state across blocks.
Equivalent to decompress_into
in behaviour and error semantics, but avoids the per-call ~100 KiB
zlib-state allocation that DeflateDecoder::new would otherwise
pay. The apply layer threads a single Decompress through every
block in a multi-block SqpkFile::AddFile chunk; uncompressed blocks
short-circuit to write_all and leave the decompressor untouched.
decompressor is reset via Decompress::reset(false)
at the start of every compressed block, so callers may pass an
already-used state without manually resetting it.
§Errors
ZiPatchError::Decompress— the DEFLATE stream is malformed or the manual feed loop made no forward progress (corrupt or truncated payload).ZiPatchError::Io—w.write_allfailed.
Sourcepub fn is_compressed(&self) -> bool
pub fn is_compressed(&self) -> bool
Returns true if the block stores a raw DEFLATE stream.
false means the block carries already-decompressed bytes (the
compressed_size == 0x7d00 sentinel).
Sourcepub fn decompressed_size(&self) -> usize
pub fn decompressed_size(&self) -> usize
Returns the block’s expected decompressed length in bytes.
Sourcepub fn data_len(&self) -> usize
pub fn data_len(&self) -> usize
Returns the byte length of the block’s stored data slab.
For compressed blocks this is the length of the DEFLATE payload as the
parser stored it (which may include trailing 128-byte alignment padding
that the decoder ignores past the end-of-stream marker). For
uncompressed blocks it equals decompressed_size.
Sourcepub fn decompress(&self) -> Result<Cow<'_, [u8]>>
pub fn decompress(&self) -> Result<Cow<'_, [u8]>>
Return the block’s decompressed bytes as a Cow.
Uncompressed blocks return Cow::Borrowed(&self.data) — a zero-copy
borrow into the block’s existing buffer. Compressed blocks decompress
into a newly allocated Vec and return Cow::Owned.
Use decompress_into instead
when writing to a file handle, to avoid the intermediate allocation.
§Errors
ZiPatchError::Decompress— the DEFLATE stream is malformed or truncated (compressed blocks only).
Trait Implementations§
Source§impl Clone for SqpkCompressedBlock
impl Clone for SqpkCompressedBlock
Source§fn clone(&self) -> SqpkCompressedBlock
fn clone(&self) -> SqpkCompressedBlock
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for SqpkCompressedBlock
impl Debug for SqpkCompressedBlock
Source§impl PartialEq for SqpkCompressedBlock
impl PartialEq for SqpkCompressedBlock
Source§fn eq(&self, other: &SqpkCompressedBlock) -> bool
fn eq(&self, other: &SqpkCompressedBlock) -> bool
self and other values to be equal, and is used by ==.impl Eq for SqpkCompressedBlock
impl StructuralPartialEq for SqpkCompressedBlock
Auto Trait Implementations§
impl Freeze for SqpkCompressedBlock
impl RefUnwindSafe for SqpkCompressedBlock
impl Send for SqpkCompressedBlock
impl Sync for SqpkCompressedBlock
impl Unpin for SqpkCompressedBlock
impl UnsafeUnpin for SqpkCompressedBlock
impl UnwindSafe for SqpkCompressedBlock
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more