Metafile import: a file that reaches the most objects one file may hold says so

The reader keeps at most 200,000 objects from one file and stops reading
there. A picture that reaches that count now carries a warning that any
objects after them were not read, and objects dropped past the import's own
object limit carry a warning too.
This commit is contained in:
dotCooCoo
2026-11-14 07:55:40 -08:00
parent d5e58b0e4b
commit 9e85368a44
2 changed files with 23 additions and 1 deletions
+11 -1
View File
@@ -36,6 +36,13 @@ use crate::{Imported, Kind};
const PATTERNS: &str = "hatched and pattern brushes are filled with their average color";
const ENDS_EARLY: &str = "the file ends early: what it held was imported";
const TOO_MANY: &str = "objects past the most one file may hold were left out";
const AT_LIMIT: &str = "the file reached the most objects one file may hold: any after them were not read";
/// The most items `craft_metafile` keeps from one file (its `MAX_ITEMS`). It stops reading at the
/// limit and does not say whether more items followed, so a picture holding this many may have
/// been cut short.
const READER_ITEMS: usize = 200_000;
/// Points a unit of a WMF without a placeable header (1440 units an inch).
const WMF_UNIT: f64 = 72.0 / 1440.0;
@@ -243,7 +250,7 @@ impl Mapper {
fn push(&mut self, clips: Vec<Arc<Clip>>, mut node: Node) {
if self.out.len() >= MAX_NODES {
return;
return self.warn(TOO_MANY);
}
if !node.visual_bounds().is_none_or(sane) {
return self.warn(FAR_AWAY);
@@ -526,6 +533,9 @@ pub(crate) fn import(bytes: &[u8]) -> Result<Imported, String> {
if ends_early(bytes, kind) {
m.warn(ENDS_EARLY);
}
if pic.items.len() >= READER_ITEMS {
m.warn(AT_LIMIT);
}
for item in pic.items {
m.item(item);
}
+12
View File
@@ -370,6 +370,18 @@ fn damaged_files_fail_or_import_partly() {
assert!(import(&huge).is_ok());
}
#[test]
fn a_file_with_more_objects_than_are_read_says_so() {
// RECTANGLE records: 10 more than the reader keeps, then a few under that.
let rect = (43, le(&[0, 0, 100, 100]));
let many = hand_emf(5000, 3000, &vec![rect.clone(); 200_010]);
let back = import(&many).unwrap();
assert_eq!(paths(&back.document).len(), 200_000);
assert!(back.warnings.iter().any(|w| w.contains("reached the most objects")), "{:?}", back.warnings);
let few = import(&hand_emf(5000, 3000, &vec![rect; 3])).unwrap();
assert!(few.warnings.is_empty(), "{:?}", few.warnings);
}
/// An EMR_STRETCHDIBITS copying `png` (a BI_PNG bitmap) to a 10 × 10 box.
fn png_stretch_dibits(png: &[u8]) -> Vec<u8> {
// Bounds; destination, source and its size; the BITMAPINFO and the bits (from the record start);