lofty/config/parse_options.rs
1/// Options to control how Lofty parses a file
2#[derive(Copy, Clone, Debug, Eq, PartialEq)]
3#[non_exhaustive]
4pub struct ParseOptions {
5 pub(crate) read_properties: bool,
6 pub(crate) read_tags: bool,
7 pub(crate) parsing_mode: ParsingMode,
8 pub(crate) max_junk_bytes: usize,
9 pub(crate) read_cover_art: bool,
10 pub(crate) implicit_conversions: bool,
11}
12
13impl Default for ParseOptions {
14 /// The default implementation for `ParseOptions`
15 ///
16 /// The defaults are as follows:
17 ///
18 /// ```rust,ignore
19 /// ParseOptions {
20 /// read_properties: true,
21 /// read_tags: true,
22 /// parsing_mode: ParsingMode::BestAttempt,
23 /// max_junk_bytes: 1024,
24 /// read_cover_art: true,
25 /// implicit_conversions: true,
26 /// }
27 /// ```
28 fn default() -> Self {
29 Self::new()
30 }
31}
32
33impl ParseOptions {
34 /// Default parsing mode
35 pub const DEFAULT_PARSING_MODE: ParsingMode = ParsingMode::BestAttempt;
36
37 /// Default number of junk bytes to read
38 pub const DEFAULT_MAX_JUNK_BYTES: usize = 1024;
39
40 /// Creates a new `ParseOptions`, alias for `Default` implementation
41 ///
42 /// See also: [`ParseOptions::default`]
43 ///
44 /// # Examples
45 ///
46 /// ```rust
47 /// use lofty::config::ParseOptions;
48 ///
49 /// let parsing_options = ParseOptions::new();
50 /// ```
51 #[must_use]
52 pub const fn new() -> Self {
53 Self {
54 read_properties: true,
55 read_tags: true,
56 parsing_mode: Self::DEFAULT_PARSING_MODE,
57 max_junk_bytes: Self::DEFAULT_MAX_JUNK_BYTES,
58 read_cover_art: true,
59 implicit_conversions: true,
60 }
61 }
62
63 /// Whether or not to read the audio properties
64 ///
65 /// # Examples
66 ///
67 /// ```rust
68 /// use lofty::config::ParseOptions;
69 ///
70 /// // By default, `read_properties` is enabled. Here, we don't want to read them.
71 /// let parsing_options = ParseOptions::new().read_properties(false);
72 /// ```
73 pub fn read_properties(&mut self, read_properties: bool) -> Self {
74 self.read_properties = read_properties;
75 *self
76 }
77
78 /// Whether or not to read the tags
79 ///
80 /// # Examples
81 ///
82 /// ```rust
83 /// use lofty::config::ParseOptions;
84 ///
85 /// // By default, `read_tags` is enabled. Here, we don't want to read them.
86 /// let parsing_options = ParseOptions::new().read_tags(false);
87 /// ```
88 pub fn read_tags(&mut self, read_tags: bool) -> Self {
89 self.read_tags = read_tags;
90 *self
91 }
92
93 /// The parsing mode to use, see [`ParsingMode`] for details
94 ///
95 /// # Examples
96 ///
97 /// ```rust
98 /// use lofty::config::{ParseOptions, ParsingMode};
99 ///
100 /// // By default, `parsing_mode` is ParsingMode::BestAttempt. Here, we need absolute correctness.
101 /// let parsing_options = ParseOptions::new().parsing_mode(ParsingMode::Strict);
102 /// ```
103 pub fn parsing_mode(&mut self, parsing_mode: ParsingMode) -> Self {
104 self.parsing_mode = parsing_mode;
105 *self
106 }
107
108 /// The maximum number of allowed junk bytes to search
109 ///
110 /// Some information may be surrounded by junk bytes, such as tag padding remnants. This sets the maximum
111 /// number of junk/unrecognized bytes Lofty will search for required information before giving up.
112 ///
113 /// # Examples
114 ///
115 /// ```rust
116 /// use lofty::config::ParseOptions;
117 ///
118 /// // I have files full of junk, I'll double the search window!
119 /// let parsing_options = ParseOptions::new().max_junk_bytes(2048);
120 /// ```
121 pub fn max_junk_bytes(&mut self, max_junk_bytes: usize) -> Self {
122 self.max_junk_bytes = max_junk_bytes;
123 *self
124 }
125
126 /// Whether or not to read cover art
127 ///
128 /// # Examples
129 ///
130 /// ```rust
131 /// use lofty::config::ParseOptions;
132 ///
133 /// // Reading cover art is expensive, and I do not need it!
134 /// let parsing_options = ParseOptions::new().read_cover_art(false);
135 /// ```
136 pub fn read_cover_art(&mut self, read_cover_art: bool) -> Self {
137 self.read_cover_art = read_cover_art;
138 *self
139 }
140
141 /// Whether or not to perform implicit conversions
142 ///
143 /// Implicit conversions are conversions that are not explicitly defined by the spec, but are commonly used.
144 ///
145 /// ⚠ **Warning** ⚠
146 ///
147 /// Turning this off may cause some [`Accessor`](crate::tag::Accessor) methods to return nothing.
148 /// Lofty makes some assumptions about the data, if they are broken, the caller will have more
149 /// responsibility.
150 ///
151 /// Examples include:
152 ///
153 /// * Converting the outdated MP4 `gnre` atom to a `©gen` atom
154 /// * Combining the ID3v2.3 `TYER`, `TDAT`, and `TIME` frames into a single `TDRC` frame
155 ///
156 /// Examples of what this does *not* include:
157 ///
158 /// * Converting a Vorbis `COVERART` field to `METADATA_BLOCK_PICTURE`
159 /// * This is a non-standard field, with a well-defined conversion. Lofty will not support
160 /// the non-standard `COVERART` for [`Picture`](crate::picture::Picture)s.
161 pub fn implicit_conversions(&mut self, implicit_conversions: bool) -> Self {
162 self.implicit_conversions = implicit_conversions;
163 *self
164 }
165}
166
167/// The parsing strictness mode
168///
169/// This can be set with [`Probe::options`](crate::probe::Probe).
170///
171/// # Examples
172///
173/// ```rust,no_run
174/// use lofty::config::{ParseOptions, ParsingMode};
175/// use lofty::probe::Probe;
176///
177/// # fn main() -> lofty::error::Result<()> {
178/// // We only want to read spec-compliant inputs
179/// let parsing_options = ParseOptions::new().parsing_mode(ParsingMode::Strict);
180/// let tagged_file = Probe::open("foo.mp3")?.options(parsing_options).read()?;
181/// # Ok(()) }
182/// ```
183#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Default)]
184#[non_exhaustive]
185pub enum ParsingMode {
186 /// Will eagerly error on invalid input
187 ///
188 /// This mode will eagerly error on any non spec-compliant input.
189 ///
190 /// ## Examples of behavior
191 ///
192 /// * Unable to decode text - The parser will error and the entire input is discarded
193 /// * Unable to determine the sample rate - The parser will error and the entire input is discarded
194 Strict,
195 /// Default mode, less eager to error on recoverably malformed input
196 ///
197 /// This mode will attempt to fill in any holes where possible in otherwise valid, spec-compliant input.
198 ///
199 /// NOTE: A readable input does *not* necessarily make it writeable.
200 ///
201 /// ## Examples of behavior
202 ///
203 /// * Unable to decode text - If valid otherwise, the field will be replaced by an empty string and the parser moves on
204 /// * Unable to determine the sample rate - The sample rate will be 0
205 #[default]
206 BestAttempt,
207 /// Least eager to error, may produce invalid/partial output
208 ///
209 /// This mode will discard any invalid fields, and ignore the majority of non-fatal errors.
210 ///
211 /// If the input is malformed, the resulting tags may be incomplete, and the properties zeroed.
212 ///
213 /// ## Examples of behavior
214 ///
215 /// * Unable to decode text - The entire item is discarded and the parser moves on
216 /// * Unable to determine the sample rate - The sample rate will be 0
217 Relaxed,
218}