use crate::formats::archive;
use crate::formats::archive::BinArchive;
use crate::compression::{CompressionProvider, LZ13CompressionProvider};
use crate::filesystem::FilesystemLayer;
use crate::filesystem::{FE14PathLocalizer, PathLocalizer};
use crate::model::Language;
use anyhow::{anyhow, Result};
pub struct LayeredFilesystem {
compression_provider: Box<dyn CompressionProvider>,
path_localizer: Box<dyn PathLocalizer>,
layers: Vec<Box<dyn FilesystemLayer>>,
language: Language,
}
impl LayeredFilesystem {
pub fn create_fe14_filesystem(
layers: Vec<Box<dyn FilesystemLayer>>,
language: Language,
) -> Self {
LayeredFilesystem {
compression_provider: Box::new(LZ13CompressionProvider {}),
path_localizer: Box::new(FE14PathLocalizer {}),
layers,
language,
}
}
pub fn localize_path(&self, filename: &str) -> Result<String> {
self.path_localizer.localize_path(filename, &self.language)
}
pub fn is_compressed_file_path(&self, filename: &str) -> bool {
self.compression_provider.is_compressed_filename(filename)
}
pub fn open(&self, filename: &str) -> Result<Vec<u8>> {
for layer in self.layers.iter().rev() {
if layer.exists(filename) {
let contents = layer.open(filename)?;
if self.is_compressed_file_path(filename) {
let decompressed_contents = self.compression_provider.decompress(&contents)?;
return Ok(decompressed_contents);
} else {
return Ok(contents);
}
}
}
Err(anyhow!("File {} does not exist in any layer", filename))
}
pub fn save(&self, filename: &str, bytes: &[u8]) -> Result<()> {
let layer = self
.layers
.first()
.ok_or(anyhow!("LayeredFilesystem has no layers"))?;
if filename.ends_with(".lz") {
let compressed_contents = self.compression_provider.compress(bytes)?;
layer.save(filename, &compressed_contents)
} else {
layer.save(filename, bytes)
}
}
pub fn open_archive(&self, filename: &str) -> Result<BinArchive> {
let bytes = self.open(&filename)?;
archive::from_bytes(&bytes)
}
pub fn save_archive(&self, filename: &str, archive: &mut BinArchive) -> Result<()> {
let raw_archive = archive.serialize()?;
self.save(filename, &raw_archive)
}
pub fn open_archive_localized(&self, filename: &str) -> Result<BinArchive> {
let localized_path = self.localize_path(filename)?;
self.open_archive(&localized_path)
}
pub fn save_archive_localized(&self, filename: &str, archive: &mut BinArchive) -> Result<()> {
let localized_path = self.localize_path(filename)?;
self.save_archive(&localized_path, archive)
}
}