1use super::Frame;
2use super::header::parse::{parse_header, parse_v2_header};
3use crate::config::{ParseOptions, ParsingMode};
4use crate::error::{Id3v2Error, Id3v2ErrorKind, Result};
5use crate::id3::v2::frame::content::parse_content;
6use crate::id3::v2::header::Id3v2Version;
7use crate::id3::v2::tag::ATTACHED_PICTURE_ID;
8use crate::id3::v2::util::synchsafe::{SynchsafeInteger, UnsynchronizedStream};
9use crate::id3::v2::{BinaryFrame, FrameFlags, FrameHeader, FrameId};
10use crate::macros::try_vec;
11
12use std::io::Read;
13
14use byteorder::{BigEndian, ReadBytesExt};
15
16pub(crate) enum ParsedFrame<'a> {
17 Next(Frame<'a>),
18 Skip,
19 Eof,
20}
21
22impl ParsedFrame<'_> {
23 pub(crate) fn read<R>(
24 reader: &mut R,
25 version: Id3v2Version,
26 parse_options: ParseOptions,
27 ) -> Result<Self>
28 where
29 R: Read,
30 {
31 let mut size = 0u32;
32
33 let parse_header_result = match version {
35 Id3v2Version::V2 => parse_v2_header(reader, &mut size),
36 Id3v2Version::V3 => parse_header(reader, &mut size, false, parse_options),
37 Id3v2Version::V4 => parse_header(reader, &mut size, true, parse_options),
38 };
39 let (id, mut flags) = match parse_header_result {
40 Ok(None) => {
41 return Ok(Self::Eof);
43 },
44 Ok(Some(some)) => some,
45 Err(err) => {
46 match parse_options.parsing_mode {
47 ParsingMode::Strict => return Err(err),
48 ParsingMode::BestAttempt | ParsingMode::Relaxed => {
49 log::warn!("Failed to read frame header, skipping: {}", err);
50
51 skip_frame(reader, size)?;
53 return Ok(Self::Skip);
54 },
55 }
56 },
57 };
58
59 if !parse_options.read_cover_art && id == ATTACHED_PICTURE_ID {
60 skip_frame(reader, size)?;
61 return Ok(Self::Skip);
62 }
63
64 if size == 0 {
65 if parse_options.parsing_mode == ParsingMode::Strict {
66 return Err(Id3v2Error::new(Id3v2ErrorKind::EmptyFrame(id)).into());
67 }
68
69 log::debug!("Encountered a zero length frame, skipping");
70
71 skip_frame(reader, size)?;
72 return Ok(Self::Skip);
73 }
74
75 if let Some(enc) = flags.encryption.as_mut() {
77 log::trace!("Reading encryption method symbol");
78
79 if size < 1 {
80 return Err(Id3v2Error::new(Id3v2ErrorKind::BadFrameLength).into());
81 }
82
83 *enc = reader.read_u8()?;
84 size -= 1;
85 }
86
87 if let Some(group) = flags.grouping_identity.as_mut() {
89 log::trace!("Reading group identifier");
90
91 if size < 1 {
92 return Err(Id3v2Error::new(Id3v2ErrorKind::BadFrameLength).into());
93 }
94
95 *group = reader.read_u8()?;
96 size -= 1;
97 }
98
99 if flags.data_length_indicator.is_some() || flags.compression {
101 log::trace!("Reading data length indicator");
102
103 if size < 4 {
104 return Err(Id3v2Error::new(Id3v2ErrorKind::BadFrameLength).into());
105 }
106
107 let len = reader.read_u32::<BigEndian>()?.unsynch();
110 flags.data_length_indicator = Some(len);
111 size -= 4;
112 }
113
114 if size == 0 {
116 return Err(Id3v2Error::new(Id3v2ErrorKind::BadFrameLength).into());
117 }
118
119 let mut reader = reader.take(u64::from(size));
121
122 match flags {
128 FrameFlags {
135 unsynchronisation: true,
136 ..
137 } => {
138 let mut unsynchronized_reader = UnsynchronizedStream::new(reader);
139
140 if flags.compression {
141 let mut compression_reader = handle_compression(unsynchronized_reader)?;
142
143 if flags.encryption.is_some() {
144 return handle_encryption(&mut compression_reader, size, id, flags);
145 }
146
147 return parse_frame(
148 &mut compression_reader,
149 size,
150 id,
151 flags,
152 version,
153 parse_options.parsing_mode,
154 );
155 }
156
157 if flags.encryption.is_some() {
158 return handle_encryption(&mut unsynchronized_reader, size, id, flags);
159 }
160
161 return parse_frame(
162 &mut unsynchronized_reader,
163 size,
164 id,
165 flags,
166 version,
167 parse_options.parsing_mode,
168 );
169 },
170 FrameFlags {
175 compression: true, ..
176 } => {
177 let mut compression_reader = handle_compression(reader)?;
178
179 if flags.encryption.is_some() {
180 return handle_encryption(&mut compression_reader, size, id, flags);
181 }
182
183 return parse_frame(
184 &mut compression_reader,
185 size,
186 id,
187 flags,
188 version,
189 parse_options.parsing_mode,
190 );
191 },
192 FrameFlags {
196 encryption: Some(_),
197 ..
198 } => {
199 return handle_encryption(&mut reader, size, id, flags);
200 },
201 _ => {
203 return parse_frame(
204 &mut reader,
205 size,
206 id,
207 flags,
208 version,
209 parse_options.parsing_mode,
210 );
211 },
212 }
213 }
214}
215
216#[cfg(feature = "id3v2_compression_support")]
217#[allow(clippy::unnecessary_wraps)]
218fn handle_compression<R: Read>(reader: R) -> Result<flate2::read::ZlibDecoder<R>> {
219 Ok(flate2::read::ZlibDecoder::new(reader))
220}
221
222#[cfg(not(feature = "id3v2_compression_support"))]
223#[allow(clippy::unnecessary_wraps)]
224fn handle_compression<R>(_: R) -> Result<std::io::Empty> {
225 Err(Id3v2Error::new(Id3v2ErrorKind::CompressedFrameEncountered).into())
226}
227
228fn handle_encryption<R: Read>(
229 reader: &mut R,
230 size: u32,
231 id: FrameId<'static>,
232 flags: FrameFlags,
233) -> Result<ParsedFrame<'static>> {
234 if flags.data_length_indicator.is_none() {
235 return Err(Id3v2Error::new(Id3v2ErrorKind::MissingDataLengthIndicator).into());
236 }
237
238 let mut content = try_vec![0; size as usize];
239 reader.read_exact(&mut content)?;
240
241 let encrypted_frame = Frame::Binary(BinaryFrame {
242 header: FrameHeader::new(id, flags),
243 data: content,
244 });
245
246 Ok(ParsedFrame::Next(encrypted_frame))
248}
249
250fn parse_frame<R: Read>(
251 reader: &mut R,
252 size: u32,
253 id: FrameId<'static>,
254 flags: FrameFlags,
255 version: Id3v2Version,
256 parse_mode: ParsingMode,
257) -> Result<ParsedFrame<'static>> {
258 match parse_content(reader, id, flags, version, parse_mode)? {
259 Some(frame) => Ok(ParsedFrame::Next(frame)),
260 None => {
261 skip_frame(reader, size)?;
262 Ok(ParsedFrame::Skip)
263 },
264 }
265}
266
267fn skip_frame(reader: &mut impl Read, size: u32) -> Result<()> {
274 log::trace!("Skipping frame of size {}", size);
275
276 let size = u64::from(size);
277 let mut reader = reader.take(size);
278 let skipped = std::io::copy(&mut reader, &mut std::io::sink())?;
279 debug_assert!(skipped <= size);
280
281 Ok(())
282}