Skip to main content

opcua/types/
byte_string.rs

1// OPCUA for Rust
2// SPDX-License-Identifier: MPL-2.0
3// Copyright (C) 2017-2022 Adam Lock
4
5//! Contains the implementation of `ByteString`.
6
7use std::{
8    convert::TryFrom,
9    fmt,
10    io::{Read, Write},
11};
12
13use base64::{engine::general_purpose::STANDARD, Engine};
14use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
15
16use crate::types::{
17    encoding::{
18        process_decode_io_result, process_encode_io_result, write_i32, BinaryEncoder,
19        DecodingOptions, EncodingResult,
20    },
21    status_codes::StatusCode,
22    Guid,
23};
24
25/// A sequence of octets.
26#[derive(Eq, PartialEq, Debug, Clone, Hash)]
27pub struct ByteString {
28    pub value: Option<Vec<u8>>,
29}
30
31impl AsRef<[u8]> for ByteString {
32    fn as_ref(&self) -> &[u8] {
33        if self.value.is_none() {
34            &[]
35        } else {
36            self.value.as_ref().unwrap()
37        }
38    }
39}
40
41impl Serialize for ByteString {
42    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
43    where
44        S: Serializer,
45    {
46        if self.value.is_some() {
47            serializer.serialize_str(&self.as_base64())
48        } else {
49            serializer.serialize_none()
50        }
51    }
52}
53struct ByteStringVisitor;
54
55impl<'de> serde::de::Visitor<'de> for ByteStringVisitor {
56    type Value = ByteString;
57    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
58        write!(formatter, "a base64 encoded string value or null")
59    }
60
61    fn visit_none<E>(self) -> Result<Self::Value, E>
62    where
63        E: de::Error,
64    {
65        Ok(Self::Value::null())
66    }
67
68    fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
69    where
70        D: Deserializer<'de>,
71    {
72        deserializer.deserialize_str(self)
73    }
74
75    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
76    where
77        E: de::Error,
78    {
79        Self::Value::from_base64(v)
80            .ok_or_else(|| de::Error::custom("Cannot decode base64 bytestring"))
81    }
82}
83
84impl<'de> Deserialize<'de> for ByteString {
85    fn deserialize<D>(deserializer: D) -> Result<ByteString, D::Error>
86    where
87        D: Deserializer<'de>,
88    {
89        deserializer.deserialize_option(ByteStringVisitor)
90    }
91}
92
93impl BinaryEncoder<ByteString> for ByteString {
94    fn byte_len(&self) -> usize {
95        // Length plus the actual length of bytes (if not null)
96        4 + if self.value.is_none() {
97            0
98        } else {
99            self.value.as_ref().unwrap().len()
100        }
101    }
102
103    fn encode<S: Write>(&self, stream: &mut S) -> EncodingResult<usize> {
104        // Strings are uncoded as UTF8 chars preceded by an Int32 length. A -1 indicates a null string
105        if self.value.is_none() {
106            write_i32(stream, -1)
107        } else {
108            let mut size: usize = 0;
109            let value = self.value.as_ref().unwrap();
110            size += write_i32(stream, value.len() as i32)?;
111            size += process_encode_io_result(stream.write(value))?;
112            assert_eq!(size, self.byte_len());
113            Ok(size)
114        }
115    }
116
117    fn decode<S: Read>(stream: &mut S, decoding_options: &DecodingOptions) -> EncodingResult<Self> {
118        let len = i32::decode(stream, decoding_options)?;
119        // Null string?
120        if len == -1 {
121            Ok(ByteString::null())
122        } else if len < -1 {
123            error!("ByteString buf length is a negative number {}", len);
124            Err(StatusCode::BadDecodingError)
125        } else if len as usize > decoding_options.max_byte_string_length {
126            error!(
127                "ByteString length {} exceeds decoding limit {}",
128                len, decoding_options.max_string_length
129            );
130            Err(StatusCode::BadDecodingError)
131        } else {
132            // Create a buffer filled with zeroes and read the byte string over the top
133            let mut buf: Vec<u8> = vec![0u8; len as usize];
134            process_decode_io_result(stream.read_exact(&mut buf))?;
135            Ok(ByteString { value: Some(buf) })
136        }
137    }
138}
139
140impl<'a, T> From<&'a T> for ByteString
141where
142    T: AsRef<[u8]> + ?Sized,
143{
144    fn from(value: &'a T) -> Self {
145        Self::from(value.as_ref().to_vec())
146    }
147}
148
149impl From<Vec<u8>> for ByteString {
150    fn from(value: Vec<u8>) -> Self {
151        // Empty bytes will be treated as Some([])
152        ByteString { value: Some(value) }
153    }
154}
155
156impl From<Guid> for ByteString {
157    fn from(value: Guid) -> Self {
158        ByteString::from(value.as_bytes().to_vec())
159    }
160}
161
162impl TryFrom<&ByteString> for Guid {
163    type Error = ();
164
165    fn try_from(value: &ByteString) -> Result<Self, Self::Error> {
166        if value.is_null_or_empty() {
167            Err(())
168        } else {
169            let bytes = value.as_ref();
170            if bytes.len() != 16 {
171                Err(())
172            } else {
173                let mut guid = [0u8; 16];
174                guid.copy_from_slice(bytes);
175                Ok(Guid::from_bytes(guid))
176            }
177        }
178    }
179}
180
181impl Into<String> for ByteString {
182    fn into(self) -> String {
183        self.as_base64()
184    }
185}
186
187impl Default for ByteString {
188    fn default() -> Self {
189        ByteString::null()
190    }
191}
192
193impl ByteString {
194    /// Create a null string (not the same as an empty string)
195    pub fn null() -> ByteString {
196        ByteString { value: None }
197    }
198
199    /// Test if the string is null
200    pub fn is_null(&self) -> bool {
201        self.value.is_none()
202    }
203
204    // Test if the bytestring has an empty value (not the same as null)
205    pub fn is_empty(&self) -> bool {
206        if let Some(v) = &self.value {
207            v.is_empty()
208        } else {
209            false
210        }
211    }
212
213    /// Test if the string is null or empty
214    pub fn is_null_or_empty(&self) -> bool {
215        self.is_null() || self.is_empty()
216    }
217
218    /// Creates a byte string from a Base64 encoded string
219    pub fn from_base64(data: &str) -> Option<ByteString> {
220        if let Ok(bytes) = STANDARD.decode(data) {
221            Some(Self::from(bytes))
222        } else {
223            None
224        }
225    }
226
227    /// Encodes the bytestring as a Base64 encoded string
228    pub fn as_base64(&self) -> String {
229        // Base64 encodes the byte string so it can be represented as a string
230        if let Some(ref value) = self.value {
231            STANDARD.encode(value)
232        } else {
233            STANDARD.encode("")
234        }
235    }
236
237    /// This function is meant for use with NumericRange. It creates a substring from this string
238    /// from min up to and inclusive of max. Note that min must have an index within the string
239    /// but max is allowed to be beyond the end in which case the remainder of the string is
240    /// returned (see docs for NumericRange).
241    pub fn substring(&self, min: usize, max: usize) -> Result<ByteString, ()> {
242        if let Some(ref v) = self.value {
243            if min >= v.len() {
244                Err(())
245            } else {
246                let max = if max >= v.len() { v.len() - 1 } else { max };
247                let v = v[min..=max].to_vec();
248                Ok(ByteString::from(v))
249            }
250        } else {
251            Err(())
252        }
253    }
254}
255
256#[test]
257fn bytestring_null() {
258    let v = ByteString::null();
259    assert!(v.is_null());
260}
261
262#[test]
263fn bytestring_empty() {
264    let v = ByteString::from(&[]);
265    assert!(!v.is_null());
266    assert!(v.is_null_or_empty());
267    assert!(v.is_empty());
268}
269
270#[test]
271fn bytestring_bytes() {
272    let a = [0x1u8, 0x2u8, 0x3u8, 0x4u8];
273    let v = ByteString::from(&a);
274    assert!(!v.is_null());
275    assert!(!v.is_empty());
276    assert_eq!(v.value.as_ref().unwrap(), &a);
277}
278
279#[test]
280fn bytestring_substring() {
281    let a = [0x1u8, 0x2u8, 0x3u8, 0x4u8];
282    let v = ByteString::from(&a);
283    let v2 = v.substring(2, 10000).unwrap();
284    let a2 = v2.value.as_ref().unwrap().as_slice();
285    assert_eq!(a2, &a[2..]);
286
287    let v2 = v.substring(2, 2).unwrap();
288    let a2 = v2.value.as_ref().unwrap().as_slice();
289    assert_eq!(a2, &a[2..3]);
290
291    let v2 = v.substring(0, 2000).unwrap();
292    assert_eq!(v, v2);
293    assert_eq!(v2.value.as_ref().unwrap(), &a);
294
295    assert!(v.substring(4, 10000).is_err());
296    assert!(ByteString::null().substring(0, 0).is_err());
297}