fix(xfa): read and validate the first alternative in typed_date (#6120)

This commit is contained in:
jonathanwxh-cell authored and GitHub committed 2026-11-09 08:42:54 +08:00
1 parent 3b731f9458
commit 9b2c8d6026
1 file changed
+48 -2
+48 -2
View File
@@ -39,14 +39,15 @@ pub fn typed_date(tpl: &Template, som: &str, text: &str) -> Option<String> {
}
let picture = f.picture.as_deref()?;
let reads = |pattern: &str| pattern_to_iso(text, pattern).filter(|iso| iso_to_pattern(iso, pattern).eq_ignore_ascii_case(text.trim()));
let first = date_pattern(Some(picture));
let mut alts = alternatives(picture).into_iter();
let first = alts.next().filter(|a| is_date_clause(a) && date_letters(a).is_some()).map(|a| date_pattern(Some(a)))?;
if reads(&first).is_some() {
return None;
}
// The first later date pattern that reads the text and gives a date the first pattern keeps:
// written in the first, it must read back as the same date (a two-digit year can't hold 1901
// or 1203), else the next pattern is tried.
alternatives(picture).into_iter().skip(1).filter(|a| is_date_clause(a)).filter_map(date_letters).find_map(|p| {
alts.filter(|a| is_date_clause(a)).filter_map(date_letters).find_map(|p| {
let iso = reads(&p)?;
let shown = iso_to_pattern(&iso, &first);
(pattern_to_iso(&shown, &first).as_deref() == Some(iso.as_str())).then_some(shown)
@@ -63,3 +64,48 @@ fn is_date_clause(clause: &str) -> bool {
None => true,
}
}
#[cfg(test)]
mod tests {
use super::*;
fn tpl_with_pictures(fields: &[(&str, &str)]) -> Template {
let mut body = String::new();
for (name, pic) in fields {
body.push_str(&format!(
"<field name=\"{name}\" w=\"2in\" h=\"0.3in\"><ui><dateTimeEdit/><picture>{pic}</picture></ui><value><date/></value></field>"
));
}
let xml = format!(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
<xdp:xdp xmlns:xdp=\"http://ns.adobe.com/xdp/\">\
<template xmlns=\"http://www.xfa.org/schema/xfa-template/3.3/\">\
<subform name=\"form\" layout=\"tb\">\
<pageSet><pageArea name=\"front\"><contentArea x=\"0.5in\" y=\"0.5in\" w=\"7.5in\" h=\"10in\"/><medium short=\"8.5in\" long=\"11in\"/></pageArea></pageSet>\
{body}\
</subform></template></xdp:xdp>"
);
crate::parse(&xml).expect("valid template").0
}
#[test]
fn typed_date_reads_bare_first_alternative_instead_of_whole_picture_or_later_braces() {
let tpl = tpl_with_pictures(&[("bare", "YYYYMMDD|YYMMDD"), ("mixed", "YYYYMMDD|date{YYMMDD}")]);
assert_eq!(typed_date(&tpl, "form[0].bare[0]", "261018").as_deref(), Some("20261018"));
assert_eq!(typed_date(&tpl, "form[0].bare[0]", "20261018"), None);
assert_eq!(typed_date(&tpl, "form[0].mixed[0]", "261018").as_deref(), Some("20261018"));
assert_eq!(typed_date(&tpl, "form[0].mixed[0]", "20261018"), None);
}
#[test]
fn typed_date_rejects_non_date_or_unreadable_first_alternative() {
let tpl = tpl_with_pictures(&[
("text_first", "text{YYYYMMDD}|date{YYMMDD}"),
("num_first", "num{99999999}|date{YYMMDD}"),
("datetime_first", "date{YYYY-MM-DD HH:MM}|date{YYMMDD}"),
]);
assert_eq!(typed_date(&tpl, "form[0].text_first[0]", "261018"), None);
assert_eq!(typed_date(&tpl, "form[0].num_first[0]", "261018"), None);
assert_eq!(typed_date(&tpl, "form[0].datetime_first[0]", "261018"), None);
}
}