mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-10 13:35:21 +00:00
M6: the engine checks that the XFA data layer and forms spell state names alike
pdfcraft-xfa keeps its own copy of pdfcraft_forms::name_text (it can't depend on forms), and a radio group's value only finds its button while the two agree. xfa_and_forms_spell_names_alike compares them, and checks that forms' name_bytes reads the copy's spelling back, for UTF-8, '#', Shift-JIS and stray bytes. With the copy writing lowercase hex it fails at the Shift-JIS case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pq7HyCfwzyRXj4VfQAVVdv
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
0e70564cec
commit
2b74366c64
@@ -6146,6 +6146,17 @@ fn a_static_xfa_radio_group_with_numeric_items_keeps_the_picked_button() {
|
||||
}
|
||||
}
|
||||
|
||||
/// The XFA data layer keeps its own copy of the forms crate's name spelling (it can't depend on
|
||||
/// forms), and a radio group's value only finds its button while the two agree: UTF-8 as
|
||||
/// itself, `#` and bytes that aren't UTF-8 as `#XX`.
|
||||
#[test]
|
||||
fn xfa_and_forms_spell_names_alike() {
|
||||
for bytes in [&b"Yes"[..], b"", b"a b", b"A#1", "はい".as_bytes(), b"\x82\xcd\x82\xa2", b"\xff#\x00", b"\x7f\x20~"] {
|
||||
assert_eq!(pdfcraft_xfa::data::name_text(bytes), pdfcraft_forms::name_text(bytes), "{bytes:?}");
|
||||
assert_eq!(pdfcraft_forms::name_bytes(&pdfcraft_xfa::data::name_text(bytes)), bytes, "{bytes:?}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Taking the XFA out of a radio group whose buttons carry `/PCOn` as well as `/Opt` (the item
|
||||
/// saving writes ahead of the `/Opt` entry) notes no lost data when the data holds that item:
|
||||
/// one equal to the on state, and one equal to neither the state nor the `/Opt` entry.
|
||||
|
||||
@@ -36,9 +36,7 @@ pub use import::{DataImport, ImportNode, export_data, import_data, parse_data_fi
|
||||
pub use passwords::{clear_password_values, has_password_values};
|
||||
pub(crate) use path::template_field;
|
||||
pub use path::{data_path, parse_datasets, som_to_path};
|
||||
#[cfg(test)]
|
||||
pub(crate) use values::name_text;
|
||||
pub use values::{FieldData, FieldDatum, is_on, radio_dataset_value, radio_state_for_item, read_values, read_values_with};
|
||||
pub use values::{FieldData, FieldDatum, is_on, name_text, radio_dataset_value, radio_state_for_item, read_values, read_values_with};
|
||||
#[cfg(test)]
|
||||
pub(crate) use write::ENSURED;
|
||||
pub use write::{
|
||||
|
||||
@@ -76,7 +76,8 @@ fn radio_widgets(doc: &Document, f: &FieldDatum) -> Vec<(Option<String>, Option<
|
||||
/// written `#XX`, as in PDF name syntax. This is `pdfcraft_forms::name_text`, which this crate
|
||||
/// can't depend on; the value saving gets is read through it, and the state opening returns is
|
||||
/// written back through its inverse, `pdfcraft_forms::name_bytes`.
|
||||
pub(crate) fn name_text(bytes: &[u8]) -> String {
|
||||
/// The engine checks that the two spell names alike (`xfa_and_forms_spell_names_alike`).
|
||||
pub fn name_text(bytes: &[u8]) -> String {
|
||||
let escape = |b: u8| format!("#{b:02X}");
|
||||
match std::str::from_utf8(bytes) {
|
||||
Ok(s) => s.replace('#', "#23"),
|
||||
|
||||
Reference in New Issue
Block a user