From 283789c1f4be5823edc681eb177183abf1ea4e1a Mon Sep 17 00:00:00 2001 From: Hector Villarreal Date: Mon, 2 Nov 2026 23:54:23 -0600 Subject: [PATCH] #2339: write the XLDAPR extension URI in lower case next to rich values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A workbook with an in-cell picture and a dynamic-array formula wrote the XLDAPR futureMetadata extension URI in upper case ({BDBB8CDC-…}), and Excel refuses such a workbook. The metadata part written for dynamic arrays alone, which Excel opens, spells the same URI in lower case; the rich-value writer now does too. Together with #1533 (content types and the XLRICHVALUE URI) this lets Excel open a workbook with an in-cell picture and a spilled formula. Co-Authored-By: Claude Opus 5.5 --- crates/xlsx/src/richdata.rs | 4 +++- crates/xlsx/src/tests/richdata_tests.rs | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/crates/xlsx/src/richdata.rs b/crates/xlsx/src/richdata.rs index 8a4f6ec0a..29c31e5dc 100644 --- a/crates/xlsx/src/richdata.rs +++ b/crates/xlsx/src/richdata.rs @@ -349,7 +349,9 @@ fn metadata(count: usize, dynamic: bool) -> String { } xml.push_str(""); if dynamic { - xml.push_str(""); + // Lower case, as the dynamic-array-only metadata in `write.rs` spells it: Excel refuses + // a workbook whose XLDAPR extension URI is in upper case (#2339). + xml.push_str(""); } let _ = write!(xml, ""); for i in 0..count { diff --git a/crates/xlsx/src/tests/richdata_tests.rs b/crates/xlsx/src/tests/richdata_tests.rs index c7bd488f7..b4beb92f1 100644 --- a/crates/xlsx/src/tests/richdata_tests.rs +++ b/crates/xlsx/src/tests/richdata_tests.rs @@ -151,6 +151,30 @@ fn reads_independent_indices_reordered_keys_and_both_relationship_layouts() { } } +#[test] +fn dynamic_array_metadata_is_spelled_the_same_with_and_without_pictures() { + // #2339: with an in-cell picture the XLDAPR extension URI was written in upper case, and + // Excel refused the workbook; the dynamic-array-only metadata, which Excel opens, is lower case. + let xldapr_uri = |pictures: bool| { + let mut wb = Workbook::new(); + let sheet = wb.sheet_mut(0).unwrap(); + if pictures { + sheet.set_picture(at("B2"), Arc::new(picture(png(), "image/png", "red"))); + } + let mut f = Cell::formula(Formula::new("SEQUENCE(3)")); + f.value = Value::Number(1.0); + sheet.cells.set(at("D1"), f); + sheet.spill_ranges.insert(at("D1"), RangeRef::parse("D1:D3").unwrap()); + let bytes = write_xlsx(&wb).unwrap(); + let mut package = Package::open(&bytes).unwrap(); + let metadata = package.read_xml("xl/metadata.xml").unwrap().unwrap(); + let future = metadata.kids("futureMetadata").find(|m| m.attr("name") == Some("XLDAPR")).unwrap(); + future.child("bk").unwrap().child("extLst").unwrap().child("ext").unwrap().attr("uri").unwrap().to_string() + }; + assert_eq!(xldapr_uri(false), "{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}"); + assert_eq!(xldapr_uri(true), xldapr_uri(false)); +} + #[test] fn pictures_roundtrip_across_sheets_with_and_without_dynamic_arrays() { for dynamic in [false, true] {