From 3de4056df4ea5d0afbcea388ad8d681daea1aac3 Mon Sep 17 00:00:00 2001 From: SulfurNitride Date: Wed, 8 Apr 2026 03:30:04 -0500 Subject: 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) --- libs/nak/src/icons.rs | 195 -------------------------------------------------- 1 file changed, 195 deletions(-) delete mode 100644 libs/nak/src/icons.rs (limited to 'libs/nak/src/icons.rs') diff --git a/libs/nak/src/icons.rs b/libs/nak/src/icons.rs deleted file mode 100644 index 940d0d1..0000000 --- a/libs/nak/src/icons.rs +++ /dev/null @@ -1,195 +0,0 @@ -//! Extract icons from Windows PE (.exe/.dll) files using pelite. -//! -//! Returns raw ICO file bytes that can be loaded directly by Qt's QIcon/QImage. - -use std::path::Path; - -use pelite::resources::{Entry, Name, Resources}; - -/// Extract the best (largest) icon from a PE executable as raw ICO bytes. -/// -/// Returns `None` if the file can't be read, isn't a valid PE, or has no icons. -pub fn extract_icon(exe_path: &Path) -> Option> { - let data = std::fs::read(exe_path).ok()?; - - // Try PE32+ (64-bit) first, fall back to PE32 (32-bit) - if let Ok(icon) = extract_from_pe64(&data) { - return Some(icon); - } - if let Ok(icon) = extract_from_pe32(&data) { - return Some(icon); - } - - None -} - -fn extract_from_pe64(data: &[u8]) -> Result, Box> { - use pelite::pe64::{Pe, PeFile}; - let pe = PeFile::from_bytes(data)?; - let resources = pe.resources()?; - build_ico_from_resources(&resources) -} - -fn extract_from_pe32(data: &[u8]) -> Result, Box> { - use pelite::pe32::{Pe, PeFile}; - let pe = PeFile::from_bytes(data)?; - let resources = pe.resources()?; - build_ico_from_resources(&resources) -} - -/// Build an ICO file from PE resources, picking the group icon with the -/// largest total pixel area. -fn build_ico_from_resources( - resources: &Resources, -) -> Result, Box> { - let root = resources.root()?; - - // Find RT_GROUP_ICON directory (type 14) - let group_icon_dir = root - .get_dir(Name::Id(14)) - .map_err(|_| "no RT_GROUP_ICON")?; - - let mut best_group: Option<(i32, Vec)> = None; - - for dir_entry in group_icon_dir.entries() { - // Each entry is a group; get its subdirectory (language variants) - let sub_dir = match dir_entry.entry() { - Ok(Entry::Directory(d)) => d, - _ => continue, - }; - - // Get the first language variant's data - let data_entry = match sub_dir.entries().next() { - Some(e) => match e.entry() { - Ok(Entry::DataEntry(d)) => d, - _ => continue, - }, - None => continue, - }; - - let grp_data = match data_entry.bytes() { - Ok(d) => d, - Err(_) => continue, - }; - - // Parse GRPICONDIR header: reserved(2) + type(2) + count(2) = 6 bytes - if grp_data.len() < 6 { - continue; - } - let count = u16::from_le_bytes([grp_data[4], grp_data[5]]) as usize; - // Each GRPICONDIRENTRY is 14 bytes - if grp_data.len() < 6 + count * 14 { - continue; - } - - // Calculate total pixel area for ranking - let mut total_area: i32 = 0; - for i in 0..count { - let offset = 6 + i * 14; - let w = if grp_data[offset] == 0 { - 256i32 - } else { - grp_data[offset] as i32 - }; - let h = if grp_data[offset + 1] == 0 { - 256i32 - } else { - grp_data[offset + 1] as i32 - }; - total_area += w * h; - } - - if let Ok(ico_bytes) = build_ico_file(resources, grp_data, count) { - if best_group.is_none() || total_area > best_group.as_ref().unwrap().0 { - best_group = Some((total_area, ico_bytes)); - } - } - } - - best_group - .map(|(_, bytes)| bytes) - .ok_or_else(|| "no valid icon group found".into()) -} - -/// Build a complete ICO file from a GRPICONDIR and the corresponding RT_ICON resources. -fn build_ico_file( - resources: &Resources, - grp_data: &[u8], - count: usize, -) -> Result, Box> { - let root = resources.root()?; - - // RT_ICON = type 3 - let icon_dir = root.get_dir(Name::Id(3)).map_err(|_| "no RT_ICON")?; - - // Collect individual icon image data - struct IconEntry<'a> { - header: [u8; 8], // first 8 bytes of GRPICONDIRENTRY (w, h, colors, reserved, planes, bpp) - data: &'a [u8], - } - let mut entries: Vec = Vec::new(); - - for i in 0..count { - let grp_offset = 6 + i * 14; - let icon_id = - u16::from_le_bytes([grp_data[grp_offset + 12], grp_data[grp_offset + 13]]) as u32; - - // Find the RT_ICON with this ID - let icon_sub = match icon_dir.get_dir(Name::Id(icon_id)) { - Ok(d) => d, - Err(_) => continue, - }; - - let data_entry = match icon_sub.entries().next() { - Some(e) => match e.entry() { - Ok(Entry::DataEntry(d)) => d, - _ => continue, - }, - None => continue, - }; - - let image_data = match data_entry.bytes() { - Ok(d) => d, - Err(_) => continue, - }; - - let mut header = [0u8; 8]; - header.copy_from_slice(&grp_data[grp_offset..grp_offset + 8]); - - entries.push(IconEntry { - header, - data: image_data, - }); - } - - if entries.is_empty() { - return Err("no icon entries found".into()); - } - - let entry_count = entries.len() as u16; - let header_size = 6 + (entry_count as usize) * 16; // ICONDIR + ICONDIRENTRYs - - let mut ico = Vec::new(); - - // ICONDIR header - ico.extend_from_slice(&0u16.to_le_bytes()); // reserved - ico.extend_from_slice(&1u16.to_le_bytes()); // type = ICO - ico.extend_from_slice(&entry_count.to_le_bytes()); - - // Write ICONDIRENTRY records (16 bytes each) - let mut data_offset = header_size as u32; - for entry in &entries { - ico.extend_from_slice(&entry.header); // width, height, colors, reserved, planes, bpp (8 bytes) - let size = entry.data.len() as u32; - ico.extend_from_slice(&size.to_le_bytes()); // dwBytesInRes (4 bytes) - ico.extend_from_slice(&data_offset.to_le_bytes()); // dwImageOffset (4 bytes) - data_offset += size; - } - - // Write image data - for entry in &entries { - ico.extend_from_slice(entry.data); - } - - Ok(ico) -} -- cgit v1.3.1