use super::misc::mktag;
use crate::error::{Error, Result};
use crate::tag::Tag;
use crate::value::Value;
pub fn read_real_audio(data: &[u8]) -> Result<Vec<Tag>> {
if data.len() < 8 || !data.starts_with(b".ra\xfd") {
return Err(Error::InvalidData("not a RealAudio file".into()));
}
let mut tags = Vec::new();
let version = u16::from_be_bytes([data[4], data[5]]);
if version != 4 {
return Ok(tags);
}
let d = &data[8..];
if d.len() < 40 {
return Ok(tags);
}
let mut pos = 0;
pos += 4;
pos += 4;
pos += 2;
pos += 4;
pos += 2;
pos += 4;
if pos + 4 > d.len() {
return Ok(tags);
}
let audio_bytes = u32::from_be_bytes([d[pos], d[pos + 1], d[pos + 2], d[pos + 3]]);
pos += 4;
tags.push(mktag(
"Real",
"AudioBytes",
"Audio Bytes",
Value::U32(audio_bytes),
));
if pos + 4 > d.len() {
return Ok(tags);
}
let bpm = u32::from_be_bytes([d[pos], d[pos + 1], d[pos + 2], d[pos + 3]]);
pos += 4;
tags.push(mktag(
"Real",
"BytesPerMinute",
"Bytes Per Minute",
Value::U32(bpm),
));
pos += 4;
pos += 2;
if pos + 2 > d.len() {
return Ok(tags);
}
let afs = u16::from_be_bytes([d[pos], d[pos + 1]]);
pos += 2;
tags.push(mktag(
"Real",
"AudioFrameSize",
"Audio Frame Size",
Value::U16(afs),
));
pos += 2;
pos += 2;
if pos + 2 > d.len() {
return Ok(tags);
}
let sr = u16::from_be_bytes([d[pos], d[pos + 1]]);
pos += 2;
tags.push(mktag("Real", "SampleRate", "Sample Rate", Value::U16(sr)));
pos += 2;
if pos + 2 > d.len() {
return Ok(tags);
}
let bps = u16::from_be_bytes([d[pos], d[pos + 1]]);
pos += 2;
tags.push(mktag(
"Real",
"BitsPerSample",
"Bits Per Sample",
Value::U16(bps),
));
if pos + 2 > d.len() {
return Ok(tags);
}
let ch = u16::from_be_bytes([d[pos], d[pos + 1]]);
pos += 2;
tags.push(mktag("Real", "Channels", "Channels", Value::U16(ch)));
if pos >= d.len() {
return Ok(tags);
}
let fc2l = d[pos] as usize;
pos += 1;
pos += fc2l;
if pos >= d.len() {
return Ok(tags);
}
let fc3l = d[pos] as usize;
pos += 1;
pos += fc3l;
if pos >= d.len() {
return Ok(tags);
}
pos += 1;
if pos + 2 > d.len() {
return Ok(tags);
}
pos += 2;
if pos >= d.len() {
return Ok(tags);
}
let title_len = d[pos] as usize;
pos += 1;
if pos + title_len <= d.len() && title_len > 0 {
let title = crate::encoding::decode_utf8_or_latin1(&d[pos..pos + title_len]).to_string();
tags.push(mktag("Real", "Title", "Title", Value::String(title)));
}
pos += title_len;
if pos >= d.len() {
return Ok(tags);
}
let artist_len = d[pos] as usize;
pos += 1;
if pos + artist_len <= d.len() && artist_len > 0 {
let artist = crate::encoding::decode_utf8_or_latin1(&d[pos..pos + artist_len]).to_string();
tags.push(mktag("Real", "Artist", "Artist", Value::String(artist)));
}
pos += artist_len;
if pos >= d.len() {
return Ok(tags);
}
let copy_len = d[pos] as usize;
pos += 1;
if pos + copy_len <= d.len() && copy_len > 0 {
let copyright = crate::encoding::decode_utf8_or_latin1(&d[pos..pos + copy_len]).to_string();
tags.push(mktag(
"Real",
"Copyright",
"Copyright",
Value::String(copyright),
));
}
Ok(tags)
}