1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
use std::fs::{File, OpenOptions};
use std::io::{Result, SeekFrom, Error, ErrorKind, Seek, Read, Write};
#[cfg(test)]
use std::io::Cursor;
use std::path::Path;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
static UNDEF_RECORD: u32 = 0xFEFEFEFF;
static INDEX_SIZE: u32 = 12;
pub struct MulRecord {
pub data: Vec<u8>,
pub start: u32,
pub length: u32,
pub opt1: u16,
pub opt2: u16
}
pub struct MulReader<T: Read + Seek> {
idx_reader: T,
data_reader: T
}
impl MulReader<File> {
pub fn new(idx_path: &Path, mul_path: &Path) -> Result<MulReader<File>> {
let idx_reader = try!(File::open(idx_path));
let data_reader = try!(File::open(mul_path));
Ok(MulReader {
idx_reader: idx_reader,
data_reader: data_reader
})
}
}
impl<T: Read + Seek> MulReader<T> {
pub fn from_readables(idx_reader: T, data_reader: T) -> MulReader<T> {
MulReader {
idx_reader: idx_reader,
data_reader: data_reader
}
}
pub fn read(&mut self, index: u32) -> Result<MulRecord> {
try!(self.idx_reader.seek(SeekFrom::Start((index * INDEX_SIZE) as u64)));
let start = try!(self.idx_reader.read_u32::<LittleEndian>());
if start == UNDEF_RECORD || start == u32::max_value() {
Err(Error::new(ErrorKind::Other, format!("Trying to read out of bounds record {}, with a start of {}", index, start)))
} else {
let length = try!(self.idx_reader.read_u32::<LittleEndian>());
let mut data = vec![0; length as usize];
let opt1 = try!(self.idx_reader.read_u16::<LittleEndian>());
let opt2 = try!(self.idx_reader.read_u16::<LittleEndian>());
try!(self.data_reader.seek(SeekFrom::Start(start as u64)));
try!(self.data_reader.read_exact(data.as_mut_slice()));
Ok(MulRecord {
data: data,
start: start,
length: length,
opt1: opt1,
opt2: opt2
})
}
}
}
pub struct MulWriter<T: Write + Seek> {
idx_writer: T,
data_writer: T
}
pub enum MulWriterMode {
Append,
Truncate
}
impl MulWriter<File> {
pub fn new(idx_path: &Path, mul_path: &Path, mode: MulWriterMode) -> Result<MulWriter<File>> {
let mut options = OpenOptions::new();
let options = options.write(true).create(true).truncate(match mode { MulWriterMode::Append => false, MulWriterMode::Truncate => true});
let idx_writer = try!(options.open(idx_path));
let data_writer = try!(options.open(mul_path));
Ok(MulWriter {
idx_writer: idx_writer,
data_writer: data_writer
})
}
}
impl<T: Write + Seek> MulWriter<T> {
pub fn append(&mut self, data: &Vec<u8>, opt1: Option<u16>, opt2: Option<u16>) -> Result<()> {
try!(self.idx_writer.seek(SeekFrom::End(0)));
let mul_size = try!(self.data_writer.seek(SeekFrom::End(0)));
let start = mul_size as u32;
let length = data.len() as u32;
let opt1 = match opt1 { Some(value) => value, None => 0} as u16;
let opt2 = match opt2 { Some(value) => value, None => 0} as u16;
try!(self.data_writer.write(data.as_slice()));
try!(self.idx_writer.write_u32::<LittleEndian>(start));
try!(self.idx_writer.write_u32::<LittleEndian>(length));
try!(self.idx_writer.write_u16::<LittleEndian>(opt1));
try!(self.idx_writer.write_u16::<LittleEndian>(opt2));
Ok(())
}
}
#[cfg(test)]
pub fn simple_from_vecs(vectors: Vec<Vec<u8>>, opt1: u16, opt2: u16) -> MulReader<Cursor<Vec<u8>>> {
let mut idx_reader = Cursor::new(vec![]);
let mut mul_reader = Cursor::new(vec![]);
for vec in vectors {
let len = vec.len();
let mul_size = mul_reader.seek(SeekFrom::End(0)).unwrap();
let mut idx_cursor = Cursor::new(vec![]);
idx_cursor.write_u32::<LittleEndian>(mul_size as u32).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(idx_cursor.get_ref()).unwrap();
mul_reader.write(&vec).unwrap();
}
MulReader::from_readables(idx_reader, mul_reader)
}
#[cfg(test)]
pub fn simple_from_mul_records(records: Vec<MulRecord>) -> MulReader<Cursor<Vec<u8>>> {
let mut idx_reader = Cursor::new(vec![]);
let mut mul_reader = Cursor::new(vec![]);
for record in records {
let mul_size = mul_reader.seek(SeekFrom::End(0)).unwrap();
let mut idx_cursor = Cursor::new(vec![]);
idx_cursor.write_u32::<LittleEndian>(mul_size as u32).unwrap();
idx_cursor.write_u32::<LittleEndian>(record.data.len() as u32).unwrap();
idx_cursor.write_u16::<LittleEndian>(record.opt1).unwrap();
idx_cursor.write_u16::<LittleEndian>(record.opt2).unwrap();
idx_reader.write(idx_cursor.get_ref()).unwrap();
mul_reader.write(&record.data).unwrap();
}
MulReader::from_readables(idx_reader, mul_reader)
}