decode_preR13_section (Dwg_Section_Type_r11 id, Bit_Chain *restrict dat,
                       Dwg_Data *restrict dwg)
{
  Dwg_Section *tbl = &dwg->header.section[id];
  int i;
  BITCODE_BL vcount;
  int error = 0;
  long unsigned int num = dwg->num_objects;
  long unsigned int old_size = num * sizeof (Dwg_Object);
  long unsigned int size = tbl->number * sizeof (Dwg_Object);
  long unsigned int pos;

  if ((unsigned)tbl->number > 100000 || size > dat->size)
    {
      LOG_ERROR ("Invalid table number %ld for %-8s [%2d]", (long)tbl->number, tbl->name, id);
      return DWG_ERR_INVALIDDWG;
    }
  LOG_TRACE ("\ncontents table %-8s [%2d]: size:%-4u nr:%-3ld (0x%lx-0x%lx)\n",
             tbl->name, id, tbl->size, (long)tbl->number, (unsigned long)tbl->address,
             (unsigned long)(tbl->address + ((unsigned long long)tbl->number * tbl->size)))
  dat->byte = tbl->address;
  if ((unsigned long)(tbl->number * tbl->size) > dat->size - dat->byte)
    {
      LOG_ERROR ("Invalid table number %ld or size %ld for %-8s [%2d]", (long)tbl->number, (long)tbl->size,
                 tbl->name, id);
      return DWG_ERR_INVALIDDWG;
    }
  if (dwg->num_objects % REFS_PER_REALLOC == 0)
    dwg->object = realloc (dwg->object, old_size + size + REFS_PER_REALLOC);

    // TODO: move to a spec dwg_r11.spec, and dwg_decode_r11_NAME
#define PREP_TABLE(token)                                                     \
  Dwg_Object *obj = &dwg->object[num + i];                                    \
  Dwg_Object_##token *_obj = calloc (1, sizeof (Dwg_Object_##token));         \
  if (dat->byte > dat->size)                                                  \
    {                                                                         \
      free (_obj);                                                            \
      return DWG_ERR_INVALIDDWG;                                              \
    }                                                                         \
  obj->index = num + i;                                                       \
  obj->tio.object = calloc (1, sizeof (Dwg_Object_Object));                   \
  if (!_obj || !obj->tio.object)                                              \
    if (_obj) free (_obj);                                                    \
    return DWG_ERR_OUTOFMEM;                                                  \
  obj->tio.object->tio.token = _obj;                                          \
  obj->tio.object->objid = obj->index;                                        \
  obj->supertype = DWG_SUPERTYPE_OBJECT;                                      \
  obj->parent = dwg;                                                          \
  obj->name = obj->dxfname = (char *)#token;                                  \
  obj->type = obj->fixedtype = DWG_TYPE_##token;                              \
  _obj->parent = obj->tio.object;                                             \
  obj->tio.object->dwg = obj->parent;                                         \
  obj->tio.object->objid = obj->index; /* obj ptr itself might move */        \
  LOG_TRACE ("\n-- table entry " #token " [%d]:\n", i)

#define CHK_ENDPOS                                                            \
  pos = tbl->address + ((long)(i + 1) * tbl->size);                           \
  if ((long)(pos - dat->byte) != 2)                                           \
    {                                                                         \
      LOG_WARN ("offset %ld", pos - dat->byte);                               \
    }                                                                         \
  dat->byte = pos

  switch (id)
    {

    case SECTION_BLOCK:
      for (i = 0; i < tbl->number; i++)
        {
          PREP_TABLE (BLOCK_HEADER);
          // TODO DXF 8: layer name
          FIELD_RC (flag, 70);
          FIELD_TF (name, 32, 2);
          FIELD_RS (used, 0);

          // TODO RD elevation 30, 2RD base_pt 10: 24
          FIELD_RC (block_scaling, 0);
          FIELD_CAST (num_owned, RS, BL, 0);
          FIELD_RC (flag2, 0);
          FIELD_CAST (num_inserts, RS, RL, 0);
          FIELD_RS (flag3, 0);
          CHK_ENDPOS;
        }
      break;

    case SECTION_LAYER:
      for (i = 0; i < tbl->number; i++)
        {
          PREP_TABLE (LAYER);

          FIELD_CAST (flag, RC, RS, 70); // 860
          FIELD_TF (name, 32, 2);
          FIELD_RS (used, 0);

          FIELD_RS (color_rs, 62); // color, off if negative
          FIELD_RS (ltype_rs, 6);  // style
          // FIELD_RS (crc, 0);
          CHK_ENDPOS;
        }
      break;

    // was a text STYLE table, became a STYLE object
    case SECTION_STYLE:
      for (i = 0; i < tbl->number; i++)
        {
          PREP_TABLE (STYLE);

          FIELD_RC (flag, 70);
          FIELD_TF (name, 32, 2);
          FIELD_RS (used, 0);

          FIELD_RD (fixed_height, 40); // ok
          FIELD_RD (width_factor, 41);
          FIELD_RD (oblique_ang, 50);
          FIELD_RC (generation, 71);
          FIELD_RD (last_height, 42);
          FIELD_TF (font_name, 64, 3);    // 8ed
          FIELD_TF (bigfont_name, 64, 4); // 92d
          CHK_ENDPOS;
        }
      break;

    case SECTION_LTYPE:
      for (i = 0; i < tbl->number; i++)
        {
          PREP_TABLE (LTYPE);

          FIELD_RC (flag, 70);
          FIELD_TF (name, 32, 2);
          FIELD_RS (used, 0);
          FIELD_TF (description, 48, 3);
          FIELD_RC (alignment, 72);
          FIELD_RC (num_dashes, 73);
          FIELD_VECTOR (dashes_r11, RD, num_dashes, 340);
          // ... 106 byte
          // 3, 40, 49, 74, 75, 340, 46, 50, 44, 45, 9

          CHK_ENDPOS;
        }
      break;

    case SECTION_VIEW:
      for (i = 0; i < tbl->number; i++)
        {
          PREP_TABLE (VIEW);

          FIELD_RC (flag, 70);
          FIELD_TF (name, 32, 2);
          FIELD_RS (used, 0);

          FIELD_RD (height, 40);
          FIELD_2RD (center, 10);
          FIELD_RD (width, 41);
          FIELD_3RD (target, 12);
          FIELD_3RD (direction, 11);
          FIELD_CAST (VIEWMODE, RS, 4BITS, 71);
          FIELD_RD (lens_length, 42);
          FIELD_RD (front_clip, 43);
          FIELD_RD (back_clip, 44);
          FIELD_RD (twist_angle, 50);
          CHK_ENDPOS;
        }
      break;

    case SECTION_UCS:
      for (i = 0; i < tbl->number; i++)
        {
          PREP_TABLE (UCS);

          FIELD_RC (flag, 70);
          FIELD_TF (name, 32, 2);
          FIELD_RS (used, 0);
          FIELD_2RD (origin, 10);
          FIELD_2RD (x_direction, 11);
          FIELD_2RD (y_direction, 12);

          CHK_ENDPOS;
        }
      break;

    case SECTION_VPORT:
      for (i = 0; i < tbl->number; i++)
        {
          PREP_TABLE (VPORT);

          FIELD_RC (flag, 70);
          FIELD_TF (name, 32, 2);
          FIELD_RS (used, 0);

          FIELD_RD (VIEWSIZE, 40);
          FIELD_RD (aspect_ratio, 41);
          FIELD_2RD (VIEWCTR, 12);
          FIELD_3RD (view_target, 17);
          FIELD_3RD (VIEWDIR, 16);
          FIELD_RD (view_twist, 50);
          FIELD_RD (lens_length, 42);
          FIELD_RD (front_clip, 43);
          FIELD_RD (back_clip, 33);
          FIELD_CAST (VIEWMODE, RS, 4BITS, 71);

          FIELD_2RD (lower_left, 10);
          FIELD_2RD (upper_right, 11);
          FIELD_RC (UCSFOLLOW, 71);
          FIELD_RS (circle_zoom, 72);
          FIELD_RC (FASTZOOM, 73);
          FIELD_RC (UCSICON, 74);
          FIELD_RC (GRIDMODE, 76);
          FIELD_2RD (GRIDUNIT, 15);
          FIELD_CAST (SNAPMODE, RS, B, 70); // 75
          FIELD_RC (SNAPSTYLE, 70);         // 77
          FIELD_RS (SNAPISOPAIR, 78);
          FIELD_RD (SNAPANG, 50);
          FIELD_2RD (SNAPBASE, 13);
          FIELD_2RD (SNAPUNIT, 14);
          // ... 74 byte

          CHK_ENDPOS;
        }
      break;

    case SECTION_APPID:
      for (i = 0; i < tbl->number; i++)
        {
          PREP_TABLE (APPID);

          FIELD_RC (flag, 70);
          FIELD_TF (name, 32, 2);
          FIELD_RS (used, 0);
          CHK_ENDPOS;
        }
      break;

    case SECTION_DIMSTYLE:
      for (i = 0; i < tbl->number; i++)
        {
          // unsigned long off;
          PREP_TABLE (DIMSTYLE); // d1f

          FIELD_RC (flag, 70);
          FIELD_TF (name, 32, 2);
          // off = dat->byte;
          FIELD_RS (used, 0);      // d40
          FIELD_RD (DIMSCALE, 40); // d42
          FIELD_RD (DIMASZ, 41);
          FIELD_RD (DIMEXO, 42);
          FIELD_RD (DIMDLI, 43);
          FIELD_RD (DIMEXE, 44);
          FIELD_RD (DIMRND, 45);
          FIELD_RD (DIMDLE, 46);
          FIELD_RD (DIMTP, 47);
          FIELD_RD (DIMTM, 48); // ok
          FIELD_RD (DIMTXT, 140);
          FIELD_RD (DIMCEN, 141); // ok
          FIELD_RD (DIMTSZ, 142);
          FIELD_RD (DIMALTF, 143);
          FIELD_RD (DIMLFAC, 144);
          FIELD_RD (DIMTVP, 145); // db2
          FIELD_RC (DIMTOL, 71);  // dba
          FIELD_RC (DIMLIM, 72);  // dbb
          FIELD_RC (DIMTIH, 73);
          FIELD_RC (DIMTOH, 74);
          FIELD_RC (DIMSE1, 75);
          FIELD_RC (DIMSE2, 76);
          FIELD_CAST (DIMTAD, RC, RS, 77); // ok
          FIELD_CAST (DIMZIN, RC, BS, 78); // dc1
          FIELD_RC (DIMALT, 170);
          FIELD_CAST (DIMALTD, RC, BS, 171); // ok
          FIELD_RC (DIMTOFL, 172);           // ok
          FIELD_RC (DIMSAH, 173);            // ok
          FIELD_RC (DIMTIX, 174);            // ok
          FIELD_RC (DIMSOXD, 175);           // ok
          FIELD_TF (DIMPOST, 16, 3);         // ok dc8
          FIELD_TF (DIMAPOST, 16, 4);        // dd8
          FIELD_TF (DIMBLK_T, 16, 5);        //?? unsupported by ODA
          FIELD_TF (DIMBLK1_T, 16, 6);       //?? unsupported by ODA
          FIELD_TF (DIMBLK2_T, 66, 7);       //?? unsupported by ODA
          // DEBUG_HERE; //e18
          // dat->byte += 50; //unknown: DIMSHO, DIMASO (global)
          FIELD_RS (DIMCLRD_N, 176); // e4a
          FIELD_RS (DIMCLRE_N, 177);
          FIELD_RS (DIMCLRT_N, 178); // e4e
          FIELD_RC (DIMUPT, 0);      //??
          FIELD_RD (DIMTFAC, 146);   // e51
          FIELD_RD (DIMGAP, 147);    // e59
          CHK_ENDPOS;                //-e63
        }
      break;

    case SECTION_VPORT_ENTITY:
      if (tbl->number)
        {
          LOG_WARN ("VPORT_ENTITY table");
        }
      break;

    case SECTION_HEADER_R11:
    default:
      LOG_ERROR ("Invalid table id %d", id);
      tbl->number = 0;
      break;
    }
  dwg->num_objects += tbl->number;
  dat->byte = tbl->address + (tbl->number * tbl->size);
  return error;
}
decode_preR13_section (Dwg_Section_Type_r11 id, Bit_Chain *restrict dat,
                       Dwg_Data *restrict dwg)
{
  Dwg_Section *tbl = &dwg->header.section[id];
  int i;
  BITCODE_BL vcount;
  int error = 0;
  long unsigned int num = dwg->num_objects;
  long unsigned int old_size = num * sizeof (Dwg_Object);
  long unsigned int size = tbl->number * sizeof (Dwg_Object);
  long unsigned int pos;

  if ((unsigned)tbl->number > 100000 || size > dat->size)
    {
      LOG_ERROR ("Invalid table number %ld for %-8s [%2d]", (long)tbl->number, tbl->name, id);
      return DWG_ERR_INVALIDDWG;
    }
  LOG_TRACE ("\ncontents table %-8s [%2d]: size:%-4u nr:%-3ld (0x%lx-0x%lx)\n",
             tbl->name, id, tbl->size, (long)tbl->number, (unsigned long)tbl->address,
             (unsigned long)(tbl->address + ((unsigned long long)tbl->number * tbl->size)))
  dat->byte = tbl->address;
  if ((unsigned long)(tbl->number * tbl->size) > dat->size - dat->byte)
    {
      LOG_ERROR ("Invalid table number %ld or size %ld for %-8s [%2d]", (long)tbl->number, (long)tbl->size,
                 tbl->name, id);
      return DWG_ERR_INVALIDDWG;
    }
  if (dwg->num_objects % REFS_PER_REALLOC == 0)
    dwg->object = realloc (dwg->object, old_size + size + REFS_PER_REALLOC);

     
#define PREP_TABLE(token)                                                     \
  Dwg_Object *obj = &dwg->object[num + i];                                    \
  Dwg_Object_##token *_obj = calloc (1, sizeof (Dwg_Object_##token));         \
  if (dat->byte > dat->size)                                                  \
    {                                                                         \
      free (_obj);                                                            \
      return DWG_ERR_INVALIDDWG;                                              \
    }                                                                         \
  obj->index = num + i;                                                       \
  obj->tio.object = calloc (1, sizeof (Dwg_Object_Object));                   \
  if (!_obj || !obj->tio.object)                                              \
    if (_obj) free (_obj);                                                    \
    return DWG_ERR_OUTOFMEM;                                                  \
  obj->tio.object->tio.token = _obj;                                          \
  obj->tio.object->objid = obj->index;                                        \
  obj->supertype = DWG_SUPERTYPE_OBJECT;                                      \
  obj->parent = dwg;                                                          \
  obj->name = obj->dxfname = (char *)#token;                                  \
  obj->type = obj->fixedtype = DWG_TYPE_##token;                              \
  _obj->parent = obj->tio.object;                                             \
  obj->tio.object->dwg = obj->parent;                                         \
  obj->tio.object->objid = obj->index;          \
  LOG_TRACE ("\n-- table entry " #token " [%d]:\n", i)

#define CHK_ENDPOS                                                            \
  pos = tbl->address + ((long)(i + 1) * tbl->size);                           \
  if ((long)(pos - dat->byte) != 2)                                           \
    {                                                                         \
      LOG_WARN ("offset %ld", pos - dat->byte);                               \
    }                                                                         \
  dat->byte = pos

  switch (id)
    {

    case SECTION_BLOCK:
      for (i = 0; i < tbl->number; i++)
        {
          PREP_TABLE (BLOCK_HEADER);
           
          FIELD_RC (flag, 70);
          FIELD_TF (name, 32, 2);
          FIELD_RS (used, 0);

           
          FIELD_RC (block_scaling, 0);
          FIELD_CAST (num_owned, RS, BL, 0);
          FIELD_RC (flag2, 0);
          FIELD_CAST (num_inserts, RS, RL, 0);
          FIELD_RS (flag3, 0);
          CHK_ENDPOS;
        }
      break;

    case SECTION_LAYER:
      for (i = 0; i < tbl->number; i++)
        {
          PREP_TABLE (LAYER);

          FIELD_CAST (flag, RC, RS, 70);  
          FIELD_TF (name, 32, 2);
          FIELD_RS (used, 0);

          FIELD_RS (color_rs, 62);  
          FIELD_RS (ltype_rs, 6);   
           
          CHK_ENDPOS;
        }
      break;

     
    case SECTION_STYLE:
      for (i = 0; i < tbl->number; i++)
        {
          PREP_TABLE (STYLE);

          FIELD_RC (flag, 70);
          FIELD_TF (name, 32, 2);
          FIELD_RS (used, 0);

          FIELD_RD (fixed_height, 40);  
          FIELD_RD (width_factor, 41);
          FIELD_RD (oblique_ang, 50);
          FIELD_RC (generation, 71);
          FIELD_RD (last_height, 42);
          FIELD_TF (font_name, 64, 3);     
          FIELD_TF (bigfont_name, 64, 4);  
          CHK_ENDPOS;
        }
      break;

    case SECTION_LTYPE:
      for (i = 0; i < tbl->number; i++)
        {
          PREP_TABLE (LTYPE);

          FIELD_RC (flag, 70);
          FIELD_TF (name, 32, 2);
          FIELD_RS (used, 0);
          FIELD_TF (description, 48, 3);
          FIELD_RC (alignment, 72);
          FIELD_RC (num_dashes, 73);
          FIELD_VECTOR (dashes_r11, RD, num_dashes, 340);
           
           

          CHK_ENDPOS;
        }
      break;

    case SECTION_VIEW:
      for (i = 0; i < tbl->number; i++)
        {
          PREP_TABLE (VIEW);

          FIELD_RC (flag, 70);
          FIELD_TF (name, 32, 2);
          FIELD_RS (used, 0);

          FIELD_RD (height, 40);
          FIELD_2RD (center, 10);
          FIELD_RD (width, 41);
          FIELD_3RD (target, 12);
          FIELD_3RD (direction, 11);
          FIELD_CAST (VIEWMODE, RS, 4BITS, 71);
          FIELD_RD (lens_length, 42);
          FIELD_RD (front_clip, 43);
          FIELD_RD (back_clip, 44);
          FIELD_RD (twist_angle, 50);
          CHK_ENDPOS;
        }
      break;

    case SECTION_UCS:
      for (i = 0; i < tbl->number; i++)
        {
          PREP_TABLE (UCS);

          FIELD_RC (flag, 70);
          FIELD_TF (name, 32, 2);
          FIELD_RS (used, 0);
          FIELD_2RD (origin, 10);
          FIELD_2RD (x_direction, 11);
          FIELD_2RD (y_direction, 12);

          CHK_ENDPOS;
        }
      break;

    case SECTION_VPORT:
      for (i = 0; i < tbl->number; i++)
        {
          PREP_TABLE (VPORT);

          FIELD_RC (flag, 70);
          FIELD_TF (name, 32, 2);
          FIELD_RS (used, 0);

          FIELD_RD (VIEWSIZE, 40);
          FIELD_RD (aspect_ratio, 41);
          FIELD_2RD (VIEWCTR, 12);
          FIELD_3RD (view_target, 17);
          FIELD_3RD (VIEWDIR, 16);
          FIELD_RD (view_twist, 50);
          FIELD_RD (lens_length, 42);
          FIELD_RD (front_clip, 43);
          FIELD_RD (back_clip, 33);
          FIELD_CAST (VIEWMODE, RS, 4BITS, 71);

          FIELD_2RD (lower_left, 10);
          FIELD_2RD (upper_right, 11);
          FIELD_RC (UCSFOLLOW, 71);
          FIELD_RS (circle_zoom, 72);
          FIELD_RC (FASTZOOM, 73);
          FIELD_RC (UCSICON, 74);
          FIELD_RC (GRIDMODE, 76);
          FIELD_2RD (GRIDUNIT, 15);
          FIELD_CAST (SNAPMODE, RS, B, 70);  
          FIELD_RC (SNAPSTYLE, 70);          
          FIELD_RS (SNAPISOPAIR, 78);
          FIELD_RD (SNAPANG, 50);
          FIELD_2RD (SNAPBASE, 13);
          FIELD_2RD (SNAPUNIT, 14);
           

          CHK_ENDPOS;
        }
      break;

    case SECTION_APPID:
      for (i = 0; i < tbl->number; i++)
        {
          PREP_TABLE (APPID);

          FIELD_RC (flag, 70);
          FIELD_TF (name, 32, 2);
          FIELD_RS (used, 0);
          CHK_ENDPOS;
        }
      break;

    case SECTION_DIMSTYLE:
      for (i = 0; i < tbl->number; i++)
        {
           
          PREP_TABLE (DIMSTYLE);  

          FIELD_RC (flag, 70);
          FIELD_TF (name, 32, 2);
           
          FIELD_RS (used, 0);       
          FIELD_RD (DIMSCALE, 40);  
          FIELD_RD (DIMASZ, 41);
          FIELD_RD (DIMEXO, 42);
          FIELD_RD (DIMDLI, 43);
          FIELD_RD (DIMEXE, 44);
          FIELD_RD (DIMRND, 45);
          FIELD_RD (DIMDLE, 46);
          FIELD_RD (DIMTP, 47);
          FIELD_RD (DIMTM, 48);  
          FIELD_RD (DIMTXT, 140);
          FIELD_RD (DIMCEN, 141);  
          FIELD_RD (DIMTSZ, 142);
          FIELD_RD (DIMALTF, 143);
          FIELD_RD (DIMLFAC, 144);
          FIELD_RD (DIMTVP, 145);  
          FIELD_RC (DIMTOL, 71);   
          FIELD_RC (DIMLIM, 72);   
          FIELD_RC (DIMTIH, 73);
          FIELD_RC (DIMTOH, 74);
          FIELD_RC (DIMSE1, 75);
          FIELD_RC (DIMSE2, 76);
          FIELD_CAST (DIMTAD, RC, RS, 77);  
          FIELD_CAST (DIMZIN, RC, BS, 78);  
          FIELD_RC (DIMALT, 170);
          FIELD_CAST (DIMALTD, RC, BS, 171);  
          FIELD_RC (DIMTOFL, 172);            
          FIELD_RC (DIMSAH, 173);             
          FIELD_RC (DIMTIX, 174);             
          FIELD_RC (DIMSOXD, 175);            
          FIELD_TF (DIMPOST, 16, 3);          
          FIELD_TF (DIMAPOST, 16, 4);         
          FIELD_TF (DIMBLK_T, 16, 5);         
          FIELD_TF (DIMBLK1_T, 16, 6);        
          FIELD_TF (DIMBLK2_T, 66, 7);        
           
           
          FIELD_RS (DIMCLRD_N, 176);  
          FIELD_RS (DIMCLRE_N, 177);
          FIELD_RS (DIMCLRT_N, 178);  
          FIELD_RC (DIMUPT, 0);       
          FIELD_RD (DIMTFAC, 146);    
          FIELD_RD (DIMGAP, 147);     
          CHK_ENDPOS;                 
        }
      break;

    case SECTION_VPORT_ENTITY:
      if (tbl->number)
        {
          LOG_WARN ("VPORT_ENTITY table");
        }
      break;

    case SECTION_HEADER_R11:
    default:
      LOG_ERROR ("Invalid table id %d", id);
      tbl->number = 0;
      break;
    }
  dwg->num_objects += tbl->number;
  dat->byte = tbl->address + (tbl->number * tbl->size);
  return error;
}