1#![forbid(unsafe_code)]
17
18extern crate byteorder;
19
20pub mod chunks;
21mod enums;
22mod error;
23
24pub use enums::ChunkType;
25pub use enums::FormatType;
26pub use error::CafError;
27
28use chunks::CafChunk;
29use chunks::CafChunkHeader;
30
31use std::io::{Read, Seek, SeekFrom};
32use byteorder::{BigEndian as Be, ReadBytesExt};
33
34const CAF_HEADER_MAGIC :[u8; 8] = [0x63, 0x61, 0x66, 0x66, 0x00, 0x01, 0x00, 0x00];
36
37pub struct CafChunkReader<T> where T :Read {
38 rdr :T,
39}
40
41impl<T> CafChunkReader<T> where T :Read {
42 pub fn new(mut rdr :T) -> Result<Self, CafError> {
43 let mut hdr_buf = [0;8];
44 try!(rdr.read_exact(&mut hdr_buf));
45 if hdr_buf != CAF_HEADER_MAGIC {
46 return Err(CafError::NotCaf);
47 }
48 Ok(CafChunkReader { rdr : rdr })
49 }
50 pub fn into_inner(self) -> T {
52 self.rdr
53 }
54 pub fn read_chunk(&mut self) -> Result<CafChunk, CafError> {
72 let hdr = try!(self.read_chunk_header());
73 self.read_chunk_body(&hdr)
74 }
75 pub fn read_chunk_body(&mut self, hdr :&CafChunkHeader)
77 -> Result<CafChunk, CafError> {
78 if hdr.ch_size == -1 {
79 panic!("unspecified chunk size is not yet implemented");
82 }
83 let mut chunk_content = vec![0; hdr.ch_size as usize];
84 try!(self.rdr.read_exact(&mut chunk_content));
85 chunks::decode_chunk(hdr.ch_type, chunk_content)
86 }
87 pub fn read_chunk_header(&mut self) -> Result<CafChunkHeader, CafError> {
89 let chunk_type_u32 = try!(self.rdr.read_u32::<Be>());
90 let chunk_type = ChunkType::from(chunk_type_u32);
91 let chunk_size = try!(self.rdr.read_i64::<Be>());
93 Ok(CafChunkHeader {
94 ch_type : chunk_type,
95 ch_size : chunk_size,
96 })
97 }
98}
99
100impl<T> CafChunkReader<T> where T :Read + Seek {
101
102 pub fn to_next_chunk(&mut self, hdr :&CafChunkHeader) -> Result<(), CafError> {
118 if hdr.ch_size == -1 {
119 panic!("can't seek to end of chunk with unspecified chunk size.");
121 }
122 try!(self.rdr.seek(SeekFrom::Current(hdr.ch_size)));
123 Ok(())
124 }
125 pub fn to_previous_chunk(&mut self, hdr :&CafChunkHeader) -> Result<(), CafError> {
136 if hdr.ch_size == -1 {
137 panic!("can't seek to end of chunk with unspecified chunk size.");
139 }
140 try!(self.rdr.seek(SeekFrom::Current(-hdr.ch_size)));
141 Ok(())
142 }
143
144 pub fn read_chunks_to_mem(&mut self,
159 mut required :Vec<ChunkType>, content_read :&[ChunkType])
160 -> Result<(Vec<CafChunk>, Vec<CafChunkHeader>), CafError> {
161 let mut res = Vec::with_capacity(content_read.len());
162 let mut read_headers = Vec::new();
163 loop {
164 let hdr = try!(self.read_chunk_header());
165 let mut required_idx = None;
166 let mut content_read_found = false;
167 for (i, &searched_type) in required.iter().enumerate() {
168 if searched_type == hdr.ch_type {
169 required_idx = Some(i);
170 break;
171 }
172 }
173 for &searched_type in content_read.iter() {
174 if searched_type == hdr.ch_type {
175 content_read_found = true;
176 break;
177 }
178 }
179 if hdr.ch_size == -1 {
180 }
190
191 match required_idx { None => (), Some(i) => { required.remove(i); } }
192 if content_read_found {
193 res.push(try!(self.read_chunk_body(&hdr)));
194 } else {
195 try!(self.to_next_chunk(&hdr));
196 }
197 read_headers.push(hdr.clone());
198 if required.len() == 0 {
199 break;
200 }
201 }
202 Ok((res, read_headers))
203 }
204}
205
206pub struct CafPacketReader<T> where T :Read + Seek {
212 ch_rdr :CafChunkReader<T>,
213 pub audio_desc :chunks::AudioDescription,
214 pub packet_table :Option<chunks::PacketTable>,
215 pub chunks :Vec<CafChunk>,
216 pub edit_count :u32,
218 audio_chunk_len :i64,
219 audio_chunk_offs :i64,
220 packet_idx :usize,
221}
222
223impl<T> CafPacketReader<T> where T :Read + Seek {
224 pub fn new(rdr :T, filter_by :Vec<ChunkType>) -> Result<Self, CafError> {
237 let ch_rdr = try!(CafChunkReader::new(rdr));
238 return CafPacketReader::from_chunk_reader(ch_rdr, filter_by);
239 }
240
241 pub fn from_chunk_reader(mut ch_rdr :CafChunkReader<T>,
251 mut filter_by :Vec<ChunkType>) -> Result<Self, CafError> {
252
253 filter_by.push(ChunkType::AudioDescription);
255 let mut content_read = filter_by.clone();
256 content_read.push(ChunkType::PacketTable);
257 let (mut chunks_in_mem, mut read_headers) =
258 try!(ch_rdr.read_chunks_to_mem(filter_by, &content_read));
259
260 let mut audio_desc_idx = None;
262 let mut packet_table_idx = None;
263 for (idx, ch) in chunks_in_mem.iter().enumerate() {
264 use ChunkType::*;
265 match ch.get_type() {
267 AudioDescription => (audio_desc_idx = Some(idx)),
268 PacketTable => (packet_table_idx = Some(idx)),
269 _ => (),
270 }
271 }
272 macro_rules! remove_and_unwrap {
273 ($idx:expr, $id:ident) => {
274 match chunks_in_mem.remove($idx) {
275 CafChunk::$id(v) => v,
276 _ => panic!(),
277 }
278 }
279 }
280 let audio_desc = remove_and_unwrap!(audio_desc_idx.unwrap(), Desc);
281 let p_table_required = audio_desc.bytes_per_packet == 0 ||
282 audio_desc.frames_per_packet == 0;
283 let packet_table = match packet_table_idx {
284 Some(i) => Some(remove_and_unwrap!(i, PacketTable)),
285 None if p_table_required => {
286 let (chunks, hdrs) = try!(ch_rdr.read_chunks_to_mem(
287 vec![ChunkType::PacketTable],
288 &content_read));
289 chunks_in_mem.extend_from_slice(&chunks);
290 read_headers.extend_from_slice(&hdrs);
291 for (idx, ch) in chunks_in_mem.iter().enumerate() {
292 use ChunkType::*;
293 match ch.get_type() {
294 PacketTable => (packet_table_idx = Some(idx)),
295 _ => (),
296 }
297 }
298 Some(remove_and_unwrap!(packet_table_idx.unwrap(), PacketTable))
299 },
300 None => None,
302 };
303
304 let mut audio_chunk_len = 0;
308 let mut seek_backwards = 0;
309 const HEADER_LEN :i64 = 12;
310 for hdr in read_headers.iter() {
311 if seek_backwards > 0 || hdr.ch_type == ChunkType::AudioData {
312 seek_backwards += HEADER_LEN;
313 seek_backwards += hdr.ch_size;
314 }
315 if hdr.ch_type == ChunkType::AudioData {
316 audio_chunk_len = hdr.ch_size;
317 }
318 }
319 if seek_backwards != 0 {
320 seek_backwards -= HEADER_LEN;
323 try!(ch_rdr.rdr.seek(SeekFrom::Current(-(seek_backwards as i64))));
325 } else {
326 loop {
328 let ch_hdr = try!(ch_rdr.read_chunk_header());
329 if ch_hdr.ch_type == ChunkType::AudioData {
330 audio_chunk_len = ch_hdr.ch_size;
331 break;
332 } else {
333 try!(ch_rdr.to_next_chunk(&ch_hdr));
334 }
335 }
336 }
337 let edit_count = {
339 use byteorder::{ReadBytesExt, BigEndian};
340 try!(ch_rdr.rdr.read_u32::<BigEndian>())
341 };
342 Ok(CafPacketReader {
344 ch_rdr : ch_rdr,
345 audio_desc : audio_desc,
346 packet_table : packet_table,
347 chunks : chunks_in_mem,
348 edit_count : edit_count,
349 audio_chunk_len : audio_chunk_len,
350 audio_chunk_offs : 4, packet_idx : 0,
352 })
353 }
354 pub fn into_inner(self) -> CafChunkReader<T> {
355 self.ch_rdr
356 }
357 pub fn packet_size_is_constant(&self) -> bool {
362 return self.audio_desc.bytes_per_packet != 0;
363 }
364 pub fn next_packet_size(&self) -> Option<usize> {
372 let res = match self.audio_desc.bytes_per_packet {
373 0 => match self.packet_table.as_ref()
374 .unwrap().lengths.get(self.packet_idx) {
375 Some(v) => *v as usize,
376 None => return None,
377 },
378 v => v as usize,
379 };
380 if self.audio_chunk_len != -1 &&
381 self.audio_chunk_offs + res as i64 > self.audio_chunk_len {
382 None
388 } else {
389 Some(res)
390 }
391 }
392 pub fn next_packet(&mut self) -> Result<Option<Vec<u8>>, CafError> {
397 let next_packet_size = match self.next_packet_size() {
398 Some(v) => v,
399 None => return Ok(None),
400 };
401
402 let mut arr = vec![0; next_packet_size];
403 try!(self.ch_rdr.rdr.read_exact(&mut arr));
404 self.packet_idx += 1;
405 self.audio_chunk_offs += next_packet_size as i64;
406 return Ok(Some(arr));
407 }
408 pub fn read_packet_into(&mut self, data :&mut [u8]) -> Result<(), CafError> {
415 try!(self.ch_rdr.rdr.read_exact(data));
416 self.packet_idx += 1;
417 self.audio_chunk_offs += data.len() as i64;
418 return Ok(());
419 }
420
421 pub fn get_packet_count(&self) -> Option<usize> {
423 match &self.packet_table {
424 &Some(ref t) => Some(t.lengths.len()),
425 &None => match self.audio_desc.bytes_per_packet {
426 0 => panic!("No packet table was stored by the constructor"),
430 _ if self.audio_chunk_len == -1 => None,
434 v => Some((self.audio_chunk_len as usize - 4) / v as usize),
435 },
436 }
437 }
438
439 pub fn get_packet_idx(&self) -> usize {
441 self.packet_idx
442 }
443
444 pub fn seek_to_packet(&mut self, packet_idx :usize) -> Result<(), CafError> {
449
450 let min_idx = ::std::cmp::min(self.packet_idx, packet_idx);
451 let max_idx = ::std::cmp::min(self.packet_idx, packet_idx);
452
453 let offs :i64 = match self.audio_desc.bytes_per_packet {
455 0 => self.packet_table.as_ref()
456 .unwrap().lengths[min_idx..max_idx].iter().map(|v| *v as i64).sum(),
457 v => (max_idx - min_idx) as i64 * v as i64,
458 };
459 if self.packet_idx < packet_idx {
460 try!(self.ch_rdr.rdr.seek(SeekFrom::Current(offs)));
461 } else if self.packet_idx > packet_idx {
462 try!(self.ch_rdr.rdr.seek(SeekFrom::Current(-offs)));
463 } else {
464 }
466 Ok(())
467 }
468}