Skip to content

Write BlockRepresentationData (AcDbRepData) in DWG and DXF#1137

Open
Sipowiz wants to merge 5 commits into
DomCR:masterfrom
Sipowiz:feat/write-block-representation-data
Open

Write BlockRepresentationData (AcDbRepData) in DWG and DXF#1137
Sipowiz wants to merge 5 commits into
DomCR:masterfrom
Sipowiz:feat/write-block-representation-data

Conversation

@Sipowiz

@Sipowiz Sipowiz commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

First step toward the dynamic-block write support discussed in #1133: writing BlockRepresentationData (AcDbRepData) in both the DWG and DXF writers.

What this does

BlockRepresentationData is the per-insert object (under Insert.XDictionary → AcDbBlockRepresentation → AcDbRepData) that links an anonymous *U… block instance back to its source dynamic block. Its sibling AppDataCache → ACAD_ENHANCEDBLOCKDATA → XRecord chain already round-trips through the existing dictionary/XRecord writers — only AcDbRepData itself was dropped by skipEntry / isObjectSupported.

  • Removes BlockRepresentationData from the DWG skipEntry and DXF isObjectSupported drop-lists.
  • writeBlockRepresentationData in both writers, mirroring the readers: BS 70 (Value70) + a hard pointer (340) to the source BlockRecord.
  • Adds the AcDbBlockRepresentationData DxfClass entry (values taken from AutoCAD-authored files: ProxyFlags=1153, ItemClassId=499, DwgVersion=AC1018, MaintenanceVersion=58; identical across the AC1027 and AC1032 files I checked).
  • Refactors DynamicBlockTests asserts into a reusable assertRepresentationChain layer and adds unconditional DWG + DXF round-trip theories (they are not gated on SELF_CHECK_OUTPUT, so they run in CI).

Scope / what this deliberately does NOT do

This does not write the EvaluationGraph (ACAD_ENHANCEDBLOCK) — you mentioned in #1133 you're exploring that yourself, so I've kept this PR to the representation-data half and left the graph alone.

Validation against real AutoCAD

I ran the rewritten files through AutoCAD 2022 (via COM AUDIT + block-reference enumeration) on a corpus of real production dynamic-block templates: all open without a recover prompt and audit-clean apart from a finding that is already present in the untouched source file (an unrelated ACAD_LAYERFILTERS XRecord length). One honest caveat: restoring AcDbRepData alone does not make IsDynamicBlock return true — that needs the graph — but it adds no audit errors and is a prerequisite for it. 61/61 DynamicBlockTests pass.

Note

Stacked on #1136 (the DXF objects-section writer fixes) — the round-trip tests here rely on those. I'll rebase once #1136 merges; until then this branch contains those three commits too.

Sipowiz and others added 5 commits July 7, 2026 00:44
DxfObjectsSectionWriter.writeDictionary emitted the 3/350 entry pair for
every dictionary entry, while writeObject later dropped the unsupported
types via isObjectSupported. The output contained soft-ownership handles
pointing to objects that were never written (e.g. ACAD_ENHANCEDBLOCK,
AcDbRepData, visual styles), which readers report as missing entries.

Filter the entries with isObjectSupported before writing the pair and
enqueuing the object, mirroring the skipEntry filtering already done by
the dwg writer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An object can be enqueued in the objects section queue multiple times,
once by the dictionary that owns it and once by the objects that
reference it, e.g. a Field enqueued by its owning dictionary and by the
FieldList that references it. Each copy was written to the output, and
reading the result back created duplicated templates whose builds
assigned the same object to two owners, failing with 'Item already has
an owner'.

Track the written handles and write each object only once.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Writing a document containing a Field whose value string is null failed
with a NullReferenceException in writeLongTextValue. Treat the null text
as an empty string, matching the dwg writer behavior.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Split the per-parameter assert helpers into assertRepresentationChain
(the per-insert AcDbBlockRepresentation -> AcDbRepData + AppDataCache ->
ACAD_ENHANCEDBLOCKDATA chain) and assertGraph<T> (the evaluation graph
node expressions), dispatched by assertIsolatedDocument. This allows the
write round-trip tests to assert the representation chain independently
from the evaluation graph, which is not written yet.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Remove BlockRepresentationData from the writer skip lists and emit the
object mirroring the readers: BS 70 followed by a hard pointer (340) to
the source block record. The per-insert representation chain
(AcDbBlockRepresentation -> AcDbRepData) is restored on the output while
the evaluation graph is still dropped, so dynamic block inserts keep the
link to their source block record.

Add the AcDbBlockRepresentationData class to UpdateDxfClasses with the
values found in AutoCAD generated files (proxy flags 1153, maintenance
version 58) so documents created from scratch get a valid CLASSES entry.

Add write and re-read round-trip tests over the dynamic-blocks samples
for both formats, asserting the representation chain and the absence of
dangling dictionary handles. The tests run unconditionally so they are
not skipped in CI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@DomCR

DomCR commented Jul 7, 2026

Copy link
Copy Markdown
Owner

It seems that there is a duplication of the task done in:

@Sipowiz

Sipowiz commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Sorry for the confusion — #1137 is stacked on top of #1136, so its branch currently contains #1136's three commits as well; that's the overlap you're seeing, not a re-do. Its own change is a single commit: the BlockRepresentationData (AcDbRepData) writer for DWG + DXF (writeBlockRepresentationData = BS 70 + hard pointer 340 to the source BlockRecord) plus the AcDbBlockRepresentationData DxfClass entry.

Once #1136 merges I'll rebase this onto master so the diff shows only the RepData writer. Want me to rebase now onto #1136's branch instead, or hold until #1136 lands? (I'll also drop the DynamicBlockTests.cs additions here to match the scoping you asked for on #1136.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants