1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use crate::{errors::DataParseError, utils::ParseResult};
use super::core::DataParser;
impl DataParser<'_> {
fn _get_string(&mut self, str_len: usize, utf16: bool) -> ParseResult<String> {
let strict = self.options.strict_encoding;
let trim_nulls = self.options.trim_null_strings;
let bytes = self.take(str_len)?;
if utf16 {
if bytes.len() % 2 != 0 {
return Err(DataParseError::InvalidConversion {
e: "UTF-16 input length must be even".into(),
});
}
let utf_16_vec: Vec<u16> = bytes
.chunks_exact(2)
.map(|pair| u16::from_ne_bytes([pair[0], pair[1]]))
.collect();
let mut string = if strict {
String::from_utf16(&utf_16_vec)
.map_err(|e| DataParseError::InvalidConversion { e: e.to_string() })?
} else {
String::from_utf16_lossy(&utf_16_vec)
};
if trim_nulls {
string = string.trim_end_matches('\0').to_string();
}
Ok(string)
} else {
let mut string = if strict {
std::str::from_utf8(bytes)
.map_err(|e| DataParseError::InvalidConversion { e: e.to_string() })?
.to_string()
} else {
String::from_utf8_lossy(bytes).into()
};
if trim_nulls {
string = string.trim_end_matches('\0').to_string();
}
Ok(string)
}
}
fn _get_string_raw(&mut self, utf16: bool) -> ParseResult<String> {
if utf16 {
let mut utf16_buf = Vec::new();
while self.remaining() >= 2 {
let bytes = self.take(2)?;
let val = u16::from_ne_bytes([bytes[0], bytes[1]]);
if val == 0 {
break;
}
utf16_buf.push(val);
}
let mut s = String::from_utf16_lossy(&utf16_buf);
if self.options.trim_null_strings {
s = s.trim_end_matches('\0').to_string();
}
Ok(s)
} else {
let mut string_buf = Vec::new();
while self.remaining() > 0 {
let byte = self.get_byte()?;
if byte == 0 {
break;
}
string_buf.push(byte);
}
let result = if self.options.strict_encoding {
String::from_utf8(string_buf)
.map_err(|e| DataParseError::InvalidConversion { e: e.to_string() })?
} else {
String::from_utf8_lossy(&string_buf).to_string()
};
Ok(result)
}
}
/// Parses a length-prefixed string from the input stream.
///
/// This method expects a `u32` length prefix followed by a UTF-8 or UTF-16 encoded string.
/// The parsing behavior can be adjusted via the following options:
///
/// - [`strict_encoding`]: If `true`, parsing will return an error on invalid encoding.
/// - [`trim_null_strings`]: If `true`, trailing null bytes (`\0`) will be removed.
///
/// # Parameters
/// - `utf16`: If `true`, the string is parsed as UTF-16. Otherwise, UTF-8 is used.
///
/// # Returns
/// A `String` if parsing succeeds, or a [`DataParseError`] on failure.
///
/// # Format
/// ```
/// [length: u32][string_bytes...]
/// ```
///
/// # Errors
/// Returns an error if:
/// - The length prefix is invalid
/// - The encoding is invalid (under `strict_encoding`)
///
/// # Example
/// ```rust
/// let mut parser = DataParser::new(Cursor::new(vec![0x05, 0x00, 0x00, 0x00, b'H', b'e', b'l', b'l', b'o']));
/// let s = parser.get_string(false).unwrap();
/// assert_eq!(s, "Hello");
/// ```
///
/// [`strict_encoding`]: crate::options::ParseOptions
/// [`trim_null_strings`]: crate::options::ParseOptions
pub fn get_string(&mut self, utf16: bool) -> ParseResult<String> {
let str_len = self.get_u32()?;
// Strings also have to prepend the size to the data
self._get_string(str_len as usize, utf16)
}
}