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