@@ -44,6 +44,10 @@ impl BmpString {
4444 #[ allow( clippy:: integer_arithmetic) ]
4545 let mut bytes = Vec :: with_capacity ( utf8. len ( ) * 2 ) ;
4646
47+ if utf8. chars ( ) . any ( |c| c. len_utf16 ( ) != 1 ) {
48+ return Err ( Tag :: BmpString . value_error ( ) ) ;
49+ }
50+
4751 for code_point in utf8. encode_utf16 ( ) {
4852 bytes. extend ( code_point. to_be_bytes ( ) ) ;
4953 }
@@ -77,6 +81,24 @@ impl BmpString {
7781 . chunks_exact ( 2 )
7882 . map ( |chunk| u16:: from_be_bytes ( chunk. try_into ( ) . expect ( "two bytes" ) ) )
7983 }
84+
85+ #[ cfg( feature = "hazmat" ) ]
86+ /// Create a new [`BmpString`] from bytes.
87+ ///
88+ /// It bypasses the check for utf16 encoding of its values.
89+ pub fn new_unchecked ( bytes : impl Into < Box < [ u8 ] > > ) -> Result < Self > {
90+ let bytes = bytes. into ( ) ;
91+
92+ if bytes. len ( ) % 2 != 0 {
93+ return Err ( Tag :: BmpString . length_error ( ) ) ;
94+ }
95+
96+ let ret = Self {
97+ bytes : bytes. try_into ( ) ?,
98+ } ;
99+
100+ Ok ( ret)
101+ }
80102}
81103
82104impl AsRef < [ u8 ] > for BmpString {
@@ -131,7 +153,7 @@ impl fmt::Display for BmpString {
131153#[ cfg( test) ]
132154mod tests {
133155 use super :: BmpString ;
134- use crate :: { Decode , Encode } ;
156+ use crate :: { Decode , Encode , Tag } ;
135157 use alloc:: string:: ToString ;
136158 use hex_literal:: hex;
137159
@@ -157,4 +179,15 @@ mod tests {
157179 let encoded = bmp_string. to_der ( ) . unwrap ( ) ;
158180 assert_eq ! ( encoded, EXAMPLE_BYTES ) ;
159181 }
182+
183+ #[ test]
184+ fn encode_errors ( ) {
185+ let err = BmpString :: from_utf8 ( "🔥" ) ;
186+ assert_eq ! ( err, Err ( Tag :: BmpString . value_error( ) ) ) ;
187+
188+ #[ cfg( feature = "hazmat" ) ]
189+ {
190+ assert ! ( BmpString :: new_unchecked( "🔥" . as_bytes( ) ) . is_ok( ) ) ;
191+ }
192+ }
160193}
0 commit comments