Function decodeBlock [src]
Decode a single block from src into dest. The beginning of src must be
the start of the block content (i.e. directly after the block header).
Increments consumed_count by the number of bytes read from src to decode
the block and returns the decompressed size of the block.
Errors returned:
error.BlockSizeOverMaximum if block's size is larger than 1 << 17 or
dest[written_count..].len
error.MalformedBlockSize if src.len is smaller than the block size
and the block is a raw or compressed block
error.ReservedBlock if the block is a reserved block
error.MalformedRleBlock if the block is an RLE block and src.len < 1
error.MalformedCompressedBlock if there are errors decoding a
compressed block
error.DestTooSmall is dest is not large enough to hold the
decompressed block
Prototype
pub fn decodeBlock( dest: []u8, src: []const u8, block_header: frame.Zstandard.Block.Header, decode_state: *DecodeState, consumed_count: *usize, block_size_max: usize, written_count: usize, ) (error{DestTooSmall} || Error)!usize
Parameters
dest: []u8
src: []const u8
block_header: frame.Zstandard.Block.Header
decode_state: *DecodeState
consumed_count: *usize
block_size_max: usize
written_count: usize
Source
pub fn decodeBlock(
dest: []u8,
src: []const u8,
block_header: frame.Zstandard.Block.Header,
decode_state: *DecodeState,
consumed_count: *usize,
block_size_max: usize,
written_count: usize,
) (error{DestTooSmall} || Error)!usize {
const block_size = block_header.block_size;
if (block_size_max < block_size) return error.BlockSizeOverMaximum;
switch (block_header.block_type) {
.raw => {
if (src.len < block_size) return error.MalformedBlockSize;
if (dest[written_count..].len < block_size) return error.DestTooSmall;
@memcpy(dest[written_count..][0..block_size], src[0..block_size]);
consumed_count.* += block_size;
decode_state.written_count += block_size;
return block_size;
},
.rle => {
if (src.len < 1) return error.MalformedRleBlock;
if (dest[written_count..].len < block_size) return error.DestTooSmall;
for (written_count..block_size + written_count) |write_pos| {
dest[write_pos] = src[0];
}
consumed_count.* += 1;
decode_state.written_count += block_size;
return block_size;
},
.compressed => {
if (src.len < block_size) return error.MalformedBlockSize;
var bytes_read: usize = 0;
const literals = decodeLiteralsSectionSlice(src[0..block_size], &bytes_read) catch
return error.MalformedCompressedBlock;
var fbs = std.io.fixedBufferStream(src[bytes_read..block_size]);
const fbs_reader = fbs.reader();
const sequences_header = decodeSequencesHeader(fbs_reader) catch
return error.MalformedCompressedBlock;
decode_state.prepare(fbs_reader, literals, sequences_header) catch
return error.MalformedCompressedBlock;
bytes_read += fbs.pos;
var bytes_written: usize = 0;
{
const bit_stream_bytes = src[bytes_read..block_size];
var bit_stream: readers.ReverseBitReader = undefined;
bit_stream.init(bit_stream_bytes) catch return error.MalformedCompressedBlock;
if (sequences_header.sequence_count > 0) {
decode_state.readInitialFseState(&bit_stream) catch
return error.MalformedCompressedBlock;
var sequence_size_limit = block_size_max;
for (0..sequences_header.sequence_count) |i| {
const write_pos = written_count + bytes_written;
const decompressed_size = decode_state.decodeSequenceSlice(
dest,
write_pos,
&bit_stream,
sequence_size_limit,
i == sequences_header.sequence_count - 1,
) catch |err| switch (err) {
error.DestTooSmall => return error.DestTooSmall,
else => return error.MalformedCompressedBlock,
};
bytes_written += decompressed_size;
sequence_size_limit -= decompressed_size;
}
}
if (!bit_stream.isEmpty()) {
return error.MalformedCompressedBlock;
}
}
if (decode_state.literal_written_count < literals.header.regenerated_size) {
const len = literals.header.regenerated_size - decode_state.literal_written_count;
if (len > dest[written_count + bytes_written ..].len) return error.DestTooSmall;
decode_state.decodeLiteralsSlice(dest[written_count + bytes_written ..], len) catch
return error.MalformedCompressedBlock;
bytes_written += len;
}
switch (decode_state.literal_header.block_type) {
.treeless, .compressed => {
if (!decode_state.isLiteralStreamEmpty()) return error.MalformedCompressedBlock;
},
.raw, .rle => {},
}
consumed_count.* += block_size;
return bytes_written;
},
.reserved => return error.ReservedBlock,
}
}