1use std::cmp::Ordering;
2
3use lz4_flex::decompress;
4
5use crate::{file::NxFile, NxBitmap, NxError, NxTryGet};
6
7const NX_NODE_OFFSET: u64 = 20;
8
9#[derive(Copy, Clone)]
10pub(crate) struct NxNodeData {
11 pub(crate) index: u64,
12 pub(crate) name: u32,
13 pub(crate) children: u32,
14 pub(crate) count: u16,
15 pub(crate) data_type: NxNodeType,
16 pub(crate) data: u64,
17}
18
19pub struct NxNode<'a> {
21 pub(crate) data: NxNodeData,
22 pub(crate) file: &'a NxFile,
23}
24
25impl<'a> NxNode<'a> {
26 fn get(&self, name: &str) -> Option<NxNode> {
28 let mut index = self.file.header.node_offset + self.data.children as u64 * NX_NODE_OFFSET;
29 let mut count = self.data.count as u64;
30
31 while count > 0 {
32 let middle = count / 2;
33
34 let current = match self
35 .file
36 .data
37 .try_get_node_data(index + (middle * NX_NODE_OFFSET))
38 {
39 Ok(node) => node,
40 Err(_) => return None,
41 };
42
43 let current_name = match self.file.get_str(current.name) {
44 Ok(name) => name,
45 Err(_) => return None,
46 };
47
48 match current_name.cmp(name) {
49 Ordering::Less => {
50 index = current.index + NX_NODE_OFFSET;
51 count -= middle + 1;
52 }
53 Ordering::Equal => {
54 return Some(NxNode {
55 data: current,
56 file: self.file,
57 });
58 }
59 Ordering::Greater => count = middle,
60 }
61 }
62
63 None
64 }
65
66 pub fn name(&self) -> Result<&str, NxError> {
68 self.file.get_str(self.data.name)
69 }
70
71 pub fn data_type(&self) -> NxNodeType {
73 self.data.data_type
74 }
75
76 pub fn bitmap(&self) -> Result<Option<NxBitmap>, NxError> {
78 match self.data.data_type {
79 NxNodeType::Bitmap => {
80 let bytes = self.data.data.to_le_bytes();
83
84 let index = u32::from_le_bytes(bytes[0..4].try_into()?);
85 let width = u16::from_le_bytes(bytes[4..6].try_into()?);
86 let height = u16::from_le_bytes(bytes[6..8].try_into()?);
87
88 let data = decompress(
89 self.file.get_bitmap(index)?,
90 width as usize * height as usize * size_of::<u32>(),
91 )
92 .unwrap();
93
94 let bitmap = NxBitmap {
95 width,
96 height,
97 data,
98 };
99
100 Ok(Some(bitmap))
101 }
102 _ => Ok(None),
103 }
104 }
105
106 pub fn iter(&self) -> Result<NxNodeIterator, NxError> {
108 let data = self.file.data.try_get_node_data(
109 self.file.header.node_offset + self.data.children as u64 * NX_NODE_OFFSET,
110 )?;
111
112 Ok(NxNodeIterator {
113 data,
114 file: self.file,
115 count: self.data.count as usize,
116 })
117 }
118}
119
120#[derive(PartialEq, Eq, Clone, Copy, Debug)]
122pub enum NxNodeType {
123 Empty,
124 Integer,
125 Float,
126 String,
127 Vector,
128 Bitmap,
129 Audio,
130 Invalid(u16),
131}
132
133impl From<u16> for NxNodeType {
134 fn from(value: u16) -> Self {
135 match value {
136 0 => Self::Empty,
137 1 => Self::Integer,
138 2 => Self::Float,
139 3 => Self::String,
140 4 => Self::Vector,
141 5 => Self::Bitmap,
142 6 => Self::Audio,
143 _ => Self::Invalid(value),
144 }
145 }
146}
147
148pub trait Node {
149 fn get(&self, name: &str) -> Option<NxNode>;
150
151 fn bitmap(&self) -> Result<Option<NxBitmap>, NxError>;
152}
153
154impl<'a> Node for NxNode<'a> {
155 fn get(&self, name: &str) -> Option<NxNode> {
156 self.get(name)
157 }
158
159 fn bitmap(&self) -> Result<Option<NxBitmap>, NxError> {
160 self.bitmap()
161 }
162}
163
164impl<'a> Node for Option<NxNode<'a>> {
165 fn get(&self, name: &str) -> Option<NxNode> {
166 match self {
167 Some(node) => node.get(name),
168 None => None,
169 }
170 }
171
172 fn bitmap(&self) -> Result<Option<NxBitmap>, NxError> {
173 match self {
174 Some(node) => node.bitmap(),
175 None => Ok(None),
176 }
177 }
178}
179
180pub struct NxNodeIterator<'a> {
182 data: NxNodeData,
183 file: &'a NxFile,
184 count: usize,
185}
186
187impl<'a> Iterator for NxNodeIterator<'a> {
188 type Item = NxNode<'a>;
189
190 fn size_hint(&self) -> (usize, Option<usize>) {
191 (self.count, Some(self.count))
192 }
193
194 fn next(&mut self) -> Option<NxNode<'a>> {
195 match self.count {
196 0 => None,
197 _ => {
198 self.count -= 1;
199
200 let node = NxNode {
201 data: self.data,
202 file: self.file,
203 };
204
205 let next = match self
208 .file
209 .data
210 .try_get_node_data(self.data.index + NX_NODE_OFFSET)
211 {
212 Ok(node) => node,
213 Err(_) => return None,
214 };
215
216 self.data = next;
217 Some(node)
218 }
219 }
220 }
221}