A drawing program is only useful if it opens the files you already have. Ours had to open DWG, which AutoCAD writes and does not document, so the reader was built the slow way: one layer of the format at a time, each one checked against the same drawing exported to a format we could already read.

That check is the whole method. A binary format gives you no errors, only numbers. Read a field one bit early and you still get a number, and it still looks like a number, and everything downstream believes it.

The number

Every object in a DWG says what it is. Read the file's 21,241 objects and count: 21,072 of them came back as custom types — objects belonging to the add-on the drawing was made with, whose shapes are private to that add-on. Only 169 were ordinary lines, arcs and text.

That is a devastating result, and it was written down as one. If ninety-nine percent of a drawing is private to a program you do not have, then reading the ordinary shapes buys you nothing, and the only way to draw the file is to decode the cached picture such objects sometimes carry. That is a much larger, much more speculative job, and it became the plan of record. It sat at the top of the roadmap for months.

What the field actually is

The type is not a plain number. From the 2010 format on it is two bits that say how to read the rest: read one byte, or read one byte and add 496, or read two. Our reader used an older encoding, which swallowed those two bits as part of the value. Every code came out shifted into the range reserved for custom types. The drawing had not been ninety-nine percent private. It had been ninety-nine percent ordinary all along.

read asordinary typescustom typesmost common codes
the old way16921,072785, 845, 787
correctly21,11612517, 77, 19
the DXF export of the same drawingARC, LWPOLYLINE, LINE
Codes 17, 77 and 19 are arc, polyline and line. The counts match the exported drawing exactly: 6,734 arcs, 5,850 polylines, 4,762 lines.

The corrected reading is not merely more plausible. It agrees, object for object, with a copy of the same drawing exported by AutoCAD itself. Thirteen shape types, thirteen exact matches. A wrong reading does not do that.

Why nothing caught it

There were fifty-eight tests and they were green. One of them asserted that the drawing had more custom objects than ordinary ones.

What found it was not a test. It was writing a small program whose only job was to print what the bytes said, running it against the real file, and comparing the output with the same drawing in a format we could already read. Five of those, one per layer of the format. They took an afternoon and they are committed next to the code, because the last set was kept as scratch files and lost.

Where it left us

  • The reader now decodes 19,067 shapes from the drawing. Exported by AutoCAD, the same drawing has 19,067.
  • Drawn on screen, both produce 27,028 elements, with the same bounding box and the same thirteen colours.
  • The large speculative job is worth 23 shapes out of 19,067. It is no longer the plan.

Two bugs in our own DXF reader fell out of this as well, in the path that had been shipping for months. Rotated labels were drawn flat, because the angle is stored as a direction rather than a number and we read the number. Long labels were cut to their last fragment, because text over 250 characters arrives in pieces and we read the final piece. Neither was visible until a second, independent reader disagreed.

The part worth keeping

The lesson is not that binary formats are hard, though they are. It is that a number your own code produced is not a measurement. It becomes one when something you did not write agrees with it.

The note in the repository said ninety-nine percent custom for months, and everyone who read it, including us, treated it as a fact about the file. It was a fact about a bug. The cheapest way to tell those apart is to go and look.