(root)/
libredwg-0.13/
test/
unit-testing/
dxf_test.c
       1  /* ex: ft=c: -*- mode: c; -*- */
       2  /*****************************************************************************/
       3  /*  LibreDWG - free implementation of the DWG file format                    */
       4  /*                                                                           */
       5  /*  Copyright (C) 2020 Free Software Foundation, Inc.                        */
       6  /*                                                                           */
       7  /*  This library is free software, licensed under the terms of the GNU       */
       8  /*  General Public License as published by the Free Software Foundation,     */
       9  /*  either version 3 of the License, or (at your option) any later version.  */
      10  /*  You should have received a copy of the GNU General Public License        */
      11  /*  along with this program.  If not, see <http://www.gnu.org/licenses/>.    */
      12  /*****************************************************************************/
      13  
      14  /* compare against dxf values, generated from examples/unknown */
      15  /* written by: Reini Urban */
      16  
      17  #define DXF_TEST_C
      18  #include <stdio.h>
      19  #include <stdlib.h>
      20  #include <string.h>
      21  #include <math.h>
      22  
      23  #include "config.h"
      24  #ifdef HAVE_UNISTD_H
      25  #  include <unistd.h>
      26  #endif
      27  #include "../../programs/my_stat.h"
      28  #include "common.h"
      29  #include "decode.h"
      30  #include "tests_common.h"
      31  #include "dwg.h"
      32  #include "dwg_api.h"
      33  
      34  int g_counter;
      35  #define MAX_COUNTER 10
      36  int g_max_count;
      37  int g_all;
      38  
      39  void object_alias (char *restrict name);
      40  void entity_alias (char *restrict name);
      41  ATTRIBUTE_MALLOC char *dwg_dynapi_subclass_name (const char *restrict type);
      42  int dwg_dynapi_subclass_size (const char *restrict name);
      43  
      44  #include "../../examples/unknown.h"
      45  
      46  static struct _unknown_dxf unknown_dxf[] = {
      47  // see log_unknown_dxf.pl
      48  #include "../../examples/alldxf_0.inc"
      49    { NULL, NULL, 0, "", 0, 0, 0, 0, 0, 0, 0, NULL }
      50  };
      51  
      52  #include "../../examples/alldxf_1.inc"
      53  
      54  static void
      55  test_subclass (const Dwg_Data *restrict dwg, const void *restrict ptr,
      56                 const struct _unknown_field *restrict f,
      57                 const Dwg_DYNAPI_field *restrict fp,
      58                 const char *restrict subclass, const char *restrict fieldname,
      59                 const char *restrict key, int index)
      60  {
      61    Dwg_DYNAPI_field field;
      62    enum RESBUF_VALUE_TYPE vtype;
      63    Dwg_Version_Type dwg_version = dwg->header.version;
      64  
      65    if (!ptr)
      66      {
      67        fail ("test_subclass %s.%s: empty ptr", subclass, key);
      68        return;
      69      }
      70    if (strEQc (fp->type, "CMC"))
      71      {
      72        BITCODE_CMC color;
      73        if (dwg_dynapi_subclass_value (ptr, subclass, key, &color, &field))
      74          {
      75            BITCODE_BS i = (BITCODE_BS)strtol (f->value, NULL, 10);
      76            if (i == color.index)
      77              {
      78                if (g_counter > g_max_count)
      79                  pass ();
      80                else
      81                  ok ("%s[%d].%s: %s", fieldname, index, key, f->value);
      82              }
      83            else if (field.type)
      84              fail ("%s[%d].%s: %d <=> \"%s\" [%s]", fieldname, index, key,
      85                    (int)color.index, f->value, field.type);
      86            else
      87              {
      88                if (g_counter > g_max_count)
      89                  pass ();
      90                else
      91                  ok ("%s[%d].%s: %d <=> \"%s\" [CMC] (TODO)", fieldname, index,
      92                      key, (int)color.index, f->value);
      93              }
      94          }
      95        return;
      96      }
      97    vtype = dwg_resbuf_value_type (f->code);
      98    if (vtype == DWG_VT_REAL && fp->size >= 16)
      99      goto DWG_VT_POINT3D;
     100    if (vtype == DWG_VT_INT8 && fp->size == 1 && strEQc (fp->type, "B"))
     101      goto DWG_VT_BOOL;
     102    if ((vtype == DWG_VT_BOOL || vtype == DWG_VT_INT16) && fp->size == 1
     103        && strEQc (fp->type, "RC"))
     104      goto DWG_VT_INT8;
     105    if (vtype == DWG_VT_INT8 && fp->size == 2)
     106      goto DWG_VT_INT16;
     107    if (vtype == DWG_VT_INT16 && fp->size == 4)
     108      goto DWG_VT_INT32;
     109    if (vtype == DWG_VT_INT32 && fp->size == 8)
     110      goto DWG_VT_INT64;
     111    switch (vtype)
     112      {
     113      case DWG_VT_STRING:
     114        {
     115          char *value;
     116          int isnew = 0;
     117          if (dwg_dynapi_subclass_value (ptr, subclass, key, &value, &field))
     118            {
     119              // convert to UTF8
     120              if (value && dwg_version >= R_2007
     121                  && strNE (field.type, "TF")) /* not TF */
     122                {
     123                  value = bit_convert_TU ((BITCODE_TU)value);
     124                  if (!value) // some conversion error, invalid wchar (nyi)
     125                    {
     126                      fail ("%s[%d].%s: NULL [STRING %s]", fieldname, index, key,
     127                            field.type);
     128                    }
     129                  else
     130                    {
     131                      isnew = 1;
     132                    }
     133                }
     134              if (!value || strEQ (value, f->value))
     135                {
     136                  if (g_counter > g_max_count)
     137                    pass ();
     138                  else
     139                    ok ("%s[%d].%s: %s", fieldname, index, key, value);
     140                }
     141              else
     142                fail ("%s[%d].%s: %s [STRING %s]", fieldname, index, key, value,
     143                      field.type);
     144            }
     145          if (isnew)
     146            free (value);
     147        }
     148        break;
     149      case DWG_VT_POINT3D:
     150      DWG_VT_POINT3D:
     151        {
     152          BITCODE_3BD pt;
     153          if (dwg_dynapi_subclass_value (ptr, subclass, key, &pt, &field))
     154            {
     155              double d = strtod (f->value, NULL);
     156              double ptv;
     157              int offset = f->code;
     158              if (strstr (field.type, "_1"))
     159                {
     160                  while (offset > 10) // 10,11,12
     161                    offset -= 10;
     162                  if (offset == 2 && field.size > 2 * sizeof (double))
     163                    ptv = pt.z;
     164                  else if (offset == 1)
     165                    ptv = pt.y;
     166                  else
     167                    ptv = pt.x;
     168                }
     169              else // 10/20/30
     170                {
     171                  offset = offset % 100;
     172                  if (offset >= 30 && field.size > 2 * sizeof (double))
     173                    ptv = pt.z;
     174                  else if (offset >= 20)
     175                    ptv = pt.y;
     176                  else
     177                    ptv = pt.x;
     178                }
     179              if (fabs (ptv - d) < 1e-6)
     180                {
     181                  if (g_counter > g_max_count)
     182                    pass ();
     183                  else
     184                    ok ("%s[%d].%s: %f [%s %d]", fieldname, index, key, ptv,
     185                        field.type, f->code);
     186                }
     187              else
     188                fail ("%s[%d].%s: %f <=> \"%s\" [%s %d]", fieldname, index, key,
     189                      ptv, f->value, field.type, f->code);
     190            }
     191        }
     192        break;
     193      case DWG_VT_REAL:
     194        {
     195          double value;
     196          if (dwg_dynapi_subclass_value (ptr, subclass, key, &value, &field))
     197            {
     198              double d = strtod (f->value, NULL);
     199              if (f->code >= 50 && f->code < 59)
     200                d = deg2rad (d);
     201              if (fabs (value - d) < 1e-6)
     202                {
     203                  if (g_counter > g_max_count)
     204                    pass ();
     205                  else
     206                    ok ("%s[%d].%s: %f", fieldname, index, key, value);
     207                }
     208              else
     209                fail ("%s[%d].%s: %f <=> \"%s\" [REAL %s]", fieldname, index,
     210                      key, value, f->value, field.type);
     211            }
     212        }
     213        break;
     214      case DWG_VT_BOOL:
     215      DWG_VT_BOOL:
     216        {
     217          BITCODE_B value;
     218          if (dwg_dynapi_subclass_value (ptr, subclass, key, &value, &field))
     219            {
     220              BITCODE_B i = (BITCODE_B)strtol (f->value, NULL, 10);
     221              if (i == value)
     222                {
     223                  if (g_counter > g_max_count)
     224                    pass ();
     225                  else
     226                    ok ("%s[%d].%s: %d", fieldname, index, key, value);
     227                }
     228              else
     229                fail ("%s[%d].%s: %d <=> \"%s\" [BOOL %s]", fieldname, index,
     230                      key, value, f->value, field.type);
     231            }
     232        }
     233        break;
     234      case DWG_VT_INT8:
     235      DWG_VT_INT8:
     236        {
     237          BITCODE_RC value;
     238          if (dwg_dynapi_subclass_value (ptr, subclass, key, &value, &field))
     239            {
     240              BITCODE_RC i = (BITCODE_RC)strtol (f->value, NULL, 10);
     241              if (i == value)
     242                {
     243                  if (g_counter > g_max_count)
     244                    pass ();
     245                  else
     246                    ok ("%s[%d].%s: %d", fieldname, index, key, value);
     247                }
     248              else if (field.type)
     249                fail ("%s[%d].%s: %d <=> \"%s\" [INT8 %s]", fieldname, index,
     250                      key, value, f->value, field.type);
     251              else
     252                {
     253                  if (g_counter > g_max_count)
     254                    pass ();
     255                  else
     256                    ok ("%s[%d].%s: %d <=> \"%s\" [INT8] (TODO)", fieldname,
     257                        index, key, value, f->value);
     258                }
     259            }
     260        }
     261        break;
     262      case DWG_VT_INT16:
     263      DWG_VT_INT16:
     264        {
     265          BITCODE_BS value;
     266          if (dwg_dynapi_subclass_value (ptr, subclass, key, &value, &field))
     267            {
     268              BITCODE_BS i = (BITCODE_BS)strtol (f->value, NULL, 10);
     269              if (i == value)
     270                {
     271                  if (g_counter > g_max_count)
     272                    pass ();
     273                  else
     274                    ok ("%s[%d].%s: %d", fieldname, index, key, (int)value);
     275                }
     276              else if (field.type)
     277                fail ("%s[%d].%s: %d <=> \"%s\" [INT16 %s]", fieldname, index,
     278                      key, (int)value, f->value, field.type);
     279              else
     280                {
     281                  if (g_counter > g_max_count)
     282                    pass ();
     283                  else
     284                    ok ("%s[%d].%s: %d <=> \"%s\" [INT16] (TODO)", fieldname,
     285                        index, key, (int)value, f->value);
     286                }
     287            }
     288        }
     289        break;
     290      case DWG_VT_INT32:
     291      DWG_VT_INT32:
     292        {
     293          BITCODE_BL value;
     294          if (dwg_dynapi_subclass_value (ptr, subclass, key, &value, &field))
     295            {
     296              long l = strtol (f->value, NULL, 10);
     297              BITCODE_BL i = (BITCODE_BL)l;
     298              if (strEQc (key, "rgb") && i == (value & 0xffffff))
     299                {
     300                  if (g_counter > g_max_count)
     301                    pass ();
     302                  else
     303                    ok ("%s[%d].%s: 0x%x", fieldname, index, key,
     304                        (unsigned)value);
     305                }
     306              else if (i == value)
     307                {
     308                  if (g_counter > g_max_count)
     309                    pass ();
     310                  else
     311                    ok ("%s[%d].%s: %u", fieldname, index, key, (unsigned)value);
     312                }
     313              else if (field.type)
     314                fail ("%s[%d].%s: %u <=> \"%s\" [INT32 %s]", fieldname, index,
     315                      key, (unsigned)value, f->value, field.type);
     316              else
     317                {
     318                  if (g_counter > g_max_count)
     319                    pass ();
     320                  else
     321                    ok ("%s[%d].%s: %u <=> \"%s\" [INT32] (TODO)", fieldname,
     322                        index, key, (unsigned)value, f->value);
     323                }
     324            }
     325        }
     326        break;
     327      case DWG_VT_INT64:
     328      DWG_VT_INT64:
     329        {
     330          BITCODE_RLL value;
     331          if (dwg_dynapi_subclass_value (ptr, subclass, key, &value, &field))
     332            {
     333              BITCODE_RLL i = (BITCODE_RLL)strtol (f->value, NULL, 10);
     334              if (i == value)
     335                {
     336                  if (g_counter > g_max_count)
     337                    pass ();
     338                  else
     339                    ok ("%s[%d].%s: %ld", fieldname, index, key, (long)value);
     340                }
     341              else if (field.type)
     342                fail ("%s[%d].%s: %ld <=> \"%s\" [INT64]", fieldname, index, key,
     343                      (long)value, f->value);
     344              else
     345                {
     346                  if (g_counter > g_max_count)
     347                    pass ();
     348                  else
     349                    ok ("%s[%d].%s: %ld <=> \"%s\" [INT64] (TODO)", fieldname,
     350                        index, key, (long)value, f->value);
     351                }
     352            }
     353        }
     354        break;
     355      case DWG_VT_BINARY:
     356        break;
     357      case DWG_VT_HANDLE:
     358        {
     359          BITCODE_H value;
     360          if (dwg_dynapi_subclass_value (ptr, subclass, key, &value, &field))
     361            {
     362              unsigned long l;
     363              sscanf (f->value, "%lX", &l);
     364              if (l == value->absolute_ref || l == value->handleref.value)
     365                {
     366                  if (g_counter > g_max_count)
     367                    pass ();
     368                  else
     369                    ok ("%s[%d].%s: %s", fieldname, index, key, f->value);
     370                }
     371              else
     372                fail ("%s[%d].%s: %lX <=> \"%s\" [H]", fieldname, index, key, l,
     373                      f->value);
     374            }
     375        }
     376        break;
     377      case DWG_VT_OBJECTID:
     378      case DWG_VT_INVALID:
     379      default:
     380        break;
     381      }
     382  }
     383  
     384  static int
     385  DIMASSOC_index (const Dwg_Object *restrict obj, int sub_i)
     386  {
     387    // check associativity bitmask for the index
     388    Dwg_Object_DIMASSOC *_obj = obj->tio.object->tio.DIMASSOC;
     389    while (!(_obj->associativity & (1 << sub_i)) && sub_i < 4)
     390      sub_i++;
     391    return sub_i;
     392  }
     393  
     394  static int
     395  test_object (const Dwg_Data *restrict dwg, const Dwg_Object *restrict obj,
     396               const struct _unknown_dxf *restrict dxf,
     397               const char *restrict name)
     398  {
     399    int isnew;
     400    const struct _unknown_field *f = dxf->fields;
     401    int sub_i = 0;
     402    char firstkey[80];
     403  
     404    *firstkey = '\0';
     405    g_counter++;
     406  
     407    // check all fields against dxf->fields
     408    for (; f->value; f++)
     409      {
     410        Dwg_DYNAPI_field field;
     411        const Dwg_DYNAPI_field *fp, *fp1;
     412        enum RESBUF_VALUE_TYPE vtype;
     413        if (!f->name || !*f->name)
     414          continue;
     415        // support subclass, as in in_json
     416        if (strchr (f->name, '.'))
     417          {
     418            char *subf = strdup (f->name);
     419            char *key = strchr (subf, '.');
     420            char *subclass;
     421            char *p;
     422            char *ptr;
     423  
     424            *key = '\0';
     425            key++;
     426            if (!*firstkey)
     427              {
     428                strcpy (firstkey, key);
     429                if (strEQc (name, "DIMASSOC"))
     430                  sub_i = DIMASSOC_index (obj, sub_i);
     431              }
     432            else if (strEQ (key, firstkey)) // next index, like ref[1]
     433              {
     434                if (strEQc (name, "DIMASSOC"))
     435                  {
     436                    sub_i = DIMASSOC_index (obj, sub_i + 1);
     437                    if (sub_i > 3)
     438                      break;
     439                  }
     440                else
     441                  sub_i++;
     442              }
     443            // unused
     444            if ((p = strchr (subf, '['))) // ref[0].osnap_type
     445              *p = '\0';
     446            // generalize. lookup type of subclass field
     447            if (!(fp1 = dwg_dynapi_entity_field (name, subf)))
     448              {
     449                free (subf);
     450                continue;
     451              }
     452            subclass = dwg_dynapi_subclass_name (fp1->type);
     453            if (!subclass)
     454              {
     455                free (subf);
     456                continue;
     457              }
     458            fp = dwg_dynapi_subclass_field (subclass, key);
     459            if (!fp)
     460              {
     461                free (subclass);
     462                free (subf);
     463                continue;
     464              }
     465            // embedded or reference?
     466            if (fp1->is_malloc) // vector
     467              {
     468                // ptr = ref[i].key
     469                int subsize = sub_i ? dwg_dynapi_subclass_size (subclass) : 0;
     470                ptr = *(char **)((char *)obj->tio.object->tio.APPID
     471                                 + fp1->offset); // deref
     472                ptr += (sub_i * subsize);        // index offset
     473              }
     474            else
     475              { // embedded. no deref, and also no index offset. ptr = &ref.key
     476                ptr = &((char *)obj->tio.object->tio.APPID)[fp1->offset];
     477              }
     478            if (ptr)
     479              test_subclass (dwg, ptr, f, fp, subclass, subf, key, sub_i);
     480            free (subclass);
     481            free (subf);
     482            continue;
     483          }
     484        else if (!(fp = dwg_dynapi_entity_field (name, f->name)))
     485          continue;
     486        if (strEQc (fp->type, "CMC"))
     487          {
     488            BITCODE_CMC color;
     489            if (dwg_dynapi_entity_value (obj->tio.object->tio.APPID, name,
     490                                         f->name, &color, &field))
     491              {
     492                BITCODE_BS i = (BITCODE_BS)strtol (f->value, NULL, 10);
     493                if (i == color.index)
     494                  {
     495                    if (g_counter > g_max_count)
     496                      pass ();
     497                    else
     498                      ok ("%s.%s: %s", name, f->name, f->value);
     499                  }
     500                else if (field.type)
     501                  fail ("%s.%s: %d <=> \"%s\" [%s %d]", name, f->name,
     502                        (int)color.index, f->value, field.type, field.dxf);
     503                else
     504                  {
     505                    if (g_counter > g_max_count)
     506                      pass ();
     507                    else
     508                      ok ("%s.%s: %d <=> \"%s\" [CMC] (TODO)", name, f->name,
     509                          (int)color.index, f->value);
     510                  }
     511              }
     512            continue;
     513          }
     514        // TODO: inlined array support, as with subfields
     515        vtype = dwg_resbuf_value_type (f->code);
     516        if (vtype == DWG_VT_REAL && fp->size >= 16)
     517          goto DWG_VT_POINT3D;
     518        if (vtype == DWG_VT_INT8 && fp->size == 1 && strEQc (fp->type, "B"))
     519          goto DWG_VT_BOOL;
     520        if (vtype == DWG_VT_INT16 && fp->size == 1 && strEQc (fp->type, "RC"))
     521          goto DWG_VT_INT8;
     522        if (vtype == DWG_VT_INT8 && fp->size == 2)
     523          goto DWG_VT_INT16;
     524        if (vtype == DWG_VT_INT16 && fp->size == 4)
     525          goto DWG_VT_INT32;
     526        if (vtype == DWG_VT_INT16 && fp->size == 1)
     527          goto DWG_VT_INT8;
     528        if (vtype == DWG_VT_INT32 && fp->size == 8)
     529          goto DWG_VT_INT64;
     530        switch (vtype)
     531          {
     532          case DWG_VT_STRING:
     533            {
     534              char *value = NULL;
     535              if (fp->is_malloc
     536                  && dwg_dynapi_entity_utf8text (obj->tio.object->tio.APPID,
     537                                                 name, f->name, &value, &isnew,
     538                                                 &field))
     539                {
     540                  if (!value || strEQ (value, f->value))
     541                    {
     542                      if (g_counter > g_max_count)
     543                        pass ();
     544                      else
     545                        ok ("%s.%s: %s", name, f->name, value);
     546                    }
     547                  else
     548                    fail ("%s.%s: %s [%s %d] STRING", name, f->name, value,
     549                          field.type, field.dxf);
     550                }
     551              if (isnew && value)
     552                free (value);
     553            }
     554            break;
     555          case DWG_VT_POINT3D:
     556          DWG_VT_POINT3D:
     557            {
     558              BITCODE_3BD pt;
     559              if (fp->is_malloc
     560                  && dwg_dynapi_entity_value (obj->tio.object->tio.APPID, name,
     561                                              f->name, &pt, &field))
     562                {
     563                  double d = strtod (f->value, NULL);
     564                  double ptv;
     565                  int offset = f->code;
     566                  if (strstr (field.type, "_1"))
     567                    {
     568                      while (offset > 10) // 10,11,12
     569                        offset -= 10;
     570                      if (offset == 2 && field.size > 2 * sizeof (double))
     571                        ptv = pt.z;
     572                      else if (offset == 1)
     573                        ptv = pt.y;
     574                      else
     575                        ptv = pt.x;
     576                    }
     577                  else // 10/20/30
     578                    {
     579                      offset = offset % 100;
     580                      if (offset >= 30 && field.size > 2 * sizeof (double))
     581                        ptv = pt.z;
     582                      else if (offset >= 20)
     583                        ptv = pt.y;
     584                      else
     585                        ptv = pt.x;
     586                    }
     587                  if (fabs (ptv - d) < 1e-6)
     588                    {
     589                      if (g_counter > g_max_count)
     590                        pass ();
     591                      else
     592                        ok ("%s.%s: %f [%s %d]", name, f->name, ptv, field.type,
     593                            f->code);
     594                    }
     595                  else
     596                    fail ("%s.%s: %f <=> \"%s\" [%s %d]", name, f->name, ptv,
     597                          f->value, field.type, f->code);
     598                }
     599            }
     600            break;
     601          case DWG_VT_REAL:
     602            {
     603              double value;
     604              if (fp->is_malloc
     605                  && dwg_dynapi_entity_value (obj->tio.object->tio.APPID, name,
     606                                              f->name, &value, &field))
     607                {
     608                  double d = strtod (f->value, NULL);
     609                  if (f->code >= 50 && f->code < 59)
     610                    d = deg2rad (d);
     611                  if (fabs (value - d) < 1e-6)
     612                    {
     613                      if (g_counter > g_max_count)
     614                        pass ();
     615                      else
     616                        ok ("%s.%s: %f", name, f->name, value);
     617                    }
     618                  else
     619                    fail ("%s.%s: %f <=> \"%s\" [%s %d] REAL", name, f->name,
     620                          value, f->value, field.type, field.dxf);
     621                }
     622            }
     623            break;
     624          case DWG_VT_BOOL:
     625          DWG_VT_BOOL:
     626            {
     627              BITCODE_B value;
     628              if (fp->is_malloc
     629                  && dwg_dynapi_entity_value (obj->tio.object->tio.APPID, name,
     630                                              f->name, &value, &field))
     631                {
     632                  BITCODE_B i = (BITCODE_B)strtol (f->value, NULL, 10);
     633                  if (i == value)
     634                    {
     635                      if (g_counter > g_max_count)
     636                        pass ();
     637                      else
     638                        ok ("%s.%s: %d", name, f->name, value);
     639                    }
     640                  else
     641                    fail ("%s.%s: %d <=> \"%s\" [%s %d] BOOL", name, f->name,
     642                          value, f->value, field.type, field.dxf);
     643                }
     644            }
     645            break;
     646          case DWG_VT_INT8:
     647          DWG_VT_INT8:
     648            {
     649              BITCODE_RC value;
     650              if (fp->is_malloc
     651                  && dwg_dynapi_entity_value (obj->tio.object->tio.APPID, name,
     652                                              f->name, &value, &field))
     653                {
     654                  BITCODE_RC i = (BITCODE_RC)strtol (f->value, NULL, 10);
     655                  if (i == value)
     656                    {
     657                      if (g_counter > g_max_count)
     658                        pass ();
     659                      else
     660                        ok ("%s.%s: %d", name, f->name, value);
     661                    }
     662                  else if (field.type)
     663                    fail ("%s.%s: %d <=> \"%s\" [%s %d] INT8", name, f->name,
     664                          value, f->value, field.type, field.dxf);
     665                  else
     666                    {
     667                      if (g_counter > g_max_count)
     668                        pass ();
     669                      else
     670                        ok ("%s.%s: %d <=> \"%s\" INT8 (TODO)", name, f->name,
     671                            value, f->value);
     672                    }
     673                }
     674            }
     675            break;
     676          case DWG_VT_INT16:
     677          DWG_VT_INT16:
     678            {
     679              BITCODE_BS value;
     680              if (fp->is_malloc
     681                  && dwg_dynapi_entity_value (obj->tio.object->tio.APPID, name,
     682                                              f->name, &value, &field))
     683                {
     684                  BITCODE_BS i = (BITCODE_BS)strtol (f->value, NULL, 10);
     685                  if (i == value)
     686                    {
     687                      if (g_counter > g_max_count)
     688                        pass ();
     689                      else
     690                        ok ("%s.%s: %d", name, f->name, (int)value);
     691                    }
     692                  else if (field.type)
     693                    fail ("%s.%s: %d <=> \"%s\" [%s %d] INT16", name, f->name,
     694                          (int)value, f->value, field.type, field.dxf);
     695                  else
     696                    {
     697                      if (g_counter > g_max_count)
     698                        pass ();
     699                      else
     700                        ok ("%s.%s: %d <=> \"%s\" INT16 (TODO)", name, f->name,
     701                            (int)value, f->value);
     702                    }
     703                }
     704            }
     705            break;
     706          case DWG_VT_INT32:
     707          DWG_VT_INT32:
     708            {
     709              BITCODE_BL value;
     710              if (fp->is_malloc
     711                  && dwg_dynapi_entity_value (obj->tio.object->tio.APPID, name,
     712                                              f->name, &value, &field))
     713                {
     714                  long l = strtol (f->value, NULL, 10);
     715                  BITCODE_BL i = (BITCODE_BL)l;
     716                  if (strEQc (f->name, "rgb") && i == (value & 0xffffff))
     717                    {
     718                      if (g_counter > g_max_count)
     719                        pass ();
     720                      else
     721                        ok ("%s.%s: 0x%x", name, f->name, (unsigned)value);
     722                    }
     723                  else if (i == value)
     724                    {
     725                      if (g_counter > g_max_count)
     726                        pass ();
     727                      else
     728                        ok ("%s.%s: %u", name, f->name, (unsigned)value);
     729                    }
     730                  else if (field.type)
     731                    fail ("%s.%s: %u <=> \"%s\" [%s %d] INT32", name, f->name,
     732                          (unsigned)value, f->value, field.type, field.dxf);
     733                  else
     734                    {
     735                      if (g_counter > g_max_count)
     736                        pass ();
     737                      else
     738                        ok ("%s.%s: %u <=> \"%s\" INT32 (TODO)", name, f->name,
     739                            (unsigned)value, f->value);
     740                    }
     741                }
     742            }
     743            break;
     744          case DWG_VT_INT64:
     745          DWG_VT_INT64:
     746            {
     747              BITCODE_RLL value;
     748              if (fp->is_malloc
     749                  && dwg_dynapi_entity_value (obj->tio.object->tio.APPID, name,
     750                                              f->name, &value, &field))
     751                {
     752                  BITCODE_RLL i = (BITCODE_RLL)strtol (f->value, NULL, 10);
     753                  if (i == value)
     754                    {
     755                      if (g_counter > g_max_count)
     756                        pass ();
     757                      else
     758                        ok ("%s.%s: %ld", name, f->name, (long)value);
     759                    }
     760                  else if (field.type)
     761                    fail ("%s.%s: %ld <=> \"%s\" [%s %d] INT64", name, f->name,
     762                          (long)value, f->value, field.type, field.dxf);
     763                  else
     764                    {
     765                      if (g_counter > g_max_count)
     766                        pass ();
     767                      else
     768                        ok ("%s.%s: %ld <=> \"%s\" INT64 (TODO)", name, f->name,
     769                            (long)value, f->value);
     770                    }
     771                }
     772            }
     773            break;
     774          case DWG_VT_BINARY:
     775            break;
     776          case DWG_VT_HANDLE:
     777            {
     778              BITCODE_H value;
     779              if (fp->is_malloc
     780                  && dwg_dynapi_entity_value (obj->tio.object->tio.APPID, name,
     781                                              f->name, &value, &field))
     782                {
     783                  unsigned long l;
     784                  sscanf (f->value, "%lX", &l);
     785                  if (l == value->absolute_ref || l == value->handleref.value)
     786                    {
     787                      if (g_counter > g_max_count)
     788                        pass ();
     789                      else
     790                        ok ("%s.%s: %s", name, f->name, f->value);
     791                    }
     792                  else
     793                    fail ("%s.%s: %lX <=> \"%s\" [H %d]", name, f->name, l,
     794                          f->value, field.dxf);
     795                }
     796            }
     797            break;
     798          case DWG_VT_OBJECTID:
     799          case DWG_VT_INVALID:
     800          default:
     801            break;
     802          }
     803      }
     804    return failed;
     805  }
     806  
     807  static int
     808  test_dxf (const struct _unknown_dxf *dxf, const char *restrict name,
     809            const char *restrict dwgfile)
     810  {
     811    int error = 0;
     812    static char prev_dwgfile[128];
     813    static Dwg_Data dwg;
     814    BITCODE_BL i;
     815    char *trace;
     816    int tracelevel = 0;
     817  
     818    trace = getenv ("LIBREDWG_TRACE");
     819    if (trace)
     820      tracelevel = atoi (trace);
     821  
     822    loglevel = is_make_silent () ? 0 : MAX (tracelevel, 2);
     823    LOG_TRACE ("%s %X %s\n", dxf->name, dxf->handle, dwgfile);
     824    num = passed = failed = 0;
     825  
     826    if (dwg.num_objects && strEQ (dwgfile, prev_dwgfile))
     827      ;
     828    else
     829      {
     830        if (dwg.num_objects && dwg.header.version > R_INVALID)
     831          dwg_free (&dwg);
     832        dwg.opts = tracelevel;
     833        if (dwg_read_file (dwgfile, &dwg) >= DWG_ERR_CRITICAL)
     834          {
     835            dwg_free (&dwg);
     836            return 1;
     837          }
     838      }
     839    strcpy (prev_dwgfile, dwgfile);
     840  
     841    // find the object
     842    for (i = 0; i < dwg.num_objects; i++)
     843      {
     844        if (dwg.object[i].handle.value == dxf->handle)
     845          {
     846            if (dwg.object[i].fixedtype >= DWG_TYPE_UNKNOWN_ENT)
     847              break;
     848            if (strNE (dwg.object[i].dxfname, dxf->name))
     849              LOG_WARN ("Invalid handle 0x%X for %s", dxf->handle, dxf->name)
     850            else
     851              error += test_object (&dwg, &dwg.object[i], dxf, name);
     852            break;
     853          }
     854      }
     855    /* This value is the return value for `main',
     856       so clamp it to either 0 or 1.  */
     857    return error ? 1 : 0;
     858  }
     859  
     860  int
     861  main (int argc, char *argv[])
     862  {
     863    int i = 1, error = 0;
     864    struct _unknown_dxf *dxf;
     865    char *class = NULL;
     866    char *file = NULL;
     867    char name[80];
     868    char olddxf[80];
     869    int big = 0;
     870    int is_docker = 0;
     871    char *docker;
     872  // clang-format off
     873    #include "../../examples/alldxf_2.inc"
     874    // clang-format on
     875  
     876    docker = getenv ("DOCKER");
     877    if (docker && strNE (docker, "0"))
     878      is_docker = 1;
     879    g_max_count = MAX_COUNTER;
     880    g_all = 0;
     881    name[0] = '\0';
     882    olddxf[0] = '\0';
     883    if (argc > 2 && !strcmp (argv[i], "--class"))
     884      {
     885        class = argv[++i];
     886        ++i;
     887      }
     888    if (argc - i >= 2 && !strcmp (argv[i], "--file"))
     889      {
     890        file = argv[++i];
     891        ++i;
     892      }
     893    if (argc - i >= 1 && !strcmp (argv[i], "-a"))
     894      {
     895        ++i;
     896        g_all = 1;
     897        g_max_count = 1000;
     898      }
     899    if (argc - i >= 1 && !strcmp (argv[i], "--big"))
     900      {
     901        ++i;
     902        big = 1;
     903      }
     904  
     905    g_counter = 0;
     906    for (dxf = &unknown_dxf[0]; dxf->name; dxf++)
     907      {
     908        const char *dxffile = dxf->dxf;
     909        struct stat attrib;
     910        size_t len = strlen (dxffile);
     911        char *dwgfile = strdup (dxffile);
     912        char *s = strrchr (dwgfile, '.');
     913        *(s + 2) = 'w';
     914        *(s + 3) = 'g';
     915  
     916        // display ok values only for the first 6 object types per file
     917        if (strNE (name, dxf->name) && strNE (olddxf, dxf->dxf))
     918          g_counter = 0;
     919        if (!big && strstr (dxffile, "/test-big/"))
     920          {
     921            free (dwgfile);
     922            continue;
     923          }
     924  
     925        strcpy (olddxf, dxf->dxf);
     926        strcpy (name, dxf->name);
     927        if (!is_dwg_object (name) && !is_dwg_entity (name))
     928          {
     929            object_alias (name);
     930            if (!is_dwg_object (name))
     931              {
     932                strcpy (name, dxf->name);
     933                entity_alias (name);
     934                if (!is_dwg_entity (name) && !class)
     935                  {
     936                    free (dwgfile);
     937                    if (!g_counter) // use --enable-debug
     938                      LOG_WARN ("Unhandled %s", dxf->name)
     939                    continue;
     940                  }
     941              }
     942          }
     943        if (class && strNE (class, name))
     944          {
     945            free (dwgfile);
     946            continue;
     947          }
     948        if (file && strNE (file, dwgfile))
     949          {
     950            free (dwgfile);
     951            continue;
     952          }
     953        // GH #268. skip 2018/Helix.dwg. podman works fine.
     954        if (is_docker && strEQ (dxffile, "test/test-data/2018/Helix.dxf"))
     955          {
     956            LOG_ERROR ("Skip %s in docker", dwgfile)
     957            free (dwgfile);
     958            continue;
     959          }
     960        if (stat (dwgfile, &attrib)) // not found
     961          {
     962            char path[80];
     963            char *top_srcdir = getenv ("top_srcdir");
     964            // fixup wrong alldxf_0.inc paths
     965            if (len > 3 && dwgfile[0] == '.' && dwgfile[1] == '.'
     966                && dwgfile[2] == '/')
     967              memmove (dwgfile, &dwgfile[3], len - 2); // include the final \0
     968            if (top_srcdir)
     969              {
     970                strcpy (path, top_srcdir);
     971                strcat (path, "/");
     972              }
     973            else
     974              strcpy (path, "../../../");
     975            strcat (path, dwgfile);
     976            if (stat (path, &attrib))
     977              LOG_WARN ("%s not found\n", path)
     978            else
     979              error += test_dxf (dxf, name, path);
     980          }
     981        else
     982          error += test_dxf (dxf, name, dwgfile);
     983        free (dwgfile);
     984      }
     985    // so far all unknown objects are debugging or unstable. ignore all errors
     986    return 0;
     987  }