physis/
common_file_operations.rs
1use binrw::{BinReaderExt, BinResult, binread};
5use half::f16;
6use std::ffi::CString;
7use std::io::SeekFrom;
8
9pub(crate) fn read_bool_from<T: std::convert::From<u8> + std::cmp::PartialEq>(x: T) -> bool {
10 x == T::from(1u8)
11}
12
13pub(crate) fn write_bool_as<T: std::convert::From<u8>>(x: &bool) -> T {
14 if *x { T::from(1u8) } else { T::from(0u8) }
15}
16
17pub(crate) fn read_string(byte_stream: Vec<u8>) -> String {
18 let str = String::from_utf8(byte_stream).unwrap();
19 str.trim_matches(char::from(0)).to_string() }
21
22pub(crate) fn write_string(str: &String) -> Vec<u8> {
23 let c_string = CString::new(&**str).unwrap();
24 c_string.as_bytes_with_nul().to_vec()
25}
26
27pub(crate) fn get_string_len(str: &String) -> usize {
28 let c_string = CString::new(&**str).unwrap();
29 c_string.count_bytes() + 1 }
31
32#[binrw::parser(reader)]
33pub(crate) fn strings_parser(
34 base_offset: u64,
35 strings_offset: &Vec<u16>,
36) -> BinResult<Vec<String>> {
37 let mut strings: Vec<String> = vec![];
38
39 for offset in strings_offset {
40 let string_offset = base_offset + *offset as u64;
41
42 let mut string = String::new();
43
44 reader.seek(SeekFrom::Start(string_offset))?;
45 let mut next_char = reader.read_le::<u8>().unwrap() as char;
46 while next_char != '\0' {
47 string.push(next_char);
48 next_char = reader.read_le::<u8>().unwrap() as char;
49 }
50
51 strings.push(string);
52 }
53
54 Ok(strings)
55}
56
57#[binrw::parser(reader)]
58pub(crate) fn string_from_offset(start: u64) -> BinResult<String> {
59 let offset: u32 = reader.read_le::<u32>()?;
60
61 let mut string = String::new();
62
63 let old_pos = reader.stream_position()?;
64
65 reader.seek(SeekFrom::Start(start + offset as u64))?;
66 reader.seek(SeekFrom::Start(start))?;
67 let mut next_char = reader.read_le::<u8>().unwrap() as char;
68 while next_char != '\0' {
69 string.push(next_char);
70 next_char = reader.read_le::<u8>().unwrap() as char;
71 }
72 reader.seek(SeekFrom::Start(old_pos))?;
73 Ok(string)
74}
75
76fn read_half1(data: [u16; 1]) -> Half1 {
77 Half1 {
78 value: f16::from_bits(data[0]),
79 }
80}
81
82#[binread]
83#[derive(Debug, Default, Clone, Copy)]
84#[br(map = read_half1)]
85pub(crate) struct Half1 {
86 pub value: f16,
87}
88
89fn read_half2(data: [u16; 2]) -> Half2 {
90 Half2 {
91 x: f16::from_bits(data[0]),
92 y: f16::from_bits(data[0]),
93 }
94}
95
96#[binread]
97#[derive(Debug, Default, Clone, Copy)]
98#[br(map = read_half2)]
99pub(crate) struct Half2 {
100 pub x: f16,
101 pub y: f16,
102}
103
104fn read_half3(data: [u16; 3]) -> Half3 {
105 Half3 {
106 r: f16::from_bits(data[0]),
107 g: f16::from_bits(data[0]),
108 b: f16::from_bits(data[0]),
109 }
110}
111
112#[binread]
113#[derive(Debug, Default, Clone, Copy)]
114#[br(map = read_half3)]
115pub(crate) struct Half3 {
116 pub r: f16,
117 pub g: f16,
118 pub b: f16,
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 const DATA: [u8; 2] = [0u8, 1u8];
126
127 #[test]
130 fn read_bool_u8() {
131 assert!(!read_bool_from::<u8>(DATA[0]));
132 assert!(read_bool_from::<u8>(DATA[1]));
133 }
134
135 #[test]
136 fn write_bool_u8() {
137 assert_eq!(write_bool_as::<u8>(&false), DATA[0]);
138 assert_eq!(write_bool_as::<u8>(&true), DATA[1]);
139 }
140
141 const STRING_DATA: [u8; 4] = [0x46u8, 0x4Fu8, 0x4Fu8, 0x0u8];
143
144 #[test]
145 fn read_string() {
146 assert_eq!(
148 crate::common_file_operations::read_string(STRING_DATA.to_vec()),
149 "FOO".to_string()
150 );
151 }
152
153 #[test]
154 fn write_string() {
155 assert_eq!(
157 crate::common_file_operations::write_string(&"FOO".to_string()),
158 STRING_DATA.to_vec()
159 );
160 }
161
162 #[test]
163 fn get_string_len() {
164 assert_eq!(
166 crate::common_file_operations::get_string_len(&"FOO".to_string()),
167 4
168 );
169 }
170}