ID3v2: Expose {synch_u32, unsynch_u32}

This commit is contained in:
Serial 2022-07-26 21:55:58 -04:00
parent efedf0f443
commit ec4fb07042
No known key found for this signature in database
GPG key ID: DA95198DC17C4568
7 changed files with 72 additions and 57 deletions

View file

@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **A proc macro for file creation**: - **A proc macro for file creation**:
- With the new `lofty_attr` crate, file creation has been simplified significantly. - With the new `lofty_attr` crate, file creation has been simplified significantly.
It is available for both internal and external usage. It is available for both internal and external usage.
- **ID3v2**: Exposed internal functions `id3::v2::util::{synch_u32, unsynch_u32}`
### Changed ### Changed
- **TaggedFile**: `tag{_mut}` no longer takes a reference to `TagType` - **TaggedFile**: `tag{_mut}` no longer takes a reference to `TagType`

View file

@ -699,7 +699,7 @@ impl FileType {
// TODO: APE tags in the beginning of the file // TODO: APE tags in the beginning of the file
pub(crate) fn from_buffer_inner(buf: &[u8]) -> (Option<Self>, Option<u32>) { pub(crate) fn from_buffer_inner(buf: &[u8]) -> (Option<Self>, Option<u32>) {
use crate::id3::v2::unsynch_u32; use crate::id3::v2::util::unsynch_u32;
// Start out with an empty return: (File type, id3 size) // Start out with an empty return: (File type, id3 size)
// Only one can be set // Only one can be set

View file

@ -80,7 +80,7 @@ where
// unsynch the frame size if necessary // unsynch the frame size if necessary
if synchsafe { if synchsafe {
size = crate::id3::v2::unsynch_u32(size); size = crate::id3::v2::util::unsynch_u32(size);
} }
let frame_id = FrameID::new(id_str)?; let frame_id = FrameID::new(id_str)?;

View file

@ -8,10 +8,11 @@
//! * [Frame] //! * [Frame]
mod flags; mod flags;
pub(crate) mod util; pub mod util;
use crate::error::{ID3v2Error, ID3v2ErrorKind, Result}; use crate::error::{ID3v2Error, ID3v2ErrorKind, Result};
use crate::macros::err; use crate::macros::err;
use util::unsynch_u32;
use std::io::Read; use std::io::Read;
@ -66,24 +67,6 @@ pub enum ID3v2Version {
V4, V4,
} }
// https://github.com/polyfloyd/rust-id3/blob/e142ec656bf70a8153f6e5b34a37f26df144c3c1/src/stream/unsynch.rs#L18-L20
pub(crate) fn unsynch_u32(n: u32) -> u32 {
n & 0xFF | (n & 0xFF00) >> 1 | (n & 0xFF_0000) >> 2 | (n & 0xFF00_0000) >> 3
}
#[cfg(feature = "id3v2")]
// https://github.com/polyfloyd/rust-id3/blob/e142ec656bf70a8153f6e5b34a37f26df144c3c1/src/stream/unsynch.rs#L9-L15
pub(crate) fn synch_u32(n: u32) -> Result<u32> {
if n > 0x1000_0000 {
err!(TooMuchData);
}
let mut x: u32 = n & 0x7F | (n & 0xFFFF_FF80) << 1;
x = x & 0x7FFF | (x & 0xFFFF_8000) << 1;
x = x & 0x7F_FFFF | (x & 0xFF80_0000) << 1;
Ok(x)
}
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub(crate) struct ID3v2Header { pub(crate) struct ID3v2Header {
#[cfg(feature = "id3v2")] #[cfg(feature = "id3v2")]

View file

@ -1,53 +1,84 @@
//! Utilities for working with ID3v2 tags
pub(crate) mod text_utils; pub(crate) mod text_utils;
#[cfg(feature = "id3v2")]
pub(crate) mod upgrade;
#[cfg(feature = "id3v2")] cfg_if::cfg_if! {
use crate::error::{ID3v2Error, ID3v2ErrorKind, Result}; if #[cfg(feature = "id3v2")] {
pub(crate) mod upgrade;
#[cfg(feature = "id3v2")] use crate::error::{ID3v2Error, ID3v2ErrorKind, Result};
pub(in crate::id3::v2) fn unsynch_content(content: &[u8]) -> Result<Vec<u8>> {
let mut unsynch_content = Vec::new();
let mut discard = false; pub(in crate::id3::v2) fn unsynch_content(content: &[u8]) -> Result<Vec<u8>> {
let mut unsynch_content = Vec::new();
let mut i = 0; let mut discard = false;
let mut next = 0;
let content_len = content.len();
// Check for (0xFF, 0x00, 0x00), replace with (0xFF, 0x00) let mut i = 0;
while i < content_len && next < content_len { let mut next = 0;
// Verify the next byte is less than 0xE0 (0b111xxxxx) let content_len = content.len();
// Then remove the next byte if it is a zero
if discard { // Check for (0xFF, 0x00, 0x00), replace with (0xFF, 0x00)
if content[next] >= 0xE0 { while i < content_len && next < content_len {
return Err(ID3v2Error::new(ID3v2ErrorKind::Other( // Verify the next byte is less than 0xE0 (0b111xxxxx)
"Encountered an invalid unsynchronisation", // Then remove the next byte if it is a zero
)) if discard {
.into()); if content[next] >= 0xE0 {
} return Err(ID3v2Error::new(ID3v2ErrorKind::Other(
"Encountered an invalid unsynchronisation",
))
.into());
}
if content[next] == 0 {
discard = false;
next += 1;
continue;
}
}
if content[next] == 0 {
discard = false; discard = false;
unsynch_content.push(content[next]);
if content[next] == 0xFF {
discard = true
}
i += 1;
next += 1; next += 1;
continue;
} }
Ok(unsynch_content)
} }
discard = false; /// Create a synchsafe integer
///
/// See [`FrameFlags::unsynchronisation`](crate::id3::v2::FrameFlags::unsynchronisation) for an explanation.
///
/// # Errors
///
/// `n` doesn't fit in 28 bits
// https://github.com/polyfloyd/rust-id3/blob/e142ec656bf70a8153f6e5b34a37f26df144c3c1/src/stream/unsynch.rs#L9-L15
pub fn synch_u32(n: u32) -> Result<u32> {
if n > 0x1000_0000 {
crate::macros::err!(TooMuchData);
}
unsynch_content.push(content[next]); let mut x: u32 = n & 0x7F | (n & 0xFFFF_FF80) << 1;
x = x & 0x7FFF | (x & 0xFFFF_8000) << 1;
if content[next] == 0xFF { x = x & 0x7F_FFFF | (x & 0xFF80_0000) << 1;
discard = true Ok(x)
} }
i += 1;
next += 1;
} }
}
Ok(unsynch_content) /// Unsynchronise a synchsafe integer
///
/// See [`FrameFlags::unsynchronisation`](crate::id3::v2::FrameFlags::unsynchronisation) for an explanation.
// https://github.com/polyfloyd/rust-id3/blob/e142ec656bf70a8153f6e5b34a37f26df144c3c1/src/stream/unsynch.rs#L18-L20
pub fn unsynch_u32(n: u32) -> u32 {
n & 0xFF | (n & 0xFF00) >> 1 | (n & 0xFF_0000) >> 2 | (n & 0xFF00_0000) >> 3
} }
#[cfg(test)] #[cfg(test)]

View file

@ -1,6 +1,6 @@
use crate::error::{ID3v2Error, ID3v2ErrorKind, Result}; use crate::error::{ID3v2Error, ID3v2ErrorKind, Result};
use crate::id3::v2::frame::{FrameFlags, FrameRef, FrameValue}; use crate::id3::v2::frame::{FrameFlags, FrameRef, FrameValue};
use crate::id3::v2::synch_u32; use crate::id3::v2::util::synch_u32;
use std::io::Write; use std::io::Write;

View file

@ -6,8 +6,8 @@ use crate::error::Result;
use crate::file::FileType; use crate::file::FileType;
use crate::id3::find_id3v2; use crate::id3::find_id3v2;
use crate::id3::v2::frame::FrameRef; use crate::id3::v2::frame::FrameRef;
use crate::id3::v2::synch_u32;
use crate::id3::v2::tag::Id3v2TagRef; use crate::id3::v2::tag::Id3v2TagRef;
use crate::id3::v2::util::synch_u32;
use crate::macros::err; use crate::macros::err;
use crate::probe::Probe; use crate::probe::Probe;