use std::io::Read;
use crate::BoxResult as Result;
use crate::blob::{BlobKind, MAX_BLOB_HEADER_SIZE, parse_blob_header_with_index};
use crate::blob_meta::BlobIndex;
use crate::file_reader::FileReader;
pub(crate) struct RawBlobFrame {
pub(crate) frame_bytes: Vec<u8>,
pub(crate) blob_type: BlobKind,
pub(crate) blob_offset: usize,
pub(crate) index: Option<BlobIndex>,
#[allow(dead_code)]
pub(crate) tagdata: Option<Box<[u8]>>,
#[allow(dead_code)]
pub(crate) file_offset: u64,
}
impl RawBlobFrame {
pub(crate) fn blob_bytes(&self) -> &[u8] {
&self.frame_bytes[self.blob_offset..]
}
pub(crate) fn header_bytes(&self) -> &[u8] {
&self.frame_bytes[4..self.blob_offset]
}
}
#[cfg_attr(feature = "hotpath", hotpath::measure)]
#[allow(clippy::cast_possible_truncation)]
pub(crate) fn read_raw_frame<R: Read>(
reader: &mut R,
file_offset: &mut u64,
) -> Result<Option<RawBlobFrame>> {
let frame_start = *file_offset;
let mut len_buf = [0u8; 4];
match reader.read_exact(&mut len_buf) {
Ok(()) => {}
Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => return Ok(None),
Err(e) => return Err(e.into()),
}
let header_len = u32::from_be_bytes(len_buf) as usize;
if header_len as u64 >= MAX_BLOB_HEADER_SIZE {
return Err(
crate::error::new_blob_error(crate::error::BlobError::HeaderTooBig {
size: header_len as u64,
})
.into(),
);
}
let mut header_bytes = vec![0u8; header_len];
reader.read_exact(&mut header_bytes)?;
let (blob_type, data_size, raw_index, tagdata) = parse_blob_header_with_index(&header_bytes)?;
let index = raw_index.and_then(|ref data| BlobIndex::deserialize(data));
let blob_offset = 4 + header_len;
let frame_len = blob_offset + data_size;
*file_offset += frame_len as u64;
let mut frame_bytes = vec![0u8; frame_len];
frame_bytes[..4].copy_from_slice(&len_buf);
frame_bytes[4..blob_offset].copy_from_slice(&header_bytes);
reader.read_exact(&mut frame_bytes[blob_offset..])?;
Ok(Some(RawBlobFrame {
frame_bytes,
blob_type,
blob_offset,
index,
tagdata,
file_offset: frame_start,
}))
}
pub(crate) struct BlobHeaderInfo {
pub blob_type: BlobKind,
pub data_size: usize,
pub index: Option<BlobIndex>,
pub has_tagdata: bool,
}
#[allow(clippy::cast_possible_truncation)]
pub(crate) fn read_blob_header_only(
reader: &mut FileReader,
file_offset: &mut u64,
) -> Result<Option<BlobHeaderInfo>> {
let mut len_buf = [0u8; 4];
match reader.read_exact(&mut len_buf) {
Ok(()) => {}
Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => return Ok(None),
Err(e) => return Err(e.into()),
}
let header_len = u32::from_be_bytes(len_buf) as usize;
if header_len as u64 >= MAX_BLOB_HEADER_SIZE {
return Err(
crate::error::new_blob_error(crate::error::BlobError::HeaderTooBig {
size: header_len as u64,
})
.into(),
);
}
let mut header_bytes = vec![0u8; header_len];
reader.read_exact(&mut header_bytes)?;
let (blob_type, data_size, raw_index, tagdata) = parse_blob_header_with_index(&header_bytes)?;
let index = raw_index.and_then(|ref data| BlobIndex::deserialize(data));
*file_offset += (4 + header_len) as u64;
Ok(Some(BlobHeaderInfo {
blob_type,
data_size,
index,
has_tagdata: tagdata.is_some(),
}))
}