use crate::error::{Error, Result};
use std::{
io::{Read, Seek, SeekFrom},
str,
};
pub(super) static APE_PREAMBLE: &[u8] = b"APETAGEX";
static ID3V1_HEADER: &[u8] = b"TAG";
static LYRICS3V2_HEADER: &[u8] = b"LYRICS200";
pub(super) const ID3V1_OFFSET: i64 = -128;
const LYRICS3V2_SIZE: i64 = 6;
pub(super) fn probe_ape<R: Read + Seek>(reader: &mut R, pos: SeekFrom) -> Result<bool> {
let capacity = APE_PREAMBLE.len();
let mut preamble = Vec::<u8>::with_capacity(capacity);
reader.seek(pos)?;
reader.take(capacity as u64).read_to_end(&mut preamble)?;
Ok(preamble == APE_PREAMBLE)
}
pub(super) fn probe_id3v1<R: Read + Seek>(reader: &mut R) -> Result<bool> {
let capacity = ID3V1_HEADER.len();
let mut header = Vec::<u8>::with_capacity(capacity);
reader.seek(SeekFrom::End(ID3V1_OFFSET))?;
reader.take(capacity as u64).read_to_end(&mut header)?;
Ok(header == ID3V1_HEADER)
}
pub(super) fn probe_lyrics3v2<R: Read + Seek>(reader: &mut R) -> Result<i64> {
let capacity = LYRICS3V2_HEADER.len();
let mut header = Vec::<u8>::with_capacity(capacity);
reader.seek(SeekFrom::End(ID3V1_OFFSET - capacity as i64))?;
reader.take(capacity as u64).read_to_end(&mut header)?;
reader.seek(SeekFrom::Current(0 - capacity as i64))?;
if header == LYRICS3V2_HEADER {
let mut buf = Vec::<u8>::with_capacity(LYRICS3V2_SIZE as usize);
reader.seek(SeekFrom::Current(-LYRICS3V2_SIZE))?;
reader.take(LYRICS3V2_SIZE as u64).read_to_end(&mut buf)?;
let raw_size = str::from_utf8(&buf).map_err(Error::ParseLyrics3V2SizeStr)?;
let int_size = raw_size.parse::<i64>().map_err(Error::ParseLyrics3V2SizeInt)?;
Ok(int_size + LYRICS3V2_SIZE + capacity as i64)
} else {
Ok(-1)
}
}