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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
use std::fmt;
use crate::{Command, CommandCode, Key, MouseButton};

/// Error enum for [`parse_byte_command`](parse_byte_command).
#[derive(Debug)]
pub enum ParseByteCommandError {
    /// Encountered a byte that isn't a valid [`CommandCode`](CommandCode).
    InvalidCommandCode(u8),
    /// Encountered a byte that isn't a valid [`Key`](Key).
    InvalidKey(u8),
    /// Encountered a byte that isn't a valid [`MouseButton`](MouseButton).
    InvalidMouseButton(u8),
    /// Expected the buffer to be longer based upon the
    /// [`CommandCode`](CommandCode) byte.
    BufferTooShort(usize),
}

use ParseByteCommandError::*;

impl fmt::Display for ParseByteCommandError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            InvalidCommandCode(byte) => write!(f, "Invalid command code byte ({})", byte),
            InvalidKey(byte) => write!(f, "Invalid key byte ({})", byte),
            InvalidMouseButton(byte) => write!(f, "Invalid mouse button byte ({})", byte),
            BufferTooShort(len) => write!(f, "Buffer length ({}) is too short", len),
        }
    }
}

impl std::error::Error for ParseByteCommandError {}

fn parse_int(byte_0: u8, byte_1: u8) -> i32 {
    (((byte_0 as i16) << 8) | (byte_1 as i16)) as i32
}

fn parse_command_code(byte: u8) -> Result<CommandCode, ParseByteCommandError> {
    if byte < CommandCode::COUNT {
        unsafe { Ok(std::mem::transmute(byte)) }
    } else {
        Err(InvalidCommandCode(byte))
    }
}

fn parse_key(byte: u8) -> Result<Key, ParseByteCommandError> {
    if byte < Key::COUNT {
        unsafe { Ok(std::mem::transmute(byte)) }
    } else {
        Err(InvalidKey(byte))
    }
}

fn parse_mouse_button(byte: u8) -> Result<MouseButton, ParseByteCommandError> {
    if byte < MouseButton::COUNT {
        unsafe { Ok(std::mem::transmute(byte)) }
    } else {
        Err(InvalidMouseButton(byte))
    }
}

fn check_buffer_length(buf: &[u8], len: usize) -> Result<(), ParseByteCommandError> {
    if buf.len() >= len {
        Ok(())
    } else {
        // Should we put expected, actual, or both?
        Err(BufferTooShort(buf.len()))
    }
}

/// Parse a sequence of bytes to create a [`Command`](Command).
///
/// The first byte in the buffer must be a [`CommandCode`](CommandCode). This
/// identifies the command and its arguments. Following the command identifier
/// is a sequence of bytes that encode the arguments of the command.
/// [`Key`](Key) and [`MouseButton`](MouseButton) are single bytes. For integer
/// arguments (used for moving the mouse and scrolling), 16-bit signed
/// big-endian integers are used.
///
/// Returns the command and the number of bytes that were read from the buffer.
///
/// # Arguments
/// * `buf` - The byte buffer to read from.
///
/// # Examples
///
/// ```
/// let bytes = &[
///     tfc::CommandCode::MouseMoveRel as u8, 255, 214, 0, 64,
///     tfc::CommandCode::KeyClick as u8, tfc::Key::K as u8
/// ];
///
/// let (command, len) = tfc::parse_byte_command(bytes).unwrap();
/// assert_eq!(len, 5);
/// assert_eq!(command, tfc::Command::MouseMoveRel(-42, 64));
///
/// let bytes = &bytes[len..];
/// let (command, len) = tfc::parse_byte_command(bytes).unwrap();
/// assert_eq!(len, 2);
/// assert_eq!(command, tfc::Command::KeyClick(tfc::Key::K));
/// ```
pub fn parse_byte_command(buf: &[u8]) -> Result<(Command, usize), ParseByteCommandError> {
    if buf.len() == 0 {
        return Err(BufferTooShort(0));
    }

    match parse_command_code(buf[0])? {
        CommandCode::KeyDown => {
            check_buffer_length(buf, 2)?;
            Ok((Command::KeyDown(parse_key(buf[1])?), 2))
        },
        CommandCode::KeyUp => {
            check_buffer_length(buf, 2)?;
            Ok((Command::KeyUp(parse_key(buf[1])?), 2))
        },
        CommandCode::KeyClick => {
            check_buffer_length(buf, 2)?;
            Ok((Command::KeyClick(parse_key(buf[1])?), 2))
        },
        CommandCode::MouseMoveRel => {
            check_buffer_length(buf, 5)?;
            Ok((Command::MouseMoveRel(parse_int(buf[1], buf[2]), parse_int(buf[3], buf[4])), 5))
        },
        CommandCode::MouseMoveAbs => {
            check_buffer_length(buf, 5)?;
            Ok((Command::MouseMoveAbs(parse_int(buf[1], buf[2]), parse_int(buf[3], buf[4])), 5))
        },
        CommandCode::MouseWarp => {
            check_buffer_length(buf, 5)?;
            Ok((Command::MouseWarp(parse_int(buf[1], buf[2]), parse_int(buf[3], buf[4])), 5))
        },
        CommandCode::MouseScroll => {
            check_buffer_length(buf, 5)?;
            Ok((Command::MouseScroll(parse_int(buf[1], buf[2]), parse_int(buf[3], buf[4])), 5))
        },
        CommandCode::MouseDown => {
            check_buffer_length(buf, 2)?;
            Ok((Command::MouseDown(parse_mouse_button(buf[1])?), 2))
        },
        CommandCode::MouseUp => {
            check_buffer_length(buf, 2)?;
            Ok((Command::MouseUp(parse_mouse_button(buf[1])?), 2))
        },
        CommandCode::MouseClick => {
            check_buffer_length(buf, 2)?;
            Ok((Command::MouseClick(parse_mouse_button(buf[1])?), 2))
        },
    }
}