anni_flac/blocks/
seek_table.rs

1use crate::error::FlacError;
2use crate::prelude::*;
3use crate::utils::*;
4use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
5use std::fmt;
6use std::io::{Read, Write};
7
8pub struct BlockSeekTable {
9    pub seek_points: Vec<SeekPoint>,
10}
11
12/// Notes:
13/// - For placeholder points, the second and third field values are undefined.
14/// - Seek points within a table must be sorted in ascending order by sample number.
15/// - Seek points within a table must be unique by sample number, with the exception of placeholder points.
16/// - The previous two notes imply that there may be any number of placeholder points, but they must all occur at the end of the table.
17#[derive(Debug)]
18pub struct SeekPoint {
19    // Sample number of first sample in the target frame, or 0xFFFFFFFFFFFFFFFF for a placeholder point.
20    pub sample_number: u64,
21    // Offset (in bytes) from the first byte of the first frame header to the first byte of the target frame's header.
22    pub stream_offset: u64,
23    // Number of samples in the target frame.
24    pub frame_samples: u16,
25}
26
27impl SeekPoint {
28    pub fn is_placeholder(&self) -> bool {
29        self.sample_number == 0xFFFFFFFFFFFFFFFF
30    }
31}
32
33impl Decode for BlockSeekTable {
34    fn from_reader<R: Read>(reader: &mut R) -> Result<Self> {
35        let buf = take_to_end(reader)?;
36        let size = buf.len();
37        let mut reader = std::io::Cursor::new(buf);
38
39        // The number of seek points is implied by the metadata header 'length' field, i.e. equal to length / 18.
40        let points = size / 18;
41        let remaining = size % 18;
42        if remaining != 0 {
43            return Err(FlacError::InvalidSeekTableSize);
44        }
45
46        let mut seek_points = Vec::with_capacity(points);
47        for _ in 0..points {
48            let sample_number = ReadBytesExt::read_u64::<BigEndian>(&mut reader)?;
49            let stream_offset = ReadBytesExt::read_u64::<BigEndian>(&mut reader)?;
50            let frame_samples = ReadBytesExt::read_u16::<BigEndian>(&mut reader)?;
51            seek_points.push(SeekPoint {
52                sample_number,
53                stream_offset,
54                frame_samples,
55            });
56        }
57
58        Ok(BlockSeekTable { seek_points })
59    }
60}
61
62#[cfg(feature = "async")]
63#[async_trait::async_trait]
64impl AsyncDecode for BlockSeekTable {
65    async fn from_async_reader<R>(reader: &mut R) -> Result<Self>
66    where
67        R: AsyncRead + Unpin + Send,
68    {
69        let buf = take_to_end_async(reader).await?;
70        let size = buf.len();
71        let mut reader = std::io::Cursor::new(buf);
72
73        // The number of seek points is implied by the metadata header 'length' field, i.e. equal to length / 18.
74        let points = size / 18;
75        let remaining = size % 18;
76        if remaining != 0 {
77            return Err(FlacError::InvalidSeekTableSize);
78        }
79
80        let mut seek_points = Vec::with_capacity(points);
81        for _ in 0..points {
82            let sample_number = AsyncReadExt::read_u64(&mut reader).await?;
83            let stream_offset = AsyncReadExt::read_u64(&mut reader).await?;
84            let frame_samples = AsyncReadExt::read_u16(&mut reader).await?;
85            seek_points.push(SeekPoint {
86                sample_number,
87                stream_offset,
88                frame_samples,
89            });
90        }
91
92        Ok(BlockSeekTable { seek_points })
93    }
94}
95
96impl Encode for BlockSeekTable {
97    fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
98        for point in self.seek_points.iter() {
99            writer.write_u64::<BigEndian>(point.sample_number)?;
100            writer.write_u64::<BigEndian>(point.stream_offset)?;
101            writer.write_u16::<BigEndian>(point.frame_samples)?;
102        }
103        Ok(())
104    }
105}
106
107impl fmt::Debug for BlockSeekTable {
108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        let mut prefix = "".to_owned();
110        if let Some(width) = f.width() {
111            prefix = " ".repeat(width);
112        }
113        writeln!(
114            f,
115            "{prefix}seek points: {}",
116            self.seek_points.len(),
117            prefix = prefix
118        )?;
119        for (i, p) in self.seek_points.iter().enumerate() {
120            if p.is_placeholder() {
121                writeln!(f, "{prefix}point {}: PLACEHOLDER", i, prefix = prefix)?;
122            } else {
123                writeln!(
124                    f,
125                    "{prefix}point {}: sample_number={}, stream_offset={}, frame_samples={}",
126                    i,
127                    p.sample_number,
128                    p.stream_offset,
129                    p.frame_samples,
130                    prefix = prefix
131                )?;
132            }
133        }
134        Ok(())
135    }
136}