use crate::{
DbcHeader, DbcParser, DbcVersion, Error, Result, Schema, StringBlock,
versions::{Wdb2Header, Wdb5Header},
};
use memmap2::{Mmap, MmapOptions};
use std::fs::File;
use std::io::{Cursor, Seek, SeekFrom};
use std::path::Path;
pub struct MmapDbcFile {
mmap: Mmap,
version: DbcVersion,
header: DbcHeader,
}
impl MmapDbcFile {
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
let file = File::open(path)?;
let mmap = unsafe { MmapOptions::new().map(&file)? };
let mut cursor = Cursor::new(&mmap[..]);
let version = DbcVersion::detect(&mut cursor)?;
let header = match version {
DbcVersion::WDBC => DbcHeader::parse(&mut cursor)?,
DbcVersion::WDB2 => {
let wdb2_header = Wdb2Header::parse(&mut cursor)?;
wdb2_header.to_dbc_header()
}
DbcVersion::WDB5 => {
let wdb5_header = Wdb5Header::parse(&mut cursor)?;
wdb5_header.to_dbc_header()
}
_ => {
return Err(Error::InvalidHeader(format!(
"Unsupported DBC version: {version:?}"
)));
}
};
Ok(Self {
mmap,
version,
header,
})
}
pub fn as_slice(&self) -> &[u8] {
&self.mmap[..]
}
pub fn header(&self) -> &DbcHeader {
&self.header
}
pub fn version(&self) -> DbcVersion {
self.version
}
pub fn parser(&self) -> DbcParser {
DbcParser::parse_bytes(self.as_slice()).unwrap()
}
pub fn parser_with_schema(&self, schema: Schema) -> Result<DbcParser> {
self.parser().with_schema(schema)
}
pub fn string_block(&self) -> Result<StringBlock> {
let mut cursor = Cursor::new(self.as_slice());
cursor.seek(SeekFrom::Start(self.header.string_block_offset()))?;
StringBlock::parse(
&mut cursor,
self.header.string_block_offset(),
self.header.string_block_size,
)
}
}