xsd_types/value/
base64_binary.rs

1use std::{
2	borrow::Borrow,
3	fmt,
4	ops::{Deref, DerefMut},
5	str::FromStr,
6};
7
8use crate::{
9	lexical::{self, LexicalFormOf},
10	Datatype, ParseXsd, XsdValue,
11};
12
13const CHARS: [char; 64] = [
14	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
15	'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
16	'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
17	'5', '6', '7', '8', '9', '+', '/',
18];
19
20const PADDING: char = '=';
21
22#[derive(Debug, thiserror::Error)]
23#[error("invalid base64")]
24pub struct InvalidBase64;
25
26#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
27pub struct Base64BinaryBuf(Vec<u8>);
28
29impl Base64BinaryBuf {
30	pub fn new() -> Self {
31		Self::default()
32	}
33
34	pub fn from_bytes(bytes: Vec<u8>) -> Self {
35		Self(bytes)
36	}
37
38	pub fn decode(input: impl AsRef<[u8]>) -> Result<Self, InvalidBase64> {
39		let input = input.as_ref();
40		let mut bytes = Vec::with_capacity(input.len() * 3 / 4);
41		let mut buffer = 0u16;
42		let mut buffer_len = 0u16;
43		let mut padding = false;
44
45		for &c in input {
46			if c == 0x20 {
47				continue;
48			}
49
50			if padding {
51				if c != b'=' {
52					return Err(InvalidBase64);
53				}
54			} else if c == b'=' {
55				padding = true
56			} else {
57				buffer_len += 6;
58				buffer = buffer << 6 | decode_char(c)? as u16;
59
60				while buffer_len >= 8 {
61					buffer_len -= 8;
62					let b = buffer >> buffer_len;
63					bytes.push(b as u8)
64				}
65			}
66		}
67
68		Ok(Self(bytes))
69	}
70
71	pub fn into_bytes(self) -> Vec<u8> {
72		self.0
73	}
74
75	pub fn as_bytes(&self) -> &[u8] {
76		&self.0
77	}
78
79	pub fn as_base64_binary(&self) -> &Base64Binary {
80		Base64Binary::new(&self.0)
81	}
82
83	pub fn as_base64_binary_mut(&mut self) -> &mut Base64Binary {
84		Base64Binary::new_mut(&mut self.0)
85	}
86}
87
88fn decode_char(c: u8) -> Result<u8, InvalidBase64> {
89	match c {
90		b'A'..=b'Z' => Ok(c - b'A'),
91		b'a'..=b'z' => Ok(c - b'a' + 26),
92		b'0'..=b'9' => Ok(c - b'0' + 52),
93		b'+' => Ok(62),
94		b'/' => Ok(63),
95		_ => Err(InvalidBase64),
96	}
97}
98
99impl fmt::Display for Base64BinaryBuf {
100	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101		self.as_base64_binary().fmt(f)
102	}
103}
104
105impl From<Vec<u8>> for Base64BinaryBuf {
106	fn from(value: Vec<u8>) -> Self {
107		Base64BinaryBuf::from_bytes(value)
108	}
109}
110
111impl FromStr for Base64BinaryBuf {
112	type Err = InvalidBase64;
113
114	fn from_str(s: &str) -> Result<Self, Self::Err> {
115		Self::decode(s)
116	}
117}
118
119impl AsRef<[u8]> for Base64BinaryBuf {
120	fn as_ref(&self) -> &[u8] {
121		self.as_bytes()
122	}
123}
124
125impl AsRef<Base64Binary> for Base64BinaryBuf {
126	fn as_ref(&self) -> &Base64Binary {
127		self.as_base64_binary()
128	}
129}
130
131impl Borrow<Base64Binary> for Base64BinaryBuf {
132	fn borrow(&self) -> &Base64Binary {
133		self.as_base64_binary()
134	}
135}
136
137impl Deref for Base64BinaryBuf {
138	type Target = Base64Binary;
139
140	fn deref(&self) -> &Self::Target {
141		self.as_base64_binary()
142	}
143}
144
145impl DerefMut for Base64BinaryBuf {
146	fn deref_mut(&mut self) -> &mut Self::Target {
147		self.as_base64_binary_mut()
148	}
149}
150
151impl XsdValue for Base64BinaryBuf {
152	fn datatype(&self) -> Datatype {
153		Datatype::Base64Binary
154	}
155}
156
157impl ParseXsd for Base64BinaryBuf {
158	type LexicalForm = lexical::Base64Binary;
159}
160
161impl LexicalFormOf<Base64BinaryBuf> for lexical::Base64Binary {
162	type ValueError = std::convert::Infallible;
163
164	fn try_as_value(&self) -> Result<Base64BinaryBuf, Self::ValueError> {
165		Ok(self.value())
166	}
167}
168
169#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
170pub struct Base64Binary([u8]);
171
172impl Base64Binary {
173	pub fn new(bytes: &[u8]) -> &Self {
174		unsafe { std::mem::transmute(bytes) }
175	}
176
177	pub fn new_mut(bytes: &mut [u8]) -> &mut Self {
178		unsafe { std::mem::transmute(bytes) }
179	}
180
181	pub fn chars(&self) -> Chars {
182		Chars {
183			offset: 0,
184			rest: 0,
185			padding: false,
186			bytes: self.0.iter(),
187		}
188	}
189
190	pub fn as_bytes(&self) -> &[u8] {
191		&self.0
192	}
193}
194
195impl<'a> From<&'a [u8]> for &'a Base64Binary {
196	fn from(value: &'a [u8]) -> Self {
197		Base64Binary::new(value)
198	}
199}
200
201impl<'a> From<&'a mut [u8]> for &'a Base64Binary {
202	fn from(value: &'a mut [u8]) -> Self {
203		Base64Binary::new(value)
204	}
205}
206
207impl<'a> From<&'a mut [u8]> for &'a mut Base64Binary {
208	fn from(value: &'a mut [u8]) -> Self {
209		Base64Binary::new_mut(value)
210	}
211}
212
213impl fmt::Display for Base64Binary {
214	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215		for c in self.chars() {
216			c.fmt(f)?;
217		}
218
219		Ok(())
220	}
221}
222
223impl ToOwned for Base64Binary {
224	type Owned = Base64BinaryBuf;
225
226	fn to_owned(&self) -> Self::Owned {
227		Base64BinaryBuf::from_bytes(self.as_bytes().to_vec())
228	}
229}
230
231pub struct Chars<'a> {
232	offset: u8,
233	rest: u8,
234	padding: bool,
235	bytes: std::slice::Iter<'a, u8>,
236}
237
238impl<'a> Iterator for Chars<'a> {
239	type Item = char;
240
241	fn next(&mut self) -> Option<Self::Item> {
242		if self.padding {
243			if self.offset <= 6 {
244				self.offset += 2;
245				Some(PADDING)
246			} else {
247				None
248			}
249		} else if self.offset == 6 {
250			let sextet = self.rest;
251			self.rest = 0;
252			self.offset = 0;
253			Some(CHARS[sextet as usize])
254		} else {
255			match self.bytes.next() {
256				Some(b) => {
257					let sextet = self.rest | (b >> 2 >> self.offset & 0b111111);
258					self.offset += 2;
259					self.rest = b << (6 - self.offset) & 0b111111;
260					Some(CHARS[sextet as usize])
261				}
262				None => {
263					if self.offset > 0 {
264						let sextet = self.rest;
265						self.offset += 2;
266						self.padding = true;
267						Some(CHARS[sextet as usize])
268					} else {
269						None
270					}
271				}
272			}
273		}
274	}
275}
276
277impl XsdValue for Base64Binary {
278	fn datatype(&self) -> Datatype {
279		Datatype::Base64Binary
280	}
281}
282
283#[cfg(test)]
284mod tests {
285	use super::*;
286
287	const TESTS: [(&'static [u8], &'static str); 9] = [
288		(b"M", "TQ=="),
289		(b"Ma", "TWE="),
290		(b"Man", "TWFu"),
291		(b"light w", "bGlnaHQgdw=="),
292		(b"light wo", "bGlnaHQgd28="),
293		(b"light wor", "bGlnaHQgd29y"),
294		(b"light work", "bGlnaHQgd29yaw=="),
295		(b"light work.", "bGlnaHQgd29yay4="),
296		(
297			b"Many hands make light work.",
298			"TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcmsu",
299		),
300	];
301
302	#[test]
303	fn encoding() {
304		for (input, expected) in TESTS {
305			let output = Base64Binary::new(input).to_string();
306			assert_eq!(output, expected)
307		}
308	}
309
310	#[test]
311	fn decoding() {
312		for (expected, input) in TESTS {
313			let output = Base64BinaryBuf::decode(input).unwrap();
314			assert_eq!(output.as_bytes(), expected)
315		}
316	}
317}