use anyhow::Context;
use manganis_core::linker::LinkSection;
use manganis_core::BundledAsset;
use object::{read::archive::ArchiveFile, File as ObjectFile, Object, ObjectSection};
use serde::{Deserialize, Serialize};
use std::path::Path;
use std::{collections::HashMap, path::PathBuf};
mod css;
mod file;
mod folder;
mod image;
mod js;
mod json;
pub use file::process_file_to;
#[derive(Debug, PartialEq, Default, Clone, Serialize, Deserialize)]
pub struct AssetManifest {
pub assets: HashMap<PathBuf, BundledAsset>,
}
impl AssetManifest {
#[allow(dead_code)]
pub fn load_from_file(path: &Path) -> anyhow::Result<Self> {
let src = std::fs::read_to_string(path)?;
serde_json::from_str(&src)
.with_context(|| format!("Failed to parse asset manifest from {path:?}\n{src}"))
}
pub fn add_from_object_path(&mut self, path: &Path) -> anyhow::Result<()> {
let data = std::fs::read(path)?;
match path.extension().and_then(|ext| ext.to_str()) {
Some("rlib") => {
if let Ok(archive) = object::read::archive::ArchiveFile::parse(&*data) {
self.add_from_archive_file(&archive, &data)?;
}
}
_ => {
if let Ok(object) = object::File::parse(&*data) {
self.add_from_object_file(&object)?;
}
}
}
Ok(())
}
fn add_from_archive_file(&mut self, archive: &ArchiveFile, data: &[u8]) -> object::Result<()> {
for member in archive.members() {
let member = member?;
let name = String::from_utf8_lossy(member.name()).to_string();
if name.ends_with(".o") {
let data = member.data(data)?;
let object = object::File::parse(data)?;
_ = self.add_from_object_file(&object);
}
}
Ok(())
}
fn add_from_object_file(&mut self, obj: &ObjectFile) -> anyhow::Result<()> {
for section in obj.sections() {
let Ok(section_name) = section.name() else {
continue;
};
let matches = LinkSection::ALL
.iter()
.any(|x| x.link_section == section_name);
if !matches {
continue;
}
let bytes = section
.uncompressed_data()
.context("Could not read uncompressed data from object file")?;
let mut buffer = const_serialize::ConstReadBuffer::new(&bytes);
while let Some((remaining_buffer, asset)) =
const_serialize::deserialize_const!(BundledAsset, buffer)
{
self.assets
.insert(asset.absolute_source_path().into(), asset);
buffer = remaining_buffer;
}
}
Ok(())
}
}