1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
//! This module defines several low-level utility functions for general use by ArmorLib. You can
//! use these functions in your own program, but they are designed for internal use.

use std::num::ParseIntError;

/// A utility function that converts a string of space-separated hexadecimal bytes into a `Vec<u8>`
/// for use by preprocessors, scan modules, and other programs.
///
/// # Examples
///
/// ```rust
/// use armorlib::util;
/// assert_eq!(
///     util::hex_to_vec("00 00 01 00 BA 3C 2B A9").unwrap(),
///     [
///         0x00_u8, 0x00_u8, 0x01_u8, 0x00_u8, 0xBA_u8, 0x3C_u8, 0x2B_u8, 0xA9_u8
///     ]
/// );
///
/// match util::hex_to_vec("invalid HEX string") {
///     Ok(_) => assert!(false),
///     Err(_) => assert!(true),
/// }
/// ```
#[allow(dead_code)]
pub fn hex_to_vec(hex: &str) -> Result<Vec<u8>, ParseIntError> {
    let mut bytes: Vec<u8> = Vec::new();
    for byte in String::from(hex).to_uppercase().split(" ") {
        bytes.push(u8::from_str_radix(byte, 16)?);
    }
    Ok(bytes)
}

/// A utility function that, given two `u8`s, uses a bit shift operation and a binary `OR`
/// operation to return a `u16`. The first 8 bits of this `u16` are those of the argument `first`,
/// while the second 8 bits are those of the argument `second`.
///
/// # Examples
///
/// ```rust
/// use armorlib::util;
/// let first = 0x12_u8;
/// let second = 0xAB_u8;
/// assert_eq!(util::u8s_to_u16(first, second), 0x12AB_u16);
/// ```
pub fn u8s_to_u16(first: u8, second: u8) -> u16 {
    let first: u16 = (first as u16) << 8;
    let second: u16 = second as u16;

    first | second
}

/// A utility function that, given four `u8`s, uses a bit shift operation and a binary `OR`
/// operation to return a `u32`. The first 8 bits of this `u32` are those of the argument `first`,
/// the second 8 bits are those of the argument `second`, the third eight bits from `third`, and
/// the final 8 bits from `fourth`.
///
/// # Examples
///
/// ```rust
/// use armorlib::util;
/// let first = 0x12_u8;
/// let second = 0xAB_u8;
/// let third = 0xDE_u8;
/// let fourth = 0x53_u8;
/// assert_eq!(util::u8s_to_u32(first, second, third, fourth), 0x12ABDE53_u32);
/// ```
pub fn u8s_to_u32(first: u8, second: u8, third: u8, fourth: u8) -> u32 {
    let first: u32 = (first as u32) << 24;
    let second: u32 = (second as u32) << 16;
    let third: u32 = (third as u32) << 8;
    let fourth: u32 = fourth as u32;

    first | second | third | fourth
}

#[cfg(test)]
mod tests {
    use util::{hex_to_vec, u8s_to_u16, u8s_to_u32};

    #[test]
    fn test_hex_to_vec() {
        assert_eq!(
            hex_to_vec("00 00 01 00 BA 3C 2B A9").unwrap(),
            [
                0x00_u8, 0x00_u8, 0x01_u8, 0x00_u8, 0xBA_u8, 0x3C_u8, 0x2B_u8, 0xA9_u8
            ]
        );

        match hex_to_vec("invalid HEX string") {
            Ok(_) => assert!(false),
            Err(_) => assert!(true),
        }
    }

    #[test]
    fn test_u8s_to_u16() {
        let first = 0xAB_u8;
        let second = 0xCD_u8;
        assert_eq!(u8s_to_u16(first, second), 0xABCD_u16);
    }

    #[test]
    fn test_u8s_to_u32() {
        let first = 0x01_u8;
        let second = 0x23_u8;
        let third = 0x45_u8;
        let fourth = 0x67_u8;
        assert_eq!(u8s_to_u32(first, second, third, fourth), 0x01234567_u32);
    }

}