Decode tile #`idx`. CRC is checked by the framing layer.
(&self, idx: usize)
| 248 | |
| 249 | /// Decode tile #`idx`. CRC is checked by the framing layer. |
| 250 | pub fn read_tile(&self, idx: usize) -> ArrayResult<TilePayload> { |
| 251 | let entry = self |
| 252 | .footer |
| 253 | .tiles |
| 254 | .get(idx) |
| 255 | .ok_or_else(|| ArrayError::SegmentCorruption { |
| 256 | detail: format!( |
| 257 | "tile index {idx} out of range (have {})", |
| 258 | self.footer.tiles.len() |
| 259 | ), |
| 260 | })?; |
| 261 | let off = entry.offset as usize; |
| 262 | let len = entry.length as usize; |
| 263 | let end = off |
| 264 | .checked_add(len) |
| 265 | .ok_or_else(|| ArrayError::SegmentCorruption { |
| 266 | detail: "tile entry offset+length overflows".into(), |
| 267 | })?; |
| 268 | if end > self.bytes.len() { |
| 269 | return Err(ArrayError::SegmentCorruption { |
| 270 | detail: format!( |
| 271 | "tile {idx} block out of bounds: off={off} len={len} \ |
| 272 | file_size={}", |
| 273 | self.bytes.len() |
| 274 | ), |
| 275 | }); |
| 276 | } |
| 277 | let (payload, _) = BlockFraming::decode(&self.bytes[off..end])?; |
| 278 | match entry.kind { |
| 279 | TileKind::Sparse => { |
| 280 | let t = read_sparse_tile(payload)?; |
| 281 | Ok(TilePayload::Sparse(t)) |
| 282 | } |
| 283 | TileKind::Dense => { |
| 284 | let t: DenseTile = |
| 285 | zerompk::from_msgpack(payload).map_err(|e| ArrayError::SegmentCorruption { |
| 286 | detail: format!("dense tile decode failed: {e}"), |
| 287 | })?; |
| 288 | Ok(TilePayload::Dense(t)) |
| 289 | } |
| 290 | } |
| 291 | } |
| 292 | } |
| 293 | |
| 294 | /// An owned segment reader that holds decrypted segment bytes. |