1use core::fmt::Write;
8
9#[inline(never)]
18unsafe fn unsanitized_copy(src: *const u8, dest: *mut u8, chunk_len: usize) {
19 for i in 0..chunk_len {
20 unsafe {
21 *dest.add(i) = *src.add(i);
22 }
23 }
24}
25
26pub fn hexdump_very_ex_rs<W: Write>(
31 writer: &mut W,
32 data: &[u8],
33 disp_addr: u64,
34) -> core::fmt::Result {
35 unsafe { hexdump_very_ex_raw(writer, data.as_ptr(), data.len(), disp_addr) }
37}
38
39pub unsafe fn hexdump_very_ex_raw<W: Write>(
46 writer: &mut W,
47 ptr: *const u8,
48 len: usize,
49 disp_addr: u64,
50) -> core::fmt::Result {
51 for count in (0..len).step_by(16) {
52 let chunk_len = core::cmp::min(len - count, 16);
53 let s = chunk_len.next_multiple_of(4);
55
56 let mut buf = [0u8; 16];
58 unsafe {
60 unsanitized_copy(ptr.add(count), buf.as_mut_ptr(), chunk_len);
61 }
62
63 if disp_addr + len as u64 > 0xFFFFFFFF {
64 core::write!(writer, "0x{:016x}: ", disp_addr + count as u64)?;
65 } else {
66 core::write!(writer, "0x{:08x}: ", disp_addr + count as u64)?;
67 }
68
69 let words = s / 4;
70 let (chunks, _) = buf[..s].as_chunks::<4>();
71 for chunk in chunks {
72 let val = u32::from_ne_bytes(*chunk);
75 core::write!(writer, "{:08x} ", val)?;
76 }
77 for _ in words..4 {
78 core::write!(writer, " ")?;
79 }
80 core::write!(writer, "|")?;
81
82 for (i, &c) in buf.iter().enumerate() {
83 if i < s && (c.is_ascii_graphic() || c == b' ') {
84 core::write!(writer, "{}", c as char)?;
85 } else {
86 core::write!(writer, ".")?;
87 }
88 }
89 core::writeln!(writer, "|")?;
90 }
91 Ok(())
92}
93
94pub fn hexdump8_very_ex_rs<W: Write>(
97 writer: &mut W,
98 data: &[u8],
99 disp_addr: u64,
100) -> core::fmt::Result {
101 unsafe { hexdump8_very_ex_raw(writer, data.as_ptr(), data.len(), disp_addr) }
103}
104
105pub unsafe fn hexdump8_very_ex_raw<W: Write>(
112 writer: &mut W,
113 ptr: *const u8,
114 len: usize,
115 disp_addr: u64,
116) -> core::fmt::Result {
117 for count in (0..len).step_by(16) {
118 let chunk_len = core::cmp::min(len - count, 16);
119
120 let mut buf = [0u8; 16];
122 unsafe {
124 unsanitized_copy(ptr.add(count), buf.as_mut_ptr(), chunk_len);
125 }
126
127 if disp_addr + len as u64 > 0xFFFFFFFF {
128 core::write!(writer, "0x{:016x}: ", disp_addr + count as u64)?;
129 } else {
130 core::write!(writer, "0x{:08x}: ", disp_addr + count as u64)?;
131 }
132
133 for &b in &buf[..chunk_len] {
134 core::write!(writer, "{:02x} ", b)?;
135 }
136 for _ in chunk_len..16 {
137 core::write!(writer, " ")?;
138 }
139
140 core::write!(writer, "|")?;
141
142 for &c in &buf[..chunk_len] {
143 if c.is_ascii_graphic() || c == b' ' {
144 core::write!(writer, "{}", c as char)?;
145 } else {
146 core::write!(writer, ".")?;
147 }
148 }
149 core::writeln!(writer)?;
150 }
151 Ok(())
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157 extern crate std;
158 use std::string::String;
159
160 #[test]
161 fn test_hexdump_very_ex() {
162 let input = [0u8, 1, 2, 3, b'a', b'b', b'c', b'd'];
163 let test_display_addr = 0x1000;
164 let expected = "0x00001000: 03020100 64636261 |....abcd........|\n";
165
166 let mut output = String::new();
167 hexdump_very_ex_rs(&mut output, &input, test_display_addr).unwrap();
168 assert_eq!(output, expected);
169 }
170
171 #[test]
172 fn test_hexdump_very_ex_raw() {
173 let input = [0u8, 1, 2, 3, b'a', b'b', b'c', b'd'];
174 let test_display_addr = 0x1000;
175 let expected = "0x00001000: 03020100 64636261 |....abcd........|\n";
176
177 let mut output = String::new();
178 unsafe {
180 hexdump_very_ex_raw(&mut output, input.as_ptr(), input.len(), test_display_addr)
181 .unwrap();
182 }
183 assert_eq!(output, expected);
184 }
185
186 #[test]
187 fn test_hexdump8_very_ex() {
188 let input = [0u8, 1, 2, 3, b'a', b'b', b'c', b'd'];
189 let test_display_addr = 0x1000;
190 let expected = "0x00001000: 00 01 02 03 61 62 63 64 |....abcd\n";
191
192 let mut output = String::new();
193 hexdump8_very_ex_rs(&mut output, &input, test_display_addr).unwrap();
194 assert_eq!(output, expected);
195 }
196
197 #[test]
198 fn test_hexdump8_very_ex_raw() {
199 let input = [0u8, 1, 2, 3, b'a', b'b', b'c', b'd'];
200 let test_display_addr = 0x1000;
201 let expected = "0x00001000: 00 01 02 03 61 62 63 64 |....abcd\n";
202
203 let mut output = String::new();
204 unsafe {
206 hexdump8_very_ex_raw(&mut output, input.as_ptr(), input.len(), test_display_addr)
207 .unwrap();
208 }
209 assert_eq!(output, expected);
210 }
211}