nx_pkg4/
node.rs

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
19/// A node in an NX file.
20pub struct NxNode<'a> {
21    pub(crate) data: NxNodeData,
22    pub(crate) file: &'a NxFile,
23}
24
25impl<'a> NxNode<'a> {
26    /// Gets a node with the given name starting from the current node.
27    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    /// Gets the name of the node.
67    pub fn name(&self) -> Result<&str, NxError> {
68        self.file.get_str(self.data.name)
69    }
70
71    /// Gets the data type of the node.
72    pub fn data_type(&self) -> NxNodeType {
73        self.data.data_type
74    }
75
76    /// Gets a bitmap from a node.
77    pub fn bitmap(&self) -> Result<Option<NxBitmap>, NxError> {
78        match self.data.data_type {
79            NxNodeType::Bitmap => {
80                // Data is a u64 that we need to reinterpret as a u32 (index), and two u16's
81                // (width and height).
82                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    /// Gets an iterator over the node's children.
107    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/// The type of a node.
121#[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
180/// A node iterator.
181pub 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                // Get the next child node.
206                // It's position will be the current node's position + the size of a node.
207                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}