dxf_read_file (const char *restrict filename, Dwg_Data *restrict dwg)
{
  int error;
  FILE *fp;
  struct stat attrib;
  size_t size;
  Bit_Chain dat = { 0 };
  Dwg_Version_Type version;

  loglevel = dwg->opts & DWG_OPTS_LOGLEVEL;

  if (!filename || stat (filename, &attrib))
    {
      LOG_ERROR ("File not found: %s\n", filename ? filename : "(null)")
      return DWG_ERR_IOERROR;
    }
  if (!(S_ISREG (attrib.st_mode)
#  ifndef _WIN32
        || S_ISLNK (attrib.st_mode)
#  endif
            ))
    {
      LOG_ERROR ("Error: %s\n", filename)
      return DWG_ERR_IOERROR;
    }
  fp = fopen (filename, "rb");
  if (!fp)
    {
      LOG_ERROR ("Could not open file: %s\n", filename)
      return DWG_ERR_IOERROR;
    }

  /* Load whole file into memory
   */
  version = dwg->header.version;
  memset (dwg, 0, sizeof (Dwg_Data));
  dwg->opts = loglevel | DWG_OPTS_INDXF;
  dwg->header.version = version;

  memset (&dat, 0, sizeof (Bit_Chain));
  dat.size = attrib.st_size;
  dat.chain = (unsigned char *)calloc (1, dat.size + 2);
  if (!dat.chain)
    {
      LOG_ERROR ("Not enough memory.\n");
      fclose (fp);
      return DWG_ERR_OUTOFMEM;
    }
  dat.byte = 0;
  dat.bit = 0;
  dat.from_version = dwg->header.from_version;
  dat.version = dwg->header.version;
  dat.opts = dwg->opts;

  size = fread (dat.chain, sizeof (char), dat.size, fp);
  fclose (fp);
  if (size != dat.size)
    {
      LOG_ERROR ("Could not read the entire file (%lu out of %lu): %s\n",
                 (long unsigned int)size, dat.size, filename)
      free (dat.chain);
      dat.chain = NULL;
      dat.size = 0;
      return DWG_ERR_IOERROR;
    }
  if (size < 256)
    {
      LOG_ERROR ("File %s too small, %lu byte.\n", filename,
                 (long unsigned int)size)
      return DWG_ERR_IOERROR;
    }
  // properly end the buffer for strtol()/... readers
  if (dat.chain[size-1] != '\n')
    {
      dat.chain[size] = '\n';
      dat.size++;
    }
  dat.chain[size] = '\0';

  /* Fail on DWG */
  if (!memcmp (dat.chain, "AC10", 4) ||
      !memcmp (dat.chain, "AC1.", 4) ||
      !memcmp (dat.chain, "AC2.10", 4) ||
      !memcmp (dat.chain, "MC0.0", 4))
    {
      LOG_ERROR ("This is a DWG, not a DXF file: %s\n", filename)
      free (dat.chain);
      dat.chain = NULL;
      dat.size = 0;
      return DWG_ERR_INVALIDDWG;
    }
  /* See if binary or ascii */
  if (!memcmp (dat.chain, "AutoCAD Binary DXF",
               sizeof ("AutoCAD Binary DXF") - 1))
    {
      dat.byte = 22;
      error = dwg_read_dxfb (&dat, dwg);
    }
  else
    error = dwg_read_dxf (&dat, dwg);

  dwg->opts |= (DWG_OPTS_INDXF | loglevel);
  if (error >= DWG_ERR_CRITICAL)
    {
      LOG_ERROR ("Failed to decode DXF file: %s\n", filename)
      free (dat.chain);
      dat.chain = NULL;
      dat.size = 0;
      return error;
    }

  // TODO: does dwg hold any char* pointers to the dat or are they all copied?
  free (dat.chain);
  dat.chain = NULL;
  dat.size = 0;

  return 0;
}
dxf_read_file (const char *restrict filename, Dwg_Data *restrict dwg)
{
  int error;
  FILE *fp;
  struct stat attrib;
  size_t size;
  Bit_Chain dat = { 0 };
  Dwg_Version_Type version;

  loglevel = dwg->opts & DWG_OPTS_LOGLEVEL;

  if (!filename || stat (filename, &attrib))
    {
      LOG_ERROR ("File not found: %s\n", filename ? filename : "(null)")
      return DWG_ERR_IOERROR;
    }
  if (!(S_ISREG (attrib.st_mode)
#  ifndef _WIN32
        || S_ISLNK (attrib.st_mode)
#  endif
            ))
    {
      LOG_ERROR ("Error: %s\n", filename)
      return DWG_ERR_IOERROR;
    }
  fp = fopen (filename, "rb");
  if (!fp)
    {
      LOG_ERROR ("Could not open file: %s\n", filename)
      return DWG_ERR_IOERROR;
    }

   
  version = dwg->header.version;
  memset (dwg, 0, sizeof (Dwg_Data));
  dwg->opts = loglevel | DWG_OPTS_INDXF;
  dwg->header.version = version;

  memset (&dat, 0, sizeof (Bit_Chain));
  dat.size = attrib.st_size;
  dat.chain = (unsigned char *)calloc (1, dat.size + 2);
  if (!dat.chain)
    {
      LOG_ERROR ("Not enough memory.\n");
      fclose (fp);
      return DWG_ERR_OUTOFMEM;
    }
  dat.byte = 0;
  dat.bit = 0;
  dat.from_version = dwg->header.from_version;
  dat.version = dwg->header.version;
  dat.opts = dwg->opts;

  size = fread (dat.chain, sizeof (char), dat.size, fp);
  fclose (fp);
  if (size != dat.size)
    {
      LOG_ERROR ("Could not read the entire file (%lu out of %lu): %s\n",
                 (long unsigned int)size, dat.size, filename)
      free (dat.chain);
      dat.chain = NULL;
      dat.size = 0;
      return DWG_ERR_IOERROR;
    }
  if (size < 256)
    {
      LOG_ERROR ("File %s too small, %lu byte.\n", filename,
                 (long unsigned int)size)
      return DWG_ERR_IOERROR;
    }
   
  if (dat.chain[size-1] != '\n')
    {
      dat.chain[size] = '\n';
      dat.size++;
    }
  dat.chain[size] = '\0';

   
  if (!memcmp (dat.chain, "AC10", 4) ||
      !memcmp (dat.chain, "AC1.", 4) ||
      !memcmp (dat.chain, "AC2.10", 4) ||
      !memcmp (dat.chain, "MC0.0", 4))
    {
      LOG_ERROR ("This is a DWG, not a DXF file: %s\n", filename)
      free (dat.chain);
      dat.chain = NULL;
      dat.size = 0;
      return DWG_ERR_INVALIDDWG;
    }
   
  if (!memcmp (dat.chain, "AutoCAD Binary DXF",
               sizeof ("AutoCAD Binary DXF") - 1))
    {
      dat.byte = 22;
      error = dwg_read_dxfb (&dat, dwg);
    }
  else
    error = dwg_read_dxf (&dat, dwg);

  dwg->opts |= (DWG_OPTS_INDXF | loglevel);
  if (error >= DWG_ERR_CRITICAL)
    {
      LOG_ERROR ("Failed to decode DXF file: %s\n", filename)
      free (dat.chain);
      dat.chain = NULL;
      dat.size = 0;
      return error;
    }

   
  free (dat.chain);
  dat.chain = NULL;
  dat.size = 0;

  return 0;
}