Compare commits

...
Author SHA1 Message Date
Brandon Thomas 04c5613b2c Merge remote-tracking branch 'origin/main' into fix2708
# Conflicts:
#	crates/io/src/tests.rs
2026-11-03 09:07:28 -05:00
Brandon ThomasandClaude Opus 5.5 4c6a9bcb56 Test: assert the empty table is read (CodeRabbit)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 08:57:21 -05:00
Dylan M. Taylor 1881f1ed59 fix(io): an ACAD_TABLE with no rows or no columns reads as an empty table
The table cell budget charges rows x columns, which is zero when either dimension is, so a table declaring 10 000 rows and no columns still allocated row heights and empty row vectors for free, once per record. Such a table now keeps neither dimension.
2026-11-03 11:10:06 +00:00
2 changed files with 17 additions and 1 deletions
+3 -1
View File
@@ -299,7 +299,9 @@ pub(super) fn acad_table(tags: &[Tag], table_cells_left: &mut usize) -> Table {
// Large declared sizes must be backed by cell records (no allocation from a bare count).
let n_cells = tail.iter().filter(|x| x.code == 171).count();
let declared = rows.saturating_mul(cols);
if declared > MAX_CELLS || (declared > 10_000 && n_cells < declared) {
// A table with no rows or no columns has no cells: keep neither dimension, so its row heights
// and column widths (allocated per dimension, outside the cell budget) are not allocated.
if declared == 0 || declared > MAX_CELLS || (declared > 10_000 && n_cells < declared) {
rows = 0;
cols = 0;
}
+14
View File
@@ -337,6 +337,20 @@ fn entity_transparency_roundtrips_as_group_440() {
assert_eq!(d.model.iter().map(|e| e.common.transparency).collect::<Vec<_>>(), [Transparency::ByLayer, Transparency::Percent(90)]);
}
/// A table declaring 10 000 rows and no columns (or the reverse) is read as an empty table.
#[test]
fn table_with_an_empty_dimension_allocates_nothing() {
for (rows, cols) in [(10_000, 0), (0, 10_000)] {
let t = format!("0\nSECTION\n2\nENTITIES\n0\nACAD_TABLE\n100\nAcDbTable\n91\n{rows}\n92\n{cols}\n0\nENDSEC\n0\nEOF\n");
let d = read(t.as_bytes(), "t.dxf").unwrap();
let tables: Vec<_> = d.model.iter().filter_map(|e| if let EntityKind::Table(t) = &e.kind { Some(t) } else { None }).collect();
assert_eq!(tables.len(), 1, "the table is read");
for t in tables {
assert!(t.row_heights.is_empty() && t.col_widths.is_empty() && t.cells.is_empty());
}
}
}
/// Many distinct layer, linetype and style names (in the tables and on entities) read in linear
/// time, with the duplicate rules kept: first LTYPE wins, last STYLE wins, layers case-insensitive.
#[test]