use crate::error::Result;
use crate::reader::Reader;
use crate::writer::Writer;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StreamHeader {
pub offset: u32,
pub size: u32,
pub name: String,
}
impl StreamHeader {
pub const TABLES: &'static str = "#~";
pub const TABLES_UNCOMPRESSED: &'static str = "#-";
pub const STRINGS: &'static str = "#Strings";
pub const USER_STRINGS: &'static str = "#US";
pub const GUID: &'static str = "#GUID";
pub const BLOB: &'static str = "#Blob";
pub fn parse(reader: &mut Reader<'_>) -> Result<Self> {
let offset = reader.read_u32()?;
let size = reader.read_u32()?;
let name_start = reader.position();
let name = reader.read_null_str()?.to_string();
let name_len_with_null = reader.position() - name_start;
let padding = (4 - (name_len_with_null % 4)) % 4;
if padding > 0 {
reader.read_bytes(padding)?;
}
Ok(Self { offset, size, name })
}
pub fn write(&self, writer: &mut Writer) {
writer.write_u32(self.offset);
writer.write_u32(self.size);
writer.write_null_str(&self.name);
let name_len_with_null = self.name.len() + 1;
let padding = (4 - (name_len_with_null % 4)) % 4;
for _ in 0..padding {
writer.write_u8(0);
}
}
#[must_use]
pub fn serialized_size(&self) -> usize {
let name_len_with_null = self.name.len() + 1;
let padding = (4 - (name_len_with_null % 4)) % 4;
8 + name_len_with_null + padding }
#[must_use]
pub fn is_tables(&self) -> bool {
self.name == Self::TABLES || self.name == Self::TABLES_UNCOMPRESSED
}
#[must_use]
pub fn is_strings(&self) -> bool {
self.name == Self::STRINGS
}
#[must_use]
pub fn is_user_strings(&self) -> bool {
self.name == Self::USER_STRINGS
}
#[must_use]
pub fn is_guid(&self) -> bool {
self.name == Self::GUID
}
#[must_use]
pub fn is_blob(&self) -> bool {
self.name == Self::BLOB
}
}
pub fn find_stream<'a>(streams: &'a [StreamHeader], name: &str) -> Option<&'a StreamHeader> {
streams.iter().find(|s| s.name == name)
}
pub fn find_tables_stream(streams: &[StreamHeader]) -> Option<&StreamHeader> {
streams.iter().find(|s| s.is_tables())
}