use std::collections::BTreeMap;
use std::io::{Cursor, SeekFrom, Write};
use crate::binary::{ReadBytes, WriteBytes};
use crate::compression::{Compressible, CompressionFormat, Decompressible};
use crate::error::{RLibError, Result};
use super::*;
impl ESF {
pub(crate) fn read_cbab<R: ReadBytes>(&mut self, data: &mut R) -> Result<()> {
self.unknown_1 = data.read_u32()?;
self.creation_date = data.read_u32()?;
let record_names_offset = data.read_u32()?;
let nodes_offset = data.stream_position()?;
data.seek(SeekFrom::Start(record_names_offset as u64))?;
let record_names_count = data.read_u16()?;
let mut record_names = vec![];
for _ in 0..record_names_count {
record_names.push(data.read_sized_string_u8()?);
}
let strings_count_utf16 = data.read_u32()?;
let mut strings_utf16 = BTreeMap::new();
for _ in 0..strings_count_utf16 {
let name = data.read_sized_string_u16_u32()?;
let index = data.read_u32()?;
strings_utf16.insert(index, name);
}
let strings_count_utf8 = data.read_u32()?;
let mut strings_utf8 = BTreeMap::new();
for _ in 0..strings_count_utf8 {
let name = data.read_sized_string_u8_u32()?;
let index = data.read_u32()?;
strings_utf8.insert(index, name);
}
let data_len = data.len()?;
let curr_pos = data.stream_position()?;
if curr_pos != data_len {
return Err(RLibError::DecodingMismatchSizeError(data_len as usize, curr_pos as usize));
}
data.seek(SeekFrom::Start(nodes_offset))?;
self.root_node = Self::read_node(data, true, &record_names, &strings_utf8, &strings_utf16)?;
let curr_pos = data.stream_position()?;
if curr_pos != record_names_offset as u64 {
return Err(RLibError::DecodingMismatchSizeError(record_names_offset as usize, curr_pos as usize));
}
if let NodeType::Record(ref mut node) = self.root_node {
if let Some(child) = node.children_mut().get_mut(0) {
if let Some(NodeType::Record(cnode)) = child.last_mut() {
if cnode.name == COMPRESSED_DATA_TAG {
let mut dec_data = vec![];
if let Some(NodeType::U8Array(data)) = cnode.children()[0].first() {
if let Some(NodeType::Record(hnode)) = cnode.children()[0].get(1) {
if hnode.name == COMPRESSED_DATA_INFO_TAG {
if let Some(NodeType::U32(len)) = hnode.children()[0].first() {
if let Some(NodeType::U8Array(magic_number)) = hnode.children()[0].get(1) {
let mut mdata = vec![];
mdata.write_u32(*len.value())?;
mdata.write_all(magic_number)?;
mdata.write_all(data)?;
dec_data = mdata.as_slice().decompress()?;
}
}
}
}
}
if !dec_data.is_empty() {
let mut dec_datac = Cursor::new(dec_data.clone());
let new_esf = ESF::decode(&mut dec_datac, &None)?;
*self = new_esf;
}
}
}
}
}
Ok(())
}
pub(crate) fn save_cbab<W: WriteBytes>(&mut self, buffer: &mut W, extra_data: &Option<EncodeableExtraData>) -> Result<()> {
let mut extra_data = extra_data.clone().unwrap_or_default();
let disable_compression = extra_data.disable_compression;
let backup = self.clone();
let mut revert_compression = false;
let mut index = None;
if !disable_compression {
if let NodeType::Record(ref root_node) = self.root_node {
for (i1, parent) in root_node.children().iter().enumerate() {
for (i2, child) in parent.iter().enumerate() {
if let NodeType::Record(ref cnode) = child {
if COMPRESSED_TAGS.contains(&&*cnode.name) {
index = Some((i1, i2));
break;
}
}
}
}
}
if let Some((i1, i2)) = index {
let mut ncdata = vec![];
extra_data.disable_compression = true;
self.encode(&mut ncdata, &Some(extra_data))?;
revert_compression = true;
let mut fdata = ncdata.compress(CompressionFormat::Lzma1)?;
let cdata = fdata.split_off(9);
let mut hdata = Cursor::new(fdata);
let hnode = RecordNode {
record_flags: RecordNodeFlags::IS_RECORD_NODE,
version: 0,
name: COMPRESSED_DATA_INFO_TAG.to_owned(),
children: vec![vec![
NodeType::U32(U32Node {
value: hdata.read_i32()? as u32,
optimized: false,
}),
NodeType::U8Array(hdata.read_slice(5, false)?),
]],
};
let cnode = RecordNode {
record_flags: RecordNodeFlags::IS_RECORD_NODE,
version: 0,
name: COMPRESSED_DATA_TAG.to_owned(),
children: vec![vec![
NodeType::U8Array(cdata),
NodeType::Record(Box::new(hnode)),
]],
};
if let NodeType::Record(ref mut root_node) = self.root_node {
if let Some(parent) = root_node.children_mut().get_mut(i1) {
if let Some(child) = parent.get_mut(i2) {
*child = NodeType::Record(Box::new(cnode));
}
}
}
}
}
buffer.write_u32(self.unknown_1)?;
buffer.write_u32(self.creation_date)?;
let mut record_names = vec![];
let mut strings_utf8 = vec![];
let mut strings_utf16 = vec![];
Self::read_string_from_node(&self.root_node, &mut record_names, &mut strings_utf8, &mut strings_utf16);
let mut nodes_data = vec![];
Self::save_node(&mut nodes_data, &self.root_node, true, &record_names, &strings_utf8, &strings_utf16)?;
let mut strings_data: Vec<u8> = vec![];
strings_data.write_u16(record_names.len() as u16)?;
for name in record_names {
strings_data.write_sized_string_u8(&name)?;
}
strings_data.write_u32(strings_utf16.len() as u32)?;
for (index, string) in strings_utf16.iter().enumerate() {
strings_data.write_sized_string_u16_u32(string)?;
strings_data.write_u32(index as u32)?;
}
strings_data.write_u32(strings_utf8.len() as u32)?;
for (index, string) in strings_utf8.iter().enumerate() {
strings_data.write_sized_string_u8_u32(string)?;
strings_data.write_u32(index as u32)?;
}
buffer.write_u32((12 + nodes_data.len() + 4) as u32)?;
buffer.write_all(&nodes_data)?;
buffer.write_all(&strings_data)?;
if revert_compression {
*self = backup;
}
Ok(())
}
}