(root)/
libredwg-0.13/
src/
out_dxfb.c
       1  /*****************************************************************************/
       2  /*  LibreDWG - free implementation of the DWG file format                    */
       3  /*                                                                           */
       4  /*  Copyright (C) 2018-2021 Free Software Foundation, Inc.                   */
       5  /*                                                                           */
       6  /*  This library is free software, licensed under the terms of the GNU       */
       7  /*  General Public License as published by the Free Software Foundation,     */
       8  /*  either version 3 of the License, or (at your option) any later version.  */
       9  /*  You should have received a copy of the GNU General Public License        */
      10  /*  along with this program.  If not, see <http://www.gnu.org/licenses/>.    */
      11  /*****************************************************************************/
      12  
      13  /*
      14   * out_dxfb.c: write as Binary DXF
      15   * Does not work yet.
      16   * written by Reini Urban
      17   */
      18  
      19  #include "config.h"
      20  #include <stdio.h>
      21  #include <stdlib.h>
      22  #include <string.h>
      23  #include <assert.h>
      24  
      25  #define IS_DXF
      26  #include "common.h"
      27  #include "bits.h"
      28  #include "dwg.h"
      29  #include "decode.h"
      30  #include "decode_r11.h"
      31  #include "out_dxf.h"
      32  
      33  static unsigned int loglevel;
      34  #define DWG_LOGLEVEL loglevel
      35  #include "logging.h"
      36  
      37  /* the current version per spec block. */
      38  static unsigned int cur_ver = 0;
      39  static char buf[4096];
      40  static BITCODE_BL rcount1, rcount2;
      41  
      42  // imported
      43  char *dwg_obj_table_get_name (const Dwg_Object *restrict obj,
      44                                int *restrict error);
      45  #ifndef _DWG_API_H_
      46  Dwg_Object *dwg_obj_generic_to_object (const void *restrict obj,
      47                                         int *restrict error);
      48  #endif
      49  
      50  // private
      51  static int dxfb_common_entity_handle_data (Bit_Chain *restrict dat,
      52                                             const Dwg_Object *restrict obj);
      53  static int dwg_dxfb_object (Bit_Chain *restrict dat,
      54                              const Dwg_Object *restrict obj, int *restrict);
      55  static int dxfb_3dsolid (Bit_Chain *restrict dat,
      56                           const Dwg_Object *restrict obj,
      57                           Dwg_Entity_3DSOLID *restrict _obj);
      58  /*static void dxfb_cvt_tablerecord (Bit_Chain *restrict dat,
      59                                    const Dwg_Object *restrict obj,
      60                                    char *restrict name, const int dxf); */
      61  
      62  /*--------------------------------------------------------------------------------
      63   * MACROS
      64   */
      65  
      66  #define ACTION dxfb
      67  
      68  #define FMT_H "%" PRIX64
      69  #define FIELD(nam, type)
      70  #define FIELDG(nam, type, dxf)                                                \
      71    if (dxf)                                                                    \
      72      {                                                                         \
      73        FIELD_##type (nam, dxf);                                                \
      74      }
      75  #define SUB_FIELD(o, nam, type, dxf) FIELDG (o.nam, type, dxf)
      76  
      77  #define HEADER_VALUE(nam, type, dxf, value)                                   \
      78    if (dxf)                                                                    \
      79      {                                                                         \
      80        GROUP (9);                                                              \
      81        fprintf (dat->fh, "$%s%c", #nam, 0);                                    \
      82        VALUE_##type (value, dxf);                                              \
      83      }
      84  
      85  #define HEADER_VAR(nam, type, dxf)                                            \
      86    HEADER_VALUE (nam, type, dxf, dwg->header_vars.nam)
      87  #define HEADER_VALUE_TV(nam, dxf, value) HEADER_VALUE (nam, TV, dxf, value)
      88  #define HEADER_VALUE_TU(nam, dxf, value) HEADER_VALUE (nam, TU, dxf, value)
      89  #define HEADER_VALUE_TU0(nam, dxf, value)                                     \
      90    if (dxf && value && !bit_empty_T (dat, (BITCODE_T)value))                   \
      91      {                                                                         \
      92        HEADER_VALUE (nam, TU, dxf, value);                                     \
      93      }
      94  
      95  #define FIELD_CAST(nam, type, cast, dxf) FIELDG (nam, cast, dxf)
      96  #define SUB_FIELD_CAST(o, nam, type, cast, dxf) FIELDG (o.nam, cast, dxf)
      97  #define FIELD_TRACE(nam, type)
      98  #define VALUE_TV(value, dxf)                                                  \
      99    {                                                                           \
     100      GROUP (dxf);                                                              \
     101      fprintf (dat->fh, "%s%c", value, 0);                                      \
     102    }
     103  #define VALUE_TV0(value, dxf)                                                 \
     104    if (dxf && value && *value)                                                 \
     105      {                                                                         \
     106        GROUP (dxf);                                                            \
     107        fprintf (dat->fh, "%s%c", value, 0);                                    \
     108      }
     109  #define VALUE_TU(wstr, dxf)                                                   \
     110    {                                                                           \
     111      if (dxf)                                                                  \
     112        {                                                                       \
     113          char *_u8 = bit_convert_TU ((BITCODE_TU)wstr);                        \
     114          GROUP (dxf);                                                          \
     115          if (_u8)                                                              \
     116            fprintf (dat->fh, "%s%c", _u8, 0);                                  \
     117          else                                                                  \
     118            fprintf (dat->fh, "%c", 0);                                         \
     119          free (_u8);                                                           \
     120        }                                                                       \
     121    }
     122  #define VALUE_TFF(str, dxf) VALUE_TV (str, dxf)
     123  #define VALUE_BINARY(value, size, dxf)                                        \
     124    {                                                                           \
     125      long _len = (long)(size);                                                 \
     126      do                                                                        \
     127        {                                                                       \
     128          short j;                                                              \
     129          long _l = _len > 127 ? 127 : _len;                                    \
     130          GROUP (dxf);                                                          \
     131          if (value)                                                            \
     132            for (j = 0; j < _l; j++)                                            \
     133              {                                                                 \
     134                fprintf (dat->fh, "%c", value[j]);                              \
     135              }                                                                 \
     136          fprintf (dat->fh, "%c", '\0');                                        \
     137          _len -= 127;                                                          \
     138        }                                                                       \
     139      while (_len > 127);                                                       \
     140    }
     141  #define FIELD_BINARY(name, size, dxf) VALUE_BINARY (_obj->name, size, dxf)
     142  
     143  #define FIELD_VALUE(nam) _obj->nam
     144  #define ANYCODE -1
     145  // a null-terminated string of the value as %X
     146  #define VALUE_HANDLE(ref, nam, handle_code, dxf)                              \
     147    if (dxf)                                                                    \
     148      {                                                                         \
     149        char _s[18];                                                            \
     150        snprintf (_s, sizeof (_s), FMT_H, ref ? ref->absolute_ref : 0UL);       \
     151        _s[sizeof (_s) - 1] = '\0';                                             \
     152        VALUE_TV (_s, dxf);                                                     \
     153      }
     154  // TODO: try to resolve the handle. rather write 0 than in invalid handle:
     155  // if (_obj->nam->obj) ...
     156  #define FIELD_HANDLE(nam, handle_code, dxf)                                   \
     157    VALUE_HANDLE (_obj->nam, nam, handle_code, dxf)
     158  #define FIELD_HANDLE0(nam, handle_code, dxf)                                  \
     159    if (dxf && _obj->nam && _obj->nam->absolute_ref)                            \
     160      {                                                                         \
     161        FIELD_HANDLE (nam, handle_code, dxf);                                   \
     162      }
     163  #define SUB_FIELD_HANDLE(o, nam, handle_code, dxf)                            \
     164    VALUE_HANDLE (_obj->o.nam, nam, handle_code, dxf)
     165  #define SUB_FIELD_HANDLE0(o, nam, handle_code, dxf)                           \
     166    if (dxf && _obj->o.nam && _obj->o.nam->absolute_ref)                        \
     167      {                                                                         \
     168        VALUE_HANDLE (_obj->o.nam, nam, handle_code, dxf)                       \
     169      }
     170  
     171  #define GROUP(code)                                                           \
     172    if (dat->version < R_14)                                                    \
     173      {                                                                         \
     174        if (code >= 1000)                                                       \
     175          {                                                                     \
     176            uint16_t icode = (uint16_t)(code);                                  \
     177            fputc (0xff, dat->fh);                                              \
     178            fwrite (&icode, 2, 1, dat->fh);                                     \
     179          }                                                                     \
     180        else                                                                    \
     181          {                                                                     \
     182            uint8_t icode = (uint8_t)((code)&0xff);                             \
     183            fwrite (&icode, 1, 1, dat->fh);                                     \
     184          }                                                                     \
     185      }                                                                         \
     186    else                                                                        \
     187      {                                                                         \
     188        uint16_t icode = (uint16_t)(code);                                      \
     189        fwrite (&icode, 2, 1, dat->fh);                                         \
     190      }
     191  #define FIELD_TV(nam, dxf)                                                    \
     192    if (_obj->nam != NULL && dxf != 0)                                          \
     193      {                                                                         \
     194        VALUE_TV (_obj->nam, dxf)                                               \
     195      }
     196  #define FIELD_TU(nam, dxf)                                                    \
     197    if (_obj->nam != NULL && dxf != 0)                                          \
     198      {                                                                         \
     199        VALUE_TU (_obj->nam, dxf)                                               \
     200      }
     201  #define VALUE_T(value, dxf)                                                   \
     202    {                                                                           \
     203      if (IS_FROM_TU (dat))                                                     \
     204        {                                                                       \
     205          VALUE_TU (value, dxf)                                                 \
     206        }                                                                       \
     207      else                                                                      \
     208        {                                                                       \
     209          VALUE_TV ((char *)value, dxf)                                         \
     210        }                                                                       \
     211    }
     212  #define VALUE_T0(value, dxf)                                                  \
     213    if (!bit_empty_T (dat, value))                                              \
     214      VALUE_T (value, dxf)
     215  #define FIELD_T(nam, dxf)                                                     \
     216    {                                                                           \
     217      if (IS_FROM_TU (dat))                                                     \
     218        {                                                                       \
     219          FIELD_TU (nam, dxf)                                                   \
     220        }                                                                       \
     221      else                                                                      \
     222        {                                                                       \
     223          FIELD_TV (nam, dxf)                                                   \
     224        }                                                                       \
     225    }
     226  #define FIELD_TF(nam, len, dxf) VALUE_TV (_obj->nam, dxf)
     227  #define FIELD_TFF(nam, len, dxf) VALUE_TV (_obj->nam, dxf)
     228  
     229  // skip if 0
     230  #define FIELD_RD0(nam, dxf) FIELD_BD0 (nam, dxf)
     231  #define FIELD_BD0(nam, dxf)                                                   \
     232    {                                                                           \
     233      if (_obj->nam != 0.0)                                                     \
     234        FIELD_BD (nam, dxf)                                                     \
     235    }
     236  // for scale (1.0, 1.0, 1.0) and width_factor
     237  #define FIELD_RD1(nam, dxf) FIELD_BD1 (nam, dxf)
     238  #define FIELD_BD1(nam, dxf)                                                   \
     239    {                                                                           \
     240      if (_obj->nam != 1.0)                                                     \
     241        FIELD_BD (nam, dxf)                                                     \
     242    }
     243  #define FIELD_BL0(nam, dxf)                                                   \
     244    {                                                                           \
     245      if (_obj->nam != 0)                                                       \
     246        FIELD_BL (nam, dxf)                                                     \
     247    }
     248  #define SUB_FIELD_BL0(o, nam, dxf)                                            \
     249    {                                                                           \
     250      if (_obj->o.nam != 0)                                                     \
     251        SUB_FIELD_BL (o, nam, dxf)                                              \
     252    }
     253  #define FIELD_BS0(nam, dxf)                                                   \
     254    {                                                                           \
     255      if (_obj->nam != 0)                                                       \
     256        FIELD_BS (nam, dxf)                                                     \
     257    }
     258  #define FIELD_BS1(nam, dxf)                                                   \
     259    {                                                                           \
     260      if (_obj->nam != 1)                                                       \
     261        FIELD_BS (nam, dxf)                                                     \
     262    }
     263  #define FIELD_B0(nam, dxf)                                                    \
     264    {                                                                           \
     265      if (_obj->nam)                                                            \
     266        FIELD_B (nam, dxf)                                                      \
     267    }
     268  #define FIELD_RC0(nam, dxf)                                                   \
     269    {                                                                           \
     270      if (_obj->nam != 0)                                                       \
     271        FIELD_RC (nam, dxf)                                                     \
     272    }
     273  #define FIELD_RS0(nam, dxf)                                                   \
     274    {                                                                           \
     275      if (_obj->nam != 0)                                                       \
     276        FIELD_RS (nam, dxf)                                                     \
     277    }
     278  #define FIELD_RL0(nam, dxf)                                                   \
     279    {                                                                           \
     280      if (_obj->nam != 0)                                                       \
     281        FIELD_RL (nam, dxf)                                                     \
     282    }
     283  #define FIELD_BT0(nam, dxf)                                                   \
     284    {                                                                           \
     285      if (_obj->nam != 0)                                                       \
     286        FIELD_BT (nam, dxf)                                                     \
     287    }
     288  #define FIELD_T0(nam, dxf)                                                    \
     289    if (!bit_empty_T (dat, _obj->nam))                                          \
     290      {                                                                         \
     291        FIELD_T (nam, dxf)                                                      \
     292      }
     293  #define FIELD_TV0(nam, dxf) VALUE_TV0 (_obj->nam, dxf)
     294  
     295  #define HEADER_TV(nam, dxf)                                                   \
     296    {                                                                           \
     297      HEADER_9 (nam);                                                           \
     298      VALUE_TV (dwg->header_vars.nam, dxf);                                     \
     299    }
     300  #define HEADER_TU(nam, dxf)                                                   \
     301    {                                                                           \
     302      HEADER_9 (nam);                                                           \
     303      VALUE_TU (dwg->header_vars.nam, dxf);                                     \
     304    }
     305  #define HEADER_T(nam, dxf)                                                    \
     306    {                                                                           \
     307      HEADER_9 (nam);                                                           \
     308      VALUE_T (dwg->header_vars.nam, dxf);                                      \
     309    }
     310  #define HEADER_T0(nam, dxf)                                                   \
     311    if (dxf && !bit_empty_T (dat, _obj->nam))                                   \
     312      {                                                                         \
     313        HEADER_9 (nam);                                                         \
     314        VALUE_T (_obj->nam, dxf);                                               \
     315      }
     316  #define HEADER_VALUE_T(nam, dxf, value)                                       \
     317    if (dxf)                                                                    \
     318      {                                                                         \
     319        HEADER_9 (nam);                                                         \
     320        if (IS_FROM_TU (dat))                                                   \
     321          VALUE_T (value, dxf)                                                  \
     322        else                                                                    \
     323          VALUE_TV ((char *)value, dxf)                                         \
     324      }
     325  #define HEADER_VALUE_T0(nam, dxf, value)                                      \
     326    if (dxf && !bit_empty_T (dat, value))                                       \
     327      {                                                                         \
     328        HEADER_9 (nam);                                                         \
     329        if (IS_FROM_TU (dat))                                                   \
     330          VALUE_T (value, dxf)                                                  \
     331        else                                                                    \
     332          VALUE_TV ((char *)value, dxf)                                         \
     333      }
     334  #define POINT_3D(nam, var, c1, c2, c3)                                        \
     335    {                                                                           \
     336      VALUE_RD (dwg->var.x, c1);                                                \
     337      VALUE_RD (dwg->var.y, c2);                                                \
     338      VALUE_RD (dwg->var.z, c3);                                                \
     339    }
     340  #define POINT_2D(nam, var, c1, c2)                                            \
     341    {                                                                           \
     342      VALUE_RD (dwg->var.x, c1);                                                \
     343      VALUE_RD (dwg->var.x, c2);                                                \
     344    }
     345  #define HEADER_3D(nam)                                                        \
     346    {                                                                           \
     347      HEADER_9 (nam);                                                           \
     348      POINT_3D (nam, header_vars.nam, 10, 20, 30);                              \
     349    }
     350  #define HEADER_2D(nam)                                                        \
     351    {                                                                           \
     352      HEADER_9 (nam);                                                           \
     353      POINT_2D (nam, header_vars.nam, 10, 20);                                  \
     354    }
     355  #define SECTION(token)                                                        \
     356    VALUE_TV ("SECTION", 0);                                                    \
     357    VALUE_TV (#token, 2)
     358  #define ENDSEC() VALUE_TV ("ENDSEC", 0)
     359  #define TABLE(token)                                                          \
     360    VALUE_TV ("TABLE", 0);                                                      \
     361    VALUE_TV (#token, 2)
     362  #define ENDTAB() VALUE_TV ("ENDTAB", 0)
     363  #define RECORD(token) VALUE_TV (#token, 0)
     364  #define SUBCLASS(text)                                                        \
     365    if (dat->version >= R_13b1)                                                 \
     366      {                                                                         \
     367        VALUE_TV (#text, 100)                                                   \
     368      }
     369  
     370  /*
     371  #define VALUE(code, value) \
     372    { \
     373      GCC30_DIAG_IGNORE (-Wformat-nonliteral) \
     374      snprintf (buf, 4096, "%3i\n%s\n", code, dxfb_format (code)); \
     375      fprintf(dat->fh, buf, value); \
     376      GCC_DIAG_RESTORE \
     377    }
     378   */
     379  
     380  #define FIELD_HANDLE_N(nam, vcount, handle_code, dxf)                         \
     381    FIELD_HANDLE (nam, handle_code, dxf)
     382  
     383  #define FIELD_B(nam, dxf) FIELD_RC (nam, dxf)
     384  #define FIELD_BB(nam, dxf) FIELD_RC (nam, dxf)
     385  #define FIELD_3B(nam, dxf) FIELD_RC (nam, dxf)
     386  #define FIELD_BS(nam, dxf) FIELD_RS (nam, dxf)
     387  #define FIELD_BL(nam, dxf) FIELD_RL (nam, dxf)
     388  #define HEADER_BLL(nam, dxf) HEADER_RLL (nam, dxf)
     389  #define FIELD_BD(nam, dxf) FIELD_RD (nam, dxf)
     390  
     391  #define HEADER_9(nam)                                                         \
     392    {                                                                           \
     393      GROUP (9);                                                                \
     394      fprintf (dat->fh, "$%s%c", #nam, 0);                                      \
     395    }
     396  #define VALUE(value, type, dxf) VALUE_##type (value, dxf)
     397  #define VALUE_B(value, dxf) VALUE_INT (value, dxf)
     398  #define VALUE_BB(value, dxf) VALUE_INT (value, dxf)
     399  #define VALUE_3B(value, dxf) VALUE_INT (value, dxf)
     400  #define VALUE_RCs(value, dxf) VALUE_INT (value, dxf)
     401  #define VALUE_BS(value, dxf) VALUE_INT (value, dxf)
     402  #define VALUE_BL(value, dxf) VALUE_INT (value, dxf)
     403  #define VALUE_BD(value, dxf) VALUE_RD (value, dxf)
     404  #define VALUE_RC(value, dxf)                                                  \
     405    {                                                                           \
     406      BITCODE_RC _c = (BITCODE_RC)(value);                                      \
     407      GROUP (dxf);                                                              \
     408      fwrite (&_c, 1, 1, dat->fh);                                              \
     409    }
     410  #define VALUE_RS(value, dxf)                                                  \
     411    {                                                                           \
     412      BITCODE_RS _s = (BITCODE_RS)(value);                                      \
     413      GROUP (dxf);                                                              \
     414      fwrite (&_s, 2, 1, dat->fh);                                              \
     415    }
     416  #define VALUE_RSd(value, dxf)                                                 \
     417    {                                                                           \
     418      BITCODE_RSd _s = (BITCODE_RSd)(value);                                    \
     419      GROUP (dxf);                                                              \
     420      fwrite (&_s, 2, 1, dat->fh);                                              \
     421    }
     422  #define VALUE_RL(value, dxf)                                                  \
     423    {                                                                           \
     424      BITCODE_RL _s = (BITCODE_RL)value;                                        \
     425      GROUP (dxf);                                                              \
     426      fwrite (&_s, 4, 1, dat->fh);                                              \
     427    }
     428  #define VALUE_RLL(value, dxf)                                                 \
     429    {                                                                           \
     430      BITCODE_RLL _s = (BITCODE_RLL)value;                                      \
     431      GROUP (dxf);                                                              \
     432      fwrite (&_s, 8, 1, dat->fh);                                              \
     433    }
     434  // most DXFB FIELD_RC are written as int16 actually
     435  // we need to check dwg_resbuf_value_type()
     436  #define FIELD_RC(nam, dxf) VALUE_INT (_obj->nam, dxf)
     437  #define VALUE_INT(value, dxf)                                                 \
     438    {                                                                           \
     439      if (dxf == 0)                                                             \
     440        VALUE_RS (value, dxf)                                                   \
     441      else                                                                      \
     442        switch (dwg_resbuf_value_type (dxf))                                    \
     443          {                                                                     \
     444          case DWG_VT_BOOL:                                                     \
     445          case DWG_VT_INT8:                                                     \
     446            VALUE_RC (value, dxf);                                              \
     447            break;                                                              \
     448          case DWG_VT_INT16:                                                    \
     449            VALUE_RS (value, dxf);                                              \
     450            break;                                                              \
     451          case DWG_VT_INT32:                                                    \
     452            VALUE_RL (value, dxf);                                              \
     453            break;                                                              \
     454          case DWG_VT_INT64:                                                    \
     455            VALUE_RLL (value, dxf);                                             \
     456            break;                                                              \
     457          case DWG_VT_STRING:                                                   \
     458          case DWG_VT_POINT3D:                                                  \
     459          case DWG_VT_REAL:                                                     \
     460          case DWG_VT_BINARY:                                                   \
     461          case DWG_VT_HANDLE:                                                   \
     462          case DWG_VT_OBJECTID:                                                 \
     463          case DWG_VT_INVALID:                                                  \
     464          default:                                                              \
     465            LOG_ERROR ("Unhandled VALUE_INT code %d", dxf);                     \
     466          }                                                                     \
     467    }
     468  
     469  #define VALUE_3BD(value, dxf)                                                 \
     470    {                                                                           \
     471      VALUE_RD (value.x, dxf);                                                  \
     472      VALUE_RD (value.y, dxf + 10);                                             \
     473      VALUE_RD (value.z, dxf + 20);                                             \
     474    }
     475  #define HEADER_RC(nam, dxf)                                                   \
     476    {                                                                           \
     477      HEADER_9 (nam);                                                           \
     478      VALUE_INT (dwg->header_vars.nam, dxf);                                    \
     479    }
     480  #define HEADER_RC0(nam, dxf)                                                  \
     481    if (dwg->header_vars.nam)                                                   \
     482      {                                                                         \
     483        HEADER_9 (nam);                                                         \
     484        VALUE_INT (dwg->header_vars.nam, dxf);                                  \
     485      }
     486  #define HEADER_RS0(nam, dxf)                                                  \
     487    if (dwg->header_vars.nam)                                                   \
     488      {                                                                         \
     489        HEADER_9 (nam);                                                         \
     490        VALUE_RS (dwg->header_vars.nam, dxf);                                   \
     491      }
     492  #define HEADER_B(nam, dxf) HEADER_RC (nam, dxf)
     493  #define FIELD_RS(nam, dxf) VALUE_INT (_obj->nam, dxf)
     494  #define HEADER_RS(nam, dxf)                                                   \
     495    {                                                                           \
     496      HEADER_9 (nam);                                                           \
     497      VALUE_RS (dwg->header_vars.nam, dxf);                                     \
     498    }
     499  #define HEADER_RSd(nam, dxf)                                                  \
     500    {                                                                           \
     501      HEADER_9 (nam);                                                           \
     502      VALUE_RSd (dwg->header_vars.nam, dxf);                                    \
     503    }
     504  #define VALUE_RD(value, dxf)                                                  \
     505    {                                                                           \
     506      double d = (value);                                                       \
     507      GROUP (dxf);                                                              \
     508      fwrite (&d, 8, 1, dat->fh);                                               \
     509    }
     510  #define FIELD_RD(nam, dxf) VALUE_RD (_obj->nam, dxf)
     511  #define HEADER_RD(nam, dxf)                                                   \
     512    {                                                                           \
     513      HEADER_9 (nam);                                                           \
     514      VALUE_RD (dwg->header_vars.nam, dxf);                                     \
     515    }
     516  
     517  #define FIELD_RL(nam, dxf) VALUE_INT (_obj->nam, dxf)
     518  #define HEADER_RL(nam, dxf)                                                   \
     519    {                                                                           \
     520      HEADER_9 (nam);                                                           \
     521      VALUE_RL (dwg->header_vars.nam, dxf);                                     \
     522    }
     523  
     524  #define HEADER_B(nam, dxf) HEADER_RC (nam, dxf)
     525  #define HEADER_BS(nam, dxf) HEADER_RS (nam, dxf)
     526  #define HEADER_BSd(nam, dxf) HEADER_RS (nam, dxf)
     527  #define HEADER_BD(nam, dxf) HEADER_RD (nam, dxf)
     528  #define HEADER_BL(nam, dxf) HEADER_RL (nam, dxf)
     529  #define HEADER_BLd(nam, dxf) HEADER_RL (nam, dxf)
     530  
     531  #define FIELD_DATAHANDLE(nam, code, dxf)                                      \
     532    {                                                                           \
     533      Dwg_Object_Ref *ref = _obj->nam;                                          \
     534      HEADER_9 (nam);                                                           \
     535      VALUE_H (ref ? ref->handleref.value : 0UL, dxf);                          \
     536    }
     537  // I would rather assume 8-byte LE
     538  #define VALUE_H(value, dxf)                                                   \
     539    if (dxf)                                                                    \
     540      {                                                                         \
     541        char _s[18];                                                            \
     542        snprintf (_s, sizeof (_s), FMT_H, (BITCODE_RLL)(value));                \
     543        _s[sizeof (_s) - 1] = '\0';                                             \
     544        VALUE_TV (_s, dxf);                                                     \
     545      }
     546  #define HEADER_H(nam, dxf)                                                    \
     547    if (dxf)                                                                    \
     548      {                                                                         \
     549        HEADER_9 (nam);                                                         \
     550        VALUE_HANDLE (dwg->header_vars.nam, nam, 0, dxf);                       \
     551      }
     552  #define HEADER_H0(nam, dxf)                                                   \
     553    if (dxf && dwg->header_vars.nam && dwg->header_vars.nam->absolute_ref)      \
     554      {                                                                         \
     555        HEADER_9 (nam);                                                         \
     556        VALUE_H (dwg->header_vars.nam->absolute_ref, dxf);                      \
     557      }
     558  
     559  #define HANDLE_NAME(nam, code, table)                                         \
     560    VALUE_HANDLE_NAME (dwg->header_vars.nam, dxf, table)
     561  // TODO: convert STANDARD to Standard?
     562  #define VALUE_HANDLE_NAME(value, dxf, table)                                  \
     563    {                                                                           \
     564      Dwg_Object_Ref *ref = value;                                              \
     565      if (ref && obj && obj->parent                                             \
     566          && (!ref->obj || ref->obj->supertype != DWG_SUPERTYPE_OBJECT          \
     567              || ref->obj->fixedtype != DWG_TYPE_##table))                      \
     568        ref->obj = dwg_resolve_handle (obj->parent, ref->absolute_ref);         \
     569      if (ref && ref->obj && ref->obj->supertype == DWG_SUPERTYPE_OBJECT        \
     570          && ref->obj->fixedtype == DWG_TYPE_##table)                           \
     571        {                                                                       \
     572          VALUE_TV (ref->obj->tio.object->tio.table->name, dxf)                 \
     573        }                                                                       \
     574      else                                                                      \
     575        VALUE_TV ("", dxf)                                                      \
     576    }
     577  #define FIELD_HANDLE_NAME(nam, dxf, table)                                    \
     578    VALUE_HANDLE_NAME (_obj->nam, dxf, table)
     579  #define SUB_FIELD_HANDLE_NAME(ob, nam, dxf, table)                            \
     580    VALUE_HANDLE_NAME (_obj->ob.nam, dxf, table)
     581  #define HEADER_HANDLE_NAME(nam, dxf, table)                                   \
     582    HEADER_9 (nam);                                                             \
     583    VALUE_HANDLE_NAME (dwg->header_vars.nam, dxf, table)
     584  
     585  #define FIELD_BLL(nam, dxf)                                                   \
     586    {                                                                           \
     587      BITCODE_BLL s = _obj->nam;                                                \
     588      GROUP (dxf);                                                              \
     589      fwrite (&s, 8, 1, dat->fh);                                               \
     590    }
     591  #define FIELD_RLL(nam, dxf) FIELD_BLL (nam, dxf)
     592  #define HEADER_RLL(nam, dxf)                                                  \
     593    {                                                                           \
     594      GROUP (9);                                                                \
     595      fprintf (dat->fh, "$%s%c", #nam, 0);                                      \
     596      FIELD_BLL (nam, dxf);                                                     \
     597    }
     598  
     599  #define FIELD_MC(nam, dxf) FIELD_RC (nam, dxf)
     600  #define FIELD_MS(nam, dxf) FIELD_RS (nam, dxf)
     601  #define FIELD_BT(nam, dxf) FIELD_BD (nam, dxf);
     602  #define FIELD_4BITS(nam, dxf) FIELD_RC (nam, dxf)
     603  #define FIELD_BE(nam, dxf)                                                    \
     604    {                                                                           \
     605      if (dxf                                                                   \
     606          && !(_obj->nam.x == 0.0 && _obj->nam.y == 0.0 && _obj->nam.z == 1.0)) \
     607        FIELD_3RD (nam, dxf)                                                    \
     608    }
     609  #define FIELD_DD(nam, _default, dxf) FIELD_RD (nam, dxf)
     610  #define FIELD_2DD(nam, def, dxf)                                              \
     611    if (dxf)                                                                    \
     612      {                                                                         \
     613        FIELD_DD (nam.x, FIELD_VALUE (def.x), dxf);                             \
     614        FIELD_DD (nam.y, FIELD_VALUE (def.y), dxf + 10);                        \
     615      }
     616  #define FIELD_3DD(nam, def, dxf)                                              \
     617    if (dxf)                                                                    \
     618      {                                                                         \
     619        FIELD_DD (nam.x, FIELD_VALUE (def.x), dxf);                             \
     620        FIELD_DD (nam.y, FIELD_VALUE (def.y), dxf + 10);                        \
     621        FIELD_DD (nam.z, FIELD_VALUE (def.z), dxf + 20);                        \
     622      }
     623  #define FIELD_2RD(nam, dxf)                                                   \
     624    if (dxf)                                                                    \
     625      {                                                                         \
     626        FIELD_RD (nam.x, dxf);                                                  \
     627        FIELD_RD (nam.y, dxf + 10);                                             \
     628      }
     629  #define FIELD_2RD0(nam, dxf)                                                  \
     630    if (dxf && _obj->nam.x != 0.0 && _obj->nam.y != 0.0)                        \
     631      {                                                                         \
     632        FIELD_RD (nam.x, dxf);                                                  \
     633        FIELD_RD (nam.y, dxf + 10);                                             \
     634      }
     635  #define FIELD_2BD(nam, dxf) FIELD_2RD (nam, dxf)
     636  #define FIELD_2BD_1(nam, dxf)                                                 \
     637    if (dxf)                                                                    \
     638      {                                                                         \
     639        FIELD_RD (nam.x, dxf);                                                  \
     640        FIELD_RD (nam.y, dxf + 1);                                              \
     641      }
     642  #define FIELD_3RD(nam, dxf)                                                   \
     643    if (dxf)                                                                    \
     644      {                                                                         \
     645        FIELD_RD (nam.x, dxf);                                                  \
     646        FIELD_RD (nam.y, dxf + 10);                                             \
     647        FIELD_RD (nam.z, dxf + 20);                                             \
     648      }
     649  #define FIELD_3BD(nam, dxf) FIELD_3RD (nam, dxf)
     650  #define FIELD_3BD_1(nam, dxf)                                                 \
     651    if (dxf)                                                                    \
     652      {                                                                         \
     653        FIELD_RD (nam.x, dxf);                                                  \
     654        FIELD_RD (nam.y, dxf + 1);                                              \
     655        FIELD_RD (nam.z, dxf + 2);                                              \
     656      }
     657  #define FIELD_3DPOINT(nam, dxf) FIELD_3RD (nam, dxf)
     658  #define FIELD_CMC(color, dxf)                                                 \
     659    {                                                                           \
     660      if (dat->version < R_2004)                                                \
     661        {                                                                       \
     662          if (dat->from_version >= R_2004)                                      \
     663            bit_downconvert_CMC (dat, (Dwg_Color *)&_obj->color);               \
     664          VALUE_RS (_obj->color.index, dxf);                                    \
     665        }                                                                       \
     666      else                                                                      \
     667        {                                                                       \
     668          if (dat->from_version < R_2004)                                       \
     669            bit_upconvert_CMC (dat, (Dwg_Color *)&_obj->color);                 \
     670          if (dxf >= 90)                                                        \
     671            {                                                                   \
     672              VALUE_RL (_obj->color.rgb, dxf);                                  \
     673            }                                                                   \
     674          else if (_obj->color.method == 0xc3)                                  \
     675            {                                                                   \
     676              VALUE_RL (_obj->color.rgb & 0x00ffffff, dxf);                     \
     677            }                                                                   \
     678          else if (_obj->color.method == 0xc8)                                  \
     679            {                                                                   \
     680              VALUE_RS (257, dxf);                                              \
     681            }                                                                   \
     682          else                                                                  \
     683            {                                                                   \
     684              VALUE_RS (_obj->color.index, dxf);                                \
     685              if (_obj->color.method == 0xc2)                                   \
     686                VALUE_RL (_obj->color.rgb, (unsigned)(dxf + 420 - 62));         \
     687            }                                                                   \
     688        }                                                                       \
     689    }
     690  #define FIELD_CMC0(color, dxf)                                                \
     691    {                                                                           \
     692      if (dat->version < R_2004)                                                \
     693        {                                                                       \
     694          if (dat->from_version >= R_2004)                                      \
     695            bit_downconvert_CMC (dat, (Dwg_Color *)&_obj->color);               \
     696          if (_obj->color.index)                                                \
     697            VALUE_RS (_obj->color.index, dxf);                                  \
     698        }                                                                       \
     699      else                                                                      \
     700        {                                                                       \
     701          if (dat->from_version < R_2004)                                       \
     702            bit_upconvert_CMC (dat, (Dwg_Color *)&_obj->color);                 \
     703          if (dxf >= 90)                                                        \
     704            {                                                                   \
     705              VALUE_RL (_obj->color.rgb, dxf);                                  \
     706            }                                                                   \
     707          else if (_obj->color.method == 0xc3)                                  \
     708            {                                                                   \
     709              VALUE_RL (_obj->color.rgb & 0x00ffffff, dxf);                     \
     710            }                                                                   \
     711          else if (_obj->color.method == 0xc8)                                  \
     712            {                                                                   \
     713              VALUE_RS (257, dxf);                                              \
     714            }                                                                   \
     715          else                                                                  \
     716            {                                                                   \
     717              if (_obj->color.index)                                            \
     718                VALUE_RS (_obj->color.index, dxf);                              \
     719              if (_obj->color.method == 0xc2)                                   \
     720                VALUE_RL (_obj->color.rgb, (unsigned)(dxf + 420 - 62));         \
     721            }                                                                   \
     722        }                                                                       \
     723    }
     724  #define SUB_FIELD_CMC(o, color, dxf)                                          \
     725    {                                                                           \
     726      if (dat->version < R_2004)                                                \
     727        {                                                                       \
     728          if (dat->from_version >= R_2004)                                      \
     729            bit_downconvert_CMC (dat, (Dwg_Color *)&_obj->o.color);             \
     730          VALUE_RS (_obj->o.color.index, dxf);                                  \
     731        }                                                                       \
     732      else                                                                      \
     733        {                                                                       \
     734          if (dat->from_version < R_2004)                                       \
     735            bit_upconvert_CMC (dat, (Dwg_Color *)&_obj->o.color);               \
     736          if (dxf >= 90)                                                        \
     737            {                                                                   \
     738              VALUE_RL (_obj->o.color.rgb, dxf);                                \
     739            }                                                                   \
     740          else if (_obj->o.color.method == 0xc8)                                \
     741            {                                                                   \
     742              VALUE_RS (257, dxf);                                              \
     743            }                                                                   \
     744          else if (_obj->o.color.method == 0xc3)                                \
     745            {                                                                   \
     746              VALUE_RL (_obj->o.color.rgb & 0x00ffffff, dxf);                   \
     747            }                                                                   \
     748          else                                                                  \
     749            {                                                                   \
     750              VALUE_RS (_obj->o.color.index, dxf);                              \
     751              if (_obj->o.color.method == 0xc2)                                 \
     752                VALUE_RL (_obj->o.color.rgb, (unsigned)(dxf + 420 - 62));       \
     753            }                                                                   \
     754        }                                                                       \
     755    }
     756  #define HEADER_CMC(nam, dxf)                                                  \
     757    {                                                                           \
     758      HEADER_9 (nam);                                                           \
     759      VALUE_RS (dwg->header_vars.nam.index, dxf);                               \
     760    }
     761  #define HEADER_TIMEBLL(nam, dxf)                                              \
     762    {                                                                           \
     763      HEADER_9 (nam);                                                           \
     764      FIELD_TIMEBLL (nam, dxf);                                                 \
     765    }
     766  #define FIELD_TIMEBLL(nam, dxf) VALUE_RD (_obj->nam.value, dxf)
     767  
     768  // FIELD_VECTOR_N(nam, type, size):
     769  // reads data of the type indicated by 'type' 'size' times and stores
     770  // it all in the vector called 'nam'.
     771  #define FIELD_VECTOR_N(nam, type, size, dxf)                                  \
     772    if (dxf && _obj->nam)                                                       \
     773      {                                                                         \
     774        for (vcount = 0; vcount < (BITCODE_BL)size; vcount++)                   \
     775          VALUE (_obj->nam[vcount], type, dxf);                                 \
     776      }
     777  #define FIELD_VECTOR_T(nam, type, size, dxf)                                  \
     778    if (dxf && _obj->nam)                                                       \
     779      {                                                                         \
     780        if (!IS_FROM_TU (dat))                                                  \
     781          {                                                                     \
     782            for (vcount = 0; vcount < (BITCODE_BL)_obj->size; vcount++)         \
     783              VALUE_TV (_obj->nam[vcount], dxf)                                 \
     784          }                                                                     \
     785        else                                                                    \
     786          {                                                                     \
     787            for (vcount = 0; vcount < (BITCODE_BL)_obj->size; vcount++)         \
     788              VALUE_TU (_obj->nam[vcount], dxf)                                 \
     789          }                                                                     \
     790      }
     791  
     792  #define FIELD_VECTOR(nam, type, size, dxf)                                    \
     793    FIELD_VECTOR_N (nam, type, _obj->size, dxf)
     794  
     795  #define FIELD_2RD_VECTOR(nam, size, dxf)                                      \
     796    if (dxf && _obj->nam)                                                       \
     797      {                                                                         \
     798        for (vcount = 0; vcount < (BITCODE_BL)_obj->size; vcount++)             \
     799          {                                                                     \
     800            FIELD_2RD (nam[vcount], dxf);                                       \
     801          }                                                                     \
     802      }
     803  
     804  #define FIELD_2DD_VECTOR(nam, size, dxf)                                      \
     805    FIELD_2RD (nam[0], dxf);                                                    \
     806    if (dxf && _obj->nam)                                                       \
     807      {                                                                         \
     808        for (vcount = 1; vcount < (BITCODE_BL)_obj->size; vcount++)             \
     809          {                                                                     \
     810            FIELD_2DD (nam[vcount], nam[vcount - 1], dxf);                      \
     811          }                                                                     \
     812      }
     813  
     814  #define FIELD_3DPOINT_VECTOR(nam, size, dxf)                                  \
     815    if (dxf && _obj->nam)                                                       \
     816      {                                                                         \
     817        for (vcount = 0; vcount < (BITCODE_BL)_obj->size; vcount++)             \
     818          {                                                                     \
     819            FIELD_3DPOINT (nam[vcount], dxf);                                   \
     820          }                                                                     \
     821      }
     822  
     823  #define HANDLE_VECTOR_N(nam, size, code, dxf)                                 \
     824    if (dxf && _obj->nam)                                                       \
     825      {                                                                         \
     826        for (vcount = 0; vcount < (BITCODE_BL)size; vcount++)                   \
     827          {                                                                     \
     828            FIELD_HANDLE_N (nam[vcount], vcount, code, dxf);                    \
     829          }                                                                     \
     830      }
     831  
     832  #define HANDLE_VECTOR(nam, sizefield, code, dxf)                              \
     833    HANDLE_VECTOR_N (nam, FIELD_VALUE (sizefield), code, dxf)
     834  
     835  #define FIELD_NUM_INSERTS(num_inserts, type, dxf)                             \
     836    FIELDG (num_inserts, type, dxf)
     837  
     838  #define FIELD_XDATA(nam, size)                                                \
     839    dxfb_write_xdata (dat, obj, _obj->nam, _obj->size)
     840  
     841  #define _XDICOBJHANDLE(code)                                                  \
     842    if (dat->version >= R_13b1 && obj->tio.object->xdicobjhandle                \
     843        && obj->tio.object->xdicobjhandle->absolute_ref)                        \
     844      {                                                                         \
     845        VALUE_TV ("{ACAD_XDICTIONARY", 102);                                    \
     846        VALUE_HANDLE (obj->tio.object->xdicobjhandle, xdicobjhandle, code,      \
     847                      360);                                                     \
     848        VALUE_TV ("}", 102);                                                    \
     849      }
     850  #define _REACTORS(code)                                                       \
     851    if (dat->version >= R_13b1 && obj->tio.object->num_reactors                 \
     852        && obj->tio.object->reactors)                                           \
     853      {                                                                         \
     854        VALUE_TV ("{ACAD_REACTORS", 102)                                        \
     855        for (vcount = 0; vcount < obj->tio.object->num_reactors; vcount++)      \
     856          {                                                                     \
     857            VALUE_HANDLE (obj->tio.object->reactors[vcount], reactors, code,    \
     858                          330);                                                 \
     859          }                                                                     \
     860        VALUE_TV ("}", 102)                                                     \
     861      }
     862  #define ENT_REACTORS(code)                                                    \
     863    if (dat->version >= R_13b1 && _obj->num_reactors && _obj->reactors)         \
     864      {                                                                         \
     865        VALUE_TV ("{ACAD_REACTORS", 102)                                        \
     866        for (vcount = 0; vcount < _obj->num_reactors; vcount++)                 \
     867          {                                                                     \
     868            VALUE_HANDLE (_obj->reactors[vcount], reactors, code, 330);         \
     869          }                                                                     \
     870        VALUE_TV ("}", 102)                                                     \
     871      }
     872  
     873  #define REACTORS(code)
     874  #define XDICOBJHANDLE(code)
     875  #define ENT_XDICOBJHANDLE(code)                                               \
     876    if (dat->version >= R_13b1 && obj->tio.entity->xdicobjhandle                \
     877        && obj->tio.entity->xdicobjhandle->absolute_ref)                        \
     878      {                                                                         \
     879        VALUE_TV ("{ACAD_XDICTIONARY", 102);                                    \
     880        VALUE_HANDLE (obj->tio.entity->xdicobjhandle, xdicobjhandle, code,      \
     881                      360);                                                     \
     882        VALUE_TV ("}", 102);                                                    \
     883      }
     884  #define BLOCK_NAME(nam, dxf) dxfb_cvt_blockname (dat, _obj->nam, dxf)
     885  
     886  #define COMMON_ENTITY_HANDLE_DATA
     887  #define SECTION_STRING_STREAM
     888  #define START_STRING_STREAM
     889  #define END_STRING_STREAM
     890  #define START_HANDLE_STREAM
     891  
     892  #ifndef DEBUG_CLASSES
     893  static int
     894  dwg_dxfb_TABLECONTENT (Bit_Chain *restrict dat, const Dwg_Object *restrict obj)
     895  {
     896    (void)dat;
     897    (void)obj;
     898    return 0;
     899  }
     900  #else
     901  static int dwg_dxfb_TABLECONTENT (Bit_Chain *restrict dat,
     902                                    const Dwg_Object *restrict obj);
     903  #endif
     904  
     905  #define DWG_ENTITY(token)                                                     \
     906    static int dwg_dxfb_##token##_private (Bit_Chain *dat, Bit_Chain *hdl_dat,  \
     907                                           Bit_Chain *str_dat,                  \
     908                                           const Dwg_Object *restrict obj);     \
     909    static int dwg_dxfb_##token (Bit_Chain *restrict dat,                       \
     910                                 const Dwg_Object *restrict obj)                \
     911    {                                                                           \
     912      int error = 0;                                                            \
     913      Bit_Chain *hdl_dat = dat;                                                 \
     914      Bit_Chain *str_dat = dat;                                                 \
     915      if (obj->fixedtype != DWG_TYPE_##token)                                   \
     916        {                                                                       \
     917          LOG_ERROR ("Invalid type 0x%x, expected 0x%x %s", obj->fixedtype,     \
     918                     DWG_TYPE_##token, #token);                                 \
     919          return DWG_ERR_INVALIDTYPE;                                           \
     920        }                                                                       \
     921      if (strEQc (#token, "GEOPOSITIONMARKER"))                                 \
     922        RECORD (POSITIONMARKER)                                                 \
     923      else if (dat->version < R_13b1 && strlen (#token) == 10                   \
     924               && strEQc (#token, "LWPOLYLINE"))                                \
     925        RECORD (POLYLINE)                                                       \
     926      else if (strlen (#token) > 10 && !memcmp (#token, "DIMENSION_", 10))      \
     927        RECORD (DIMENSION)                                                      \
     928      else if (strlen (#token) > 9 && !memcmp (#token, "POLYLINE_", 9))         \
     929        RECORD (POLYLINE)                                                       \
     930      else if (strlen (#token) > 7 && !memcmp (#token, "VERTEX_", 7))           \
     931        RECORD (VERTEX)                                                         \
     932      else if (strEQc (#token, "MINSERT"))                                      \
     933        RECORD (INSERT)                                                         \
     934      else if (dat->version >= R_2010 && strEQc (#token, "TABLE"))              \
     935        {                                                                       \
     936          RECORD (ACAD_TABLE);                                                  \
     937          return dwg_dxfb_TABLECONTENT (dat, obj);                              \
     938        }                                                                       \
     939      else if (strlen (#token) > 3 && !memcmp (#token, "_3D", 3))               \
     940        VALUE_TV (obj->dxfname, 0)                                              \
     941      else if (obj->type >= 498 && obj->dxfname)                                \
     942        VALUE_TV (obj->dxfname, 0)                                              \
     943      else                                                                      \
     944        RECORD (token)                                                          \
     945      LOG_INFO ("Entity " #token ":\n")                                         \
     946      SINCE (R_11)                                                              \
     947      {                                                                         \
     948        LOG_TRACE ("Entity handle: " FORMAT_H "\n", ARGS_H (obj->handle))       \
     949        VALUE_H (obj->handle.value, 5);                                         \
     950      }                                                                         \
     951      SINCE (R_13b1)                                                            \
     952      {                                                                         \
     953        VALUE_HANDLE_NAME (obj->parent->header_vars.BLOCK_RECORD_MSPACE, 330,   \
     954                           BLOCK_HEADER);                                       \
     955      }                                                                         \
     956      error |= dxfb_common_entity_handle_data (dat, obj);                       \
     957      error |= dwg_dxfb_##token##_private (dat, hdl_dat, str_dat, obj);         \
     958      error |= dxfb_write_eed (dat, obj->tio.object);                           \
     959      return error;                                                             \
     960    }                                                                           \
     961    static int dwg_dxfb_##token##_private (Bit_Chain *dat, Bit_Chain *hdl_dat,  \
     962                                           Bit_Chain *str_dat,                  \
     963                                           const Dwg_Object *restrict obj)      \
     964    {                                                                           \
     965      int error = 0;                                                            \
     966      BITCODE_BL vcount, rcount3, rcount4;                                      \
     967      Dwg_Data *dwg = obj->parent;                                              \
     968      Dwg_Entity_##token *_obj = obj->tio.entity->tio.token;                    \
     969      Dwg_Object_Entity *_ent = obj->tio.entity;
     970  
     971  #define DWG_ENTITY_END                                                        \
     972    return error;                                                               \
     973    }
     974  
     975  #define DWG_OBJECT(token)                                                     \
     976    static int dwg_dxfb_##token##_private (Bit_Chain *dat, Bit_Chain *hdl_dat,  \
     977                                           Bit_Chain *str_dat,                  \
     978                                           const Dwg_Object *restrict obj);     \
     979    static int dwg_dxfb_##token (Bit_Chain *restrict dat,                       \
     980                                 const Dwg_Object *restrict obj)                \
     981    {                                                                           \
     982      BITCODE_BL vcount;                                                        \
     983      int error = 0;                                                            \
     984      Bit_Chain *str_dat = dat;                                                 \
     985      Bit_Chain *hdl_dat = dat;                                                 \
     986      LOG_INFO ("Object " #token ":\n")                                         \
     987      if (obj->fixedtype != DWG_TYPE_##token)                                   \
     988        {                                                                       \
     989          LOG_ERROR ("Invalid type 0x%x, expected 0x%x %s", obj->fixedtype,     \
     990                     DWG_TYPE_##token, #token);                                 \
     991          return DWG_ERR_INVALIDTYPE;                                           \
     992        }                                                                       \
     993      PRE (R_14)                                                                \
     994      {                                                                         \
     995        if (obj->fixedtype == DWG_TYPE_PLACEHOLDER)                             \
     996          return 0;                                                             \
     997      }                                                                         \
     998      if (!dwg_obj_is_control (obj))                                            \
     999        {                                                                       \
    1000          if (obj->fixedtype == DWG_TYPE_TABLE)                                 \
    1001            ;                                                                   \
    1002          else if (obj->type >= 500 && obj->dxfname)                            \
    1003            VALUE_TV (obj->dxfname, 0)                                          \
    1004          else if (obj->type == DWG_TYPE_PLACEHOLDER)                           \
    1005            RECORD (ACDBPLACEHOLDER)                                            \
    1006          else if (obj->fixedtype == DWG_TYPE_PROXY_OBJECT)                     \
    1007            RECORD (ACAD_PROXY_OBJECT)                                          \
    1008          else if (obj->type != DWG_TYPE_BLOCK_HEADER)                          \
    1009            RECORD (token)                                                      \
    1010          SINCE (R_13b1)                                                        \
    1011          {                                                                     \
    1012            const int dxf = obj->type == DWG_TYPE_DIMSTYLE ? 105 : 5;           \
    1013            VALUE_H (obj->handle.value, dxf);                                   \
    1014            _XDICOBJHANDLE (3);                                                 \
    1015            _REACTORS (4);                                                      \
    1016          }                                                                     \
    1017          SINCE (R_14)                                                          \
    1018          {                                                                     \
    1019            VALUE_HANDLE (obj->tio.object->ownerhandle, ownerhandle, 3, 330);   \
    1020          }                                                                     \
    1021        }                                                                       \
    1022      if (DWG_LOGLEVEL >= DWG_LOGLEVEL_TRACE)                                   \
    1023        {                                                                       \
    1024          if (dwg_obj_is_table (obj))                                           \
    1025            {                                                                   \
    1026              char *_name = dwg_obj_table_get_name (obj, &error);               \
    1027              LOG_TRACE ("Object handle: " FORMAT_H ", name: %s\n",             \
    1028                         ARGS_H (obj->handle), _name);                          \
    1029              if (IS_FROM_TU (dat))                                             \
    1030                free (_name);                                                   \
    1031            }                                                                   \
    1032          else                                                                  \
    1033            LOG_TRACE ("Object handle: " FORMAT_H "\n", ARGS_H (obj->handle))   \
    1034        }                                                                       \
    1035      error |= dwg_dxfb_##token##_private (dat, hdl_dat, str_dat, obj);         \
    1036      error |= dxfb_write_eed (dat, obj->tio.object);                           \
    1037      return error;                                                             \
    1038    }                                                                           \
    1039    static int dwg_dxfb_##token##_private (Bit_Chain *dat, Bit_Chain *hdl_dat,  \
    1040                                           Bit_Chain *str_dat,                  \
    1041                                           const Dwg_Object *restrict obj)      \
    1042    {                                                                           \
    1043      int error = 0;                                                            \
    1044      BITCODE_BL vcount, rcount3, rcount4;                                      \
    1045      Dwg_Data *dwg = obj->parent;                                              \
    1046      Dwg_Object_##token *_obj = obj->tio.object->tio.token;
    1047  
    1048  // then 330, SUBCLASS
    1049  
    1050  #define DWG_OBJECT_END                                                        \
    1051    return error;                                                               \
    1052    }
    1053  
    1054  static int
    1055  dxfb_write_eed (Bit_Chain *restrict dat, const Dwg_Object_Object *restrict obj)
    1056  {
    1057    int error = 0;
    1058    Dwg_Data *dwg = obj->dwg;
    1059    for (BITCODE_BL i = 0; i < obj->num_eed; i++)
    1060      {
    1061        const Dwg_Eed *_obj = &obj->eed[i];
    1062        if (_obj->size)
    1063          {
    1064            // name of APPID
    1065            Dwg_Object *appid = dwg_resolve_handle (dwg, _obj->handle.value);
    1066            if (appid && appid->fixedtype == DWG_TYPE_APPID)
    1067              VALUE_T (appid->tio.object->tio.APPID->name, 1001)
    1068            else
    1069              VALUE_TFF ("ACAD", 1001);
    1070          }
    1071        if (_obj->data)
    1072          {
    1073            const Dwg_Eed_Data *data = _obj->data;
    1074            const int dxf = data->code + 1000;
    1075            switch (data->code)
    1076              {
    1077              case 0:
    1078                if (IS_FROM_TU (dat))
    1079                  VALUE_TU (data->u.eed_0_r2007.string, 1000)
    1080                else
    1081                  VALUE_TV (data->u.eed_0.string, 1000)
    1082                break;
    1083              case 2:
    1084                if (data->u.eed_2.close)
    1085                  VALUE_TFF ("}", 1002)
    1086                else
    1087                  VALUE_TFF ("{", 1002)
    1088                break;
    1089              case 3:
    1090                GROUP (dxf);
    1091                fprintf (dat->fh, "%9lu\r\n",
    1092                         (unsigned long)data->u.eed_3.layer);
    1093                // VALUE_RLL (data->u.eed_3.layer, dxf);
    1094                break;
    1095              case 4:
    1096                VALUE_BINARY (data->u.eed_4.data, data->u.eed_4.length, dxf);
    1097                break;
    1098              case 5:
    1099                VALUE_H (data->u.eed_5.entity, dxf);
    1100                break; // not in DXF
    1101              case 10:
    1102              case 11:
    1103              case 12:
    1104              case 13:
    1105              case 14:
    1106              case 15:
    1107                VALUE_3BD (data->u.eed_10.point, dxf);
    1108                break;
    1109              case 40:
    1110              case 41:
    1111              case 42:
    1112                VALUE_RD (data->u.eed_40.real, dxf);
    1113                break;
    1114              case 70:
    1115                VALUE_RS (data->u.eed_70.rs, dxf);
    1116                break;
    1117              case 71:
    1118                VALUE_RL (data->u.eed_71.rl, dxf);
    1119                break;
    1120              default:
    1121                VALUE_RC (0, dxf);
    1122              }
    1123          }
    1124      }
    1125    return error;
    1126  }
    1127  
    1128  static void
    1129  dxfb_write_xdata (Bit_Chain *restrict dat, const Dwg_Object *restrict obj,
    1130                    Dwg_Resbuf *restrict rbuf, BITCODE_BL size)
    1131  {
    1132    Dwg_Resbuf *tmp;
    1133    int i;
    1134  
    1135    while (rbuf)
    1136      {
    1137        // const char* fmt = dxf_format(rbuf->type);
    1138        short type = dwg_resbuf_value_type (rbuf->type);
    1139        int dxftype = (rbuf->type > 1000 || obj->fixedtype == DWG_TYPE_XRECORD)
    1140                          ? rbuf->type
    1141                          : rbuf->type + 1000;
    1142  
    1143        tmp = rbuf->nextrb;
    1144        switch (type)
    1145          {
    1146          case DWG_VT_STRING:
    1147            if (IS_FROM_TU (dat))
    1148              {
    1149                VALUE_TU (rbuf->value.str.u.wdata, dxftype);
    1150              }
    1151            else
    1152              {
    1153                VALUE_TV (rbuf->value.str.u.data, dxftype);
    1154              }
    1155            break;
    1156          case DWG_VT_REAL:
    1157            VALUE_RD (rbuf->value.dbl, dxftype);
    1158            break;
    1159          case DWG_VT_BOOL:
    1160          case DWG_VT_INT8:
    1161            VALUE_RC (rbuf->value.i8, dxftype);
    1162            break;
    1163          case DWG_VT_INT16:
    1164            VALUE_RS (rbuf->value.i16, dxftype);
    1165            break;
    1166          case DWG_VT_INT32:
    1167            VALUE_RL (rbuf->value.i32, dxftype);
    1168            break;
    1169          case DWG_VT_INT64:
    1170            VALUE_RLL (rbuf->value.i64, dxftype);
    1171            break;
    1172          case DWG_VT_POINT3D:
    1173            VALUE_RD (rbuf->value.pt[0], dxftype);
    1174            VALUE_RD (rbuf->value.pt[1], dxftype + 10);
    1175            VALUE_RD (rbuf->value.pt[2], dxftype + 20);
    1176            break;
    1177          case DWG_VT_BINARY:
    1178            VALUE_BINARY (rbuf->value.str.u.data, rbuf->value.str.size, dxftype);
    1179            break;
    1180          case DWG_VT_HANDLE:
    1181          case DWG_VT_OBJECTID:
    1182            VALUE_H (rbuf->value.absref, dxftype);
    1183            break;
    1184          case DWG_VT_INVALID:
    1185          default:
    1186            // fprintf(dat->fh, "");
    1187            break;
    1188          }
    1189        rbuf = tmp;
    1190      }
    1191  }
    1192  
    1193  #undef DXF_3DSOLID
    1194  #define DXF_3DSOLID dxfb_3dsolid (dat, obj, (Dwg_Entity_3DSOLID *)_obj);
    1195  
    1196  // r13+ converts STANDARD to Standard, BYLAYER to ByLayer, BYBLOCK to ByBlock
    1197  static void
    1198  dxfb_cvt_tablerecord (Bit_Chain *restrict dat, const Dwg_Object *restrict obj,
    1199                        char *restrict name, const int dxf)
    1200  {
    1201    if (obj && obj->supertype == DWG_SUPERTYPE_OBJECT && name)
    1202      {
    1203        if (IS_FROM_TU (dat))
    1204          {
    1205            name = bit_convert_TU ((BITCODE_TU)name);
    1206          }
    1207        if (dat->from_version >= R_13b1 && dat->version < R_13b1)
    1208          { // convert the other way round, from newer to older
    1209            if (strEQc (name, "Standard"))
    1210              VALUE_TV ("STANDARD", dxf)
    1211            else if (strEQc (name, "ByLayer"))
    1212              VALUE_TV ("BYLAYER", dxf)
    1213            else if (strEQc (name, "ByBlock"))
    1214              VALUE_TV ("BYBLOCK", dxf)
    1215            else if (strEQc (name, "*Active"))
    1216              VALUE_TV ("*ACTIVE", dxf)
    1217            else
    1218              VALUE_TV (name, dxf)
    1219          }
    1220        else
    1221          { // convert some standard names
    1222            if (dat->version >= R_13b1 && strEQc (name, "STANDARD"))
    1223              VALUE_TV ("Standard", dxf)
    1224            else if (dat->version >= R_13b1 && strEQc (name, "BYLAYER"))
    1225              VALUE_TV ("ByLayer", dxf)
    1226            else if (dat->version >= R_13b1 && strEQc (name, "BYBLOCK"))
    1227              VALUE_TV ("ByBlock", dxf)
    1228            else if (dat->version >= R_13b1 && strEQc (name, "*ACTIVE"))
    1229              VALUE_TV ("*Active", dxf)
    1230            else
    1231              VALUE_TV (name, dxf)
    1232          }
    1233        if (IS_FROM_TU (dat))
    1234          free (name);
    1235      }
    1236    else
    1237      {
    1238        VALUE_TV ("", dxf)
    1239      }
    1240  }
    1241  
    1242  /* pre-r13 mspace and pspace blocks have different names:
    1243   *Model_Space => $MODEL_SPACE
    1244   *Paper_Space => $PAPER_SPACE
    1245   */
    1246  static void
    1247  dxfb_cvt_blockname (Bit_Chain *restrict dat, char *restrict name,
    1248                      const int dxf)
    1249  {
    1250    if (!name)
    1251      {
    1252        VALUE_TV ("", dxf)
    1253        return;
    1254      }
    1255    if (IS_FROM_TU (dat)) // r2007+ unicode names
    1256      {
    1257        name = bit_convert_TU ((BITCODE_TU)name);
    1258      }
    1259    if (dat->version == dat->from_version) // no conversion
    1260      {
    1261        VALUE_TV (name, dxf)
    1262      }
    1263    else if (dat->version < R_13b1 && dat->from_version >= R_13b1) // to older
    1264      {
    1265        if (strlen (name) < 10)
    1266          VALUE_TV (name, dxf)
    1267        else if (strEQc (name, "*Model_Space"))
    1268          VALUE_TV ("$MODEL_SPACE", dxf)
    1269        else if (strEQc (name, "*Paper_Space"))
    1270          VALUE_TV ("$PAPER_SPACE", dxf)
    1271        else if (!memcmp (name, "*Paper_Space", sizeof ("*Paper_Space") - 1))
    1272          {
    1273            GROUP (dxf);
    1274            fprintf (dat->fh, "$PAPER_SPACE%s%c", &name[12], 0);
    1275          }
    1276        else
    1277          VALUE_TV (name, dxf)
    1278      }
    1279    else if (dat->version >= R_13b1 && dat->from_version < R_13b1) // to newer
    1280      {
    1281        if (strlen (name) < 10)
    1282          VALUE_TV (name, dxf)
    1283        else if (strEQc (name, "$MODEL_SPACE"))
    1284          VALUE_TV ("*Model_Space", dxf)
    1285        else if (strEQc (name, "$PAPER_SPACE"))
    1286          VALUE_TV ("*Paper_Space", dxf)
    1287        else if (!memcmp (name, "$PAPER_SPACE", sizeof ("$PAPER_SPACE") - 1))
    1288          {
    1289            GROUP (dxf);
    1290            fprintf (dat->fh, "*Paper_Space%s%c", &name[12], 0);
    1291          }
    1292        else
    1293          VALUE_TV (name, dxf)
    1294      }
    1295    if (IS_FROM_TU (dat))
    1296      free (name);
    1297  }
    1298  
    1299  #define START_OBJECT_HANDLE_STREAM
    1300  
    1301  // Handle 5 written here first
    1302  #define COMMON_TABLE_CONTROL_FLAGS                                            \
    1303    if (ctrl)                                                                   \
    1304      {                                                                         \
    1305        SINCE (R_13b1)                                                          \
    1306        {                                                                       \
    1307          BITCODE_BL vcount;                                                    \
    1308          VALUE_H (ctrl->handle.value, 5);                                      \
    1309          _XDICOBJHANDLE (3);                                                   \
    1310          _REACTORS (4);                                                        \
    1311        }                                                                       \
    1312        SINCE (R_14)                                                            \
    1313        {                                                                       \
    1314          VALUE_HANDLE (ctrl->tio.object->ownerhandle, ownerhandle, 3, 330);    \
    1315        }                                                                       \
    1316      }                                                                         \
    1317    SINCE (R_13b1)                                                              \
    1318    {                                                                           \
    1319      VALUE_TV ("AcDbSymbolTable", 100);                                        \
    1320    }
    1321  
    1322  #define COMMON_TABLE_FLAGS(acdbname)                                          \
    1323    SINCE (R_13b1)                                                              \
    1324    {                                                                           \
    1325      VALUE_TV ("AcDbSymbolTableRecord", 100)                                   \
    1326      VALUE_TV ("AcDb" #acdbname "TableRecord", 100)                            \
    1327    }                                                                           \
    1328    if (strEQc (#acdbname, "Block") && dat->version >= R_13b1)                  \
    1329      {                                                                         \
    1330        Dwg_Object *blk = dwg_ref_object (                                      \
    1331            dwg, ((Dwg_Object_BLOCK_HEADER *)_obj)->block_entity);              \
    1332        if (blk && blk->type == DWG_TYPE_BLOCK)                                 \
    1333          {                                                                     \
    1334            Dwg_Entity_BLOCK *_blk = blk->tio.entity->tio.BLOCK;                \
    1335            VALUE_T (_blk->name, 2)                                             \
    1336          }                                                                     \
    1337        else if (_obj->name)                                                    \
    1338          {                                                                     \
    1339            VALUE_T (_obj->name, 2)                                             \
    1340          }                                                                     \
    1341        else                                                                    \
    1342          VALUE_TV ("*", 2)                                                     \
    1343      }                                                                         \
    1344    /* Empty name with xref shape names */                                      \
    1345    else if (strEQc (#acdbname, "TextStyle") && _obj->flag & 1                  \
    1346             && dxf_is_xrefdep_name (dat, _obj->name))                          \
    1347      VALUE_TV ("", 2)                                                          \
    1348    else if (_obj->name)                                                        \
    1349      dxfb_cvt_tablerecord (dat, obj, _obj->name, 2);                           \
    1350    else                                                                        \
    1351      VALUE_TV ("*", 2)                                                         \
    1352    if (strEQc (#acdbname, "Layer") && dat->version >= R_2000)                  \
    1353      {                                                                         \
    1354        /* Mask off plotflag and linewt. */                                     \
    1355        BITCODE_RC _flag = _obj->flag & ~0x3e0;                                 \
    1356        /* Don't keep bit 16 when not xrefdep like "XREF|name" */               \
    1357        if (_flag & 0x10 && !dxf_has_xrefdep_vertbar (dat, _obj->name))         \
    1358          _flag &= ~0x10;                                                       \
    1359        VALUE_RC (_flag, 70);                                                   \
    1360      }                                                                         \
    1361    else if (strEQc (#acdbname, "Block") && dat->version >= R_2000)             \
    1362      ; /* skip 70 for AcDbBlockTableRecord here. done in AcDbBlockBegin */     \
    1363    else                                                                        \
    1364      {                                                                         \
    1365        /* mask off 64, the loaded bit 6 */                                     \
    1366        VALUE_RS (_obj->flag & ~64, 70);                                        \
    1367      }
    1368  
    1369  #define LAYER_TABLE_FLAGS(acdbname)                                           \
    1370    SINCE (R_14)                                                                \
    1371    {                                                                           \
    1372      VALUE_HANDLE (obj->tio.object->ownerhandle, ownerhandle, 3, 330);         \
    1373    }                                                                           \
    1374    SINCE (R_13b1)                                                              \
    1375    {                                                                           \
    1376      VALUE_TV ("AcDbSymbolTableRecord", 100)                                   \
    1377      VALUE_TV ("AcDb" #acdbname "TableRecord", 100)                            \
    1378    }                                                                           \
    1379    if (_obj->name)                                                             \
    1380      dxfb_cvt_tablerecord (dat, obj, _obj->name, 2);                           \
    1381    FIELD_RS (flag, 70)
    1382  
    1383  #include "dwg.spec"
    1384  
    1385  static int
    1386  dxfb_3dsolid (Bit_Chain *restrict dat, const Dwg_Object *restrict obj,
    1387                Dwg_Entity_3DSOLID *restrict _obj)
    1388  {
    1389    BITCODE_BL i;
    1390    int error = 0;
    1391  
    1392    COMMON_ENTITY_HANDLE_DATA;
    1393    SUBCLASS (AcDbModelerGeometry);
    1394  
    1395    FIELD_B (acis_empty, 0);
    1396    if (!FIELD_VALUE (acis_empty))
    1397      {
    1398        FIELD_B (unknown, 0);
    1399        FIELD_BS (version, 70);
    1400        if (FIELD_VALUE (version) == 1)
    1401          {
    1402            for (i = 0; i < FIELD_VALUE (num_blocks); i++)
    1403              {
    1404                char *s = FIELD_VALUE (encr_sat_data[i]);
    1405                int len = FIELD_VALUE (block_size[i]);
    1406                // DXF 1 + 3 if >255
    1407                while (len > 0)
    1408                  {
    1409                    char *n = strchr (s, '\n');
    1410                    int l = len > 255 ? 255 : len & 0xff;
    1411                    if (n && ((long)(n - s) < (long)len))
    1412                      {
    1413                        l = n - s;
    1414                      }
    1415                    if (l)
    1416                      {
    1417                        if (len < 255)
    1418                          VALUE_BINARY (s, l, 1)
    1419                        else
    1420                          VALUE_BINARY (s, l, 3)
    1421                        l++;
    1422                        len -= l;
    1423                        s += l;
    1424                      }
    1425                    else
    1426                      {
    1427                        len--;
    1428                        s++;
    1429                      }
    1430                  }
    1431              }
    1432            // LOG_TRACE("acis_data [1]:\n%s\n", FIELD_VALUE (acis_data));
    1433          }
    1434        else // if (FIELD_VALUE(version)==2)
    1435          // must use ASCII out
    1436          {
    1437            LOG_ERROR ("ACIS BinaryFile v2 not yet supported. Use ASCII output.");
    1438          }
    1439      }
    1440    return error;
    1441  }
    1442  
    1443  /* returns 0 on success
    1444   */
    1445  static int
    1446  dwg_dxfb_variable_type (const Dwg_Data *restrict dwg, Bit_Chain *restrict dat,
    1447                          Dwg_Object *restrict obj)
    1448  {
    1449    int i;
    1450    Dwg_Class *klass;
    1451    int is_entity;
    1452  
    1453    i = obj->type - 500;
    1454    if (i < 0 || i >= dwg->num_classes)
    1455      return DWG_ERR_INVALIDTYPE;
    1456    if (obj->fixedtype == DWG_TYPE_UNKNOWN_ENT
    1457        || obj->fixedtype == DWG_TYPE_UNKNOWN_OBJ)
    1458      return DWG_ERR_UNHANDLEDCLASS;
    1459  
    1460    klass = &dwg->dwg_class[i];
    1461    if (!klass || !klass->dxfname)
    1462      return DWG_ERR_INTERNALERROR;
    1463    // almost always false
    1464    is_entity = dwg_class_is_entity (klass);
    1465    if (dat->version < R_2000)
    1466      {
    1467        // keep only: IMAGE, LWPOLYLINE, HATCH
    1468        if (is_entity && strNE (klass->dxfname, "IMAGE")
    1469            && strNEc (klass->dxfname, "LWPOLYLINE")
    1470            && strNEc (klass->dxfname, "HATCH"))
    1471          {
    1472            LOG_WARN ("Skip %s\n", klass->dxfname)
    1473            return DWG_ERR_UNHANDLEDCLASS;
    1474          }
    1475        // keep only: DICTIONARYVAR, MATERIAL, RASTERVARIABLES, IMAGEDEF_REACTOR,
    1476        // XRECORD
    1477        else if (!is_entity && strNEc (klass->dxfname, "DICTIONARYVAR")
    1478                 && strNEc (klass->dxfname, "MATERIAL")
    1479                 && strNEc (klass->dxfname, "RASTERVARIABLES")
    1480                 && strNEc (klass->dxfname, "IDBUFFER")
    1481                 && strNEc (klass->dxfname, "IMAGEDEF_REACTOR")
    1482                 && strNEc (klass->dxfname, "XRECORD"))
    1483          {
    1484            LOG_WARN ("Skip %s\n", klass->dxfname)
    1485            return DWG_ERR_UNHANDLEDCLASS;
    1486          }
    1487      }
    1488  
    1489      // clang-format off
    1490    #include "classes.inc"
    1491    // clang-format on
    1492  
    1493    return DWG_ERR_UNHANDLEDCLASS;
    1494  }
    1495  
    1496  /* process unsorted vertices */
    1497  #define decl_dxfb_process_VERTEX(token)                                       \
    1498    static int dxfb_process_VERTEX_##token (Bit_Chain *restrict dat,            \
    1499                                            const Dwg_Object *restrict obj,     \
    1500                                            int *restrict i)                    \
    1501    {                                                                           \
    1502      int error = 0;                                                            \
    1503      Dwg_Entity_POLYLINE_##token *_obj                                         \
    1504          = obj->tio.entity->tio.POLYLINE_##token;                              \
    1505                                                                                \
    1506      VERSIONS (R_13b1, R_2000)                                                 \
    1507      {                                                                         \
    1508        Dwg_Object *last_vertex                                                 \
    1509            = _obj->last_vertex ? _obj->last_vertex->obj : NULL;                \
    1510        Dwg_Object *o = _obj->first_vertex ? _obj->first_vertex->obj : NULL;    \
    1511        if (!o || !last_vertex)                                                 \
    1512          return DWG_ERR_INVALIDHANDLE;                                         \
    1513        if (o->fixedtype == DWG_TYPE_VERTEX_##token)                            \
    1514          error |= dwg_dxfb_VERTEX_##token (dat, o);                            \
    1515        *i = *i + 1;                                                            \
    1516        do                                                                      \
    1517          {                                                                     \
    1518            o = dwg_next_object (o);                                            \
    1519            if (!o)                                                             \
    1520              return DWG_ERR_INVALIDHANDLE;                                     \
    1521            if (strEQc (#token, "PFACE")                                        \
    1522                && o->fixedtype == DWG_TYPE_VERTEX_PFACE_FACE)                  \
    1523              {                                                                 \
    1524                error |= dwg_dxfb_VERTEX_PFACE_FACE (dat, o);                   \
    1525              }                                                                 \
    1526            else if (o->fixedtype == DWG_TYPE_VERTEX_##token)                   \
    1527              {                                                                 \
    1528                error |= dwg_dxfb_VERTEX_##token (dat, o);                      \
    1529              }                                                                 \
    1530            *i = *i + 1;                                                        \
    1531          }                                                                     \
    1532        while (o->fixedtype != DWG_TYPE_SEQEND && o != last_vertex);            \
    1533        o = _obj->seqend ? _obj->seqend->obj : NULL;                            \
    1534        if (o && o->fixedtype == DWG_TYPE_SEQEND)                               \
    1535          error |= dwg_dxfb_SEQEND (dat, o);                                    \
    1536        *i = *i + 1;                                                            \
    1537      }                                                                         \
    1538      SINCE (R_2004)                                                            \
    1539      {                                                                         \
    1540        Dwg_Object *o;                                                          \
    1541        for (BITCODE_BL j = 0; j < _obj->num_owned; j++)                        \
    1542          {                                                                     \
    1543            o = _obj->vertex && _obj->vertex[j] ? _obj->vertex[j]->obj : NULL;  \
    1544            if (strEQc (#token, "PFACE") && o                                   \
    1545                && o->fixedtype == DWG_TYPE_VERTEX_PFACE_FACE)                  \
    1546              {                                                                 \
    1547                error |= dwg_dxfb_VERTEX_PFACE_FACE (dat, o);                   \
    1548              }                                                                 \
    1549            else if (o && o->fixedtype == DWG_TYPE_VERTEX_##token)              \
    1550              {                                                                 \
    1551                error |= dwg_dxfb_VERTEX_##token (dat, o);                      \
    1552              }                                                                 \
    1553          }                                                                     \
    1554        o = _obj->seqend ? _obj->seqend->obj : NULL;                            \
    1555        if (o && o->fixedtype == DWG_TYPE_SEQEND)                               \
    1556          error |= dwg_dxfb_SEQEND (dat, o);                                    \
    1557        *i = *i + _obj->num_owned + 1;                                          \
    1558      }                                                                         \
    1559      return error;                                                             \
    1560    }
    1561  
    1562  // clang-format off
    1563  decl_dxfb_process_VERTEX (2D)
    1564  decl_dxfb_process_VERTEX (3D)
    1565  decl_dxfb_process_VERTEX (MESH)
    1566  decl_dxfb_process_VERTEX (PFACE)
    1567  // clang-format on
    1568  
    1569  /* process seqend before attribs */
    1570  #define decl_dxfb_process_INSERT(token)                                       \
    1571    static int dxfb_process_##token (Bit_Chain *restrict dat,                   \
    1572                                     const Dwg_Object *restrict obj,            \
    1573                                     int *restrict i)                           \
    1574    {                                                                           \
    1575      int error = 0;                                                            \
    1576      Dwg_Entity_##token *_obj = obj->tio.entity->tio.token;                    \
    1577      if (!_obj->has_attribs)                                                   \
    1578        return 0;                                                               \
    1579                                                                                \
    1580      VERSIONS (R_13b1, R_2000)                                                 \
    1581      {                                                                         \
    1582        Dwg_Object *last_attrib                                                 \
    1583            = _obj->last_attrib ? _obj->last_attrib->obj : NULL;                \
    1584        Dwg_Object *o = _obj->first_attrib ? _obj->first_attrib->obj : NULL;    \
    1585        if (!o || !last_attrib)                                                 \
    1586          return DWG_ERR_INVALIDHANDLE;                                         \
    1587        if (o->fixedtype == DWG_TYPE_ATTRIB)                                    \
    1588          error |= dwg_dxfb_ATTRIB (dat, o);                                    \
    1589        *i = *i + 1;                                                            \
    1590        do                                                                      \
    1591          {                                                                     \
    1592            o = dwg_next_object (o);                                            \
    1593            if (!o)                                                             \
    1594              return DWG_ERR_INVALIDHANDLE;                                     \
    1595            if (o->fixedtype == DWG_TYPE_ATTRIB)                                \
    1596              error |= dwg_dxfb_ATTRIB (dat, o);                                \
    1597            *i = *i + 1;                                                        \
    1598          }                                                                     \
    1599        while (o->fixedtype == DWG_TYPE_ATTRIB && o != last_attrib);            \
    1600        o = _obj->seqend ? _obj->seqend->obj : NULL;                            \
    1601        if (o && o->fixedtype == DWG_TYPE_SEQEND)                               \
    1602          error |= dwg_dxfb_SEQEND (dat, o);                                    \
    1603        *i = *i + 1;                                                            \
    1604      }                                                                         \
    1605      SINCE (R_2004)                                                            \
    1606      {                                                                         \
    1607        Dwg_Object *o;                                                          \
    1608        for (BITCODE_BL j = 0; j < _obj->num_owned; j++)                        \
    1609          {                                                                     \
    1610            o = _obj->attribs && _obj->attribs[j] ? _obj->attribs[j]->obj       \
    1611                                                  : NULL;                       \
    1612            if (o && o->fixedtype == DWG_TYPE_ATTRIB)                           \
    1613              error |= dwg_dxfb_ATTRIB (dat, o);                                \
    1614          }                                                                     \
    1615        o = _obj->seqend ? _obj->seqend->obj : NULL;                            \
    1616        if (o && o->fixedtype == DWG_TYPE_SEQEND)                               \
    1617          error |= dwg_dxfb_SEQEND (dat, o);                                    \
    1618        *i = *i + _obj->num_owned + 1;                                          \
    1619      }                                                                         \
    1620      return error;                                                             \
    1621    }
    1622  
    1623      // clang-format off
    1624  decl_dxfb_process_INSERT (INSERT)
    1625  decl_dxfb_process_INSERT (MINSERT)
    1626      // clang-format on
    1627  
    1628      static int dwg_dxfb_object (Bit_Chain *restrict dat,
    1629                                  const Dwg_Object *restrict obj,
    1630                                  int *restrict i)
    1631  {
    1632    int error = 0;
    1633    int minimal;
    1634    unsigned int type;
    1635  
    1636    if (!obj || !obj->parent)
    1637      return DWG_ERR_INTERNALERROR;
    1638    minimal = obj->parent->opts & DWG_OPTS_MINIMAL;
    1639    if (dat->version < R_13b1)
    1640      type = (unsigned int)obj->fixedtype;
    1641    else
    1642      {
    1643        type = obj->type;
    1644        if (obj->fixedtype == DWG_TYPE_UNKNOWN_ENT)
    1645          type = DWG_TYPE_UNKNOWN_ENT;
    1646        if (obj->fixedtype == DWG_TYPE_UNKNOWN_OBJ)
    1647          type = DWG_TYPE_UNKNOWN_OBJ;
    1648      }
    1649  
    1650    switch (type)
    1651      {
    1652      case DWG_TYPE_TEXT:
    1653        return dwg_dxfb_TEXT (dat, obj);
    1654      case DWG_TYPE_ATTDEF:
    1655        return dwg_dxfb_ATTDEF (dat, obj);
    1656      case DWG_TYPE_BLOCK:
    1657        return dwg_dxfb_BLOCK (dat, obj);
    1658      case DWG_TYPE_ENDBLK:
    1659        LOG_WARN ("stale %s subentity", obj->dxfname);
    1660        return 0; // dwg_dxfb_ENDBLK(dat, obj);
    1661      case DWG_TYPE_SEQEND:
    1662        LOG_WARN ("stale %s subentity", obj->dxfname);
    1663        return 0; // dwg_dxfb_SEQEND(dat, obj);
    1664  
    1665      case DWG_TYPE_INSERT:
    1666        error = dwg_dxfb_INSERT (dat, obj);
    1667        return error | dxfb_process_INSERT (dat, obj, i);
    1668      case DWG_TYPE_MINSERT:
    1669        error = dwg_dxfb_MINSERT (dat, obj);
    1670        return error | dxfb_process_MINSERT (dat, obj, i);
    1671      case DWG_TYPE_POLYLINE_2D:
    1672        error = dwg_dxfb_POLYLINE_2D (dat, obj);
    1673        return error | dxfb_process_VERTEX_2D (dat, obj, i);
    1674      case DWG_TYPE_POLYLINE_3D:
    1675        error = dwg_dxfb_POLYLINE_3D (dat, obj);
    1676        return error | dxfb_process_VERTEX_3D (dat, obj, i);
    1677      case DWG_TYPE_POLYLINE_PFACE:
    1678        error = dwg_dxfb_POLYLINE_PFACE (dat, obj);
    1679        return error | dxfb_process_VERTEX_PFACE (dat, obj, i);
    1680      case DWG_TYPE_POLYLINE_MESH:
    1681        error = dwg_dxfb_POLYLINE_MESH (dat, obj);
    1682        return error | dxfb_process_VERTEX_MESH (dat, obj, i);
    1683  
    1684      case DWG_TYPE_ATTRIB:
    1685        LOG_WARN ("stale %s subentity", obj->dxfname);
    1686        return dwg_dxfb_ATTRIB (dat, obj);
    1687      case DWG_TYPE_VERTEX_2D:
    1688        LOG_WARN ("stale %s subentity", obj->dxfname);
    1689        return dwg_dxfb_VERTEX_2D (dat, obj);
    1690      case DWG_TYPE_VERTEX_3D:
    1691        LOG_WARN ("stale %s subentity", obj->dxfname);
    1692        return dwg_dxfb_VERTEX_3D (dat, obj);
    1693      case DWG_TYPE_VERTEX_MESH:
    1694        LOG_WARN ("stale %s subentity", obj->dxfname);
    1695        return dwg_dxfb_VERTEX_MESH (dat, obj);
    1696      case DWG_TYPE_VERTEX_PFACE:
    1697        LOG_WARN ("stale %s subentity", obj->dxfname);
    1698        return dwg_dxfb_VERTEX_PFACE (dat, obj);
    1699      case DWG_TYPE_VERTEX_PFACE_FACE:
    1700        LOG_WARN ("stale %s subentity", obj->dxfname);
    1701        return dwg_dxfb_VERTEX_PFACE_FACE (dat, obj);
    1702  
    1703      case DWG_TYPE_ARC:
    1704        return dwg_dxfb_ARC (dat, obj);
    1705      case DWG_TYPE_CIRCLE:
    1706        return dwg_dxfb_CIRCLE (dat, obj);
    1707      case DWG_TYPE_LINE:
    1708        return dwg_dxfb_LINE (dat, obj);
    1709      case DWG_TYPE_DIMENSION_ORDINATE:
    1710        return dwg_dxfb_DIMENSION_ORDINATE (dat, obj);
    1711      case DWG_TYPE_DIMENSION_LINEAR:
    1712        return dwg_dxfb_DIMENSION_LINEAR (dat, obj);
    1713      case DWG_TYPE_DIMENSION_ALIGNED:
    1714        return dwg_dxfb_DIMENSION_ALIGNED (dat, obj);
    1715      case DWG_TYPE_DIMENSION_ANG3PT:
    1716        return dwg_dxfb_DIMENSION_ANG3PT (dat, obj);
    1717      case DWG_TYPE_DIMENSION_ANG2LN:
    1718        return dwg_dxfb_DIMENSION_ANG2LN (dat, obj);
    1719      case DWG_TYPE_DIMENSION_RADIUS:
    1720        return dwg_dxfb_DIMENSION_RADIUS (dat, obj);
    1721      case DWG_TYPE_DIMENSION_DIAMETER:
    1722        return dwg_dxfb_DIMENSION_DIAMETER (dat, obj);
    1723      case DWG_TYPE_POINT:
    1724        return dwg_dxfb_POINT (dat, obj);
    1725      case DWG_TYPE__3DFACE:
    1726        return dwg_dxfb__3DFACE (dat, obj);
    1727      case DWG_TYPE_SOLID:
    1728        return dwg_dxfb_SOLID (dat, obj);
    1729      case DWG_TYPE_TRACE:
    1730        return dwg_dxfb_TRACE (dat, obj);
    1731      case DWG_TYPE_SHAPE:
    1732        return dwg_dxfb_SHAPE (dat, obj);
    1733      case DWG_TYPE_VIEWPORT:
    1734        return minimal ? 0 : dwg_dxfb_VIEWPORT (dat, obj);
    1735      case DWG_TYPE_ELLIPSE:
    1736        return dwg_dxfb_ELLIPSE (dat, obj);
    1737      case DWG_TYPE_SPLINE:
    1738        return dwg_dxfb_SPLINE (dat, obj);
    1739      case DWG_TYPE_REGION:
    1740        return dwg_dxfb_REGION (dat, obj);
    1741      case DWG_TYPE__3DSOLID:
    1742        return dwg_dxfb__3DSOLID (dat, obj);
    1743      case DWG_TYPE_BODY:
    1744        return dwg_dxfb_BODY (dat, obj);
    1745      case DWG_TYPE_RAY:
    1746        return dwg_dxfb_RAY (dat, obj);
    1747      case DWG_TYPE_XLINE:
    1748        return dwg_dxfb_XLINE (dat, obj);
    1749      case DWG_TYPE_DICTIONARY:
    1750        return minimal ? 0 : dwg_dxfb_DICTIONARY (dat, obj);
    1751      case DWG_TYPE_MTEXT:
    1752        return dwg_dxfb_MTEXT (dat, obj);
    1753      case DWG_TYPE_LEADER:
    1754        return dwg_dxfb_LEADER (dat, obj);
    1755      case DWG_TYPE_TOLERANCE:
    1756        return dwg_dxfb_TOLERANCE (dat, obj);
    1757      case DWG_TYPE_MLINE:
    1758        if (0)
    1759          {
    1760            // bypass -Wunused-function
    1761            dwg_dxfb_JUMP (dat, obj);
    1762            dwg_dxfb_LOAD (dat, obj);
    1763          }
    1764  #ifdef DEBUG_CLASSES
    1765        // TODO: looks good, but acad import crashes
    1766        return dwg_dxfb_MLINE (dat, obj);
    1767  #else
    1768        LOG_WARN ("Unhandled Entity MLINE in out_dxfb %u/" FMT_H, obj->index,
    1769                  obj->handle.value)
    1770        if (0)
    1771          // bypass -Wunused-function
    1772          dwg_dxfb_MLINE (dat, obj);
    1773        return DWG_ERR_UNHANDLEDCLASS;
    1774  #endif
    1775      case DWG_TYPE_BLOCK_CONTROL:
    1776      case DWG_TYPE_BLOCK_HEADER:
    1777      case DWG_TYPE_LAYER_CONTROL:
    1778      case DWG_TYPE_LAYER:
    1779      case DWG_TYPE_STYLE_CONTROL:
    1780      case DWG_TYPE_STYLE:
    1781      case DWG_TYPE_LTYPE_CONTROL:
    1782      case DWG_TYPE_LTYPE:
    1783      case DWG_TYPE_VIEW_CONTROL:
    1784      case DWG_TYPE_VIEW:
    1785      case DWG_TYPE_UCS_CONTROL:
    1786      case DWG_TYPE_UCS:
    1787      case DWG_TYPE_VPORT_CONTROL:
    1788      case DWG_TYPE_VPORT:
    1789      case DWG_TYPE_APPID_CONTROL:
    1790      case DWG_TYPE_APPID:
    1791      case DWG_TYPE_DIMSTYLE_CONTROL:
    1792      case DWG_TYPE_DIMSTYLE:
    1793      case DWG_TYPE_VX_CONTROL:
    1794      /* no dxf */
    1795      case DWG_TYPE_VX_TABLE_RECORD:
    1796      /* preR13: no dxfb */
    1797      case DWG_TYPE_REPEAT:
    1798      case DWG_TYPE_ENDREP:
    1799      case DWG_TYPE__3DLINE:
    1800      case DWG_TYPE_LOAD:
    1801      case DWG_TYPE_JUMP:
    1802        LOG_INFO ("Skip unsupported object %s\n", obj->name);
    1803        break;
    1804  
    1805      case DWG_TYPE_GROUP:
    1806        return dwg_dxfb_GROUP (dat, obj);
    1807      case DWG_TYPE_MLINESTYLE:
    1808        return minimal ? 0 : dwg_dxfb_MLINESTYLE (dat, obj);
    1809      case DWG_TYPE_OLE2FRAME:
    1810        return minimal ? 0 : dwg_dxfb_OLE2FRAME (dat, obj);
    1811      case DWG_TYPE_DUMMY:
    1812        return 0;
    1813      case DWG_TYPE_LONG_TRANSACTION:
    1814        return minimal ? 0 : dwg_dxfb_LONG_TRANSACTION (dat, obj);
    1815      case DWG_TYPE_LWPOLYLINE:
    1816        return dwg_dxfb_LWPOLYLINE (dat, obj);
    1817      case DWG_TYPE_HATCH:
    1818        return dwg_dxfb_HATCH (dat, obj);
    1819      case DWG_TYPE_XRECORD:
    1820        return minimal ? 0 : dwg_dxfb_XRECORD (dat, obj);
    1821      case DWG_TYPE_PLACEHOLDER:
    1822        return minimal ? 0 : dwg_dxfb_PLACEHOLDER (dat, obj);
    1823      case DWG_TYPE_PROXY_ENTITY:
    1824        return minimal ? 0 : dwg_dxfb_PROXY_ENTITY (dat, obj);
    1825      case DWG_TYPE_OLEFRAME:
    1826        return minimal ? 0 : dwg_dxfb_OLEFRAME (dat, obj);
    1827      case DWG_TYPE_VBA_PROJECT:
    1828        if (!minimal)
    1829          {
    1830            LOG_ERROR ("Unhandled Object VBA_PROJECT");
    1831            // dwg_dxfb_VBA_PROJECT(dat, obj);
    1832            return DWG_ERR_UNHANDLEDCLASS;
    1833          }
    1834        return 0;
    1835      case DWG_TYPE_LAYOUT:
    1836        return minimal ? 0 : dwg_dxfb_LAYOUT (dat, obj);
    1837      default:
    1838        if (obj->type == obj->parent->layout_type)
    1839          {
    1840            return minimal ? 0 : dwg_dxfb_LAYOUT (dat, obj);
    1841          }
    1842        /* > 500 */
    1843        else if (DWG_ERR_UNHANDLEDCLASS
    1844                 & (error = dwg_dxfb_variable_type (obj->parent, dat,
    1845                                                    (Dwg_Object *)obj)))
    1846          {
    1847            Dwg_Data *dwg = obj->parent;
    1848            int j = obj->type - 500;
    1849            Dwg_Class *klass = NULL;
    1850  
    1851            if (j >= 0 && j < (int)dwg->num_classes
    1852                && obj->fixedtype < DWG_TYPE_FREED)
    1853              klass = &dwg->dwg_class[j];
    1854            if (!klass)
    1855              {
    1856                LOG_WARN ("Unknown object, skipping eed/reactors/xdic");
    1857                return DWG_ERR_INVALIDTYPE;
    1858              }
    1859            return error;
    1860          }
    1861      }
    1862    return DWG_ERR_UNHANDLEDCLASS;
    1863  }
    1864  
    1865  static int
    1866  dxfb_common_entity_handle_data (Bit_Chain *restrict dat,
    1867                                  const Dwg_Object *restrict obj)
    1868  {
    1869    const Dwg_Data *dwg = obj->parent;
    1870    const Dwg_Object_Entity *_ent = obj->tio.entity;
    1871    const Dwg_Object_Entity *_obj = _ent;
    1872    int error = 0;
    1873    BITCODE_BL vcount = 0;
    1874  
    1875    // clang-format off
    1876    if (dat->version >= R_13b1)
    1877      {
    1878        #include "common_entity_handle_data.spec"
    1879      }
    1880    #include "common_entity_data.spec"
    1881    // clang-format on
    1882  
    1883    return error;
    1884  }
    1885  
    1886  // see
    1887  // https://www.autodesk.com/techpubs/autocad/acad2000/dxf/header_section_group_codes_dxf_02.htm
    1888  AFL_GCC_TOOBIG
    1889  static int
    1890  dxfb_header_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
    1891  {
    1892    Dwg_Header_Variables *_obj = &dwg->header_vars;
    1893    Dwg_Object *obj = NULL;
    1894    double ms;
    1895    const int minimal = dwg->opts & DWG_OPTS_MINIMAL;
    1896    const char *codepage = dxf_codepage (dwg->header.codepage, dwg);
    1897  
    1898    if (dwg->header.codepage != 30 && dwg->header.codepage != 29
    1899        && dwg->header.codepage != 0 && dwg->header.version < R_2007)
    1900      {
    1901        // some asian or eastern-european codepage
    1902        // see
    1903        // https://github.com/mozman/ezdxf/blob/master/docs/source/dxfinternals/fileencoding.rst
    1904        LOG_WARN ("Unknown codepage %d, assuming ANSI_1252",
    1905                  dwg->header.codepage);
    1906      }
    1907  
    1908      // clang-format off
    1909    #include "header_variables_dxf.spec"
    1910    // clang-format on
    1911  
    1912    return 0;
    1913  }
    1914  AFL_GCC_POP
    1915  
    1916  static int
    1917  dxfb_classes_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
    1918  {
    1919    BITCODE_BS j;
    1920  
    1921    SECTION (CLASSES);
    1922    LOG_TRACE ("num_classes: %u\n", dwg->num_classes);
    1923    for (j = 0; j < dwg->num_classes; j++)
    1924      {
    1925        const char *dxfname = dwg->dwg_class[j].dxfname;
    1926        if (!dxfname)
    1927          continue;
    1928        // some classes are now builtin
    1929        if (dat->version >= R_2004
    1930            && (strEQc (dxfname, "ACDBPLACEHOLDER")
    1931                || strEQc (dxfname, "LAYOUT")))
    1932          continue;
    1933        if (strEQc (dxfname, "DATATABLE"))
    1934          dxfname = "ACDBDATATABLE";
    1935        RECORD (CLASS);
    1936        VALUE_TV (dxfname, 1);
    1937        VALUE_T (dwg->dwg_class[j].cppname, 2);
    1938        if (strEQc (dxfname, "SPATIAL_INDEX"))
    1939          VALUE_TFF ("AutoCAD 2000", 3)
    1940        else
    1941          VALUE_T (dwg->dwg_class[j].appname, 3)
    1942        VALUE_RL (dwg->dwg_class[j].proxyflag, 90);
    1943        SINCE (R_2004)
    1944        {
    1945          VALUE_RL (dwg->dwg_class[j].num_instances, 91);
    1946        }
    1947        VALUE_RS (dwg->dwg_class[j].is_zombie, 280); // acad: was-a-zombie
    1948        // Is-an-entity. 1f2 for entities, 1f3 for objects
    1949        VALUE_RS (dwg->dwg_class[j].item_class_id == 0x1F2 ? 1 : 0, 281);
    1950      }
    1951    ENDSEC ();
    1952    return 0;
    1953  }
    1954  
    1955  static int
    1956  dxfb_tables_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
    1957  {
    1958    int error = 0;
    1959    unsigned int i;
    1960  
    1961    SECTION (TABLES);
    1962    SINCE (R_9c1)
    1963    {
    1964      Dwg_Object *ctrl = dwg_get_first_object (dwg, DWG_TYPE_VPORT_CONTROL);
    1965      if (ctrl && ctrl->tio.object && ctrl->tio.object->tio.VPORT_CONTROL)
    1966        {
    1967          Dwg_Object *obj = ctrl;
    1968          Dwg_Object_VPORT_CONTROL *_ctrl = ctrl->tio.object->tio.VPORT_CONTROL;
    1969          TABLE (VPORT);
    1970          // add handle 5 here at first
    1971          COMMON_TABLE_CONTROL_FLAGS;
    1972          error |= dwg_dxfb_VPORT_CONTROL (dat, ctrl);
    1973          // TODO how far back can DXF read 1000?
    1974          if (dat->version != dat->from_version && dat->from_version >= R_2000)
    1975            {
    1976              /* if saved from newer version, eg. AC1032: */
    1977              VALUE_TV ("ACAD", 1001);
    1978              VALUE_TV ("DbSaveVer", 1000);
    1979              VALUE_RS (dwg->header.dwg_version, 1071); // so that 69 is R_2018
    1980            }
    1981          for (i = 0; i < _ctrl->num_entries; i++)
    1982            {
    1983              if (!_ctrl->entries)
    1984                break;
    1985              if (!_ctrl->entries[i])
    1986                continue;
    1987              obj = dwg_ref_object (dwg, _ctrl->entries[i]);
    1988              if (obj && obj->type == DWG_TYPE_VPORT)
    1989                {
    1990                  // reordered in the DXF: 2,70,10,11,12,13,14,15,16,...
    1991                  // special-cased in the spec
    1992                  error |= dwg_dxfb_VPORT (dat, obj);
    1993                }
    1994            }
    1995          ENDTAB ();
    1996        }
    1997    }
    1998    {
    1999      Dwg_Object *ctrl = dwg_get_first_object (dwg, DWG_TYPE_LTYPE_CONTROL);
    2000      if (ctrl && ctrl->tio.object && ctrl->tio.object->tio.LTYPE_CONTROL)
    2001        {
    2002          Dwg_Object *obj = ctrl;
    2003          Dwg_Object_LTYPE_CONTROL *_ctrl = ctrl->tio.object->tio.LTYPE_CONTROL;
    2004          TABLE (LTYPE);
    2005          COMMON_TABLE_CONTROL_FLAGS;
    2006          error |= dwg_dxfb_LTYPE_CONTROL (dat, ctrl);
    2007          // first the 2 builtin ltypes: ByBlock, ByLayer
    2008          if ((obj = dwg_ref_object (dwg, dwg->header_vars.LTYPE_BYBLOCK)))
    2009            {
    2010              dwg_dxfb_LTYPE (dat, obj);
    2011            }
    2012          if ((obj = dwg_ref_object (dwg, dwg->header_vars.LTYPE_BYLAYER)))
    2013            {
    2014              error |= dwg_dxfb_LTYPE (dat, obj);
    2015            }
    2016          // here LTYPE_CONTINUOUS is already included
    2017          for (i = 0; i < _ctrl->num_entries; i++)
    2018            {
    2019              if (!_ctrl->entries)
    2020                break;
    2021              if (!_ctrl->entries[i])
    2022                continue;
    2023              obj = dwg_ref_object (dwg, _ctrl->entries[i]);
    2024              if (obj && obj->type == DWG_TYPE_LTYPE)
    2025                {
    2026                  error |= dwg_dxfb_LTYPE (dat, obj);
    2027                }
    2028            }
    2029          ENDTAB ();
    2030        }
    2031    }
    2032    {
    2033      Dwg_Object *ctrl = dwg_get_first_object (dwg, DWG_TYPE_LAYER_CONTROL);
    2034      if (ctrl && ctrl->tio.object && ctrl->tio.object->tio.LAYER_CONTROL)
    2035        {
    2036          Dwg_Object *obj = ctrl;
    2037          Dwg_Object_LAYER_CONTROL *_ctrl = ctrl->tio.object->tio.LAYER_CONTROL;
    2038          TABLE (LAYER);
    2039          COMMON_TABLE_CONTROL_FLAGS;
    2040          error |= dwg_dxfb_LAYER_CONTROL (dat, ctrl);
    2041          for (i = 0; i < _ctrl->num_entries; i++)
    2042            {
    2043              if (!_ctrl->entries)
    2044                break;
    2045              if (!_ctrl->entries[i])
    2046                continue;
    2047              obj = dwg_ref_object (dwg, _ctrl->entries[i]);
    2048              if (obj && obj->type == DWG_TYPE_LAYER)
    2049                {
    2050                  error |= dwg_dxfb_LAYER (dat, obj);
    2051                  // else if (obj && obj->type == DWG_TYPE_DICTIONARY)
    2052                  //  error |= dwg_dxfb_DICTIONARY(dat, obj);
    2053                }
    2054            }
    2055          ENDTAB ();
    2056        }
    2057    }
    2058    {
    2059      Dwg_Object *ctrl = dwg_get_first_object (dwg, DWG_TYPE_STYLE_CONTROL);
    2060      if (ctrl && ctrl->tio.object && ctrl->tio.object->tio.STYLE_CONTROL)
    2061        {
    2062          Dwg_Object *obj = ctrl;
    2063          Dwg_Object_STYLE_CONTROL *_ctrl = ctrl->tio.object->tio.STYLE_CONTROL;
    2064          TABLE (STYLE);
    2065          COMMON_TABLE_CONTROL_FLAGS;
    2066          error |= dwg_dxfb_STYLE_CONTROL (dat, ctrl);
    2067          for (i = 0; i < _ctrl->num_entries; i++)
    2068            {
    2069              if (!_ctrl->entries)
    2070                break;
    2071              if (!_ctrl->entries[i])
    2072                continue;
    2073              obj = dwg_ref_object (dwg, _ctrl->entries[i]);
    2074              if (obj && obj->type == DWG_TYPE_STYLE)
    2075                {
    2076                  error |= dwg_dxfb_STYLE (dat, obj);
    2077                }
    2078            }
    2079          ENDTAB ();
    2080        }
    2081    }
    2082    {
    2083      Dwg_Object *ctrl = dwg_get_first_object (dwg, DWG_TYPE_VIEW_CONTROL);
    2084      if (ctrl && ctrl->tio.object && ctrl->tio.object->tio.VIEW_CONTROL)
    2085        {
    2086          Dwg_Object *obj = ctrl;
    2087          Dwg_Object_VIEW_CONTROL *_ctrl = ctrl->tio.object->tio.VIEW_CONTROL;
    2088          TABLE (VIEW);
    2089          COMMON_TABLE_CONTROL_FLAGS;
    2090          error |= dwg_dxfb_VIEW_CONTROL (dat, ctrl);
    2091          for (i = 0; i < _ctrl->num_entries; i++)
    2092            {
    2093              if (!_ctrl->entries)
    2094                break;
    2095              if (!_ctrl->entries[i])
    2096                continue;
    2097              obj = dwg_ref_object (dwg, _ctrl->entries[i]);
    2098              if (obj && obj->type == DWG_TYPE_VIEW)
    2099                error |= dwg_dxfb_VIEW (dat, obj);
    2100            }
    2101          ENDTAB ();
    2102        }
    2103    }
    2104    SINCE (R_9c1)
    2105    {
    2106      Dwg_Object *ctrl = dwg_get_first_object (dwg, DWG_TYPE_UCS_CONTROL);
    2107      if (ctrl && ctrl->tio.object && ctrl->tio.object->tio.UCS_CONTROL)
    2108        {
    2109          Dwg_Object *obj = ctrl;
    2110          Dwg_Object_UCS_CONTROL *_ctrl = ctrl->tio.object->tio.UCS_CONTROL;
    2111          TABLE (UCS);
    2112          COMMON_TABLE_CONTROL_FLAGS;
    2113          error |= dwg_dxfb_UCS_CONTROL (dat, ctrl);
    2114          for (i = 0; i < _ctrl->num_entries; i++)
    2115            {
    2116              if (!_ctrl->entries)
    2117                break;
    2118              if (!_ctrl->entries[i])
    2119                continue;
    2120              obj = dwg_ref_object (dwg, _ctrl->entries[i]);
    2121              if (obj && obj->type == DWG_TYPE_UCS)
    2122                {
    2123                  error |= dwg_dxfb_UCS (dat, obj);
    2124                }
    2125            }
    2126          ENDTAB ();
    2127        }
    2128    }
    2129    SINCE (R_11b1)
    2130    {
    2131      Dwg_Object *ctrl = dwg_get_first_object (dwg, DWG_TYPE_APPID_CONTROL);
    2132      if (ctrl && ctrl->tio.object && ctrl->tio.object->tio.APPID_CONTROL)
    2133        {
    2134          Dwg_Object *obj = ctrl;
    2135          Dwg_Object_APPID_CONTROL *_ctrl = ctrl->tio.object->tio.APPID_CONTROL;
    2136          TABLE (APPID);
    2137          COMMON_TABLE_CONTROL_FLAGS;
    2138          error |= dwg_dxfb_APPID_CONTROL (dat, ctrl);
    2139          for (i = 0; i < _ctrl->num_entries; i++)
    2140            {
    2141              if (!_ctrl->entries)
    2142                break;
    2143              if (!_ctrl->entries[i])
    2144                continue;
    2145              obj = dwg_ref_object (dwg, _ctrl->entries[i]);
    2146              if (obj && obj->type == DWG_TYPE_APPID)
    2147                {
    2148                  error |= dwg_dxfb_APPID (dat, obj);
    2149                }
    2150            }
    2151          ENDTAB ();
    2152        }
    2153    }
    2154    SINCE (R_11b1)
    2155    {
    2156      Dwg_Object *ctrl = dwg_get_first_object (dwg, DWG_TYPE_DIMSTYLE_CONTROL);
    2157      if (ctrl && ctrl->tio.object && ctrl->tio.object->tio.DIMSTYLE_CONTROL)
    2158        {
    2159          Dwg_Object *obj = ctrl;
    2160          Dwg_Object_DIMSTYLE_CONTROL *_ctrl
    2161              = ctrl->tio.object->tio.DIMSTYLE_CONTROL;
    2162          TABLE (DIMSTYLE);
    2163          COMMON_TABLE_CONTROL_FLAGS;
    2164          dwg_dxfb_DIMSTYLE_CONTROL (dat, ctrl);
    2165          // ignoring morehandles
    2166          for (i = 0; i < _ctrl->num_entries; i++)
    2167            {
    2168              if (!_ctrl->entries)
    2169                break;
    2170              if (!_ctrl->entries[i])
    2171                continue;
    2172              obj = dwg_ref_object (dwg, _ctrl->entries[i]);
    2173              if (obj && obj->type == DWG_TYPE_DIMSTYLE)
    2174                {
    2175                  error |= dwg_dxfb_DIMSTYLE (dat, obj);
    2176                }
    2177            }
    2178          ENDTAB ();
    2179        }
    2180    }
    2181    // fool the warnings. this table is nowhere to be found in the wild. maybe
    2182    // pre-R11
    2183    if (0)
    2184      {
    2185        Dwg_Object *ctrl = dwg_get_first_object (dwg, DWG_TYPE_VX_CONTROL);
    2186        Dwg_Object_VX_CONTROL *_ctrl = ctrl->tio.object->tio.VX_CONTROL;
    2187        if (ctrl && ctrl->fixedtype == DWG_TYPE_VX_CONTROL)
    2188          {
    2189            Dwg_Object *obj = ctrl;
    2190            TABLE (VX_TABLE_RECORD);
    2191            COMMON_TABLE_CONTROL_FLAGS;
    2192            error |= dwg_dxfb_VX_CONTROL (dat, ctrl);
    2193            for (i = 0; i < _ctrl->num_entries; i++)
    2194              {
    2195                if (!_ctrl->entries)
    2196                  break;
    2197                if (!_ctrl->entries[i])
    2198                  continue;
    2199                obj = dwg_ref_object (dwg, _ctrl->entries[i]);
    2200                if (obj && obj->type == DWG_TYPE_VX_TABLE_RECORD)
    2201                  {
    2202                    RECORD (VX_TABLE_RECORD);
    2203                    error |= dwg_dxfb_VX_TABLE_RECORD (dat, obj);
    2204                  }
    2205              }
    2206            ENDTAB ();
    2207          }
    2208      }
    2209    SINCE (R_12)
    2210    {
    2211      Dwg_Object *ctrl, *obj;
    2212      Dwg_Object_BLOCK_CONTROL *_ctrl = dwg_block_control (dwg);
    2213      Dwg_Object_Ref *ref;
    2214      Dwg_Object *mspace = NULL, *pspace = NULL;
    2215      if (!_ctrl)
    2216        {
    2217          LOG_ERROR ("BLOCK_CONTROL missing");
    2218          return DWG_ERR_INVALIDDWG;
    2219        }
    2220      ctrl = dwg_obj_generic_to_object (_ctrl, &error);
    2221      if (!ctrl || ctrl->fixedtype != DWG_TYPE_BLOCK_CONTROL)
    2222        return DWG_ERR_INVALIDDWG;
    2223  
    2224      obj = ctrl;
    2225      TABLE (BLOCK_RECORD);
    2226      COMMON_TABLE_CONTROL_FLAGS;
    2227      error |= dwg_dxfb_BLOCK_CONTROL (dat, ctrl);
    2228  
    2229  #if 0
    2230      for (i = 0; i < dwg->num_objects; i++)
    2231        {
    2232          Dwg_Object *hdr = &dwg->object[i];
    2233          if (hdr && hdr->supertype == DWG_SUPERTYPE_OBJECT
    2234              && hdr->type == DWG_TYPE_BLOCK_HEADER)
    2235            {
    2236              RECORD (BLOCK_RECORD);
    2237              error |= dwg_dxfb_BLOCK_HEADER (dat, hdr);
    2238            }
    2239        }
    2240  #else
    2241      mspace = dwg_model_space_object (dwg);
    2242      if (!mspace)
    2243        return DWG_ERR_INVALIDDWG;
    2244      RECORD (BLOCK_RECORD);
    2245      error |= dwg_dxfb_BLOCK_HEADER (dat, mspace);
    2246  
    2247      ref = dwg_paper_space_ref (dwg);
    2248      pspace = ref ? dwg_ref_object (dwg, ref) : NULL;
    2249      if (pspace)
    2250        {
    2251          RECORD (BLOCK_RECORD);
    2252          error |= dwg_dxfb_BLOCK_HEADER (dat, pspace);
    2253        }
    2254  
    2255      for (i = 0; i < _ctrl->num_entries; i++)
    2256        {
    2257          if (!_ctrl->entries)
    2258            break;
    2259          if (!_ctrl->entries[i])
    2260            continue;
    2261          obj = dwg_ref_object (dwg, _ctrl->entries[i]);
    2262          if (obj && obj->type == DWG_TYPE_BLOCK_HEADER && obj != mspace
    2263              && obj != pspace)
    2264            {
    2265              RECORD (BLOCK_RECORD);
    2266              error |= dwg_dxfb_BLOCK_HEADER (dat, obj);
    2267            }
    2268        }
    2269  #endif
    2270  
    2271      ENDTAB ();
    2272    }
    2273  
    2274    ENDSEC ();
    2275    return 0;
    2276  }
    2277  
    2278  static void
    2279  dxfb_ENDBLK_empty (Bit_Chain *restrict dat, const Dwg_Object *restrict hdr)
    2280  {
    2281    Dwg_Object *obj = (Dwg_Object *)calloc (1, sizeof (Dwg_Object));
    2282    obj->parent = hdr->parent;
    2283    obj->index = obj->parent->num_objects;
    2284    dwg_setup_ENDBLK (obj);
    2285    obj->tio.entity->ownerhandle
    2286        = (Dwg_Object_Ref *)calloc (1, sizeof (Dwg_Object_Ref));
    2287    obj->tio.entity->ownerhandle->obj = (Dwg_Object *)hdr;
    2288    obj->tio.entity->ownerhandle->handleref = hdr->handle;
    2289    obj->tio.entity->ownerhandle->absolute_ref = hdr->handle.value;
    2290    dwg_dxfb_ENDBLK (dat, obj);
    2291    free (obj->tio.entity->tio.ENDBLK);
    2292    free (obj->tio.entity->ownerhandle);
    2293    free (obj->tio.entity);
    2294    free (obj);
    2295  }
    2296  
    2297  static int
    2298  dxfb_block_write (Bit_Chain *restrict dat, const Dwg_Object *restrict hdr,
    2299                    const Dwg_Object *restrict mspace,
    2300                    const Dwg_Object *restrict pspace, int *restrict i)
    2301  {
    2302    int error = 0;
    2303    Dwg_Object *restrict obj = get_first_owned_block (hdr); // BLOCK
    2304    const Dwg_Object_BLOCK_HEADER *restrict _hdr
    2305        = hdr->tio.object->tio.BLOCK_HEADER;
    2306    Dwg_Object *restrict endblk;
    2307    Dwg_Data *dwg = hdr->parent;
    2308    BITCODE_RLL mspace_ref = mspace ? mspace->handle.value : 0;
    2309    BITCODE_RLL pspace_ref = pspace ? pspace->handle.value : 0;
    2310  
    2311    if (obj)
    2312      error |= dwg_dxfb_object (dat, obj, i);
    2313    else
    2314      {
    2315        LOG_ERROR ("BLOCK_HEADER.block_entity missing");
    2316        return DWG_ERR_INVALIDDWG;
    2317      }
    2318    // Skip all *Model_Space and *Paper_Space entities, esp. new ones: UNDERLAY,
    2319    // MULTILEADER, ... They are all under ENTITIES later. Note: the objects may
    2320    // vary (e.g. example_2000), but the index not
    2321    if ((hdr == mspace) || (hdr->index == mspace->index))
    2322      obj = NULL;
    2323    else if ((hdr == pspace) || (pspace && hdr->index == pspace->index))
    2324      obj = NULL;
    2325    else
    2326      obj = get_first_owned_entity (hdr); // first_entity
    2327    while (obj)
    2328      {
    2329        if (obj->supertype == DWG_SUPERTYPE_ENTITY
    2330            && obj->fixedtype != DWG_TYPE_ENDBLK && obj->tio.entity != NULL
    2331            && (obj->tio.entity->entmode != 2
    2332                || (obj->tio.entity->ownerhandle != NULL
    2333                    && obj->tio.entity->ownerhandle->absolute_ref != mspace_ref
    2334                    && obj->tio.entity->ownerhandle->absolute_ref
    2335                           != pspace_ref)))
    2336          error |= dwg_dxfb_object (dat, obj, i);
    2337        obj = get_next_owned_entity (hdr, obj); // until last_entity
    2338      }
    2339    endblk = get_last_owned_block (hdr);
    2340    if (endblk)
    2341      error |= dwg_dxfb_ENDBLK (dat, endblk);
    2342    else
    2343      {
    2344        LOG_WARN ("Empty ENDBLK for \"%s\" " FORMAT_BL, _hdr->name,
    2345                  hdr ? hdr->tio.object->objid : 0);
    2346        dxfb_ENDBLK_empty (dat, hdr);
    2347      }
    2348    return error;
    2349  }
    2350  
    2351  static int
    2352  dxfb_blocks_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
    2353  {
    2354    int error = 0;
    2355    int i = 0;
    2356    Dwg_Object *restrict mspace = dwg_model_space_object (dwg);
    2357    Dwg_Object *restrict pspace = dwg_paper_space_object (dwg);
    2358  
    2359    if (!mspace)
    2360      return DWG_ERR_UNHANDLEDCLASS;
    2361  
    2362    SECTION (BLOCKS);
    2363    /* There may be unconnected blocks (not caught by above),
    2364       such as pspace referred by a LAYOUT or DIMENSION, so for simplicity just
    2365       scan all BLOCK_HEADER's and just skip *Model_Space and *Paper_Space.
    2366       pspace might be NULL.
    2367     */
    2368    {
    2369      for (i = 0; (BITCODE_BL)i < dwg->num_objects; i++)
    2370        {
    2371          const Dwg_Object *restrict obj = &dwg->object[i];
    2372          if (obj->supertype == DWG_SUPERTYPE_OBJECT
    2373              && obj->type == DWG_TYPE_BLOCK_HEADER)
    2374            {
    2375              error |= dxfb_block_write (dat, obj, mspace, pspace, &i);
    2376            }
    2377        }
    2378    }
    2379  
    2380    ENDSEC ();
    2381    return error;
    2382  }
    2383  
    2384  static int
    2385  dxfb_entities_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
    2386  {
    2387    int error = 0;
    2388    Dwg_Object *restrict ms = dwg_model_space_object (dwg);
    2389    Dwg_Object *restrict ps = dwg_paper_space_object (dwg);
    2390    Dwg_Object *obj;
    2391    if (!ms)
    2392      return DWG_ERR_INVALIDDWG;
    2393  
    2394    SECTION (ENTITIES);
    2395    // First mspace
    2396    obj = get_first_owned_entity (ms); // first_entity or entities[0]
    2397    while (obj)
    2398      {
    2399        int i = obj->index;
    2400        error |= dwg_dxfb_object (dat, obj, &i);
    2401        obj = get_next_owned_block_entity (ms, obj); // until last_entity
    2402      }
    2403    // Then all pspace entities. just filter out other BLOCKS entities
    2404    if (ps)
    2405      {
    2406        obj = get_first_owned_entity (ps);
    2407        while (obj)
    2408          {
    2409            int i = obj->index;
    2410            error |= dwg_dxfb_object (dat, obj, &i);
    2411            obj = get_next_owned_block_entity (ps, obj);
    2412          }
    2413      }
    2414    ENDSEC ();
    2415    return error;
    2416  }
    2417  
    2418  static int
    2419  dxfb_objects_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
    2420  {
    2421    int error = 0;
    2422    int i = 0;
    2423    Dwg_Object *nod;
    2424  
    2425    SECTION (OBJECTS);
    2426    // The NOD (Named Object Dict) must be always the very first OBJECT,
    2427    // not just DICTIONARY.
    2428    nod = dwg_get_first_object (dwg, DWG_TYPE_DICTIONARY);
    2429    if (nod)
    2430      error |= dwg_dxfb_object (dat, nod, &i);
    2431    for (i = 0; (BITCODE_BL)i < dwg->num_objects; i++)
    2432      {
    2433        const Dwg_Object *restrict obj = &dwg->object[i];
    2434        if (obj == nod)
    2435          continue;
    2436        if (obj->supertype == DWG_SUPERTYPE_OBJECT
    2437            && obj->type != DWG_TYPE_BLOCK_HEADER && !dwg_obj_is_control (obj))
    2438          error |= dwg_dxfb_object (dat, obj, &i);
    2439      }
    2440    ENDSEC ();
    2441    return error;
    2442  }
    2443  
    2444  static int
    2445  dxfb_thumbnail_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
    2446  {
    2447    Bit_Chain *pic = (Bit_Chain *)&dwg->thumbnail;
    2448    if (pic->chain && pic->size && pic->size > 10)
    2449      {
    2450        SECTION (THUMBNAILIMAGE);
    2451        VALUE_RL (pic->size, 90);
    2452        VALUE_BINARY (pic->chain, pic->size, 310);
    2453        ENDSEC ();
    2454      }
    2455    return 0;
    2456  }
    2457  
    2458  int
    2459  dwg_write_dxfb (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
    2460  {
    2461    int error = 0;
    2462    const int minimal = dwg->opts & DWG_OPTS_MINIMAL;
    2463  
    2464    loglevel = dwg->opts & DWG_OPTS_LOGLEVEL;
    2465    if (dat->from_version == R_INVALID)
    2466      dat->from_version = dat->version;
    2467    if (dwg->header.version <= R_2000 && dwg->header.from_version > R_2000)
    2468      dwg_fixup_BLOCKS_entities (dwg);
    2469    dwg_resolve_objectrefs_silent (dwg);
    2470  
    2471    fprintf (dat->fh, "AutoCAD Binary DXF\r\n%c%c", 0x1a, 0);
    2472    // VALUE_TV (PACKAGE_STRING, 999); // not used in binary DXF
    2473  
    2474    // a minimal header requires only $ACADVER, $HANDSEED, and then ENTITIES
    2475    // see https://pythonhosted.org/ezdxf/dxfinternals/filestructure.html
    2476    dxfb_header_write (dat, dwg);
    2477  
    2478    if (!minimal)
    2479      {
    2480        // if downgraded to r13, but we still have classes, keep the
    2481        // classes
    2482        if ((dat->from_version >= R_13b1 && dwg->num_classes)
    2483            || dat->version >= R_2000)
    2484          {
    2485            if (dxfb_classes_write (dat, dwg) >= DWG_ERR_CRITICAL)
    2486              goto fail;
    2487          }
    2488  
    2489        if (dxfb_tables_write (dat, dwg) >= DWG_ERR_CRITICAL)
    2490          goto fail;
    2491  
    2492        if (dxfb_blocks_write (dat, dwg) >= DWG_ERR_CRITICAL)
    2493          goto fail;
    2494      }
    2495  
    2496    if (dxfb_entities_write (dat, dwg) >= DWG_ERR_CRITICAL)
    2497      goto fail;
    2498  
    2499    if (!minimal)
    2500      {
    2501        SINCE (R_13b1)
    2502        {
    2503          if (dxfb_objects_write (dat, dwg) >= DWG_ERR_CRITICAL)
    2504            goto fail;
    2505        }
    2506        SINCE (R_2000)
    2507        {
    2508          if (dxfb_thumbnail_write (dat, dwg) >= DWG_ERR_CRITICAL)
    2509            goto fail;
    2510        }
    2511      }
    2512    RECORD (EOF);
    2513  
    2514    return 0;
    2515  fail:
    2516    return 1;
    2517  }
    2518  
    2519  #undef IS_PRINT
    2520  #undef IS_DXF