From cbffb07d784a2b4257f968c55c1536bcb8ef0e8c Mon Sep 17 00:00:00 2001 From: "Lee Maskell (PLT)" <268947818+lee-cyrille-maskell@users.noreply.github.com> Date: Wed, 28 Oct 2026 09:23:11 -0600 Subject: [PATCH] fix(ticket): write QName values as prefix:local PropertyValue::QName was written with OwnedName's Display, which puts the namespace URI in front ("{uri}psk:LongEdgeFirst"). That is not a valid QName, so PTMergeAndValidatePrintTicket rejects any delta ticket carrying a QName value copied from a driver's PrintCapabilities with 0x80040005 (E_DELTA_PRINTTICKET_FORMAT). The Microsoft IPP Class Driver lists Letter, A4 and Executive with such a property, so printing those sizes fails (storytold/pdfcraft#3823). Write the value as prefix:local, and declare the value's prefix on the root so a namespace used only in a value stays bound. Co-Authored-By: Claude Opus 5.5 --- src/ticket/document/writer.rs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/ticket/document/writer.rs b/src/ticket/document/writer.rs index 318a3de..8707a95 100644 --- a/src/ticket/document/writer.rs +++ b/src/ticket/document/writer.rs @@ -256,6 +256,9 @@ impl XmlSerializer for super::PropertyValue { ns.put("psf", NS_PSF); ns.put("xsi", NS_XSI); collect_namespace_from_name(&self.xsi_type(), ns); + if let super::PropertyValue::QName(q) = self { + collect_namespace_from_name(q, ns); + } } fn write_to(&self, writer: &mut EventWriter) -> Result<(), xml::writer::Error> { @@ -270,8 +273,10 @@ impl XmlSerializer for super::PropertyValue { super::PropertyValue::Integer(i) => { writer.write(XmlEvent::characters(&i.to_string()))?; } + // `OwnedName`'s `Display` prefixes the namespace URI (`{uri}psk:Name`), which is not + // a valid QName, so drivers reject the ticket. super::PropertyValue::QName(q) => { - writer.write(XmlEvent::characters(&q.to_string()))?; + writer.write(XmlEvent::characters(format_name(q).as_ref()))?; } super::PropertyValue::Unknown(_, s) => { writer.write(XmlEvent::characters(s))?; @@ -337,4 +342,27 @@ mod tests { let xml2 = document.to_xml(); assert_eq!(xml1, xml2); } + + #[test] + fn serialize_qname_value_as_prefixed_name() { + // As the Microsoft IPP Class Driver lists Letter (storytold/pdfcraft#3823). + let origin = br#" + + + + psk:LongEdgeFirst + + + ns0004:Letter + + + +"#; + let document = PrintTicketDocument::parse_from_bytes(origin).unwrap(); + let xml = String::from_utf8(document.to_xml()).unwrap(); + assert!(xml.contains(">psk:LongEdgeFirst<"), "{xml}"); + assert!(xml.contains(">ns0004:Letter<"), "{xml}"); + assert!(xml.contains(r#"xmlns:ns0004="urn:only-used-in-a-value""#), "{xml}"); + assert!(!xml.contains('{'), "{xml}"); + } }