1#![warn(missing_docs)]
14
15use std::{
16 fs::File,
17 io::{self, BufReader, Cursor, ErrorKind, Read, Seek, SeekFrom},
18 path::Path,
19};
20
21use byteorder::{BigEndian, ReadBytesExt};
22use compression::CompressedRead;
23use read::{get_info, read_next_item};
24
25pub mod compression;
26pub mod extract;
27pub mod read;
28
29pub struct MarFileInfo {
31 offset_to_index: u32,
32 #[allow(dead_code)]
33 has_signature_block: bool,
34 #[allow(dead_code)]
35 num_signatures: u32,
36 #[allow(dead_code)]
37 has_additional_blocks: bool,
38 #[allow(dead_code)]
39 offset_additional_blocks: u32,
40 #[allow(dead_code)]
41 num_additional_blocks: u32,
42}
43
44pub struct MarItem {
46 offset: u32,
48 pub length: u32,
50 pub flags: u32,
52 pub name: String,
54}
55
56pub struct Mar<R> {
58 info: MarFileInfo,
59 buffer: R,
60}
61
62impl<R> Mar<R>
63where
64 R: Read + Seek,
65{
66 pub fn from_buffer(mut buffer: R) -> io::Result<Mar<R>> {
68 let info = get_info(&mut buffer)?;
69
70 Ok(Mar { info, buffer })
71 }
72}
73
74impl Mar<BufReader<File>> {
75 pub fn from_path<P: AsRef<Path>>(path: P) -> io::Result<Mar<BufReader<File>>> {
77 let buffer = BufReader::new(File::open(path)?);
78 Self::from_buffer(buffer)
79 }
80}
81
82impl<R> Mar<R>
83where
84 R: Read + Seek,
85{
86 pub fn read<'a>(&'a mut self, item: &MarItem) -> io::Result<CompressedRead<'a, R>> {
88 self.buffer.seek(SeekFrom::Start(item.offset as u64))?;
89 CompressedRead::new(&mut self.buffer, item.length as u64)
90 }
91
92 pub fn files(&mut self) -> io::Result<Files> {
94 self.buffer
95 .seek(SeekFrom::Start(self.info.offset_to_index as u64))?;
96
97 let size_of_index = self.buffer.read_u32::<BigEndian>()?;
99 let mut index = vec![0; size_of_index as usize];
100 self.buffer.read_exact(&mut index)?;
101
102 Ok(Files {
103 index: Cursor::new(index),
104 })
105 }
106}
107
108pub struct Files {
110 index: Cursor<Vec<u8>>,
111}
112
113impl Iterator for Files {
114 type Item = io::Result<MarItem>;
115
116 fn next(&mut self) -> Option<Self::Item> {
117 match read_next_item(&mut self.index) {
118 Ok(item) => Some(Ok(item)),
119 Err(e) => {
120 if e.kind() == ErrorKind::UnexpectedEof {
121 None
122 } else {
123 Some(Err(e))
124 }
125 }
126 }
127 }
128}