serde_llsd/ser/
binary.rs

1//! # ser/binary -- 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, serialization.
9//
10//  Animats
11//  March, 2021.
12//  License: LGPL.
13//
14use crate::LLSDValue;
15use anyhow::Error;
16use std::io::Write;
17//
18//  Constants
19//
20// Binary LLSD prefix
21pub const LLSDBINARYPREFIX: &[u8] = b"<? LLSD/Binary ?>\n"; // binary LLSD prefix
22pub const LLSDBINARYSENTINEL: &[u8] = LLSDBINARYPREFIX; // prefix must match exactly
23
24/// Outputs an LLSDValue as a string of bytes, in LLSD "binary" format.
25pub fn to_bytes(val: &LLSDValue) -> Result<Vec<u8>, Error> {
26    let mut writer: Vec<u8> = Vec::new(); // just make a stream and use the stream form
27    to_writer(&mut writer, val)?;
28    Ok(writer)
29}
30
31/// Outputs an LLSD value to an output stream
32pub fn to_writer<W: Write>(writer: &mut W, val: &LLSDValue) -> Result<(), Error> {
33    writer.write_all(LLSDBINARYPREFIX)?; // prefix
34    generate_value(writer, val)?;
35    writer.flush()?;
36    Ok(())
37}
38
39/// Generate one <TYPE> VALUE </TYPE> output. VALUE is recursive.
40fn generate_value<W: Write>(writer: &mut W, val: &LLSDValue) -> Result<(), Error> {
41    //  Emit binary for all possible types.
42    match val {
43        LLSDValue::Undefined => writer.write_all(b"!")?,
44        LLSDValue::Boolean(v) => writer.write_all(if *v { b"1" } else { b"0" })?,
45        LLSDValue::String(v) => {
46            writer.write_all(b"s")?;
47            writer.write_all(&(v.len() as u32).to_be_bytes())?;
48            writer.write_all(v.as_bytes())?
49        }
50        LLSDValue::URI(v) => {
51            writer.write_all(b"l")?;
52            writer.write_all(&(v.len() as u32).to_be_bytes())?;
53            writer.write_all(v.as_bytes())?
54        }
55        LLSDValue::Integer(v) => {
56            writer.write_all(b"i")?;
57            writer.write_all(&v.to_be_bytes())?
58        }
59        LLSDValue::Real(v) => {
60            writer.write_all(b"r")?;
61            writer.write_all(&v.to_be_bytes())?
62        }
63        LLSDValue::UUID(v) => {
64            writer.write_all(b"u")?;
65            writer.write_all(v.as_bytes())?
66        }
67        LLSDValue::Binary(v) => {
68            writer.write_all(b"b")?;
69            writer.write_all(&(v.len() as u32).to_be_bytes())?;
70            writer.write_all(v)?
71        }
72        LLSDValue::Date(v) => {
73            writer.write_all(b"d")?;
74            writer.write_all(&v.to_be_bytes())?
75        }
76
77        //  Map is { childcnt key value key value ... }
78        LLSDValue::Map(v) => {
79            //  Output count of key/value pairs
80            writer.write_all(b"{")?;
81            writer.write_all(&(v.len() as u32).to_be_bytes())?;
82            //  Output key/value pairs
83            for (key, value) in v {
84                writer.write_all(&[b'k'])?; // k prefix to key. UNDOCUMENTED
85                writer.write_all(&(key.len() as u32).to_be_bytes())?;
86                writer.write_all(key.as_bytes())?;
87                generate_value(writer, value)?;
88            }
89            writer.write_all(b"}")?
90        }
91        //  Array is [ childcnt child child ... ]
92        LLSDValue::Array(v) => {
93            //  Output count of array entries
94            writer.write_all(b"[")?;
95            writer.write_all(&(v.len() as u32).to_be_bytes())?;
96            //  Output array entries
97            for value in v {
98                generate_value(writer, value)?;
99            }
100            writer.write_all(b"]")?
101        }
102    };
103    Ok(())
104}