use serde::{Deserialize, Serialize};
use super::Parsable;
use thiserror::Error;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Resource {
pub images: Vec<ResourceItem>,
pub sounds: Vec<ResourceItem>,
pub fonts: Vec<ResourceItem>,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum ResourceSection {
Images,
Sounds,
Fonts,
None,
}
impl Parsable for Resource {
type ParseError = ResourceParseError;
type ReconstructionError = ResourceReconstructionError;
fn parse(decrypted_content: &str) -> Result<Self, Self::ParseError> {
let mut iterator = decrypted_content.split("\n");
let mut cur_section = ResourceSection::None;
let mut result = Resource { images: vec![], sounds: vec![], fonts: vec![] };
let mut line_count = 0u32;
loop {
let line = iterator.next();
if line.is_none() { break; }
let line = line.unwrap();
if line == "@images" {
cur_section = ResourceSection::Images;
} else if line == "@sounds" {
cur_section = ResourceSection::Sounds;
} else if line == "@fonts" {
cur_section = ResourceSection::Fonts
} else if cur_section != ResourceSection::None {
if line.is_empty() { break; }
let resource_item = ResourceItem::parse(line)
.map_err(|err| ResourceParseError::ResourceItemParseError {
source: err,
section: cur_section,
line: line_count
})?;
if cur_section == ResourceSection::Images {
&mut result.images
} else if cur_section == ResourceSection::Sounds {
&mut result.sounds
} else if cur_section == ResourceSection::Fonts {
&mut result.fonts
} else { break }
.push(resource_item)
}
line_count += 1;
}
Ok(result)
}
fn reconstruct(&self) -> Result<String, Self::ReconstructionError> {
Ok(format!(
"@images\n{}@sounds\n{}@fonts\n{}",
self.images
.iter()
.try_fold(String::new(), |acc, i|
Ok(format!("{}{}\n", acc, i.reconstruct()
.map_err(|err| ResourceReconstructionError::ResourceItemReconstructionError {
source: err,
section: ResourceSection::Images,
item: i.to_owned()
})?))
)?,
self.sounds
.iter()
.try_fold(String::new(), |acc, i|
Ok(format!("{}{}\n", acc, i.reconstruct()
.map_err(|err| ResourceReconstructionError::ResourceItemReconstructionError {
source: err,
section: ResourceSection::Sounds,
item: i.to_owned()
})?))
)?,
self.fonts
.iter()
.try_fold(String::new(), |acc, i|
Ok(format!("{}{}\n", acc, i.reconstruct()
.map_err(|err| ResourceReconstructionError::ResourceItemReconstructionError {
source: err,
section: ResourceSection::Fonts,
item: i.to_owned()
})?))
)?
.trim(), ))
}
}
#[derive(Error, Debug)]
pub enum ResourceParseError {
#[error("error while parsing a resource item of {section:?} at line {line}")]
ResourceItemParseError {
#[source]
source: serde_json::Error,
section: ResourceSection,
line: u32
}
}
#[derive(Error, Debug)]
pub enum ResourceReconstructionError {
#[error("error while reconstruction resource item `{item:?}` of section {section:?}")]
ResourceItemReconstructionError {
#[source]
source: serde_json::Error,
section: ResourceSection,
item: ResourceItem
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
pub struct ResourceItem {
#[serde(rename = "resFullName")]
pub full_name: String,
#[serde(rename = "resName")]
pub name: String,
#[serde(rename = "resType")]
pub r#type: u8,
}
impl Parsable for ResourceItem {
type ParseError = serde_json::Error;
type ReconstructionError = serde_json::Error;
fn parse(decrypted_content: &str) -> Result<Self, Self::ParseError> {
serde_json::from_str(decrypted_content)
}
fn reconstruct(&self) -> Result<String, Self::ReconstructionError> {
serde_json::to_string(self)
}
}