#![allow(clippy::redundant_closure_call)]
use crate::commonstring::COMMONSTRING;
use crate::read_ext::ReadSeekUrexExt;
use crate::read_ext::ReadUrexExt;
use bitflags::bitflags;
use byteorder::{ByteOrder, ReadBytesExt};
use rmp;
use std::io::{Read, Seek, Write};
bitflags! {
struct TransferMetaFlags: i32 {
const NO_TRANSFER_FLAGS = 0;
const HIDE_IN_EDITOR_MASK = 1 << 0;
const NOT_EDITABLE_MASK = 1 << 4;
const STRONG_PPTR_MASK = 1 << 6;
const EDITOR_DISPLAYS_CHECK_BOX_MASK = 1 << 8;
const SIMPLE_EDITOR_MASK = 1 << 11;
const DEBUG_PROPERTY_MASK = 1 << 12;
const ALIGN_BYTES_FLAG = 1 << 14;
const ANY_CHILD_USES_ALIGN_BYTES_FLAG = 1 << 15;
const IGNORE_WITH_INSPECTOR_UNDO_MASK = 1 << 16;
const IGNORE_IN_META_FILES = 1 << 19;
const TRANSFER_AS_ARRAY_ENTRY_NAME_IN_META_FILES = 1 << 20;
const TRANSFER_USING_FLOW_MAPPING_STYLE = 1 << 21;
const GENERATE_BITWISE_DIFFERENCES = 1 << 22;
const DONT_ANIMATE = 1 << 23;
}
}
macro_rules! generate_read_as {
($format: expr, $result: ty, $conv_i8: expr, $conv_u8: expr, $conv_i16: expr, $conv_u16: expr, $conv_i32: expr, $conv_u32: expr, $conv_i64: expr, $conv_u64: expr, $conv_f32: expr, $conv_f64: expr, $conv_bool: expr, $conv_str: expr, $conv_bytes: expr, $conv_map: expr, $conv_array: expr, $conv_cls: expr) => {
paste::item! {
#[doc = "Parses the data as of the object into the " $format "."]
pub fn [< read_as_ $format >]<R: Read + Seek, B: ByteOrder> (&self, reader: &mut R,) -> Result<$result, std::io::Error>{
let mut align = self.requires_align();
let value: $result = match self.m_Type.as_str() {
"SInt8" => {
$conv_i8(reader.read_i8().unwrap())
}
"UInt8" => {
$conv_u8(reader.read_u8().unwrap())
}
"char" => {
$conv_str((reader.read_u8().unwrap() as char).to_string())
}
"SInt16" | "short" => {
$conv_i16(reader.read_i16::<B>().unwrap())
}
"UInt16" | "unsigned short" => {
$conv_u16(reader.read_u16::<B>().unwrap())
}
"SInt32" | "int" => {
$conv_i32(reader.read_i32::<B>().unwrap())
}
"UInt32" | "unsigned int" | "Type*" => {
$conv_u32(reader.read_u32::<B>().unwrap())
}
"SInt64" | "long long" => {
$conv_i64(reader.read_i64::<B>().unwrap())
}
"UInt64" | "unsigned long long" | "FileSize" => {
$conv_u64(reader.read_u64::<B>().unwrap())
}
"float" => {
$conv_f32(reader.read_f32::<B>().unwrap())
}
"double" => {
$conv_f64(reader.read_f64::<B>().unwrap())
}
"bool" => {
$conv_bool(reader.read_bool().unwrap())
}
"string" => {
align |= &self.children[0].requires_align();
$conv_str(reader.read_string::<B>().unwrap())
}
"TypelessData" => $conv_bytes(&reader.read_bytes::<B>().unwrap()),
"map" => {
let size = reader.read_array_len::<B>().unwrap();
let pair = &self.children[0].children[1];
align |= pair.requires_align();
let first = &pair.children[0];
let second = &pair.children[1];
$conv_map(reader, size, first, second)
}
default => {
if self.children.len() == 1 && self.children[0].m_Type == "Array" {
let array = &self.children[0];
align |= array.requires_align();
let size = reader.read_array_len::<B>().unwrap();
let array_node = &array.children[1];
$conv_array(reader, size, array_node)
} else {
$conv_cls(reader, &self.children)
}
}
};
if align {
reader.align4()?;
}
Ok(value)
}
}
};
}
#[derive(Debug, Clone)]
pub struct TypeTreeNode {
m_Version: i32,
m_Level: u8,
m_TypeFlags: i32,
m_ByteSize: i32,
m_Index: Option<i32>,
m_MetaFlag: Option<i32>,
m_Type: String,
m_Name: String,
m_RefTypeHash: Option<u64>,
m_VariableCount: Option<i32>,
children: Vec<TypeTreeNode>,
}
impl TypeTreeNode {
pub fn from_reader<R: std::io::Read + std::io::Seek, B: ByteOrder>(
reader: &mut R,
version: u32,
) -> Result<TypeTreeNode, std::io::Error> {
fn read_node_base<R: std::io::Read + std::io::Seek, B: ByteOrder>(
reader: &mut R,
version: u32,
level: u8,
) -> Result<TypeTreeNode, std::io::Error> {
let mut node = TypeTreeNode {
m_Level: level,
m_Type: reader.read_cstr().unwrap(),
m_Name: reader.read_cstr().unwrap(),
m_ByteSize: reader.read_i32::<B>().unwrap(),
m_VariableCount: if version == 2 {
Some(reader.read_i32::<B>().unwrap())
} else {
None
},
m_Index: if version != 3 {
Some(reader.read_i32::<B>().unwrap())
} else {
None
},
m_TypeFlags: reader.read_i32::<B>().unwrap(),
m_Version: reader.read_i32::<B>().unwrap(),
m_MetaFlag: if version != 3 {
Some(reader.read_i32::<B>().unwrap())
} else {
None
},
m_RefTypeHash: None,
children: Vec::new(),
};
let children_count = reader.read_i32::<B>().unwrap();
node.children = (0..children_count)
.map(|_| read_node_base::<R, B>(reader, version, node.m_Level + 1).unwrap())
.collect();
Ok(node)
}
Ok(read_node_base::<R, B>(reader, version, 0).unwrap())
}
pub fn blob_from_reader<R: std::io::Read + std::io::Seek, B: ByteOrder>(
reader: &mut R,
version: u32,
) -> Result<TypeTreeNode, std::io::Error> {
let node_size = if version >= 19 { 32 } else { 24 };
let node_count = reader.read_i32::<B>()?;
let string_buffer_size = reader.read_i32::<B>()?;
let mut node_reader = std::io::Cursor::new(
reader.read_bytes_sized(node_size as usize * node_count as usize)?,
);
let mut string_buffer_reader =
std::io::Cursor::new(reader.read_bytes_sized(string_buffer_size as usize)?);
fn read_string<R: std::io::Read + std::io::Seek, B: ByteOrder>(
string_buffer_reader: &mut R,
value: u32,
) -> Result<String, std::io::Error> {
let isOffset = (value & 0x80000000) == 0;
if isOffset {
string_buffer_reader
.seek(std::io::SeekFrom::Start(value as u64))
.unwrap();
return string_buffer_reader.read_cstr();
}
let offset = value & 0x7FFFFFFF;
let ret = COMMONSTRING.get(&offset);
if let Some(ret) = ret {
Ok(ret.to_string())
} else {
Ok(offset.to_string())
}
}
let nodes: Vec<TypeTreeNode> = (0..node_count)
.map(|_| TypeTreeNode {
m_Version: node_reader.read_u16::<B>().unwrap() as i32,
m_Level: node_reader.read_u8().unwrap(),
m_TypeFlags: node_reader.read_u8().unwrap() as i32,
m_Type: read_string::<std::io::Cursor<Vec<u8>>, B>(
&mut string_buffer_reader,
node_reader.read_u32::<B>().unwrap(),
)
.unwrap(),
m_Name: read_string::<std::io::Cursor<Vec<u8>>, B>(
&mut string_buffer_reader,
node_reader.read_u32::<B>().unwrap(),
)
.unwrap(),
m_ByteSize: node_reader.read_i32::<B>().unwrap(),
m_Index: Some(node_reader.read_i32::<B>().unwrap()),
m_MetaFlag: Some(node_reader.read_i32::<B>().unwrap()),
m_RefTypeHash: if version >= 19 {
Some(node_reader.read_u64::<B>().unwrap())
} else {
None
},
children: Vec::new(),
m_VariableCount: None,
})
.collect();
fn add_children(parent: &mut TypeTreeNode, nodes: &[TypeTreeNode], offset: usize) -> i32 {
let mut added: i32 = 0;
for i in (offset + 1)..nodes.len() {
let mut node = nodes[i].clone();
if node.m_Level == parent.m_Level + 1 {
added += add_children(&mut node, nodes, i) + 1;
parent.children.push(node.clone());
} else if node.m_Level <= parent.m_Level {
break;
}
}
added
}
let mut root_node = nodes[0].clone();
let added = add_children(&mut root_node, &nodes, 0);
if added != node_count - 1 {
println!("Warning: not all nodes were added to the tree");
}
Ok(root_node)
}
fn requires_align(&self) -> bool {
(self.m_MetaFlag.unwrap_or(0) & TransferMetaFlags::ALIGN_BYTES_FLAG.bits()) != 0
}
generate_read_as!(
json,
serde_json::Value,
|x: i8| serde_json::Value::Number(serde_json::Number::from(x)),
|x: u8| serde_json::Value::Number(serde_json::Number::from(x)),
|x: i16| serde_json::Value::Number(serde_json::Number::from(x)),
|x: u16| serde_json::Value::Number(serde_json::Number::from(x)),
|x: i32| serde_json::Value::Number(serde_json::Number::from(x)),
|x: u32| serde_json::Value::Number(serde_json::Number::from(x)),
|x: i64| serde_json::Value::Number(serde_json::Number::from(x)),
|x: u64| serde_json::Value::Number(serde_json::Number::from(x)),
|x: f32| serde_json::Value::Number(serde_json::Number::from_f64(x as f64).unwrap()),
|x: f64| serde_json::Value::Number(serde_json::Number::from_f64(x).unwrap()),
serde_json::Value::Bool,
serde_json::Value::String,
(|x: &[u8]| serde_json::Value::Array(
x.iter()
.map(|y| serde_json::Value::Number(serde_json::Number::from(*y)))
.collect()
)),
(|reader: &mut R, size: usize, first: &TypeTreeNode, second: &TypeTreeNode| {
serde_json::Value::Array(
(0..size)
.map(|_| {
serde_json::Value::Array(vec![
first.read_as_json::<R, B>(reader).unwrap(),
second.read_as_json::<R, B>(reader).unwrap(),
])
})
.collect(),
)
}),
(|reader: &mut R, size: usize, array_node: &TypeTreeNode| {
serde_json::Value::Array(
(0..size)
.map(|_| array_node.read_as_json::<R, B>(reader).unwrap())
.collect(),
)
}),
|reader: &mut R, children: &[TypeTreeNode]| {
let mut map = serde_json::Map::new();
for child in children {
map.insert(
child.m_Name.clone(),
child.read_as_json::<R, B>(reader).unwrap(),
);
}
serde_json::Value::from(map)
}
);
generate_read_as!(
yaml,
Result<serde_yaml::Value, serde_yaml::Error>,
serde_yaml::to_value,
serde_yaml::to_value,
serde_yaml::to_value,
serde_yaml::to_value,
serde_yaml::to_value,
serde_yaml::to_value,
serde_yaml::to_value,
serde_yaml::to_value,
serde_yaml::to_value,
serde_yaml::to_value,
serde_yaml::to_value,
serde_yaml::to_value,
serde_yaml::to_value,
(|reader: &mut R, size: usize, first: &TypeTreeNode, second: &TypeTreeNode| {
serde_yaml::to_value(
(0..size)
.map(|_| {
serde_yaml::to_value(vec![
first.read_as_yaml::<R, B>(reader).unwrap().unwrap(),
second.read_as_yaml::<R, B>(reader).unwrap().unwrap(),
])
})
.collect::<Result<Vec<serde_yaml::Value>, _>>()?,
)
}),
(|reader: &mut R, size: usize, array_node: &TypeTreeNode| {
serde_yaml::to_value(
(0..size)
.map(|_| array_node.read_as_yaml::<R, B>(reader).unwrap())
.collect::<Result<Vec<serde_yaml::Value>, _>>()?,
)
}),
|reader: &mut R, children: &[TypeTreeNode]| {
let mut map = serde_yaml::Mapping::new();
for child in children {
map.insert(
serde_yaml::Value::String(child.m_Name.clone()),
child.read_as_yaml::<R, B>(reader).unwrap().unwrap()
);
}
serde_yaml::to_value(map)
}
);
#[doc = "Parses the data as of the object into the msgpack."]
pub fn read_as_msgpack<R: Read + Seek, B: ByteOrder>(
&self,
reader: &mut R,
) -> Result<Vec<u8>, std::io::Error> {
let mut buf = std::io::Cursor::new(Vec::new());
self._read_as_msgpack::<R, B, std::io::Cursor<Vec<u8>>>(reader, &mut buf)?;
Ok(buf.into_inner())
}
pub fn _read_as_msgpack<R: Read + Seek, B: ByteOrder, W: Write>(
&self,
reader: &mut R,
writer: &mut W,
) -> Result<(), std::io::Error> {
let mut align = self.requires_align();
match self.m_Type.as_str() {
"SInt8" => rmp::encode::write_i8::<W>(writer, reader.read_i8().unwrap()),
"UInt8" => rmp::encode::write_u8::<W>(writer, reader.read_u8().unwrap()),
"char" => rmp::encode::write_str::<W>(
writer,
(reader.read_u8().unwrap() as char).to_string().as_str(),
),
"SInt16" | "short" => {
rmp::encode::write_i16::<W>(writer, reader.read_i16::<B>().unwrap())
}
"UInt16" | "unsigned short" => {
rmp::encode::write_u16::<W>(writer, reader.read_u16::<B>().unwrap())
}
"SInt32" | "int" => {
rmp::encode::write_i32::<W>(writer, reader.read_i32::<B>().unwrap())
}
"UInt32" | "unsigned int" | "Type*" => {
rmp::encode::write_u32::<W>(writer, reader.read_u32::<B>().unwrap())
}
"SInt64" | "long long" => {
rmp::encode::write_i64::<W>(writer, reader.read_i64::<B>().unwrap())
}
"UInt64" | "unsigned long long" | "FileSize" => {
rmp::encode::write_u64::<W>(writer, reader.read_u64::<B>().unwrap())
}
"bool" => match rmp::encode::write_bool::<W>(writer, reader.read_bool().unwrap()){
Ok(_) => Ok(()),
Err(e) => {
Err(rmp::encode::ValueWriteError::InvalidDataWrite(e))
}
},
"float" => rmp::encode::write_f32::<W>(writer, reader.read_f32::<B>().unwrap()),
"double" => rmp::encode::write_f64::<W>(writer, reader.read_f64::<B>().unwrap()),
"string" => {
align |= &self.children[0].requires_align();
rmp::encode::write_str::<W>(writer, &reader.read_string::<B>().unwrap())
}
"TypelessData" => rmp::encode::write_bin(writer, &reader.read_bytes::<B>().unwrap()),
"map" => {
let size = reader.read_array_len::<B>().unwrap();
let pair = &self.children[0].children[1];
align |= pair.requires_align();
let first = &pair.children[0];
let second = &pair.children[1];
rmp::encode::write_array_len(writer, size as u32).unwrap();
for _ in 0..size {
rmp::encode::write_array_len(writer, 2).unwrap();
first._read_as_msgpack::<R,B,W>(reader, writer)?;
second._read_as_msgpack::<R,B,W>(reader, writer)?;
}
Ok(())
}
default => {
if self.children.len() == 1 && self.children[0].m_Type == "Array" {
let array = &self.children[0];
align |= array.requires_align();
let size = reader.read_array_len::<B>().unwrap();
let array_node = &array.children[1];
rmp::encode::write_array_len(writer, size as u32).unwrap();
for _ in 0..size {
array_node._read_as_msgpack::<R,B,W>(reader, writer)?;
}
Ok(())
} else {
rmp::encode::write_map_len(writer, self.children.len() as u32).unwrap();
for child in &self.children {
rmp::encode::write_str(writer, &child.m_Name).unwrap();
child._read_as_msgpack::<R,B,W>(reader, writer)?;
}
Ok(())
}
}
}
.unwrap();
if align {
reader.align4()?;
}
Ok(())
}
}