]>
Commit | Line | Data |
---|---|---|
136023e0 | 1 | use alloc::string::String; |
17df50a5 | 2 | use core::convert::TryInto; |
136023e0 XL |
3 | use core::fmt; |
4 | use core::marker::PhantomData; | |
17df50a5 | 5 | |
136023e0 XL |
6 | use crate::pod::{from_bytes, slice_from_bytes, Pod}; |
7 | use crate::ReadRef; | |
8 | ||
9 | /// A newtype for byte slices. | |
10 | /// | |
11 | /// It has these important features: | |
12 | /// - no methods that can panic, such as `Index` | |
13 | /// - convenience methods for `Pod` types | |
14 | /// - a useful `Debug` implementation | |
15 | #[derive(Default, Clone, Copy, PartialEq, Eq)] | |
16 | pub struct Bytes<'data>(pub &'data [u8]); | |
17 | ||
18 | impl<'data> fmt::Debug for Bytes<'data> { | |
19 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { | |
20 | debug_list_bytes(self.0, fmt) | |
21 | } | |
22 | } | |
23 | ||
24 | impl<'data> Bytes<'data> { | |
25 | /// Return the length of the byte slice. | |
26 | #[inline] | |
27 | pub fn len(&self) -> usize { | |
28 | self.0.len() | |
29 | } | |
30 | ||
31 | /// Return true if the byte slice is empty. | |
32 | #[inline] | |
33 | pub fn is_empty(&self) -> bool { | |
34 | self.0.is_empty() | |
35 | } | |
36 | ||
37 | /// Skip over the given number of bytes at the start of the byte slice. | |
38 | /// | |
39 | /// Modifies the byte slice to start after the bytes. | |
40 | /// | |
41 | /// Returns an error if there are too few bytes. | |
42 | #[inline] | |
43 | pub fn skip(&mut self, offset: usize) -> Result<(), ()> { | |
44 | match self.0.get(offset..) { | |
45 | Some(tail) => { | |
46 | self.0 = tail; | |
47 | Ok(()) | |
48 | } | |
49 | None => { | |
50 | self.0 = &[]; | |
51 | Err(()) | |
52 | } | |
53 | } | |
54 | } | |
55 | ||
56 | /// Return a reference to the given number of bytes at the start of the byte slice. | |
57 | /// | |
58 | /// Modifies the byte slice to start after the bytes. | |
59 | /// | |
60 | /// Returns an error if there are too few bytes. | |
61 | #[inline] | |
62 | pub fn read_bytes(&mut self, count: usize) -> Result<Bytes<'data>, ()> { | |
63 | match (self.0.get(..count), self.0.get(count..)) { | |
64 | (Some(head), Some(tail)) => { | |
65 | self.0 = tail; | |
66 | Ok(Bytes(head)) | |
67 | } | |
68 | _ => { | |
69 | self.0 = &[]; | |
70 | Err(()) | |
71 | } | |
72 | } | |
73 | } | |
74 | ||
75 | /// Return a reference to the given number of bytes at the given offset of the byte slice. | |
76 | /// | |
77 | /// Returns an error if the offset is invalid or there are too few bytes. | |
78 | #[inline] | |
79 | pub fn read_bytes_at(mut self, offset: usize, count: usize) -> Result<Bytes<'data>, ()> { | |
80 | self.skip(offset)?; | |
81 | self.read_bytes(count) | |
82 | } | |
83 | ||
84 | /// Return a reference to a `Pod` struct at the start of the byte slice. | |
85 | /// | |
86 | /// Modifies the byte slice to start after the bytes. | |
87 | /// | |
88 | /// Returns an error if there are too few bytes or the slice is incorrectly aligned. | |
89 | #[inline] | |
90 | pub fn read<T: Pod>(&mut self) -> Result<&'data T, ()> { | |
91 | match from_bytes(self.0) { | |
92 | Ok((value, tail)) => { | |
93 | self.0 = tail; | |
94 | Ok(value) | |
95 | } | |
96 | Err(()) => { | |
97 | self.0 = &[]; | |
98 | Err(()) | |
99 | } | |
100 | } | |
101 | } | |
102 | ||
103 | /// Return a reference to a `Pod` struct at the given offset of the byte slice. | |
104 | /// | |
105 | /// Returns an error if there are too few bytes or the offset is incorrectly aligned. | |
106 | #[inline] | |
107 | pub fn read_at<T: Pod>(mut self, offset: usize) -> Result<&'data T, ()> { | |
108 | self.skip(offset)?; | |
109 | self.read() | |
110 | } | |
111 | ||
112 | /// Return a reference to a slice of `Pod` structs at the start of the byte slice. | |
113 | /// | |
114 | /// Modifies the byte slice to start after the bytes. | |
115 | /// | |
116 | /// Returns an error if there are too few bytes or the offset is incorrectly aligned. | |
117 | #[inline] | |
118 | pub fn read_slice<T: Pod>(&mut self, count: usize) -> Result<&'data [T], ()> { | |
119 | match slice_from_bytes(self.0, count) { | |
120 | Ok((value, tail)) => { | |
121 | self.0 = tail; | |
122 | Ok(value) | |
123 | } | |
124 | Err(()) => { | |
125 | self.0 = &[]; | |
126 | Err(()) | |
127 | } | |
128 | } | |
129 | } | |
130 | ||
131 | /// Return a reference to a slice of `Pod` structs at the given offset of the byte slice. | |
132 | /// | |
133 | /// Returns an error if there are too few bytes or the offset is incorrectly aligned. | |
134 | #[inline] | |
135 | pub fn read_slice_at<T: Pod>(mut self, offset: usize, count: usize) -> Result<&'data [T], ()> { | |
136 | self.skip(offset)?; | |
137 | self.read_slice(count) | |
138 | } | |
139 | ||
140 | /// Read a null terminated string. | |
141 | /// | |
142 | /// Does not assume any encoding. | |
143 | /// Reads past the null byte, but doesn't return it. | |
144 | #[inline] | |
145 | pub fn read_string(&mut self) -> Result<&'data [u8], ()> { | |
146 | match memchr::memchr(b'\0', self.0) { | |
147 | Some(null) => { | |
148 | // These will never fail. | |
149 | let bytes = self.read_bytes(null)?; | |
150 | self.skip(1)?; | |
151 | Ok(bytes.0) | |
152 | } | |
153 | None => { | |
154 | self.0 = &[]; | |
155 | Err(()) | |
156 | } | |
157 | } | |
158 | } | |
159 | ||
160 | /// Read a null terminated string at an offset. | |
161 | /// | |
162 | /// Does not assume any encoding. Does not return the null byte. | |
163 | #[inline] | |
164 | pub fn read_string_at(mut self, offset: usize) -> Result<&'data [u8], ()> { | |
165 | self.skip(offset)?; | |
166 | self.read_string() | |
167 | } | |
168 | } | |
169 | ||
170 | // Only for Debug impl of `Bytes`. | |
171 | fn debug_list_bytes(bytes: &[u8], fmt: &mut fmt::Formatter<'_>) -> fmt::Result { | |
172 | let mut list = fmt.debug_list(); | |
173 | list.entries(bytes.iter().take(8).copied().map(DebugByte)); | |
174 | if bytes.len() > 8 { | |
175 | list.entry(&DebugLen(bytes.len())); | |
176 | } | |
177 | list.finish() | |
178 | } | |
179 | ||
180 | struct DebugByte(u8); | |
181 | ||
182 | impl fmt::Debug for DebugByte { | |
183 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { | |
184 | write!(fmt, "0x{:02x}", self.0) | |
185 | } | |
186 | } | |
187 | ||
188 | struct DebugLen(usize); | |
189 | ||
190 | impl fmt::Debug for DebugLen { | |
191 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { | |
192 | write!(fmt, "...; {}", self.0) | |
193 | } | |
194 | } | |
195 | ||
196 | /// A newtype for byte strings. | |
197 | /// | |
198 | /// For byte slices that are strings of an unknown encoding. | |
199 | /// | |
200 | /// Provides a `Debug` implementation that interprets the bytes as UTF-8. | |
201 | #[derive(Default, Clone, Copy, PartialEq, Eq)] | |
202 | pub(crate) struct ByteString<'data>(pub &'data [u8]); | |
203 | ||
204 | impl<'data> fmt::Debug for ByteString<'data> { | |
205 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { | |
206 | write!(fmt, "\"{}\"", String::from_utf8_lossy(self.0)) | |
207 | } | |
208 | } | |
17df50a5 XL |
209 | |
210 | #[allow(dead_code)] | |
211 | #[inline] | |
212 | pub(crate) fn align(offset: usize, size: usize) -> usize { | |
213 | (offset + (size - 1)) & !(size - 1) | |
214 | } | |
215 | ||
216 | #[allow(dead_code)] | |
217 | pub(crate) fn data_range( | |
218 | data: &[u8], | |
219 | data_address: u64, | |
220 | range_address: u64, | |
221 | size: u64, | |
222 | ) -> Option<&[u8]> { | |
223 | let offset = range_address.checked_sub(data_address)?; | |
224 | data.get(offset.try_into().ok()?..)? | |
225 | .get(..size.try_into().ok()?) | |
226 | } | |
227 | ||
228 | /// A table of zero-terminated strings. | |
229 | /// | |
230 | /// This is used for most file formats. | |
136023e0 XL |
231 | #[derive(Debug, Clone, Copy)] |
232 | pub struct StringTable<'data, R = &'data [u8]> | |
233 | where | |
234 | R: ReadRef<'data>, | |
235 | { | |
236 | data: Option<R>, | |
237 | start: u64, | |
238 | end: u64, | |
239 | marker: PhantomData<&'data ()>, | |
17df50a5 XL |
240 | } |
241 | ||
136023e0 | 242 | impl<'data, R: ReadRef<'data>> StringTable<'data, R> { |
17df50a5 | 243 | /// Interpret the given data as a string table. |
136023e0 XL |
244 | pub fn new(data: R, start: u64, end: u64) -> Self { |
245 | StringTable { | |
246 | data: Some(data), | |
247 | start, | |
248 | end, | |
249 | marker: PhantomData, | |
250 | } | |
17df50a5 XL |
251 | } |
252 | ||
253 | /// Return the string at the given offset. | |
254 | pub fn get(&self, offset: u32) -> Result<&'data [u8], ()> { | |
136023e0 XL |
255 | match self.data { |
256 | Some(data) => { | |
257 | let r_start = self.start.checked_add(offset.into()).ok_or(())?; | |
258 | data.read_bytes_at_until(r_start..self.end, 0) | |
259 | } | |
260 | None => Err(()), | |
261 | } | |
262 | } | |
263 | } | |
264 | ||
265 | impl<'data, R: ReadRef<'data>> Default for StringTable<'data, R> { | |
266 | fn default() -> Self { | |
267 | StringTable { | |
268 | data: None, | |
269 | start: 0, | |
270 | end: 0, | |
271 | marker: PhantomData, | |
272 | } | |
273 | } | |
274 | } | |
275 | ||
276 | #[cfg(test)] | |
277 | mod tests { | |
278 | use super::*; | |
279 | use crate::pod::bytes_of; | |
280 | ||
281 | #[test] | |
282 | fn bytes() { | |
283 | let x = u32::to_be(0x0123_4567); | |
284 | let data = Bytes(bytes_of(&x)); | |
285 | ||
286 | let mut bytes = data; | |
287 | assert_eq!(bytes.skip(0), Ok(())); | |
288 | assert_eq!(bytes, data); | |
289 | ||
290 | let mut bytes = data; | |
291 | assert_eq!(bytes.skip(4), Ok(())); | |
292 | assert_eq!(bytes, Bytes(&[])); | |
293 | ||
294 | let mut bytes = data; | |
295 | assert_eq!(bytes.skip(5), Err(())); | |
296 | assert_eq!(bytes, Bytes(&[])); | |
297 | ||
298 | let mut bytes = data; | |
299 | assert_eq!(bytes.read_bytes(0), Ok(Bytes(&[]))); | |
300 | assert_eq!(bytes, data); | |
301 | ||
302 | let mut bytes = data; | |
303 | assert_eq!(bytes.read_bytes(4), Ok(data)); | |
304 | assert_eq!(bytes, Bytes(&[])); | |
305 | ||
306 | let mut bytes = data; | |
307 | assert_eq!(bytes.read_bytes(5), Err(())); | |
308 | assert_eq!(bytes, Bytes(&[])); | |
309 | ||
310 | assert_eq!(data.read_bytes_at(0, 0), Ok(Bytes(&[]))); | |
311 | assert_eq!(data.read_bytes_at(4, 0), Ok(Bytes(&[]))); | |
312 | assert_eq!(data.read_bytes_at(0, 4), Ok(data)); | |
313 | assert_eq!(data.read_bytes_at(1, 4), Err(())); | |
314 | ||
315 | let mut bytes = data; | |
316 | assert_eq!(bytes.read::<u16>(), Ok(&u16::to_be(0x0123))); | |
317 | assert_eq!(bytes, Bytes(&[0x45, 0x67])); | |
318 | assert_eq!(data.read_at::<u16>(2), Ok(&u16::to_be(0x4567))); | |
319 | assert_eq!(data.read_at::<u16>(3), Err(())); | |
320 | assert_eq!(data.read_at::<u16>(4), Err(())); | |
321 | ||
322 | let mut bytes = data; | |
323 | assert_eq!(bytes.read::<u32>(), Ok(&x)); | |
324 | assert_eq!(bytes, Bytes(&[])); | |
325 | ||
326 | let mut bytes = data; | |
327 | assert_eq!(bytes.read::<u64>(), Err(())); | |
328 | assert_eq!(bytes, Bytes(&[])); | |
329 | ||
330 | let mut bytes = data; | |
331 | assert_eq!(bytes.read_slice::<u8>(0), Ok(&[][..])); | |
332 | assert_eq!(bytes, data); | |
333 | ||
334 | let mut bytes = data; | |
335 | assert_eq!(bytes.read_slice::<u8>(4), Ok(data.0)); | |
336 | assert_eq!(bytes, Bytes(&[])); | |
337 | ||
338 | let mut bytes = data; | |
339 | assert_eq!(bytes.read_slice::<u8>(5), Err(())); | |
340 | assert_eq!(bytes, Bytes(&[])); | |
341 | ||
342 | assert_eq!(data.read_slice_at::<u8>(0, 0), Ok(&[][..])); | |
343 | assert_eq!(data.read_slice_at::<u8>(4, 0), Ok(&[][..])); | |
344 | assert_eq!(data.read_slice_at::<u8>(0, 4), Ok(data.0)); | |
345 | assert_eq!(data.read_slice_at::<u8>(1, 4), Err(())); | |
346 | ||
347 | let data = Bytes(&[0x01, 0x02, 0x00, 0x04]); | |
348 | ||
349 | let mut bytes = data; | |
350 | assert_eq!(bytes.read_string(), Ok(&data.0[..2])); | |
351 | assert_eq!(bytes.0, &data.0[3..]); | |
352 | ||
353 | let mut bytes = data; | |
354 | bytes.skip(3).unwrap(); | |
355 | assert_eq!(bytes.read_string(), Err(())); | |
356 | assert_eq!(bytes.0, &[]); | |
357 | ||
358 | assert_eq!(data.read_string_at(0), Ok(&data.0[..2])); | |
359 | assert_eq!(data.read_string_at(1), Ok(&data.0[1..2])); | |
360 | assert_eq!(data.read_string_at(2), Ok(&[][..])); | |
361 | assert_eq!(data.read_string_at(3), Err(())); | |
362 | } | |
363 | ||
364 | #[test] | |
365 | fn bytes_debug() { | |
366 | assert_eq!(format!("{:?}", Bytes(&[])), "[]"); | |
367 | assert_eq!(format!("{:?}", Bytes(&[0x01])), "[0x01]"); | |
368 | assert_eq!( | |
369 | format!( | |
370 | "{:?}", | |
371 | Bytes(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]) | |
372 | ), | |
373 | "[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]" | |
374 | ); | |
375 | assert_eq!( | |
376 | format!( | |
377 | "{:?}", | |
378 | Bytes(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09]) | |
379 | ), | |
380 | "[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, ...; 9]" | |
381 | ); | |
17df50a5 XL |
382 | } |
383 | } |