use byteorder::{LittleEndian, WriteBytesExt};
use failure::{Error, ResultExt};
use crate::model::owned::OwnedBuf;
#[derive(Default, Debug)]
pub struct Arsc {
chunks: Vec<Box<dyn OwnedBuf>>,
}
impl Arsc {
pub fn push_owned(&mut self, chunk: Box<dyn OwnedBuf>) {
self.chunks.push(chunk);
}
pub fn to_vec(&self) -> Result<Vec<u8>, Error> {
let mut out = Vec::new();
let mut inner = Vec::new();
let mut file_size = 0;
for c in &self.chunks {
let encoded_chunk = c.to_vec().context("could not encode a chunk")?;
file_size += encoded_chunk.len();
inner.extend(encoded_chunk);
}
out.write_u16::<LittleEndian>(2)?;
out.write_u16::<LittleEndian>(3 * 4)?;
out.write_u32::<LittleEndian>(file_size as u32)?;
out.write_u32::<LittleEndian>(0)?;
out.extend(inner);
Ok(out)
}
}
#[derive(Default, Debug)]
pub struct Xml {
chunks: Vec<Box<dyn OwnedBuf>>,
}
impl Xml {
pub fn push_owned(&mut self, chunk: Box<dyn OwnedBuf>) {
self.chunks.push(chunk);
}
pub fn into_vec(self) -> Result<Vec<u8>, Error> {
let mut out = Vec::new();
let mut inner = Vec::new();
let mut file_size = 0;
for c in self.chunks {
let encoded_chunk = c.to_vec().context("could not encode a chunk")?;
file_size += encoded_chunk.len();
inner.extend(encoded_chunk);
}
out.write_u16::<LittleEndian>(3)?;
out.write_u16::<LittleEndian>(2 * 4)?;
out.write_u32::<LittleEndian>(file_size as u32)?;
out.extend(inner);
Ok(out)
}
}
#[cfg(test)]
mod tests {
use std::io::Cursor;
use super::{Arsc, Xml};
use crate::{
model::owned::{ResourcesBuf, StringTableBuf},
test::CounterChunkVisitor,
visitor::Executor,
};
#[test]
fn it_can_generate_a_resources_arsc_file_content() {
let arsc = Arsc::default();
let content = arsc.to_vec().unwrap();
let mut visitor = CounterChunkVisitor::default();
assert_eq!(vec![2, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0], content);
Executor::arsc(&content, &mut visitor).unwrap();
assert_eq!(0, visitor.get_count());
}
#[test]
fn it_can_generate_a_resources_arsc_file_content_with_some_chunks() {
let mut arsc = Arsc::default();
arsc.push_owned(Box::new(StringTableBuf::default()));
arsc.push_owned(Box::new(StringTableBuf::default()));
arsc.push_owned(Box::new(ResourcesBuf::default()));
let content = arsc.to_vec().unwrap();
let mut visitor = CounterChunkVisitor::default();
Executor::arsc(&content, &mut visitor).unwrap();
assert_eq!(2, visitor.get_count());
}
#[test]
fn it_can_generate_a_resources_xml_file_content() {
let xml = Xml::default();
let content = xml.into_vec().unwrap();
let mut visitor = CounterChunkVisitor::default();
assert_eq!(vec![3, 0, 8, 0, 0, 0, 0, 0], content);
Executor::xml(Cursor::new(&content), &mut visitor).unwrap();
assert_eq!(0, visitor.get_count());
}
#[test]
fn it_can_generate_a_resources_xml_file_content_with_some_chunks() {
let mut xml = Xml::default();
xml.push_owned(Box::new(StringTableBuf::default()));
xml.push_owned(Box::new(StringTableBuf::default()));
xml.push_owned(Box::new(ResourcesBuf::default()));
let content = xml.into_vec().unwrap();
let mut visitor = CounterChunkVisitor::default();
let _ = Executor::xml(Cursor::new(&content), &mut visitor);
assert_eq!(3, visitor.get_count());
}
}