1use std::io;
2use std::io::{Read, Cursor};
3
4use crate::types;
5use crate::iff::Chunk;
6use crate::model::*;
7use crate::bytecast;
8use crate::hex::PrintHex;
9
10pub struct Reader<R: Read> {
11 reader: R,
12 pub little_endian: bool
13}
14
15impl<R: Read> Reader<R> {
16 pub fn new(reader: R, little_endian: bool) -> Self {
17 Reader { reader, little_endian }
18 }
19
20 pub fn read_u8(&mut self) -> Result<u8, io::Error> {
21 let mut v = [0u8; 1];
22 self.reader.read_exact(&mut v)?;
23 Ok(v[0])
24 }
25
26 pub fn read_u8_into(&mut self, buffer: &mut [u8]) -> Result<(), io::Error> {
27 self.reader.read_exact(buffer)?;
28 Ok(())
29 }
30
31 pub fn read_u32(&mut self) -> Result<u32, io::Error> {
32 let mut v = [0u8; 4];
33 self.reader.read_exact(&mut v)?;
34 Ok(match self.little_endian {
35 true => u32::from_le_bytes(v),
36 false => u32::from_be_bytes(v)
37 })
38 }
39
40 pub fn read_utf(&mut self, len: usize) -> Result<String, io::Error> {
41 let mut vec: Vec<u16> = vec![0; len / 2];
42 let mut arr = bytecast::u16_as_ne_mut_bytes(vec.as_mut_slice());
43 self.reader.read_exact(&mut arr)?;
44
45 match self.little_endian {
46 true => {
47 for v in vec.as_mut_slice() {
48 *v = u16::from_le(*v);
49 }
50 }
51 false => {
52 for v in vec.as_mut_slice() {
53 *v = u16::from_be(*v);
54 }
55 }
56 }
57 Ok(String::from_utf16_lossy(&vec))
58 }
59
60 pub fn read_utf_z(&mut self, len: usize) -> Result<String, io::Error> {
61 let str = self.read_utf(len)?;
62 Ok(str.split('\0').next().unwrap().to_string())
63 }
64
65 pub fn read_ascii_n(&mut self) -> Result<String, io::Error> {
66 let len = self.read_u8()? as usize;
67 let mut buffer = vec![0u8; len];
68 self.read_u8_into(&mut buffer)?;
69 let str = unsafe { String::from_utf8_unchecked(buffer) };
71 Ok(str)
72 }
73}
74
75fn reader_for_slice(slice: &[u8], little_endian: bool) -> Reader<Cursor<&[u8]>> {
76 Reader::new(Cursor::new(slice), little_endian)
77}
78
79pub struct Decoder {}
80
81impl Decoder {
82 pub fn read(data: &[u8]) -> Result<L6Patch, io::Error> {
83 let mut chunk = Chunk::from_data(data, None)?;
84
85 if chunk.has_envelope_type(types::FORM, types::L6PA) {
86 let mut patch: L6Patch = Default::default();
88 let little_endian = false;
89
90 for (type_id, chunk) in chunk.all_chunks() {
91 match type_id {
92 types::PATC => { patch.models = read_models(chunk)?; },
93 types::UNFO => { patch.meta = read_meta_tags(chunk)?; },
94 types::PINF => { patch.target_device = read_target_device(chunk, little_endian)?; },
95 _ => {}
96 }
97 }
98 return Ok(patch);
99 } else if chunk.has_envelope_type(types::FORM, types::SSLB) {
100 if chunk.all_chunks().is_empty() && data.len() > 12 {
104 chunk = Chunk::from_data_with_size(data, data.len() - 8, None).unwrap()
105 }
106
107 for (type_id, chunk) in chunk.all_chunks() {
108 match type_id {
109 types::LENT => { read_sslb_entry(chunk)?; },
110 _ => {}
112 }
113 }
114 return Err(io::Error::new(io::ErrorKind::InvalidInput, "ok"))
115 }
116
117 Err(io::Error::new(io::ErrorKind::InvalidInput, "cannot parse file"))
118 }
119}
120
121
122fn decode_date(str: &str) -> usize {
123 match str.parse::<usize>() {
124 Ok(v) => v * 1000,
125 Err(_) => 0
126 }
127}
128
129fn decode_value(data: &[u32;2]) -> Result<Value, io::Error> {
130 match data[0] {
131 0 => Ok(Value::Int(data[1])),
132 1 => {
133 let f: f32 = unsafe { std::mem::transmute_copy(&data[1]) };
134 Ok(Value::Float(f))
135 }
136 _ => Err(io::Error::new(
137 io::ErrorKind::InvalidData,
138 format!("Unsupported value type {:#x}", data[0]))
139 )
140 }
141}
142
143fn read_meta_tags(chunk: &Chunk) -> Result<MetaTags, io::Error> {
144 let mut tags: MetaTags = Default::default();
145 for (type_id, data) in chunk.data_chunks() {
146 let mut r = reader_for_slice(data, chunk.is_little_endian());
147 match type_id {
148 types::IAUT => tags.author = r.read_utf(data.len())?,
149 types::IGTR => tags.guitarist = r.read_utf(data.len())?,
150 types::IBND => tags.band = r.read_utf(data.len())?,
151 types::ISNG => tags.song = r.read_utf(data.len())?,
152 types::ISTL => tags.style = r.read_utf(data.len())?,
153 types::IPUS => tags.pickup_style = r.read_utf(data.len())?,
154 types::IPUP => tags.pickup_position = r.read_utf(data.len())?,
155 types::IDAT => tags.date = decode_date(&r.read_utf(data.len())?),
156 types::IAMP => tags.amp_name = r.read_utf(data.len())?,
157 types::IAPP => tags.creator_app = r.read_utf(data.len())?,
158 types::IAPV => tags.creator_app_version = r.read_utf(data.len())?,
159 types::ICMT => tags.comments = r.read_utf(data.len())?,
160 _ => {}
161 }
162 }
163
164 Ok(tags)
165}
166
167fn read_target_device(chunk: &Chunk, little_endian: bool) -> Result<TargetDevice, io::Error> {
168 let data = match chunk {
169 Chunk::Data { data, .. } => data,
170 _ => return Err(io::Error::new(io::ErrorKind::InvalidInput, "Data chunk expected"))
171 };
172
173 if data.len() != 76 { return Err(io::Error::new(io::ErrorKind::InvalidInput, "Incorrect chunk length")); }
174
175 let mut r = reader_for_slice(data, little_endian);
176 if r.read_u32()? != 1 {
177 return Err(io::Error::new(io::ErrorKind::InvalidInput, "Incorrect PINF version"))
178 }
179 let midi_id = r.read_u32()?;
180 let name = r.read_utf_z(32)?;
181 let version = r.read_u32()?;
182 Ok(TargetDevice { midi_id, name, version })
183}
184
185fn read_models(chunk: &Chunk) -> Result<Vec<Model>, io::Error> {
186 let chunks = match chunk {
187 Chunk::Envelope { ref chunks, .. } => chunks,
188 Chunk::Data { .. } => return Err(io::Error::new(io::ErrorKind::InvalidInput, "Container chunk expected"))
189 };
190
191 chunks.iter().map(|chunk| {
192 if chunk.has_envelope_type(types::LIST, types::MODL) {
193 read_model(chunk)
194 } else {
195 Err(io::Error::new(io::ErrorKind::InvalidInput, "Incorrect envelope type"))
196 }
197 }).collect()
198}
199
200
201fn read_model(chunk: &Chunk) -> Result<Model, io::Error> {
202 let mut model: Model = Default::default();
203 let mut params: Vec<ModelParam> = vec![];
204 let little_endian= chunk.is_little_endian();
205
206 for (type_id, chunk) in chunk.data_chunks() {
207 match type_id {
208 types::MINF => model = read_model_info(chunk, little_endian)?,
209 types::PARM => params.push(read_model_param(chunk, little_endian)?),
210 _ => {}
211 }
212 }
213 model.params.extend(params);
214
215 Ok(model)
216}
217
218fn read_model_info(data: &[u8], little_endian: bool) -> Result<Model, io::Error> {
219 let mut r = reader_for_slice(data, little_endian);
220 let mut model: Model = Default::default();
221
222 model.model_id = r.read_u32()?;
223 model.slot_id = r.read_u32()?;
224 model.ordinal = r.read_u8()?;
225 r.read_u8()?;
226 r.read_u8()?;
227 model.enabled = r.read_u8()? > 0;
228
229 Ok(model)
230}
231fn read_model_param(data: &[u8], little_endian: bool) -> Result<ModelParam, io::Error> {
232 let mut r = reader_for_slice(data, little_endian);
233 let mut param: ModelParam = Default::default();
234
235 param.param_id = r.read_u32()? & 0x00ffffff;
236 let data = [r.read_u32()?, r.read_u32()?];
237 param.value = decode_value(&data)?;
238
239 Ok(param)
240}
241
242fn read_sslb_entry(chunk: &Chunk) -> Result<(), io::Error> {
243 let little_endian = chunk.is_little_endian();
244 let data = match chunk {
245 Chunk::Data { data, .. } => data,
246 _ => return Err(io::Error::new(io::ErrorKind::InvalidInput, "Data chunk expected"))
247 };
248 if data.len() < 13 {
249 return Ok(());
251 }
252 let mut r = reader_for_slice(data, little_endian);
253 let mut header = [0u8; 13];
254 r.read_u8_into(&mut header)?;
255
256 let can_process = header[1] == 0x2a || (header[0..2] == [0x80, 0xff]);
258 let name = r.read_ascii_n()?;
259 if !can_process {
260 return Ok(());
262 }
263 r.read_u8()?; let n = r.read_u8()? - 55;
268 if n > 0 {
269 let mut bytes = vec![0u8; n as usize];
270 r.read_u8_into(&mut bytes)?;
271 }
272 let mut bytes = vec![0u8; 55];
273 r.read_u8_into(&mut bytes)?;
274
275 loop {
276 let id = r.read_u8()?;
277 match id {
278 0x02 => {
279 let str = r.read_ascii_n()?;
280 println!("comment: {}", str);
281 },
282 0x06 => {
283 let str = r.read_ascii_n()?;
284 println!("position: {}", str);
285 },
286 0x00 => {
287 let mut skip = vec![0u8; 2];
288 r.read_u8_into(&mut skip)?;
289 println!("end:");
290 skip.print_hex();
291 break;
292 }
293 _ => {
294 println!("unknown: {:#02x}", id);
295 break;
296 }
297 }
298 }
299
300 Ok(())
301}
302