1 // Copyright (c) 2013-2014 The Rust Project Developers.
2 // Copyright (c) 2015-2020 The rust-hex Developers.
3 //
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
9 //! Encoding and decoding hex strings.
10 //!
11 //! For most cases, you can simply use the [`decode`], [`encode`] and
12 //! [`encode_upper`] functions. If you need a bit more control, use the traits
13 //! [`ToHex`] and [`FromHex`] instead.
14 //!
15 //! # Example
16 //!
17 //! ```
18 //! # #[cfg(not(feature = "alloc"))]
19 //! # let mut output = [0; 0x18];
20 //! #
21 //! # #[cfg(not(feature = "alloc"))]
22 //! # hex::encode_to_slice(b"Hello world!", &mut output).unwrap();
23 //! #
24 //! # #[cfg(not(feature = "alloc"))]
25 //! # let hex_string = ::core::str::from_utf8(&output).unwrap();
26 //! #
27 //! # #[cfg(feature = "alloc")]
28 //! let hex_string = hex::encode("Hello world!");
29 //!
30 //! println!("{}", hex_string); // Prints "48656c6c6f20776f726c6421"
31 //!
32 //! # assert_eq!(hex_string, "48656c6c6f20776f726c6421");
33 //! ```
34
35 #![doc(html_root_url = "https://docs.rs/hex/0.4.3")]
36 #![cfg_attr(not(feature = "std"), no_std)]
37 #![cfg_attr(docsrs, feature(doc_cfg))]
38 #![allow(clippy::unreadable_literal)]
39
40 #[cfg(feature = "alloc")]
41 extern crate alloc;
42 #[cfg(feature = "alloc")]
43 use alloc::{string::String, vec::Vec};
44
45 use core::iter;
46
47 mod error;
48 pub use crate::error::FromHexError;
49
50 #[cfg(feature = "serde")]
51 #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
52 pub mod serde;
53 #[cfg(feature = "serde")]
54 pub use crate::serde::deserialize;
55 #[cfg(all(feature = "alloc", feature = "serde"))]
56 pub use crate::serde::{serialize, serialize_upper};
57
58 /// Encoding values as hex string.
59 ///
60 /// This trait is implemented for all `T` which implement `AsRef<[u8]>`. This
61 /// includes `String`, `str`, `Vec<u8>` and `[u8]`.
62 ///
63 /// # Example
64 ///
65 /// ```
66 /// use hex::ToHex;
67 ///
68 /// println!("{}", "Hello world!".encode_hex::<String>());
69 /// # assert_eq!("Hello world!".encode_hex::<String>(), "48656c6c6f20776f726c6421".to_string());
70 /// ```
71 ///
72 /// *Note*: instead of using this trait, you might want to use [`encode()`].
73 pub trait ToHex {
74 /// Encode the hex strict representing `self` into the result. Lower case
75 /// letters are used (e.g. `f9b4ca`)
encode_hex<T: iter::FromIterator<char>>(&self) -> T76 fn encode_hex<T: iter::FromIterator<char>>(&self) -> T;
77
78 /// Encode the hex strict representing `self` into the result. Upper case
79 /// letters are used (e.g. `F9B4CA`)
encode_hex_upper<T: iter::FromIterator<char>>(&self) -> T80 fn encode_hex_upper<T: iter::FromIterator<char>>(&self) -> T;
81 }
82
83 const HEX_CHARS_LOWER: &[u8; 16] = b"0123456789abcdef";
84 const HEX_CHARS_UPPER: &[u8; 16] = b"0123456789ABCDEF";
85
86 struct BytesToHexChars<'a> {
87 inner: ::core::slice::Iter<'a, u8>,
88 table: &'static [u8; 16],
89 next: Option<char>,
90 }
91
92 impl<'a> BytesToHexChars<'a> {
new(inner: &'a [u8], table: &'static [u8; 16]) -> BytesToHexChars<'a>93 fn new(inner: &'a [u8], table: &'static [u8; 16]) -> BytesToHexChars<'a> {
94 BytesToHexChars {
95 inner: inner.iter(),
96 table,
97 next: None,
98 }
99 }
100 }
101
102 impl<'a> Iterator for BytesToHexChars<'a> {
103 type Item = char;
104
next(&mut self) -> Option<Self::Item>105 fn next(&mut self) -> Option<Self::Item> {
106 match self.next.take() {
107 Some(current) => Some(current),
108 None => self.inner.next().map(|byte| {
109 let current = self.table[(byte >> 4) as usize] as char;
110 self.next = Some(self.table[(byte & 0x0F) as usize] as char);
111 current
112 }),
113 }
114 }
115
size_hint(&self) -> (usize, Option<usize>)116 fn size_hint(&self) -> (usize, Option<usize>) {
117 let length = self.len();
118 (length, Some(length))
119 }
120 }
121
122 impl<'a> iter::ExactSizeIterator for BytesToHexChars<'a> {
len(&self) -> usize123 fn len(&self) -> usize {
124 let mut length = self.inner.len() * 2;
125 if self.next.is_some() {
126 length += 1;
127 }
128 length
129 }
130 }
131
132 #[inline]
encode_to_iter<T: iter::FromIterator<char>>(table: &'static [u8; 16], source: &[u8]) -> T133 fn encode_to_iter<T: iter::FromIterator<char>>(table: &'static [u8; 16], source: &[u8]) -> T {
134 BytesToHexChars::new(source, table).collect()
135 }
136
137 impl<T: AsRef<[u8]>> ToHex for T {
encode_hex<U: iter::FromIterator<char>>(&self) -> U138 fn encode_hex<U: iter::FromIterator<char>>(&self) -> U {
139 encode_to_iter(HEX_CHARS_LOWER, self.as_ref())
140 }
141
encode_hex_upper<U: iter::FromIterator<char>>(&self) -> U142 fn encode_hex_upper<U: iter::FromIterator<char>>(&self) -> U {
143 encode_to_iter(HEX_CHARS_UPPER, self.as_ref())
144 }
145 }
146
147 /// Types that can be decoded from a hex string.
148 ///
149 /// This trait is implemented for `Vec<u8>` and small `u8`-arrays.
150 ///
151 /// # Example
152 ///
153 /// ```
154 /// use core::str;
155 /// use hex::FromHex;
156 ///
157 /// let buffer = <[u8; 12]>::from_hex("48656c6c6f20776f726c6421")?;
158 /// let string = str::from_utf8(&buffer).expect("invalid buffer length");
159 ///
160 /// println!("{}", string); // prints "Hello world!"
161 /// # assert_eq!("Hello world!", string);
162 /// # Ok::<(), hex::FromHexError>(())
163 /// ```
164 pub trait FromHex: Sized {
165 type Error;
166
167 /// Creates an instance of type `Self` from the given hex string, or fails
168 /// with a custom error type.
169 ///
170 /// Both, upper and lower case characters are valid and can even be
171 /// mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings).
from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error>172 fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error>;
173 }
174
val(c: u8, idx: usize) -> Result<u8, FromHexError>175 fn val(c: u8, idx: usize) -> Result<u8, FromHexError> {
176 match c {
177 b'A'..=b'F' => Ok(c - b'A' + 10),
178 b'a'..=b'f' => Ok(c - b'a' + 10),
179 b'0'..=b'9' => Ok(c - b'0'),
180 _ => Err(FromHexError::InvalidHexCharacter {
181 c: c as char,
182 index: idx,
183 }),
184 }
185 }
186
187 #[cfg(feature = "alloc")]
188 impl FromHex for Vec<u8> {
189 type Error = FromHexError;
190
from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error>191 fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
192 let hex = hex.as_ref();
193 if hex.len() % 2 != 0 {
194 return Err(FromHexError::OddLength);
195 }
196
197 hex.chunks(2)
198 .enumerate()
199 .map(|(i, pair)| Ok(val(pair[0], 2 * i)? << 4 | val(pair[1], 2 * i + 1)?))
200 .collect()
201 }
202 }
203
204 // Helper macro to implement the trait for a few fixed sized arrays. Once Rust
205 // has type level integers, this should be removed.
206 macro_rules! from_hex_array_impl {
207 ($($len:expr)+) => {$(
208 impl FromHex for [u8; $len] {
209 type Error = FromHexError;
210
211 fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
212 let mut out = [0_u8; $len];
213 decode_to_slice(hex, &mut out as &mut [u8])?;
214 Ok(out)
215 }
216 }
217 )+}
218 }
219
220 from_hex_array_impl! {
221 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
222 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
223 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
224 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
225 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
226 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
227 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
228 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
229 160 192 200 224 256 384 512 768 1024 2048 4096 8192 16384 32768
230 }
231
232 #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
233 from_hex_array_impl! {
234 65536 131072 262144 524288 1048576 2097152 4194304 8388608
235 16777216 33554432 67108864 134217728 268435456 536870912
236 1073741824 2147483648
237 }
238
239 #[cfg(target_pointer_width = "64")]
240 from_hex_array_impl! {
241 4294967296
242 }
243
244 /// Encodes `data` as hex string using lowercase characters.
245 ///
246 /// Lowercase characters are used (e.g. `f9b4ca`). The resulting string's
247 /// length is always even, each byte in `data` is always encoded using two hex
248 /// digits. Thus, the resulting string contains exactly twice as many bytes as
249 /// the input data.
250 ///
251 /// # Example
252 ///
253 /// ```
254 /// assert_eq!(hex::encode("Hello world!"), "48656c6c6f20776f726c6421");
255 /// assert_eq!(hex::encode(vec![1, 2, 3, 15, 16]), "0102030f10");
256 /// ```
257 #[must_use]
258 #[cfg(feature = "alloc")]
encode<T: AsRef<[u8]>>(data: T) -> String259 pub fn encode<T: AsRef<[u8]>>(data: T) -> String {
260 data.encode_hex()
261 }
262
263 /// Encodes `data` as hex string using uppercase characters.
264 ///
265 /// Apart from the characters' casing, this works exactly like `encode()`.
266 ///
267 /// # Example
268 ///
269 /// ```
270 /// assert_eq!(hex::encode_upper("Hello world!"), "48656C6C6F20776F726C6421");
271 /// assert_eq!(hex::encode_upper(vec![1, 2, 3, 15, 16]), "0102030F10");
272 /// ```
273 #[must_use]
274 #[cfg(feature = "alloc")]
encode_upper<T: AsRef<[u8]>>(data: T) -> String275 pub fn encode_upper<T: AsRef<[u8]>>(data: T) -> String {
276 data.encode_hex_upper()
277 }
278
279 /// Decodes a hex string into raw bytes.
280 ///
281 /// Both, upper and lower case characters are valid in the input string and can
282 /// even be mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings).
283 ///
284 /// # Example
285 ///
286 /// ```
287 /// assert_eq!(
288 /// hex::decode("48656c6c6f20776f726c6421"),
289 /// Ok("Hello world!".to_owned().into_bytes())
290 /// );
291 ///
292 /// assert_eq!(hex::decode("123"), Err(hex::FromHexError::OddLength));
293 /// assert!(hex::decode("foo").is_err());
294 /// ```
295 #[cfg(feature = "alloc")]
decode<T: AsRef<[u8]>>(data: T) -> Result<Vec<u8>, FromHexError>296 pub fn decode<T: AsRef<[u8]>>(data: T) -> Result<Vec<u8>, FromHexError> {
297 FromHex::from_hex(data)
298 }
299
300 /// Decode a hex string into a mutable bytes slice.
301 ///
302 /// Both, upper and lower case characters are valid in the input string and can
303 /// even be mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings).
304 ///
305 /// # Example
306 ///
307 /// ```
308 /// let mut bytes = [0u8; 4];
309 /// assert_eq!(hex::decode_to_slice("6b697769", &mut bytes as &mut [u8]), Ok(()));
310 /// assert_eq!(&bytes, b"kiwi");
311 /// ```
decode_to_slice<T: AsRef<[u8]>>(data: T, out: &mut [u8]) -> Result<(), FromHexError>312 pub fn decode_to_slice<T: AsRef<[u8]>>(data: T, out: &mut [u8]) -> Result<(), FromHexError> {
313 let data = data.as_ref();
314
315 if data.len() % 2 != 0 {
316 return Err(FromHexError::OddLength);
317 }
318 if data.len() / 2 != out.len() {
319 return Err(FromHexError::InvalidStringLength);
320 }
321
322 for (i, byte) in out.iter_mut().enumerate() {
323 *byte = val(data[2 * i], 2 * i)? << 4 | val(data[2 * i + 1], 2 * i + 1)?;
324 }
325
326 Ok(())
327 }
328
329 // generates an iterator like this
330 // (0, 1)
331 // (2, 3)
332 // (4, 5)
333 // (6, 7)
334 // ...
335 #[inline]
generate_iter(len: usize) -> impl Iterator<Item = (usize, usize)>336 fn generate_iter(len: usize) -> impl Iterator<Item = (usize, usize)> {
337 (0..len).step_by(2).zip((0..len).skip(1).step_by(2))
338 }
339
340 // the inverse of `val`.
341 #[inline]
342 #[must_use]
byte2hex(byte: u8, table: &[u8; 16]) -> (u8, u8)343 fn byte2hex(byte: u8, table: &[u8; 16]) -> (u8, u8) {
344 let high = table[((byte & 0xf0) >> 4) as usize];
345 let low = table[(byte & 0x0f) as usize];
346
347 (high, low)
348 }
349
350 /// Encodes some bytes into a mutable slice of bytes.
351 ///
352 /// The output buffer, has to be able to hold at least `input.len() * 2` bytes,
353 /// otherwise this function will return an error.
354 ///
355 /// # Example
356 ///
357 /// ```
358 /// # use hex::FromHexError;
359 /// # fn main() -> Result<(), FromHexError> {
360 /// let mut bytes = [0u8; 4 * 2];
361 ///
362 /// hex::encode_to_slice(b"kiwi", &mut bytes)?;
363 /// assert_eq!(&bytes, b"6b697769");
364 /// # Ok(())
365 /// # }
366 /// ```
encode_to_slice<T: AsRef<[u8]>>(input: T, output: &mut [u8]) -> Result<(), FromHexError>367 pub fn encode_to_slice<T: AsRef<[u8]>>(input: T, output: &mut [u8]) -> Result<(), FromHexError> {
368 if input.as_ref().len() * 2 != output.len() {
369 return Err(FromHexError::InvalidStringLength);
370 }
371
372 for (byte, (i, j)) in input
373 .as_ref()
374 .iter()
375 .zip(generate_iter(input.as_ref().len() * 2))
376 {
377 let (high, low) = byte2hex(*byte, HEX_CHARS_LOWER);
378 output[i] = high;
379 output[j] = low;
380 }
381
382 Ok(())
383 }
384
385 #[cfg(test)]
386 mod test {
387 use super::*;
388 #[cfg(feature = "alloc")]
389 use alloc::string::ToString;
390 use pretty_assertions::assert_eq;
391
392 #[test]
393 #[cfg(feature = "alloc")]
test_gen_iter()394 fn test_gen_iter() {
395 let result = vec![(0, 1), (2, 3)];
396
397 assert_eq!(generate_iter(5).collect::<Vec<_>>(), result);
398 }
399
400 #[test]
test_encode_to_slice()401 fn test_encode_to_slice() {
402 let mut output_1 = [0; 4 * 2];
403 encode_to_slice(b"kiwi", &mut output_1).unwrap();
404 assert_eq!(&output_1, b"6b697769");
405
406 let mut output_2 = [0; 5 * 2];
407 encode_to_slice(b"kiwis", &mut output_2).unwrap();
408 assert_eq!(&output_2, b"6b69776973");
409
410 let mut output_3 = [0; 100];
411
412 assert_eq!(
413 encode_to_slice(b"kiwis", &mut output_3),
414 Err(FromHexError::InvalidStringLength)
415 );
416 }
417
418 #[test]
test_decode_to_slice()419 fn test_decode_to_slice() {
420 let mut output_1 = [0; 4];
421 decode_to_slice(b"6b697769", &mut output_1).unwrap();
422 assert_eq!(&output_1, b"kiwi");
423
424 let mut output_2 = [0; 5];
425 decode_to_slice(b"6b69776973", &mut output_2).unwrap();
426 assert_eq!(&output_2, b"kiwis");
427
428 let mut output_3 = [0; 4];
429
430 assert_eq!(
431 decode_to_slice(b"6", &mut output_3),
432 Err(FromHexError::OddLength)
433 );
434 }
435
436 #[test]
437 #[cfg(feature = "alloc")]
test_encode()438 fn test_encode() {
439 assert_eq!(encode("foobar"), "666f6f626172");
440 }
441
442 #[test]
443 #[cfg(feature = "alloc")]
test_decode()444 fn test_decode() {
445 assert_eq!(
446 decode("666f6f626172"),
447 Ok(String::from("foobar").into_bytes())
448 );
449 }
450
451 #[test]
452 #[cfg(feature = "alloc")]
test_from_hex_okay_str()453 pub fn test_from_hex_okay_str() {
454 assert_eq!(Vec::from_hex("666f6f626172").unwrap(), b"foobar");
455 assert_eq!(Vec::from_hex("666F6F626172").unwrap(), b"foobar");
456 }
457
458 #[test]
459 #[cfg(feature = "alloc")]
test_from_hex_okay_bytes()460 pub fn test_from_hex_okay_bytes() {
461 assert_eq!(Vec::from_hex(b"666f6f626172").unwrap(), b"foobar");
462 assert_eq!(Vec::from_hex(b"666F6F626172").unwrap(), b"foobar");
463 }
464
465 #[test]
466 #[cfg(feature = "alloc")]
test_invalid_length()467 pub fn test_invalid_length() {
468 assert_eq!(Vec::from_hex("1").unwrap_err(), FromHexError::OddLength);
469 assert_eq!(
470 Vec::from_hex("666f6f6261721").unwrap_err(),
471 FromHexError::OddLength
472 );
473 }
474
475 #[test]
476 #[cfg(feature = "alloc")]
test_invalid_char()477 pub fn test_invalid_char() {
478 assert_eq!(
479 Vec::from_hex("66ag").unwrap_err(),
480 FromHexError::InvalidHexCharacter { c: 'g', index: 3 }
481 );
482 }
483
484 #[test]
485 #[cfg(feature = "alloc")]
test_empty()486 pub fn test_empty() {
487 assert_eq!(Vec::from_hex("").unwrap(), b"");
488 }
489
490 #[test]
491 #[cfg(feature = "alloc")]
test_from_hex_whitespace()492 pub fn test_from_hex_whitespace() {
493 assert_eq!(
494 Vec::from_hex("666f 6f62617").unwrap_err(),
495 FromHexError::InvalidHexCharacter { c: ' ', index: 4 }
496 );
497 }
498
499 #[test]
test_from_hex_array()500 pub fn test_from_hex_array() {
501 assert_eq!(
502 <[u8; 6] as FromHex>::from_hex("666f6f626172"),
503 Ok([0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72])
504 );
505
506 assert_eq!(
507 <[u8; 5] as FromHex>::from_hex("666f6f626172"),
508 Err(FromHexError::InvalidStringLength)
509 );
510 }
511
512 #[test]
513 #[cfg(feature = "alloc")]
test_to_hex()514 fn test_to_hex() {
515 assert_eq!(
516 [0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72].encode_hex::<String>(),
517 "666f6f626172".to_string(),
518 );
519
520 assert_eq!(
521 [0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72].encode_hex_upper::<String>(),
522 "666F6F626172".to_string(),
523 );
524 }
525 }
526