bt_obex/header/
obex_string.rs1use crate::error::PacketError;
6
7#[derive(Clone, Debug, PartialEq)]
11pub struct ObexString(pub String);
12
13impl ObexString {
14 pub fn len(&self) -> usize {
15 self.to_be_bytes().len()
16 }
17
18 pub fn to_be_bytes(&self) -> Vec<u8> {
19 self.0
20 .encode_utf16()
21 .chain([0]) .map(|v| v.to_be_bytes())
23 .flatten()
24 .collect()
25 }
26}
27
28impl From<String> for ObexString {
29 fn from(src: String) -> ObexString {
30 ObexString(src)
31 }
32}
33
34impl From<&str> for ObexString {
35 fn from(src: &str) -> ObexString {
36 ObexString(src.to_string())
37 }
38}
39
40impl TryFrom<&[u8]> for ObexString {
41 type Error = PacketError;
42
43 fn try_from(src: &[u8]) -> Result<Self, Self::Error> {
44 if src.len() == 0 {
45 return Ok(Self(String::new()));
46 }
47
48 let unicode_array = src
49 .chunks_exact(2)
50 .into_iter()
51 .map(|a| u16::from_be_bytes([a[0], a[1]]))
52 .collect::<Vec<u16>>();
53 let mut text = String::from_utf16(&unicode_array).map_err(PacketError::external)?;
54 if !text.ends_with('\0') {
56 return Err(PacketError::data("text missing null terminator"));
57 }
58
59 let _ = text.pop();
60 Ok(Self(text))
61 }
62}
63
64impl ToString for ObexString {
65 fn to_string(&self) -> String {
66 self.0.clone()
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 use assert_matches::assert_matches;
75
76 fn expect_strings_equal(s1: ObexString, s2: String) {
77 assert_eq!(s1.0, s2);
78 }
79
80 #[fuchsia::test]
81 fn obex_string_from_bytes() {
82 let converted = ObexString::try_from(&[][..]).expect("can convert to String");
84 expect_strings_equal(converted, "".to_string());
85
86 let buf = [0x00, 0x00];
88 let converted = ObexString::try_from(&buf[..]).expect("can convert to String");
89 expect_strings_equal(converted, "".to_string());
90
91 let buf = [0x00, 0x68, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x00];
93 let converted = ObexString::try_from(&buf[..]).expect("can convert to String");
94 expect_strings_equal(converted, "hello".to_string());
95
96 let buf = [0x00, 0x62, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00];
98 let converted = ObexString::try_from(&buf[..]).expect("can convert to String");
99 expect_strings_equal(converted, "bob\0".to_string());
100 }
101
102 #[fuchsia::test]
103 fn obex_string_missing_terminator_is_error() {
104 let buf =
106 [0x00, 0x66, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x78, 0x00, 0x74];
107 let converted = ObexString::try_from(&buf[..]);
108 assert_matches!(converted, Err(PacketError::Data(_)));
109 }
110
111 #[fuchsia::test]
112 fn obex_string_invalid_utf16_is_error() {
113 let buf =
115 [0xd8, 0x34, 0xdd, 0x1e, 0x00, 0x6d, 0x00, 0x75, 0xd8, 0x00, 0x00, 0x69, 0x00, 0x63];
116 let converted = ObexString::try_from(&buf[..]);
117 assert_matches!(converted, Err(PacketError::Other(_)));
118 }
119}