2024-04-16 21:03:26 -04:00
|
|
|
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
2025-03-06 18:52:26 -05:00
|
|
|
use binrw::{BinReaderExt, BinResult, binread};
|
2024-04-30 19:43:47 -04:00
|
|
|
use half::f16;
|
2025-03-06 18:52:26 -05:00
|
|
|
use std::ffi::CString;
|
2024-05-18 09:42:07 -04:00
|
|
|
use std::io::SeekFrom;
|
2024-04-30 16:17:04 -04:00
|
|
|
|
2024-04-16 21:03:26 -04:00
|
|
|
pub(crate) fn read_bool_from<T: std::convert::From<u8> + std::cmp::PartialEq>(x: T) -> bool {
|
|
|
|
x == T::from(1u8)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn write_bool_as<T: std::convert::From<u8>>(x: &bool) -> T {
|
2025-03-06 18:52:26 -05:00
|
|
|
if *x { T::from(1u8) } else { T::from(0u8) }
|
2024-04-16 21:03:26 -04:00
|
|
|
}
|
|
|
|
|
2024-06-29 11:15:19 -04:00
|
|
|
pub(crate) fn read_string(byte_stream: Vec<u8>) -> String {
|
2024-07-18 14:08:10 -04:00
|
|
|
let str = String::from_utf8(byte_stream).unwrap();
|
|
|
|
str.trim_matches(char::from(0)).to_string() // trim \0 from the end of strings
|
2024-06-29 11:15:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn write_string(str: &String) -> Vec<u8> {
|
2024-06-29 12:36:54 -04:00
|
|
|
let c_string = CString::new(&**str).unwrap();
|
2024-07-18 14:17:24 -04:00
|
|
|
c_string.as_bytes_with_nul().to_vec()
|
2024-06-29 12:36:54 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn get_string_len(str: &String) -> usize {
|
|
|
|
let c_string = CString::new(&**str).unwrap();
|
2024-07-18 14:17:24 -04:00
|
|
|
c_string.count_bytes() + 1 // for the nul terminator
|
2024-06-29 11:15:19 -04:00
|
|
|
}
|
|
|
|
|
2024-05-18 09:42:07 -04:00
|
|
|
#[binrw::parser(reader)]
|
|
|
|
pub(crate) fn strings_parser(
|
|
|
|
base_offset: u64,
|
|
|
|
strings_offset: &Vec<u16>,
|
|
|
|
) -> BinResult<Vec<String>> {
|
|
|
|
let mut strings: Vec<String> = vec![];
|
2024-04-30 16:17:04 -04:00
|
|
|
|
|
|
|
for offset in strings_offset {
|
|
|
|
let string_offset = base_offset + *offset as u64;
|
|
|
|
|
|
|
|
let mut string = String::new();
|
|
|
|
|
2024-05-18 09:42:07 -04:00
|
|
|
reader.seek(SeekFrom::Start(string_offset))?;
|
2024-04-30 16:17:04 -04:00
|
|
|
let mut next_char = reader.read_le::<u8>().unwrap() as char;
|
|
|
|
while next_char != '\0' {
|
|
|
|
string.push(next_char);
|
|
|
|
next_char = reader.read_le::<u8>().unwrap() as char;
|
|
|
|
}
|
|
|
|
|
|
|
|
strings.push(string);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(strings)
|
|
|
|
}
|
|
|
|
|
2025-07-04 11:11:05 -04:00
|
|
|
#[binrw::parser(reader)]
|
|
|
|
pub(crate) fn read_string_until_null() -> BinResult<String> {
|
|
|
|
let mut string = String::new();
|
|
|
|
|
|
|
|
let mut next_char = reader.read_le::<u8>().unwrap() as char;
|
|
|
|
while next_char != '\0' {
|
|
|
|
string.push(next_char);
|
|
|
|
next_char = reader.read_le::<u8>().unwrap() as char;
|
|
|
|
}
|
|
|
|
Ok(string)
|
|
|
|
}
|
|
|
|
|
2024-04-30 19:43:47 -04:00
|
|
|
fn read_half1(data: [u16; 1]) -> Half1 {
|
|
|
|
Half1 {
|
2024-05-18 09:42:07 -04:00
|
|
|
value: f16::from_bits(data[0]),
|
2024-04-30 19:43:47 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[binread]
|
|
|
|
#[derive(Debug, Default, Clone, Copy)]
|
|
|
|
#[br(map = read_half1)]
|
|
|
|
pub(crate) struct Half1 {
|
2024-05-04 14:19:55 -04:00
|
|
|
pub value: f16,
|
2024-04-30 19:43:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn read_half2(data: [u16; 2]) -> Half2 {
|
|
|
|
Half2 {
|
|
|
|
x: f16::from_bits(data[0]),
|
2024-05-18 09:42:07 -04:00
|
|
|
y: f16::from_bits(data[0]),
|
2024-04-30 19:43:47 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[binread]
|
|
|
|
#[derive(Debug, Default, Clone, Copy)]
|
|
|
|
#[br(map = read_half2)]
|
|
|
|
pub(crate) struct Half2 {
|
2024-05-04 14:19:55 -04:00
|
|
|
pub x: f16,
|
|
|
|
pub y: f16,
|
2024-04-30 19:43:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn read_half3(data: [u16; 3]) -> Half3 {
|
|
|
|
Half3 {
|
|
|
|
r: f16::from_bits(data[0]),
|
|
|
|
g: f16::from_bits(data[0]),
|
2024-05-18 09:42:07 -04:00
|
|
|
b: f16::from_bits(data[0]),
|
2024-04-30 19:43:47 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[binread]
|
|
|
|
#[derive(Debug, Default, Clone, Copy)]
|
|
|
|
#[br(map = read_half3)]
|
|
|
|
pub(crate) struct Half3 {
|
2024-05-04 14:19:55 -04:00
|
|
|
pub r: f16,
|
|
|
|
pub g: f16,
|
2024-05-18 09:42:07 -04:00
|
|
|
pub b: f16,
|
2024-04-30 19:43:47 -04:00
|
|
|
}
|
|
|
|
|
2024-04-16 21:03:26 -04:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2024-04-16 21:19:08 -04:00
|
|
|
use super::*;
|
2024-04-16 21:03:26 -04:00
|
|
|
|
|
|
|
const DATA: [u8; 2] = [0u8, 1u8];
|
|
|
|
|
|
|
|
// TODO: add tests for u16
|
2024-04-16 21:19:08 -04:00
|
|
|
|
2024-04-16 21:03:26 -04:00
|
|
|
#[test]
|
|
|
|
fn read_bool_u8() {
|
|
|
|
assert!(!read_bool_from::<u8>(DATA[0]));
|
|
|
|
assert!(read_bool_from::<u8>(DATA[1]));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn write_bool_u8() {
|
|
|
|
assert_eq!(write_bool_as::<u8>(&false), DATA[0]);
|
|
|
|
assert_eq!(write_bool_as::<u8>(&true), DATA[1]);
|
|
|
|
}
|
2024-07-18 14:17:24 -04:00
|
|
|
|
|
|
|
// "FOO\0"
|
|
|
|
const STRING_DATA: [u8; 4] = [0x46u8, 0x4Fu8, 0x4Fu8, 0x0u8];
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn read_string() {
|
|
|
|
// The nul terminator is supposed to be removed
|
2025-03-06 18:52:26 -05:00
|
|
|
assert_eq!(
|
|
|
|
crate::common_file_operations::read_string(STRING_DATA.to_vec()),
|
|
|
|
"FOO".to_string()
|
|
|
|
);
|
2024-07-18 14:17:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn write_string() {
|
|
|
|
// Supposed to include the nul terminator
|
2025-03-06 18:52:26 -05:00
|
|
|
assert_eq!(
|
|
|
|
crate::common_file_operations::write_string(&"FOO".to_string()),
|
|
|
|
STRING_DATA.to_vec()
|
|
|
|
);
|
2024-07-18 14:17:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn get_string_len() {
|
|
|
|
// Supposed to include the nul terminator
|
2025-03-06 18:52:26 -05:00
|
|
|
assert_eq!(
|
|
|
|
crate::common_file_operations::get_string_len(&"FOO".to_string()),
|
|
|
|
4
|
|
|
|
);
|
2024-07-18 14:17:24 -04:00
|
|
|
}
|
2024-04-20 13:18:03 -04:00
|
|
|
}
|