aboutsummaryrefslogtreecommitdiff
path: root/libs/nak/src/game_finder/registry.rs
diff options
context:
space:
mode:
authorSulfurNitride <SulfurNitride@users.noreply.github.com>2026-04-08 03:30:04 -0500
committerSulfurNitride <SulfurNitride@users.noreply.github.com>2026-04-08 03:30:04 -0500
commit3de4056df4ea5d0afbcea388ad8d681daea1aac3 (patch)
treefc5978451f9f51b84268f45bd2fa6f5d4a17baaf /libs/nak/src/game_finder/registry.rs
parent5ba23a6d7a40052d9e1d4bd0cf018cfe7814d03a (diff)
Remove NaK/Rust dependency, port remaining functionality to native C++
Replace NaK Rust crate and nak_ffi with native C++ implementations: - Game detection (Steam, Heroic, Bottles), VDF parser, icon extraction - Prefix symlinks, SLR manager, Steam path detection - Known games database Add FUSE VFS optimizations: zero-copy reads via fuse_reply_data, default_permissions mount option, FUSE_CAP_ASYNC_DIO, FUSE_CAP_EXPIRE_ONLY, lookup cache parent index, cached mode bits, increased I/O buffer sizes. Update build system, prefix setup, and various fixes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'libs/nak/src/game_finder/registry.rs')
-rw-r--r--libs/nak/src/game_finder/registry.rs227
1 files changed, 0 insertions, 227 deletions
diff --git a/libs/nak/src/game_finder/registry.rs b/libs/nak/src/game_finder/registry.rs
deleted file mode 100644
index e843b6e..0000000
--- a/libs/nak/src/game_finder/registry.rs
+++ /dev/null
@@ -1,227 +0,0 @@
-//! Wine registry parsing utilities
-//!
-//! Parses Wine registry files (system.reg, user.reg) to find game install paths.
-
-use std::fs;
-use std::path::{Path, PathBuf};
-
-use crate::logging::log_warning;
-
-/// Read a registry value from a Wine prefix registry file
-///
-/// # Arguments
-/// * `prefix_path` - Path to the Wine prefix (containing system.reg, user.reg)
-/// * `key_path` - Registry key path (e.g., "Software\\Bethesda Softworks\\Skyrim")
-/// * `value_name` - Name of the value to read (e.g., "Installed Path")
-///
-/// Returns the value as a string, or None if not found
-pub fn read_registry_value(
- prefix_path: &Path,
- key_path: &str,
- value_name: &str,
-) -> Option<String> {
- // Try system.reg first (HKEY_LOCAL_MACHINE)
- let system_reg = prefix_path.join("system.reg");
- if let Some(value) = read_value_from_reg_file(&system_reg, key_path, value_name) {
- return Some(value);
- }
-
- // Try user.reg (HKEY_CURRENT_USER)
- let user_reg = prefix_path.join("user.reg");
- if let Some(value) = read_value_from_reg_file(&user_reg, key_path, value_name) {
- return Some(value);
- }
-
- None
-}
-
-/// Read a value from a specific .reg file
-fn read_value_from_reg_file(reg_file: &Path, key_path: &str, value_name: &str) -> Option<String> {
- let content = fs::read_to_string(reg_file).ok()?;
-
- // Convert the key path to Wine's format
- // Wine uses lowercase keys with escaped backslashes
- // e.g., [Software\\Bethesda Softworks\\Skyrim] becomes [software\\\\bethesda softworks\\\\skyrim]
- let wine_key = format!(
- "[{}]",
- key_path.to_lowercase().replace('\\', "\\\\")
- );
-
- // Also try with the Wow6432Node variant for 32-bit apps on 64-bit Wine
- let wine_key_wow64 = format!(
- "[software\\\\wow6432node\\\\{}]",
- key_path
- .strip_prefix("Software\\")
- .unwrap_or(key_path)
- .to_lowercase()
- .replace('\\', "\\\\")
- );
-
- // Find the key section and extract the value
- for key_to_find in [&wine_key, &wine_key_wow64] {
- if let Some(value) = find_value_in_content(&content, key_to_find, value_name) {
- return Some(value);
- }
- }
-
- None
-}
-
-/// Find a value within registry file content
-fn find_value_in_content(content: &str, key: &str, value_name: &str) -> Option<String> {
- let mut in_target_key = false;
- let value_name_lower = value_name.to_lowercase();
-
- for line in content.lines() {
- let trimmed = line.trim();
-
- // Check for key header
- if trimmed.starts_with('[') && trimmed.ends_with(']') {
- in_target_key = trimmed.to_lowercase() == key.to_lowercase();
- continue;
- }
-
- // If we're in the target key, look for the value
- if in_target_key {
- // Empty line or new section means we've left the key
- if trimmed.is_empty() {
- continue;
- }
- if trimmed.starts_with('[') {
- break;
- }
-
- // Parse value line: "ValueName"="value" or @="default value"
- if let Some((name, value)) = parse_reg_value_line(trimmed) {
- if name.to_lowercase() == value_name_lower {
- return Some(value);
- }
- }
- }
- }
-
- None
-}
-
-/// Parse a registry value line like "ValueName"="value"
-fn parse_reg_value_line(line: &str) -> Option<(String, String)> {
- // Format: "name"="value" or "name"=dword:00000000 or @="default"
- let line = line.trim();
-
- // Find the = separator
- let eq_pos = line.find('=')?;
- let (name_part, value_part) = line.split_at(eq_pos);
- let value_part = &value_part[1..]; // Skip the '='
-
- // Extract name (remove quotes)
- let name = if name_part == "@" {
- "@".to_string()
- } else {
- name_part.trim().trim_matches('"').to_string()
- };
-
- // Extract value
- let value = if value_part.starts_with('"') {
- // String value - need to handle escapes
- parse_quoted_reg_value(value_part)?
- } else if value_part.starts_with("dword:") {
- // DWORD value - convert to decimal string
- let hex = value_part.strip_prefix("dword:")?;
- let num = u32::from_str_radix(hex, 16).ok()?;
- num.to_string()
- } else {
- // Other types - return as-is
- value_part.to_string()
- };
-
- Some((name, value))
-}
-
-/// Parse a quoted registry value, handling Wine's escape sequences
-fn parse_quoted_reg_value(s: &str) -> Option<String> {
- let s = s.trim();
- if !s.starts_with('"') {
- return None;
- }
-
- let mut result = String::new();
- let chars = s[1..].chars();
- let mut prev_was_backslash = false;
-
- for c in chars {
- if prev_was_backslash {
- match c {
- 'n' => result.push('\n'),
- 'r' => result.push('\r'),
- 't' => result.push('\t'),
- '\\' => result.push('\\'),
- '"' => result.push('"'),
- _ => {
- result.push('\\');
- result.push(c);
- }
- }
- prev_was_backslash = false;
- } else if c == '\\' {
- prev_was_backslash = true;
- } else if c == '"' {
- break; // End of string
- } else {
- result.push(c);
- }
- }
-
- Some(result)
-}
-
-/// Convert a Wine path (Z:\path\to\file) to a Linux path
-pub fn wine_path_to_linux(wine_path: &str) -> Option<PathBuf> {
- let path = wine_path.trim();
-
- // Handle Z: drive (maps to /)
- if path.starts_with("Z:") || path.starts_with("z:") {
- let linux_path = path[2..].replace('\\', "/");
- return Some(PathBuf::from(linux_path));
- }
-
- // Handle C: drive (maps to prefix/drive_c)
- // Note: This requires knowing the prefix path, so we can't convert it here
- // For now, we'll just return None for C: paths
- if path.starts_with("C:") || path.starts_with("c:") {
- log_warning(&format!(
- "Cannot convert C: drive path without prefix: {}",
- path
- ));
- return None;
- }
-
- None
-}
-
-/// Check if a Wine prefix contains a specific game by registry key
-pub fn has_game_registry(
- prefix_path: &Path,
- registry_path: &str,
- registry_value: &str,
-) -> bool {
- read_registry_value(prefix_path, registry_path, registry_value).is_some()
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_parse_reg_value_line() {
- let (name, value) =
- parse_reg_value_line(r#""Installed Path"="Z:\\mnt\\games\\Skyrim""#).unwrap();
- assert_eq!(name, "Installed Path");
- assert_eq!(value, r"Z:\mnt\games\Skyrim");
- }
-
- #[test]
- fn test_wine_path_to_linux() {
- let linux = wine_path_to_linux(r"Z:\mnt\games\Skyrim").unwrap();
- assert_eq!(linux, PathBuf::from("/mnt/games/Skyrim"));
- }
-}