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