use std::path::Path;
use crate::error::{PptxError, PptxResult};
use super::{audio_content_type_to_ext, audio_ext_to_content_type, compute_sha1};
const MAX_AUDIO_SIZE: u64 = 500 * 1024 * 1024;
#[derive(Debug, Clone)]
pub struct Audio {
blob: Vec<u8>,
content_type: String,
ext: String,
sha1: String,
}
impl Audio {
pub fn from_file(path: impl AsRef<Path>) -> PptxResult<Self> {
let path = path.as_ref();
let metadata = std::fs::metadata(path).map_err(PptxError::Io)?;
if metadata.len() > MAX_AUDIO_SIZE {
return Err(PptxError::ResourceLimit {
message: format!(
"audio file size {} bytes exceeds the limit of {} bytes",
metadata.len(),
MAX_AUDIO_SIZE
),
});
}
let blob = std::fs::read(path).map_err(PptxError::Io)?;
let file_ext = path
.extension()
.and_then(|e| e.to_str())
.map(str::to_lowercase)
.ok_or_else(|| {
PptxError::InvalidXml(format!(
"cannot determine audio format from path: {}",
path.display()
))
})?;
let content_type = audio_ext_to_content_type(&file_ext)
.ok_or_else(|| PptxError::InvalidXml(format!("unsupported audio format: {file_ext}")))?
.to_string();
let sha1 = compute_sha1(&blob);
Ok(Self {
blob,
content_type,
ext: file_ext,
sha1,
})
}
#[must_use]
pub fn from_bytes(data: Vec<u8>, content_type: &str) -> Self {
let ext = audio_content_type_to_ext(content_type)
.unwrap_or("bin")
.to_string();
let sha1 = compute_sha1(&data);
Self {
blob: data,
content_type: content_type.to_string(),
ext,
sha1,
}
}
#[must_use]
pub fn blob(&self) -> &[u8] {
&self.blob
}
#[must_use]
pub fn content_type(&self) -> &str {
&self.content_type
}
#[must_use]
pub fn ext(&self) -> &str {
&self.ext
}
#[must_use]
pub fn sha1(&self) -> &str {
&self.sha1
}
}