1use core::str;
2
3use node::NxNodeData;
4use thiserror::Error;
5
6pub use self::file::NxFile;
7pub use self::node::{Node, NxNode, NxNodeIterator, NxNodeType};
8
9pub mod file;
10pub mod node;
11
12#[derive(Error, Debug)]
14pub enum NxError {
15 #[error("failed to load nx file")]
16 Io(#[from] std::io::Error),
17
18 #[error("the file's header is invalid")]
19 InvalidHeader,
20
21 #[error("{0} is out of bounds")]
22 OutOfBoundsIndex(usize),
23
24 #[error("{0}..{1} is out of bounds")]
25 OutOfBoundsRange(usize, usize),
26
27 #[error("invalid cast")]
28 InvalidCast(#[from] core::array::TryFromSliceError),
29
30 #[error("invalid string")]
31 InvalidString(#[from] core::str::Utf8Error),
32}
33
34#[derive(Debug)]
35pub struct NxBitmap {
36 pub width: u16,
37 pub height: u16,
38 pub data: Vec<u8>,
39}
40
41pub(crate) trait NxTryGet {
42 fn try_get_bytes(&self, index: u64, len: usize) -> Result<&[u8], NxError>;
43
44 fn try_get_u16(&self, index: u64) -> Result<u16, NxError>;
45
46 fn try_get_u32(&self, index: u64) -> Result<u32, NxError>;
47
48 fn try_get_u64(&self, index: u64) -> Result<u64, NxError>;
49
50 fn try_get_str(&self, index: u64, len: u16) -> Result<&str, NxError>;
51
52 fn try_get_node_data(&self, index: u64) -> Result<NxNodeData, NxError>;
53}
54
55impl NxTryGet for [u8] {
56 fn try_get_bytes(&self, index: u64, len: usize) -> Result<&[u8], NxError> {
57 let usize_index = index as usize;
58 let usize_len = len as usize;
59
60 Ok(self
61 .get(usize_index..usize_index + usize_len)
62 .ok_or(NxError::OutOfBoundsRange(
63 usize_index,
64 usize_index + usize_len,
65 ))?)
66 }
67
68 fn try_get_u16(&self, index: u64) -> Result<u16, NxError> {
69 let bytes = self.try_get_bytes(index, size_of::<u16>())?;
70 Ok(u16::from_le_bytes(bytes.try_into()?))
71 }
72
73 fn try_get_u32(&self, index: u64) -> Result<u32, NxError> {
74 let bytes = self.try_get_bytes(index, size_of::<u32>())?;
75 Ok(u32::from_le_bytes(bytes.try_into()?))
76 }
77
78 fn try_get_u64(&self, index: u64) -> Result<u64, NxError> {
79 let bytes = self.try_get_bytes(index, size_of::<u64>())?;
80 Ok(u64::from_le_bytes(bytes.try_into()?))
81 }
82
83 fn try_get_str(&self, index: u64, len: u16) -> Result<&str, NxError> {
84 let bytes = self.try_get_bytes(index, len as usize)?;
85 Ok(str::from_utf8(bytes)?)
86 }
87
88 fn try_get_node_data(&self, index: u64) -> Result<NxNodeData, NxError> {
89 let usize_index = index as usize;
90 let node_table = self
91 .get(usize_index..)
92 .ok_or(NxError::OutOfBoundsIndex(usize_index))?;
93
94 let name = node_table.try_get_u32(0)?;
95 let children = node_table.try_get_u32(4)?;
96 let count = node_table.try_get_u16(8)?;
97 let data_type = node_table.try_get_u16(10)?.into();
98 let data = node_table.try_get_u64(12)?;
99
100 Ok(NxNodeData {
101 index,
102 name,
103 children,
104 count,
105 data_type,
106 data,
107 })
108 }
109}