1use crate::Error;
2use std::collections::HashMap;
3use byteorder::{ByteOrder, LE};
4
5pub fn read_u64(buffer: &[u8]) -> Result<(&[u8], u64), Error> {
8 let mut result = 0;
9 let mut shift = 0;
10
11 for (i, &byte) in buffer.iter().enumerate() {
12 result |= (u64::from(byte) & 0x7f) << shift;
13 shift += 7;
14
15 if byte & 0x80 == 0 {
16 return Ok((&buffer[i + 1..], result));
17 }
18 }
19
20 Err(Error::UnexpectedEof)
21}
22
23pub fn read_container(buffer: &[u8]) -> Result<(&[u8], &[u8]), Error> {
24 let (buffer, len) = read_u64(buffer)?;
25 let (result, buffer) = buffer.split_at(len as usize);
26 Ok((buffer, result))
27}
28
29pub fn read_string(buffer: &[u8]) -> Result<String, Error> {
30 let (_, result) = read_container(buffer)?;
31 Ok(String::from_utf8_lossy(result).into())
32}
33
34pub enum ParseControl {
35 Continue,
36 Stop,
37}
38
39#[allow(clippy::needless_lifetimes)]
41pub fn parse_callback<'a, F>(buffer: &'a [u8], mut callback: F) -> Result<(), Error>
42where
43 F: FnMut(&'a [u8], &'a [u8]) -> ParseControl,
44{
45 let mmkv_len = LE::read_u32(&buffer) as usize;
47
48 if buffer.len() < mmkv_len + 4 {
49 Err(Error::BufferTooSmall(mmkv_len + 4))?;
50 }
51
52 let (next, _) = read_u64(&buffer[4..4 + mmkv_len])?;
54 let mut buffer = next;
55
56 while !buffer.is_empty() {
57 let (next, key) = read_container(buffer)?;
58 let (next, value) = read_container(next)?;
59 buffer = next;
60
61 match callback(key, value) {
62 ParseControl::Continue => continue,
63 ParseControl::Stop => break,
64 }
65 }
66
67 Ok(())
68}
69
70pub fn parse(buffer: &[u8]) -> Result<HashMap<&[u8], &[u8]>, Error> {
72 let mut result = HashMap::new();
73 parse_callback(buffer, |k, v| {
74 result.insert(k, v);
75 ParseControl::Continue
76 })?;
77 Ok(result)
78}
79
80pub fn parse_string_key_value_pairs(buffer: &[u8]) -> Result<HashMap<String, String>, Error> {
83 let mut result = HashMap::new();
84 let mut parse_err = Ok(());
85 parse_callback(buffer, |k, v| match read_string(v) {
86 Ok(value) => {
87 let k = String::from_utf8_lossy(k);
88 result.insert(k.into(), value);
89 ParseControl::Continue
90 }
91 Err(err) => {
92 parse_err = Err(err);
93 ParseControl::Stop
94 }
95 })
96 .and(parse_err)?;
97 Ok(result)
98}
99
100#[cfg(test)]
101mod test {
102 use std::collections::HashMap;
103
104 use super::*;
105
106 #[test]
107 fn test_read_u64() {
108 let buffer = [0xff, 0x81, 0x01, 0x00];
109 let value = read_u64(&buffer);
110 assert_eq!(value, Ok((&buffer[3..], 16639)));
111
112 let buffer = [0x81, 0xAA];
113 let value = read_u64(&buffer);
114 assert_eq!(value, Err(Error::UnexpectedEof));
115
116 let buffer = [0x80, 0x00, 0xff];
117 let value = read_u64(&buffer);
118 assert_eq!(value, Ok((&buffer[2..], 0)));
119 }
120
121 #[test]
122 fn test_read_container() {
123 let buffer = [0x03, b'A', b'B', b'C', 0];
124 let value = read_container(&buffer);
125 assert_eq!(value, Ok((&buffer[4..], &b"ABC"[..])));
126
127 let buffer = [0x00, b'A', b'B', b'C', 0];
128 let value = read_container(&buffer);
129 assert_eq!(value, Ok((&buffer[1..], &b""[..])));
130 }
131
132 #[test]
133 fn test_parse() {
134 let buffer = [
135 19, 0, 0, 0, 0xff,0xff,0xff,0x07,
137 0x03, b'A', b'B', b'C', 0, 0x03, b'D', b'E', b'F', 0x05, 0x04, b'1', b'2', b'3', b'4',
140 ];
141 let value = parse(&buffer);
142 let mut map = HashMap::new();
143 map.insert(&b"ABC"[..], &b""[..]);
144 map.insert(&b"DEF"[..], &b"\x041234"[..]);
145 assert_eq!(value, Ok(map));
146 }
147
148 #[test]
149 fn test_parse_buffer_len() {
150 let buffer = [
151 20, 0, 0, 0, ];
153 let value = parse(&buffer);
154 assert_eq!(value, Err(Error::BufferTooSmall(24)));
155 }
156
157 #[test]
158 fn test_parse_empty() {
159 let buffer = [
160 1, 0, 0, 0, 0, 0xff, ];
164 let value = parse(&buffer);
165 assert_eq!(value, Ok(HashMap::new()));
166 }
167}