asn1_rs/asn1_types/strings/
bmpstring.rs1use crate::*;
5use alloc::borrow::Cow;
6#[cfg(not(feature = "std"))]
7use alloc::string::{String, ToString};
8#[cfg(not(feature = "std"))]
9use alloc::vec::Vec;
10
11#[derive(Debug, PartialEq, Eq)]
16pub struct BmpString<'a> {
17 pub(crate) data: Cow<'a, str>,
18}
19
20impl<'a> BmpString<'a> {
21 pub const fn new(s: &'a str) -> Self {
22 BmpString {
23 data: Cow::Borrowed(s),
24 }
25 }
26
27 pub fn string(&self) -> String {
28 self.data.to_string()
29 }
30}
31
32impl<'a> AsRef<str> for BmpString<'a> {
33 fn as_ref(&self) -> &str {
34 &self.data
35 }
36}
37
38impl<'a> From<&'a str> for BmpString<'a> {
39 fn from(s: &'a str) -> Self {
40 Self::new(s)
41 }
42}
43
44impl From<String> for BmpString<'_> {
45 fn from(s: String) -> Self {
46 Self {
47 data: Cow::Owned(s),
48 }
49 }
50}
51
52impl<'a, 'r> core::convert::TryFrom<&'r Any<'a>> for BmpString<'a> {
53 type Error = Error;
54
55 fn try_from(any: &'r Any<'a>) -> Result<BmpString<'a>> {
56 any.tag().assert_eq(Self::TAG)?;
57
58 let v = &any
60 .data
61 .chunks(2)
62 .map(|s| match s {
63 [a, b] => ((*a as u16) << 8) | (*b as u16),
64 [a] => *a as u16,
65 _ => unreachable!(),
66 })
67 .collect::<Vec<_>>();
68
69 let s = String::from_utf16(v)?;
70 let data = Cow::Owned(s);
71
72 Ok(BmpString { data })
73 }
74}
75
76impl<'a> core::convert::TryFrom<Any<'a>> for BmpString<'a> {
77 type Error = Error;
78
79 #[inline]
80 fn try_from(any: Any<'a>) -> Result<BmpString<'a>> {
81 BmpString::try_from(&any)
82 }
83}
84
85impl<'a> CheckDerConstraints for BmpString<'a> {
86 fn check_constraints(any: &Any) -> Result<()> {
87 any.header.assert_primitive()?;
88 Ok(())
89 }
90}
91
92impl DerAutoDerive for BmpString<'_> {}
93
94impl<'a> Tagged for BmpString<'a> {
95 const TAG: Tag = Tag::BmpString;
96}
97
98impl<'a> TestValidCharset for BmpString<'a> {
99 fn test_valid_charset(i: &[u8]) -> Result<()> {
100 if i.len() % 2 != 0 {
101 return Err(Error::StringInvalidCharset);
102 }
103 let iter = i.chunks(2).map(|s| ((s[0] as u16) << 8) | (s[1] as u16));
104 for c in char::decode_utf16(iter) {
105 if c.is_err() {
106 return Err(Error::StringInvalidCharset);
107 }
108 }
109 Ok(())
110 }
111}
112
113#[cfg(feature = "std")]
114impl ToDer for BmpString<'_> {
115 fn to_der_len(&self) -> Result<usize> {
116 let sz = self.data.encode_utf16().count() * 2;
118 if sz < 127 {
119 Ok(2 + sz)
121 } else {
122 let n = Length::Definite(sz).to_der_len()?;
124 Ok(1 + n + sz)
125 }
126 }
127
128 fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
129 let l = self.data.encode_utf16().count() * 2;
131 let header = Header::new(Class::Universal, false, Self::TAG, Length::Definite(l));
132 header.write_der_header(writer).map_err(Into::into)
133 }
134
135 fn write_der_content(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
136 let mut v = Vec::new();
137 for u in self.data.encode_utf16() {
138 v.push((u >> 8) as u8);
139 v.push((u & 0xff) as u8);
140 }
141 writer.write(&v).map_err(Into::into)
142 }
143}