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