The AutoCAD 12 DWG file format

This page gives a description of the DWG format used by AutoCAD version 12. The description is given in the form of a Binary File Format grammer. I also wrote a C program that can parse a DWG file. AutoCAD versions up to version 12, all used the format very similar to the version described here. AutoCAD version 13, and later, started using a completely different version. I made some attempts to crack the AutoCAD R13 format.

A number of CAD vendors have decided to form the OpenDWG Alliance, which aims at making the DWG format available to everybody who joins them.

Acknowledgements

I would like to thank Reini Urban for his contributions.

Definition of the elementary elements

typedef word word :=
     byte : b1, byte : b2
     return (word)f | ((word)s << 8).
typedef longword longp :=
     byte : b1, byte : b2, byte : b3, byte : b4
     return (longword)b1 | ((longword)b2 << 8)
          | ((longword)b3 << 16) | ((longword)b4 << 24).
typedef longword longword :=
     byte : b1, byte : b2, byte : b3, byte : b4
     return (longword)b1 | ((longword)b2 << 8)
          | ((longword)b3 << 16) | ((longword)b4 << 24).

Definition of the whole file

root dwg_file :=
 [begin : end](
  char[12] : version,
  byte, word, word, word, byte,
  longp : p_entities,  longp : p_entend,
  longp : p_blocksec,  byte[4],  longp : p_bsend,  byte[4],
  tablepos : block_table,
  tablepos : layer_table,
  tablepos : style_table,
  tablepos : ltype_table,
  tablepos : view_table,
  header,  [cur : 0x3EF]byte*,
  tablepos : ucs_table,  [cur : 0x500]byte*,
  tablepos : vport_table,  byte[8],
  tablepos : appid_table,  byte[6],
  tablepos : dimstyle_table,  [cur : 0x69F]byte*,
  tablepos : p13_table,  bytes[38],
  [p_entities : p_entend]entities : ents,   byte[19],
  [block_table.start : ]blocks : block_table,
  [layer_table.start : ]layers : layer_table,
  [style_table.start : ]styles : style_table,
  [ltype_table.start : ]ltypes : ltype_table,
  [view_table.start : ]table : view_table,
  [ucs_table.start : ]table : ucs_table,
  [vport_table.start : vport_table.end]table : vport_table,
  [appid_table.start : ]appids : appid_table,
  [dimstyle_table.start : ]table : dimstyle_table,
  [p13_table.start : ]table : p13_table,
  [p_blocksec : p_bsend]entities : blocks,  bytes[36],
  longp = p_entities,  longp = p_entend,
  longp = blocksec,  longp = bsend,
  bytes[12],
  bytes[6],
  longp = block_table.start,   bytes[6],
  longp = layer_table.start,   bytes[6],
  longp = style_table.start,   bytes[6],
  longp = ltype_table.start,   bytes[6]
  longp = view_table.start,   bytes[6],
  longp = ucs_table.start,   bytes[6],
  longp = vport_table.start,   bytes[6],
  longp = appid_table.start,   bytes[6],
  longp = dimstyle_table.start,   bytes[6],
  longp = p13_table.start,   bytes[6],
  longp  bytes*,
 ).

A table position

tablepos :=
   word : size,
   long : nr,
   long : start,

The header

header :=
   word,
   point(TRUE) : inbase,
   point(TRUE) : extmin,
   point(TRUE) : extmax,
   point(FALSE) : limmin,
   point(FALSE) : limmax,
   double[4],
   byte[2],
   double[2],
   byte[56],
   double[3],
   byte[18],
   double .

The block table

blocks :=
  ( [size](
      byte : flag,
      char[32] : name,
      word : used,
      byte, word, byte, word,
      check_2
    )
  )[nr] : blocks_info,
  check_32.

check_2 := byte[2].
check_32 := byte[32].

The layer table

layers :=
  ( [size](
      byte : flag,
      char[32] : name,
      word : used,
      word : color,
      word : style,
      check_2
    )
  )[nr] : layer_info,
  check_32.

