mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Merge pull request #3789 from Silvertree2010/fix/3573-audit-dxf-import-each-minsert-re
Cap the total array insert copies in a DXF import
This commit is contained in:
@@ -17,6 +17,8 @@ const DESCENT: f64 = 0.3;
|
||||
const LINE_SPACING: f64 = 5.0 / 3.0;
|
||||
/// The most copies one array insert (MINSERT) makes.
|
||||
const MAX_CELLS: i64 = 10_000;
|
||||
/// The most copies all the array inserts of a file make together.
|
||||
const MAX_TOTAL_CELLS: i64 = 2_000_000;
|
||||
/// Art farther than this from the origin (drawing units) is damaged data, left out.
|
||||
const MAX_COORD: f64 = 1e12;
|
||||
/// How far fit and aligned text may be squeezed or stretched to span their two points: at width
|
||||
@@ -184,12 +186,15 @@ pub(crate) struct Converter {
|
||||
/// Entity types left out, with how many.
|
||||
pub skipped: BTreeMap<String, usize>,
|
||||
pub warnings: Vec<String>,
|
||||
/// Array insert copies made so far, against [`MAX_TOTAL_CELLS`].
|
||||
cells: i64,
|
||||
}
|
||||
|
||||
const PATTERN_HATCH: &str = "pattern hatches come in as their boundaries";
|
||||
const GRADIENT_HATCH: &str = "gradient hatches are filled with their first colour";
|
||||
const MESHES: &str = "3D polygon meshes and polyface meshes are left out";
|
||||
const BIG_ARRAY: &str = "array inserts are limited to 10,000 copies each";
|
||||
const MANY_ARRAYS: &str = "array inserts are limited to 2,000,000 copies in all";
|
||||
const FAR_AWAY: &str = "entities with coordinates out of range are left out";
|
||||
|
||||
impl Converter {
|
||||
@@ -294,6 +299,15 @@ impl Converter {
|
||||
} else {
|
||||
(cols, rows)
|
||||
};
|
||||
// Past the file-wide budget, each insert keeps only its first copy.
|
||||
let left = (MAX_TOTAL_CELLS - self.cells).max(1);
|
||||
let (cols, rows) = if cols * rows > left {
|
||||
self.warn(MANY_ARRAYS);
|
||||
(cols.min(left), (left / cols.min(left)).max(1).min(rows))
|
||||
} else {
|
||||
(cols, rows)
|
||||
};
|
||||
self.cells = self.cells.saturating_add(cols * rows);
|
||||
let cells = (0..rows)
|
||||
.flat_map(|r| (0..cols).map(move |c| (r, c)))
|
||||
.map(|(r, c)| place * Affine::translate((c as f64 * cs, r as f64 * rs)) * Affine::scale_non_uniform(sx, sy))
|
||||
|
||||
@@ -1090,3 +1090,20 @@ fn paper_layout_names_are_unique_ignoring_case() {
|
||||
let info = info(&with_layouts(&names)).unwrap();
|
||||
assert_eq!(info.layouts, ["Model", "Layout1", "Other"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn many_array_inserts_of_a_missing_block_stay_bounded() {
|
||||
let one = [(0, "INSERT"), (8, "0"), (2, "NOPE"), (10, "0"), (20, "0"), (70, "100"), (71, "100"), (44, "1"), (45, "1")];
|
||||
let e: Vec<(i32, &str)> = (0..3000).flat_map(|_| one).collect();
|
||||
let bytes = entities(&e);
|
||||
let text = reader::decode(&bytes);
|
||||
let (pairs, _) = reader::pairs(&text).unwrap();
|
||||
let d = reader::Drawing::read(&pairs);
|
||||
let model = d.layout("Model").or(d.layouts.first()).unwrap();
|
||||
let mut conv = entity::Converter::default();
|
||||
let items = conv.items(&d.layout_records(model));
|
||||
assert_eq!(items.len(), 3000);
|
||||
let total: usize = items.iter().map(|i| if let entity::Geom::Insert(ins) = &i.geom { ins.cells.len() } else { 0 }).sum();
|
||||
assert!(total <= 2_000_000 + 3000, "total cells materialised: {total}");
|
||||
assert!(conv.warnings.iter().any(|w| w.contains("array inserts")), "{:?}", conv.warnings);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user