diff options
author | tomsmeding <tom.smeding@gmail.com> | 2020-01-12 20:04:31 +0100 |
---|---|---|
committer | tomsmeding <tom.smeding@gmail.com> | 2020-01-12 20:04:31 +0100 |
commit | 5e39d6876b806604090b892369cba9892c7dac25 (patch) | |
tree | 7f91fd1d9422fad3ec35f7690755dad9d70a8b9a /src/id3v2.rs | |
parent | 3a8069d1a46578c810f24c7b1b092251ffc22c39 (diff) |
Correctly interpret and change values; does not write yet
Diffstat (limited to 'src/id3v2.rs')
-rw-r--r-- | src/id3v2.rs | 75 |
1 files changed, 53 insertions, 22 deletions
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<Vec<u8>> { + let as_latin1 = || iter::once(Ok(0)) + .chain(s.chars().map(|c| u8::try_from(u32::from(c)))) + .collect::<Result<Vec<u8>, _>>(); + + let as_ucs2 = || { + let nibbles = s.chars() + .map(|c| u16::try_from(u32::from(c))) + .collect::<Result<Vec<u16>, _>>()?; + 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::<Vec<u8>>()) + }; + + 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<Vec<u8>> { - let as_latin1 = || iter::once(Ok(0)) - .chain(s.chars().map(|c| u8::try_from(u32::from(c)))) - .collect::<Result<Vec<u8>, _>>(); - - let as_ucs2 = || { - let nibbles = s.chars() - .map(|c| u16::try_from(u32::from(c))) - .collect::<Result<Vec<u16>, _>>()?; - Ok(iter::once(1) - .chain(nibbles.iter().flat_map(|&n| ArrayIter2::new([(n >> 8) as u8, n as u8]))) - .collect::<Vec<u8>>()) - }; - - as_latin1() - .or_else(|_| as_ucs2()) - .map_err(|e: TryFromIntError| e.ioerr()) - } - pub fn interpret(&self) -> io::Result<Option<Frame>> { 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<F: Fn(String) -> String>(self, f: F) -> io::Result<Option<Self>> { + pub fn map_string<F: FnOnce(String) -> String>(&self, f: F) -> io::Result<Option<Self>> { let type_t = |id: &str, body: String| -> io::Result<Self> { 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<RawFrame> { + 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", } } } |