nx_pkg4/
lib.rs

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/// An error that occured when reading an NX file.
13#[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}