| 355 | |
| 356 | impl BlobEntry { |
| 357 | fn build_all(lengths: &[i64], data_region_end: u64) -> crate::Result<Vec<Self>> { |
| 358 | let mut entries = Vec::with_capacity(lengths.len()); |
| 359 | let mut next_offset = 0_u64; |
| 360 | |
| 361 | for &entry_length in lengths { |
| 362 | if entry_length == -1 { |
| 363 | entries.push(Self { |
| 364 | data_offset: None, |
| 365 | data_length: 0, |
| 366 | }); |
| 367 | continue; |
| 368 | } |
| 369 | |
| 370 | let entry_length = u64::try_from(entry_length).map_err(|e| Error::DataInvalid { |
| 371 | message: format!("Blob entry length must be positive or -1, got {entry_length}"), |
| 372 | source: Some(Box::new(e)), |
| 373 | })?; |
| 374 | |
| 375 | if entry_length < BLOB_ENTRY_OVERHEAD { |
| 376 | return Err(Error::DataInvalid { |
| 377 | message: format!( |
| 378 | "Blob entry length {entry_length} is smaller than minimum overhead {BLOB_ENTRY_OVERHEAD}" |
| 379 | ), |
| 380 | source: None, |
| 381 | }); |
| 382 | } |
| 383 | |
| 384 | let entry_end = |
| 385 | next_offset |
| 386 | .checked_add(entry_length) |
| 387 | .ok_or_else(|| Error::DataInvalid { |
| 388 | message: format!("Blob entry length overflow at offset {next_offset}"), |
| 389 | source: None, |
| 390 | })?; |
| 391 | if entry_end > data_region_end { |
| 392 | return Err(Error::DataInvalid { |
| 393 | message: format!( |
| 394 | "Blob entry range [{next_offset}, {entry_end}) exceeds data region end {data_region_end}" |
| 395 | ), |
| 396 | source: None, |
| 397 | }); |
| 398 | } |
| 399 | |
| 400 | entries.push(Self { |
| 401 | data_offset: Some(next_offset + BLOB_INLINE_HEADER_SIZE), |
| 402 | data_length: entry_length - BLOB_ENTRY_OVERHEAD, |
| 403 | }); |
| 404 | next_offset = entry_end; |
| 405 | } |
| 406 | |
| 407 | Ok(entries) |
| 408 | } |
| 409 | |
| 410 | fn inline_data_range(&self) -> Option<Range<u64>> { |
| 411 | self.data_offset |