1use num::{BigUint, Zero};
2use std::borrow::BorrowMut;
3use std::cmp::Ordering;
4use std::convert::TryInto;
5use std::num::ParseIntError;
6use std::ops::Shl;
7
8pub fn blob_to_num<T: Into<String>>(str: T) -> u128 {
10 let mut num: u128 = 0;
11 let mut shift: u128 = 0;
12 let string = str.into();
13 for i in (0..string.len()).step_by(3) {
14 if let Ok(n) = string[i..i + 3].parse::<u128>() {
15 num += n.checked_shl(shift as u32).unwrap_or(0);
16 shift += 8;
17 }
18 }
19 num
20}
21
22pub fn bigblob_to_num<T: Into<String>>(str: T) -> BigUint {
24 let mut num: BigUint = BigUint::zero();
25 let mut shift: u128 = 0;
26 let string = str.into();
27 for i in (0..string.len()).step_by(3) {
28 if let Ok(n) = string[i..i + 3].parse::<BigUint>() {
29 num += n.shl(shift);
30 shift += 8;
31 }
32 }
33 num
34}
35
36pub(crate) fn do_vecs_match<T: PartialEq>(a: &[T], b: &[T]) -> bool {
37 let matching = a.iter().zip(b.iter()).filter(|&(a, b)| a == b).count();
38 matching == a.len() && matching == b.len()
39}
40
41pub(crate) fn read_le(buffer: &[u8], position: &mut usize) -> u32 {
42 *position += 4;
43 u32::from_le_bytes(buffer[*position - 4..*position].try_into().unwrap())
44}
45
46pub(crate) fn read_le_signed(buffer: &[u8], position: &mut usize) -> i32 {
47 *position += 4;
48 i32::from_le_bytes(buffer[*position - 4..*position].try_into().unwrap())
49}
50
51pub(crate) fn read_le_64(buffer: &[u8], position: &mut usize) -> u64 {
52 *position += 8;
53 u64::from_le_bytes(buffer[*position - 8..*position].try_into().unwrap())
54}
55
56pub(crate) fn read_le_64_signed(buffer: &[u8], position: &mut usize) -> i64 {
57 *position += 8;
58 i64::from_le_bytes(buffer[*position - 8..*position].try_into().unwrap())
59}
60
61pub(crate) fn read_fstring(buffer: &[u8], position: &mut usize) -> Option<String> {
62 let mut length = read_le_signed(buffer, position);
63 match length.cmp(&0) {
64 Ordering::Less => {
65 length *= -2;
66 *position += length as usize;
67 Some(String::from_utf16_lossy(
68 buffer[*position - length as usize..*position - 2]
69 .chunks_exact(2)
70 .map(|a| u16::from_ne_bytes([a[0], a[1]]))
71 .collect::<Vec<u16>>()
72 .as_slice(),
73 ))
74 }
75 Ordering::Equal => None,
76 Ordering::Greater => {
77 *position += length as usize;
78 match std::str::from_utf8(&buffer[*position - length as usize..*position - 1]) {
79 Ok(s) => Some(s.to_string()),
80 Err(_) => None,
81 }
82 }
83 }
84}
85
86pub(crate) fn decode_hex(s: &str) -> Result<Vec<u8>, ParseIntError> {
87 (0..s.len())
88 .step_by(2)
89 .map(|i| u8::from_str_radix(&s[i..i + 2], 16))
90 .collect()
91}
92
93pub(crate) fn write_fstring(string: &str) -> Vec<u8> {
94 let mut meta: Vec<u8> = Vec::new();
95 if !string.is_empty() {
96 meta.append(
97 ((string.len() + 1) as u32)
98 .to_le_bytes()
99 .to_vec()
100 .borrow_mut(),
101 );
102 meta.append(string.as_bytes().to_vec().borrow_mut());
103 meta.push(0);
104 } else {
105 meta.append(0u32.to_le_bytes().to_vec().borrow_mut())
106 }
107 meta
108}
109
110#[cfg(test)]
111mod tests {
112 use crate::api::utils::{
113 bigblob_to_num, blob_to_num, decode_hex, do_vecs_match, read_fstring, read_le, read_le_64,
114 read_le_64_signed, read_le_signed, write_fstring,
115 };
116 use num::bigint::ToBigUint;
117
118 #[test]
119 fn vector_match() {
120 let a = vec![0, 0, 0];
121 let b = vec![0, 0, 0];
122 assert_eq!(do_vecs_match(&a, &b), true);
123 }
124
125 #[test]
126 fn vector_not_match() {
127 let a = vec![0, 0, 0];
128 let b = vec![0, 0, 1];
129 assert_eq!(do_vecs_match(&a, &b), false);
130 }
131
132 #[test]
133 fn blob_to_num_test() {
134 assert_eq!(blob_to_num("165045004000"), 273829)
135 }
136
137 #[test]
138 fn blob_to_bignum_test() {
139 assert_eq!(
140 bigblob_to_num("165045004000"),
141 ToBigUint::to_biguint(&273829).unwrap()
142 )
143 }
144
145 #[test]
146 fn read_le_test() {
147 let mut position: usize = 0;
148 let buffer = vec![1, 2, 3, 4];
149 assert_eq!(read_le(&buffer, &mut position), 67305985);
150 assert_eq!(position, 4)
151 }
152
153 #[test]
154 fn read_le_signed_test() {
155 let mut position: usize = 0;
156 let buffer = vec![237, 201, 255, 255];
157 assert_eq!(read_le_signed(&buffer, &mut position), -13843);
158 assert_eq!(position, 4)
159 }
160
161 #[test]
162 fn read_le_64_test() {
163 let mut position: usize = 0;
164 let buffer = vec![0, 0, 5, 3, 0, 1, 2, 3];
165 assert_eq!(read_le_64(&buffer, &mut position), 216736831629492224);
166 assert_eq!(position, 8)
167 }
168
169 #[test]
170 fn read_le_64_signed_test() {
171 let mut position: usize = 0;
172 let buffer = vec![237, 201, 255, 255, 255, 255, 255, 255];
173 assert_eq!(read_le_64_signed(&buffer, &mut position), -13843);
174 assert_eq!(position, 8)
175 }
176
177 #[test]
178 fn read_fstring_utf8() {
179 let mut position: usize = 0;
180 let buffer = vec![5, 0, 0, 0, 97, 98, 99, 100, 0];
181 assert_eq!(
182 read_fstring(&buffer, &mut position),
183 Some("abcd".to_string())
184 );
185 assert_eq!(position, 9)
186 }
187
188 #[test]
189 fn read_fstring_utf16() {
190 let mut position: usize = 0;
191 let buffer = vec![251, 255, 255, 255, 97, 0, 98, 0, 99, 0, 100, 0, 0, 0];
192 assert_eq!(
193 read_fstring(&buffer, &mut position),
194 Some("abcd".to_string())
195 );
196 assert_eq!(position, 14)
197 }
198
199 #[test]
200 fn write_fstring_nonempty() {
201 let buffer = write_fstring("hello");
202 assert_eq!(buffer, vec![6, 0, 0, 0, 104, 101, 108, 108, 111, 0])
203 }
204
205 #[test]
206 fn write_fstring_empty() {
207 let buffer = write_fstring("");
208 assert_eq!(buffer, vec![0, 0, 0, 0])
209 }
210
211 #[test]
212 fn write_fstring_roundtrip() {
213 let original = "roundtrip".to_string();
214 let buffer = write_fstring(&original);
215 let mut position: usize = 0;
216 assert_eq!(read_fstring(&buffer, &mut position), Some(original));
217 }
218
219 #[test]
220 fn decode_hex_valid() {
221 assert_eq!(
222 decode_hex("48656c6c6f").unwrap(),
223 vec![72, 101, 108, 108, 111]
224 )
225 }
226
227 #[test]
228 fn decode_hex_empty() {
229 assert_eq!(decode_hex("").unwrap(), Vec::<u8>::new())
230 }
231
232 #[test]
233 fn decode_hex_invalid() {
234 assert!(decode_hex("zz").is_err())
235 }
236
237 #[test]
238 fn read_fstring_zero_length() {
239 let mut position: usize = 0;
240 let buffer = vec![0, 0, 0, 0];
241 assert_eq!(read_fstring(&buffer, &mut position), None);
242 assert_eq!(position, 4)
243 }
244
245 #[test]
246 fn read_fstring_invalid_utf8() {
247 let mut position: usize = 0;
248 let buffer = vec![3, 0, 0, 0, 255, 254, 0];
249 assert_eq!(read_fstring(&buffer, &mut position), None);
250 assert_eq!(position, 7)
251 }
252
253 #[test]
254 fn blob_to_num_empty() {
255 assert_eq!(blob_to_num(""), 0)
256 }
257
258 #[test]
259 fn blob_to_num_single() {
260 assert_eq!(blob_to_num("042"), 42)
261 }
262}