Merge pull request #746 from marcoarnulfo:fix/xls-format-short-string
This commit is contained in:
commit
0837cbc44d
|
|
@ -476,3 +476,39 @@ fn sheets_share_one_record_budget() {
|
|||
let err = read_xls(&compound("Workbook", &dup)).unwrap_err().to_string();
|
||||
assert!(err.contains("same substream"), "{err}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_format_shorter_than_its_count_keeps_its_characters() {
|
||||
// A FORMAT whose cch is one more than the characters in the record (seen in real files):
|
||||
// Excel opens them, the record's characters are the format code.
|
||||
let short = rec(0x041E, &cat(&[&165u16.to_le_bytes(), &6u16.to_le_bytes(), &[0], b"0.000"]));
|
||||
let xf = |ifmt: u16| rec(0x00E0, &cat(&[&u16s(&[0, ifmt, 0]), &[0; 14]]));
|
||||
let globals = |pos: u32| {
|
||||
cat(&[
|
||||
&bof(0x0005),
|
||||
&short,
|
||||
&rec(0x041E, &cat(&[&164u16.to_le_bytes(), &xlstr("yyyy-mm-dd")])),
|
||||
&xf(0),
|
||||
&xf(164),
|
||||
&xf(165),
|
||||
&rec(0x0085, &cat(&[&pos.to_le_bytes(), &[0, 0, 6, 0], b"Sheet1"])),
|
||||
&eof(),
|
||||
])
|
||||
};
|
||||
let sheet = cat(&[
|
||||
&bof(0x0010),
|
||||
&rec(0x0203, &cat(&[&cell(0, 0, 0), &7.0f64.to_le_bytes()])),
|
||||
&rec(0x0203, &cat(&[&cell(1, 0, 1), &0.0f64.to_le_bytes()])),
|
||||
&rec(0x0203, &cat(&[&cell(2, 0, 2), &1.25f64.to_le_bytes()])),
|
||||
&eof(),
|
||||
]);
|
||||
let stream = cat(&[&globals(globals(0).len() as u32), &sheet]);
|
||||
let (wb, report) = read_xls(&compound("Workbook", &stream)).unwrap();
|
||||
let sh = &wb.sheets[0];
|
||||
let fmt = |a1: &str| wb.styles.get(sh.style_id(CellRef::parse(a1).unwrap())).num_fmt.as_str().to_string();
|
||||
assert_eq!(v(&wb, 0, "A1"), Value::Number(7.0));
|
||||
assert_eq!(v(&wb, 0, "A3"), Value::Number(1.25));
|
||||
assert_eq!(fmt("A2"), "yyyy-mm-dd");
|
||||
assert_eq!(fmt("A3"), "0.000");
|
||||
assert!(report.warnings.iter().any(|w| w.contains("declared length")), "{:?}", report.warnings);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ pub(crate) fn read_xls_with(bytes: &[u8], mut budget: Budget) -> Result<(Workboo
|
|||
}
|
||||
};
|
||||
let mut report = ReadReport::default();
|
||||
let g = globals(&stream, &mut budget)?;
|
||||
let g = globals(&stream, &mut budget, &mut report)?;
|
||||
|
||||
let mut wb = Workbook::new();
|
||||
wb.sheets.clear();
|
||||
|
|
@ -205,7 +205,7 @@ fn bof(rec: &Record<'_>) -> Result<(u16, u16), IoError> {
|
|||
Ok((c.u16()?, c.u16()?))
|
||||
}
|
||||
|
||||
fn globals(stream: &[u8], budget: &mut Budget) -> Result<Globals, IoError> {
|
||||
fn globals(stream: &[u8], budget: &mut Budget, report: &mut ReadReport) -> Result<Globals, IoError> {
|
||||
let mut recs = Records::new(stream, 0);
|
||||
let first = recs.next_record()?.ok_or_else(|| invalid("empty Workbook stream"))?;
|
||||
let (vers, dt) = bof(&first)?;
|
||||
|
|
@ -249,7 +249,15 @@ fn globals(stream: &[u8], budget: &mut Budget) -> Result<Globals, IoError> {
|
|||
0x0022 => g.date1904 = c.u16()? == 1,
|
||||
0x041E => {
|
||||
let ifmt = c.u16()?;
|
||||
let code = c.string()?;
|
||||
let cch = usize::from(c.u16()?);
|
||||
let high = c.u8()? & 1 != 0;
|
||||
// Some writers count one character more than the record holds; Excel opens
|
||||
// those files, so keep the characters that are there.
|
||||
let fit = c.remaining() / if high { 2 } else { 1 };
|
||||
if cch > fit {
|
||||
report.warn("Some number formats were shorter than their declared length; the characters present were kept.");
|
||||
}
|
||||
let code = c.chars(cch.min(fit), high)?;
|
||||
budget.text(code.len())?;
|
||||
g.formats.insert(ifmt, code);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue