1use crate::structures::Header;
6use zx_status::Status;
7
8#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
10pub struct StringTable<'a> {
11 data: &'a [u8],
12}
13
14impl<'a> StringTable<'a> {
15 pub const fn empty() -> Self {
17 Self { data: &[] }
18 }
19
20 pub fn init(hdr: &Header, max_struct_len: usize, raw_data: &'a [u8]) -> Result<Self, Status> {
23 let hdr_len = hdr.length as usize;
24 if hdr_len > max_struct_len || hdr_len > raw_data.len() {
25 return Err(Status::IO_DATA_INTEGRITY);
26 }
27
28 let available_len = core::cmp::min(max_struct_len, raw_data.len()) - hdr_len;
29 if available_len < 2 {
31 return Err(Status::IO_DATA_INTEGRITY);
32 }
33
34 let string_bytes = &raw_data[hdr_len..hdr_len + available_len];
35
36 if string_bytes[0] == 0 && string_bytes[1] == 0 {
38 return Ok(Self { data: &string_bytes[..2] });
39 }
40
41 let start_idx = if string_bytes[0] == 0 { 1 } else { 0 };
42 let mut i = start_idx;
43
44 while i < available_len {
45 let remaining = &string_bytes[i..];
46 let len = remaining.iter().position(|&b| b == 0).unwrap_or(remaining.len());
47
48 if len == 0 {
49 let table_len = i + 1; return Ok(Self { data: &string_bytes[..table_len] });
51 }
52
53 i += len + 1;
57 }
58
59 Err(Status::IO_DATA_INTEGRITY)
60 }
61
62 pub fn length(&self) -> usize {
64 self.data.len()
65 }
66
67 pub fn is_empty(&self) -> bool {
69 self.data.is_empty() || (self.data.len() == 2 && self.data[0] == 0 && self.data[1] == 0)
70 }
71
72 pub fn get_string(&self, mut idx: usize) -> Result<&str, Status> {
78 if idx == 0 {
79 return Ok("<null>");
80 }
81
82 let mut i = 0;
83 while i < self.data.len() {
84 let remaining = &self.data[i..];
85 let len = remaining.iter().position(|&b| b == 0).unwrap_or(remaining.len());
86
87 if len == 0 {
88 if i != 0 {
89 return Err(Status::NOT_FOUND);
90 }
91
92 if self.data.len() - i < 2 {
93 return Err(Status::IO_DATA_INTEGRITY);
94 }
95 if self.data[i + 1] == 0 {
96 return Err(Status::NOT_FOUND);
97 }
98 }
99
100 if idx == 1 {
101 let str_bytes = &self.data[i..i + len];
102 return core::str::from_utf8(str_bytes).map_err(|_| Status::IO_DATA_INTEGRITY);
103 }
104
105 idx -= 1;
106 i += len + 1;
107 }
108
109 Err(Status::NOT_FOUND)
110 }
111
112 pub fn get_string_or_default(&self, idx: usize) -> &str {
115 self.get_string(idx).unwrap_or("<missing string>")
116 }
117
118 pub fn dump<W: core::fmt::Write>(&self, writer: &mut W) -> core::fmt::Result {
120 let mut i = 1;
121 while let Ok(str_val) = self.get_string(i) {
122 writeln!(writer, " str {}: {}", i, str_val)?;
123 i += 1;
124 }
125 Ok(())
126 }
127}