From 5e39d6876b806604090b892369cba9892c7dac25 Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Sun, 12 Jan 2020 20:04:31 +0100 Subject: Correctly interpret and change values; does not write yet --- src/id3v2.rs | 75 ++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 22 deletions(-) (limited to 'src/id3v2.rs') diff --git a/src/id3v2.rs b/src/id3v2.rs index 934bdf3..9e07cd3 100644 --- a/src/id3v2.rs +++ b/src/id3v2.rs @@ -26,6 +26,28 @@ fn parse_id3v2_header(bytes: &[u8]) -> Option<(u16, u8, usize)> { } } +/// Encodes native string to ID3v2 string encoding (either Latin-1 or UCS-2 according to the +/// characters used). +fn encode_string(s: &str) -> io::Result> { + let as_latin1 = || iter::once(Ok(0)) + .chain(s.chars().map(|c| u8::try_from(u32::from(c)))) + .collect::, _>>(); + + let as_ucs2 = || { + let nibbles = s.chars() + .map(|c| u16::try_from(u32::from(c))) + .collect::, _>>()?; + Ok(iter::once(1) + .chain(ArrayIter2::new([0xfe, 0xff])) // BOM + .chain(nibbles.iter().flat_map(|&n| ArrayIter2::new([(n >> 8) as u8, n as u8]))) + .collect::>()) + }; + + as_latin1() + .or_else(|_| as_ucs2()) + .map_err(|e: TryFromIntError| e.ioerr()) +} + #[derive(Debug)] pub struct ID3v2 { header_size: usize, @@ -115,25 +137,6 @@ impl RawFrame { } } - fn encode_string(s: &str) -> io::Result> { - let as_latin1 = || iter::once(Ok(0)) - .chain(s.chars().map(|c| u8::try_from(u32::from(c)))) - .collect::, _>>(); - - let as_ucs2 = || { - let nibbles = s.chars() - .map(|c| u16::try_from(u32::from(c))) - .collect::, _>>()?; - Ok(iter::once(1) - .chain(nibbles.iter().flat_map(|&n| ArrayIter2::new([(n >> 8) as u8, n as u8]))) - .collect::>()) - }; - - as_latin1() - .or_else(|_| as_ucs2()) - .map_err(|e: TryFromIntError| e.ioerr()) - } - pub fn interpret(&self) -> io::Result> { let type_t = |typ: fn(String) -> Frame| self.interpret_encoded_string().map(typ).map(Some); @@ -147,12 +150,12 @@ impl RawFrame { } } - pub fn map_string String>(self, f: F) -> io::Result> { + pub fn map_string String>(&self, f: F) -> io::Result> { let type_t = |id: &str, body: String| -> io::Result { Ok(Self { id: id.to_string(), flags: 0, - body: Self::encode_string(&body)?, + body: encode_string(&body)?, }) }; @@ -162,7 +165,35 @@ impl RawFrame { Some(Frame::TPE1(s)) => Ok(Some(type_t("TPE1", f(s))?)), Some(Frame::TALB(s)) => Ok(Some(type_t("TALB", f(s))?)), Some(Frame::TRCK(s)) => Ok(Some(type_t("TRCK", f(s))?)), - None => Ok(Some(self)), + None => Ok(None), + } + } + + pub fn get_id(&self) -> &str { + &self.id + } +} + +impl Frame { + pub fn to_raw(self) -> io::Result { + let type_t = |typ: &str, body: String| Ok(RawFrame { id: typ.to_string(), flags: 0, body: encode_string(&body)? }); + + match self { + Self::TIT2(s) => type_t("TIT2", s), + Self::TYER(s) => type_t("TYER", s), + Self::TPE1(s) => type_t("TPE1", s), + Self::TALB(s) => type_t("TALB", s), + Self::TRCK(s) => type_t("TRCK", s), + } + } + + pub fn id(&self) -> &str { + match self { + Frame::TIT2(_) => "TIT2", + Frame::TYER(_) => "TYER", + Frame::TPE1(_) => "TPE1", + Frame::TALB(_) => "TALB", + Frame::TRCK(_) => "TRCK", } } } -- cgit v1.2.3