dwg_decode_xdata (Bit_Chain *restrict dat, Dwg_Object_XRECORD *restrict obj,
                  BITCODE_BL size)
{
  Dwg_Resbuf *rbuf, *root = NULL, *curr = NULL;
  unsigned char codepage;
  long unsigned int end_address, curr_address;
  BITCODE_BL i, num_xdata = 0;
  BITCODE_RS length;
  int error;

  static int cnt = 0;
  cnt++;

  end_address = dat->byte + (unsigned long int)size;
  if (obj->parent && obj->parent->objid)
    {
      Dwg_Data *dwg = obj->parent->dwg;
      Dwg_Object *o = &dwg->object[obj->parent->objid];
      if (size > o->size)
        {
          LOG_ERROR ("Invalid XRECORD.num_databytes " FORMAT_BL, size);
          obj->num_databytes = 0;
          return NULL;
        }
    }
  LOG_INSANE ("xdata:\n");
  LOG_INSANE_TF (&dat->chain[dat->byte], (int)size);
  curr_address = dat->byte;

  while (dat->byte < end_address)
    {
      enum RES_BUF_VALUE_TYPE vtype;
      rbuf = (Dwg_Resbuf *)calloc (1, sizeof (Dwg_Resbuf));
      if (!rbuf)
        {
          LOG_ERROR ("Out of memory");
          dwg_free_xdata_resbuf (root);
          return NULL;
        }
      rbuf->next = NULL;
      rbuf->type = bit_read_RS (dat);
      if (dat->byte == curr_address)
        {
          // no advance, by dat overflow
          dat->byte = end_address;
          break;
        }
      if (rbuf->type < 0 || rbuf->type >= 2000)
        {
          LOG_ERROR ("Invalid xdata type %d [RS]", rbuf->type);
          dat->byte = end_address;
          break;
        }
      vtype = get_base_value_type (rbuf->type);
      switch (vtype)
        {
        case VT_STRING:
          PRE (R_2007)
          {
            length = rbuf->value.str.size = bit_read_RS (dat);
            rbuf->value.str.codepage = bit_read_RC (dat);
            if (length > size)
              break;
            rbuf->value.str.u.data = bit_read_TF (dat, length);
            LOG_TRACE ("xdata[%d]: \"%s\" [TF %d %d]\n", num_xdata,
                       rbuf->value.str.u.data, length, rbuf->type);
          }
          LATER_VERSIONS
          {
            length = rbuf->value.str.size = bit_read_RS (dat);
            if (length > 0 && length < size)
              {
                rbuf->value.str.u.wdata = calloc (length + 1, 2);
                if (!rbuf->value.str.u.wdata)
                  {
                    LOG_ERROR ("Out of memory");
                    if (root)
                      {
                        dwg_free_xdata_resbuf (root);
                        if (rbuf)
                          free (rbuf);
                      }
                    else
                      dwg_free_xdata_resbuf (rbuf);
                    return NULL;
                  }
                for (i = 0; i < length; i++)
                  rbuf->value.str.u.wdata[i] = bit_read_RS (dat);
                rbuf->value.str.u.wdata[i] = '\0';
                LOG_TRACE_TU ("xdata", rbuf->value.str.u.wdata, rbuf->type);
              }
          }
          break;
        case VT_REAL:
          rbuf->value.dbl = bit_read_RD (dat);
          LOG_TRACE ("xdata[%d]: %f [RD %d]\n", num_xdata, rbuf->value.dbl,
                     rbuf->type);
          break;
        case VT_BOOL:
        case VT_INT8:
          rbuf->value.i8 = bit_read_RC (dat);
          LOG_TRACE ("xdata[%d]: %d [RC %d]\n", num_xdata, (int)rbuf->value.i8,
                     rbuf->type);
          break;
        case VT_INT16:
          rbuf->value.i16 = bit_read_RS (dat);
          LOG_TRACE ("xdata[%d]: %d [RS %d]\n", num_xdata,
                     (int)rbuf->value.i16, rbuf->type);
          break;
        case VT_INT32:
          rbuf->value.i32 = bit_read_RL (dat);
          LOG_TRACE ("xdata[%d]: %d [RL %d]\n", num_xdata,
                     (int)rbuf->value.i32, rbuf->type);
          break;
        case VT_INT64:
          rbuf->value.i64 = bit_read_BLL (dat);
          LOG_TRACE ("xdata[%d]: " FORMAT_BLL " [BLL %d]\n", num_xdata,
                     rbuf->value.i64, rbuf->type);
          break;
        case VT_POINT3D:
          rbuf->value.pt[0] = bit_read_RD (dat);
          rbuf->value.pt[1] = bit_read_RD (dat);
          rbuf->value.pt[2] = bit_read_RD (dat);
          LOG_TRACE ("xdata[%d]: %f,%f,%f [3RD %d]\n", num_xdata,
                     rbuf->value.pt[0], rbuf->value.pt[1], rbuf->value.pt[2],
                     rbuf->type);
          break;
        case VT_BINARY:
          rbuf->value.str.size = bit_read_RC (dat);
          rbuf->value.str.u.data = bit_read_TF (dat, rbuf->value.str.size);
          LOG_TRACE ("xdata[%d]: [TF %d %d]", num_xdata, rbuf->value.str.size,
                     rbuf->type);
          LOG_TRACE_TF (rbuf->value.str.u.data, rbuf->value.str.size);
          break;
        case VT_HANDLE:
        case VT_OBJECTID:
          bit_read_fixed (dat, rbuf->value.hdl, 8);
          LOG_TRACE ("xdata[%d]: %X [H %d]\n", num_xdata,
                     (unsigned)*(uint64_t *)rbuf->value.hdl, rbuf->type);
          break;
        case VT_INVALID:
        default:
          LOG_ERROR ("Invalid group code in xdata[%d]: %d", num_xdata,
                     rbuf->type)
          dwg_free_xdata_resbuf (rbuf);
          dat->byte = end_address;
          obj->num_xdata = num_xdata;
          return root;
        }
      num_xdata++;

      if (!curr)
        {
          curr = root = rbuf;
        }
      else
        {
          curr->next = rbuf;
          curr = rbuf;
        }
      curr_address = dat->byte;
    }
  obj->num_xdata = num_xdata;
  return root;
}