The style table

styles :=
  ( [size](
      byte : flag,
      char[32] : name,
      word, double[3], byte, double, char[128],
      check_2
    )
  )[nr] : style_info,
  check_32.

The line-type table

ltypes :=
  ( [size](
      byte : flag,
      char[32] : name,
      word,  char[48],  byte,
      byte,  double[13],
      check_2
    )
  )[nr] : ltype_info,
  check_32 .

The application identifier table

appids :=
  ( [size](
      byte : flag,
      char[32] : name,
      word,
      check_2
    )
  )[nr] : appid_info,
  check_32 .

The other tables

table :=
  ( [size](
      byte : flag,
      [size - 3]byte*,
      check_2
    )
  )[nr],
  check_32 .

The entities

(Experimental)
entities :=
  ( byte : kind,
    byte : flag,
    word : length,
    [length - 4](
      word : layer,
      word : opts,
      if (flag & 1) then byte : color else color = 0 fi,
      if (flag & 0x40) then byte : extra else extra = 0 fi,
      if (extra & 2) then xdata fi,
      if (flag & 2) then word : type fi,
      if (flag & 4 && kind > 2 && kind != 22) then double : z fi,
      if (flag & 8) then double : th fi,
      if (flag & 0x20) then handle fi,
      if (extra & 4) then word : paper fi,
      switch (kind)
      case 1:  /* LINE */
        point(!(flag & 4)) : l10,
        point(!(flag & 4)) : l11,
        if (opts & 1) then point(TRUE) : l210 fi,
        if (opts & 2) then double : l38 fi,
      case 2:  /* POINT */
        point(!(flag & 4)) : l10,
        if (opts & 1) then point(TRUE) : l210 fi,
        if (opts & 2) then double : l38 fi,
      case 3:  /* CIRCLE */
        point(FALSE) : l10,
        double : l40,
        if (opts & 1) then point(TRUE) : l210 fi,
        if (opts & 2) then double : l38 fi,
      case 4:  /* SHAPE */
        point(FALSE) : l10,
        word : l2,
        if (opts & 1) then point(TRUE) : l210 fi,
        if (opts & 2) then double : l38 fi,
      case 7: /* TEXT */
        point(FALSE) : l10,
        double : l40,
        string : l1,
        if (opts & 1) then double : l50 fi,
        if (opts & 2) then double : l41 fi,
        if (opts & 4) then double : l51 fi,             /*?*/
        if (opts & 8) then byte : l7 fi,
        if (opts & 0x10) then byte : l71 fi,
        if (opts & 0x20) then byte : l72 fi,
        if (opts & 0x40) then point(FALSE) : l11 fi,
        if (opts & 0x100) then byte : l73 fi,
      case 8:  /* ARC */
        point(FALSE) : l10,
        double : l40,
        double : l50,
        double : l51,
        if (opts & 1) then point(TRUE) : l210 fi,
        if (opts & 2) then double : l38 fi,
      case 9:   /* TRACE */
        point(FALSE) : l10,
        point(FALSE) : l11,
        point(FALSE) : l12,
        point(FALSE) : l13,
        if (opts & 1) then point(TRUE) : l210 fi,
        if (opts & 2) then double : l38 fi,
      case 11:   /* SOLID */
        point(FALSE) : l11,
        point(FALSE) : l12,
        point(FALSE) : l13,
        point(FALSE) : l14,
        if (opts & 1) then point(TRUE) : l210 fi,
        if (opts & 2) then double : l38 fi
      case 12:   /* BLOCK */
        point(FALSE) : l10,                /*?*/
        string : l1,                       /* if (opts & 1) then ? */
        if (opts & 2) then string : l3 fi
      case 13:  /* ENDBLK */
      case 14:   /* INSERT */
        word : l1,
        point(FALSE) : l10,
        if (opts & 1) then double : l41 fi,
        if (opts & 2) then double : l42 fi,
        if (opts & 4) then double : l43 fi,
        if (opts & 8) then double : l50 fi,
        if (opts & 0x10) then word : l70 fi,
        if (opts & 0x20) then word : l71 fi,
        if (opts & 0x40) then double : l44 fi,              /*?*/
        if (opts & 0x80) then double : l45 fi              /*?*/
      case 15:    /* ATTDEF */
        point(FALSE) : l10,
        double : l40,
        string : l1,
        string : l3,
        string : l2,
        byte : l70,
        if (opts & 1) then byte : l73 fi,           /*?*/
        if (opts & 2) then double : l50 fi,         /*?*/
        if (opts & 4) then double : l41 fi,
        if (opts & 8) then double : l42 fi,
        if (opts & 0x10) then byte : l7 fi,
        if (opts & 0x20) then byte : l71 fi,
        if (opts & 0x40) then byte : l72 fi,
        if (opts & 0x80) then point(FALSE) : l11 fi,   /*?*/
        if (opts & 0x100) then point(TRUE) : l210 fi,
        if (opts & 0x200) then double : l38 fi        /*?*/
      case 16:   /* ATTRIB */
        point(FALSE) : l10,
        double : l40,
        string : l1,
        string : l2,
        byte : l70,
        if (opts & 1) then byte : l73 fi,           /*?*/
        if (opts & 2) then double : l50 fi,         /*?*/
        if (opts & 4) then double : l41 fi,
        if (opts & 8) then double : l42 fi,
        if (opts & 0x10) then byte : l7 fi,
        if (opts & 0x20) then byte : l71 fi,
        if (opts & 0x40) then byte : l72 fi,
        if (opts & 0x80) then point(FALSE) : l11 fi,   /*?*/
        if (opts & 0x100) then point(TRUE) : l210 fi,
        if (opts & 0x200) then double : l38 fi        /*?*/
      case 17:   /* S/BEND */
        long
      case 19:   /* PLINE */
        if (opts & 1) then byte : l70 fi,
        if (opts & 2) then double : l40 fi,                   /*?*/
        if (opts & 4) then byte : l71 fi,         /*?*/
        if (opts & 8) then byte : l72 fi,         /*?*/
        if (opts & 0x10) then byte : l73 fi,         /*?*/
        if (opts & 0x20) then byte : l74 fi,         /*?*/
        if (opts & 0x40) then byte : l75 fi         /*?*/
      case 20:   /* VERTEX */
        point(FALSE) : l10,
        if (opts & 1) then double : l40 fi,           /*?*/
        if (opts & 2) then double : l41 fi,           /*?*/
        if (opts & 4) then byte : l70 fi,             /*?*/
        if (opts & 8) then double : l50 fi           /*?*/
      case 22:   /* 3DFACE */
        point(!(flag & 4)) : l10,
        point(!(flag & 4)) : l11,
        point(!(flag & 4)) : l12,
        point(!(flag & 4)) : l13
      case 23:   /* DIM */
        word : l1,
        point(TRUE) : l10,
        point(FALSE) : l11,   /*?*/
        if (opts & 2) then byte : l70 fi,
        if (opts & 1) then point(TRUE) : l12 fi,    /*?*/
        if (opts & 4) then string : l1 fi,
        if (opts & 8) then point(TRUE) : l13 fi,
        if (opts & 0x10) then point(TRUE) : l14 fi,
        if (opts & 0x20) then point(TRUE) : l15 fi,
        if (opts & 0x40) then point(TRUE) : l16 fi,
        if (opts & 0x80) then double : l40 fi,
        if (opts & 0x100) then double : l50 fi,
        if (opts & 0x200) then double : l51 fi,
        if (opts & 0x400) then double : l52 fi,
        if (opts & 0x800) then double : l53 fi
      case 24:   /* VPORT */
        point(TRUE) : l10,
        double : l40,
        double : l41,
        word : l68
      endswitch
      check_2
    )
  )* : entities.
Still need to define xdata and handle.


home and email | Binary File Format | How to crack a Binary File Format