Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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.
RossSmyth committed Jul 10, 2024
1 parent 5828e1e commit 6810cf4
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
@@ -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 = [
107 changes: 82 additions & 25 deletions src/windows/enumerate.rs
Original file line number Diff line number Diff line change
@@ -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::*;
@@ -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
@@ -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,
})
}

1 change: 1 addition & 0 deletions src/windows/mod.rs
Original file line number Diff line number Diff line change
@@ -5,3 +5,4 @@ mod com;
mod dcb;
mod enumerate;
mod error;
mod uniword_word;
805 changes: 805 additions & 0 deletions src/windows/uniword_word.rs

Large diffs are not rendered by default.

0 comments on commit 6810cf4

Please sign in to comment.