1pub mod pat;
25pub mod pmt;
26
27use crate::mpegts_crc;
28use crate::packet;
29use log::warn;
30use std::fmt;
31
32pub trait SectionProcessor {
50 type Context;
53
54 fn start_section(
58 &mut self,
59 ctx: &mut Self::Context,
60 header: &SectionCommonHeader,
61 section_data: &[u8],
62 );
63 fn continue_section(&mut self, ctx: &mut Self::Context, section_data: &[u8]);
66
67 fn reset(&mut self);
70}
71
72#[derive(Debug, PartialEq, Eq)]
74pub enum CurrentNext {
75 Current,
77 Next,
79}
80
81impl CurrentNext {
82 fn from(v: u8) -> CurrentNext {
83 match v {
84 0 => CurrentNext::Next,
85 1 => CurrentNext::Current,
86 _ => panic!("invalid current_next_indicator value {}", v),
87 }
88 }
89}
90
91pub struct TableSyntaxHeader<'buf> {
97 buf: &'buf [u8],
98}
99
100impl<'buf> TableSyntaxHeader<'buf> {
101 pub const SIZE: usize = 5;
103
104 pub fn new(buf: &'buf [u8]) -> TableSyntaxHeader<'buf> {
109 assert!(buf.len() >= Self::SIZE);
110 TableSyntaxHeader { buf }
111 }
112 pub fn id(&self) -> u16 {
120 u16::from(self.buf[0]) << 8 | u16::from(self.buf[1])
121 }
122 pub fn version(&self) -> u8 {
125 (self.buf[2] >> 1) & 0b0001_1111
126 }
127 pub fn current_next_indicator(&self) -> CurrentNext {
131 CurrentNext::from(self.buf[2] & 1)
132 }
133 pub fn section_number(&self) -> u8 {
139 self.buf[3]
140 }
141 pub fn last_section_number(&self) -> u8 {
145 self.buf[4]
146 }
147}
148impl<'buf> fmt::Debug for TableSyntaxHeader<'buf> {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
150 f.debug_struct("TableSyntaxHeader")
151 .field("id", &self.id())
152 .field("version", &self.version())
153 .field("current_next_indicator", &self.current_next_indicator())
154 .field("section_number", &self.section_number())
155 .field("last_section_number", &self.last_section_number())
156 .finish()
157 }
158}
159
160pub struct CrcCheckWholeSectionSyntaxPayloadParser<P>
164where
165 P: WholeSectionSyntaxPayloadParser,
166{
167 inner: P,
168}
169impl<P> CrcCheckWholeSectionSyntaxPayloadParser<P>
170where
171 P: WholeSectionSyntaxPayloadParser,
172{
173 const CRC_SIZE: usize = 4;
174
175 pub fn new(inner: P) -> CrcCheckWholeSectionSyntaxPayloadParser<P> {
178 CrcCheckWholeSectionSyntaxPayloadParser { inner }
179 }
180}
181
182impl<P> WholeSectionSyntaxPayloadParser for CrcCheckWholeSectionSyntaxPayloadParser<P>
183where
184 P: WholeSectionSyntaxPayloadParser,
185{
186 type Context = P::Context;
187
188 fn section<'a>(
189 &mut self,
190 ctx: &mut Self::Context,
191 header: &SectionCommonHeader,
192 table_syntax_header: &TableSyntaxHeader<'a>,
193 data: &'a [u8],
194 ) {
195 assert!(header.section_syntax_indicator);
196 if data.len() < SectionCommonHeader::SIZE + TableSyntaxHeader::SIZE + Self::CRC_SIZE {
197 warn!(
199 "section data length too small for table_id {}: {}",
200 header.table_id,
201 data.len()
202 );
203 return;
204 }
205 if !cfg!(fuzzing) && mpegts_crc::sum32(data) != 0 {
208 warn!("section crc check failed for table_id {}", header.table_id,);
209 return;
210 }
211 self.inner.section(ctx, header, table_syntax_header, data);
212 }
213}
214
215pub trait WholeSectionSyntaxPayloadParser {
218 type Context;
220
221 fn section<'a>(
224 &mut self,
225 _: &mut Self::Context,
226 header: &SectionCommonHeader,
227 table_syntax_header: &TableSyntaxHeader<'a>,
228 data: &'a [u8],
229 );
230}
231
232pub trait WholeCompactSyntaxPayloadParser {
237 type Context;
239
240 fn section(&mut self, _: &mut Self::Context, header: &SectionCommonHeader, data: &[u8]);
243}
244
245enum BufferSectionState {
246 Buffering(usize),
247 Complete,
248}
249
250pub struct BufferSectionSyntaxParser<P>
254where
255 P: WholeSectionSyntaxPayloadParser,
256{
257 buf: Vec<u8>,
258 state: BufferSectionState,
259 parser: P,
260}
261impl<P> BufferSectionSyntaxParser<P>
262where
263 P: WholeSectionSyntaxPayloadParser,
264{
265 pub fn new(parser: P) -> BufferSectionSyntaxParser<P> {
268 BufferSectionSyntaxParser {
269 buf: vec![],
270 state: BufferSectionState::Complete,
271 parser,
272 }
273 }
274}
275impl<P> SectionSyntaxPayloadParser for BufferSectionSyntaxParser<P>
276where
277 P: WholeSectionSyntaxPayloadParser,
278{
279 type Context = P::Context;
280
281 fn start_syntax_section<'a>(
282 &mut self,
283 ctx: &mut Self::Context,
284 header: &SectionCommonHeader,
285 table_syntax_header: &TableSyntaxHeader<'a>,
286 data: &'a [u8],
287 ) {
288 let section_length_with_header = header.section_length + SectionCommonHeader::SIZE;
289 if section_length_with_header <= data.len() {
290 self.state = BufferSectionState::Complete;
292 self.parser.section(
293 ctx,
294 header,
295 table_syntax_header,
296 &data[..section_length_with_header],
297 )
298 } else {
299 self.buf.clear();
301 self.buf.extend_from_slice(data);
302 let to_read = section_length_with_header - data.len();
303 self.state = BufferSectionState::Buffering(to_read);
304 }
305 }
306
307 fn continue_syntax_section(&mut self, ctx: &mut Self::Context, data: &[u8]) {
308 match self.state {
309 BufferSectionState::Complete => {
310 warn!("attempt to add extra data when section already complete");
311 }
312 BufferSectionState::Buffering(remaining) => {
313 let new_remaining = if data.len() > remaining {
314 0
315 } else {
316 remaining - data.len()
317 };
318 if new_remaining == 0 {
319 self.buf.extend_from_slice(&data[..remaining]);
320 self.state = BufferSectionState::Complete;
321 let header = SectionCommonHeader::new(&self.buf[..SectionCommonHeader::SIZE]);
322 let table_syntax_header =
323 TableSyntaxHeader::new(&self.buf[SectionCommonHeader::SIZE..]);
324 self.parser
325 .section(ctx, &header, &table_syntax_header, &self.buf[..]);
326 } else {
327 self.buf.extend_from_slice(data);
328 self.state = BufferSectionState::Buffering(new_remaining);
329 }
330 }
331 }
332 }
333 fn reset(&mut self) {
334 self.buf.clear();
335 self.state = BufferSectionState::Complete;
336 }
337}
338
339pub struct BufferCompactSyntaxParser<P>
343where
344 P: WholeCompactSyntaxPayloadParser,
345{
346 buf: Vec<u8>,
347 state: BufferSectionState,
348 parser: P,
349}
350impl<P> BufferCompactSyntaxParser<P>
351where
352 P: WholeCompactSyntaxPayloadParser,
353{
354 pub fn new(parser: P) -> BufferCompactSyntaxParser<P> {
357 BufferCompactSyntaxParser {
358 buf: vec![],
359 state: BufferSectionState::Complete,
360 parser,
361 }
362 }
363}
364impl<P> CompactSyntaxPayloadParser for BufferCompactSyntaxParser<P>
365where
366 P: WholeCompactSyntaxPayloadParser,
367{
368 type Context = P::Context;
369
370 fn start_compact_section(
371 &mut self,
372 ctx: &mut Self::Context,
373 header: &SectionCommonHeader,
374 data: &[u8],
375 ) {
376 let section_length_with_header = header.section_length + SectionCommonHeader::SIZE;
377 if section_length_with_header <= data.len() {
378 self.state = BufferSectionState::Complete;
380 self.parser
381 .section(ctx, header, &data[..section_length_with_header])
382 } else {
383 self.buf.clear();
385 self.buf.extend_from_slice(data);
386 let to_read = section_length_with_header - data.len();
387 self.state = BufferSectionState::Buffering(to_read);
388 }
389 }
390
391 fn continue_compact_section(&mut self, ctx: &mut Self::Context, data: &[u8]) {
392 match self.state {
393 BufferSectionState::Complete => {
394 warn!("attempt to add extra data when section already complete");
395 }
396 BufferSectionState::Buffering(remaining) => {
397 let new_remaining = if data.len() > remaining {
398 0
399 } else {
400 remaining - data.len()
401 };
402 if new_remaining == 0 {
403 self.buf.extend_from_slice(&data[..remaining]);
404 self.state = BufferSectionState::Complete;
405 let header = SectionCommonHeader::new(&self.buf[..SectionCommonHeader::SIZE]);
406 self.parser.section(ctx, &header, &self.buf[..]);
407 } else {
408 self.buf.extend_from_slice(data);
409 self.state = BufferSectionState::Buffering(new_remaining);
410 }
411 }
412 }
413 }
414 fn reset(&mut self) {
415 self.buf.clear();
416 self.state = BufferSectionState::Complete;
417 }
418}
419
420pub struct DedupSectionSyntaxPayloadParser<SSPP>
427where
428 SSPP: SectionSyntaxPayloadParser,
429{
430 inner: SSPP,
431 last_version: Option<u8>,
432 ignore_rest: bool,
433}
434impl<SSPP> DedupSectionSyntaxPayloadParser<SSPP>
435where
436 SSPP: SectionSyntaxPayloadParser,
437{
438 pub fn new(inner: SSPP) -> DedupSectionSyntaxPayloadParser<SSPP> {
441 DedupSectionSyntaxPayloadParser {
442 inner,
443 last_version: None,
444 ignore_rest: false,
445 }
446 }
447}
448impl<SSPP> SectionSyntaxPayloadParser for DedupSectionSyntaxPayloadParser<SSPP>
449where
450 SSPP: SectionSyntaxPayloadParser,
451{
452 type Context = SSPP::Context;
453
454 fn start_syntax_section<'a>(
455 &mut self,
456 ctx: &mut Self::Context,
457 header: &SectionCommonHeader,
458 table_syntax_header: &TableSyntaxHeader<'a>,
459 data: &'a [u8],
460 ) {
461 if let Some(last) = self.last_version {
462 if last == table_syntax_header.version() {
463 self.ignore_rest = true;
464 return;
465 }
466 }
467 self.ignore_rest = false;
468 self.last_version = Some(table_syntax_header.version());
469 self.inner
470 .start_syntax_section(ctx, header, table_syntax_header, data);
471 }
472
473 fn continue_syntax_section(&mut self, ctx: &mut Self::Context, data: &[u8]) {
474 if !self.ignore_rest {
475 self.inner.continue_syntax_section(ctx, data)
476 }
477 }
478 fn reset(&mut self) {
479 self.inner.reset();
480 self.last_version = None;
481 self.ignore_rest = false;
482 }
483}
484
485pub trait SectionSyntaxPayloadParser {
487 type Context;
489
490 fn start_syntax_section<'a>(
494 &mut self,
495 ctx: &mut Self::Context,
496 header: &SectionCommonHeader,
497 table_syntax_header: &TableSyntaxHeader<'a>,
498 data: &'a [u8],
499 );
500
501 fn continue_syntax_section(&mut self, ctx: &mut Self::Context, data: &[u8]);
504
505 fn reset(&mut self);
508}
509
510pub trait CompactSyntaxPayloadParser {
512 type Context;
514
515 fn start_compact_section(
519 &mut self,
520 ctx: &mut Self::Context,
521 header: &SectionCommonHeader,
522 data: &[u8],
523 );
524
525 fn continue_compact_section(&mut self, ctx: &mut Self::Context, data: &[u8]);
528
529 fn reset(&mut self);
532}
533
534pub struct CompactSyntaxSectionProcessor<SP>
539where
540 SP: CompactSyntaxPayloadParser,
541{
542 payload_parser: SP,
543 ignore_rest: bool,
544}
545impl<SP> CompactSyntaxSectionProcessor<SP>
546where
547 SP: CompactSyntaxPayloadParser,
548{
549 const SECTION_LIMIT: usize = 1021;
550
551 pub fn new(payload_parser: SP) -> CompactSyntaxSectionProcessor<SP> {
554 CompactSyntaxSectionProcessor {
555 payload_parser,
556 ignore_rest: false,
557 }
558 }
559}
560impl<SP> SectionProcessor for CompactSyntaxSectionProcessor<SP>
561where
562 SP: CompactSyntaxPayloadParser,
563{
564 type Context = SP::Context;
565
566 fn start_section(
567 &mut self,
568 ctx: &mut Self::Context,
569 header: &SectionCommonHeader,
570 data: &[u8],
571 ) {
572 if header.section_syntax_indicator {
573 warn!(
575 "CompactSyntaxSectionProcessor requires that section_syntax_indicator NOT be set in the section header"
576 );
577 self.ignore_rest = true;
578 return;
579 }
580 if data.len() < SectionCommonHeader::SIZE {
581 warn!("CompactSyntaxSectionProcessor data {} too short for header {} (TODO: implement buffering)", data.len(), SectionCommonHeader::SIZE + TableSyntaxHeader::SIZE);
582 self.ignore_rest = true;
583 return;
584 }
585 if header.section_length > Self::SECTION_LIMIT {
586 warn!(
587 "CompactSyntaxSectionProcessor section_length={} is too large (limit {})",
588 header.section_length,
589 Self::SECTION_LIMIT
590 );
591 self.ignore_rest = true;
592 return;
593 }
594 self.ignore_rest = false;
595 self.payload_parser.start_compact_section(ctx, header, data)
596 }
597
598 fn continue_section(&mut self, ctx: &mut Self::Context, data: &[u8]) {
599 if !self.ignore_rest {
600 self.payload_parser.continue_compact_section(ctx, data)
601 }
602 }
603 fn reset(&mut self) {
604 self.payload_parser.reset()
605 }
606}
607
608pub struct SectionSyntaxSectionProcessor<SP>
614where
615 SP: SectionSyntaxPayloadParser,
616{
617 payload_parser: SP,
618 ignore_rest: bool,
619}
620impl<SP> SectionSyntaxSectionProcessor<SP>
621where
622 SP: SectionSyntaxPayloadParser,
623{
624 const SECTION_LIMIT: usize = 1021;
625
626 pub fn new(payload_parser: SP) -> SectionSyntaxSectionProcessor<SP> {
629 SectionSyntaxSectionProcessor {
630 payload_parser,
631 ignore_rest: false,
632 }
633 }
634}
635impl<SP> SectionProcessor for SectionSyntaxSectionProcessor<SP>
636where
637 SP: SectionSyntaxPayloadParser,
638{
639 type Context = SP::Context;
640
641 fn start_section(
642 &mut self,
643 ctx: &mut Self::Context,
644 header: &SectionCommonHeader,
645 data: &[u8],
646 ) {
647 if !header.section_syntax_indicator {
648 warn!(
649 "SectionSyntaxSectionProcessor requires that section_syntax_indicator be set in the section header"
650 );
651 self.ignore_rest = true;
652 return;
653 }
654 if data.len() < SectionCommonHeader::SIZE + TableSyntaxHeader::SIZE {
655 warn!("SectionSyntaxSectionProcessor data {} too short for header {} (TODO: implement buffering)", data.len(), SectionCommonHeader::SIZE + TableSyntaxHeader::SIZE);
656 self.ignore_rest = true;
657 return;
658 }
659 if header.section_length > Self::SECTION_LIMIT {
660 warn!(
661 "SectionSyntaxSectionProcessor section_length={} is too large (limit {})",
662 header.section_length,
663 Self::SECTION_LIMIT
664 );
665 self.ignore_rest = true;
666 return;
667 }
668 self.ignore_rest = false;
669 let table_syntax_header = TableSyntaxHeader::new(&data[SectionCommonHeader::SIZE..]);
670 self.payload_parser
671 .start_syntax_section(ctx, header, &table_syntax_header, data)
672 }
673
674 fn continue_section(&mut self, ctx: &mut Self::Context, data: &[u8]) {
675 if !self.ignore_rest {
676 self.payload_parser.continue_syntax_section(ctx, data)
677 }
678 }
679 fn reset(&mut self) {
680 self.payload_parser.reset()
681 }
682}
683
684#[derive(Debug)]
686pub struct SectionCommonHeader {
687 pub table_id: u8,
689 pub section_syntax_indicator: bool,
691 pub private_indicator: bool,
695 pub section_length: usize,
698}
699
700impl SectionCommonHeader {
701 pub const SIZE: usize = 3;
703
704 pub fn new(buf: &[u8]) -> SectionCommonHeader {
708 assert_eq!(buf.len(), Self::SIZE);
709 SectionCommonHeader {
710 table_id: buf[0],
711 section_syntax_indicator: buf[1] & 0b1000_0000 != 0,
712 private_indicator: buf[1] & 0b0100_0000 != 0,
713 section_length: ((u16::from(buf[1] & 0b0000_1111) << 8) | u16::from(buf[2])) as usize,
714 }
715 }
716}
717
718pub struct SectionPacketConsumer<P>
721where
722 P: SectionProcessor,
723{
724 parser: P,
725}
726
727impl<P, Ctx> SectionPacketConsumer<P>
730where
731 P: SectionProcessor<Context = Ctx>,
732{
733 pub fn new(parser: P) -> SectionPacketConsumer<P> {
736 SectionPacketConsumer { parser }
737 }
738
739 pub fn consume(&mut self, ctx: &mut Ctx, pk: &packet::Packet<'_>) {
742 match pk.payload() {
743 Some(pk_buf) => {
744 if pk.payload_unit_start_indicator() {
745 let pointer = pk_buf[0] as usize;
747 let section_data = &pk_buf[1..];
748 if pointer > 0 {
749 if pointer >= section_data.len() {
750 warn!("PSI pointer beyond end of packet payload");
751 self.parser.reset();
752 return;
753 }
754 let remainder = §ion_data[..pointer];
755 self.parser.continue_section(ctx, remainder);
756 }
759 let next_sect = §ion_data[pointer..];
760 if next_sect.len() < SectionCommonHeader::SIZE {
761 warn!(
762 "TODO: not enough bytes to read section header - implement buffering"
763 );
764 self.parser.reset();
765 return;
766 }
767 let header = SectionCommonHeader::new(&next_sect[..SectionCommonHeader::SIZE]);
768 self.parser.start_section(ctx, &header, next_sect);
769 } else {
770 self.parser.continue_section(ctx, pk_buf);
772 }
773 }
774 None => {
775 warn!("no payload present in PSI packet");
776 }
777 }
778 }
779}
780
781#[cfg(test)]
782mod test {
783 use super::*;
784 use crate::demultiplex;
785 use crate::demultiplex::PacketFilter;
786 use crate::packet::Packet;
787 use hex_literal::*;
788 use std::cell::RefCell;
789 use std::rc::Rc;
790
791 pub struct NullFilterSwitch;
792 impl PacketFilter for NullFilterSwitch {
793 type Ctx = NullDemuxContext;
794 fn consume(&mut self, _ctx: &mut Self::Ctx, _pk: &Packet<'_>) {
795 unimplemented!()
796 }
797 }
798
799 demux_context!(NullDemuxContext, NullFilterSwitch);
800 impl NullDemuxContext {
801 fn do_construct(&mut self, _req: demultiplex::FilterRequest<'_, '_>) -> NullFilterSwitch {
802 unimplemented!()
803 }
804 }
805
806 struct NullSectionProcessor;
807 impl SectionProcessor for NullSectionProcessor {
808 type Context = NullDemuxContext;
809 fn start_section<'a>(
810 &mut self,
811 _ctx: &mut Self::Context,
812 _header: &SectionCommonHeader,
813 _section_data: &'a [u8],
814 ) {
815 }
816 fn continue_section<'a>(&mut self, _ctx: &mut Self::Context, _section_data: &'a [u8]) {}
817 fn reset(&mut self) {}
818 }
819
820 #[test]
821 fn continuation_outside_section() {
822 let mut buf = [0u8; 188];
823 buf[0] = 0x47;
824 buf[3] |= 0b00010000; let pk = Packet::new(&buf[..]);
826 let mut psi_buf = SectionPacketConsumer::new(NullSectionProcessor);
827 let mut ctx = NullDemuxContext::new();
828 psi_buf.consume(&mut ctx, &pk);
829 }
830
831 #[test]
832 fn small_section() {
833 let mut buf = [0u8; 188];
834 buf[0] = 0x47;
835 buf[1] |= 0b01000000; buf[3] |= 0b00010000; buf[7] = 3; let pk = Packet::new(&buf[..]);
839 let mut psi_buf = SectionPacketConsumer::new(NullSectionProcessor);
840 let mut ctx = NullDemuxContext::new();
841 psi_buf.consume(&mut ctx, &pk);
842 }
843
844 struct MockWholeSectParse {
845 state: Rc<RefCell<bool>>,
846 }
847 impl WholeSectionSyntaxPayloadParser for MockWholeSectParse {
848 type Context = ();
849 fn section<'a>(
850 &mut self,
851 _: &mut Self::Context,
852 _header: &SectionCommonHeader,
853 _table_syntax_header: &TableSyntaxHeader<'_>,
854 _data: &[u8],
855 ) {
856 *self.state.borrow_mut() = true;
857 }
858 }
859
860 #[test]
861 fn section_spanning_packets() {
862 let state = Rc::new(RefCell::new(false));
864 let mut p = BufferSectionSyntaxParser::new(CrcCheckWholeSectionSyntaxPayloadParser::new(
865 MockWholeSectParse {
866 state: state.clone(),
867 },
868 ));
869 let ctx = &mut ();
870 {
871 let sect = hex!(
872 "
873 42f13040 84e90000 233aff44 40ff8026
874 480d1900 0a424243 2054574f 20484473
875 0c66702e 6262632e 636f2e75 6b5f0400
876 00233a7e 01f744c4 ff802148 09190006
877 49545620 4844730b 7777772e 6974762e
878 636f6d5f 04000023 3a7e01f7 4500ff80
879 2c480f19 000c4368 616e6e65 6c203420
880 48447310 7777772e 6368616e 6e656c34
881 2e636f6d 5f040000 233a7e01 f74484ff
882 8026480d 19000a42 4243204f 4e452048
883 44730c66 702e6262 632e636f 2e756b5f
884 04000023 3a7e01"
885 );
886
887 let common_header = SectionCommonHeader::new(§[..SectionCommonHeader::SIZE]);
888 let table_header = TableSyntaxHeader::new(§[SectionCommonHeader::SIZE..]);
889 p.start_syntax_section(ctx, &common_header, &table_header, §[..]);
890 }
891 {
892 let sect = hex!(
893 "
894 f746c0ff 8023480a 19000743 42424320
895 4844730c 66702e62 62632e63 6f2e756b
896 5f040000 233a7e01 f74f80ff 801e480a
897 16000746 696c6d34 2b317310 7777772e
898 6368616e 6e656c34 2e636f6d 4540ff80
899 27480f19 000c4368 616e6e65 6c203520
900 4844730b 7777772e 66697665 2e74765f
901 04000023 3a7e01f7 f28b26c4 ffffffff
902 ffffffff ffffffff ffffffff ffffffff
903 ffffffff ffffffff ffffffff ffffffff
904 ffffffff ffffffff ffffffff ffffffff
905 ffffffff ffffffff"
906 );
907
908 p.continue_syntax_section(ctx, §[..]);
909 }
910
911 assert!(*state.borrow());
912 }
913
914 #[test]
915 fn table_syntax() {
916 let sect = hex!("4084e90000");
917 let header = TableSyntaxHeader::new(§);
918 assert_eq!(header.current_next_indicator(), CurrentNext::Current);
919 assert_eq!(header.id(), 16516);
920 assert_eq!(header.section_number(), 0);
921 assert_eq!(header.last_section_number(), 0);
922 assert_eq!(header.version(), 20);
923 assert!(!format!("{:?}", header).is_empty());
925 }
926
927 #[test]
928 fn table_next_syntax() {
929 let sect = hex!("4084e80000");
930 let header = TableSyntaxHeader::new(§);
931 assert_eq!(header.current_next_indicator(), CurrentNext::Next);
932 }
933
934 #[test]
935 fn dedup_section() {
936 struct CallCounts {
937 start: usize,
938 cont: usize,
939 reset: usize,
940 }
941 struct Mock {
942 inner: Rc<RefCell<CallCounts>>,
943 }
944 let counts = Rc::new(RefCell::new(CallCounts {
945 start: 0,
946 cont: 0,
947 reset: 0,
948 }));
949 impl SectionSyntaxPayloadParser for Mock {
950 type Context = ();
951
952 fn start_syntax_section<'a>(
953 &mut self,
954 _ctx: &mut Self::Context,
955 _header: &SectionCommonHeader,
956 _table_syntax_header: &TableSyntaxHeader<'a>,
957 _data: &'a [u8],
958 ) {
959 self.inner.borrow_mut().start += 1;
960 }
961
962 fn continue_syntax_section<'a>(&mut self, _ctx: &mut Self::Context, _data: &'a [u8]) {
963 self.inner.borrow_mut().cont += 1;
964 }
965
966 fn reset(&mut self) {
967 self.inner.borrow_mut().reset += 1;
968 }
969 }
970 let mut dedup = DedupSectionSyntaxPayloadParser::new(Mock {
971 inner: counts.clone(),
972 });
973
974 let sect = hex!("42f130 4084e90000");
975
976 let common_header = SectionCommonHeader::new(§[..SectionCommonHeader::SIZE]);
977 let table_header = TableSyntaxHeader::new(§[SectionCommonHeader::SIZE..]);
978 assert_eq!(table_header.version(), 20);
979
980 let ctx = &mut ();
981 dedup.start_syntax_section(ctx, &common_header, &table_header, &[]);
982 dedup.continue_syntax_section(ctx, &[]);
983 assert_eq!(counts.borrow().start, 1);
984 assert_eq!(counts.borrow().cont, 1);
985 dedup.start_syntax_section(ctx, &common_header, &table_header, &[]);
987 dedup.continue_syntax_section(ctx, &[]);
988 assert_eq!(counts.borrow().start, 1);
990 assert_eq!(counts.borrow().cont, 1);
991
992 let sect = hex!("42f131 4084ea0000");
994
995 let common_header = SectionCommonHeader::new(§[..SectionCommonHeader::SIZE]);
996 let table_header = TableSyntaxHeader::new(§[SectionCommonHeader::SIZE..]);
997 assert_eq!(table_header.version(), 21);
998
999 dedup.start_syntax_section(ctx, &common_header, &table_header, &[]);
1000 dedup.continue_syntax_section(ctx, &[]);
1001 assert_eq!(counts.borrow().start, 2);
1003 assert_eq!(counts.borrow().cont, 2);
1004
1005 assert_eq!(counts.borrow().reset, 0);
1009 dedup.reset();
1010 assert_eq!(counts.borrow().reset, 1);
1011
1012 dedup.start_syntax_section(ctx, &common_header, &table_header, &[]);
1014 dedup.continue_syntax_section(ctx, &[]);
1015 assert_eq!(counts.borrow().start, 3);
1016 assert_eq!(counts.borrow().cont, 3);
1017 }
1018
1019 #[test]
1020 fn compact_section_syntax() {
1021 struct CallCounts {
1022 start: u64,
1023 reset: u64,
1024 continue_section: u64,
1025 }
1026 struct Mock {
1027 inner: Rc<RefCell<CallCounts>>,
1028 }
1029 impl CompactSyntaxPayloadParser for Mock {
1030 type Context = ();
1031
1032 fn start_compact_section<'a>(
1033 &mut self,
1034 _ctx: &mut Self::Context,
1035 _header: &SectionCommonHeader,
1036 _data: &'a [u8],
1037 ) {
1038 self.inner.borrow_mut().start += 1;
1039 }
1040
1041 fn continue_compact_section<'a>(&mut self, _ctx: &mut Self::Context, _data: &'a [u8]) {
1042 self.inner.borrow_mut().continue_section += 1;
1043 }
1044
1045 fn reset(&mut self) {
1046 self.inner.borrow_mut().reset += 1;
1047 }
1048 }
1049 let counts = Rc::new(RefCell::new(CallCounts {
1050 start: 0,
1051 reset: 0,
1052 continue_section: 0,
1053 }));
1054 let mut proc = CompactSyntaxSectionProcessor::new(Mock {
1055 inner: counts.clone(),
1056 });
1057
1058 let ctx = &mut ();
1059
1060 let sect = hex!("42f131");
1063 let common_header = SectionCommonHeader::new(§[..SectionCommonHeader::SIZE]);
1064 assert!(common_header.section_syntax_indicator);
1065 proc.start_section(ctx, &common_header, §);
1066 assert_eq!(0, counts.borrow().start);
1067 proc.continue_section(ctx, &[]);
1068 assert_eq!(0, counts.borrow().continue_section);
1069
1070 let sect = hex!("427131");
1071 let common_header = SectionCommonHeader::new(§[..SectionCommonHeader::SIZE]);
1072 assert!(!common_header.section_syntax_indicator);
1073 proc.start_section(ctx, &common_header, §[..2]);
1076 assert_eq!(0, counts.borrow().start);
1077 proc.continue_section(ctx, &[]);
1078 assert_eq!(0, counts.borrow().continue_section);
1079
1080 let header = hex!("4273fe");
1082 let mut sect = vec![];
1083 sect.extend_from_slice(&header);
1084 sect.resize(header.len() + 1022, 0); let common_header = SectionCommonHeader::new(§[..SectionCommonHeader::SIZE]);
1086 assert!(!common_header.section_syntax_indicator);
1087 proc.start_section(ctx, &common_header, §);
1090 assert_eq!(0, counts.borrow().start);
1091 proc.continue_section(ctx, &[]);
1092 assert_eq!(0, counts.borrow().continue_section);
1093
1094 let sect = hex!("427000");
1096 let common_header = SectionCommonHeader::new(§[..SectionCommonHeader::SIZE]);
1097 assert!(!common_header.section_syntax_indicator);
1098 proc.start_section(ctx, &common_header, §);
1099 assert_eq!(1, counts.borrow().start);
1100
1101 proc.continue_section(ctx, &[]);
1102 assert_eq!(1, counts.borrow().continue_section);
1103
1104 proc.reset();
1105 assert_eq!(1, counts.borrow().reset);
1106 }
1107
1108 #[test]
1109 fn buffer_compact() {
1110 const SECT: [u8; 7] = hex!("427003 01020304");
1111 struct Mock {
1112 section_count: usize,
1113 }
1114 impl WholeCompactSyntaxPayloadParser for Mock {
1115 type Context = ();
1116
1117 fn section<'a>(
1118 &mut self,
1119 _: &mut Self::Context,
1120 header: &SectionCommonHeader,
1121 data: &'a [u8],
1122 ) {
1123 assert_eq!(0x42, header.table_id);
1124 assert_eq!(data, &SECT[0..SECT.len() - 1]);
1127 self.section_count += 1;
1128 }
1129 }
1130 let mock = Mock { section_count: 0 };
1131 let mut parser = BufferCompactSyntaxParser::new(mock);
1132 let ctx = &mut ();
1133
1134 let common_header = SectionCommonHeader::new(&SECT[..SectionCommonHeader::SIZE]);
1135
1136 parser.start_compact_section(ctx, &common_header, &SECT[..SECT.len() - 3]);
1139 parser.reset();
1140 assert_eq!(0, parser.parser.section_count);
1141
1142 parser.start_compact_section(ctx, &common_header, &SECT[..SECT.len() - 3]);
1143 parser.continue_compact_section(ctx, &SECT[SECT.len() - 3..SECT.len() - 2]);
1144 parser.continue_compact_section(ctx, &SECT[SECT.len() - 2..]);
1147 assert_eq!(1, parser.parser.section_count);
1148
1149 parser.continue_compact_section(ctx, &SECT[SECT.len() - 2..]);
1152 assert_eq!(1, parser.parser.section_count);
1153 }
1154
1155 #[test]
1156 fn section_syntax_section_processor() {
1157 struct Mock {
1158 start_syntax_section_count: usize,
1159 continue_syntax_section_count: usize,
1160 reset_count: usize,
1161 }
1162 impl SectionSyntaxPayloadParser for Mock {
1163 type Context = ();
1164
1165 fn start_syntax_section<'a>(
1166 &mut self,
1167 _ctx: &mut Self::Context,
1168 _header: &SectionCommonHeader,
1169 _table_syntax_header: &TableSyntaxHeader<'a>,
1170 _data: &'a [u8],
1171 ) {
1172 self.start_syntax_section_count += 1;
1173 }
1174
1175 fn continue_syntax_section(&mut self, _ctx: &mut Self::Context, _data: &[u8]) {
1176 self.continue_syntax_section_count += 1;
1177 }
1178
1179 fn reset(&mut self) {
1180 self.reset_count += 1;
1181 }
1182 }
1183 let sect = hex!("42f130 4084e90000");
1184
1185 {
1186 let mock = Mock {
1187 start_syntax_section_count: 0,
1188 continue_syntax_section_count: 0,
1189 reset_count: 0,
1190 };
1191 let mut proc = SectionSyntaxSectionProcessor::new(mock);
1192 let mut not_section_syntax = sect.to_vec();
1194 not_section_syntax[1] &= 0b0111_1111;
1196 let ctx = &mut ();
1197 let common_header =
1198 SectionCommonHeader::new(¬_section_syntax[..SectionCommonHeader::SIZE]);
1199 assert!(!common_header.section_syntax_indicator);
1200 proc.start_section(ctx, &common_header, ¬_section_syntax);
1201 assert_eq!(proc.payload_parser.start_syntax_section_count, 0);
1202 }
1203
1204 {
1205 let mock = Mock {
1206 start_syntax_section_count: 0,
1207 continue_syntax_section_count: 0,
1208 reset_count: 0,
1209 };
1210 let mut proc = SectionSyntaxSectionProcessor::new(mock);
1211 let too_short = §[0..7];
1214 let ctx = &mut ();
1215 let common_header = SectionCommonHeader::new(&too_short[..SectionCommonHeader::SIZE]);
1216 assert!(common_header.section_syntax_indicator);
1217 proc.start_section(ctx, &common_header, &too_short);
1218 assert_eq!(proc.payload_parser.start_syntax_section_count, 0);
1219 }
1220
1221 {
1222 let mock = Mock {
1223 start_syntax_section_count: 0,
1224 continue_syntax_section_count: 0,
1225 reset_count: 0,
1226 };
1227 let mut proc = SectionSyntaxSectionProcessor::new(mock);
1228 let mut section_length_too_large = sect.to_vec();
1229 let bad_section_length: u16 = 1021 + 1;
1230 assert_eq!(bad_section_length >> 8 & 0b1111_0000, 0);
1231 section_length_too_large[1] =
1232 section_length_too_large[1] & 0b1111_0000 | (bad_section_length >> 8) as u8;
1233 section_length_too_large[2] = (bad_section_length & 0xff) as u8;
1234 let ctx = &mut ();
1235 let common_header =
1236 SectionCommonHeader::new(§ion_length_too_large[..SectionCommonHeader::SIZE]);
1237 assert!(common_header.section_syntax_indicator);
1238 proc.start_section(ctx, &common_header, §ion_length_too_large);
1239 assert_eq!(proc.payload_parser.start_syntax_section_count, 0);
1240 }
1241 }
1242
1243 #[test]
1244 fn should_reject_section_too_small_for_crc() {
1245 let sect = hex!(
1246 "
1247 42f13040 84e90000 233aff44 40ff8026
1248 480d1900 0a424243 2054574f 20484473
1249 0c66702e 6262632e 636f2e75 6b5f0400
1250 00233a7e 01f744c4 ff802148 09190006
1251 49545620 4844730b 7777772e 6974762e
1252 636f6d5f 04000023 3a7e01f7 4500ff80
1253 2c480f19 000c4368 616e6e65 6c203420
1254 48447310 7777772e 6368616e 6e656c34
1255 2e636f6d 5f040000 233a7e01 f74484ff
1256 8026480d 19000a42 4243204f 4e452048
1257 44730c66 702e6262 632e636f 2e756b5f
1258 04000023 3a7e01
1259 f746c0ff 8023480a 19000743 42424320
1260 4844730c 66702e62 62632e63 6f2e756b
1261 5f040000 233a7e01 f74f80ff 801e480a
1262 16000746 696c6d34 2b317310 7777772e
1263 6368616e 6e656c34 2e636f6d 4540ff80
1264 27480f19 000c4368 616e6e65 6c203520
1265 4844730b 7777772e 66697665 2e74765f
1266 04000023 3a7e01f7 f28b26c4 ffffffff
1267 ffffffff ffffffff ffffffff ffffffff
1268 ffffffff ffffffff ffffffff ffffffff
1269 ffffffff ffffffff ffffffff ffffffff
1270 ffffffff ffffffff"
1271 );
1272
1273 let mut sect_length_too_small = sect.to_vec();
1274 let bad_section_length: u16 = 11;
1275 assert_eq!(bad_section_length >> 8 & 0b1111_0000, 0);
1276 sect_length_too_small[1] =
1277 sect_length_too_small[1] & 0b1111_0000 | (bad_section_length >> 8) as u8;
1278 sect_length_too_small[2] = (bad_section_length & 0xff) as u8;
1279 sect_length_too_small.truncate(bad_section_length as usize);
1280 let state = Rc::new(RefCell::new(false));
1281 let mut crc_check = CrcCheckWholeSectionSyntaxPayloadParser::new(MockWholeSectParse {
1282 state: state.clone(),
1283 });
1284 let common_header =
1285 SectionCommonHeader::new(§_length_too_small[..SectionCommonHeader::SIZE]);
1286 let table_header =
1287 TableSyntaxHeader::new(§_length_too_small[SectionCommonHeader::SIZE..]);
1288 let ctx = &mut ();
1289 crc_check.section(ctx, &common_header, &table_header, §_length_too_small);
1290 assert!(!*state.borrow());
1291 }
1292}