1use crate::error::{Error, Result};
7use broadcast_common::len::{need_in, need_out};
8use broadcast_common::{Parse, Serialize};
9
10pub const SEGMENT_TYPE: u8 = 0x13;
12pub const HEADER_LEN: usize = 6;
14pub const FIXED_LEN: usize = 3;
16pub const INTERLACE_LEN_LEN: usize = 4;
18pub const PROGRESSIVE_HEADER_LEN: usize = 6;
20const RUN_LENGTH_7BIT_MASK: u8 = 0x7F;
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26#[cfg_attr(feature = "serde", derive(serde::Serialize))]
27#[repr(u8)]
28#[non_exhaustive]
29pub enum ObjectCodingMethod {
30 Pixels = 0x00,
32 Characters = 0x01,
34 ProgressivePixels = 0x02,
36 Reserved(u8),
38}
39
40impl ObjectCodingMethod {
41 #[must_use]
43 pub fn name(&self) -> &'static str {
44 match self {
45 Self::Pixels => "pixels",
46 Self::Characters => "characters",
47 Self::ProgressivePixels => "progressive_pixels",
48 Self::Reserved(_) => "reserved",
49 }
50 }
51
52 fn to_bits(self) -> u8 {
53 match self {
54 Self::Pixels => 0x00,
55 Self::Characters => 0x01,
56 Self::ProgressivePixels => 0x02,
57 Self::Reserved(v) => v,
58 }
59 }
60}
61
62broadcast_common::impl_spec_display!(ObjectCodingMethod, Reserved);
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66#[cfg_attr(feature = "serde", derive(serde::Serialize))]
67#[repr(u8)]
68#[non_exhaustive]
69pub enum DataType {
70 CodeString2Bit = 0x10,
72 CodeString4Bit = 0x11,
74 CodeString8Bit = 0x12,
76 MapTable2To4 = 0x20,
78 MapTable2To8 = 0x21,
80 MapTable4To8 = 0x22,
82 EndOfLine = 0xF0,
84 Reserved(u8),
86}
87
88impl DataType {
89 #[must_use]
91 pub fn name(&self) -> &'static str {
92 match self {
93 Self::CodeString2Bit => "2-bit_code_string",
94 Self::CodeString4Bit => "4-bit_code_string",
95 Self::CodeString8Bit => "8-bit_code_string",
96 Self::MapTable2To4 => "2_to_4_map_table",
97 Self::MapTable2To8 => "2_to_8_map_table",
98 Self::MapTable4To8 => "4_to_8_map_table",
99 Self::EndOfLine => "end_of_line",
100 Self::Reserved(_) => "reserved",
101 }
102 }
103}
104
105broadcast_common::impl_spec_display!(DataType, Reserved);
106
107const MAP_TABLE_2TO4_BYTES: usize = 2;
109const MAP_TABLE_2TO8_BYTES: usize = 4;
111const MAP_TABLE_4TO8_BYTES: usize = 16;
113
114#[derive(Debug, Clone, PartialEq, Eq)]
116#[cfg_attr(feature = "serde", derive(serde::Serialize))]
117pub struct PixelDataSubBlock<'a> {
118 pub data_type: DataType,
120 #[cfg_attr(feature = "serde", serde(skip))]
125 pub data: &'a [u8],
126}
127
128impl<'a> PixelDataSubBlock<'a> {
129 #[must_use]
139 pub fn runs(&self) -> Option<PixelRunIter<'a>> {
140 let depth = match self.data_type {
141 DataType::CodeString2Bit => CodeStringDepth::Two,
142 DataType::CodeString4Bit => CodeStringDepth::Four,
143 DataType::CodeString8Bit => CodeStringDepth::Eight,
144 DataType::MapTable2To4
145 | DataType::MapTable2To8
146 | DataType::MapTable4To8
147 | DataType::EndOfLine
148 | DataType::Reserved(_) => return None,
149 };
150 Some(PixelRunIter {
151 data: self.data,
152 bitpos: 0,
153 depth,
154 done: false,
155 })
156 }
157
158 fn serialized_len(&self) -> usize {
159 1 + self.data.len()
160 }
161
162 fn serialize_into(&self, buf: &mut [u8]) {
163 buf[0] = match self.data_type {
164 DataType::CodeString2Bit => 0x10,
165 DataType::CodeString4Bit => 0x11,
166 DataType::CodeString8Bit => 0x12,
167 DataType::MapTable2To4 => 0x20,
168 DataType::MapTable2To8 => 0x21,
169 DataType::MapTable4To8 => 0x22,
170 DataType::EndOfLine => 0xF0,
171 DataType::Reserved(v) => v,
172 };
173 buf[1..1 + self.data.len()].copy_from_slice(self.data);
174 }
175}
176
177#[derive(Debug, Clone, PartialEq, Eq)]
179#[cfg_attr(feature = "serde", derive(serde::Serialize))]
180pub struct InterlacedPixelsData<'a> {
181 #[cfg_attr(feature = "serde", serde(borrow))]
183 pub top_sub_blocks: alloc::vec::Vec<PixelDataSubBlock<'a>>,
184 #[cfg_attr(feature = "serde", serde(borrow))]
186 pub bottom_sub_blocks: alloc::vec::Vec<PixelDataSubBlock<'a>>,
187 #[cfg_attr(feature = "serde", serde(skip))]
193 pub stuffing: &'a [u8],
194}
195
196#[derive(Debug, Clone, PartialEq, Eq)]
198#[cfg_attr(feature = "serde", derive(serde::Serialize))]
199pub struct ProgressivePixelBlock<'a> {
200 pub bitmap_width: u16,
202 pub bitmap_height: u16,
204 #[cfg_attr(feature = "serde", serde(skip))]
206 pub compressed_data: &'a [u8],
207}
208
209#[derive(Debug, Clone, PartialEq, Eq)]
211#[cfg_attr(feature = "serde", derive(serde::Serialize))]
212#[non_exhaustive]
213pub enum ObjectDataPayload<'a> {
214 #[cfg_attr(feature = "serde", serde(borrow))]
216 InterlacedPixels(InterlacedPixelsData<'a>),
217 Characters {
222 character_codes: alloc::vec::Vec<u16>,
224 },
225 #[cfg_attr(feature = "serde", serde(borrow))]
227 ProgressivePixels(ProgressivePixelBlock<'a>),
228 Reserved {
230 coding_method: u8,
232 #[cfg_attr(feature = "serde", serde(skip))]
234 data: &'a [u8],
235 },
236}
237
238#[derive(Debug, Clone, PartialEq, Eq)]
240#[cfg_attr(feature = "serde", derive(serde::Serialize))]
241pub struct ObjectDataSegment<'a> {
242 pub page_id: u16,
244 pub object_id: u16,
246 pub object_version_number: u8,
248 pub object_coding_method: ObjectCodingMethod,
250 pub non_modifying_colour_flag: bool,
252 #[cfg_attr(feature = "serde", serde(borrow))]
254 pub payload: ObjectDataPayload<'a>,
255}
256
257#[derive(Debug, Clone, Copy, PartialEq, Eq)]
260pub struct PixelRun {
261 pub pixel_code: u8,
263 pub run_length: u32,
265}
266
267#[derive(Debug, Clone, Copy, PartialEq, Eq)]
269enum CodeStringDepth {
270 Two,
271 Four,
272 Eight,
273}
274
275#[derive(Debug, Clone)]
280pub struct PixelRunIter<'a> {
281 data: &'a [u8],
282 bitpos: usize,
283 depth: CodeStringDepth,
284 done: bool,
285}
286
287impl PixelRunIter<'_> {
288 fn bits(&self, bp: usize, n: usize) -> u8 {
291 let byte_idx = bp / 8;
292 let bit_idx = bp % 8;
293 if byte_idx >= self.data.len() {
294 return 0;
295 }
296 if bit_idx + n <= 8 {
297 (self.data[byte_idx] >> (8 - bit_idx - n)) & ((1u16 << n) - 1) as u8
298 } else {
299 let first_bits = 8 - bit_idx;
300 let v1 = ((self.data[byte_idx] & ((1u8 << first_bits) - 1)) as u16) << (n - first_bits);
301 let v2 = if byte_idx + 1 < self.data.len() {
302 (self.data[byte_idx + 1] >> (8 - (n - first_bits))) as u16
303 } else {
304 0
305 };
306 (v1 | v2) as u8
307 }
308 }
309
310 fn next_2bit(&mut self) -> Option<PixelRun> {
312 let b2 = self.bits(self.bitpos, 2);
313 self.bitpos += 2;
314 if b2 != 0 {
315 return Some(PixelRun {
316 pixel_code: b2,
317 run_length: 1,
318 });
319 }
320 let s1 = self.bits(self.bitpos, 1);
321 self.bitpos += 1;
322 if s1 == 1 {
323 let n = self.bits(self.bitpos, 3);
324 self.bitpos += 3;
325 let code = self.bits(self.bitpos, 2);
326 self.bitpos += 2;
327 return Some(PixelRun {
328 pixel_code: code,
329 run_length: u32::from(n) + 3,
330 });
331 }
332 let s2 = self.bits(self.bitpos, 1);
333 self.bitpos += 1;
334 if s2 == 1 {
335 return Some(PixelRun {
336 pixel_code: 0,
337 run_length: 1,
338 });
339 }
340 let s3 = self.bits(self.bitpos, 2);
341 self.bitpos += 2;
342 match s3 {
343 0b01 => Some(PixelRun {
344 pixel_code: 0,
345 run_length: 2,
346 }),
347 0b10 => {
348 let n = self.bits(self.bitpos, 4);
349 self.bitpos += 4;
350 let code = self.bits(self.bitpos, 2);
351 self.bitpos += 2;
352 Some(PixelRun {
353 pixel_code: code,
354 run_length: u32::from(n) + 12,
355 })
356 }
357 0b11 => {
358 let n = self.bits(self.bitpos, 8);
359 self.bitpos += 8;
360 let code = self.bits(self.bitpos, 2);
361 self.bitpos += 2;
362 Some(PixelRun {
363 pixel_code: code,
364 run_length: u32::from(n) + 29,
365 })
366 }
367 _ => {
368 self.done = true;
370 None
371 }
372 }
373 }
374
375 fn next_4bit(&mut self) -> Option<PixelRun> {
377 let b4 = self.bits(self.bitpos, 4);
378 self.bitpos += 4;
379 if b4 != 0 {
380 return Some(PixelRun {
381 pixel_code: b4,
382 run_length: 1,
383 });
384 }
385 let s1 = self.bits(self.bitpos, 1);
386 self.bitpos += 1;
387 if s1 == 0 {
388 let n3 = self.bits(self.bitpos, 3);
389 self.bitpos += 3;
390 if n3 == 0 {
391 self.done = true;
392 return None;
393 }
394 return Some(PixelRun {
395 pixel_code: 0,
396 run_length: u32::from(n3) + 2,
397 });
398 }
399 let s2 = self.bits(self.bitpos, 1);
400 self.bitpos += 1;
401 if s2 == 0 {
402 let n2 = self.bits(self.bitpos, 2);
403 self.bitpos += 2;
404 let code = self.bits(self.bitpos, 4);
405 self.bitpos += 4;
406 return Some(PixelRun {
407 pixel_code: code,
408 run_length: u32::from(n2) + 4,
409 });
410 }
411 let s3 = self.bits(self.bitpos, 2);
412 self.bitpos += 2;
413 match s3 {
414 0b00 => Some(PixelRun {
415 pixel_code: 0,
416 run_length: 1,
417 }),
418 0b01 => Some(PixelRun {
419 pixel_code: 0,
420 run_length: 2,
421 }),
422 0b10 => {
423 let n = self.bits(self.bitpos, 4);
424 self.bitpos += 4;
425 let code = self.bits(self.bitpos, 4);
426 self.bitpos += 4;
427 Some(PixelRun {
428 pixel_code: code,
429 run_length: u32::from(n) + 9,
430 })
431 }
432 _ => {
433 let n = self.bits(self.bitpos, 8);
435 self.bitpos += 8;
436 let code = self.bits(self.bitpos, 4);
437 self.bitpos += 4;
438 Some(PixelRun {
439 pixel_code: code,
440 run_length: u32::from(n) + 25,
441 })
442 }
443 }
444 }
445
446 fn next_8bit(&mut self) -> Option<PixelRun> {
449 let pos = self.bitpos / 8;
450 if pos >= self.data.len() {
451 self.done = true;
452 return None;
453 }
454 let b0 = self.data[pos];
455 if b0 != 0 {
456 self.bitpos += 8;
457 return Some(PixelRun {
458 pixel_code: b0,
459 run_length: 1,
460 });
461 }
462 if pos + 1 >= self.data.len() {
463 self.done = true;
464 return None;
465 }
466 let b1 = self.data[pos + 1];
467 if (b1 >> 7) & 1 == 0 {
468 let rl = b1 & RUN_LENGTH_7BIT_MASK;
469 self.bitpos += 16;
470 if rl == 0 {
471 self.done = true;
472 return None;
473 }
474 return Some(PixelRun {
475 pixel_code: 0,
476 run_length: u32::from(rl),
477 });
478 }
479 if pos + 2 >= self.data.len() {
481 self.done = true;
482 return None;
483 }
484 let rl = b1 & RUN_LENGTH_7BIT_MASK;
485 let code = self.data[pos + 2];
486 self.bitpos += 24;
487 Some(PixelRun {
488 pixel_code: code,
489 run_length: u32::from(rl),
490 })
491 }
492}
493
494impl Iterator for PixelRunIter<'_> {
495 type Item = PixelRun;
496
497 fn next(&mut self) -> Option<PixelRun> {
498 if self.done {
499 return None;
500 }
501 match self.depth {
502 CodeStringDepth::Two => self.next_2bit(),
503 CodeStringDepth::Four => self.next_4bit(),
504 CodeStringDepth::Eight => self.next_8bit(),
505 }
506 }
507}
508
509fn scan_2bit_code_string(data: &[u8]) -> usize {
513 let mut bitpos: usize = 0;
514 let bits = |bp: usize, n: usize| -> u8 {
515 let byte_idx = bp / 8;
516 let bit_idx = bp % 8;
517 if byte_idx >= data.len() {
518 return 0;
519 }
520 if bit_idx + n <= 8 {
521 (data[byte_idx] >> (8 - bit_idx - n)) & ((1u16 << n) - 1) as u8
522 } else {
523 let first_bits = 8 - bit_idx;
524 let v1 = ((data[byte_idx] & ((1u8 << first_bits) - 1)) as u16) << (n - first_bits);
525 let v2 = if byte_idx + 1 < data.len() {
526 (data[byte_idx + 1] >> (8 - (n - first_bits))) as u16
527 } else {
528 0
529 };
530 (v1 | v2) as u8
531 }
532 };
533 loop {
534 let b2 = bits(bitpos, 2);
535 bitpos += 2;
536 if b2 != 0 {
537 continue;
538 }
539 let s1 = bits(bitpos, 1);
541 bitpos += 1;
542 if s1 == 1 {
543 bitpos += 3 + 2;
545 continue;
546 }
547 let s2 = bits(bitpos, 1);
548 bitpos += 1;
549 if s2 == 1 {
550 continue;
552 }
553 let s3 = bits(bitpos, 2);
554 bitpos += 2;
555 match s3 {
556 0b00 => break, 0b01 => continue, 0b10 => {
559 bitpos += 4 + 2; }
561 0b11 => {
562 bitpos += 8 + 2; }
564 _ => {}
565 }
566 }
567 let byte_len = bitpos.div_ceil(8);
569 byte_len.min(data.len())
570}
571
572fn scan_4bit_code_string(data: &[u8]) -> usize {
576 let mut bitpos: usize = 0;
577 let bits = |bp: usize, n: usize| -> u8 {
578 let byte_idx = bp / 8;
579 let bit_idx = bp % 8;
580 if byte_idx >= data.len() {
581 return 0;
582 }
583 if bit_idx + n <= 8 {
584 (data[byte_idx] >> (8 - bit_idx - n)) & ((1u16 << n) - 1) as u8
585 } else {
586 let first_bits = 8 - bit_idx;
587 let v1 = ((data[byte_idx] & ((1u8 << first_bits) - 1)) as u16) << (n - first_bits);
588 let v2 = if byte_idx + 1 < data.len() {
589 (data[byte_idx + 1] >> (8 - (n - first_bits))) as u16
590 } else {
591 0
592 };
593 (v1 | v2) as u8
594 }
595 };
596 loop {
597 let b4 = bits(bitpos, 4);
598 bitpos += 4;
599 if b4 != 0 {
600 continue;
601 }
602 let s1 = bits(bitpos, 1);
604 bitpos += 1;
605 if s1 == 0 {
606 let n3 = bits(bitpos, 3);
607 bitpos += 3;
608 if n3 == 0 {
609 break;
611 }
612 continue;
614 }
615 let s2 = bits(bitpos, 1);
616 bitpos += 1;
617 if s2 == 0 {
618 bitpos += 2 + 4;
620 continue;
621 }
622 let s3 = bits(bitpos, 2);
623 bitpos += 2;
624 match s3 {
625 0b00 | 0b01 => continue, 0b10 => {
627 bitpos += 4 + 4; }
629 0b11 => {
630 bitpos += 8 + 4; }
632 _ => {}
633 }
634 }
635 let byte_len = bitpos.div_ceil(8);
637 byte_len.min(data.len())
638}
639
640fn scan_8bit_code_string(data: &[u8]) -> usize {
643 let mut pos: usize = 0;
644 loop {
645 if pos >= data.len() {
646 break;
647 }
648 if data[pos] != 0x00 {
649 pos += 1;
650 continue;
651 }
652 if pos + 1 >= data.len() {
653 pos += 1;
654 break;
655 }
656 let b = data[pos + 1];
657 let s1 = (b >> 7) & 1;
658 if s1 == 0 {
659 let rl = b & RUN_LENGTH_7BIT_MASK;
660 if rl == 0 {
661 pos += 2;
663 break;
664 }
665 pos += 2;
667 } else {
668 pos += 3;
670 }
671 }
672 pos.min(data.len())
673}
674
675fn parse_pixel_sub_blocks<'a>(
680 bytes: &'a [u8],
681 field_len: usize,
682 what: &'static str,
683) -> Result<alloc::vec::Vec<PixelDataSubBlock<'a>>> {
684 let end = field_len.min(bytes.len());
685 let field = &bytes[..end];
686 let mut blocks = alloc::vec::Vec::new();
687 let mut pos: usize = 0;
688 while pos < field.len() {
689 if pos >= field.len() {
690 break;
691 }
692 let data_type_byte = field[pos];
693 let data_type = match data_type_byte {
694 0x10 => DataType::CodeString2Bit,
695 0x11 => DataType::CodeString4Bit,
696 0x12 => DataType::CodeString8Bit,
697 0x20 => DataType::MapTable2To4,
698 0x21 => DataType::MapTable2To8,
699 0x22 => DataType::MapTable4To8,
700 0xF0 => DataType::EndOfLine,
701 v => DataType::Reserved(v),
702 };
703 pos += 1; let data_len = match data_type_byte {
706 0x10 => scan_2bit_code_string(&field[pos..]),
707 0x11 => scan_4bit_code_string(&field[pos..]),
708 0x12 => scan_8bit_code_string(&field[pos..]),
709 0x20 => MAP_TABLE_2TO4_BYTES,
710 0x21 => MAP_TABLE_2TO8_BYTES,
711 0x22 => MAP_TABLE_4TO8_BYTES,
712 0xF0 => 0,
713 _ => {
714 field.len() - pos
716 }
717 };
718
719 let block_end = (pos + data_len).min(field.len());
720 let block_data = &field[pos..block_end];
721
722 blocks.push(PixelDataSubBlock {
723 data_type,
724 data: block_data,
725 });
726 pos = block_end;
727 }
728 if pos != end {
729 return Err(Error::BufferTooShort(
730 broadcast_common::error::BufferTooShort {
731 need: end,
732 have: pos,
733 what,
734 },
735 ));
736 }
737 Ok(blocks)
738}
739
740impl<'a> Parse<'a> for ObjectDataSegment<'a> {
741 type Error = Error;
742
743 fn parse(bytes: &'a [u8]) -> Result<Self> {
744 need_in(bytes, HEADER_LEN + FIXED_LEN, "object_data_segment")?;
745 if bytes[0] != crate::pes_data_field::SYNC_BYTE {
746 return Err(Error::InvalidSync(broadcast_common::error::InvalidSync {
747 what: "sync_byte",
748 expected: u32::from(crate::pes_data_field::SYNC_BYTE),
749 found: u32::from(bytes[0]),
750 }));
751 }
752 if bytes[1] != SEGMENT_TYPE {
753 return Err(Error::UnknownSegmentType(bytes[1]));
754 }
755 let page_id = u16::from_be_bytes([bytes[2], bytes[3]]);
756 let segment_length = u16::from_be_bytes([bytes[4], bytes[5]]) as usize;
757 let total = HEADER_LEN + segment_length;
758 need_in(bytes, total, "object_data_segment data")?;
759 let body = &bytes[HEADER_LEN..HEADER_LEN + segment_length];
760 need_in(body, FIXED_LEN, "object_data_segment body")?;
761 let object_id = u16::from_be_bytes([body[0], body[1]]);
762 let object_version_number = body[2] >> 4;
763 let coding_method_bits = (body[2] >> 2) & 0x03;
764 let non_modifying_colour_flag = (body[2] & 0x02) != 0;
765 let reserved = body[2] & 0x01;
766 let _ = reserved;
768
769 let object_coding_method = match coding_method_bits {
770 0x00 => ObjectCodingMethod::Pixels,
771 0x01 => ObjectCodingMethod::Characters,
772 0x02 => ObjectCodingMethod::ProgressivePixels,
773 v => ObjectCodingMethod::Reserved(v),
774 };
775
776 let payload_data = &body[FIXED_LEN..];
777
778 let payload = match coding_method_bits {
779 0x00 => {
780 need_in(
781 payload_data,
782 INTERLACE_LEN_LEN,
783 "object_data interlace lengths",
784 )?;
785 let top_len = u16::from_be_bytes([payload_data[0], payload_data[1]]) as usize;
786 let bottom_len = u16::from_be_bytes([payload_data[2], payload_data[3]]) as usize;
787
788 let top_start = INTERLACE_LEN_LEN;
789 let top_end = top_start + top_len;
790 let bottom_start = top_end;
791 let bottom_end = bottom_start + bottom_len;
792
793 need_in(payload_data, bottom_end, "object_data pixel sub-blocks")?;
794
795 let stuffing = &payload_data[bottom_end..];
804 if let Some(&b) = stuffing.first()
805 && b != 0x00
806 {
807 return Err(Error::BadStuffingByte(b));
808 }
809
810 let top_sub_blocks = parse_pixel_sub_blocks(
811 &payload_data[top_start..top_end],
812 top_len,
813 "top pixel sub-blocks",
814 )?;
815 let bottom_sub_blocks = if bottom_len > 0 {
816 parse_pixel_sub_blocks(
817 &payload_data[bottom_start..bottom_end],
818 bottom_len,
819 "bottom pixel sub-blocks",
820 )?
821 } else {
822 alloc::vec::Vec::new()
823 };
824
825 ObjectDataPayload::InterlacedPixels(InterlacedPixelsData {
826 top_sub_blocks,
827 bottom_sub_blocks,
828 stuffing,
829 })
830 }
831 0x01 => {
832 need_in(payload_data, 1, "character count")?;
833 let number_of_codes = payload_data[0] as usize;
834 let codes_len = 1 + number_of_codes * 2;
835 need_in(payload_data, codes_len, "character codes")?;
836 let mut codes = alloc::vec::Vec::with_capacity(number_of_codes);
837 for i in 0..number_of_codes {
838 let ci = 1 + i * 2;
839 codes.push(u16::from_be_bytes([payload_data[ci], payload_data[ci + 1]]));
840 }
841 ObjectDataPayload::Characters {
842 character_codes: codes,
843 }
844 }
845 0x02 => {
846 need_in(
847 payload_data,
848 PROGRESSIVE_HEADER_LEN,
849 "progressive pixel block",
850 )?;
851 let bitmap_width = u16::from_be_bytes([payload_data[0], payload_data[1]]);
852 let bitmap_height = u16::from_be_bytes([payload_data[2], payload_data[3]]);
853 let compressed_len =
854 u16::from_be_bytes([payload_data[4], payload_data[5]]) as usize;
855 need_in(
856 payload_data,
857 PROGRESSIVE_HEADER_LEN + compressed_len,
858 "compressed bitmap data",
859 )?;
860 ObjectDataPayload::ProgressivePixels(ProgressivePixelBlock {
861 bitmap_width,
862 bitmap_height,
863 compressed_data: &payload_data
864 [PROGRESSIVE_HEADER_LEN..PROGRESSIVE_HEADER_LEN + compressed_len],
865 })
866 }
867 _ => ObjectDataPayload::Reserved {
868 coding_method: coding_method_bits,
869 data: payload_data,
870 },
871 };
872
873 Ok(ObjectDataSegment {
874 page_id,
875 object_id,
876 object_version_number,
877 object_coding_method,
878 non_modifying_colour_flag,
879 payload,
880 })
881 }
882}
883
884impl Serialize for ObjectDataSegment<'_> {
885 type Error = Error;
886
887 fn serialized_len(&self) -> usize {
888 let body_len = FIXED_LEN
889 + match &self.payload {
890 ObjectDataPayload::InterlacedPixels(ip) => {
891 let top_len: usize = ip.top_sub_blocks.iter().map(|s| s.serialized_len()).sum();
892 let bottom_len: usize = ip
893 .bottom_sub_blocks
894 .iter()
895 .map(|s| s.serialized_len())
896 .sum();
897 INTERLACE_LEN_LEN + top_len + bottom_len + ip.stuffing.len()
898 }
899 ObjectDataPayload::Characters {
900 character_codes, ..
901 } => 1 + character_codes.len() * 2,
902 ObjectDataPayload::ProgressivePixels(pp) => {
903 PROGRESSIVE_HEADER_LEN + pp.compressed_data.len()
904 }
905 ObjectDataPayload::Reserved { data, .. } => data.len(),
906 };
907 HEADER_LEN + body_len
908 }
909
910 fn serialize_into(&self, buf: &mut [u8]) -> core::result::Result<usize, Self::Error> {
911 let len = self.serialized_len();
912 need_out(buf, len)?;
913 buf[0] = 0x0F;
914 buf[1] = SEGMENT_TYPE;
915 buf[2..4].copy_from_slice(&self.page_id.to_be_bytes());
916 let seg_len = crate::segments::check_segment_length(len - HEADER_LEN)?;
917 buf[4..6].copy_from_slice(&seg_len.to_be_bytes());
918
919 buf[6..8].copy_from_slice(&self.object_id.to_be_bytes());
920 buf[8] = (broadcast_common::len::fit_mask(
921 self.object_version_number,
922 0x0F,
923 "object_version_number",
924 )? << 4)
925 | (broadcast_common::len::fit_mask(
926 self.object_coding_method.to_bits(),
927 0x03,
928 "object_coding_method",
929 )? << 2)
930 | (u8::from(self.non_modifying_colour_flag) << 1);
931
932 let mut off = HEADER_LEN + FIXED_LEN;
933 match &self.payload {
934 ObjectDataPayload::InterlacedPixels(ip) => {
935 let top_len: usize = ip.top_sub_blocks.iter().map(|s| s.serialized_len()).sum();
936 let bottom_len: usize = ip
937 .bottom_sub_blocks
938 .iter()
939 .map(|s| s.serialized_len())
940 .sum();
941 let top_len = broadcast_common::len::fit_u16(top_len, "top_field_data_length")?;
942 let bottom_len =
943 broadcast_common::len::fit_u16(bottom_len, "bottom_field_data_length")?;
944 buf[off..off + 2].copy_from_slice(&top_len.to_be_bytes());
945 buf[off + 2..off + 4].copy_from_slice(&bottom_len.to_be_bytes());
946 off += INTERLACE_LEN_LEN;
947 for sub in &ip.top_sub_blocks {
948 sub.serialize_into(&mut buf[off..]);
949 off += sub.serialized_len();
950 }
951 for sub in &ip.bottom_sub_blocks {
952 sub.serialize_into(&mut buf[off..]);
953 off += sub.serialized_len();
954 }
955 buf[off..off + ip.stuffing.len()].copy_from_slice(ip.stuffing);
956 off += ip.stuffing.len();
957 }
958 ObjectDataPayload::Characters { character_codes } => {
959 buf[off] = broadcast_common::len::fit_u8(character_codes.len(), "number_of_codes")?;
960 off += 1;
961 for code in character_codes {
962 buf[off..off + 2].copy_from_slice(&code.to_be_bytes());
963 off += 2;
964 }
965 }
966 ObjectDataPayload::ProgressivePixels(pp) => {
967 buf[off..off + 2].copy_from_slice(&pp.bitmap_width.to_be_bytes());
968 buf[off + 2..off + 4].copy_from_slice(&pp.bitmap_height.to_be_bytes());
969 let clen = broadcast_common::len::fit_u16(
970 pp.compressed_data.len(),
971 "compressed_data_length",
972 )?;
973 buf[off + 4..off + 6].copy_from_slice(&clen.to_be_bytes());
974 off += PROGRESSIVE_HEADER_LEN;
975 buf[off..off + pp.compressed_data.len()].copy_from_slice(pp.compressed_data);
976 off += pp.compressed_data.len();
977 }
978 ObjectDataPayload::Reserved { data, .. } => {
979 buf[off..off + data.len()].copy_from_slice(data);
980 off += data.len();
981 }
982 }
983 debug_assert_eq!(off, len);
984 Ok(len)
985 }
986}
987
988#[cfg(test)]
989mod tests {
990 use super::*;
991 use broadcast_common::{Parse, Serialize};
992
993 #[test]
994 fn round_trip_pixels_no_stuffing() {
995 let bytes = [
996 0x0F, 0x13, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x00, 0x03, 0x00, 0x00, 0xF0,
997 0x10, 0x0A,
998 ];
999 let seg = ObjectDataSegment::parse(&bytes).unwrap();
1000 assert_eq!(seg.object_id, 10);
1001 assert_eq!(seg.object_coding_method, ObjectCodingMethod::Pixels);
1002 match &seg.payload {
1003 ObjectDataPayload::InterlacedPixels(ip) => {
1004 assert_eq!(ip.top_sub_blocks.len(), 2);
1005 assert_eq!(ip.top_sub_blocks[0].data_type, DataType::EndOfLine);
1006 assert_eq!(ip.top_sub_blocks[1].data_type, DataType::CodeString2Bit);
1007 }
1008 _ => panic!("expected InterlacedPixels"),
1009 }
1010 let out = seg.try_to_bytes().unwrap();
1011 assert_eq!(out, bytes);
1012
1013 let mut seg2 = seg.clone();
1015 seg2.object_id = 20;
1016 let out2 = seg2.try_to_bytes().unwrap();
1017 assert_ne!(out2, bytes);
1018 let reparse = ObjectDataSegment::parse(&out2).unwrap();
1019 assert_eq!(reparse.object_id, 20);
1020 }
1021
1022 #[test]
1028 fn preserves_multi_byte_stuffing() {
1029 let bytes = [
1030 0x0F, 0x13, 0x00, 0x01, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
1035 let seg = ObjectDataSegment::parse(&bytes).unwrap();
1036 match &seg.payload {
1037 ObjectDataPayload::InterlacedPixels(ip) => {
1038 assert_eq!(ip.stuffing, &[0x00, 0x00]);
1039 }
1040 _ => panic!("expected InterlacedPixels"),
1041 }
1042 let out = seg.try_to_bytes().unwrap();
1043 assert_eq!(out, bytes, "2 trailing stuffing bytes must round-trip");
1044 }
1045
1046 #[test]
1047 fn nonzero_first_stuffing_byte_is_rejected_with_its_value() {
1048 let bytes = [
1049 0x0F, 0x13, 0x00, 0x01, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, ];
1054 assert_eq!(
1055 ObjectDataSegment::parse(&bytes).unwrap_err(),
1056 Error::BadStuffingByte(0x5A)
1057 );
1058 }
1059
1060 #[test]
1062 fn rejects_bad_sync_byte() {
1063 let bytes = [
1064 0x00, 0x13, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x00, 0x03, 0x00, 0x00, 0xF0,
1065 0x10, 0x0A,
1066 ];
1067 assert!(matches!(
1068 ObjectDataSegment::parse(&bytes),
1069 Err(Error::InvalidSync(broadcast_common::error::InvalidSync {
1070 found: 0x00,
1071 ..
1072 }))
1073 ));
1074 }
1075
1076 #[test]
1077 fn round_trip_multiple_sub_blocks() {
1078 let map_table: [u8; 2] = [0x00, 0x00];
1080 let four_bit_data = [0x11, 0x11, 0x11, 0x00]; let body: alloc::vec::Vec<u8> = [
1084 &[0x00u8, 0x0B, 0x00][..],
1085 &[0x00u8, 0x09, 0x00, 0x00][..], &[0x20u8][..],
1087 &map_table[..],
1088 &[0xF0u8][..],
1089 &[0x11u8][..],
1090 &four_bit_data[..],
1091 ]
1092 .concat();
1093
1094 let mut bytes = alloc::vec![0x0F, 0x13, 0x00, 0x01]; let body_len = body.len() as u16;
1096 bytes.extend_from_slice(&body_len.to_be_bytes());
1097 bytes.extend_from_slice(&body);
1098
1099 let seg = ObjectDataSegment::parse(&bytes).unwrap();
1100 match &seg.payload {
1101 ObjectDataPayload::InterlacedPixels(ip) => {
1102 assert_eq!(ip.top_sub_blocks.len(), 3, "expected 3 sub-blocks");
1103 assert_eq!(ip.top_sub_blocks[0].data_type, DataType::MapTable2To4);
1104 assert_eq!(ip.top_sub_blocks[0].data.len(), 2);
1105 assert_eq!(ip.top_sub_blocks[1].data_type, DataType::EndOfLine);
1106 assert_eq!(ip.top_sub_blocks[2].data_type, DataType::CodeString4Bit);
1107 assert_eq!(ip.top_sub_blocks[2].data.len(), 4);
1108 let sub = &ip.top_sub_blocks[2];
1115 let scanned_len = scan_4bit_code_string(sub.data);
1116 let mut it = sub.runs().expect("code string sub-block has runs()");
1117 let mut iterations = 0;
1118 while it.next().is_some() {
1119 iterations += 1;
1120 assert!(iterations < 1_000, "runaway iterator");
1121 }
1122 assert_eq!(it.bitpos.div_ceil(8), scanned_len);
1123 }
1124 _ => panic!("expected InterlacedPixels"),
1125 }
1126 let out = seg.try_to_bytes().unwrap();
1127 assert_eq!(out, bytes);
1128 }
1129
1130 #[test]
1134 fn runs_is_none_for_non_code_string_data_types() {
1135 let map = PixelDataSubBlock {
1136 data_type: DataType::MapTable2To4,
1137 data: &[0x00, 0x00],
1138 };
1139 assert!(map.runs().is_none());
1140 let eol = PixelDataSubBlock {
1141 data_type: DataType::EndOfLine,
1142 data: &[],
1143 };
1144 assert!(eol.runs().is_none());
1145 }
1146
1147 #[test]
1151 fn pixel_run_iter_2bit_exact() {
1152 let direct = PixelDataSubBlock {
1155 data_type: DataType::CodeString2Bit,
1156 data: &[0x80],
1157 };
1158 let mut it = direct.runs().unwrap();
1159 assert_eq!(
1160 it.next(),
1161 Some(PixelRun {
1162 pixel_code: 2,
1163 run_length: 1
1164 })
1165 );
1166 assert_eq!(it.next(), None);
1167
1168 let run = PixelDataSubBlock {
1171 data_type: DataType::CodeString2Bit,
1172 data: &[0x37],
1173 };
1174 let mut it = run.runs().unwrap();
1175 assert_eq!(
1176 it.next(),
1177 Some(PixelRun {
1178 pixel_code: 3,
1179 run_length: 8
1180 })
1181 );
1182 }
1183
1184 #[test]
1188 fn pixel_run_iter_8bit_exact() {
1189 let data = [0x05, 0x00, 0x03, 0x2A, 0x00, 0x00];
1190 let sub = PixelDataSubBlock {
1191 data_type: DataType::CodeString8Bit,
1192 data: &data,
1193 };
1194 let mut it = sub.runs().unwrap();
1195 assert_eq!(
1196 it.next(),
1197 Some(PixelRun {
1198 pixel_code: 5,
1199 run_length: 1
1200 })
1201 );
1202 assert_eq!(
1203 it.next(),
1204 Some(PixelRun {
1205 pixel_code: 0,
1206 run_length: 3
1207 })
1208 );
1209 assert_eq!(
1210 it.next(),
1211 Some(PixelRun {
1212 pixel_code: 0x2A,
1213 run_length: 1
1214 })
1215 );
1216 assert_eq!(it.next(), None);
1217 assert_eq!(scan_8bit_code_string(&data), it.bitpos.div_ceil(8));
1219 }
1220
1221 #[test]
1222 fn round_trip_characters() {
1223 let bytes = [
1224 0x0F, 0x13, 0x00, 0x01, 0x00, 0x08, 0x00, 0x0B, 0x04, 0x02, 0x00, 0x41, 0x00, 0x42,
1225 ];
1226 let seg = ObjectDataSegment::parse(&bytes).unwrap();
1227 assert_eq!(seg.object_coding_method, ObjectCodingMethod::Characters);
1228 match &seg.payload {
1229 ObjectDataPayload::Characters { character_codes } => {
1230 assert_eq!(character_codes.len(), 2);
1231 assert_eq!(character_codes[0], 0x0041);
1232 assert_eq!(character_codes[1], 0x0042);
1233 }
1234 _ => panic!("expected Characters"),
1235 }
1236 let out = seg.try_to_bytes().unwrap();
1237 assert_eq!(out, bytes);
1238
1239 let mut seg2 = seg.clone();
1244 if let ObjectDataPayload::Characters { character_codes } = &mut seg2.payload {
1245 character_codes.push(0x0043);
1246 }
1247 let out2 = seg2.try_to_bytes().unwrap();
1248 assert_ne!(out2, bytes);
1249 assert_eq!(
1250 out2[HEADER_LEN + FIXED_LEN],
1251 3,
1252 "wire number_of_codes must track the new length"
1253 );
1254 let reparse = ObjectDataSegment::parse(&out2).unwrap();
1255 match &reparse.payload {
1256 ObjectDataPayload::Characters { character_codes } => {
1257 assert_eq!(character_codes.as_slice(), &[0x0041, 0x0042, 0x0043]);
1258 }
1259 _ => panic!("expected Characters"),
1260 }
1261 }
1262
1263 #[test]
1264 fn round_trip_progressive() {
1265 let bytes = [
1266 0x0F, 0x13, 0x00, 0x01, 0x00, 0x0F, 0x00, 0x0C, 0x08, 0x00, 0x64, 0x00, 0x32, 0x00,
1267 0x06, 0x78, 0xDA, 0x63, 0x60, 0x60, 0x60,
1268 ];
1269 let seg = ObjectDataSegment::parse(&bytes).unwrap();
1270 assert_eq!(
1271 seg.object_coding_method,
1272 ObjectCodingMethod::ProgressivePixels
1273 );
1274 match &seg.payload {
1275 ObjectDataPayload::ProgressivePixels(pp) => {
1276 assert_eq!(pp.bitmap_width, 100);
1277 assert_eq!(pp.bitmap_height, 50);
1278 assert_eq!(pp.compressed_data.len(), 6);
1279 }
1280 _ => panic!("expected ProgressivePixels"),
1281 }
1282 let out = seg.try_to_bytes().unwrap();
1283 assert_eq!(out, bytes);
1284
1285 let mut seg2 = seg.clone();
1287 if let ObjectDataPayload::ProgressivePixels(pp) = &mut seg2.payload {
1288 pp.bitmap_width = 200;
1289 }
1290 let out2 = seg2.try_to_bytes().unwrap();
1291 assert_ne!(out2, bytes);
1292 let reparse = ObjectDataSegment::parse(&out2).unwrap();
1293 match &reparse.payload {
1294 ObjectDataPayload::ProgressivePixels(pp) => {
1295 assert_eq!(pp.bitmap_width, 200);
1296 }
1297 _ => panic!(),
1298 }
1299 }
1300
1301 #[test]
1302 fn oversized_segment_is_rejected_not_wrapped() {
1303 let big = alloc::vec![0u8; 65_536];
1306 let seg = ObjectDataSegment {
1307 page_id: 1,
1308 object_id: 1,
1309 object_version_number: 0,
1310 object_coding_method: ObjectCodingMethod::ProgressivePixels,
1311 non_modifying_colour_flag: false,
1312 payload: ObjectDataPayload::ProgressivePixels(ProgressivePixelBlock {
1313 bitmap_width: 1,
1314 bitmap_height: 1,
1315 compressed_data: &big,
1316 }),
1317 };
1318 let mut buf = alloc::vec![0u8; 65_600];
1319 assert_eq!(seg.serialize_into(&mut buf), Err(Error::SegmentTooLarge));
1320 }
1321}