Merge pull request #821 from marcoarnulfo:fix/xls-kept-value-string-result

This commit is contained in:
Brandon Thomas 2026-10-12 23:49:45 -04:00
commit c9b36de54c
2 changed files with 22 additions and 3 deletions

View File

@ -358,6 +358,21 @@ fn reads_values_formulas_formats_and_layout() {
assert_eq!(wb.date_system, DateSystem::D1904);
}
#[test]
fn text_result_of_a_formula_kept_as_its_value() {
// A what-if data table cell ({=TABLE(B1,)}) can't be imported as a formula, so its saved result
// is kept. With the default XF the cell is blank until the String record brings the text.
let table = cat(&[&[0x02], &u16s(&[0, 0])]);
let sheet = cat(&[&bof(0x0010), &formula(0, 0, special(0, 0), &table), &rec(0x0207, &xlstr("103a")), &eof()]);
let boundsheet = |pos: u32| rec(0x0085, &cat(&[&pos.to_le_bytes(), &[0, 0, 6, 0], b"Sheet1"]));
let len = cat(&[&bof(0x0005), &boundsheet(0), &eof()]).len() as u32;
let stream = cat(&[&bof(0x0005), &boundsheet(len), &eof(), &sheet]);
let (wb, report) = read_xls(&compound("Workbook", &stream)).unwrap();
assert!(report.warnings.iter().any(|w| w.contains("what-if data tables")), "{:?}", report.warnings);
assert_eq!(ftext(&wb, "A1"), None);
assert_eq!(v(&wb, 0, "A1"), Value::from("103a"));
}
#[test]
fn refuses_encrypted_old_and_foreign_files() {
// FILEPASS in the globals: an encrypted workbook.

View File

@ -398,7 +398,9 @@ struct SheetState<'g> {
shared: HashMap<CellRef, Parsed>,
arrays: HashMap<CellRef, (RangeRef, Parsed)>,
last_formula: Option<CellRef>,
pending_string: Option<CellRef>,
/// The cell waiting for its String record, with its style: a blank cell isn't stored, so a
/// formula kept as its value may have no cell to receive the text.
pending_string: Option<(CellRef, StyleId)>,
dropped: usize,
unsupported: Vec<&'static str>,
}
@ -602,11 +604,13 @@ fn sheet_record(rec: &Record<'_>, st: &mut SheetState<'_>, budget: &mut Budget,
}
0x0006 => formula_cell(&mut c, st, budget)?,
0x0207 => {
if let Some(pos) = st.pending_string.take() {
if let Some((pos, style)) = st.pending_string.take() {
let s = c.string()?;
budget.text(s.len())?;
if let Some(cell) = st.sheet.cells.get_mut(pos) {
cell.value = Value::from(s);
} else {
st.sheet.cells.set(pos, Cell { value: Value::from(s), formula: None, style });
}
}
}
@ -744,7 +748,7 @@ fn formula_cell(c: &mut Cursor<'_, '_>, st: &mut SheetState<'_>, budget: &mut Bu
st.sheet.cells.set(pos, Cell { value, formula: None, style });
st.last_formula = Some(pos);
if string_result {
st.pending_string = Some(pos);
st.pending_string = Some((pos, style));
}
// PtgExp: part of a shared or array formula anchored at another cell.
if f.rgce.len() == 5 && f.rgce.first() == Some(&0x01) {