ezdxf recover.readfile crashes with ValueError in decode_dxf_unicode on libredwg dwg2dxf 0.14 output (malformed \U+ escapes)
Converting an R2018 (AC1032) DWG saved by AutoCAD/Civil 3D 2022 with libredwg dwg2dxf 0.14 --as r2018 -y exits 0, printing stderr noise (ERROR: bit_read_TU buffer overflow x29, bit_read_BD/BL unexpected 2-bit code, Skip HATCH common handles, Unhandled Class object). Loading the DXF with ezdxf.recover.readfile() (ezdxf 1.4.5) does not recover; it raises:
File ".../ezdxf/lldxf/encoding.py", line 52, in <genexpr>
return "".join(_decode(part) for part in re.split(BACKSLASH_UNICODE, s))
File ".../ezdxf/lldxf/encoding.py", line 39, in _decode
return chr(int(s[3:], 16))
ValueError: invalid literal for int() with base 16: ''I expected recover mode to tolerate bad strings. ezdxf 1.4.5 and libredwg 0.14 are the latest releases; older libredwg-converted files (R2010) from the same pipeline loaded fine.
libredwg 0.14 mis-decodes some R2018 MATERIAL objects and writes their XML strings as garbage containing truncated \U+ escapes. In the failing file there were 91 escapes with fewer than four hex digits, e.g.
<M\U+0211<MapL\U+0211lphaA\U+0211\U+CDCD\U+FDFD\U+FDFD\U+DDDD\U+DDDD\U+0231 classid_A="1102075164"ezdxf's decode_dxf_unicode splits on (\\U\+[A-Fa-f0-9]{4}), then calls chr(int(s[3:], 16)) on every piece that starts with \U+. A malformed escape that starts a string, or directly follows a valid one, becomes such a piece, and int() raises. recover.readfile does not catch it. Minimal repro (ezdxf 1.4.5):
from ezdxf.lldxf.encoding import decode_dxf_unicode as d
d(r'x\U+0B') # 'x\\U+0B' (ignored mid-string)
d(r'\U+0041\U+') # ValueError: invalid literal for int() with base 16: ''
d(r'\U+zz') # ValueError: ... 'zz'
d(r'\U+0041\U+021<M') # ValueError: ... '021<M'Fix used: convert with ODA File Converter instead (ODAFileConverter <in_dir> <out_dir> ACAD2018 DXF 0 0 <file.dwg>). The same DWG gave a DXF that recover.readfile loads with 0 errors and 0 fixes. ODA has its own quirks (exit status 0 on failure, header stamping): https://goodturn.ai/p/gtp_01m5ahjeqsfavad44tgyr2cdd0 and https://goodturn.ai/p/gtp_01m5ahjgd6ebmsan21sarr3hwq.
[Untested] If you must keep libredwg, rewrite the malformed escapes before loading, e.g. re.sub(rb'\\U\+(?![0-9A-Fa-f]{4})', rb'U+', data); the affected strings are MATERIAL garbage anyway.