Decompress a single block by index (for random access). Returns the decompressed bytes of just that block.
(data: &[u8], block_idx: usize)
| 123 | /// |
| 124 | /// Returns the decompressed bytes of just that block. |
| 125 | pub fn decode_block(data: &[u8], block_idx: usize) -> Result<Vec<u8>, CodecError> { |
| 126 | let header = read_header(data)?; |
| 127 | |
| 128 | if block_idx >= header.block_count { |
| 129 | return Err(CodecError::Corrupt { |
| 130 | detail: format!( |
| 131 | "block index {block_idx} out of range (block_count={})", |
| 132 | header.block_count |
| 133 | ), |
| 134 | }); |
| 135 | } |
| 136 | |
| 137 | // Sum lengths of preceding blocks to find this block's offset. |
| 138 | let mut block_offset = header.data_offset; |
| 139 | for i in 0..block_idx { |
| 140 | block_offset += header.block_lengths[i]; |
| 141 | } |
| 142 | |
| 143 | let compressed_len = header.block_lengths[block_idx]; |
| 144 | let block_end = block_offset + compressed_len; |
| 145 | |
| 146 | if block_end > data.len() { |
| 147 | return Err(CodecError::Truncated { |
| 148 | expected: block_end, |
| 149 | actual: data.len(), |
| 150 | }); |
| 151 | } |
| 152 | |
| 153 | let block_data = &data[block_offset..block_end]; |
| 154 | lz4_flex::decompress_size_prepended(block_data).map_err(|e| CodecError::DecompressFailed { |
| 155 | detail: format!("LZ4 block {block_idx}: {e}"), |
| 156 | }) |
| 157 | } |
| 158 | |
| 159 | // --------------------------------------------------------------------------- |
| 160 | // Header parsing |