1use alloc::vec;
2use alloc::vec::Vec;
3use core::ffi::CStr;
4
5use crate::BlockRead;
6use crate::ByteOrder;
7use crate::Class;
8use crate::ElfRead;
9use crate::ElfWrite;
10use crate::Error;
11
12#[cfg_attr(test, derive(Debug, PartialEq, Eq))]
16pub struct StringTable(Vec<u8>);
17
18impl StringTable {
19 pub fn new() -> Self {
21 Self(vec![0])
23 }
24
25 pub fn insert(&mut self, string: &CStr) -> usize {
31 if let Some(offset) = self.get_offset(string) {
32 return offset;
33 }
34 debug_assert!(!self.0.is_empty());
35 let offset = self.0.len();
36 self.0.extend_from_slice(string.to_bytes_with_nul());
37 offset
38 }
39
40 pub fn get_offset(&self, string: &CStr) -> Option<usize> {
44 debug_assert!(!self.0.is_empty());
45 let string = string.to_bytes_with_nul();
46 let mut j = 0;
47 let n = string.len();
48 for i in 0..self.0.len() {
49 if self.0[i] == string[j] {
50 j += 1;
51 if j == n {
52 return Some(i + 1 - n);
53 }
54 } else {
55 j = 0;
56 }
57 }
58 None
59 }
60
61 pub fn get_string(&self, offset: usize) -> Option<&CStr> {
65 let c_str_bytes = self.0.get(offset..)?;
66 CStr::from_bytes_until_nul(c_str_bytes).ok()
67 }
68
69 pub fn is_empty(&self) -> bool {
71 self.0.iter().all(|b| *b == 0)
72 }
73
74 pub fn as_bytes(&self) -> &[u8] {
78 self.0.as_slice()
79 }
80
81 pub fn into_inner(self) -> Vec<u8> {
83 self.0
84 }
85
86 pub fn read<R: ElfRead>(reader: &mut R, len: u64) -> Result<Self, Error> {
88 let mut strings = vec![0_u8; len as usize];
89 reader.read_bytes(&mut strings[..])?;
90 Ok(Self(strings))
91 }
92
93 pub fn write<W: ElfWrite>(&self, writer: &mut W) -> Result<(), Error> {
95 writer.write_bytes(self.as_bytes())
96 }
97}
98
99impl From<Vec<u8>> for StringTable {
100 fn from(mut strings: Vec<u8>) -> Self {
101 if strings.is_empty() {
102 return Self::new();
103 }
104 if strings.first().copied() != Some(0) {
105 strings.insert(0, 0);
106 }
107 if strings.last().copied() != Some(0) {
108 strings.push(0);
109 }
110 Self(strings)
111 }
112}
113
114impl BlockRead for StringTable {
115 fn read<R: ElfRead>(
116 reader: &mut R,
117 _class: Class,
118 _byte_order: ByteOrder,
119 len: u64,
120 ) -> Result<Self, Error> {
121 StringTable::read(reader, len)
122 }
123}
124
125impl AsRef<[u8]> for StringTable {
126 fn as_ref(&self) -> &[u8] {
127 self.as_bytes()
128 }
129}
130
131impl Default for StringTable {
132 fn default() -> Self {
133 Self::new()
134 }
135}
136
137impl<T: AsRef<CStr>> FromIterator<T> for StringTable {
138 fn from_iter<I>(items: I) -> Self
139 where
140 I: IntoIterator<Item = T>,
141 {
142 let mut strings: Vec<u8> = Vec::new();
143 strings.push(0_u8);
144 for item in items.into_iter() {
145 strings.extend_from_slice(item.as_ref().to_bytes_with_nul());
146 }
147 Self(strings)
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154 use alloc::ffi::CString;
155 use arbitrary::Arbitrary;
156 use arbitrary::Unstructured;
157 use arbtest::arbtest;
158
159 use crate::test::test_block_io;
160
161 #[test]
162 fn test_get_offset() {
163 assert_eq!(
164 Some(1),
165 StringTable::from(b"hello\0".to_vec()).get_offset(c"hello")
166 );
167 assert_eq!(
168 Some(1),
169 StringTable::from(b"\0hello\0".to_vec()).get_offset(c"hello")
170 );
171 assert_eq!(
172 Some(7),
173 StringTable::from(b"\0first\0hello\0".to_vec()).get_offset(c"hello")
174 );
175 assert_eq!(None, StringTable::from(b"".to_vec()).get_offset(c"hello"));
176 assert_eq!(Some(0), StringTable::from(b"".to_vec()).get_offset(c""));
177 assert_eq!(Some(0), StringTable::from(b"abc".to_vec()).get_offset(c""));
178 assert_eq!(
179 Some(0),
180 StringTable::from(b"\0abc".to_vec()).get_offset(c"")
181 );
182 }
183
184 #[test]
185 fn test_symmetry() {
186 test_get_string(b"hello\0", c"hello");
187 test_get_string(b"\0abc", c"");
188 }
189
190 fn test_get_string(strings: &[u8], expected: &CStr) {
191 let table: StringTable = strings.to_vec().into();
192 let offset = table.get_offset(expected).unwrap();
193 let actual = table.get_string(offset).unwrap();
194 assert_eq!(expected, actual);
195 }
196
197 #[test]
198 fn test_get_offset_get_string_symmetry() {
199 arbtest(|u| {
200 let strings: Vec<CString> = u.arbitrary()?;
201 let mut table: StringTable = Default::default();
202 assert_eq!(Some(0), table.0.last().copied());
203 for s in strings.iter() {
204 table.insert(s);
205 assert_eq!(Some(0), table.0.last().copied());
206 }
207 for s in strings.iter() {
208 let offset = table.get_offset(s).unwrap();
209 let actual = table.get_string(offset).unwrap();
210 assert_eq!(s.as_ref(), actual);
211 }
212 Ok(())
213 });
214 }
215
216 #[test]
217 fn string_table_io() {
218 test_block_io::<StringTable>();
219 }
220
221 impl<'a> Arbitrary<'a> for StringTable {
222 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
223 let strings: Vec<CString> = u.arbitrary()?;
224 Ok(strings.into_iter().collect())
225 }
226 }
227}