serde_llsd/de/
binary.rs

1//! #  de/binary -- de-serialize LLSD, binary form.
2//!
3//!  Library for serializing and de-serializing data in
4//!  Linden Lab Structured Data format.
5//!
6//!  Format documentation is at http://wiki.secondlife.com/wiki/LLSD
7//!
8//!  Binary format.
9//
10//  Animats
11//  March, 2021.
12//  License: LGPL.
13//
14use crate::LLSDValue;
15use anyhow::{anyhow, Error};
16use std::collections::HashMap;
17use std::io::{Cursor, Read};
18use uuid;
19//
20//  Constants
21//
22pub const LLSDBINARYPREFIX: &[u8] = b"<? LLSD/Binary ?>\n"; // binary LLSD prefix
23pub const LLSDBINARYSENTINEL: &[u8] = LLSDBINARYPREFIX; // prefix must match exactly
24
25///    Parse LLSD array expressed in binary into an LLSDObject tree. No header.
26pub fn from_bytes(b: &[u8]) -> Result<LLSDValue, Error> {
27    let mut cursor: Cursor<&[u8]> = Cursor::new(b);
28    parse_value(&mut cursor)
29}
30
31///    Parse LLSD reader expressed in binary into an LLSDObject tree. No header.
32pub fn from_reader(cursor: &mut dyn Read) -> Result<LLSDValue, Error> {
33    parse_value(cursor)
34}
35
36/// Parse one value - real, integer, map, etc. Recursive.
37fn parse_value(cursor: &mut dyn Read) -> Result<LLSDValue, Error> {
38    //  These could be generic if generics with numeric parameters were in stable Rust.
39    fn read_u8(cursor: &mut dyn Read) -> Result<u8, Error> {
40        let mut b: [u8; 1] = [0; 1];
41        cursor.read_exact(&mut b)?; // read one byte
42        Ok(b[0])
43    }
44    fn read_u32(cursor: &mut dyn Read) -> Result<u32, Error> {
45        let mut b: [u8; 4] = [0; 4];
46        cursor.read_exact(&mut b)?; // read one byte
47        Ok(u32::from_be_bytes(b))
48    }
49    fn read_i32(cursor: &mut dyn Read) -> Result<i32, Error> {
50        let mut b: [u8; 4] = [0; 4];
51        cursor.read_exact(&mut b)?; // read one byte
52        Ok(i32::from_be_bytes(b))
53    }
54    fn read_i64(cursor: &mut dyn Read) -> Result<i64, Error> {
55        let mut b: [u8; 8] = [0; 8];
56        cursor.read_exact(&mut b)?; // read one byte
57        Ok(i64::from_be_bytes(b))
58    }
59    fn read_f64(cursor: &mut dyn Read) -> Result<f64, Error> {
60        let mut b: [u8; 8] = [0; 8];
61        cursor.read_exact(&mut b)?; // read one byte
62        Ok(f64::from_be_bytes(b))
63    }
64    fn read_variable(cursor: &mut dyn Read) -> Result<Vec<u8>, Error> {
65        let length = read_u32(cursor)?; // read length in bytes
66        let mut buf = vec![0u8; length as usize];
67        cursor.read_exact(&mut buf)?;
68        Ok(buf) // read bytes of string
69    }
70
71    let typecode = read_u8(cursor)?;
72    match typecode {
73        //  Undefined - the empty value
74        b'!' => Ok(LLSDValue::Undefined),
75        //  Boolean - 1 or 0
76        b'0' => Ok(LLSDValue::Boolean(false)),
77        b'1' => Ok(LLSDValue::Boolean(true)),
78        //  String - length followed by data
79        b's' => Ok(LLSDValue::String(
80            std::str::from_utf8(&read_variable(cursor)?)?.to_string(),
81        )),
82        //  URI - length followed by data
83        b'l' => Ok(LLSDValue::URI(
84            std::str::from_utf8(&read_variable(cursor)?)?.to_string(),
85        )),
86        //  Integer - 4 bytes
87        b'i' => Ok(LLSDValue::Integer(read_i32(cursor)?)),
88        //  Real - 4 bytes
89        b'r' => Ok(LLSDValue::Real(read_f64(cursor)?)),
90        //  UUID - 16 bytes
91        b'u' => {
92            let mut buf: [u8; 16] = [0u8; 16];
93            cursor.read_exact(&mut buf)?; // read bytes of string
94            Ok(LLSDValue::UUID(uuid::Uuid::from_bytes(buf)))
95        }
96        //  Binary - length followed by data
97        b'b' => Ok(LLSDValue::Binary(read_variable(cursor)?)),
98        //  Date - 64 bits
99        b'd' => Ok(LLSDValue::Date(read_i64(cursor)?)),
100        //  Map -- keyed collection of items
101        b'{' => {
102            let mut dict: HashMap<String, LLSDValue> = HashMap::new(); // accumulate hash here
103            let count = read_u32(cursor)?; // number of items
104            for _ in 0..count {
105                let keyprefix = &read_u8(cursor)?; // key should begin with b'k';
106                match keyprefix {
107                    b'k' => {
108                        let key = std::str::from_utf8(&read_variable(cursor)?)?.to_string();
109                        let _ = dict.insert(key, parse_value(cursor)?); // recurse and add, allowing dups
110                    }
111                    _ => {
112                        return Err(anyhow!(
113                            "Binary LLSD map key had {:?} instead of expected 'k'",
114                            keyprefix
115                        ))
116                    }
117                }
118            }
119            if read_u8(cursor)? != b'}' {
120                return Err(anyhow!("Binary LLSD map did not end properly with }}"));
121            }
122            Ok(LLSDValue::Map(dict))
123        }
124        //  Array -- array of items
125        b'[' => {
126            let mut array: Vec<LLSDValue> = Vec::new(); // accumulate hash here
127            let count = read_u32(cursor)?; // number of items
128            for _ in 0..count {
129                array.push(parse_value(cursor)?); // recurse and add, allowing dups
130            }
131            if read_u8(cursor)? != b']' {
132                return Err(anyhow!("Binary LLSD array did not end properly with ] "));
133            }
134            Ok(LLSDValue::Array(array))
135        }
136
137        _ => Err(anyhow!("Binary LLSD, unexpected type code {:?}", typecode)),
138    }
139}
140
141// Unit test
142
143#[test]
144fn binaryparsetest1() {
145    //  Construct a test value.
146    let test1map: HashMap<String, LLSDValue> = [
147        ("val1".to_string(), LLSDValue::Real(456.0)),
148        ("val2".to_string(), LLSDValue::Integer(999)),
149    ]
150    .iter()
151    .cloned()
152    .collect();
153    let test1: LLSDValue = LLSDValue::Array(vec![
154        LLSDValue::Real(123.5),
155        LLSDValue::Map(test1map),
156        LLSDValue::Integer(42),
157        LLSDValue::String("Hello world".to_string()),
158    ]);
159    //  Convert to binary form.
160    let test1bin = crate::to_bytes(&test1).unwrap();
161    println!("Binary form: {:?}", test1bin);
162    //  Convert back to value form.
163    let test1value = from_bytes(&test1bin[LLSDBINARYSENTINEL.len()..]).unwrap();
164    println!("Value after round-trip conversion: {:?}", test1value);
165    //  Check that results match after round trip.
166    assert_eq!(test1, test1value);
167}