aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-02-10 13:49:31 +0100
committermetamuffin <metamuffin@disroot.org>2025-02-10 13:49:31 +0100
commit3dade4b3815db7bfa1baf3fbb4fb332b29aba363 (patch)
tree690ef5c0ddb552b50ec295d39714cc46938ab6d8 /src
parentd786df60b89e52c5e4a605f95c677f4bce4c6ec3 (diff)
downloadunity-tools-3dade4b3815db7bfa1baf3fbb4fb332b29aba363.tar
unity-tools-3dade4b3815db7bfa1baf3fbb4fb332b29aba363.tar.bz2
unity-tools-3dade4b3815db7bfa1baf3fbb4fb332b29aba363.tar.zst
first type tree read
Diffstat (limited to 'src')
-rw-r--r--src/common_strings.rs109
-rw-r--r--src/helper.rs15
-rw-r--r--src/lib.rs1
-rw-r--r--src/main.rs91
4 files changed, 194 insertions, 22 deletions
diff --git a/src/common_strings.rs b/src/common_strings.rs
new file mode 100644
index 0000000..d893c6f
--- /dev/null
+++ b/src/common_strings.rs
@@ -0,0 +1,109 @@
+pub const COMMON_STRINGS: &[u8] = b"AABB\0\
+AnimationClip\0\
+AnimationCurve\0\
+AnimationState\0\
+Array\0\
+Base\0\
+BitField\0\
+bitset\0\
+bool\0\
+char\0\
+ColorRGBA\0\
+Component\0\
+data\0\
+deque\0\
+double\0\
+dynamic_array\0\
+FastPropertyName\0\
+first\0\
+float\0\
+Font\0\
+GameObject\0\
+Generic Mono\0\
+GradientNEW\0\
+GUID\0\
+GUIStyle\0\
+int\0\
+list\0\
+long long\0\
+map\0\
+Matrix4x4f\0\
+MdFour\0\
+MonoBehaviour\0\
+MonoScript\0\
+m_ByteSize\0\
+m_Curve\0\
+m_EditorClassIdentifier\0\
+m_EditorHideFlags\0\
+m_Enabled\0\
+m_ExtensionPtr\0\
+m_GameObject\0\
+m_Index\0\
+m_IsArray\0\
+m_IsStatic\0\
+m_MetaFlag\0\
+m_Name\0\
+m_ObjectHideFlags\0\
+m_PrefabInternal\0\
+m_PrefabParentObject\0\
+m_Script\0\
+m_StaticEditorFlags\0\
+m_Type\0\
+m_Version\0\
+Object\0\
+pair\0\
+PPtr<Component>\0\
+PPtr<GameObject>\0\
+PPtr<Material>\0\
+PPtr<MonoBehaviour>\0\
+PPtr<MonoScript>\0\
+PPtr<Object>\0\
+PPtr<Prefab>\0\
+PPtr<Sprite>\0\
+PPtr<TextAsset>\0\
+PPtr<Texture>\0\
+PPtr<Texture2D>\0\
+PPtr<Transform>\0\
+Prefab\0\
+Quaternionf\0\
+Rectf\0\
+RectInt\0\
+RectOffset\0\
+second\0\
+set\0\
+short\0\
+size\0\
+SInt16\0\
+SInt32\0\
+SInt64\0\
+SInt8\0\
+staticvector\0\
+string\0\
+TextAsset\0\
+TextMesh\0\
+Texture\0\
+Texture2D\0\
+Transform\0\
+TypelessData\0\
+UInt16\0\
+UInt32\0\
+UInt64\0\
+UInt8\0\
+unsigned int\0\
+unsigned long long\0\
+unsigned short\0\
+vector\0\
+Vector2f\0\
+Vector3f\0\
+Vector4f\0\
+m_ScriptingClassIdentifier\0\
+Gradient\0\
+Type*\0\
+int2_storage\0\
+int3_storage\0\
+BoundsInt\0\
+m_CorrespondingSourceObject\0\
+m_PrefabInstance\0\
+m_PrefabAsset\0\
+FileSize\0\
+Hash128";
diff --git a/src/helper.rs b/src/helper.rs
index c2b9a92..0b126ad 100644
--- a/src/helper.rs
+++ b/src/helper.rs
@@ -8,6 +8,8 @@ pub enum Endianness {
pub trait ReadExt {
fn read_u8(&mut self) -> Result<u8>;
+ fn read_u16(&mut self, e: Endianness) -> Result<u16>;
+ fn read_u16_le(&mut self) -> Result<u16>;
fn read_u16_be(&mut self) -> Result<u16>;
fn read_i16(&mut self, e: Endianness) -> Result<i16>;
fn read_i16_be(&mut self) -> Result<i16>;
@@ -26,15 +28,26 @@ pub trait ReadExt {
}
impl<T: Read> ReadExt for T {
fn read_u8(&mut self) -> Result<u8> {
- let mut buf = [0; 2];
+ let mut buf = [0; 1];
self.read_exact(&mut buf)?;
Ok(buf[0])
}
+ fn read_u16(&mut self, e: Endianness) -> Result<u16> {
+ match e {
+ Endianness::Big => self.read_u16_be(),
+ Endianness::Little => self.read_u16_le(),
+ }
+ }
fn read_u16_be(&mut self) -> Result<u16> {
let mut buf = [0; 2];
self.read_exact(&mut buf)?;
Ok(u16::from_be_bytes(buf))
}
+ fn read_u16_le(&mut self) -> Result<u16> {
+ let mut buf = [0; 2];
+ self.read_exact(&mut buf)?;
+ Ok(u16::from_le_bytes(buf))
+ }
fn read_i16(&mut self, e: Endianness) -> Result<i16> {
match e {
Endianness::Big => self.read_i16_be(),
diff --git a/src/lib.rs b/src/lib.rs
index eed5b02..d2370b3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,2 +1,3 @@
pub mod unityfs;
pub mod helper;
+pub mod common_strings;
diff --git a/src/main.rs b/src/main.rs
index c1dcfd2..a0b35c3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,9 +2,10 @@ use log::debug;
use std::{
env::args,
fs::File,
- io::{BufReader, Read},
+ io::{BufReader, Cursor, Read},
};
use unity_tools::{
+ common_strings::COMMON_STRINGS,
helper::{Endianness, ReadExt},
unityfs::UnityFS,
};
@@ -20,7 +21,7 @@ fn main() -> anyhow::Result<()> {
}
let mut cab = fs.read(&node)?;
// let mut writer = File::create(format!("/tmp/{}", node.name))?;
- // copy(&mut cab, &mut writer)?;
+ // std::io::copy(&mut cab, &mut writer)?;
// continue;
let mut metadata_size = cab.read_u32_be()?;
@@ -54,39 +55,74 @@ fn main() -> anyhow::Result<()> {
let has_type_trees = cab.read_u8()? != 0;
let num_types = cab.read_u32(e)?;
+ debug!("has_type_trees={has_type_trees:?}");
+ debug!("num_types={num_types}");
for _ in 0..num_types {
- let mut class_id = cab.read_i32(e)?;
+ let class_id = cab.read_i32(e)?;
let stripped_type = cab.read_u8()? != 0;
- let script_id = cab.read_i16(e)?;
+ let script_index = cab.read_i16(e)?;
+ let mut script_id = 0;
+ // TODO reftype
if class_id == 114 {
- if script_id >= 0 {
- class_id = -2 - script_id as i32;
- } else {
- class_id = -1;
- }
+ script_id = cab.read_u128_be()?;
}
+ let _old_hash = cab.read_u128_be()?;
+
eprintln!("class_id={class_id}");
eprintln!("stripped_type={stripped_type}");
+ eprintln!("script_index={script_index}");
eprintln!("script_id={script_id}");
- let hash = if class_id < 0 {
- (cab.read_u128_be()?, cab.read_u128_be()?)
- } else {
- (cab.read_u128_be()?, 0)
- };
- eprintln!("{hash:032x?}");
-
if has_type_trees {
let num_nodes = cab.read_u32(e)?;
- eprintln!("tree:num_nodes={num_nodes}");
let size = cab.read_u32(e)?;
- assert!(format >= 19);
+ eprintln!("tree:num_nodes={num_nodes}");
+ eprintln!("tree:size={size}");
+
+ let mut node_data = vec![0u8; num_nodes as usize * 32];
+ cab.read_exact(&mut node_data)?;
+ let mut node_data = Cursor::new(node_data);
+ let mut string_data = vec![0u8; size as usize];
+ cab.read_exact(&mut string_data)?;
+
+ let get_string = |off: u32| {
+ let data = if off & 0x80000000 != 0 {
+ let off = off & 0x7fffffff;
+ &COMMON_STRINGS[(off & 0x7fffffff) as usize..]
+ } else {
+ &string_data[off as usize..]
+ };
+ String::from_utf8(
+ data.iter()
+ .copied()
+ .take_while(|e| *e != 0)
+ .collect::<Vec<u8>>(),
+ )
+ };
+
+ let mut nodes = Vec::new();
for _ in 0..num_nodes {
- cab.read_u32(e)?;
+ nodes.push(TypeTreeNode {
+ version: node_data.read_u16(e)?,
+ level: node_data.read_u8()?,
+ type_flags: node_data.read_u8()?,
+ type_string: get_string(node_data.read_u32(e)?)?,
+ name_string: get_string(node_data.read_u32(e)?)?,
+ byte_size: node_data.read_i32(e)?,
+ index: node_data.read_i32(e)?,
+ flags: node_data.read_i32(e)?,
+ ref_type_hash: node_data.read_u64(e)?,
+ });
+ }
+ eprintln!("{nodes:#?}");
+
+ if format >= 21 {
+ let num_deps = cab.read_u32(e)?;
+ for _ in 0..num_deps {
+ cab.read_u32(e)?;
+ }
}
- let mut data = vec![0u8; size as usize];
- cab.read_exact(&mut data)?;
}
if format > 21 {
@@ -101,3 +137,16 @@ fn main() -> anyhow::Result<()> {
Ok(())
}
+
+#[derive(Debug)]
+struct TypeTreeNode {
+ version: u16,
+ level: u8,
+ type_flags: u8,
+ type_string: String,
+ name_string: String,
+ byte_size: i32,
+ index: i32,
+ flags: i32,
+ ref_type_hash: u64,
+}