Skip to content

Commit

Permalink
Remove regex dependency
Browse files Browse the repository at this point in the history
Remove regex as the capture that are done are not too complex.
Just implement our own capturing.
  • Loading branch information
RossSmyth committed Jul 10, 2024
1 parent 5828e1e commit 916c2fd
Show file tree
Hide file tree
Showing 4 changed files with 888 additions and 28 deletions.
3 changes: 0 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ core-foundation-sys = "0.8.4"
io-kit-sys = "0.4.0"
mach2 = "0.4.1"

[target."cfg(windows)".dependencies]
regex = "1.5.5"

[target."cfg(windows)".dependencies.winapi]
version = "0.3.9"
features = [
Expand Down
107 changes: 82 additions & 25 deletions src/windows/enumerate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use std::collections::HashSet;
use std::ffi::{CStr, CString};
use std::{mem, ptr};

use regex::Regex;
use winapi::shared::guiddef::*;
use winapi::shared::minwindef::*;
use winapi::shared::winerror::*;
Expand Down Expand Up @@ -69,6 +68,80 @@ fn get_ports_guids() -> Result<Vec<GUID>> {
Ok(guids)
}

#[derive(Debug)]
struct HwidMatches<'hwid> {
vid: &'hwid str,
pid: &'hwid str,
serial: Option<&'hwid str>,
interface: Option<&'hwid str>,
}

impl<'hwid> HwidMatches<'hwid> {
fn new(hwid: &'hwid str) -> Option<Self> {
use super::uniword_word::is_word_character;

// When we match something, update this so that we are always looking forward
let mut hwid_tail = hwid;

// VID_(?P<vid>[[:xdigit:]]{4})
let vid_start = hwid.find("VID_")?;

// We won't match for hex characters here. That can be done when parsed.
let vid = &hwid_tail[vid_start + 4..vid_start + 8];
hwid_tail = &hwid_tail[vid_start + 8..];

// [&+]PID_(?P<pid>[[:xdigit:]]{4})
let pid = if hwid_tail.starts_with("&PID_") || hwid_tail.starts_with("+PID_") {
// We will let the hex parser fail if there are not hex digits.
hwid_tail.get(5..9)?
} else {
return None;
};
hwid_tail = &hwid_tail[9..];

// (?:[&+]MI_(?P<iid>[[:xdigit:]]{2})){0,1}
let iid = if hwid_tail.starts_with("&MI_") || hwid_tail.starts_with("+MI_") {
// We will let the hex parser fail if there are not hex digits.
let iid = hwid_tail.get(4..6);
hwid_tail = &hwid_tail[6..];

iid
} else {
None
};

// ([\\+](?P<serial>\w+))? (modified)
let serial = if hwid_tail.starts_with('\\') || hwid_tail.starts_with('+') {
hwid_tail = &hwid_tail[1..];

// Scan the iterator until we hit the first non-word or non-'&' character.
let serial = hwid_tail
.chars()
.enumerate()
.find(|&(_, char)| !is_word_character(char) && char != '&');

match serial {
Some((0, _)) => None,
Some((i, _)) => {
// Apparently some serials have a '&' in it.
// If that is so, pick the second one.
hwid_tail[..i].split('&').take(2).last()
}
None => hwid_tail.split('&').take(2).last(),
}
} else {
None
};

Some(dbg!(Self {
vid,
pid,
serial,
interface: iid
}))
}
}

/// Windows usb port information can be determined by the port's HWID string.
///
/// This function parses the HWID string using regex, and returns the USB port
Expand All @@ -86,40 +159,24 @@ fn get_ports_guids() -> Result<Vec<GUID>> {
/// - BlackMagic UART port: USB\VID_1D50&PID_6018&MI_02\6&A694CA9&0&0002
/// - FTDI Serial Adapter: FTDIBUS\VID_0403+PID_6001+A702TB52A\0000
fn parse_usb_port_info(hardware_id: &str, parent_hardware_id: Option<&str>) -> Option<UsbPortInfo> {
let re = Regex::new(concat!(
r"VID_(?P<vid>[[:xdigit:]]{4})",
r"[&+]PID_(?P<pid>[[:xdigit:]]{4})",
r"(?:[&+]MI_(?P<iid>[[:xdigit:]]{2})){0,1}",
r"([\\+](?P<serial>\w+))?"
))
.unwrap();

let mut caps = re.captures(hardware_id)?;
let mut caps = HwidMatches::new(hardware_id)?;

let interface = caps
.name("iid")
.and_then(|m| u8::from_str_radix(m.as_str(), 16).ok());
let interface = caps.interface.and_then(|m| u8::from_str_radix(m, 16).ok());

if interface.is_some() {
// If this is a composite device, we need to parse the parent's HWID to get the correct information.
caps = re.captures(parent_hardware_id?)?;
caps = HwidMatches::new(parent_hardware_id?)?;
}

Some(UsbPortInfo {
vid: u16::from_str_radix(&caps[1], 16).ok()?,
pid: u16::from_str_radix(&caps[2], 16).ok()?,
serial_number: caps.name("serial").map(|m| {
let m = m.as_str();
if m.contains('&') {
m.split('&').nth(1).unwrap().to_string()
} else {
m.to_string()
}
}),
vid: u16::from_str_radix(caps.vid, 16).ok()?,
pid: u16::from_str_radix(caps.pid, 16).ok()?,
serial_number: caps.serial.map(str::to_string),
manufacturer: None,
product: None,

#[cfg(feature = "usbportinfo-interface")]
interface: interface,
interface,
})
}

Expand Down
1 change: 1 addition & 0 deletions src/windows/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub use self::com::*;
pub use self::enumerate::*;

mod uniword_word;
mod com;
mod dcb;
mod enumerate;
Expand Down
Loading

0 comments on commit 916c2fd

Please sign in to comment.