1use std::{
7 collections::HashMap,
8 fmt,
9 io::{self, BufRead, Cursor},
10};
11
12use byteorder::{LittleEndian, ReadBytesExt};
13
14#[derive(Debug)]
16pub enum BinaryKvError {
17 Io(io::Error),
19 InvalidType(u8),
21 InvalidString,
23 UnexpectedEof,
25}
26
27impl fmt::Display for BinaryKvError {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 match self {
30 BinaryKvError::Io(e) => write!(f, "IO error: {}", e),
31 BinaryKvError::InvalidType(t) => write!(f, "Invalid type byte: {}", t),
32 BinaryKvError::InvalidString => write!(f, "Invalid string encoding"),
33 BinaryKvError::UnexpectedEof => write!(f, "Unexpected end of data"),
34 }
35 }
36}
37
38impl std::error::Error for BinaryKvError {}
39
40impl From<io::Error> for BinaryKvError {
41 fn from(e: io::Error) -> Self {
42 BinaryKvError::Io(e)
43 }
44}
45
46#[repr(u8)]
48#[derive(Debug, Clone, Copy, PartialEq)]
49enum BinaryKvType {
50 None = 0,
51 String = 1,
52 Int32 = 2,
53 Float32 = 3,
54 Pointer = 4,
55 WideString = 5,
56 Color = 6,
57 UInt64 = 7,
58 End = 8,
59 Int64 = 10,
60 AlternateEnd = 11,
61}
62
63impl TryFrom<u8> for BinaryKvType {
64 type Error = BinaryKvError;
65
66 fn try_from(value: u8) -> Result<Self, Self::Error> {
67 match value {
68 0 => Ok(BinaryKvType::None),
69 1 => Ok(BinaryKvType::String),
70 2 => Ok(BinaryKvType::Int32),
71 3 => Ok(BinaryKvType::Float32),
72 4 => Ok(BinaryKvType::Pointer),
73 5 => Ok(BinaryKvType::WideString),
74 6 => Ok(BinaryKvType::Color),
75 7 => Ok(BinaryKvType::UInt64),
76 8 => Ok(BinaryKvType::End),
77 10 => Ok(BinaryKvType::Int64),
78 11 => Ok(BinaryKvType::AlternateEnd),
79 _ => Err(BinaryKvError::InvalidType(value)),
80 }
81 }
82}
83
84#[derive(Debug, Clone, PartialEq)]
86pub enum BinaryKvValue {
87 None,
89 String(String),
91 Int32(i32),
93 Float32(f32),
95 Pointer(u32),
97 WideString(String),
99 Color(u32),
101 UInt64(u64),
103 Int64(i64),
105 Object(HashMap<String, BinaryKvValue>),
107}
108
109impl BinaryKvValue {
110 pub fn as_str(&self) -> Option<&str> {
112 match self {
113 BinaryKvValue::String(s) | BinaryKvValue::WideString(s) => Some(s),
114 _ => None,
115 }
116 }
117
118 pub fn as_i32(&self) -> Option<i32> {
120 match self {
121 BinaryKvValue::Int32(v) => Some(*v),
122 _ => None,
123 }
124 }
125
126 pub fn as_u64(&self) -> Option<u64> {
128 match self {
129 BinaryKvValue::UInt64(v) => Some(*v),
130 BinaryKvValue::Int64(v) => Some(*v as u64),
131 BinaryKvValue::Int32(v) => Some(*v as u64),
132 _ => None,
133 }
134 }
135
136 pub fn as_object(&self) -> Option<&HashMap<String, BinaryKvValue>> {
138 match self {
139 BinaryKvValue::Object(obj) => Some(obj),
140 _ => None,
141 }
142 }
143
144 pub fn get(&self, key: &str) -> Option<&BinaryKvValue> {
146 self.as_object().and_then(|obj| obj.get(key))
147 }
148
149 pub fn get_str(&self, key: &str) -> Option<&str> {
151 self.get(key).and_then(|v| v.as_str())
152 }
153
154 pub fn get_i32(&self, key: &str) -> Option<i32> {
156 self.get(key).and_then(|v| v.as_i32())
157 }
158}
159
160struct BinaryKvParser<R> {
162 reader: R,
163}
164
165impl<R: BufRead> BinaryKvParser<R> {
166 fn new(reader: R) -> Self {
167 Self { reader }
168 }
169
170 fn read_cstring(&mut self) -> Result<String, BinaryKvError> {
171 let mut bytes = Vec::new();
172 self.reader.read_until(0, &mut bytes)?;
173 if bytes.last() == Some(&0) {
174 bytes.pop();
175 }
176 String::from_utf8(bytes).map_err(|_| BinaryKvError::InvalidString)
177 }
178
179 fn read_value(&mut self, value_type: BinaryKvType) -> Result<BinaryKvValue, BinaryKvError> {
180 match value_type {
181 BinaryKvType::None => {
182 self.read_object()
184 }
185 BinaryKvType::String => {
186 let s = self.read_cstring()?;
187 Ok(BinaryKvValue::String(s))
188 }
189 BinaryKvType::Int32 => {
190 let v = self.reader.read_i32::<LittleEndian>()?;
191 Ok(BinaryKvValue::Int32(v))
192 }
193 BinaryKvType::Float32 => {
194 let v = self.reader.read_f32::<LittleEndian>()?;
195 Ok(BinaryKvValue::Float32(v))
196 }
197 BinaryKvType::Pointer => {
198 let v = self.reader.read_u32::<LittleEndian>()?;
199 Ok(BinaryKvValue::Pointer(v))
200 }
201 BinaryKvType::WideString => {
202 let mut chars = Vec::new();
204 loop {
205 let word = self.reader.read_u16::<LittleEndian>()?;
206 if word == 0 {
207 break;
208 }
209 chars.push(word);
210 }
211 let s = String::from_utf16(&chars).map_err(|_| BinaryKvError::InvalidString)?;
212 Ok(BinaryKvValue::WideString(s))
213 }
214 BinaryKvType::Color => {
215 let v = self.reader.read_u32::<LittleEndian>()?;
216 Ok(BinaryKvValue::Color(v))
217 }
218 BinaryKvType::UInt64 => {
219 let v = self.reader.read_u64::<LittleEndian>()?;
220 Ok(BinaryKvValue::UInt64(v))
221 }
222 BinaryKvType::Int64 => {
223 let v = self.reader.read_i64::<LittleEndian>()?;
224 Ok(BinaryKvValue::Int64(v))
225 }
226 BinaryKvType::End | BinaryKvType::AlternateEnd => {
227 Ok(BinaryKvValue::None)
229 }
230 }
231 }
232
233 fn read_object(&mut self) -> Result<BinaryKvValue, BinaryKvError> {
234 self.read_object_internal(true)
235 }
236
237 fn read_object_internal(&mut self, is_root: bool) -> Result<BinaryKvValue, BinaryKvError> {
238 let mut map = HashMap::new();
239 let mut is_first = true;
240
241 loop {
242 let type_byte = self.reader.read_u8()?;
243 let value_type = BinaryKvType::try_from(type_byte)?;
244
245 if value_type == BinaryKvType::End || value_type == BinaryKvType::AlternateEnd {
246 break;
247 }
248
249 let mut key = self.read_cstring()?;
250
251 if value_type == BinaryKvType::None && key.is_empty() && is_root && is_first {
255 key = self.read_cstring()?;
256 }
257
258 is_first = false;
259
260 let value = self.read_value_internal(value_type)?;
261
262 if !key.is_empty() {
264 map.insert(key, value);
265 }
266 }
267
268 Ok(BinaryKvValue::Object(map))
269 }
270
271 fn read_value_internal(&mut self, value_type: BinaryKvType) -> Result<BinaryKvValue, BinaryKvError> {
272 match value_type {
273 BinaryKvType::None => {
274 self.read_object_internal(false)
276 }
277 _ => self.read_value(value_type),
278 }
279 }
280
281 fn parse(&mut self) -> Result<BinaryKvValue, BinaryKvError> {
282 self.read_object()
284 }
285}
286
287pub fn parse_binary_kv(data: &[u8]) -> Result<BinaryKvValue, BinaryKvError> {
297 let cursor = Cursor::new(data);
298 let mut parser = BinaryKvParser::new(cursor);
299 parser.parse()
300}
301
302pub fn get_binary_kv_length(data: &[u8]) -> Result<usize, BinaryKvError> {
305 let mut pos = 0;
306
307 fn skip_object(data: &[u8], pos: &mut usize) -> Result<(), BinaryKvError> {
308 loop {
309 if *pos >= data.len() {
310 return Err(BinaryKvError::UnexpectedEof);
311 }
312
313 let type_byte = data[*pos];
314 *pos += 1;
315
316 if type_byte == 8 || type_byte == 11 {
317 return Ok(());
319 }
320
321 let value_type = BinaryKvType::try_from(type_byte)?;
322
323 while *pos < data.len() && data[*pos] != 0 {
325 *pos += 1;
326 }
327 if *pos >= data.len() {
328 return Err(BinaryKvError::UnexpectedEof);
329 }
330 *pos += 1; match value_type {
334 BinaryKvType::None => skip_object(data, pos)?,
335 BinaryKvType::String => {
336 while *pos < data.len() && data[*pos] != 0 {
337 *pos += 1;
338 }
339 if *pos >= data.len() {
340 return Err(BinaryKvError::UnexpectedEof);
341 }
342 *pos += 1;
343 }
344 BinaryKvType::Int32 | BinaryKvType::Float32 | BinaryKvType::Pointer | BinaryKvType::Color => {
345 if *pos + 4 > data.len() {
346 return Err(BinaryKvError::UnexpectedEof);
347 }
348 *pos += 4;
349 }
350 BinaryKvType::UInt64 | BinaryKvType::Int64 => {
351 if *pos + 8 > data.len() {
352 return Err(BinaryKvError::UnexpectedEof);
353 }
354 *pos += 8;
355 }
356 BinaryKvType::WideString => loop {
357 if *pos + 1 >= data.len() {
358 return Err(BinaryKvError::UnexpectedEof);
359 }
360 let word = u16::from_le_bytes([data[*pos], data[*pos + 1]]);
361 *pos += 2;
362 if word == 0 {
363 break;
364 }
365 },
366 BinaryKvType::End | BinaryKvType::AlternateEnd => return Ok(()),
367 }
368 }
369 }
370
371 skip_object(data, &mut pos)?;
372 Ok(pos)
373}
374
375#[cfg(test)]
376mod tests {
377 use super::*;
378
379 #[test]
380 fn test_simple_object() {
381 let mut data = Vec::new();
383 data.push(1); data.extend_from_slice(b"key\0"); data.extend_from_slice(b"value\0"); data.push(8); let result = parse_binary_kv(&data).unwrap();
389 assert_eq!(result.get_str("key"), Some("value"));
390 }
391
392 #[test]
393 fn test_int32_value() {
394 let mut data = Vec::new();
396 data.push(2); data.extend_from_slice(b"count\0"); data.extend_from_slice(&42i32.to_le_bytes()); data.push(8); let result = parse_binary_kv(&data).unwrap();
402 assert_eq!(result.get_i32("count"), Some(42));
403 }
404
405 #[test]
406 fn test_nested_object() {
407 let mut data = Vec::new();
409 data.push(0); data.extend_from_slice(b"parent\0"); data.push(1); data.extend_from_slice(b"child\0"); data.extend_from_slice(b"value\0"); data.push(8); data.push(8); let result = parse_binary_kv(&data).unwrap();
419 let parent = result.get("parent").unwrap();
420 assert_eq!(parent.get_str("child"), Some("value"));
421 }
422}