1 //! ASN.1 `TeletexString` support.
2 //!
3 use crate::{asn1::AnyRef, FixedTag, Result, StrRef, Tag};
4 use core::{fmt, ops::Deref};
5 
6 macro_rules! impl_teletex_string {
7     ($type: ty) => {
8         impl_teletex_string!($type,);
9     };
10     ($type: ty, $($li: lifetime)?) => {
11         impl_string_type!($type, $($li),*);
12 
13         impl<$($li),*> FixedTag for $type {
14             const TAG: Tag = Tag::TeletexString;
15         }
16 
17         impl<$($li),*> fmt::Debug for $type {
18             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19                 write!(f, "TeletexString({:?})", self.as_str())
20             }
21         }
22     };
23 }
24 
25 /// ASN.1 `TeletexString` type.
26 ///
27 /// Supports a subset the ASCII character set (described below).
28 ///
29 /// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead.
30 /// For the full ASCII character set, use
31 /// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`].
32 ///
33 /// This is a zero-copy reference type which borrows from the input data.
34 ///
35 /// # Supported characters
36 ///
37 /// The standard defines a complex character set allowed in this type. However, quoting the ASN.1
38 /// mailing list, "a sizable volume of software in the world treats TeletexString (T61String) as a
39 /// simple 8-bit string with mostly Windows Latin 1 (superset of iso-8859-1) encoding".
40 ///
41 #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
42 pub struct TeletexStringRef<'a> {
43     /// Inner value
44     inner: StrRef<'a>,
45 }
46 
47 impl<'a> TeletexStringRef<'a> {
48     /// Create a new ASN.1 `TeletexString`.
new<T>(input: &'a T) -> Result<Self> where T: AsRef<[u8]> + ?Sized,49     pub fn new<T>(input: &'a T) -> Result<Self>
50     where
51         T: AsRef<[u8]> + ?Sized,
52     {
53         let input = input.as_ref();
54 
55         // FIXME: support higher part of the charset
56         if input.iter().any(|&c| c > 0x7F) {
57             return Err(Self::TAG.value_error());
58         }
59 
60         StrRef::from_bytes(input)
61             .map(|inner| Self { inner })
62             .map_err(|_| Self::TAG.value_error())
63     }
64 }
65 
66 impl_teletex_string!(TeletexStringRef<'a>, 'a);
67 
68 impl<'a> Deref for TeletexStringRef<'a> {
69     type Target = StrRef<'a>;
70 
deref(&self) -> &Self::Target71     fn deref(&self) -> &Self::Target {
72         &self.inner
73     }
74 }
75 
76 impl<'a> From<&TeletexStringRef<'a>> for TeletexStringRef<'a> {
from(value: &TeletexStringRef<'a>) -> TeletexStringRef<'a>77     fn from(value: &TeletexStringRef<'a>) -> TeletexStringRef<'a> {
78         *value
79     }
80 }
81 
82 impl<'a> From<TeletexStringRef<'a>> for AnyRef<'a> {
from(teletex_string: TeletexStringRef<'a>) -> AnyRef<'a>83     fn from(teletex_string: TeletexStringRef<'a>) -> AnyRef<'a> {
84         AnyRef::from_tag_and_value(Tag::TeletexString, teletex_string.inner.into())
85     }
86 }
87 
88 #[cfg(feature = "alloc")]
89 pub use self::allocation::TeletexString;
90 
91 #[cfg(feature = "alloc")]
92 mod allocation {
93     use super::TeletexStringRef;
94 
95     use crate::{
96         asn1::AnyRef,
97         referenced::{OwnedToRef, RefToOwned},
98         BytesRef, Error, FixedTag, Result, StrOwned, Tag,
99     };
100     use alloc::string::String;
101     use core::{fmt, ops::Deref};
102 
103     /// ASN.1 `TeletexString` type.
104     ///
105     /// Supports a subset the ASCII character set (described below).
106     ///
107     /// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead.
108     /// For the full ASCII character set, use
109     /// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`].
110     ///
111     /// # Supported characters
112     ///
113     /// The standard defines a complex character set allowed in this type. However, quoting the ASN.1
114     /// mailing list, "a sizable volume of software in the world treats TeletexString (T61String) as a
115     /// simple 8-bit string with mostly Windows Latin 1 (superset of iso-8859-1) encoding".
116     ///
117     #[derive(Clone, Eq, PartialEq, PartialOrd, Ord)]
118     pub struct TeletexString {
119         /// Inner value
120         inner: StrOwned,
121     }
122 
123     impl TeletexString {
124         /// Create a new ASN.1 `TeletexString`.
new<T>(input: &T) -> Result<Self> where T: AsRef<[u8]> + ?Sized,125         pub fn new<T>(input: &T) -> Result<Self>
126         where
127             T: AsRef<[u8]> + ?Sized,
128         {
129             let input = input.as_ref();
130 
131             TeletexStringRef::new(input)?;
132 
133             StrOwned::from_bytes(input)
134                 .map(|inner| Self { inner })
135                 .map_err(|_| Self::TAG.value_error())
136         }
137     }
138 
139     impl_teletex_string!(TeletexString);
140 
141     impl Deref for TeletexString {
142         type Target = StrOwned;
143 
deref(&self) -> &Self::Target144         fn deref(&self) -> &Self::Target {
145             &self.inner
146         }
147     }
148 
149     impl<'a> From<TeletexStringRef<'a>> for TeletexString {
from(value: TeletexStringRef<'a>) -> TeletexString150         fn from(value: TeletexStringRef<'a>) -> TeletexString {
151             let inner =
152                 StrOwned::from_bytes(value.inner.as_bytes()).expect("Invalid TeletexString");
153             Self { inner }
154         }
155     }
156 
157     impl<'a> From<&'a TeletexString> for AnyRef<'a> {
from(teletex_string: &'a TeletexString) -> AnyRef<'a>158         fn from(teletex_string: &'a TeletexString) -> AnyRef<'a> {
159             AnyRef::from_tag_and_value(
160                 Tag::TeletexString,
161                 BytesRef::new(teletex_string.inner.as_bytes()).expect("Invalid TeletexString"),
162             )
163         }
164     }
165 
166     impl<'a> RefToOwned<'a> for TeletexStringRef<'a> {
167         type Owned = TeletexString;
ref_to_owned(&self) -> Self::Owned168         fn ref_to_owned(&self) -> Self::Owned {
169             TeletexString {
170                 inner: self.inner.ref_to_owned(),
171             }
172         }
173     }
174 
175     impl OwnedToRef for TeletexString {
176         type Borrowed<'a> = TeletexStringRef<'a>;
owned_to_ref(&self) -> Self::Borrowed<'_>177         fn owned_to_ref(&self) -> Self::Borrowed<'_> {
178             TeletexStringRef {
179                 inner: self.inner.owned_to_ref(),
180             }
181         }
182     }
183 
184     impl TryFrom<String> for TeletexString {
185         type Error = Error;
186 
try_from(input: String) -> Result<Self>187         fn try_from(input: String) -> Result<Self> {
188             TeletexStringRef::new(&input)?;
189 
190             StrOwned::new(input)
191                 .map(|inner| Self { inner })
192                 .map_err(|_| Self::TAG.value_error())
193         }
194     }
195 }
196 
197 #[cfg(test)]
198 mod tests {
199     use super::TeletexStringRef;
200     use crate::Decode;
201     use crate::SliceWriter;
202 
203     #[test]
parse_bytes()204     fn parse_bytes() {
205         let example_bytes = &[
206             0x14, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31,
207         ];
208 
209         let teletex_string = TeletexStringRef::from_der(example_bytes).unwrap();
210         assert_eq!(teletex_string.as_str(), "Test User 1");
211         let mut out = [0_u8; 30];
212         let mut writer = SliceWriter::new(&mut out);
213         writer.encode(&teletex_string).unwrap();
214         let encoded = writer.finish().unwrap();
215         assert_eq!(encoded, example_bytes);
216     }
217 }
218