bms_sm/
lib.rs

1mod flight_data;
2mod intellivibe_data;
3mod string_data;
4
5pub use flight_data::FlightData;
6pub use intellivibe_data::IntellivibeData;
7pub use string_data::*;
8
9use std::mem::size_of;
10
11use windows::{
12    core::HSTRING,
13    Win32::{
14        Foundation::{CloseHandle, HANDLE},
15        System::Memory::{
16            MapViewOfFile, OpenFileMappingW, UnmapViewOfFile, FILE_MAP_READ,
17            MEMORY_MAPPED_VIEW_ADDRESS,
18        },
19    },
20};
21
22pub struct MemoryFile<'a, T> {
23    data: &'a T,
24    map: HANDLE,
25    p_buf: MEMORY_MAPPED_VIEW_ADDRESS,
26}
27
28// I need to know how much of a bad idea this is...
29unsafe impl<'a, T> Send for MemoryFile<'a, T> {}
30unsafe impl<'a, T> Sync for MemoryFile<'a, T> {}
31
32impl<'a, T> MemoryFile<'a, T>
33where
34    T: Default,
35{
36    /// # Safety
37    /// If the generic struct given does not match the memory layout,
38    /// this is probably going to make shit hit the fan
39    /// Do not use directly unless you know what you're doing.
40    pub unsafe fn new(name: &'a str) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
41        Self::new_with_size(name, size_of::<T>())
42    }
43
44    /// # Safety
45    /// If the generic struct given does not match the memory layout,
46    /// this is probably going to make shit hit the fan
47    /// Do not use directly unless you know what you're doing.
48    pub unsafe fn new_with_size(
49        name: &'a str,
50        size: usize,
51    ) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
52        Self::new_with_offset_and_size(name, 0, size)
53    }
54
55    /// # Safety
56    /// If the generic struct given does not match the memory layout,
57    /// this is probably going to make shit hit the fan
58    /// Do not use directly unless you know what you're doing.
59    pub unsafe fn new_with_offset_and_size(
60        name: &'a str,
61        offset: usize,
62        size: usize,
63    ) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
64        let hname: HSTRING = HSTRING::from(name);
65        let map = OpenFileMappingW(FILE_MAP_READ.0, false, &hname)?;
66
67        let p_buf = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
68
69        let p = p_buf.Value.add(offset);
70        let ptr: *const u8 = p as *const u8;
71
72        let slice = std::slice::from_raw_parts(ptr, size);
73
74        let data = &slice.align_to::<T>().1;
75        if data.is_empty() {
76            let unaligned = std::ptr::addr_of!(slice);
77            let data: &T = std::ptr::read_unaligned(unaligned as *const _);
78            return Ok(Self { data, map, p_buf });
79        }
80        Ok(Self {
81            data: &data[0],
82            map,
83            p_buf,
84        })
85    }
86
87    pub fn read(&self) -> &T {
88        self.data
89    }
90}
91
92impl<'a, T> Drop for MemoryFile<'a, T> {
93    fn drop(&mut self) {
94        let _ = unsafe { CloseHandle(self.map) };
95        let _ = unsafe { UnmapViewOfFile(self.p_buf) };
96    }
97}
98
99pub struct RawMemoryFile<'a> {
100    data: &'a [u8],
101    map: HANDLE,
102    p_buf: MEMORY_MAPPED_VIEW_ADDRESS,
103}
104
105// I need to know how much of a bad idea this is...
106unsafe impl<'a> Send for RawMemoryFile<'a> {}
107unsafe impl<'a> Sync for RawMemoryFile<'a> {}
108
109impl<'a> RawMemoryFile<'a> {
110    /// # Safety
111    /// If the generic struct given does not match the memory layout,
112    /// this is probably going to make shit hit the fan
113    /// Do not use directly unless you know what you're doing.
114    pub unsafe fn new_with_size(
115        name: &'a str,
116        size: usize,
117    ) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
118        Self::new_with_offset_and_size(name, 0, size)
119    }
120
121    /// # Safety
122    /// If the generic struct given does not match the memory layout,
123    /// this is probably going to make shit hit the fan
124    /// Do not use directly unless you know what you're doing.
125    pub unsafe fn new_with_offset_and_size(
126        name: &'a str,
127        offset: usize,
128        size: usize,
129    ) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
130        let hname: HSTRING = HSTRING::from(name);
131        let map = OpenFileMappingW(FILE_MAP_READ.0, false, &hname)?;
132
133        let p_buf = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
134
135        let p = p_buf.Value.add(offset);
136        let ptr: *const u8 = p as *const u8;
137
138        let slice = std::slice::from_raw_parts(ptr, size);
139
140        Ok(Self {
141            data: slice,
142            map,
143            p_buf,
144        })
145    }
146
147    pub fn read(&self) -> &'a [u8] {
148        self.data
149    }
150}
151
152impl<'a> Drop for RawMemoryFile<'a> {
153    fn drop(&mut self) {
154        let _ = unsafe { CloseHandle(self.map) };
155        let _ = unsafe { UnmapViewOfFile(self.p_buf) };
156    }
157}