asn1_rs/asn1_types/
strings.rs

1mod bmpstring;
2mod generalstring;
3mod graphicstring;
4mod ia5string;
5mod numericstring;
6mod printablestring;
7mod str;
8mod string;
9mod teletexstring;
10mod universalstring;
11mod utf8string;
12mod videotexstring;
13mod visiblestring;
14
15pub use bmpstring::*;
16pub use generalstring::*;
17pub use graphicstring::*;
18pub use ia5string::*;
19pub use numericstring::*;
20pub use printablestring::*;
21
22pub use teletexstring::*;
23pub use universalstring::*;
24pub use utf8string::*;
25pub use videotexstring::*;
26pub use visiblestring::*;
27
28/// Base trait for BER string objects and character set validation
29///
30/// This trait is implemented by several types, and is used to determine if some bytes
31/// would be valid for the given type.
32///
33/// # Example
34///
35/// ```rust
36/// use asn1_rs::{PrintableString, TestValidCharset, VisibleString};
37///
38/// let bytes: &[u8] = b"abcd*4";
39/// let res = PrintableString::test_valid_charset(bytes);
40/// assert!(res.is_err());
41/// let res = VisibleString::test_valid_charset(bytes);
42/// assert!(res.is_ok());
43/// ```
44pub trait TestValidCharset {
45    /// Check character set for this object type.
46    fn test_valid_charset(i: &[u8]) -> crate::Result<()>;
47}
48
49#[doc(hidden)]
50#[macro_export]
51macro_rules! asn1_string {
52    (IMPL $name:ident, $sname:expr) => {
53        #[doc="ASN.1 restricted character string type (`"]
54        #[doc = $sname]
55        #[doc = "`)"]
56        #[derive(Debug, PartialEq, Eq)]
57        pub struct $name<'a> {
58            pub(crate) data: alloc::borrow::Cow<'a, str>,
59        }
60
61        impl<'a> $name<'a> {
62            pub const fn new(s: &'a str) -> Self {
63                $name {
64                    data: alloc::borrow::Cow::Borrowed(s),
65                }
66            }
67
68            pub fn string(&self) -> String {
69                use alloc::string::ToString;
70                self.data.to_string()
71            }
72        }
73
74        impl<'a> AsRef<str> for $name<'a> {
75            fn as_ref(&self) -> &str {
76                &self.data
77            }
78        }
79
80        impl<'a> From<&'a str> for $name<'a> {
81            fn from(s: &'a str) -> Self {
82                Self::new(s)
83            }
84        }
85
86        impl From<String> for $name<'_> {
87            fn from(s: String) -> Self {
88                Self {
89                    data: alloc::borrow::Cow::Owned(s),
90                }
91            }
92        }
93
94        impl<'a> core::convert::TryFrom<$crate::Any<'a>> for $name<'a> {
95            type Error = $crate::Error;
96
97            fn try_from(any: $crate::Any<'a>) -> $crate::Result<$name<'a>> {
98                use core::convert::TryFrom;
99                TryFrom::try_from(&any)
100            }
101        }
102
103        impl<'a, 'b> core::convert::TryFrom<&'b $crate::Any<'a>> for $name<'a> {
104            type Error = $crate::Error;
105
106            fn try_from(any: &'b $crate::Any<'a>) -> $crate::Result<$name<'a>> {
107                use $crate::traits::Tagged;
108                use alloc::borrow::Cow;
109                any.tag().assert_eq(Self::TAG)?;
110                <$name>::test_valid_charset(any.data)?;
111
112                let s = alloc::str::from_utf8(any.data)?;
113                let data = Cow::Borrowed(s);
114                Ok($name { data })
115            }
116        }
117
118        impl<'a> $crate::CheckDerConstraints for $name<'a> {
119            fn check_constraints(any: &$crate::Any) -> $crate::Result<()> {
120                any.header.assert_primitive()?;
121                Ok(())
122            }
123        }
124
125        impl $crate::DerAutoDerive for $name<'_> {}
126
127        impl<'a> $crate::Tagged for $name<'a> {
128            const TAG: $crate::Tag = $crate::Tag::$name;
129        }
130
131        #[cfg(feature = "std")]
132        impl $crate::ToDer for $name<'_> {
133            fn to_der_len(&self) -> Result<usize> {
134                let sz = self.data.as_bytes().len();
135                if sz < 127 {
136                    // 1 (class+tag) + 1 (length) + len
137                    Ok(2 + sz)
138                } else {
139                    // 1 (class+tag) + n (length) + len
140                    let n = $crate::Length::Definite(sz).to_der_len()?;
141                    Ok(1 + n + sz)
142                }
143            }
144
145            fn write_der_header(
146                &self,
147                writer: &mut dyn std::io::Write,
148            ) -> $crate::SerializeResult<usize> {
149                use $crate::Tagged;
150                let header = $crate::Header::new(
151                    $crate::Class::Universal,
152                    false,
153                    Self::TAG,
154                    $crate::Length::Definite(self.data.len()),
155                );
156                header.write_der_header(writer).map_err(Into::into)
157            }
158
159            fn write_der_content(
160                &self,
161                writer: &mut dyn std::io::Write,
162            ) -> $crate::SerializeResult<usize> {
163                writer.write(self.data.as_bytes()).map_err(Into::into)
164            }
165        }
166    };
167    ($name:ident) => {
168        asn1_string!(IMPL $name, stringify!($name));
169    };
170}