add header detector
This commit is contained in:
@ -14,8 +14,12 @@ use thiserror::Error as TeError;
|
|||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("IO error {0}")]
|
#[error("IO error {0}")]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
#[error("fail to cast value into integral value. this usually caused by some value out of range")]
|
#[error(
|
||||||
|
"fail to cast value into integral value. this usually caused by some value out of range"
|
||||||
|
)]
|
||||||
CastToInt(#[from] std::num::TryFromIntError),
|
CastToInt(#[from] std::num::TryFromIntError),
|
||||||
|
#[error("something was overflow")]
|
||||||
|
Overflow,
|
||||||
#[error("wrong endian integer {0:#X} in block head. it must be one of 0x4 or 0x4000000")]
|
#[error("wrong endian integer {0:#X} in block head. it must be one of 0x4 or 0x4000000")]
|
||||||
WrongEndianInt(u32),
|
WrongEndianInt(u32),
|
||||||
#[error("wrong block head value {0:#X}. it must be 0x4")]
|
#[error("wrong block head value {0:#X}. it must be 0x4")]
|
||||||
@ -61,7 +65,7 @@ impl HspiceBlock {
|
|||||||
block_len,
|
block_len,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn absolute_offset(&self, relative_offset: u32) -> u64 {
|
pub fn compute_offset(&self, relative_offset: u32) -> u64 {
|
||||||
if relative_offset >= self.block_len {
|
if relative_offset >= self.block_len {
|
||||||
panic!("relative offset is out of range")
|
panic!("relative offset is out of range")
|
||||||
} else {
|
} else {
|
||||||
@ -156,7 +160,7 @@ where
|
|||||||
T: Read + Seek,
|
T: Read + Seek,
|
||||||
{
|
{
|
||||||
fn read(&mut self, mut buf: &mut [u8]) -> std::io::Result<usize> {
|
fn read(&mut self, mut buf: &mut [u8]) -> std::io::Result<usize> {
|
||||||
use std::io::{Result, Error, ErrorKind};
|
use std::io::{Error, ErrorKind, Result};
|
||||||
|
|
||||||
let old_block_cursor = self.block_cursor;
|
let old_block_cursor = self.block_cursor;
|
||||||
let old_cursor = self.cursor;
|
let old_cursor = self.cursor;
|
||||||
@ -169,7 +173,10 @@ where
|
|||||||
}
|
}
|
||||||
// Check whether we reach the tail of block chain.
|
// Check whether we reach the tail of block chain.
|
||||||
if self.block_cursor >= self.blocks.len() {
|
if self.block_cursor >= self.blocks.len() {
|
||||||
break Err(Error::new(ErrorKind::UnexpectedEof, "reach the tail of blocks"));
|
break Err(Error::new(
|
||||||
|
ErrorKind::UnexpectedEof,
|
||||||
|
"reach the tail of blocks",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
// Check whether we need to switch to next block.
|
// Check whether we need to switch to next block.
|
||||||
if self.cursor >= self.blocks[self.block_cursor].block_len {
|
if self.cursor >= self.blocks[self.block_cursor].block_len {
|
||||||
@ -182,7 +189,7 @@ where
|
|||||||
let remain = self.blocks[self.block_cursor].block_len - self.cursor;
|
let remain = self.blocks[self.block_cursor].block_len - self.cursor;
|
||||||
let read_count = std::cmp::min(usize::try_from(remain).unwrap(), buf.len());
|
let read_count = std::cmp::min(usize::try_from(remain).unwrap(), buf.len());
|
||||||
// Read data
|
// Read data
|
||||||
let offset = self.blocks[self.block_cursor].absolute_offset(self.cursor);
|
let offset = self.blocks[self.block_cursor].compute_offset(self.cursor);
|
||||||
if let Err(e) = self.reader.seek(SeekFrom::Start(offset)) {
|
if let Err(e) = self.reader.seek(SeekFrom::Start(offset)) {
|
||||||
break Err(e);
|
break Err(e);
|
||||||
}
|
}
|
||||||
@ -217,34 +224,34 @@ where
|
|||||||
let reader_cursor = match pos {
|
let reader_cursor = match pos {
|
||||||
SeekFrom::Start(v) => {
|
SeekFrom::Start(v) => {
|
||||||
if v > self.total_len {
|
if v > self.total_len {
|
||||||
return Err(err_instance)
|
return Err(err_instance);
|
||||||
} else {
|
} else {
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
SeekFrom::End(v) => {
|
SeekFrom::End(v) => {
|
||||||
if v > 0 {
|
if v > 0 {
|
||||||
return Err(err_instance)
|
return Err(err_instance);
|
||||||
} else {
|
} else {
|
||||||
match self.total_len.checked_add_signed(v) {
|
match self.total_len.checked_add_signed(v) {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => return Err(err_instance),
|
None => return Err(err_instance),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
SeekFrom::Current(v) => {
|
SeekFrom::Current(v) => {
|
||||||
let current = self.offset_table[self.block_cursor] + u64::from(self.cursor);
|
let current = self.offset_table[self.block_cursor] + u64::from(self.cursor);
|
||||||
match current.checked_add_signed(v) {
|
match current.checked_add_signed(v) {
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
if v > self.total_len {
|
if v > self.total_len {
|
||||||
return Err(err_instance)
|
return Err(err_instance);
|
||||||
} else {
|
} else {
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
None => return Err(err_instance),
|
None => return Err(err_instance),
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let block_cursor = match self.offset_table.binary_search(&reader_cursor) {
|
let block_cursor = match self.offset_table.binary_search(&reader_cursor) {
|
||||||
@ -355,13 +362,34 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Analyze header block count
|
// Analyze header block count
|
||||||
// for block in &blocks {
|
let mut header_blk_cnt: Option<usize> = None;
|
||||||
// let relative_offset = block.block_len.sa
|
for (i, block) in blocks.iter().enumerate() {
|
||||||
// let offset = block.absolute_offset(block.block_len - (SIGNAL_NAME_LEN as u32));
|
let signal_name_len = u32::try_from(SIGNAL_NAME_LEN).unwrap();
|
||||||
// }
|
let offset = if block.block_len < signal_name_len {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
block.compute_offset(block.block_len - signal_name_len)
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.seek(SeekFrom::Start(offset))?;
|
||||||
|
let mut magic_word = [0u8; MAGIC_WORDS.len()];
|
||||||
|
reader.read_exact(&mut magic_word)?;
|
||||||
|
if &magic_word == MAGIC_WORDS {
|
||||||
|
match i.checked_add(1) {
|
||||||
|
Some(v) => header_blk_cnt = Some(v),
|
||||||
|
None => return Err(Error::Overflow),
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let header_blk_cnt = match header_blk_cnt {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return Err(Error::NoMagicWords),
|
||||||
|
};
|
||||||
|
|
||||||
// Build result and return.
|
// Build result and return.
|
||||||
Ok(HspiceBlocks::new(sim_source, blocks, 0))
|
Ok(HspiceBlocks::new(sim_source, blocks, header_blk_cnt))
|
||||||
}
|
}
|
||||||
|
|
||||||
const SIGNAL_NAME_LEN: usize = 8;
|
const SIGNAL_NAME_LEN: usize = 8;
|
||||||
|
const MAGIC_WORDS: &[u8; 4] = b"$&%#";
|
||||||
|
Reference in New Issue
Block a user