1#![cfg_attr(not(feature = "std"), no_std)]
18
19extern crate alloc;
20use alloc::string::String;
21use alloc::vec::Vec;
22use byteorder::{BigEndian, ByteOrder};
23use core::str;
24use osc_types10::{Bundle, Message, OscPacket, OscType};
25
26#[derive(Debug, Clone, PartialEq, Eq)]
28pub enum Error {
29 Truncated,
30 InvalidString,
31 InvalidTag,
32 UnexpectedEof,
33 NonMessageInBundle,
35}
36
37pub type Result<T> = core::result::Result<T, Error>;
38
39#[inline]
40fn pad4_len(len: usize) -> usize {
41 (4 - (len & 3)) & 3
42}
43
44fn put_str(buf: &mut Vec<u8>, s: &str) {
45 buf.extend_from_slice(s.as_bytes());
46 buf.push(0);
47 let pad = pad4_len(s.len() + 1);
48 buf.extend(std::iter::repeat_n(0, pad));
49}
50
51fn get_cstr_4(bytes: &[u8], mut off: usize) -> Result<(&str, usize)> {
52 let start = off;
54 while off < bytes.len() && bytes[off] != 0 {
55 off += 1;
56 }
57 if off >= bytes.len() {
58 return Err(Error::Truncated);
59 }
60 let s = core::str::from_utf8(&bytes[start..off]).map_err(|_| Error::InvalidString)?;
61 off += 1; let pad = pad4_len(off - start);
64 if off + pad > bytes.len() {
65 return Err(Error::Truncated);
66 }
67 Ok((s, off + pad))
68}
69
70#[inline]
71fn put_i32(buf: &mut Vec<u8>, v: i32) {
72 let mut tmp = [0u8; 4];
73 BigEndian::write_i32(&mut tmp, v);
74 buf.extend_from_slice(&tmp);
75}
76#[inline]
77fn put_f32(buf: &mut Vec<u8>, v: f32) {
78 let mut tmp = [0u8; 4];
79 BigEndian::write_f32(&mut tmp, v);
80 buf.extend_from_slice(&tmp);
81}
82
83#[inline]
84fn get_i32(bytes: &[u8], off: &mut usize) -> Result<i32> {
85 if *off + 4 > bytes.len() {
86 return Err(Error::UnexpectedEof);
87 }
88 let v = BigEndian::read_i32(&bytes[*off..*off + 4]);
89 *off += 4;
90 Ok(v)
91}
92#[inline]
93fn get_f32(bytes: &[u8], off: &mut usize) -> Result<f32> {
94 if *off + 4 > bytes.len() {
95 return Err(Error::UnexpectedEof);
96 }
97 let v = BigEndian::read_f32(&bytes[*off..*off + 4]);
98 *off += 4;
99 Ok(v)
100}
101
102pub fn encode_message(msg: &Message<'_>) -> Vec<u8> {
104 let mut buf = Vec::new();
105 put_str(&mut buf, msg.address);
106
107 let mut tag = String::from(",");
109 for a in &msg.args {
110 match a {
111 OscType::Int(_) => tag.push('i'),
112 OscType::Float(_) => tag.push('f'),
113 OscType::String(_) => tag.push('s'),
114 OscType::Blob(_) => tag.push('b'),
115 }
116 }
117 put_str(&mut buf, &tag);
118
119 for a in &msg.args {
120 match a {
121 OscType::Int(v) => put_i32(&mut buf, *v),
122 OscType::Float(v) => put_f32(&mut buf, *v),
123 OscType::String(s) => put_str(&mut buf, s),
124 OscType::Blob(b) => {
125 put_i32(&mut buf, b.len() as i32);
126 buf.extend_from_slice(b);
127 let pad = pad4_len(b.len());
128 buf.extend(std::iter::repeat_n(0, pad));
129 }
130 }
131 }
132 buf
133}
134
135pub fn decode_message<'a>(bytes: &'a [u8]) -> Result<(Message<'a>, usize)> {
137 let (address, mut off) = get_cstr_4(bytes, 0)?;
138 let (tag, off2) = get_cstr_4(bytes, off)?;
139 off = off2;
140
141 let mut args = Vec::new();
142 let mut chars = tag.chars();
143 if chars.next() != Some(',') {
144 return Err(Error::InvalidTag);
145 }
146
147 for t in chars {
148 match t {
149 'i' => {
150 args.push(OscType::Int(get_i32(bytes, &mut off)?));
151 }
152 'f' => {
153 args.push(OscType::Float(get_f32(bytes, &mut off)?));
154 }
155 's' => {
156 let (s, new_off) = get_cstr_4(bytes, off)?;
157 args.push(OscType::String(s));
158 off = new_off;
159 }
160 'b' => {
161 let len = get_i32(bytes, &mut off)? as usize;
162 if off + len > bytes.len() {
163 return Err(Error::UnexpectedEof);
164 }
165 let blob = &bytes[off..off + len];
166 off += len;
167 let pad = pad4_len(len);
168 if off + pad > bytes.len() {
169 return Err(Error::UnexpectedEof);
170 }
171 off += pad;
172 args.push(OscType::Blob(blob));
173 }
174 _ => return Err(Error::InvalidTag),
175 }
176 }
177
178 Ok((Message::new(address, args), off))
179}
180
181const BUNDLE_TAG: &str = "#bundle";
182
183pub fn encode_bundle(b: &Bundle<'_>) -> Vec<u8> {
185 let mut buf = Vec::new();
186 put_str(&mut buf, BUNDLE_TAG);
187 let mut tt = [0u8; 8];
189 BigEndian::write_u64(&mut tt, b.timetag);
190 buf.extend_from_slice(&tt);
191
192 for packet in &b.packets {
193 let pkt = match packet {
194 OscPacket::Message(msg) => encode_message(msg),
195 OscPacket::Bundle(bundle) => encode_bundle(bundle),
196 };
197 put_i32(&mut buf, pkt.len() as i32);
198 buf.extend_from_slice(&pkt);
199 }
200 buf
201}
202
203pub fn decode_bundle<'a>(bytes: &'a [u8]) -> Result<(Bundle<'a>, usize)> {
205 let (tag, mut off) = get_cstr_4(bytes, 0)?;
206 if tag != BUNDLE_TAG {
207 return Err(Error::InvalidString);
208 }
209 if off + 8 > bytes.len() {
210 return Err(Error::Truncated);
211 }
212 let timetag = BigEndian::read_u64(&bytes[off..off + 8]);
213 off += 8;
214
215 let mut packets = Vec::new();
216 while off < bytes.len() {
217 let size = get_i32(bytes, &mut off)? as usize;
218 if off + size > bytes.len() {
219 return Err(Error::Truncated);
220 }
221
222 let element_bytes = &bytes[off..off + size];
223
224 let is_bundle =
227 if element_bytes.len() >= 16 && element_bytes.starts_with(BUNDLE_TAG.as_bytes()) {
228 let tag_end = BUNDLE_TAG.len();
230 element_bytes.get(tag_end) == Some(&0) && {
231 let tag_with_null_len = tag_end + 1;
233 let padding = pad4_len(tag_with_null_len);
234 let timetag_start = tag_with_null_len + padding;
235 element_bytes.len() >= timetag_start + 8
237 }
238 } else {
239 false
240 };
241
242 if is_bundle {
243 match decode_bundle(element_bytes) {
245 Ok((bundle, used)) if used == size => {
246 packets.push(OscPacket::Bundle(bundle));
247 }
248 _ => {
249 let (msg, used) = decode_message(element_bytes)?;
251 if used != size {
252 return Err(Error::InvalidTag);
253 }
254 packets.push(OscPacket::Message(msg));
255 }
256 }
257 } else {
258 let (msg, used) = decode_message(element_bytes)?;
259 if used != size {
260 return Err(Error::InvalidTag);
261 }
262 packets.push(OscPacket::Message(msg));
263 }
264
265 off += size;
266 }
267 Ok((Bundle::new(timetag, packets), off))
268}