use crate::cartridge::{Cartridge, CartridgeDTO, CartridgeError, CartridgeManifest}; use std::fs; use std::path::Path; pub struct CartridgeLoader; impl CartridgeLoader { pub fn load(path: impl AsRef) -> Result { let path = path.as_ref(); if !path.exists() { return Err(CartridgeError::NotFound); } if path.is_dir() { DirectoryCartridgeLoader::load(path) } else if path.extension().is_some_and(|ext| ext == "pmc") { PackedCartridgeLoader::load(path) } else { Err(CartridgeError::InvalidFormat) } } } pub struct DirectoryCartridgeLoader; impl DirectoryCartridgeLoader { pub fn load(path: &Path) -> Result { let manifest_path = path.join("manifest.json"); if !manifest_path.exists() { return Err(CartridgeError::InvalidManifest); } let manifest_content = fs::read_to_string(manifest_path).map_err(|_| CartridgeError::IoError)?; let manifest: CartridgeManifest = serde_json::from_str(&manifest_content).map_err(|_| CartridgeError::InvalidManifest)?; // Additional validation as per requirements if manifest.magic != "PMTU" { return Err(CartridgeError::InvalidManifest); } if manifest.cartridge_version != 1 { return Err(CartridgeError::UnsupportedVersion); } let program_path = path.join("program.pbc"); if !program_path.exists() { return Err(CartridgeError::MissingProgram); } let program = fs::read(program_path).map_err(|_| CartridgeError::IoError)?; let assets_pa_path = path.join("assets.pa"); let assets = if assets_pa_path.exists() { fs::read(assets_pa_path).map_err(|_| CartridgeError::IoError)? } else { Vec::new() }; let dto = CartridgeDTO { app_id: manifest.app_id, title: manifest.title, app_version: manifest.app_version, app_mode: manifest.app_mode, entrypoint: manifest.entrypoint, program, assets, asset_table: manifest.asset_table, preload: manifest.preload, }; Ok(Cartridge::from(dto)) } } pub struct PackedCartridgeLoader; impl PackedCartridgeLoader { pub fn load(_path: &Path) -> Result { Err(CartridgeError::InvalidFormat) } }