diff --git a/loadsig/loadsig/src/hspice.rs b/loadsig/loadsig/src/hspice.rs index 592a504..f4b168d 100644 --- a/loadsig/loadsig/src/hspice.rs +++ b/loadsig/loadsig/src/hspice.rs @@ -14,8 +14,12 @@ use thiserror::Error as TeError; pub enum Error { #[error("IO error {0}")] 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), + #[error("something was overflow")] + Overflow, #[error("wrong endian integer {0:#X} in block head. it must be one of 0x4 or 0x4000000")] WrongEndianInt(u32), #[error("wrong block head value {0:#X}. it must be 0x4")] @@ -61,7 +65,7 @@ impl HspiceBlock { 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 { panic!("relative offset is out of range") } else { @@ -156,20 +160,23 @@ where T: Read + Seek, { fn read(&mut self, mut buf: &mut [u8]) -> std::io::Result { - use std::io::{Result, Error, ErrorKind}; + use std::io::{Error, ErrorKind, Result}; let old_block_cursor = self.block_cursor; let old_cursor = self.cursor; let mut total_read_count: usize = 0; - let rv: Result<()> = loop { + let rv: Result<()> = loop { // Check whether there is space to be filled in buffer. if buf.is_empty() { break Ok(()); } // Check whether we reach the tail of block chain. 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. 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 read_count = std::cmp::min(usize::try_from(remain).unwrap(), buf.len()); // 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)) { break Err(e); } @@ -217,34 +224,34 @@ where let reader_cursor = match pos { SeekFrom::Start(v) => { if v > self.total_len { - return Err(err_instance) + return Err(err_instance); } else { v } - }, + } SeekFrom::End(v) => { if v > 0 { - return Err(err_instance) + return Err(err_instance); } else { match self.total_len.checked_add_signed(v) { Some(v) => v, None => return Err(err_instance), } } - }, + } SeekFrom::Current(v) => { let current = self.offset_table[self.block_cursor] + u64::from(self.cursor); match current.checked_add_signed(v) { Some(v) => { if v > self.total_len { - return Err(err_instance) + return Err(err_instance); } else { v } - }, + } None => return Err(err_instance), } - }, + } }; let block_cursor = match self.offset_table.binary_search(&reader_cursor) { @@ -355,13 +362,34 @@ where } // Analyze header block count - // for block in &blocks { - // let relative_offset = block.block_len.sa - // let offset = block.absolute_offset(block.block_len - (SIGNAL_NAME_LEN as u32)); - // } + let mut header_blk_cnt: Option = None; + for (i, block) in blocks.iter().enumerate() { + 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. - Ok(HspiceBlocks::new(sim_source, blocks, 0)) + Ok(HspiceBlocks::new(sim_source, blocks, header_blk_cnt)) } const SIGNAL_NAME_LEN: usize = 8; +const MAGIC_WORDS: &[u8; 4] = b"$&%#";