1use crate::io::*;
7use crate::types::*;
8use std::io::{BufRead, Read, Seek, SeekFrom, Write};
9
10pub struct FstReader<R: BufRead + Seek> {
12 input: InputVariant<R>,
13 meta: MetaData,
14}
15
16enum InputVariant<R: BufRead + Seek> {
17 Original(R),
18 UncompressedInMem(std::io::Cursor<Vec<u8>>),
20}
21
22pub struct FstFilter {
26 pub start: u64,
27 pub end: Option<u64>,
28 pub include: Option<Vec<FstSignalHandle>>,
29}
30
31impl FstFilter {
32 pub fn all() -> Self {
33 FstFilter {
34 start: 0,
35 end: None,
36 include: None,
37 }
38 }
39
40 pub fn new(start: u64, end: u64, signals: Vec<FstSignalHandle>) -> Self {
41 FstFilter {
42 start,
43 end: Some(end),
44 include: Some(signals),
45 }
46 }
47
48 pub fn filter_time(start: u64, end: u64) -> Self {
49 FstFilter {
50 start,
51 end: Some(end),
52 include: None,
53 }
54 }
55
56 pub fn filter_signals(signals: Vec<FstSignalHandle>) -> Self {
57 FstFilter {
58 start: 0,
59 end: None,
60 include: Some(signals),
61 }
62 }
63}
64
65#[derive(Debug, Clone, PartialEq)]
66pub struct FstHeader {
67 pub start_time: u64,
69 pub end_time: u64,
71 pub var_count: u64,
73 pub max_handle: u64,
75 pub version: String,
77 pub date: String,
79 pub timescale_exponent: i8,
81}
82
83impl<R: BufRead + Seek> FstReader<R> {
84 pub fn open(input: R) -> Result<Self> {
86 Self::open_internal(input, false)
87 }
88
89 pub fn open_and_read_time_table(input: R) -> Result<Self> {
90 Self::open_internal(input, true)
91 }
92
93 fn open_internal(mut input: R, read_time_table: bool) -> Result<Self> {
94 let uncompressed_input = uncompress_gzip_wrapper(&mut input)?;
95 match uncompressed_input {
96 UncompressGzipWrapper::None => {
97 let mut header_reader = HeaderReader::new(input);
98 header_reader.read(read_time_table)?;
99 let (input, meta) = header_reader.into_input_and_meta_data().unwrap();
100 Ok(FstReader {
101 input: InputVariant::Original(input),
102 meta,
103 })
104 }
105 UncompressGzipWrapper::InMemory(uc) => {
106 let mut header_reader = HeaderReader::new(uc);
107 header_reader.read(read_time_table)?;
108 let (uc2, meta) = header_reader.into_input_and_meta_data().unwrap();
109 Ok(FstReader {
110 input: InputVariant::UncompressedInMem(uc2),
111 meta,
112 })
113 }
114 }
115 }
116
117 pub fn get_header(&self) -> FstHeader {
118 FstHeader {
119 start_time: self.meta.header.start_time,
120 end_time: self.meta.header.end_time,
121 var_count: self.meta.header.var_count,
122 max_handle: self.meta.header.max_var_id_code,
123 version: self.meta.header.version.clone(),
124 date: self.meta.header.date.clone(),
125 timescale_exponent: self.meta.header.timescale_exponent,
126 }
127 }
128
129 pub fn get_time_table(&self) -> Option<&[u64]> {
130 match &self.meta.time_table {
131 Some(table) => Some(table),
132 None => None,
133 }
134 }
135
136 pub fn read_hierarchy(&mut self, callback: impl FnMut(FstHierarchyEntry)) -> Result<()> {
138 match &mut self.input {
139 InputVariant::Original(input) => read_hierarchy(input, &self.meta, callback),
140 InputVariant::UncompressedInMem(input) => read_hierarchy(input, &self.meta, callback),
141 }
142 }
143
144 pub fn read_signals(
146 &mut self,
147 filter: &FstFilter,
148 callback: impl FnMut(u64, FstSignalHandle, FstSignalValue),
149 ) -> Result<()> {
150 let signal_count = self.meta.signals.len();
152 let signal_mask = if let Some(signals) = &filter.include {
153 let mut signal_mask = BitMask::repeat(false, signal_count);
154 for sig in signals {
155 let signal_idx = sig.get_index();
156 signal_mask.set(signal_idx, true);
157 }
158 signal_mask
159 } else {
160 BitMask::repeat(true, signal_count)
162 };
163 let data_filter = DataFilter {
164 start: filter.start,
165 end: filter.end.unwrap_or(self.meta.header.end_time),
166 signals: signal_mask,
167 };
168
169 match &mut self.input {
171 InputVariant::Original(input) => {
172 read_signals(input, &self.meta, &data_filter, callback)
173 }
174 InputVariant::UncompressedInMem(input) => {
175 read_signals(input, &self.meta, &data_filter, callback)
176 }
177 }
178 }
179}
180
181pub enum FstSignalValue<'a> {
182 String(&'a [u8]),
183 Real(f64),
184}
185
186pub fn is_fst_file(input: &mut (impl Read + Seek)) -> bool {
188 let is_fst = matches!(internal_check_fst_file(input), Ok(true));
189 let _ = input.seek(SeekFrom::Start(0));
191 is_fst
192}
193
194fn internal_check_fst_file(input: &mut (impl Read + Seek)) -> Result<bool> {
196 let mut seen_header = false;
197
198 loop {
200 let block_tpe = match read_block_tpe(input) {
201 Err(ReaderError::Io(_)) => {
202 break;
203 }
204 Err(other) => return Err(other),
205 Ok(tpe) => tpe,
206 };
207 let section_length = read_u64(input)?;
208 match block_tpe {
209 BlockType::GZipWrapper => return Ok(true),
210 BlockType::Header => {
211 seen_header = true;
212 }
213 BlockType::Skip if section_length == 0 => {
214 break;
215 }
216 _ => {}
217 }
218 input.seek(SeekFrom::Current((section_length as i64) - 8))?;
219 }
220 Ok(seen_header)
221}
222
223fn read_hierarchy(
224 input: &mut (impl Read + Seek),
225 meta: &MetaData,
226 mut callback: impl FnMut(FstHierarchyEntry),
227) -> Result<()> {
228 input.seek(SeekFrom::Start(meta.hierarchy_offset))?;
229 let bytes = read_hierarchy_bytes(input, meta.hierarchy_compression)?;
230 let mut input = bytes.as_slice();
231 let mut handle_count = 0u32;
232 while let Some(entry) = read_hierarchy_entry(&mut input, &mut handle_count)? {
233 callback(entry);
234 }
235 Ok(())
236}
237
238fn read_signals(
239 input: &mut (impl Read + Seek),
240 meta: &MetaData,
241 filter: &DataFilter,
242 mut callback: impl FnMut(u64, FstSignalHandle, FstSignalValue),
243) -> Result<()> {
244 let mut reader = DataReader {
245 input,
246 meta,
247 filter,
248 callback: &mut callback,
249 };
250 reader.read()
251}
252
253enum UncompressGzipWrapper {
254 None,
255 InMemory(std::io::Cursor<Vec<u8>>),
257}
258
259fn uncompress_gzip_wrapper(input: &mut (impl Read + Seek)) -> Result<UncompressGzipWrapper> {
262 let block_tpe = read_block_tpe(input)?;
263 if block_tpe != BlockType::GZipWrapper {
264 input.seek(SeekFrom::Start(0))?;
266 Ok(UncompressGzipWrapper::None)
267 } else {
268 let section_length = read_u64(input)?;
270 let uncompress_length = read_u64(input)? as usize;
271 if section_length == 0 {
272 return Err(ReaderError::NotFinishedCompressing());
273 }
274
275 let mut target = vec![];
278 decompress_gz_in_chunks(input, uncompress_length, &mut target)?;
279 let new_input = std::io::Cursor::new(target);
280 Ok(UncompressGzipWrapper::InMemory(new_input))
281 }
282}
283
284fn decompress_gz_in_chunks(
285 input: &mut (impl Read + Seek),
286 mut remaining: usize,
287 target: &mut impl Write,
288) -> Result<()> {
289 read_gzip_header(input)?;
290 let mut buf_in = vec![0u8; 32768 / 2]; let mut buf_out = vec![0u8; 32768 * 2]; let mut state = miniz_oxide::inflate::stream::InflateState::new(miniz_oxide::DataFormat::Raw);
294 let mut buf_in_remaining = 0;
295 while remaining > 0 {
296 buf_in_remaining += input.read(&mut buf_in[buf_in_remaining..])?;
298 debug_assert!(
299 buf_in_remaining > 0,
300 "ran out of input data while gzip decompressing"
301 );
302
303 let res = miniz_oxide::inflate::stream::inflate(
305 &mut state,
306 &buf_in[0..buf_in_remaining],
307 buf_out.as_mut_slice(),
308 miniz_oxide::MZFlush::None,
309 );
310
311 println!("{res:?}\nremaining={remaining}");
312
313 match res.status {
314 Ok(status) => {
315 buf_in.copy_within(res.bytes_consumed..buf_in_remaining, 0);
317 buf_in_remaining -= res.bytes_consumed;
318
319 let out_bytes = std::cmp::min(res.bytes_written, remaining);
321 remaining -= out_bytes;
322 target.write_all(&buf_out[..out_bytes])?;
323
324 match status {
325 miniz_oxide::MZStatus::Ok => {
326 }
328 miniz_oxide::MZStatus::StreamEnd => {
329 debug_assert_eq!(remaining, 0);
330 return Ok(());
331 }
332 miniz_oxide::MZStatus::NeedDict => {
333 todo!("hande NeedDict status");
334 }
335 }
336 }
337 Err(err) => {
338 return Err(ReaderError::GZipBody(format!("{err:?}")));
339 }
340 }
341 }
342
343 Ok(())
344}
345
346#[derive(Debug)]
347struct MetaData {
348 header: Header,
349 signals: Vec<SignalInfo>,
350 #[allow(dead_code)]
351 blackouts: Vec<BlackoutData>,
352 data_sections: Vec<DataSectionInfo>,
353 float_endian: FloatingPointEndian,
354 hierarchy_compression: HierarchyCompression,
355 hierarchy_offset: u64,
356 time_table: Option<Vec<u64>>,
357}
358
359pub type Result<T> = std::result::Result<T, ReaderError>;
360
361struct HeaderReader<R: Read + Seek> {
362 input: R,
363 header: Option<Header>,
364 signals: Option<Vec<SignalInfo>>,
365 blackouts: Option<Vec<BlackoutData>>,
366 data_sections: Vec<DataSectionInfo>,
367 float_endian: FloatingPointEndian,
368 hierarchy: Option<(HierarchyCompression, u64)>,
369 time_table: Option<Vec<u64>>,
370}
371
372impl<R: Read + Seek> HeaderReader<R> {
373 fn new(input: R) -> Self {
374 HeaderReader {
375 input,
376 header: None,
377 signals: None,
378 blackouts: None,
379 data_sections: Vec::default(),
380 float_endian: FloatingPointEndian::Little,
381 hierarchy: None,
382 time_table: None,
383 }
384 }
385
386 fn read_data(&mut self, tpe: &BlockType) -> Result<()> {
387 let file_offset = self.input.stream_position()?;
388 let section_length = read_u64(&mut self.input)?;
390 let start_time = read_u64(&mut self.input)?;
391 let end_time = read_u64(&mut self.input)?;
392 let mem_required_for_traversal = read_u64(&mut self.input)?;
393
394 if let Some(table) = &mut self.time_table {
396 let (_, mut time_chain) =
397 read_time_table(&mut self.input, file_offset, section_length)?;
398 let is_first_section = table.is_empty();
400 if is_first_section && time_chain[0] > start_time {
401 table.push(start_time);
402 }
403 table.append(&mut time_chain);
404 self.input.seek(SeekFrom::Start(file_offset + 4 * 8))?;
405 }
406 self.skip(section_length, 4 * 8)?;
408 let kind = DataSectionKind::from_block_type(tpe).unwrap();
409 let info = DataSectionInfo {
410 file_offset,
411 start_time,
412 end_time,
413 kind,
414 mem_required_for_traversal,
415 };
416 self.data_sections.push(info);
417 Ok(())
418 }
419
420 fn skip(&mut self, section_length: u64, already_read: i64) -> Result<u64> {
421 Ok(self
422 .input
423 .seek(SeekFrom::Current((section_length as i64) - already_read))?)
424 }
425
426 fn read_hierarchy(&mut self, compression: HierarchyCompression) -> Result<()> {
427 let file_offset = self.input.stream_position()?;
428 let section_length = read_u64(&mut self.input)?;
430 self.skip(section_length, 8)?;
431 assert!(
432 self.hierarchy.is_none(),
433 "Only a single hierarchy block is expected!"
434 );
435 self.hierarchy = Some((compression, file_offset));
436 Ok(())
437 }
438
439 fn read(&mut self, read_time_table: bool) -> Result<()> {
440 if read_time_table {
441 self.time_table = Some(Vec::new());
442 }
443 loop {
444 let block_tpe = match read_block_tpe(&mut self.input) {
445 Err(ReaderError::Io(_)) => {
446 break;
447 }
448 Err(other) => return Err(other),
449 Ok(tpe) => tpe,
450 };
451
452 dbg!(&block_tpe);
453
454 match block_tpe {
455 BlockType::Header => {
456 let (header, endian) = read_header(&mut self.input)?;
457 self.header = Some(header);
458 self.float_endian = endian;
459 }
460 BlockType::VcData => self.read_data(&block_tpe)?,
461 BlockType::VcDataDynamicAlias => self.read_data(&block_tpe)?,
462 BlockType::VcDataDynamicAlias2 => self.read_data(&block_tpe)?,
463 BlockType::Blackout => {
464 self.blackouts = Some(read_blackout(&mut self.input)?);
465 }
466 BlockType::Geometry => {
467 self.signals = Some(read_geometry(&mut self.input)?);
468 }
469 BlockType::Hierarchy => self.read_hierarchy(HierarchyCompression::ZLib)?,
470 BlockType::HierarchyLZ4 => self.read_hierarchy(HierarchyCompression::Lz4)?,
471 BlockType::HierarchyLZ4Duo => self.read_hierarchy(HierarchyCompression::Lz4Duo)?,
472 BlockType::GZipWrapper => panic!("GZip Wrapper should have been handled earlier!"),
473 BlockType::Skip => {
474 let section_length = read_u64(&mut self.input)?;
475 if section_length == 0 {
476 break;
477 }
478 self.skip(section_length, 8)?;
479 }
480 };
481 }
482
483 if self.signals.is_none() {
484 return Err(ReaderError::MissingGeometry());
485 }
486
487 if self.hierarchy.is_none() {
488 return Err(ReaderError::MissingHierarchy());
489 }
490
491 Ok(())
492 }
493
494 fn into_input_and_meta_data(mut self) -> Result<(R, MetaData)> {
495 self.input.seek(SeekFrom::Start(0))?;
496 let meta = MetaData {
497 header: self.header.unwrap(),
498 signals: self.signals.unwrap(),
499 blackouts: self.blackouts.unwrap_or_default(),
500 data_sections: self.data_sections,
501 float_endian: self.float_endian,
502 hierarchy_compression: self.hierarchy.unwrap().0,
503 hierarchy_offset: self.hierarchy.unwrap().1,
504 time_table: self.time_table,
505 };
506 Ok((self.input, meta))
507 }
508}
509
510struct DataReader<'a, R: Read + Seek, F: FnMut(u64, FstSignalHandle, FstSignalValue)> {
511 input: &'a mut R,
512 meta: &'a MetaData,
513 filter: &'a DataFilter,
514 callback: &'a mut F,
515}
516
517impl<R: Read + Seek, F: FnMut(u64, FstSignalHandle, FstSignalValue)> DataReader<'_, R, F> {
518 fn read_value_changes(
519 &mut self,
520 section_kind: DataSectionKind,
521 section_start: u64,
522 section_length: u64,
523 time_section_length: u64,
524 time_table: &[u64],
525 ) -> Result<()> {
526 let (max_handle, _) = read_variant_u64(&mut self.input)?;
527 let vc_start = self.input.stream_position()?;
528 let packtpe = ValueChangePackType::from_u8(read_u8(&mut self.input)?);
529 let chain_len_offset = section_start + section_length - time_section_length - 8;
531 let signal_offsets = read_signal_locs(
532 &mut self.input,
533 chain_len_offset,
534 section_kind,
535 max_handle,
536 vc_start,
537 )?;
538
539 let mut mu: Vec<u8> = Vec::new();
541 let mut head_pointer = vec![0u32; max_handle as usize];
542 let mut length_remaining = vec![0u32; max_handle as usize];
543 let mut scatter_pointer = vec![0u32; max_handle as usize];
544 let mut tc_head = vec![0u32; std::cmp::max(1, time_table.len())];
545
546 for entry in signal_offsets.iter() {
547 if self.filter.signals.is_set(entry.signal_idx) {
549 self.input.seek(SeekFrom::Start(vc_start + entry.offset))?;
551 let mut bytes =
552 read_packed_signal_value_bytes(&mut self.input, entry.len, packtpe)?;
553
554 let len = self.meta.signals[entry.signal_idx].len();
556 let tdelta = if len == 1 {
557 read_one_bit_signal_time_delta(&bytes, 0)?
558 } else {
559 read_multi_bit_signal_time_delta(&bytes, 0)?
560 };
561
562 head_pointer[entry.signal_idx] = mu.len() as u32;
564 length_remaining[entry.signal_idx] = bytes.len() as u32;
565 mu.append(&mut bytes);
566
567 scatter_pointer[entry.signal_idx] = tc_head[tdelta];
569 tc_head[tdelta] = entry.signal_idx as u32 + 1; }
571 }
572
573 let mut buffer = Vec::new();
574
575 for (time_id, time) in time_table.iter().enumerate() {
576 if *time > self.filter.end {
580 break;
581 }
582
583 let eof_error = || {
584 ReaderError::Io(std::io::Error::new(
585 std::io::ErrorKind::UnexpectedEof,
586 "unexpected eof",
587 ))
588 };
589
590 while tc_head[time_id] != 0 {
592 let signal_id = (tc_head[time_id] - 1) as usize; let mut mu_slice = &mu.as_slice()[head_pointer[signal_id] as usize..];
594 let (vli, skiplen) = read_variant_u32(&mut mu_slice)?;
595 let signal_len = self.meta.signals[signal_id].len();
596 let signal_handle = FstSignalHandle::from_index(signal_id);
597 let len = match signal_len {
598 1 => {
599 let value = one_bit_signal_value_to_char(vli);
600 let value_buf = [value];
601 (self.callback)(*time, signal_handle, FstSignalValue::String(&value_buf));
602 0 }
604 0 => {
605 let (len, skiplen2) = read_variant_u32(&mut mu_slice)?;
606 let value = mu_slice.get(..len as usize).ok_or_else(eof_error)?;
607 (self.callback)(*time, signal_handle, FstSignalValue::String(value));
608 len + skiplen2
609 }
610 len => {
611 let signal_len = len as usize;
612 if !self.meta.signals[signal_id].is_real() {
613 let (value, len) = if (vli & 1) == 0 {
614 let read_len = signal_len.div_ceil(8);
616 let bytes = mu_slice.get(..read_len).ok_or_else(eof_error)?;
617 multi_bit_digital_signal_to_chars(bytes, signal_len, &mut buffer);
618 (buffer.as_slice(), read_len as u32)
619 } else {
620 let value = mu_slice.get(..signal_len).ok_or_else(eof_error)?;
621 (value, len)
622 };
623 (self.callback)(*time, signal_handle, FstSignalValue::String(value));
624 len
625 } else {
626 assert_eq!(vli & 1, 1, "TODO: implement support for rare packed case");
627 let value = read_f64(&mut mu_slice, self.meta.float_endian)?;
628 (self.callback)(*time, signal_handle, FstSignalValue::Real(value));
629 8
630 }
631 }
632 };
633
634 let total_skiplen = skiplen + len;
636 head_pointer[signal_id] += total_skiplen;
638 length_remaining[signal_id] -= total_skiplen;
639 tc_head[time_id] = scatter_pointer[signal_id];
641 scatter_pointer[signal_id] = 0;
643
644 if length_remaining[signal_id] > 0 {
646 let tdelta = if signal_len == 1 {
647 read_one_bit_signal_time_delta(&mu, head_pointer[signal_id])?
648 } else {
649 read_multi_bit_signal_time_delta(&mu, head_pointer[signal_id])?
650 };
651
652 scatter_pointer[signal_id] = tc_head[time_id + tdelta];
654 tc_head[time_id + tdelta] = (signal_id + 1) as u32; }
656 }
657 }
658
659 Ok(())
660 }
661
662 fn read(&mut self) -> Result<()> {
663 let sections = self.meta.data_sections.clone();
664 let relevant_sections = sections
666 .iter()
667 .filter(|s| self.filter.end >= s.start_time && s.end_time >= self.filter.start);
668 for (sec_num, section) in relevant_sections.enumerate() {
669 self.input.seek(SeekFrom::Start(section.file_offset))?;
671 let section_length = read_u64(&mut self.input)?;
672
673 let start_time = read_u64(&mut self.input)?;
675 let end_time = read_u64(&mut self.input)?;
676 assert_eq!(start_time, section.start_time);
677 assert_eq!(end_time, section.end_time);
678 let is_first_section = sec_num == 0;
679
680 let (time_section_length, time_table) =
682 read_time_table(&mut self.input, section.file_offset, section_length)?;
683
684 if is_first_section && (time_table.is_empty() || time_table[0] > start_time) {
687 read_frame(
688 &mut self.input,
689 section.file_offset,
690 section_length,
691 &self.meta.signals,
692 &self.filter.signals,
693 self.meta.float_endian,
694 start_time,
695 self.callback,
696 )?;
697 } else {
698 skip_frame(&mut self.input, section.file_offset)?;
699 }
700
701 self.read_value_changes(
702 section.kind,
703 section.file_offset,
704 section_length,
705 time_section_length,
706 &time_table,
707 )?;
708 }
709
710 Ok(())
711 }
712}