Reject a short READ CAPACITY reply, and count only entry marks as chapters
Two cases of the same shape: one policy implemented twice, with only one copy hardened. Disc::read_capacity decoded buf[0..4] from READ CAPACITY (10) without checking that the transport actually delivered four bytes, even though its comment claims to mirror decode_read_capacity — which has exactly that check, and documents why. A drive answering GOOD with an empty data phase leaves the buffer zeroed, so last_lba decodes to 0 and the probe reports a one-sector disc instead of an error. It now calls the shared decoder rather than re-deriving it. collect_chapter_summary filtered chapters on mark_type <= 1, counting the reserved type 0. PlaylistMark's own doc says filters must test == 1, and disc/bluray.rs did; the labels path did not, inflating the public chapter_count and letting a playlist whose only marks are reserved pass the chapter_count == 0 skip. Both sites now share PlaylistMark::is_chapter_mark so the copies cannot drift again. Both fixes were confirmed red before green.
This commit is contained in:
+32
@@ -39,6 +39,18 @@ pub(crate) struct PlaylistMark {
|
||||
pub timestamp: u32,
|
||||
}
|
||||
|
||||
impl PlaylistMark {
|
||||
/// Is this mark a chapter entry point?
|
||||
///
|
||||
/// Only `mark_type == 1` counts. Type 0 is reserved and type 2 is a link
|
||||
/// point, and neither is a chapter. Every chapter filter in the crate goes
|
||||
/// through here: two hand-rolled copies had already drifted, one testing
|
||||
/// `<= 1` and silently counting reserved marks as chapters.
|
||||
pub(crate) fn is_chapter_mark(&self) -> bool {
|
||||
self.mark_type == 1
|
||||
}
|
||||
}
|
||||
|
||||
/// A play item — one clip reference with in/out times.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct PlayItem {
|
||||
@@ -1698,4 +1710,24 @@ mod tests {
|
||||
assert_eq!(entry.coding_type, 0x90);
|
||||
assert_eq!(entry.language, "");
|
||||
}
|
||||
|
||||
/// Type 0 is reserved and type 2 is a link point; neither is a chapter.
|
||||
/// `labels::collect_chapter_summary` used to filter on `mark_type <= 1`,
|
||||
/// which counted reserved marks and inflated the public `chapter_count`
|
||||
/// (and let a playlist whose only marks are reserved pass the
|
||||
/// `chapter_count == 0` skip). Both call sites now share this predicate.
|
||||
#[test]
|
||||
fn only_entry_marks_count_as_chapters() {
|
||||
let mk = |mark_type| PlaylistMark {
|
||||
mark_type,
|
||||
play_item_ref: 0,
|
||||
timestamp: 0,
|
||||
};
|
||||
assert!(
|
||||
!mk(0).is_chapter_mark(),
|
||||
"type 0 is reserved, not a chapter"
|
||||
);
|
||||
assert!(mk(1).is_chapter_mark());
|
||||
assert!(!mk(2).is_chapter_mark(), "type 2 is a link point");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user