1use std::borrow::Borrow;
3use std::io;
4use types::{Error, ParseHexError};
5
6#[inline]
10pub fn intoval(c: u8) -> Result<u8, ParseHexError> {
11 match c {
26 b'A'...b'F' => Ok(c - b'A' + 10),
27 b'a'...b'f' => Ok(c - b'a' + 10),
28 b'0'...b'9' => Ok(c - b'0'),
29 _ => {
30 let val = c as char;
31 Err(ParseHexError::Char { val })
32 }
33 }
34}
35
36#[inline]
39pub fn fromval(val: u8) -> u8 {
40 match val {
41 0xa...0xf => val - 0xa + b'a',
42 0x0...0x9 => val + b'0',
43 _ => panic!("value outside range 0x0...0xf"),
44 }
45}
46
47#[inline]
50pub fn fromvalcaps(val: u8) -> u8 {
51 match val {
52 0xA...0xF => val - 0xa + b'A',
53 0x0...0x9 => val + b'0',
54 _ => panic!("value outside range 0x0...0xf"),
55 }
56}
57
58#[inline]
61pub fn intobyte(a: u8, b: u8) -> Result<u8, ParseHexError> {
62 Ok(intoval(a)? << 4 | intoval(b)?)
63}
64
65#[inline]
67fn frombyte(val: u8) -> (u8, u8) {
68 (fromval(val >> 4), fromval(val & 0x0f))
69}
70
71#[inline]
73pub fn frombytecaps(val: u8) -> (u8, u8) {
74 (fromvalcaps(val >> 4), fromvalcaps(val & 0x0f))
75}
76
77pub fn fromhex(buf: &mut [u8], src: &[u8]) -> Result<(), ParseHexError> {
82 let expect = buf.len() * 2;
83 let actual = src.len();
84 if expect == actual {
85 for (idx, pair) in src.chunks(2).enumerate() {
86 buf[idx] = intobyte(pair[0], pair[1])?;
87 }
88 Ok(())
89 } else {
90 Err(ParseHexError::Size { expect, actual })
91 }
92}
93
94pub fn intohex(buf: &mut [u8], src: &[u8]) {
100 if buf.len() == src.len() * 2 {
101 for (i, byte) in src.iter().enumerate() {
102 let (a, b) = frombyte(*byte);
103 let idx = i * 2;
104 buf[idx] = a;
105 buf[idx + 1] = b;
106 }
107 } else {
108 panic!("invalid buffer sizes");
109 }
110}
111
112pub fn intohexcaps(buf: &mut [u8], src: &[u8]) {
118 if buf.len() == src.len() * 2 {
119 for (i, byte) in src.iter().enumerate() {
120 let (a, b) = frombytecaps(*byte);
121 let idx = i * 2;
122 buf[idx] = a;
123 buf[idx + 1] = b;
124 }
125 } else {
126 panic!("invalid buffer sizes");
127 }
128}
129
130pub fn writehex<S, B, D>(src: S, mut dst: D) -> Result<(), Error>
133where
134 S: IntoIterator<Item = B>,
135 B: Borrow<u8>,
136 D: io::Write,
137{
138 for byte in src.into_iter() {
139 let (a, b) = frombyte(*byte.borrow());
140 dst.write_all(&[a, b])?;
141 }
142 Ok(())
143}
144
145pub fn writehexcaps<S, B, D>(src: S, mut dst: D) -> Result<(), Error>
148where
149 S: IntoIterator<Item = B>,
150 B: Borrow<u8>,
151 D: io::Write,
152{
153 for byte in src.into_iter() {
154 let (a, b) = frombytecaps(*byte.borrow());
155 dst.write_all(&[a, b])?;
156 }
157 Ok(())
158}
159
160#[cfg(test)]
161mod tests {
162 #[test]
163 fn hex_bytes() {
164 use utils::{frombyte, intobyte};
165 for i in 0..255u8 {
166 let h = frombyte(i);
167 let b = intobyte(h.0, h.1).unwrap();
168 assert_eq!(i, b);
169 }
170 let hex = ["ff", "aa", "f0", "a0", "0f", "0a", "00", "99", "90", "09"];
171 for s in hex.iter() {
172 let s: &[u8] = s.as_ref();
173 let v = intobyte(s[0], s[1]).unwrap();
174 let (a, b) = frombyte(v);
175 assert_eq!(s, &[a, b]);
176 }
177 }
178
179 #[test]
180 fn hex_strings() {
181 use utils::{fromhex, intohex};
182 let hv = [
183 "ff",
184 "aa",
185 "f0f0",
186 "a0a0",
187 "1234",
188 "5678",
189 "0000",
190 "0123456789abfdef",
191 ];
192 for hs in hv.iter() {
193 let src: &[u8] = hs.as_ref();
194 let mut buff = vec![0u8; src.len() / 2];
195 let mut rslt = vec![0u8; buff.len() * 2];
196 fromhex(&mut buff, src).unwrap();
197 intohex(&mut rslt, &buff);
198 assert_eq!(src, AsRef::<[u8]>::as_ref(&rslt));
199 }
200 }
201}