1use crate::asn1::{
8 ASN1Fmt, BmpStringFmt, BoolFmt, Class, EnumeratedFmt, Ia5StringFmt, IntegerFmt, NullFmt,
9 NumericStringFmt, ObjectIdentifierFmt, PrintableStringFmt, RealFmt, TagFmt, TeletexStringFmt,
10 UniversalStringFmt, Utf8StringFmt, BER,
11};
12use crate::core::spec::SpecByteLen;
13use vstd::prelude::*;
14
15use super::modifiers::{defaulted, explicit_tag};
16pub use super::modifiers::{
17 implicitly_tagged as Implicit, ImplicitFmt, CHOICE, IMPLICIT, IMPLICIT_APPLICATION,
18 IMPLICIT_PRIVATE, OPTIONAL, REQUIRED,
19};
20use super::{GeneralizedTimeFmt, Integer16Fmt, Integer8Fmt, UtcTimeFmt};
21
22pub mod any;
23pub mod bit_string;
24pub mod char_string;
25pub mod octet_string;
26pub mod sequence;
27pub mod sequence_of;
28
29pub use any::*;
30pub use bit_string::*;
31pub use char_string::*;
32pub use octet_string::*;
33pub use sequence::*;
34pub use sequence_of::*;
35
36verus! {
37
38pub const MAX_RECURSION_DEPTH: usize = 30;
40
41pub type BoolTlvFmt = ASN1Fmt<BoolFmt<BER>, BER>;
43
44pub type AnyTlvFmt = BerAnyFmt<MAX_RECURSION_DEPTH>;
45
46pub type IntegerTlvFmt = ASN1Fmt<IntegerFmt, BER>;
47
48pub type Integer8TlvFmt = ASN1Fmt<Integer8Fmt, BER>;
49
50pub type Integer16TlvFmt = ASN1Fmt<Integer16Fmt, BER>;
51
52pub type EnumeratedTlvFmt = ASN1Fmt<EnumeratedFmt, BER>;
53
54pub type Enumerated16TlvFmt = ASN1Fmt<Integer16Fmt, BER>;
55
56pub type ObjectIdentifierTlvFmt = ASN1Fmt<ObjectIdentifierFmt, BER>;
57
58pub type RealTlvFmt = ASN1Fmt<RealFmt<BER>, BER>;
59
60pub type BitStringTlvFmt = BerBitStringFmt<MAX_RECURSION_DEPTH>;
61
62pub type OctetStringTlvFmt = BerOctetStringFmt<MAX_RECURSION_DEPTH>;
63
64pub type NullTlvFmt = ASN1Fmt<NullFmt, BER>;
65
66pub type Utf8StringTlvFmt = BerUtf8StringFmt<MAX_RECURSION_DEPTH>;
67
68pub type PrintableStringTlvFmt = BerPrintableStringFmt<MAX_RECURSION_DEPTH>;
69
70pub type NumericStringTlvFmt = BerNumericStringFmt<MAX_RECURSION_DEPTH>;
71
72pub type TeletexStringTlvFmt = BerTeletexStringFmt<MAX_RECURSION_DEPTH>;
73
74pub type Ia5StringTlvFmt = BerIa5StringFmt<MAX_RECURSION_DEPTH>;
75
76pub type UtcTimeTlvFmt = ASN1Fmt<UtcTimeFmt<BER>, BER>;
77
78pub type GeneralizedTimeTlvFmt = ASN1Fmt<GeneralizedTimeFmt<BER>, BER>;
79
80pub type BmpStringTlvFmt = BerBmpStringFmt<MAX_RECURSION_DEPTH>;
81
82pub type UniversalStringTlvFmt = BerUniversalStringFmt<MAX_RECURSION_DEPTH>;
83
84pub type SequenceFmt<C> = BerSequenceFmt<C>;
85
86pub type SequenceOfFmt<C> = BerSequenceOfFmt<C>;
87
88pub type SetOfTlvFmt<C> = BerSequenceOfFmt<C>;
89
90pub type ExplicitFmt<C> = BerSequenceFmt<C>;
91
92pub type DefaultFmt<Field, Default, Rest> = super::DefaultedFmt<Field, Default, Rest, BER>;
93
94pub const BOOLEAN: BoolTlvFmt = ASN1Fmt(TagFmt::BOOLEAN, BoolFmt::<BER>);
95
96pub const ANY: AnyTlvFmt = BerAnyFmt;
97
98pub const INTEGER: IntegerTlvFmt = ASN1Fmt(TagFmt::INTEGER, IntegerFmt);
99
100pub const INTEGER8: Integer8TlvFmt = ASN1Fmt(TagFmt::INTEGER, Integer8Fmt);
101
102pub const INTEGER16: Integer16TlvFmt = ASN1Fmt(TagFmt::INTEGER, Integer16Fmt);
103
104pub const ENUMERATED: EnumeratedTlvFmt = ASN1Fmt(TagFmt::ENUMERATED, EnumeratedFmt);
105
106pub const ENUMERATED16: Enumerated16TlvFmt = ASN1Fmt(TagFmt::ENUMERATED, Integer16Fmt);
107
108pub const OBJECT_IDENTIFIER: ObjectIdentifierTlvFmt = ASN1Fmt(
109 TagFmt::OBJECT_IDENTIFIER,
110 ObjectIdentifierFmt,
111);
112
113pub const REAL: RealTlvFmt = ASN1Fmt(TagFmt::REAL, RealFmt::<BER>);
114
115pub const BIT_STRING: BitStringTlvFmt = BerBitStringFmt(TagFmt::BIT_STRING);
116
117pub const NULL: NullTlvFmt = ASN1Fmt(TagFmt::NULL, NullFmt);
118
119pub const UTC_TIME: UtcTimeTlvFmt = ASN1Fmt(TagFmt::UTC_TIME, UtcTimeFmt::<BER>);
120
121pub const GENERALIZED_TIME: GeneralizedTimeTlvFmt = ASN1Fmt(
122 TagFmt::GENERALIZED_TIME,
123 GeneralizedTimeFmt::<BER>,
124);
125
126pub const OCTET_STRING: OctetStringTlvFmt = BerOctetStringFmt(TagFmt::OCTET_STRING);
127
128pub const UTF8_STRING: Utf8StringTlvFmt = BerCharStringFmt(TagFmt::UTF8_STRING, Utf8StringFmt);
129
130pub const PRINTABLE_STRING: PrintableStringTlvFmt = BerCharStringFmt(
131 TagFmt::PRINTABLE_STRING,
132 PrintableStringFmt,
133);
134
135pub const NUMERIC_STRING: NumericStringTlvFmt = BerCharStringFmt(
136 TagFmt::NUMERIC_STRING,
137 NumericStringFmt,
138);
139
140pub const IA5_STRING: Ia5StringTlvFmt = BerCharStringFmt(TagFmt::IA5_STRING, Ia5StringFmt);
141
142pub const TELETEX_STRING: TeletexStringTlvFmt = BerCharStringFmt(
143 TagFmt::TELETEX_STRING,
144 TeletexStringFmt,
145);
146
147pub const BMP_STRING: BmpStringTlvFmt = BerCharStringFmt(TagFmt::BMP_STRING, BmpStringFmt);
148
149pub const UNIVERSAL_STRING: UniversalStringTlvFmt = BerCharStringFmt(
150 TagFmt::UNIVERSAL_STRING,
151 UniversalStringFmt,
152);
153
154#[allow(non_snake_case)]
156#[verifier::allow_in_spec]
157pub const fn SEQUENCE<C: Copy>(content: C) -> SequenceFmt<C>
158 returns
159 BerSequenceFmt(TagFmt::SEQUENCE, content),
160{
161 BerSequenceFmt::universal(content)
162}
163
164#[allow(non_snake_case)]
166#[verifier::allow_in_spec]
167pub const fn SEQUENCE_OF<C: Copy>(content: C) -> SequenceOfFmt<C>
168 returns
169 BerSequenceOfFmt(TagFmt::SEQUENCE, content),
170{
171 BerSequenceOfFmt::universal(content)
172}
173
174#[allow(non_snake_case)]
176#[verifier::allow_in_spec]
177pub const fn SET_OF<C: Copy>(content: C) -> SetOfTlvFmt<C>
178 returns
179 BerSequenceOfFmt(TagFmt::SET, content),
180{
181 BerSequenceOfFmt(TagFmt::SET, content)
182}
183
184#[allow(non_snake_case)]
186#[verifier::allow_in_spec]
187pub const fn Explicit<C: Copy>(class: Class, number: u64, inner: C) -> ExplicitFmt<C>
188 returns
189 BerSequenceFmt(explicit_tag(class, number), inner),
190{
191 BerSequenceFmt(explicit_tag(class, number), inner)
192}
193
194#[allow(non_snake_case)]
195#[verifier::allow_in_spec]
196pub const fn EXPLICIT<C: Copy>(number: u64, inner: C) -> ExplicitFmt<C>
197 returns
198 Explicit(Class::ContextSpecific, number, inner),
199{
200 Explicit(Class::ContextSpecific, number, inner)
201}
202
203#[allow(non_snake_case)]
204#[verifier::allow_in_spec]
205pub const fn EXPLICIT_APPLICATION<C: Copy>(number: u64, inner: C) -> ExplicitFmt<C>
206 returns
207 Explicit(Class::Application, number, inner),
208{
209 Explicit(Class::Application, number, inner)
210}
211
212#[allow(non_snake_case)]
213#[verifier::allow_in_spec]
214pub const fn EXPLICIT_PRIVATE<C: Copy>(number: u64, inner: C) -> ExplicitFmt<C>
215 returns
216 Explicit(Class::Private, number, inner),
217{
218 Explicit(Class::Private, number, inner)
219}
220
221#[allow(non_snake_case)]
222#[verifier::allow_in_spec]
223pub const fn DEFAULT<Field, Rest>(field: Field, default: Field::T, cont: Rest) -> DefaultFmt<
224 Field,
225 Field::T,
226 Rest,
227> where Field: SpecByteLen
228 returns
229 defaulted::<Field, Rest, BER>(field, default, cont),
230{
231 defaulted::<Field, Rest, BER>(field, default, cont)
232}
233
234} #[cfg(all(test, feature = "alloc"))]
236mod tests {
237 use alloc::{string::String, vec::Vec};
238
239 use super::*;
240 use crate::asn1::{BmpString, Integer8Fmt};
241 use crate::combinators::Pair;
242 use crate::core::exec::{ParseErrorKind, Parser, Prepare, SerializerExt};
243
244 type Octets = BerOctetStringFmt<8>;
245
246 fn parse_universal(input: &[u8]) -> (usize, Vec<u8>) {
247 Octets::universal().parse(&input).unwrap()
248 }
249
250 fn integer_sequence() -> BerSequenceOfFmt<ASN1Fmt<Integer8Fmt, BER>> {
251 SEQUENCE_OF(ASN1Fmt(TagFmt::INTEGER, Integer8Fmt))
252 }
253
254 fn integer_fields_sequence(
255 ) -> BerSequenceFmt<Pair<ASN1Fmt<Integer8Fmt, BER>, ASN1Fmt<Integer8Fmt, BER>>> {
256 let integer = ASN1Fmt::<_, BER>(TagFmt::INTEGER, Integer8Fmt);
257 SEQUENCE(Pair(integer, integer))
258 }
259
260 #[test]
261 fn eoc_is_exactly_the_canonical_tag_and_zero_length_octet() {
262 let input = [0x00, 0x00, 0xff];
263 assert_eq!(EOC.parse(&&input[..]).unwrap(), (2, (TagFmt::EOC, 0u8)),);
264
265 for invalid in [
266 &[0x00][..],
267 &[0x00, 0x01],
268 &[0x20, 0x00],
269 &[0x40, 0x00],
270 &[0x1f, 0x00, 0x00],
271 ] {
272 assert!(EOC.parse(&invalid).is_err());
273 }
274
275 let value = (TagFmt::EOC, 0u8);
276 let mut output = [0xff; 2];
277 assert_eq!(EOC.prepare(&value).unwrap(), output.len());
278 EOC.serialize(&value, output.as_mut_slice());
279 assert_eq!(output, [0x00, 0x00]);
280 }
281
282 #[test]
283 fn ber_sequence_parses_definite_and_indefinite_schema_bodies() {
284 let format = integer_fields_sequence();
285 let definite = [0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02];
286 let indefinite = [0x30, 0x80, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00];
287
288 assert_eq!(
289 format.parse(&&definite[..]).unwrap(),
290 (definite.len(), (1i8, 2i8)),
291 );
292 assert_eq!(
293 format.parse(&&indefinite[..]).unwrap(),
294 (indefinite.len(), (1i8, 2i8)),
295 );
296
297 let missing_eoc = [0x30, 0x80, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02];
298 assert!(format.parse(&&missing_eoc[..]).is_err());
299
300 let extra_component = [
301 0x30, 0x80, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x03, 0x00, 0x00,
302 ];
303 assert!(format.parse(&&extra_component[..]).is_err());
304 }
305
306 #[test]
307 fn ber_sequence_supports_implicit_tags_and_definite_normalization() {
308 let content = integer_fields_sequence().1;
309 let format = BerSequenceFmt::implicit(Class::ContextSpecific, 0, content);
310 let indefinite = [0xa0, 0x80, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00];
311 let (_, value) = format.parse(&&indefinite[..]).unwrap();
312 assert_eq!(value, (1i8, 2i8));
313
314 let mut output = vec![0; format.prepare(&value).unwrap()];
315 format.serialize(&value, output.as_mut_slice());
316 assert_eq!(output, [0xa0, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02]);
317
318 let universal = [0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02];
319 assert!(format.parse(&&universal[..]).is_err());
320 }
321
322 #[test]
323 fn ber_sequence_of_parses_definite_and_indefinite_forms() {
324 let format = integer_sequence();
325 let definite = [0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02];
326 let indefinite = [0x30, 0x80, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00];
327
328 assert_eq!(
329 format.parse(&&definite[..]).unwrap(),
330 (definite.len(), vec![1i8, 2i8]),
331 );
332 assert_eq!(
333 format.parse(&&indefinite[..]).unwrap(),
334 (indefinite.len(), vec![1i8, 2i8]),
335 );
336
337 let empty_definite = [0x30, 0x00];
338 let empty_indefinite = [0x30, 0x80, 0x00, 0x00];
339 assert_eq!(
340 format.parse(&&empty_definite[..]).unwrap(),
341 (empty_definite.len(), Vec::<i8>::new()),
342 );
343 assert_eq!(
344 format.parse(&&empty_indefinite[..]).unwrap(),
345 (empty_indefinite.len(), Vec::<i8>::new()),
346 );
347 }
348
349 #[test]
350 fn ber_sequence_of_supports_implicit_outer_tags() {
351 let element = ASN1Fmt::<_, BER>(TagFmt::INTEGER, Integer8Fmt);
352 let format = BerSequenceOfFmt::implicit(Class::ContextSpecific, 0, element);
353 let definite = [0xa0, 0x03, 0x02, 0x01, 0x01];
354 let indefinite = [0xa0, 0x80, 0x02, 0x01, 0x01, 0x00, 0x00];
355
356 assert_eq!(
357 format.parse(&&definite[..]).unwrap(),
358 (definite.len(), vec![1i8]),
359 );
360 assert_eq!(
361 format.parse(&&indefinite[..]).unwrap(),
362 (indefinite.len(), vec![1i8]),
363 );
364
365 let universal = [0x30, 0x03, 0x02, 0x01, 0x01];
366 assert!(format.parse(&&universal[..]).is_err());
367
368 let value = vec![1i8];
369 let mut output = vec![0; format.prepare(&value).unwrap()];
370 format.serialize(&value, output.as_mut_slice());
371 assert_eq!(output, definite);
372 }
373
374 #[test]
375 fn ber_sequence_of_serialization_normalizes_to_definite_form() {
376 let format = integer_sequence();
377 let indefinite = [0x30, 0x80, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00];
378 let (_, value) = format.parse(&&indefinite[..]).unwrap();
379 let mut output = vec![0; format.prepare(&value).unwrap()];
380 format.serialize(&value, output.as_mut_slice());
381
382 assert_eq!(output, [0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02]);
383 }
384
385 #[test]
386 fn nested_ber_sequence_of_delegates_indefinite_values_to_the_element_codec() {
387 let inner = integer_sequence();
388 let outer = SEQUENCE_OF(inner);
389 let input = [
390 0x30, 0x80, 0x30, 0x80, 0x02, 0x01, 0x01, 0x00, 0x00, 0x30, 0x03, 0x02, 0x01, 0x02, 0x00, 0x00, ];
395
396 assert_eq!(
397 outer.parse(&&input[..]).unwrap(),
398 (input.len(), vec![vec![1i8], vec![2i8]]),
399 );
400 }
401
402 #[test]
403 fn ber_sequence_of_rejects_missing_eoc_and_non_elements() {
404 let format = integer_sequence();
405 let missing_eoc = [0x30, 0x80, 0x02, 0x01, 0x01];
406 assert!(format.parse(&&missing_eoc[..]).is_err());
407
408 let boolean_element = [0x30, 0x80, 0x01, 0x01, 0xff, 0x00, 0x00];
409 assert!(format.parse(&&boolean_element[..]).is_err());
410 }
411
412 #[test]
413 fn parses_primitive_and_definite_constructed_octet_strings() {
414 let primitive = [0x04, 0x03, b'a', b'b', b'c'];
415 assert_eq!(
416 parse_universal(&primitive),
417 (primitive.len(), b"abc".to_vec())
418 );
419
420 let constructed = [0x24, 0x07, 0x04, 0x02, b'a', b'b', 0x04, 0x01, b'c'];
421 assert_eq!(
422 parse_universal(&constructed),
423 (constructed.len(), b"abc".to_vec()),
424 );
425 }
426
427 #[test]
428 fn parses_indefinite_and_nested_constructed_octet_strings() {
429 let indefinite = [
430 0x24, 0x80, 0x04, 0x02, b'a', b'b', 0x04, 0x01, b'c', 0x00, 0x00,
431 ];
432 assert_eq!(
433 parse_universal(&indefinite),
434 (indefinite.len(), b"abc".to_vec()),
435 );
436
437 let nested = [
438 0x24, 0x80, 0x24, 0x80, 0x04, 0x01, b'a', 0x00, 0x00, 0x04, 0x01, b'b', 0x00, 0x00,
439 ];
440 assert_eq!(parse_universal(&nested), (nested.len(), b"ab".to_vec()));
441 }
442
443 #[test]
444 fn implicit_tagging_replaces_only_the_outer_tag() {
445 let format = Octets::implicit(Class::ContextSpecific, 0);
446
447 let primitive = [0x80, 0x03, b'a', b'b', b'c'];
448 assert_eq!(
449 format.parse(&&primitive[..]).unwrap(),
450 (primitive.len(), b"abc".to_vec()),
451 );
452
453 let constructed = [
454 0xa0, 0x80, 0x04, 0x02, b'a', b'b', 0x04, 0x01, b'c', 0x00, 0x00,
455 ];
456 assert_eq!(
457 format.parse(&&constructed[..]).unwrap(),
458 (constructed.len(), b"abc".to_vec()),
459 );
460
461 let retagged_child = [0xa0, 0x80, 0x80, 0x01, b'a', 0x00, 0x00];
463 assert_eq!(
464 format.parse(&&retagged_child[..]).unwrap_err().kind,
465 ParseErrorKind::InvalidTag,
466 );
467 }
468
469 #[test]
470 fn rejects_malformed_framing_and_enforces_the_recursion_limit() {
471 let missing_eoc = [0x24, 0x80, 0x04, 0x01, b'a'];
472 assert!(Octets::universal().parse(&&missing_eoc[..]).is_err());
473
474 let short_definite_body = [0x24, 0x04, 0x04, 0x01, b'a'];
475 assert!(Octets::universal()
476 .parse(&&short_definite_body[..])
477 .is_err());
478
479 let nested_2 = [
480 0x24, 0x80, 0x24, 0x80, 0x04, 0x01, b'a', 0x00, 0x00, 0x04, 0x01, b'b', 0x00, 0x00,
481 ];
482 assert!(BerOctetStringFmt::<1>::universal()
483 .parse(&&nested_2[..])
484 .is_err());
485 }
486
487 #[test]
488 fn serialization_normalizes_to_primitive_definite_form() {
489 let constructed = [
490 0x24, 0x80, 0x04, 0x02, b'a', b'b', 0x04, 0x01, b'c', 0x00, 0x00,
491 ];
492 let (_, value) = parse_universal(&constructed);
493 let format = Octets::universal();
494 let mut output = vec![0; format.prepare(value.as_slice()).unwrap()];
495 format.serialize(value.as_slice(), output.as_mut_slice());
496 assert_eq!(output, [0x04, 0x03, b'a', b'b', b'c']);
497
498 let implicit = Octets::implicit(Class::ContextSpecific, 0);
499 let mut output = vec![0; implicit.prepare(value.as_slice()).unwrap()];
500 implicit.serialize(value.as_slice(), output.as_mut_slice());
501 assert_eq!(output, [0x80, 0x03, b'a', b'b', b'c']);
502 }
503
504 #[test]
505 fn ber_utf8_string_validates_after_flattening_segments() {
506 type Format = BerUtf8StringFmt<8>;
507
508 let split_scalar = [
511 0x2c, 0x80, 0x04, 0x01, 0xe2, 0x04, 0x02, 0x82, 0xac, 0x00, 0x00,
512 ];
513 let (n, value) = Format::universal().parse(&&split_scalar[..]).unwrap();
514 assert_eq!(n, split_scalar.len());
515 assert_eq!(value.as_str(), "€");
516
517 let primitive = [0x0c, 0x03, 0xe2, 0x82, 0xac];
518 assert_eq!(
519 Format::universal()
520 .parse(&&primitive[..])
521 .unwrap()
522 .1
523 .as_str(),
524 "€"
525 );
526
527 let nested = [
528 0x2c, 0x80, 0x24, 0x80, 0x04, 0x01, 0xe2, 0x04, 0x02, 0x82, 0xac, 0x00, 0x00, 0x00, 0x00, ];
533 assert_eq!(
534 Format::universal().parse(&&nested[..]).unwrap().1.as_str(),
535 "€"
536 );
537
538 let format = Format::universal();
539 let mut output = vec![0; format.prepare(&value).unwrap()];
540 format.serialize(&value, output.as_mut_slice());
541 assert_eq!(output, [0x0c, 0x03, 0xe2, 0x82, 0xac]);
542 }
543
544 #[test]
545 fn ber_restricted_strings_support_implicit_outer_tags() {
546 type Format = BerUtf8StringFmt<8>;
547 let format = Format::implicit(Class::ContextSpecific, 0);
548 let input = [
549 0xa0, 0x80, 0x04, 0x01, 0xe2, 0x04, 0x02, 0x82, 0xac, 0x00, 0x00,
550 ];
551 let (_, value) = format.parse(&&input[..]).unwrap();
552 assert_eq!(value.as_str(), "€");
553
554 let mut output = vec![0; format.prepare(&value).unwrap()];
555 format.serialize(&value, output.as_mut_slice());
556 assert_eq!(output, [0x80, 0x03, 0xe2, 0x82, 0xac]);
557 }
558
559 #[test]
560 fn ber_printable_and_ia5_validate_flattened_contents() {
561 let printable = [
562 0x33, 0x80, 0x04, 0x02, b'A', b'B', 0x04, 0x02, b'1', b'?', 0x00, 0x00,
563 ];
564 let (_, value) = BerPrintableStringFmt::<8>::universal()
565 .parse(&&printable[..])
566 .unwrap();
567 assert_eq!(value.inner(), "AB1?");
568
569 let invalid_ia5 = [0x36, 0x80, 0x04, 0x01, 0x80, 0x00, 0x00];
570 assert!(BerIa5StringFmt::<8>::universal()
571 .parse(&&invalid_ia5[..])
572 .is_err());
573 }
574
575 #[test]
576 fn ber_bmp_string_allows_code_units_to_cross_segments() {
577 type Format = BerBmpStringFmt<8>;
578
579 let split_code_unit = [0x3e, 0x80, 0x04, 0x01, 0x00, 0x04, 0x01, 0x41, 0x00, 0x00];
581 let (_, value) = Format::universal().parse(&&split_code_unit[..]).unwrap();
582 assert_eq!(value.inner(), "A");
583
584 let malformed = [0x1e, 0x01, 0x00];
585 assert!(Format::universal().parse(&&malformed[..]).is_err());
586 let surrogate = [0x1e, 0x02, 0xd8, 0x00];
587 assert!(Format::universal().parse(&&surrogate[..]).is_err());
588
589 let value = BmpString::new(String::from("A"));
590 let format = Format::universal();
591 let mut output = vec![0; format.prepare(&value).unwrap()];
592 format.serialize(&value, output.as_mut_slice());
593 assert_eq!(output, [0x1e, 0x02, 0x00, 0x41]);
594 }
595}