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 & 0x03,
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 0x20 => MAP_TABLE_2TO4_BYTES,
706 0x21 => MAP_TABLE_2TO8_BYTES,
707 0x22 => MAP_TABLE_4TO8_BYTES,
708 0xF0 => 0,
709 0x10 => scan_2bit_code_string(&field[pos..]),
710 0x11 => scan_4bit_code_string(&field[pos..]),
711 0x12 => scan_8bit_code_string(&field[pos..]),
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] = (self.object_version_number << 4)
963 | (self.object_coding_method.to_bits() << 2)
964 | (u8::from(self.non_modifying_colour_flag) << 1);
965
966 let mut off = HEADER_LEN + FIXED_LEN;
967 match &self.payload {
968 ObjectDataPayload::InterlacedPixels(ip) => {
969 let top_len: usize = ip.top_sub_blocks.iter().map(|s| s.serialized_len()).sum();
970 let bottom_len: usize = ip
971 .bottom_sub_blocks
972 .iter()
973 .map(|s| s.serialized_len())
974 .sum();
975 let top_len = broadcast_common::len::fit_u16(top_len, "top_field_data_length")?;
976 let bottom_len =
977 broadcast_common::len::fit_u16(bottom_len, "bottom_field_data_length")?;
978 buf[off..off + 2].copy_from_slice(&top_len.to_be_bytes());
979 buf[off + 2..off + 4].copy_from_slice(&bottom_len.to_be_bytes());
980 off += INTERLACE_LEN_LEN;
981 for sub in &ip.top_sub_blocks {
982 sub.serialize_into(&mut buf[off..]);
983 off += sub.serialized_len();
984 }
985 for sub in &ip.bottom_sub_blocks {
986 sub.serialize_into(&mut buf[off..]);
987 off += sub.serialized_len();
988 }
989 buf[off..off + ip.stuffing.len()].copy_from_slice(ip.stuffing);
990 off += ip.stuffing.len();
991 }
992 ObjectDataPayload::Characters { character_codes } => {
993 buf[off] = broadcast_common::len::fit_u8(character_codes.len(), "number_of_codes")?;
994 off += 1;
995 for code in character_codes {
996 buf[off..off + 2].copy_from_slice(&code.to_be_bytes());
997 off += 2;
998 }
999 }
1000 ObjectDataPayload::ProgressivePixels(pp) => {
1001 buf[off..off + 2].copy_from_slice(&pp.bitmap_width.to_be_bytes());
1002 buf[off + 2..off + 4].copy_from_slice(&pp.bitmap_height.to_be_bytes());
1003 let clen = broadcast_common::len::fit_u16(
1004 pp.compressed_data.len(),
1005 "compressed_data_length",
1006 )?;
1007 buf[off + 4..off + 6].copy_from_slice(&clen.to_be_bytes());
1008 off += PROGRESSIVE_HEADER_LEN;
1009 buf[off..off + pp.compressed_data.len()].copy_from_slice(pp.compressed_data);
1010 off += pp.compressed_data.len();
1011 }
1012 ObjectDataPayload::Reserved { data, .. } => {
1013 buf[off..off + data.len()].copy_from_slice(data);
1014 off += data.len();
1015 }
1016 }
1017 debug_assert_eq!(off, len);
1018 Ok(len)
1019 }
1020}
1021
1022#[cfg(test)]
1023mod tests {
1024 use super::*;
1025 use broadcast_common::{Parse, Serialize};
1026
1027 #[test]
1028 fn round_trip_pixels_no_stuffing() {
1029 let bytes = [
1030 0x0F, 0x13, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x00, 0x03, 0x00, 0x00, 0xF0,
1031 0x10, 0x0A,
1032 ];
1033 let seg = ObjectDataSegment::parse(&bytes).unwrap();
1034 assert_eq!(seg.object_id, 10);
1035 assert_eq!(seg.object_coding_method, ObjectCodingMethod::Pixels);
1036 match &seg.payload {
1037 ObjectDataPayload::InterlacedPixels(ip) => {
1038 assert_eq!(ip.top_sub_blocks.len(), 2);
1039 assert_eq!(ip.top_sub_blocks[0].data_type, DataType::EndOfLine);
1040 assert_eq!(ip.top_sub_blocks[1].data_type, DataType::CodeString2Bit);
1041 }
1042 _ => panic!("expected InterlacedPixels"),
1043 }
1044 let out = seg.to_bytes();
1045 assert_eq!(out, bytes);
1046
1047 let mut seg2 = seg.clone();
1049 seg2.object_id = 20;
1050 let out2 = seg2.to_bytes();
1051 assert_ne!(out2, bytes);
1052 let reparse = ObjectDataSegment::parse(&out2).unwrap();
1053 assert_eq!(reparse.object_id, 20);
1054 }
1055
1056 #[test]
1062 fn preserves_multi_byte_stuffing() {
1063 let bytes = [
1064 0x0F, 0x13, 0x00, 0x01, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
1069 let seg = ObjectDataSegment::parse(&bytes).unwrap();
1070 match &seg.payload {
1071 ObjectDataPayload::InterlacedPixels(ip) => {
1072 assert_eq!(ip.stuffing, &[0x00, 0x00]);
1073 }
1074 _ => panic!("expected InterlacedPixels"),
1075 }
1076 let out = seg.to_bytes();
1077 assert_eq!(out, bytes, "2 trailing stuffing bytes must round-trip");
1078 }
1079
1080 #[test]
1082 fn rejects_bad_sync_byte() {
1083 let bytes = [
1084 0x00, 0x13, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x00, 0x03, 0x00, 0x00, 0xF0,
1085 0x10, 0x0A,
1086 ];
1087 assert!(matches!(
1088 ObjectDataSegment::parse(&bytes),
1089 Err(Error::BadSyncByte(0x00))
1090 ));
1091 }
1092
1093 #[test]
1094 fn round_trip_multiple_sub_blocks() {
1095 let map_table: [u8; 2] = [0x00, 0x00];
1097 let four_bit_data = [0x11, 0x11, 0x11, 0x00]; let body: alloc::vec::Vec<u8> = [
1101 &[0x00u8, 0x0B, 0x00][..],
1102 &[0x00u8, 0x09, 0x00, 0x00][..], &[0x20u8][..],
1104 &map_table[..],
1105 &[0xF0u8][..],
1106 &[0x11u8][..],
1107 &four_bit_data[..],
1108 ]
1109 .concat();
1110
1111 let mut bytes = alloc::vec![0x0F, 0x13, 0x00, 0x01]; let body_len = body.len() as u16;
1113 bytes.extend_from_slice(&body_len.to_be_bytes());
1114 bytes.extend_from_slice(&body);
1115
1116 let seg = ObjectDataSegment::parse(&bytes).unwrap();
1117 match &seg.payload {
1118 ObjectDataPayload::InterlacedPixels(ip) => {
1119 assert_eq!(ip.top_sub_blocks.len(), 3, "expected 3 sub-blocks");
1120 assert_eq!(ip.top_sub_blocks[0].data_type, DataType::MapTable2To4);
1121 assert_eq!(ip.top_sub_blocks[0].data.len(), 2);
1122 assert_eq!(ip.top_sub_blocks[1].data_type, DataType::EndOfLine);
1123 assert_eq!(ip.top_sub_blocks[2].data_type, DataType::CodeString4Bit);
1124 assert_eq!(ip.top_sub_blocks[2].data.len(), 4);
1125 let sub = &ip.top_sub_blocks[2];
1132 let scanned_len = scan_4bit_code_string(sub.data);
1133 let mut it = sub.runs().expect("code string sub-block has runs()");
1134 let mut iterations = 0;
1135 while it.next().is_some() {
1136 iterations += 1;
1137 assert!(iterations < 1_000, "runaway iterator");
1138 }
1139 assert_eq!(it.bitpos.div_ceil(8), scanned_len);
1140 }
1141 _ => panic!("expected InterlacedPixels"),
1142 }
1143 let out = seg.to_bytes();
1144 assert_eq!(out, bytes);
1145 }
1146
1147 #[test]
1151 fn runs_is_none_for_non_code_string_data_types() {
1152 let map = PixelDataSubBlock {
1153 data_type: DataType::MapTable2To4,
1154 data: &[0x00, 0x00],
1155 };
1156 assert!(map.runs().is_none());
1157 let eol = PixelDataSubBlock {
1158 data_type: DataType::EndOfLine,
1159 data: &[],
1160 };
1161 assert!(eol.runs().is_none());
1162 }
1163
1164 #[test]
1168 fn pixel_run_iter_2bit_exact() {
1169 let direct = PixelDataSubBlock {
1172 data_type: DataType::CodeString2Bit,
1173 data: &[0x80],
1174 };
1175 let mut it = direct.runs().unwrap();
1176 assert_eq!(
1177 it.next(),
1178 Some(PixelRun {
1179 pixel_code: 2,
1180 run_length: 1
1181 })
1182 );
1183 assert_eq!(it.next(), None);
1184
1185 let run = PixelDataSubBlock {
1188 data_type: DataType::CodeString2Bit,
1189 data: &[0x37],
1190 };
1191 let mut it = run.runs().unwrap();
1192 assert_eq!(
1193 it.next(),
1194 Some(PixelRun {
1195 pixel_code: 3,
1196 run_length: 8
1197 })
1198 );
1199 }
1200
1201 #[test]
1205 fn pixel_run_iter_8bit_exact() {
1206 let data = [0x05, 0x00, 0x03, 0x2A, 0x00, 0x00];
1207 let sub = PixelDataSubBlock {
1208 data_type: DataType::CodeString8Bit,
1209 data: &data,
1210 };
1211 let mut it = sub.runs().unwrap();
1212 assert_eq!(
1213 it.next(),
1214 Some(PixelRun {
1215 pixel_code: 5,
1216 run_length: 1
1217 })
1218 );
1219 assert_eq!(
1220 it.next(),
1221 Some(PixelRun {
1222 pixel_code: 0,
1223 run_length: 3
1224 })
1225 );
1226 assert_eq!(
1227 it.next(),
1228 Some(PixelRun {
1229 pixel_code: 0x2A,
1230 run_length: 1
1231 })
1232 );
1233 assert_eq!(it.next(), None);
1234 assert_eq!(scan_8bit_code_string(&data), it.bitpos.div_ceil(8));
1236 }
1237
1238 #[test]
1239 fn round_trip_characters() {
1240 let bytes = [
1241 0x0F, 0x13, 0x00, 0x01, 0x00, 0x08, 0x00, 0x0B, 0x04, 0x02, 0x00, 0x41, 0x00, 0x42,
1242 ];
1243 let seg = ObjectDataSegment::parse(&bytes).unwrap();
1244 assert_eq!(seg.object_coding_method, ObjectCodingMethod::Characters);
1245 match &seg.payload {
1246 ObjectDataPayload::Characters { character_codes } => {
1247 assert_eq!(character_codes.len(), 2);
1248 assert_eq!(character_codes[0], 0x0041);
1249 assert_eq!(character_codes[1], 0x0042);
1250 }
1251 _ => panic!("expected Characters"),
1252 }
1253 let out = seg.to_bytes();
1254 assert_eq!(out, bytes);
1255
1256 let mut seg2 = seg.clone();
1261 if let ObjectDataPayload::Characters { character_codes } = &mut seg2.payload {
1262 character_codes.push(0x0043);
1263 }
1264 let out2 = seg2.to_bytes();
1265 assert_ne!(out2, bytes);
1266 assert_eq!(
1267 out2[HEADER_LEN + FIXED_LEN],
1268 3,
1269 "wire number_of_codes must track the new length"
1270 );
1271 let reparse = ObjectDataSegment::parse(&out2).unwrap();
1272 match &reparse.payload {
1273 ObjectDataPayload::Characters { character_codes } => {
1274 assert_eq!(character_codes.as_slice(), &[0x0041, 0x0042, 0x0043]);
1275 }
1276 _ => panic!("expected Characters"),
1277 }
1278 }
1279
1280 #[test]
1281 fn round_trip_progressive() {
1282 let bytes = [
1283 0x0F, 0x13, 0x00, 0x01, 0x00, 0x0F, 0x00, 0x0C, 0x08, 0x00, 0x64, 0x00, 0x32, 0x00,
1284 0x06, 0x78, 0xDA, 0x63, 0x60, 0x60, 0x60,
1285 ];
1286 let seg = ObjectDataSegment::parse(&bytes).unwrap();
1287 assert_eq!(
1288 seg.object_coding_method,
1289 ObjectCodingMethod::ProgressivePixels
1290 );
1291 match &seg.payload {
1292 ObjectDataPayload::ProgressivePixels(pp) => {
1293 assert_eq!(pp.bitmap_width, 100);
1294 assert_eq!(pp.bitmap_height, 50);
1295 assert_eq!(pp.compressed_data.len(), 6);
1296 }
1297 _ => panic!("expected ProgressivePixels"),
1298 }
1299 let out = seg.to_bytes();
1300 assert_eq!(out, bytes);
1301
1302 let mut seg2 = seg.clone();
1304 if let ObjectDataPayload::ProgressivePixels(pp) = &mut seg2.payload {
1305 pp.bitmap_width = 200;
1306 }
1307 let out2 = seg2.to_bytes();
1308 assert_ne!(out2, bytes);
1309 let reparse = ObjectDataSegment::parse(&out2).unwrap();
1310 match &reparse.payload {
1311 ObjectDataPayload::ProgressivePixels(pp) => {
1312 assert_eq!(pp.bitmap_width, 200);
1313 }
1314 _ => panic!(),
1315 }
1316 }
1317
1318 #[test]
1319 fn oversized_segment_is_rejected_not_wrapped() {
1320 let big = alloc::vec![0u8; 65_536];
1323 let seg = ObjectDataSegment {
1324 page_id: 1,
1325 object_id: 1,
1326 object_version_number: 0,
1327 object_coding_method: ObjectCodingMethod::ProgressivePixels,
1328 non_modifying_colour_flag: false,
1329 payload: ObjectDataPayload::ProgressivePixels(ProgressivePixelBlock {
1330 bitmap_width: 1,
1331 bitmap_height: 1,
1332 compressed_data: &big,
1333 }),
1334 };
1335 let mut buf = alloc::vec![0u8; 65_600];
1336 assert_eq!(seg.serialize_into(&mut buf), Err(Error::SegmentTooLarge));
1337 }
1338}