mirror of
https://github.com/freemkv/libfreemkv.git
synced 2026-10-07 18:13:10 +00:00
bdnav: warn on dropped MPLS, dedupe be_u16, pin SET taint test
This commit is contained in:
+2
-3
@@ -3,6 +3,8 @@
|
||||
//! documented binary format, never executed: every field is bounds-checked and
|
||||
//! any malformed input yields `None` (the nav resolver then abstains).
|
||||
|
||||
use super::be_u16;
|
||||
|
||||
/// One playback/title object in `index.bdmv`.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum PlaybackObj {
|
||||
@@ -29,9 +31,6 @@ const OBJ_LEN: usize = 12;
|
||||
/// Sanity cap on the title count (real discs have well under this).
|
||||
const MAX_TITLES: usize = 4096;
|
||||
|
||||
fn be_u16(d: &[u8], o: usize) -> Option<u16> {
|
||||
Some(u16::from_be_bytes([*d.get(o)?, *d.get(o + 1)?]))
|
||||
}
|
||||
fn be_u32(d: &[u8], o: usize) -> Option<u32> {
|
||||
Some(u32::from_be_bytes([
|
||||
*d.get(o)?,
|
||||
|
||||
+2
-4
@@ -7,6 +7,8 @@
|
||||
//! byte 50. Each object is `flags`(1) + reserved(1) + `num_cmds`(u16) followed
|
||||
//! by `num_cmds` 12-byte navigation commands.
|
||||
|
||||
use super::be_u16;
|
||||
|
||||
// One decoded 12-byte navigation command.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) struct Cmd {
|
||||
@@ -36,10 +38,6 @@ const CMD_LEN: usize = 12;
|
||||
/// separate cap would be dead code.
|
||||
const MAX_OBJECTS: usize = 4096;
|
||||
|
||||
fn be_u16(d: &[u8], o: usize) -> Option<u16> {
|
||||
Some(u16::from_be_bytes([*d.get(o)?, *d.get(o + 1)?]))
|
||||
}
|
||||
|
||||
/// Decode one 12-byte command. Caller guarantees `b.len() == 12`.
|
||||
fn decode_cmd(b: &[u8]) -> Cmd {
|
||||
let (b0, b1, b2, b3) = (b[0], b[1], b[2], b[3]);
|
||||
|
||||
@@ -14,6 +14,10 @@ pub(crate) mod vm;
|
||||
use crate::sector::SectorSource;
|
||||
use crate::udf::UdfFs;
|
||||
|
||||
pub(super) fn be_u16(d: &[u8], o: usize) -> Option<u16> {
|
||||
Some(u16::from_be_bytes([*d.get(o)?, *d.get(o + 1)?]))
|
||||
}
|
||||
|
||||
// Resolve the playlist id First-Play navigation plays as the feature, among ids the caller
|
||||
// marks as feature candidates (`is_feature_candidate`). Returns `None` for BD-J discs,
|
||||
// malformed nav data, or non-convergence.
|
||||
|
||||
@@ -674,6 +674,17 @@ mod tests {
|
||||
assert_eq!(resolve(&index, &mobjs, &|_| true), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_from_rnd_source_taints_destination() {
|
||||
// GPR0 = RND; GPR1 (clean) += GPR0 (register src); PlayPL GPR1 must abstain.
|
||||
let rnd = set_imm(0x08, 0, 10);
|
||||
let add = cmd((2 << 5) | (2 << 3), 0x00, 0, 0x03, 1, 0);
|
||||
let d = build(&[&[rnd, add, play_pl_reg(1), play_pl(1)]]);
|
||||
let mobjs = mobj::parse(&d).unwrap();
|
||||
let index = idx(PlaybackObj::Hdmv { id_ref: 0 }, vec![]);
|
||||
assert_eq!(resolve(&index, &mobjs, &|_| true), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn playpl_operand_over_16_bits_is_not_a_playlist_id() {
|
||||
// 0x1_0001 must not alias playlist 1; the VM falls through to 800.
|
||||
|
||||
+22
-7
@@ -62,8 +62,18 @@ impl Disc {
|
||||
filename: &str,
|
||||
data: &[u8],
|
||||
) -> Result<Option<DiscTitle>> {
|
||||
let Ok(parsed) = mpls::parse(data) else {
|
||||
return Ok(None);
|
||||
let parsed = match mpls::parse(data) {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
// Real code, matching the CLPI path: a malformed playlist is
|
||||
// dropped, but never silently.
|
||||
tracing::warn!(
|
||||
target: "freemkv::disc",
|
||||
playlist = ?filename,
|
||||
"E{}", e.code()
|
||||
);
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
|
||||
// Calculate duration from play items
|
||||
@@ -665,11 +675,16 @@ mod tests {
|
||||
let mut disc = MemDisc::new();
|
||||
let udf = make_min_fs(&mut disc);
|
||||
let junk = vec![0u8; 100];
|
||||
assert!(
|
||||
Disc::parse_playlist(&mut disc, &udf, "00001.mpls", &junk)
|
||||
.expect("scan")
|
||||
.is_none()
|
||||
);
|
||||
let (t, events) = crate::testlog::capture(|| {
|
||||
Disc::parse_playlist(&mut disc, &udf, "00001.mpls", &junk).expect("scan")
|
||||
});
|
||||
assert!(t.is_none());
|
||||
let line = events
|
||||
.iter()
|
||||
.find(|e| e.target == "freemkv::disc")
|
||||
.unwrap_or_else(|| panic!("a dropped playlist must be logged; got {events:?}"));
|
||||
assert_eq!(line.level, tracing::Level::WARN);
|
||||
assert_eq!(line.message(), format!("E{}", crate::error::E_MPLS_PARSE));
|
||||
}
|
||||
|
||||
/// Build the minimal fixture: an empty `BDMV/` directory (no STREAM,
|
||||
|
||||
Reference in New Issue
Block a user