Place: a Word .doc style sheet that holds fewer styles than it counts is refused

Stshif.cstd counts the LPStd records of the style sheet and must be less than
0x0FFE. A sheet that ended before cstd records was read as far as it went, and
paragraphs in the missing styles were placed with the document defaults; a
cstd of 0x0FFE or more was cut to 0x0FFE. Both are now refused as a damaged
style sheet.
This commit is contained in:
dotCooCoo
2026-11-02 12:03:58 +07:00
committed by bflatastic
parent 22218e9097
commit a6db4c9112
3 changed files with 19 additions and 6 deletions
+6 -3
View File
@@ -70,7 +70,7 @@ const MAX_STREAM: u64 = 64 << 20;
const MAX_PIECES: usize = 100_000;
/// The most 512-byte pages of character or of paragraph properties read.
const MAX_PAGES: usize = 16_384;
/// The most styles read from the style sheet (`Stshif.cstd` is below 0x0FFE).
/// The style count `Stshif.cstd` must be below.
const MAX_STYLES: usize = 0x0FFE;
/// The most fonts read from the font table (SttbfFfn's `cData` is at most 0x7FF0).
const MAX_FONTS: usize = 0x7FF0;
@@ -505,14 +505,17 @@ impl Sheet {
let broken = || damaged(cmd, "its style sheet is damaged");
let size = usize::from(u16_at(stsh, 0).ok_or_else(broken)?);
let stshi = bytes_at(stsh, 2, size).ok_or_else(broken)?;
let count = usize::from(u16_at(stshi, 0).ok_or_else(broken)?).min(MAX_STYLES);
let count = usize::from(u16_at(stshi, 0).ok_or_else(broken)?);
if count >= MAX_STYLES {
return Err(broken());
}
// cbSTDBaseInFile: StdfBase, and StdfPost2000 when it is 18.
let base_size = usize::from(u16_at(stshi, 2).ok_or_else(broken)?).max(10);
let font = u16_at(stshi, 12);
let mut at = 2 + size;
let mut styles = Vec::with_capacity(count);
for _ in 0..count {
let Some(len) = u16_at(stsh, at) else { break };
let len = u16_at(stsh, at).ok_or_else(broken)?;
let std = bytes_at(stsh, at + 2, usize::from(len)).ok_or_else(broken)?;
styles.push(if std.is_empty() { None } else { Some(style(std, base_size).ok_or_else(broken)?) });
// LPStd records start on even offsets.