mirror of
https://github.com/freemkv/libfreemkv.git
synced 2026-10-07 18:13:10 +00:00
labels: one control-character filter for disc-authored titles
bdmt title and description text kept raw control characters from CDATA and plain bodies, so a disc could put a terminal escape sequence into a shown title or a file name. It now goes through the same filter as the Blu-ray di:name title.
This commit is contained in:
+3
-5
@@ -511,11 +511,9 @@ impl Disc {
|
||||
if let Some(end) = xml[s..].find("</di:name>") {
|
||||
// Disc-authored text reaches terminals and file names:
|
||||
// control characters (decoded from `` too) are dropped.
|
||||
let title: String = xml_text_decode(xml[s..s + end].trim())
|
||||
.chars()
|
||||
.filter(|c| !c.is_control())
|
||||
.collect();
|
||||
let title = title.trim().to_string();
|
||||
let title = crate::labels::display_text(&xml_text_decode(
|
||||
xml[s..s + end].trim(),
|
||||
));
|
||||
if !title.is_empty() && !crate::labels::is_placeholder_title(&title)
|
||||
{
|
||||
return Some(title);
|
||||
|
||||
+21
-2
@@ -182,10 +182,10 @@ fn field_text(raw: &str) -> Option<String> {
|
||||
.strip_prefix("<![CDATA[")
|
||||
.and_then(|r| r.strip_suffix("]]>"))
|
||||
{
|
||||
Some(inner) if !inner.contains("]]>") => inner.trim().to_string(),
|
||||
Some(inner) if !inner.contains("]]>") => display_text(inner),
|
||||
Some(_) => return None,
|
||||
None if looks_like_xml(raw) => return None,
|
||||
None => decode_entities(raw),
|
||||
None => display_text(&decode_entities(raw)),
|
||||
};
|
||||
if out.is_empty() || looks_like_xml(&out) {
|
||||
return None;
|
||||
@@ -233,6 +233,13 @@ fn decode_entities(s: &str) -> String {
|
||||
out
|
||||
}
|
||||
|
||||
/// Disc-authored text as shown and put in file names: control characters (an escape
|
||||
/// sequence, a raw newline) dropped, then trimmed.
|
||||
pub(crate) fn display_text(s: &str) -> String {
|
||||
let kept: String = s.chars().filter(|c| !c.is_control()).collect();
|
||||
kept.trim().to_string()
|
||||
}
|
||||
|
||||
/// True for the generic `Blu-ray` some discs (Warner's non-English bdmt files) put where
|
||||
/// the title belongs: not a title, so callers skip to the next candidate.
|
||||
pub(crate) fn is_placeholder_title(title: &str) -> bool {
|
||||
@@ -322,6 +329,18 @@ mod tests {
|
||||
assert!(d.expect("desc").len() <= MAX_BDMT_TEXT);
|
||||
}
|
||||
|
||||
// A title or description, CDATA or plain, keeps no control character (a terminal escape
|
||||
// sequence, a raw newline), as the Blu-ray di:name path does not.
|
||||
#[test]
|
||||
fn disc_text_drops_control_characters() {
|
||||
let xml = "<d><di:name><![CDATA[Movie\x1b]0;pwned\x07]]></di:name>\
|
||||
<di:description>Line\x1b[2Jone\ntwo</di:description></d>";
|
||||
let (t, d, _) = parse_bdmt_xml(xml).expect("parse");
|
||||
assert_eq!(t, "Movie]0;pwned");
|
||||
assert_eq!(d.as_deref(), Some("Line[2Jonetwo"));
|
||||
assert_eq!(display_text(" \x1bA\tB "), "AB");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cap_text_cuts_on_a_char_boundary() {
|
||||
let s = format!("aa{}", "\u{4e16}".repeat(400));
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ use crate::udf::UdfFs;
|
||||
// disc-level metadata via `labels::DiscMetadata`. The module itself
|
||||
// stays private — analyze() drives the parse path.
|
||||
pub use bdmt::DiscMetadata;
|
||||
pub(crate) use bdmt::is_placeholder_title;
|
||||
pub(crate) use bdmt::{display_text, is_placeholder_title};
|
||||
|
||||
// Re-exported via crate::disc — the public API surfaces these next to
|
||||
// AudioStream/SubtitleStream so callers can map purpose/qualifier to display
|
||||
|
||||
Reference in New Issue
Block a user