hex/
lib.rs

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")]
41extern crate alloc;
42#[cfg(feature = "alloc")]
43use alloc::{string::String, vec::Vec};
44
45use core::iter;
46
47mod error;
48pub use crate::error::FromHexError;
49
50#[cfg(feature = "serde")]
51#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
52pub mod serde;
53#[cfg(feature = "serde")]
54pub use crate::serde::deserialize;
55#[cfg(all(feature = "alloc", feature = "serde"))]
56pub 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()`].
73pub trait ToHex {
74    /// Encode the hex strict representing `self` into the result. Lower case
75    /// letters are used (e.g. `f9b4ca`)
76    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`)
80    fn encode_hex_upper<T: iter::FromIterator<char>>(&self) -> T;
81}
82
83const HEX_CHARS_LOWER: &[u8; 16] = b"0123456789abcdef";
84const HEX_CHARS_UPPER: &[u8; 16] = b"0123456789ABCDEF";
85
86struct BytesToHexChars<'a> {
87    inner: ::core::slice::Iter<'a, u8>,
88    table: &'static [u8; 16],
89    next: Option<char>,
90}
91
92impl<'a> 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
102impl<'a> Iterator for BytesToHexChars<'a> {
103    type Item = char;
104
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
116    fn size_hint(&self) -> (usize, Option<usize>) {
117        let length = self.len();
118        (length, Some(length))
119    }
120}
121
122impl<'a> iter::ExactSizeIterator for BytesToHexChars<'a> {
123    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]
133fn encode_to_iter<T: iter::FromIterator<char>>(table: &'static [u8; 16], source: &[u8]) -> T {
134    BytesToHexChars::new(source, table).collect()
135}
136
137impl<T: AsRef<[u8]>> ToHex for T {
138    fn encode_hex<U: iter::FromIterator<char>>(&self) -> U {
139        encode_to_iter(HEX_CHARS_LOWER, self.as_ref())
140    }
141
142    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/// ```
164pub 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).
172    fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error>;
173}
174
175fn 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")]
188impl FromHex for Vec<u8> {
189    type Error = FromHexError;
190
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.
206macro_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
220from_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"))]
233from_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")]
240from_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")]
259pub 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")]
275pub 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")]
296pub 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/// ```
312pub 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]
336fn 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]
343fn 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/// ```
367pub 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)]
386mod 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")]
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]
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]
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")]
438    fn test_encode() {
439        assert_eq!(encode("foobar"), "666f6f626172");
440    }
441
442    #[test]
443    #[cfg(feature = "alloc")]
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")]
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")]
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")]
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")]
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")]
486    pub fn test_empty() {
487        assert_eq!(Vec::from_hex("").unwrap(), b"");
488    }
489
490    #[test]
491    #[cfg(feature = "alloc")]
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]
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")]
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}