1use std::io::{Read, Write};
2
3use chrono::{DateTime, Utc};
4use uuid::Uuid;
5
6use crate::{Llsd, Uri};
7
8fn write_inner<W: Write>(llsd: &Llsd, w: &mut W) -> Result<(), anyhow::Error> {
9 match llsd {
10 Llsd::Undefined => w.write_all(b"!")?,
11 Llsd::Boolean(v) => w.write_all(if *v { b"1" } else { b"0" })?,
12 Llsd::Integer(v) => {
13 w.write_all(b"i")?;
14 w.write_all(&v.to_be_bytes())?;
15 }
16 Llsd::Real(v) => {
17 w.write_all(b"r")?;
18 w.write_all(&v.to_be_bytes())?;
19 }
20 Llsd::String(v) => {
21 w.write_all(b"s")?;
22 w.write_all(&(v.len() as u32).to_be_bytes())?;
23 w.write_all(v.as_bytes())?;
24 }
25 Llsd::Uri(v) => {
26 w.write_all(b"l")?;
27 let v = v.as_str();
28 w.write_all(&(v.len() as u32).to_be_bytes())?;
29 w.write_all(v.as_bytes())?;
30 }
31 Llsd::Uuid(v) => {
32 w.write_all(b"u")?;
33 w.write_all((*v).as_bytes())?;
34 }
35 Llsd::Date(v) => {
36 w.write_all(b"d")?;
37 let real: f64 =
38 v.timestamp() as f64 + (v.timestamp_subsec_nanos() as f64 / 1_000_000_000.0);
39 w.write_all(&real.to_le_bytes())?;
41 }
42 Llsd::Binary(v) => {
43 w.write_all(b"b")?;
44 w.write_all(&(v.len() as u32).to_be_bytes())?;
45 w.write_all(v)?;
46 }
47 Llsd::Array(v) => {
48 w.write_all(b"[")?;
49 w.write_all(&(v.len() as u32).to_be_bytes())?;
50 for e in v {
51 write_inner(e, w)?;
52 }
53 w.write_all(b"]")?;
54 }
55 Llsd::Map(v) => {
56 w.write_all(b"{")?;
57 w.write_all(&(v.len() as u32).to_be_bytes())?;
58 for (k, e) in v {
59 w.write_all(b"k")?;
60 w.write_all(&(k.len() as u32).to_be_bytes())?;
61 w.write_all(k.as_bytes())?;
62 write_inner(e, w)?;
63 }
64 w.write_all(b"}")?;
65 }
66 }
67 Ok(())
68}
69
70pub fn write<W: Write>(llsd: &Llsd, w: &mut W) -> Result<(), anyhow::Error> {
71 write_inner(llsd, w)
72}
73
74pub fn to_vec(llsd: &Llsd) -> Result<Vec<u8>, anyhow::Error> {
75 let mut buf = Vec::new();
76 write(llsd, &mut buf)?;
77 Ok(buf)
78}
79
80macro_rules! read_be_fn {
81 ($func_name:ident, $type:ty) => {
82 fn $func_name<R: Read>(reader: &mut R) -> Result<$type, anyhow::Error> {
83 let mut buf = [0_u8; std::mem::size_of::<$type>()];
84 reader.read_exact(&mut buf)?;
85 Ok(<$type>::from_be_bytes(buf))
86 }
87 };
88}
89
90read_be_fn!(read_u8, u8);
91read_be_fn!(read_i32_be, i32);
92read_be_fn!(read_f64_be, f64);
93
94fn hex<R: Read>(r: &mut R) -> Result<u8, anyhow::Error> {
95 let c = read_u8(r)?;
96 match c {
97 b'0'..=b'9' => Ok(c - b'0'),
98 b'a'..=b'f' => Ok(c - b'a' + 10),
99 b'A'..=b'F' => Ok(c - b'A' + 10),
100 _ => Ok(0),
101 }
102}
103
104fn unescape<R: Read>(r: &mut R, delim: u8) -> Result<String, anyhow::Error> {
105 let mut buf = Vec::new();
106 loop {
107 match read_u8(r)? {
108 c if c == delim => break,
109 b'\\' => match read_u8(r)? {
110 b'a' => buf.push(0x07),
111 b'b' => buf.push(0x08),
112 b'f' => buf.push(0x0c),
113 b'n' => buf.push(b'\n'),
114 b'r' => buf.push(b'\r'),
115 b't' => buf.push(b'\t'),
116 b'v' => buf.push(0x0b),
117 b'\\' => buf.push(b'\\'),
118 b'\'' => buf.push(b'\''),
119 b'"' => buf.push(b'"'),
120 b'x' => buf.push((hex(r)? << 4) | hex(r)?),
121 other => buf.push(other),
122 },
123 other => buf.push(other),
124 }
125 }
126 Ok(String::from_utf8(buf)?)
127}
128
129pub fn from_reader_inner<R: Read>(r: &mut R) -> Result<Llsd, anyhow::Error> {
130 match read_u8(r)? {
131 b'!' => Ok(Llsd::Undefined),
132 b'1' => Ok(Llsd::Boolean(true)),
133 b'0' => Ok(Llsd::Boolean(false)),
134 b'i' => Ok(Llsd::Integer(read_i32_be(r)?)),
135 b'r' => Ok(Llsd::Real(read_f64_be(r)?)),
136 b's' => {
137 let len = read_i32_be(r)? as usize;
138 let mut buf = vec![0; len];
139 r.read_exact(&mut buf)?;
140 Ok(Llsd::String(String::from_utf8(buf)?))
141 }
142 b'l' => {
143 let len = read_i32_be(r)? as usize;
144 let mut buf = vec![0; len];
145 r.read_exact(&mut buf)?;
146 Ok(Llsd::Uri(Uri::parse(std::str::from_utf8(&buf)?)))
147 }
148 b'u' => {
149 let mut buf = [0_u8; 16];
150 r.read_exact(&mut buf)?;
151 Ok(Llsd::Uuid(Uuid::from_slice(&buf)?))
152 }
153 b'd' => {
154 let mut buf = [0_u8; 8];
155 r.read_exact(&mut buf)?;
156 let real = f64::from_le_bytes(buf);
158 let date = DateTime::<Utc>::from_timestamp(
159 real.trunc() as i64,
160 (real.fract() * 1_000_000_000.0) as u32,
161 );
162 Ok(Llsd::Date(date.unwrap_or_default()))
163 }
164 b'b' => {
165 let len = read_i32_be(r)? as usize;
166 let mut buf = vec![0; len];
167 r.read_exact(&mut buf)?;
168 Ok(Llsd::Binary(buf))
169 }
170 b'[' => {
171 let len = read_i32_be(r)? as usize;
172 let mut buf = Vec::with_capacity(len);
173 for _ in 0..len {
174 buf.push(from_reader_inner(r)?);
175 }
176 Ok(Llsd::Array(buf))
177 }
178 b'{' => {
179 let len = read_i32_be(r)? as usize;
180 let mut buf = std::collections::HashMap::with_capacity(len);
181 for _ in 0..len {
182 if read_u8(r)? != b'k' {
183 return Err(anyhow::anyhow!("Expected 'k'"));
184 }
185 let key_len = read_i32_be(r)? as usize;
186 let mut key_buf = vec![0; key_len];
187 r.read_exact(&mut key_buf)?;
188 let key = String::from_utf8(key_buf)?;
189 let value = from_reader_inner(r)?;
190 buf.insert(key, value);
191 }
192 if read_u8(r)? != b'}' {
193 return Err(anyhow::anyhow!("Expected '}}'"));
194 }
195 Ok(Llsd::Map(buf))
196 }
197 b'"' => Ok(Llsd::String(unescape(r, b'"')?)),
198 b'\'' => Ok(Llsd::String(unescape(r, b'\'')?)),
199 other => Err(anyhow::anyhow!("Unknown LLSD type: {}", other)),
200 }
201}
202
203pub fn from_reader<R: Read>(r: &mut R) -> Result<Llsd, anyhow::Error> {
204 from_reader_inner(r)
205}
206
207pub fn from_slice(data: &[u8]) -> Result<Llsd, anyhow::Error> {
208 from_reader(&mut std::io::Cursor::new(data))
209}
210
211#[cfg(test)]
212mod tests {
213 use super::*;
214 use chrono::{TimeZone, Utc};
215 use std::collections::HashMap;
216
217 fn round_trip(llsd: Llsd) {
218 let encoded = to_vec(&llsd).expect("Failed to encode");
219 let decoded = from_slice(&encoded).expect("Failed to decode");
220 assert_eq!(llsd, decoded);
221 }
222
223 #[test]
224 fn undefined() {
225 round_trip(Llsd::Undefined);
226 }
227
228 #[test]
229 fn boolean() {
230 round_trip(Llsd::Boolean(true));
231 round_trip(Llsd::Boolean(false));
232 }
233
234 #[test]
235 fn integer() {
236 round_trip(Llsd::Integer(42));
237 }
238
239 #[test]
240 fn real() {
241 round_trip(Llsd::Real(13.1415));
242 }
243
244 #[test]
245 fn string() {
246 round_trip(Llsd::String("Hello, LLSD!".to_owned()));
247 }
248
249 #[test]
250 fn uri() {
251 round_trip(Llsd::Uri(Uri::parse("https://example.com/")));
252 }
253
254 #[test]
255 fn uuid() {
256 let uuid = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
257 round_trip(Llsd::Uuid(uuid));
258 }
259
260 #[test]
261 fn date() {
262 let dt = Utc.timestamp_opt(1_620_000_000, 0).unwrap();
263 round_trip(Llsd::Date(dt));
264 }
265
266 #[test]
267 fn binary() {
268 round_trip(Llsd::Binary(vec![0xde, 0xad, 0xbe, 0xef]));
269 }
270
271 #[test]
272 fn array() {
273 let arr = vec![
274 Llsd::Integer(1),
275 Llsd::String("two".into()),
276 Llsd::Boolean(false),
277 ];
278 round_trip(Llsd::Array(arr));
279 }
280
281 #[test]
282 fn map() {
283 let mut map = HashMap::new();
284 map.insert("answer".into(), Llsd::Integer(42));
285 map.insert("pi".into(), Llsd::Real(13.14));
286 map.insert("greeting".into(), Llsd::String("hello".into()));
287 round_trip(Llsd::Map(map));
288 }
289}