1use chrono::NaiveDateTime;
6use fuchsia_bluetooth::types::Uuid;
7use log::trace;
8use packet_encoding::{decodable_enum, Decodable, Encodable};
9
10pub use self::header_set::HeaderSet;
11use self::obex_string::ObexString;
12use crate::error::PacketError;
13
14pub mod header_set;
16mod obex_string;
18
19#[derive(Copy, Clone, Debug, PartialEq)]
22pub struct ConnectionIdentifier(pub(crate) u32);
23
24impl ConnectionIdentifier {
25 pub fn id(&self) -> u32 {
26 self.0
27 }
28}
29
30impl TryFrom<u32> for ConnectionIdentifier {
31 type Error = PacketError;
32
33 fn try_from(src: u32) -> Result<Self, Self::Error> {
34 if src == u32::MAX {
36 return Err(PacketError::Reserved);
37 }
38 Ok(Self(src))
39 }
40}
41
42#[derive(Copy, Clone, Debug, PartialEq)]
45#[repr(u8)]
46pub enum ActionIdentifier {
47 Copy = 0x00,
48 MoveOrRename = 0x01,
49 SetPermissions = 0x02,
50 Vendor(u8),
53}
54
55impl ActionIdentifier {
56 fn is_vendor(id_raw: u8) -> bool {
57 id_raw >= 0x80
58 }
59}
60
61impl From<&ActionIdentifier> for u8 {
62 fn from(src: &ActionIdentifier) -> u8 {
63 match src {
64 ActionIdentifier::Copy => 0x00,
65 ActionIdentifier::MoveOrRename => 0x01,
66 ActionIdentifier::SetPermissions => 0x02,
67 ActionIdentifier::Vendor(v) => *v,
68 }
69 }
70}
71
72impl TryFrom<u8> for ActionIdentifier {
73 type Error = PacketError;
74
75 fn try_from(src: u8) -> Result<ActionIdentifier, Self::Error> {
76 match src {
77 0x00 => Ok(ActionIdentifier::Copy),
78 0x01 => Ok(ActionIdentifier::MoveOrRename),
79 0x02 => Ok(ActionIdentifier::SetPermissions),
80 v if ActionIdentifier::is_vendor(v) => Ok(ActionIdentifier::Vendor(v)),
81 _v => Err(Self::Error::Reserved),
82 }
83 }
84}
85
86#[derive(Clone, Debug, PartialEq)]
90pub struct MimeType(String);
91
92impl MimeType {
93 pub fn len(&self) -> usize {
94 self.0.len() + 1
96 }
97
98 pub fn to_be_bytes(&self) -> Vec<u8> {
99 let mut encoded_buf: Vec<u8> = self.0.clone().into_bytes();
101 encoded_buf.push(0); encoded_buf
103 }
104}
105
106impl TryFrom<&[u8]> for MimeType {
107 type Error = PacketError;
108
109 fn try_from(src: &[u8]) -> Result<Self, Self::Error> {
110 if src.len() == 0 {
111 return Err(PacketError::data("empty Type header"));
112 }
113
114 let mut text = String::from_utf8(src.to_vec()).map_err(PacketError::external)?;
115 if !text.ends_with('\0') {
117 return Err(PacketError::data("Type missing null terminator"));
118 }
119
120 let _ = text.pop();
121 Ok(Self(text))
122 }
123}
124
125impl From<String> for MimeType {
126 fn from(src: String) -> MimeType {
127 MimeType(src)
128 }
129}
130
131impl From<&str> for MimeType {
132 fn from(src: &str) -> MimeType {
133 MimeType(src.to_string())
134 }
135}
136
137#[derive(Clone, Debug, PartialEq)]
141pub struct UserDefinedHeader {
142 identifier: u8,
145 value: Vec<u8>,
147}
148
149pub type TypeValue = (u8, Vec<u8>);
152
153#[derive(Clone, Debug, PartialEq)]
157pub struct TagLengthValue(Vec<TypeValue>);
158
159impl TagLengthValue {
160 const MIN_TRIPLET_LENGTH_BYTES: usize = 2;
162
163 pub fn iter(&self) -> std::slice::Iter<'_, (u8, Vec<u8>)> {
164 self.0.iter()
165 }
166}
167
168impl From<Vec<TypeValue>> for TagLengthValue {
169 fn from(value: Vec<TypeValue>) -> Self {
170 Self(value)
171 }
172}
173
174impl Encodable for TagLengthValue {
175 type Error = PacketError;
176
177 fn encoded_len(&self) -> core::primitive::usize {
178 self.0
179 .iter()
180 .fold(0, |init, triplet| init + Self::MIN_TRIPLET_LENGTH_BYTES + triplet.1.len())
181 }
182
183 fn encode(&self, buf: &mut [u8]) -> core::result::Result<(), Self::Error> {
184 if buf.len() < self.encoded_len() {
185 return Err(PacketError::BufferTooSmall);
186 }
187 let mut start_index = 0;
188 for (tag, value) in &self.0 {
189 buf[start_index] = *tag;
190 buf[start_index + 1] = value.len() as u8;
191 buf[start_index + 2..start_index + 2 + value.len()].copy_from_slice(value.as_slice());
192 start_index += 2 + value.len();
193 }
194 Ok(())
195 }
196}
197
198impl TryFrom<&[u8]> for TagLengthValue {
199 type Error = PacketError;
200
201 fn try_from(raw_data: &[u8]) -> Result<Self, Self::Error> {
203 let data_len = raw_data.len();
204
205 let mut decoded_len = 0;
206 let mut list = vec![];
207
208 while decoded_len < data_len {
209 if data_len < (decoded_len + Self::MIN_TRIPLET_LENGTH_BYTES) {
210 return Err(PacketError::DataLength);
211 }
212 let tag: u8 = raw_data[decoded_len];
213 let value_len = raw_data[decoded_len + 1] as usize;
214 if data_len < (decoded_len + Self::MIN_TRIPLET_LENGTH_BYTES + value_len) {
215 return Err(PacketError::DataLength);
216 }
217 let value_start_idx = decoded_len + Self::MIN_TRIPLET_LENGTH_BYTES;
218 let value = (&raw_data[value_start_idx..value_start_idx + value_len]).into();
219 let _ = list.push((tag, value));
220 decoded_len += Self::MIN_TRIPLET_LENGTH_BYTES + value_len;
221 }
222 Ok(TagLengthValue(list))
223 }
224}
225
226decodable_enum! {
227 pub enum SingleResponseMode<u8, PacketError, Reserved> {
231 Disable = 0x00,
233 Enable = 0x01,
235 }
238}
239
240impl From<bool> for SingleResponseMode {
241 fn from(src: bool) -> SingleResponseMode {
242 if src {
243 SingleResponseMode::Enable
244 } else {
245 SingleResponseMode::Disable
246 }
247 }
248}
249
250impl From<SingleResponseMode> for Header {
251 fn from(src: SingleResponseMode) -> Header {
252 Header::SingleResponseMode(src)
253 }
254}
255
256decodable_enum! {
257 enum HeaderEncoding<u8, PacketError, HeaderEncoding> {
261 Text = 0x00,
264 Bytes = 0x40,
267 OneByte = 0x80,
269 FourBytes = 0xC0,
271 }
272}
273
274#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
281#[repr(u8)]
282pub enum HeaderIdentifier {
283 Count = 0xC0,
285 Name = 0x01,
287 Type = 0x42,
289 Length = 0xC3,
291 TimeIso8601 = 0x44,
293 Time4Byte = 0xC4,
295 Description = 0x05,
297 Target = 0x46,
299 Http = 0x47,
301 Body = 0x48,
303 EndOfBody = 0x49,
305 Who = 0x4A,
307 ConnectionId = 0xCB,
309 ApplicationParameters = 0x4C,
311 AuthenticationChallenge = 0x4D,
313 AuthenticationResponse = 0x4E,
315 CreatorId = 0xCF,
317 WanUuid = 0x50,
319 ObjectClass = 0x51,
321 SessionParameters = 0x52,
323 SessionSequenceNumber = 0x93,
325 ActionId = 0x94,
327 DestName = 0x15,
329 Permissions = 0xD6,
331 SingleResponseMode = 0x97,
333 SingleResponseModeParameters = 0x98,
335 User(u8),
337 }
339
340impl HeaderIdentifier {
341 fn is_user(id: u8) -> bool {
342 let lower_6_bits = id & 0x3f;
345 lower_6_bits >= 0x30 && lower_6_bits <= 0x3f
346 }
347
348 fn is_reserved(id: u8) -> bool {
349 let lower_6_bits = id & 0x3f;
352 lower_6_bits >= 0x19 && lower_6_bits <= 0x2f
353 }
354
355 fn encoding(&self) -> HeaderEncoding {
356 let id_raw: u8 = self.into();
357 HeaderEncoding::try_from(id_raw & 0xc0).expect("valid Header encoding")
359 }
360}
361
362impl TryFrom<u8> for HeaderIdentifier {
363 type Error = PacketError;
364
365 fn try_from(src: u8) -> Result<Self, Self::Error> {
366 match src {
367 0xC0 => Ok(Self::Count),
368 0x01 => Ok(Self::Name),
369 0x42 => Ok(Self::Type),
370 0xC3 => Ok(Self::Length),
371 0x44 => Ok(Self::TimeIso8601),
372 0xC4 => Ok(Self::Time4Byte),
373 0x05 => Ok(Self::Description),
374 0x46 => Ok(Self::Target),
375 0x47 => Ok(Self::Http),
376 0x48 => Ok(Self::Body),
377 0x49 => Ok(Self::EndOfBody),
378 0x4A => Ok(Self::Who),
379 0xCB => Ok(Self::ConnectionId),
380 0x4C => Ok(Self::ApplicationParameters),
381 0x4D => Ok(Self::AuthenticationChallenge),
382 0x4E => Ok(Self::AuthenticationResponse),
383 0xCF => Ok(Self::CreatorId),
384 0x50 => Ok(Self::WanUuid),
385 0x51 => Ok(Self::ObjectClass),
386 0x52 => Ok(Self::SessionParameters),
387 0x93 => Ok(Self::SessionSequenceNumber),
388 0x94 => Ok(Self::ActionId),
389 0x15 => Ok(Self::DestName),
390 0xD6 => Ok(Self::Permissions),
391 0x97 => Ok(Self::SingleResponseMode),
392 0x98 => Ok(Self::SingleResponseModeParameters),
393 id if HeaderIdentifier::is_user(id) => Ok(Self::User(id)),
394 id if HeaderIdentifier::is_reserved(id) => Err(Self::Error::Reserved),
395 id => Err(Self::Error::Identifier(id)),
396 }
397 }
398}
399
400impl Into<u8> for &HeaderIdentifier {
401 fn into(self) -> u8 {
402 match &self {
403 HeaderIdentifier::Count => 0xC0,
404 HeaderIdentifier::Name => 0x01,
405 HeaderIdentifier::Type => 0x42,
406 HeaderIdentifier::Length => 0xC3,
407 HeaderIdentifier::TimeIso8601 => 0x44,
408 HeaderIdentifier::Time4Byte => 0xC4,
409 HeaderIdentifier::Description => 0x05,
410 HeaderIdentifier::Target => 0x46,
411 HeaderIdentifier::Http => 0x47,
412 HeaderIdentifier::Body => 0x48,
413 HeaderIdentifier::EndOfBody => 0x49,
414 HeaderIdentifier::Who => 0x4A,
415 HeaderIdentifier::ConnectionId => 0xCB,
416 HeaderIdentifier::ApplicationParameters => 0x4C,
417 HeaderIdentifier::AuthenticationChallenge => 0x4D,
418 HeaderIdentifier::AuthenticationResponse => 0x4E,
419 HeaderIdentifier::CreatorId => 0xCF,
420 HeaderIdentifier::WanUuid => 0x50,
421 HeaderIdentifier::ObjectClass => 0x51,
422 HeaderIdentifier::SessionParameters => 0x52,
423 HeaderIdentifier::SessionSequenceNumber => 0x93,
424 HeaderIdentifier::ActionId => 0x94,
425 HeaderIdentifier::DestName => 0x15,
426 HeaderIdentifier::Permissions => 0xD6,
427 HeaderIdentifier::SingleResponseMode => 0x97,
428 HeaderIdentifier::SingleResponseModeParameters => 0x98,
429 HeaderIdentifier::User(id) => *id,
430 }
431 }
432}
433
434#[derive(Clone, Debug, PartialEq)]
437pub enum Header {
438 Count(u32),
439 Name(Option<ObexString>),
443 Type(MimeType),
444 Length(u32),
446 TimeIso8601(NaiveDateTime),
449 Time4Byte(NaiveDateTime),
452 Description(ObexString),
453 Target(Vec<u8>),
454 Http(Vec<u8>),
455 Body(Vec<u8>),
456 EndOfBody(Vec<u8>),
457 Who(Vec<u8>),
458 ConnectionId(ConnectionIdentifier),
459 ApplicationParameters(TagLengthValue),
460 AuthenticationChallenge(Vec<u8>),
461 AuthenticationResponse(Vec<u8>),
462 CreatorId(u32),
463 WanUuid(Uuid),
464 ObjectClass(Vec<u8>),
465 SessionParameters(Vec<u8>),
466 SessionSequenceNumber(u8),
467 ActionId(ActionIdentifier),
468 DestName(ObexString),
469 Permissions(u32),
471 SingleResponseMode(SingleResponseMode),
472 SingleResponseModeParameters(u8),
474 User(UserDefinedHeader),
476}
477
478impl Header {
479 const MIN_HEADER_LENGTH_BYTES: usize = 1;
481
482 const MIN_UNICODE_OR_BYTE_SEQ_LENGTH_BYTES: usize = 3;
485
486 const ISO_8601_TIME_FORMAT: &'static str = "%Y%m%dT%H%M%S";
491
492 const ISO_8601_LENGTH_BYTES: usize = 34;
498
499 pub fn identifier(&self) -> HeaderIdentifier {
500 match &self {
501 Self::Count(_) => HeaderIdentifier::Count,
502 Self::Name(_) => HeaderIdentifier::Name,
503 Self::Type(_) => HeaderIdentifier::Type,
504 Self::Length(_) => HeaderIdentifier::Length,
505 Self::TimeIso8601(_) => HeaderIdentifier::TimeIso8601,
506 Self::Time4Byte(_) => HeaderIdentifier::Time4Byte,
507 Self::Description(_) => HeaderIdentifier::Description,
508 Self::Target(_) => HeaderIdentifier::Target,
509 Self::Http(_) => HeaderIdentifier::Http,
510 Self::Body(_) => HeaderIdentifier::Body,
511 Self::EndOfBody(_) => HeaderIdentifier::EndOfBody,
512 Self::Who(_) => HeaderIdentifier::Who,
513 Self::ConnectionId(_) => HeaderIdentifier::ConnectionId,
514 Self::ApplicationParameters(_) => HeaderIdentifier::ApplicationParameters,
515 Self::AuthenticationChallenge(_) => HeaderIdentifier::AuthenticationChallenge,
516 Self::AuthenticationResponse(_) => HeaderIdentifier::AuthenticationResponse,
517 Self::CreatorId(_) => HeaderIdentifier::CreatorId,
518 Self::WanUuid(_) => HeaderIdentifier::WanUuid,
519 Self::ObjectClass(_) => HeaderIdentifier::ObjectClass,
520 Self::SessionParameters(_) => HeaderIdentifier::SessionParameters,
521 Self::SessionSequenceNumber(_) => HeaderIdentifier::SessionSequenceNumber,
522 Self::ActionId(_) => HeaderIdentifier::ActionId,
523 Self::DestName(_) => HeaderIdentifier::DestName,
524 Self::Permissions(_) => HeaderIdentifier::Permissions,
525 Self::SingleResponseMode(_) => HeaderIdentifier::SingleResponseMode,
526 Self::SingleResponseModeParameters(_) => HeaderIdentifier::SingleResponseModeParameters,
527 Self::User(UserDefinedHeader { identifier, .. }) => HeaderIdentifier::User(*identifier),
528 }
529 }
530
531 fn data_length(&self) -> usize {
533 use Header::*;
534 match &self {
535 SessionSequenceNumber(_)
536 | ActionId(_)
537 | SingleResponseMode(_)
538 | SingleResponseModeParameters(_) => 1,
539 Count(_) | Length(_) | ConnectionId(_) | CreatorId(_) | Permissions(_)
540 | Time4Byte(_) => 4,
541 Name(option_str) => option_str.as_ref().map_or(0, |s| s.len()),
542 Description(s) | DestName(s) => s.len(),
543 Target(b)
544 | Http(b)
545 | Body(b)
546 | EndOfBody(b)
547 | Who(b)
548 | AuthenticationChallenge(b)
549 | AuthenticationResponse(b)
550 | ObjectClass(b)
551 | SessionParameters(b) => b.len(),
552 ApplicationParameters(params) => params.0.iter().fold(0, |acc, param| {
553 acc + TagLengthValue::MIN_TRIPLET_LENGTH_BYTES + param.1.len()
554 }),
555 Type(mime_type) => mime_type.len(),
556 TimeIso8601(_) => Self::ISO_8601_LENGTH_BYTES,
557 WanUuid(_) => Uuid::BLUETOOTH_UUID_LENGTH_BYTES,
558 User(UserDefinedHeader { value, .. }) => value.len(),
559 }
560 }
561
562 pub fn name(s: &str) -> Self {
563 Self::Name(Some(s.into()))
564 }
565
566 pub fn empty_name() -> Self {
567 Self::Name(None)
568 }
569}
570
571impl Encodable for Header {
572 type Error = PacketError;
573
574 fn encoded_len(&self) -> usize {
575 let payload_length_encoded_bytes = match self.identifier().encoding() {
577 HeaderEncoding::Text | HeaderEncoding::Bytes => 2,
578 _ => 0,
579 };
580 Self::MIN_HEADER_LENGTH_BYTES + payload_length_encoded_bytes + self.data_length()
581 }
582
583 fn encode(&self, buf: &mut [u8]) -> Result<(), Self::Error> {
584 if buf.len() < self.encoded_len() {
585 return Err(PacketError::BufferTooSmall);
586 }
587
588 buf[0] = (&self.identifier()).into();
590
591 let start_index = match self.identifier().encoding() {
593 HeaderEncoding::Text | HeaderEncoding::Bytes => {
594 let data_length_bytes = (self.encoded_len() as u16).to_be_bytes();
595 buf[Self::MIN_HEADER_LENGTH_BYTES..Self::MIN_UNICODE_OR_BYTE_SEQ_LENGTH_BYTES]
596 .copy_from_slice(&data_length_bytes);
597 Self::MIN_UNICODE_OR_BYTE_SEQ_LENGTH_BYTES
598 }
599 _ => Self::MIN_HEADER_LENGTH_BYTES,
600 };
601
602 use Header::*;
604 match &self {
605 Count(v)
606 | Length(v)
607 | ConnectionId(ConnectionIdentifier(v))
608 | CreatorId(v)
609 | Permissions(v) => {
610 buf[start_index..start_index + 4].copy_from_slice(&v.to_be_bytes());
612 }
613 Name(None) => {} Name(Some(str)) | Description(str) | DestName(str) => {
615 let s = str.to_be_bytes();
617 buf[start_index..start_index + s.len()].copy_from_slice(&s);
618 }
619 Target(src)
620 | Http(src)
621 | Body(src)
622 | EndOfBody(src)
623 | Who(src)
624 | AuthenticationChallenge(src)
625 | AuthenticationResponse(src)
626 | ObjectClass(src)
627 | SessionParameters(src) => {
628 let n = src.len();
630 buf[start_index..start_index + n].copy_from_slice(&src[..]);
631 }
632 ApplicationParameters(params) => {
633 params.encode(&mut buf[start_index..])?;
634 }
635 SessionSequenceNumber(v) | SingleResponseModeParameters(v) => {
636 buf[start_index] = *v;
638 }
639 SingleResponseMode(v) => {
640 buf[start_index] = v.into();
641 }
642 Type(mime_type) => {
643 let b = mime_type.to_be_bytes();
644 buf[start_index..start_index + b.len()].copy_from_slice(&b[..]);
645 }
646 ActionId(v) => {
647 buf[start_index] = v.into();
648 }
649 TimeIso8601(time) => {
650 let mut formatted = time.format(Self::ISO_8601_TIME_FORMAT).to_string();
651 formatted.push('Z');
654 let s = ObexString::from(formatted).to_be_bytes();
655 buf[start_index..start_index + s.len()].copy_from_slice(&s);
656 }
657 Time4Byte(time) => {
658 let timestamp_bytes = (time.timestamp() as u32).to_be_bytes();
659 buf[start_index..start_index + 4].copy_from_slice(×tamp_bytes[..])
660 }
661 WanUuid(uuid) => buf[start_index..start_index + Uuid::BLUETOOTH_UUID_LENGTH_BYTES]
662 .copy_from_slice(&uuid.as_be_bytes()[..]),
663 User(UserDefinedHeader { value, .. }) => {
664 let n = value.len();
665 buf[start_index..start_index + n].copy_from_slice(&value[..]);
666 }
667 }
668 Ok(())
669 }
670}
671
672impl Decodable for Header {
673 type Error = PacketError;
674
675 fn decode(buf: &[u8]) -> Result<Self, Self::Error> {
676 if buf.len() < Self::MIN_HEADER_LENGTH_BYTES {
678 return Err(PacketError::BufferTooSmall);
679 }
680
681 let id = HeaderIdentifier::try_from(buf[0])?;
682 let mut start_idx = 1;
683 let data_length = match id.encoding() {
684 HeaderEncoding::Text | HeaderEncoding::Bytes => {
685 if buf.len() < Self::MIN_UNICODE_OR_BYTE_SEQ_LENGTH_BYTES {
686 return Err(PacketError::BufferTooSmall);
687 }
688 let total_length = u16::from_be_bytes(
691 buf[Self::MIN_HEADER_LENGTH_BYTES..Self::MIN_UNICODE_OR_BYTE_SEQ_LENGTH_BYTES]
692 .try_into()
693 .expect("checked length"),
694 ) as usize;
695 let data_length = total_length
696 .checked_sub(Self::MIN_UNICODE_OR_BYTE_SEQ_LENGTH_BYTES)
697 .ok_or(PacketError::DataLength)?;
698 start_idx = Self::MIN_UNICODE_OR_BYTE_SEQ_LENGTH_BYTES;
699 data_length
700 }
701 HeaderEncoding::OneByte => 1, HeaderEncoding::FourBytes => 4, };
704 trace!(id:?, data_length:%; "Parsed OBEX packet");
705
706 if buf.len() < start_idx + data_length {
707 return Err(PacketError::BufferTooSmall);
708 }
709
710 let data = &buf[start_idx..start_idx + data_length];
711 let mut out_buf = vec![0; data_length];
712 match id {
713 HeaderIdentifier::Count => {
714 Ok(Header::Count(u32::from_be_bytes(data[..].try_into().unwrap())))
715 }
716 HeaderIdentifier::Name => {
717 let name = if data.len() == 0 { None } else { Some(ObexString::try_from(data)?) };
718 Ok(Header::Name(name))
719 }
720 HeaderIdentifier::Type => Ok(Header::Type(MimeType::try_from(data)?)),
721 HeaderIdentifier::Length => {
722 Ok(Header::Length(u32::from_be_bytes(data[..].try_into().unwrap())))
723 }
724 HeaderIdentifier::TimeIso8601 => {
725 let mut time_str = ObexString::try_from(data).map(|s| s.to_string())?;
726 if time_str.ends_with("Z") {
730 let _ = time_str.pop();
731 }
732 let parsed = NaiveDateTime::parse_from_str(&time_str, Self::ISO_8601_TIME_FORMAT)
733 .map_err(PacketError::external)?;
734 Ok(Header::TimeIso8601(parsed))
735 }
736 HeaderIdentifier::Time4Byte => {
737 let elapsed_time_seconds = u32::from_be_bytes(data[..].try_into().unwrap());
738 let parsed = NaiveDateTime::from_timestamp_opt(
739 elapsed_time_seconds.into(),
740 0,
741 )
742 .ok_or_else(|| PacketError::external(anyhow::format_err!("invalid timestamp")))?;
743 Ok(Header::Time4Byte(parsed))
744 }
745 HeaderIdentifier::Description => Ok(Header::Description(ObexString::try_from(data)?)),
746 HeaderIdentifier::Target => {
747 out_buf.copy_from_slice(&data[..]);
748 Ok(Header::Target(out_buf))
749 }
750 HeaderIdentifier::Http => {
751 out_buf.copy_from_slice(&data[..]);
752 Ok(Header::Http(out_buf))
753 }
754 HeaderIdentifier::Body => {
755 out_buf.copy_from_slice(&data[..]);
756 Ok(Header::Body(out_buf))
757 }
758 HeaderIdentifier::EndOfBody => {
759 out_buf.copy_from_slice(&data[..]);
760 Ok(Header::EndOfBody(out_buf))
761 }
762 HeaderIdentifier::Who => {
763 out_buf.copy_from_slice(&data[..]);
764 Ok(Header::Who(out_buf))
765 }
766 HeaderIdentifier::ConnectionId => Ok(Header::ConnectionId(
767 ConnectionIdentifier::try_from(u32::from_be_bytes(data[..].try_into().unwrap()))?,
768 )),
769 HeaderIdentifier::ApplicationParameters => {
770 Ok(Header::ApplicationParameters(TagLengthValue::try_from(&data[..])?))
771 }
772 HeaderIdentifier::AuthenticationChallenge => {
773 out_buf.copy_from_slice(&data[..]);
774 Ok(Header::AuthenticationChallenge(out_buf))
775 }
776 HeaderIdentifier::AuthenticationResponse => {
777 out_buf.copy_from_slice(&data[..]);
778 Ok(Header::AuthenticationResponse(out_buf))
779 }
780 HeaderIdentifier::CreatorId => {
781 Ok(Header::CreatorId(u32::from_be_bytes(data[..].try_into().unwrap())))
782 }
783 HeaderIdentifier::WanUuid => {
784 let bytes: [u8; Uuid::BLUETOOTH_UUID_LENGTH_BYTES] =
785 data[..].try_into().map_err(|_| PacketError::BufferTooSmall)?;
786 Ok(Header::WanUuid(Uuid::from_be_bytes(bytes)))
787 }
788 HeaderIdentifier::ObjectClass => {
789 out_buf.copy_from_slice(&data[..]);
790 Ok(Header::ObjectClass(out_buf))
791 }
792 HeaderIdentifier::SessionParameters => {
793 out_buf.copy_from_slice(&data[..]);
794 Ok(Header::SessionParameters(out_buf))
795 }
796 HeaderIdentifier::SessionSequenceNumber => {
797 Ok(Header::SessionSequenceNumber(buf[start_idx]))
798 }
799 HeaderIdentifier::ActionId => {
800 Ok(Header::ActionId(ActionIdentifier::try_from(buf[start_idx])?))
801 }
802 HeaderIdentifier::DestName => Ok(Header::DestName(ObexString::try_from(data)?)),
803 HeaderIdentifier::Permissions => {
804 Ok(Header::Permissions(u32::from_be_bytes(data[..].try_into().unwrap())))
805 }
806 HeaderIdentifier::SingleResponseMode => {
807 Ok(Header::SingleResponseMode(SingleResponseMode::try_from(buf[start_idx])?))
808 }
809 HeaderIdentifier::SingleResponseModeParameters => {
810 Ok(Header::SingleResponseModeParameters(buf[start_idx]))
811 }
812 HeaderIdentifier::User(identifier) => {
813 out_buf.copy_from_slice(&data[..]);
814 Ok(Header::User(UserDefinedHeader { identifier, value: out_buf }))
815 }
816 }
817 }
818}
819
820#[cfg(test)]
821mod tests {
822 use super::*;
823
824 use assert_matches::assert_matches;
825 use chrono::{NaiveDate, NaiveTime};
826
827 #[fuchsia::test]
828 fn convert_action_identifier_success() {
829 let id_raw = 0x00;
830 let result = ActionIdentifier::try_from(id_raw).expect("valid identifier");
831 assert_eq!(result, ActionIdentifier::Copy);
832 let converted: u8 = (&result).into();
833 assert_eq!(id_raw, converted);
834
835 let vendor_id_raw = 0x85;
836 let result = ActionIdentifier::try_from(vendor_id_raw).expect("valid identifier");
837 assert_eq!(result, ActionIdentifier::Vendor(0x85));
838 let converted: u8 = (&result).into();
839 assert_eq!(vendor_id_raw, converted);
840 }
841
842 #[fuchsia::test]
843 fn convert_action_identifier_error() {
844 let invalid = 0x03;
845 assert_matches!(ActionIdentifier::try_from(invalid), Err(PacketError::Reserved));
846
847 let invalid = 0x7f;
848 assert_matches!(ActionIdentifier::try_from(invalid), Err(PacketError::Reserved));
849 }
850
851 #[fuchsia::test]
852 fn is_user_id() {
853 let ids = [0x00, 0x10, 0x29, 0x40, 0x80, 0xc0];
854 for id in ids {
855 assert!(!HeaderIdentifier::is_user(id));
856 }
857
858 let ids = [0x30, 0x3f, 0x71, 0x7f, 0xb5, 0xbf, 0xf0, 0xff];
859 for id in ids {
860 assert!(HeaderIdentifier::is_user(id));
861 }
862 }
863
864 #[fuchsia::test]
865 fn is_reserved_id() {
866 let ids = [0x00, 0x10, 0x30, 0x70, 0xb0, 0xf0];
867 for id in ids {
868 assert!(!HeaderIdentifier::is_reserved(id));
869 }
870
871 let ids = [0x19, 0x2f, 0x60, 0x6f, 0x99, 0xae, 0xd9, 0xef];
872 for id in ids {
873 assert!(HeaderIdentifier::is_reserved(id));
874 }
875 }
876
877 #[fuchsia::test]
878 fn valid_header_id_parsed_ok() {
879 let valid = 0x15;
880 let result = HeaderIdentifier::try_from(valid);
881 assert_matches!(result, Ok(HeaderIdentifier::DestName));
882 }
883
884 #[fuchsia::test]
885 fn user_header_id_is_ok() {
886 let user_header_id_raw = 0x33;
887 let result = HeaderIdentifier::try_from(user_header_id_raw);
888 assert_matches!(result, Ok(HeaderIdentifier::User(_)));
889 }
890
891 #[fuchsia::test]
892 fn rfa_header_id_is_reserved_error() {
893 let rfa_header_id_raw = 0x20;
894 let result = HeaderIdentifier::try_from(rfa_header_id_raw);
895 assert_matches!(result, Err(PacketError::Reserved));
896 }
897
898 #[fuchsia::test]
899 fn unknown_header_id_is_error() {
900 let unknown_header_id_raw = 0x03;
903 let result = HeaderIdentifier::try_from(unknown_header_id_raw);
904 assert_matches!(result, Err(PacketError::Identifier(_)));
905 }
906
907 #[fuchsia::test]
908 fn header_encoding_from_identifier() {
909 assert_eq!(HeaderIdentifier::SessionSequenceNumber.encoding(), HeaderEncoding::OneByte);
910 assert_eq!(HeaderIdentifier::Count.encoding(), HeaderEncoding::FourBytes);
911 assert_eq!(HeaderIdentifier::Name.encoding(), HeaderEncoding::Text);
912 assert_eq!(HeaderIdentifier::Target.encoding(), HeaderEncoding::Bytes);
913 }
914
915 #[fuchsia::test]
916 fn decode_empty_header_is_error() {
917 assert_matches!(Header::decode(&[]), Err(PacketError::BufferTooSmall));
918 }
919
920 #[fuchsia::test]
921 fn decode_header_no_payload_is_error() {
922 assert_matches!(Header::decode(&[0xc0]), Err(PacketError::BufferTooSmall));
924 }
925
926 #[fuchsia::test]
927 fn decode_byte_seq_invalid_length_is_error() {
928 let buf = [0x01, 0x07];
930 assert_matches!(Header::decode(&buf), Err(PacketError::BufferTooSmall));
931
932 let buf = [0x46, 0x05];
934 assert_matches!(Header::decode(&buf), Err(PacketError::BufferTooSmall));
935
936 let buf = [0x48, 0x00, 0x02];
938 assert_matches!(Header::decode(&buf), Err(PacketError::DataLength));
939 }
940
941 #[fuchsia::test]
942 fn decode_header_invalid_payload_is_error() {
943 let buf = [
945 0x42, 0x00, 0x0b, 0x00, 0x68, 0x00, 0x69, 0x00,
948 0x00, ];
950 assert_matches!(Header::decode(&buf), Err(PacketError::BufferTooSmall));
951
952 let buf = [
954 0xc3, 0x00, 0x00, 0x00, ];
957 assert_matches!(Header::decode(&buf), Err(PacketError::BufferTooSmall));
958
959 let buf = [
961 0x94, ];
963 assert_matches!(Header::decode(&buf), Err(PacketError::BufferTooSmall));
964
965 let buf = [
967 0x42, 0x00, 0x06, 0x12, 0x34, ];
971 assert_matches!(Header::decode(&buf), Err(PacketError::BufferTooSmall));
972 }
973
974 #[fuchsia::test]
975 fn decode_valid_header_success() {
976 let name_buf = [
978 0x01, 0x00, 0x17, 0x00, 0x54, 0x00, 0x48, 0x00, 0x49,
981 0x00, 0x4e, 0x00, 0x47, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x4f, 0x00, 0x43, 0x00, 0x00,
983 ];
984 let result = Header::decode(&name_buf).expect("can decode name header");
985 assert_eq!(result, Header::name("THING.DOC"));
986
987 let object_class_buf = [
989 0x51, 0x00, 0x0a, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, ];
993 let result = Header::decode(&object_class_buf).expect("can decode object class header");
994 assert_eq!(result, Header::ObjectClass(vec![0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06]));
995
996 let session_seq_num_buf = [
998 0x93, 0x05, ];
1001 let result = Header::decode(&session_seq_num_buf).expect("can decode valid name header");
1002 assert_eq!(result, Header::SessionSequenceNumber(5));
1003
1004 let connection_id_buf = [
1006 0xcb, 0x00, 0x00, 0x12, 0x34, ];
1009 let result = Header::decode(&connection_id_buf).expect("can decode connection id header");
1010 assert_eq!(result, Header::ConnectionId(ConnectionIdentifier(0x1234)));
1011 }
1012
1013 #[fuchsia::test]
1014 fn decode_user_data_header_success() {
1015 let user_buf = [
1016 0xb3, 0x05, ];
1019 let result = Header::decode(&user_buf).expect("can decode user header");
1020 assert_eq!(result, Header::User(UserDefinedHeader { identifier: 0xb3, value: vec![0x05] }));
1021 }
1022
1023 #[fuchsia::test]
1024 fn decode_time_header_success() {
1025 let utc_time_buf = [
1026 0x44, 0x00, 0x25, 0x00, 0x32, 0x00, 0x30, 0x00, 0x32, 0x00, 0x33, 0x00, 0x30, 0x00, 0x32, 0x00, 0x32,
1029 0x00, 0x34, 0x00, 0x54, 0x00, 0x31, 0x00, 0x32, 0x00, 0x34, 0x00, 0x31, 0x00, 0x33,
1030 0x00, 0x30, 0x00, 0x5a, 0x00, 0x00, ];
1032 let result = Header::decode(&utc_time_buf).expect("can decode a utc time header");
1033 assert_matches!(result, Header::TimeIso8601(t) if t == NaiveDate::from_ymd_opt(2023, 2, 24).unwrap().and_hms_opt(12, 41, 30).unwrap());
1034
1035 let local_time_buf = [
1036 0x44, 0x00, 0x23, 0x00, 0x32, 0x00, 0x30, 0x00, 0x32, 0x00, 0x33, 0x00, 0x30, 0x00, 0x32, 0x00, 0x32,
1039 0x00, 0x34, 0x00, 0x54, 0x00, 0x31, 0x00, 0x32, 0x00, 0x34, 0x00, 0x31, 0x00, 0x33,
1040 0x00, 0x30, 0x00, 0x00, ];
1042 let result = Header::decode(&local_time_buf).expect("can decode a local time header");
1043 assert_matches!(result, Header::TimeIso8601(t) if t == NaiveDate::from_ymd_opt(2023, 2, 24).unwrap().and_hms_opt(12, 41, 30).unwrap());
1044
1045 let timestamp_buf = [
1047 0xc4, 0x3b, 0x9a, 0xca, 0x00, ];
1050 let result = Header::decode(×tamp_buf).expect("can decode a timestamp header");
1051 assert_matches!(result, Header::Time4Byte(t) if t == NaiveDate::from_ymd_opt(2001, 9, 9).unwrap().and_hms_opt(1, 46, 40).unwrap());
1052 }
1053
1054 #[fuchsia::test]
1055 fn decode_invalid_time_header_is_error() {
1056 let invalid_utc_time_buf = [
1057 0x44, 0x00, 0x23, 0x00, 0x32, 0x00, 0x30, 0x00, 0x32, 0x00, 0x33, 0x00, 0x30, 0x00, 0x32, 0x00, 0x32,
1060 0x00, 0x34, 0x00, 0x31, 0x00, 0x32, 0x00, 0x34, 0x00, 0x31, 0x00, 0x33, 0x00, 0x30,
1061 0x00, 0x5a, 0x00,
1062 0x00, ];
1064 assert_matches!(Header::decode(&invalid_utc_time_buf), Err(PacketError::Other(_)));
1065
1066 }
1069
1070 #[fuchsia::test]
1071 fn decode_name_header_success() {
1072 let empty_name_buf = [
1073 0x01, 0x00, 0x03, ];
1076 let result = Header::decode(&empty_name_buf).expect("can decode empty name");
1077 assert_eq!(result, Header::Name(None));
1078
1079 let empty_string_name_buf = [
1080 0x01, 0x00, 0x05, 0x00, 0x00, ];
1084 let result = Header::decode(&empty_string_name_buf).expect("can decode empty string name");
1085 assert_eq!(result, Header::Name(Some("".into())));
1086
1087 let name_buf = [
1088 0x01, 0x00, 0x0b, 0x00, 0x44, 0x00, 0x4f, 0x00, 0x43, 0x00, 0x00, ];
1092 let result = Header::decode(&name_buf).expect("can decode empty string name");
1093 assert_eq!(result, Header::Name(Some("DOC".into())));
1094 }
1095
1096 #[fuchsia::test]
1097 fn decode_invalid_name_header_is_error() {
1098 let invalid_name_buf = [
1099 0x01, 0x00, 0x09, 0x00, 0x44, 0x00, 0x4f, 0x00, 0x43, ];
1103 let result = Header::decode(&invalid_name_buf);
1104 assert_matches!(result, Err(PacketError::Data(_)));
1105 }
1106
1107 #[fuchsia::test]
1108 fn decode_type_header_success() {
1109 let type_buf = [
1110 0x42, 0x00, 0x10, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x78, 0x2d, 0x76, 0x43, 0x61, 0x72, 0x64,
1113 0x00, ];
1115 let result = Header::decode(&type_buf).expect("can decode type header");
1116 assert_eq!(result, Header::Type("text/x-vCard".into()));
1117
1118 let empty_type_buf = [
1119 0x42, 0x00, 0x04, 0x00, ];
1123 let result = Header::decode(&empty_type_buf).expect("can decode type header");
1124 assert_eq!(result, Header::Type("".into()));
1125 }
1126
1127 #[fuchsia::test]
1128 fn decode_invalid_type_header_is_error() {
1129 let invalid_type_buf = [
1131 0x42, 0x00, 0x03, ];
1134 assert_matches!(Header::decode(&invalid_type_buf), Err(PacketError::Data(_)));
1135
1136 let invalid_type_buf = [
1138 0x42, 0x00, 0x0f, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x78, 0x2d, 0x76, 0x43, 0x61, 0x72,
1141 0x64, ];
1143 assert_matches!(Header::decode(&invalid_type_buf), Err(PacketError::Data(_)));
1144
1145 let invalid_string_type_buf = [
1147 0x42, 0x00, 0x07, 0x9f, 0x92, 0x96, 0x00, ];
1151 assert_matches!(Header::decode(&invalid_string_type_buf), Err(PacketError::Other(_)));
1152 }
1153
1154 #[fuchsia::test]
1155 fn encode_user_data_header_success() {
1156 let user = Header::User(UserDefinedHeader { identifier: 0xb3, value: vec![0x12] });
1158 assert_eq!(user.encoded_len(), 2);
1159 let mut buf = vec![0; user.encoded_len()];
1160 user.encode(&mut buf).expect("can encode");
1161 let expected_buf = [0xb3, 0x12];
1162 assert_eq!(buf, expected_buf);
1163
1164 let user = Header::User(UserDefinedHeader {
1166 identifier: 0xf5,
1167 value: vec![0x00, 0x01, 0x02, 0x03],
1168 });
1169 assert_eq!(user.encoded_len(), 5);
1170 let mut buf = vec![0; user.encoded_len()];
1171 user.encode(&mut buf).expect("can encode");
1172 let expected_buf = [0xf5, 0x00, 0x01, 0x02, 0x03];
1173 assert_eq!(buf, expected_buf);
1174
1175 let user = Header::User(UserDefinedHeader {
1177 identifier: 0x38,
1178 value: vec![0x00, 0x01, 0x00, 0x02, 0x00, 0x00],
1179 });
1180 assert_eq!(user.encoded_len(), 9);
1181 let mut buf = vec![0; user.encoded_len()];
1182 user.encode(&mut buf).expect("can encode");
1183 let expected_buf = [0x38, 0x00, 0x09, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00];
1184 assert_eq!(buf, expected_buf);
1185
1186 let user =
1188 Header::User(UserDefinedHeader { identifier: 0x70, value: vec![0x01, 0x02, 0x03] });
1189 assert_eq!(user.encoded_len(), 6);
1190 let mut buf = vec![0; user.encoded_len()];
1191 user.encode(&mut buf).expect("can encode");
1192 let expected_buf = [0x70, 0x00, 0x06, 0x01, 0x02, 0x03];
1193 assert_eq!(buf, expected_buf);
1194 }
1195
1196 #[fuchsia::test]
1197 fn encode_time_header_success() {
1198 let time = Header::TimeIso8601(NaiveDateTime::new(
1200 NaiveDate::from_ymd_opt(2015, 6, 3).unwrap(),
1201 NaiveTime::from_hms_milli_opt(12, 34, 56, 0).unwrap(),
1202 ));
1203 assert_eq!(time.encoded_len(), 37);
1205 let mut buf = vec![0; time.encoded_len() + 2];
1207 time.encode(&mut buf).expect("can encode");
1208 let expected_buf = [
1209 0x44, 0x00, 0x25, 0x00, 0x32, 0x00, 0x30, 0x00, 0x31, 0x00, 0x35, 0x00, 0x30, 0x00, 0x36, 0x00, 0x30,
1212 0x00, 0x33, 0x00, 0x54, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35,
1213 0x00, 0x36, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, ];
1216 assert_eq!(buf, expected_buf);
1217
1218 let timestamp = Header::Time4Byte(NaiveDateTime::from_timestamp_opt(1_000_000, 0).unwrap());
1219 assert_eq!(timestamp.encoded_len(), 5);
1220 let mut buf = vec![0; timestamp.encoded_len()];
1221 timestamp.encode(&mut buf).expect("can encode");
1222 let expected_buf = [
1223 0xc4, 0x00, 0x0f, 0x42, 0x40, ];
1226 assert_eq!(buf, expected_buf);
1227 }
1228
1229 #[fuchsia::test]
1230 fn encode_uuid_header_success() {
1231 let uuid = Header::WanUuid(Uuid::new16(0x180d));
1232 assert_eq!(uuid.encoded_len(), 19);
1234 let mut buf = vec![0; uuid.encoded_len()];
1235 uuid.encode(&mut buf).expect("can encode");
1236 let expected_buf = [
1237 0x50, 0x00, 0x13, 0x00, 0x00, 0x18, 0x0d, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b,
1240 0x34, 0xfb, ];
1242 assert_eq!(buf, expected_buf);
1243 }
1244
1245 #[fuchsia::test]
1246 fn encode_name_header_success() {
1247 let empty_name = Header::empty_name();
1248 assert_eq!(empty_name.encoded_len(), 3);
1250 let mut buf = vec![0; empty_name.encoded_len()];
1251 empty_name.encode(&mut buf).expect("can encode");
1252 let expected_buf = [0x01, 0x00, 0x03];
1253 assert_eq!(buf, expected_buf);
1254
1255 let empty_string_name = Header::name("");
1256 assert_eq!(empty_string_name.encoded_len(), 5);
1258 let mut buf = vec![0; empty_string_name.encoded_len()];
1259 empty_string_name.encode(&mut buf).expect("can encode");
1260 let expected_buf = [0x01, 0x00, 0x05, 0x00, 0x00];
1261 assert_eq!(buf, expected_buf);
1262
1263 let normal_string_name = Header::name("f");
1264 assert_eq!(normal_string_name.encoded_len(), 7);
1266 let mut buf = vec![0; normal_string_name.encoded_len()];
1267 normal_string_name.encode(&mut buf).expect("can encode");
1268 let expected_buf = [0x01, 0x00, 0x07, 0x00, 0x66, 0x00, 0x00];
1269 assert_eq!(buf, expected_buf);
1270 }
1271
1272 #[fuchsia::test]
1273 fn encode_type_header_success() {
1274 let type_ = Header::Type("text/html".into());
1275 assert_eq!(type_.encoded_len(), 13);
1277 let mut buf = vec![0; type_.encoded_len()];
1278 type_.encode(&mut buf).expect("can encode");
1279 let expected_buf = [
1280 0x42, 0x00, 0x0d, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x00, ];
1284 assert_eq!(buf, expected_buf);
1285 }
1286
1287 #[fuchsia::test]
1288 fn encode_valid_header_success() {
1289 let srm = Header::SingleResponseMode(SingleResponseMode::Disable);
1291 assert_eq!(srm.encoded_len(), 2);
1292 let mut buf = vec![0; srm.encoded_len()];
1293 srm.encode(&mut buf).expect("can encode");
1294 let expected_buf = [
1295 0x97, 0x00, ];
1298 assert_eq!(buf, expected_buf);
1299
1300 let count = Header::Count(0x1234);
1302 assert_eq!(count.encoded_len(), 5);
1303 let mut buf = vec![0; count.encoded_len()];
1304 count.encode(&mut buf).expect("can encode");
1305 let expected_buf = [
1306 0xc0, 0x00, 0x00, 0x12, 0x34, ];
1309 assert_eq!(buf, expected_buf);
1310
1311 let desc = Header::Description("obextest".into());
1313 assert_eq!(desc.encoded_len(), 21);
1314 let mut buf = vec![0; desc.encoded_len()];
1315 desc.encode(&mut buf).expect("can encode");
1316 let expected_buf = [
1317 0x05, 0x00, 0x15, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x65, 0x00, 0x78, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73,
1320 0x00, 0x74, 0x00, 0x00, ];
1322 assert_eq!(buf, expected_buf);
1323
1324 let auth_response = Header::AuthenticationResponse(vec![0x11, 0x22]);
1326 assert_eq!(auth_response.encoded_len(), 5);
1327 let mut buf = vec![0; auth_response.encoded_len()];
1328 auth_response.encode(&mut buf).expect("can encode");
1329 let expected_buf = [
1330 0x4e, 0x00, 0x05, 0x11, 0x22, ];
1334 assert_eq!(buf, expected_buf);
1335 }
1336
1337 #[fuchsia::test]
1338 fn decode_application_header_success() {
1339 #[rustfmt::skip]
1340 let buf = [
1341 0x4C, 0x00, 0x09, 0x29, 0x04, 0x20, 0x00, 0x01, 0x00, ];
1347 let result = Header::decode(&buf).expect("can decode application parameters header");
1348 assert_eq!(
1349 result,
1350 Header::ApplicationParameters(vec![(0x29, vec![0x20, 0x00, 0x01, 0x00])].into()),
1351 );
1352
1353 #[rustfmt::skip]
1354 let buf = [
1355 0x4C, 0x00, 0x0B, 0x01, 0x02, 0x00, 0x01, 0x02, 0x02, 0x00, 0x02 ];
1364 let result = Header::decode(&buf).expect("can decode application parameters header");
1365 assert_eq!(
1366 result,
1367 Header::ApplicationParameters(
1368 vec![(0x01, vec![0x00, 0x01]), (0x02, vec![0x00, 0x02]),].into()
1369 ),
1370 );
1371 }
1372
1373 #[fuchsia::test]
1374 fn decode_application_header_fail() {
1375 #[rustfmt::skip]
1376 let buf = [
1377 0x4C, 0x00, 0x09, 0x29, 0x03, 0x20, 0x00, 0x01, 0x00, ];
1383 let _ = Header::decode(&buf).expect_err("should have failed");
1384
1385 #[rustfmt::skip]
1386 let buf = [
1387 0x4C, 0x00, 0x0B, 0x01, 0x02, 0x00, 0x01, 0x02, 0x01, 0x00, 0x02 ];
1396 let _ = Header::decode(&buf).expect_err("should have failed");
1397 }
1398
1399 #[fuchsia::test]
1400 fn encode_application_header() {
1401 let header =
1403 Header::ApplicationParameters(vec![(0x29, vec![0x20, 0x00, 0x01, 0x00])].into());
1404 let mut buf = vec![0; header.encoded_len()];
1405 let _ = header.encode(&mut buf).expect("should encode successfully");
1406
1407 #[rustfmt::skip]
1408 assert_eq!(buf, vec![
1409 0x4C, 0x00, 0x09, 0x29, 0x04, 0x20, 0x00, 0x01, 0x00, ]);
1415
1416 }
1418}