summaryrefslogtreecommitdiff
path: root/src/id3v2.rs
diff options
context:
space:
mode:
authortomsmeding <tom.smeding@gmail.com>2020-01-12 20:04:31 +0100
committertomsmeding <tom.smeding@gmail.com>2020-01-12 20:04:31 +0100
commit5e39d6876b806604090b892369cba9892c7dac25 (patch)
tree7f91fd1d9422fad3ec35f7690755dad9d70a8b9a /src/id3v2.rs
parent3a8069d1a46578c810f24c7b1b092251ffc22c39 (diff)
Correctly interpret and change values; does not write yet
Diffstat (limited to 'src/id3v2.rs')
-rw-r--r--src/id3v2.rs75
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",
}
}
}