1use std::fs::{File, OpenOptions};
10use std::io::{Read, Seek, SeekFrom, Write};
11use std::path::Path;
12
13use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
14
15use crate::error::{MulReaderError, MulReaderResult, MulWriterResult};
16
17const UNDEF_RECORD: u32 = 0xFEFEFEFF;
18const INDEX_SIZE: u32 = 12;
19
20#[derive(Debug, PartialEq, Eq, Clone)]
22pub struct MulRecord {
23 pub data: Vec<u8>,
25 pub start: u32,
27 pub length: u32,
29 pub opt1: u16,
31 pub opt2: u16,
33}
34
35#[derive(Debug)]
37pub struct MulReader<T: Read + Seek> {
38 idx_reader: T,
39 data_reader: T,
40}
41
42impl MulReader<File> {
43 pub fn new(idx_path: &Path, mul_path: &Path) -> MulReaderResult<MulReader<File>> {
45 let idx_reader = File::open(idx_path)?;
46 let data_reader = File::open(mul_path)?;
47
48 Ok(MulReader {
49 idx_reader,
50 data_reader,
51 })
52 }
53}
54
55impl<T: Read + Seek> MulReader<T> {
56 pub fn from_readables(idx_reader: T, data_reader: T) -> MulReader<T> {
58 MulReader {
59 idx_reader,
60 data_reader,
61 }
62 }
63
64 pub fn read(&mut self, index: u32) -> MulReaderResult<MulRecord> {
68 self.idx_reader
70 .seek(SeekFrom::Start((index * INDEX_SIZE) as u64))?;
71
72 let start = self.idx_reader.read_u32::<LittleEndian>()?;
73 if start == UNDEF_RECORD || start == u32::MAX {
75 return Err(MulReaderError::OffsetOutOfBounds {
76 index,
77 offset: start,
78 });
79 }
80
81 let length = self.idx_reader.read_u32::<LittleEndian>()?;
82 let mut data = vec![0; length as usize];
83 let opt1 = self.idx_reader.read_u16::<LittleEndian>()?;
84 let opt2 = self.idx_reader.read_u16::<LittleEndian>()?;
85
86 self.data_reader.seek(SeekFrom::Start(start as u64))?;
87 self.data_reader.read_exact(data.as_mut_slice())?;
88
89 Ok(MulRecord {
90 data,
91 start,
92 length,
93 opt1,
94 opt2,
95 })
96 }
97}
98
99#[derive(Debug)]
101pub struct MulWriter<T: Write + Seek> {
102 idx_writer: T,
103 data_writer: T,
104}
105
106pub enum MulWriterMode {
107 Append,
108 Truncate,
109}
110
111impl MulWriter<File> {
112 pub fn new(
114 idx_path: &Path,
115 mul_path: &Path,
116 mode: MulWriterMode,
117 ) -> MulWriterResult<MulWriter<File>> {
118 let mut options = OpenOptions::new();
119 let options = options.write(true).create(true).truncate(match mode {
120 MulWriterMode::Append => false,
121 MulWriterMode::Truncate => true,
122 });
123
124 let idx_writer = options.open(idx_path)?;
125 let data_writer = options.open(mul_path)?;
126
127 Ok(MulWriter {
128 idx_writer,
129 data_writer,
130 })
131 }
132}
133
134impl<T: Write + Seek> MulWriter<T> {
135 pub fn from_writables(idx_writer: T, data_writer: T) -> MulWriter<T> {
137 MulWriter {
138 idx_writer,
139 data_writer,
140 }
141 }
142 pub fn append(
144 &mut self,
145 data: &[u8],
146 opt1: Option<u16>,
147 opt2: Option<u16>,
148 ) -> MulWriterResult<()> {
149 self.idx_writer.seek(SeekFrom::End(0))?;
151 let mul_size = self.data_writer.seek(SeekFrom::End(0))?;
152
153 let start = mul_size as u32;
155 let length = data.len() as u32;
156 self.data_writer.write_all(data)?;
157 self.idx_writer.write_u32::<LittleEndian>(start)?;
158 self.idx_writer.write_u32::<LittleEndian>(length)?;
159 self.idx_writer
160 .write_u16::<LittleEndian>(opt1.unwrap_or_default())?;
161 self.idx_writer
162 .write_u16::<LittleEndian>(opt2.unwrap_or_default())?;
163
164 Ok(())
165 }
166}
167
168#[cfg(test)]
169pub mod tests {
170 use super::*;
171 use std::io::Cursor;
172
173 pub fn simple_from_vecs(vectors: Vec<(Vec<u8>, u16, u16)>) -> MulReader<Cursor<Vec<u8>>> {
174 let mut idx_reader = Cursor::new(vec![]);
175 let mut mul_reader = Cursor::new(vec![]);
176 for (vec, opt1, opt2) in vectors {
178 let len = vec.len();
179 let mul_size = mul_reader.seek(SeekFrom::End(0)).unwrap();
180 let mut idx_cursor = Cursor::new(vec![]);
181 idx_cursor
182 .write_u32::<LittleEndian>(mul_size as u32)
183 .unwrap(); idx_cursor.write_u32::<LittleEndian>(len as u32).unwrap(); idx_cursor.write_u16::<LittleEndian>(opt1).unwrap(); idx_cursor.write_u16::<LittleEndian>(opt2).unwrap(); idx_reader.write_all(idx_cursor.get_ref()).unwrap();
188 mul_reader.write_all(&vec).unwrap();
189 }
190 MulReader::from_readables(idx_reader, mul_reader)
191 }
192
193 pub fn simple_from_mul_records(records: Vec<MulRecord>) -> MulReader<Cursor<Vec<u8>>> {
194 let mut idx_reader = Cursor::new(vec![]);
195 let mut mul_reader = Cursor::new(vec![]);
196 for record in records {
198 let mul_size = mul_reader.seek(SeekFrom::End(0)).unwrap();
199 let mut idx_cursor = Cursor::new(vec![]);
200 idx_cursor
201 .write_u32::<LittleEndian>(mul_size as u32)
202 .unwrap(); idx_cursor
204 .write_u32::<LittleEndian>(record.data.len() as u32)
205 .unwrap(); idx_cursor.write_u16::<LittleEndian>(record.opt1).unwrap(); idx_cursor.write_u16::<LittleEndian>(record.opt2).unwrap(); idx_reader.write_all(idx_cursor.get_ref()).unwrap();
209 mul_reader.write_all(&record.data).unwrap();
210 }
211 MulReader::from_readables(idx_reader, mul_reader)
212 }
213}