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