fix(task-4): refuse LF/CR in XDATA strings before any write
encode_values() accepted strings containing "\n" or "\r". ezdxf writes 1000-tag values verbatim, so the separator split the tag pair: the saved DXF failed to reopen (DXFStructureError) and, because every undo and transaction snapshot is also a DXF save, transaction_rollback broke after a single such write. Both engines route through encode_values, so the refusal (ValueError naming values[i]) now happens there, before either backend touches the document. Only LF and CR split a DXF tag; tabs and the other Unicode separators round-trip and stay allowed. Tests: pure encoder refusal for \n, \r, \r\n; other control characters still typed; ezdxf refuses-then-rollback-and-reopen round trip; COM fake sees no SetXData / RegisteredApplications call. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
This commit is contained in:
co-authored by
Claude Opus 5
parent
cda8b69dba
commit
41d6d3505a
+11
-1
@@ -3,7 +3,11 @@
|
||||
DXF XDATA is a list of (group code, value) pairs under a registered APPID.
|
||||
This module is the one place that decides how a JSON value becomes a group
|
||||
code and enforces the two limits AutoCAD enforces silently: 255 characters
|
||||
per string and 16 KB per entity.
|
||||
per string and 16 KB per entity. It also refuses the one thing neither engine
|
||||
can store: a line separator inside a string. DXF is a text format of
|
||||
alternating "group code" / "value" lines, and ezdxf writes a 1000 tag verbatim,
|
||||
so a LF or CR in the value splits the tag pair and the saved file -- and every
|
||||
undo/transaction snapshot, which is also a DXF save -- becomes unreadable.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -15,6 +19,7 @@ RESERVED_APPS = {"ACAD"}
|
||||
MAX_STRING = 255
|
||||
MAX_BYTES = 16 * 1024
|
||||
INT_MIN, INT_MAX = -(2**31), 2**31 - 1
|
||||
LINE_SEPARATORS = ("\n", "\r")
|
||||
|
||||
|
||||
def validate_app_name(app) -> str:
|
||||
@@ -40,6 +45,11 @@ def encode_values(values) -> list[tuple[int, object]]:
|
||||
raise ValueError(
|
||||
f"xdata: {where} is {len(value)} characters; the limit is {MAX_STRING}"
|
||||
)
|
||||
if any(sep in value for sep in LINE_SEPARATORS):
|
||||
raise ValueError(
|
||||
f"xdata: {where} contains a newline; "
|
||||
"line separators are not allowed in XDATA strings"
|
||||
)
|
||||
tags.append((1000, value))
|
||||
size += len(value.encode("utf-8")) + 2
|
||||
elif isinstance(value, int):
|
||||
|
||||
Reference in New Issue
Block a user