1 /*****************************************************************************/
2 /* LibreDWG - free implementation of the DWG file format */
3 /* */
4 /* Copyright (C) 2020 Free Software Foundation, Inc. */
5 /* */
6 /* This library is free software, licensed under the terms of the GNU */
7 /* General Public License as published by the Free Software Foundation, */
8 /* either version 3 of the License, or (at your option) any later version. */
9 /* You should have received a copy of the GNU General Public License */
10 /* along with this program. If not, see <http://www.gnu.org/licenses/>. */
11 /*****************************************************************************/
12
13 /*
14 * dwgfuzz.c: afl++/honggfuzz fuzzing for all in- and exporters. Just not the
15 separate ones.
16 *
17 * Also usable like:
18 ../configure --disable-shared --disable-bindings CC=hfuzz-clang CFLAGS='-O2
19 -g -fsanitize=address,undefined -fno-omit-frame-pointer -I/usr/local/include'
20 && make -C src && make -C examples dwgfuzz honggfuzz -i ../.fuzz-in-dxf --
21 examples/dwgfuzz -indxf ___FILE___
22
23 * Also useful for debugging the fuzzers.
24 AFL_DONT_OPTIMIZE=1 AFL_LLVM_INSTRIM=1 AFL_USE_ASAN=1 make -C examples
25 dwgfuzz V=1 AFL_DEBUG=15 AFL_DEBUG_CHILD_OUTPUT=1 gdb --args afl-fuzz -m none
26 -i ../.fuzz-in-dxf/ -o .fuzz-out/ examples/dwgfuzz (gdb) set follow-fork-mode
27 child
28 * written by Reini Urban
29 */
30
31 #include "../src/config.h"
32 #ifdef HAVE_SSCANF_S
33 # define __STDC_WANT_LIB_EXT1__ 1
34 #endif
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/stat.h>
39 #include <unistd.h>
40 #include <getopt.h>
41
42 #include <dwg.h>
43 #include <dwg_api.h>
44 #include "common.h"
45 #include "decode.h"
46 #include "encode.h"
47 #include "bits.h"
48 #ifndef DISABLE_DXF
49 # include "out_dxf.h"
50 # ifndef DISABLE_JSON
51 # include "in_json.h"
52 # include "out_json.h"
53 # endif
54 # include "in_dxf.h"
55 #endif
56
57 #define FUZZ_INMEM 0
58 #define FUZZ_STDIN 1
59 #define FUZZ_FILE 2
60
61 // defined by ./make-afl-clang-fast.sh for INMEM. defaults to FILE for
62 // debugging
63 #ifndef FUZZ_MODE
64 # define FUZZ_MODE FUZZ_INMEM
65 //#define FUZZ_MODE FUZZ_STDIN
66 //#define FUZZ_MODE FUZZ_FILE
67 #endif
68
69 int dwg_fuzz_dat (Dwg_Data **restrict dwgp, Bit_Chain *restrict dat);
70
71 static int
72 version (void)
73 {
74 printf ("dwgfuzz %s INMEM\n", PACKAGE_VERSION);
75 #ifndef __AFL_COMPILER
76 printf ("not instrumented\n");
77 #else
78 # ifdef __AFL_FUZZ_TESTCASE_BUF
79 printf ("shared-memory instrumented\n");
80 # else
81 printf ("instrumented\n");
82 # endif
83 #endif
84 return 0;
85 }
86
87 #ifndef __AFL_COMPILER
88 # define __AFL_FUZZ_INIT()
89 # if FUZZ_MODE == FUZZ_INMEM
90 unsigned char *__AFL_FUZZ_TESTCASE_BUF;
91 unsigned long __AFL_FUZZ_TESTCASE_LEN;
92 # define __AFL_INIT() \
93 fp = fopen (argv[2], "rb"); \
94 if (!fp) \
95 return 0; \
96 __AFL_FUZZ_TESTCASE_LEN = dat.size; \
97 dat_read_file (&dat, fp, argv[2]); \
98 __AFL_FUZZ_TESTCASE_BUF = dat.chain;
99 # else
100 # define __AFL_INIT()
101 # endif
102 # define __AFL_FUZZ_TESTCASE_LEN dat.size
103 # define __AFL_LOOP(i) 1
104 #endif
105
106 __AFL_FUZZ_INIT ();
107
108 static int
109 help (void)
110 {
111 #if FUZZ_MODE == FUZZ_FILE
112 printf ("\nUsage: dwgfuzz MODE @@\n");
113 #elif !defined __AFL_COMPILER
114 printf ("\nUsage: dwgfuzz MODE ../.fuzz-in/INFILE\n");
115 #else
116 printf ("\nUsage: dwgfuzz MODE\n");
117 #endif
118 printf ("afl++ clang-fast shared-memory backend, using many importers and "
119 "exporters.\n"
120 "\n");
121 printf ("MODE:\n");
122 #ifdef USE_WRITE
123 # ifndef DISABLE_DXF
124 printf (" -indxf: import from DXF, export as r2000 DWG\n");
125 # endif
126 # ifndef DISABLE_JSON
127 printf (" -injson: import from JSON, export as r2000 DWG\n");
128 # endif
129 printf (" -rw: import from DWG, export as r2000 DWG, re-import from "
130 "this DWG (rewrite)\n");
131 printf (" -add: import from special add file, export as DWG and DXF, "
132 "re-import from this\n");
133 #endif
134 printf (" -dwg: import from DWG only\n");
135 #ifndef DISABLE_DXF
136 printf (" -dxf: import from DWG, export as DXF\n");
137 printf (" -dxfb: import from DWG, export as binary DXF\n");
138 #endif
139 #ifndef DISABLE_JSON
140 printf (" -json: import from DWG, export as JSON\n");
141 printf (" -geojson: import from DWG, export as GeoJSON\n");
142 #endif
143 printf ("\n"
144 " --version display the version and exit\n");
145 printf (" --help display this help and exit\n");
146 return 0;
147 }
148
149 // for LLVMFuzzerTestOneInput see llvmfuzz.c
150
151 int
152 main (int argc, char *argv[])
153 {
154 int i = 0;
155 Dwg_Data dwg;
156 Bit_Chain dat = { 0 };
157 Bit_Chain out_dat = { 0 };
158 FILE *fp;
159 struct stat attrib;
160 enum
161 {
162 INVALID,
163 DWG,
164 #if defined(USE_WRITE) && !defined(DISABLE_DXF)
165 INDXF,
166 #endif
167 #if defined(USE_WRITE) && !defined(DISABLE_JSON)
168 INJSON,
169 #endif
170 #if defined(USE_WRITE)
171 RW,
172 ADD,
173 #endif
174 #if !defined(DISABLE_DXF)
175 DXF,
176 DXFB,
177 #endif
178 #if !defined(DISABLE_JSON)
179 JSON,
180 GEOJSON,
181 #endif
182 } mode
183 = INVALID;
184 __AFL_INIT ();
185
186 if (argc <= 1 || !*argv[1])
187 return 1;
188 if (strEQc (argv[1], "-dwg"))
189 mode = DWG;
190 #ifdef USE_WRITE
191 # ifndef DISABLE_DXF
192 else if (strEQc (argv[1], "-indxf"))
193 mode = INDXF;
194 # endif
195 # ifndef DISABLE_JSON
196 else if (strEQc (argv[1], "-injson"))
197 mode = INJSON;
198 # endif
199 else if (strEQc (argv[1], "-rw"))
200 mode = RW;
201 else if (strEQc (argv[1], "-add"))
202 mode = ADD;
203 #endif /* USE_WRITE */
204 #ifndef DISABLE_DXF
205 else if (strEQc (argv[1], "-dxf"))
206 mode = DXF;
207 else if (strEQc (argv[1], "-dxfb"))
208 mode = DXFB;
209 #endif
210 #ifndef DISABLE_JSON
211 else if (strEQc (argv[1], "-json"))
212 mode = JSON;
213 else if (strEQc (argv[1], "-geojson"))
214 mode = GEOJSON;
215 #endif
216 else if (strEQc (argv[1], "--version"))
217 return version ();
218 else if (strEQc (argv[1], "--help"))
219 return help ();
220 else
221 return 1;
222 if (mode == INVALID)
223 return 1;
224 #if FUZZ_MODE == FUZZ_FILE
225 if (argc <= 2 || !*argv[2])
226 return 1;
227 #endif
228 #if FUZZ_MODE == FUZZ_INMEM && !defined(__AFL_COMPILER)
229 if (argc <= 2 || !*argv[2])
230 return 1;
231 #endif
232
233 memset (&dwg, 0, sizeof (dwg));
234 dat.chain = NULL;
235 // dat.opts = 3;;
236 #if FUZZ_MODE == FUZZ_INMEM
237 dat.chain = __AFL_FUZZ_TESTCASE_BUF;
238 #endif
239
240 while (__AFL_LOOP (10000))
241 { // llvm_mode persistent, non-forking mode
242 i++;
243 #ifndef __AFL_COMPILER
244 # ifdef USE_WRITE
245 if (mode == ADD && i > 1)
246 break;
247 # endif
248 if (i > 3)
249 break;
250 #endif
251 #if FUZZ_MODE == FUZZ_INMEM
252 // fastest mode via shared mem
253 if (!dat.chain)
254 dat.chain = __AFL_FUZZ_TESTCASE_BUF;
255 dat.size = __AFL_FUZZ_TESTCASE_LEN;
256 printf ("Fuzzing from shared memory (%" PRIuSIZE ")\n", dat.size);
257 #elif FUZZ_MODE == FUZZ_STDIN
258 // still 10x faster than the old file-forking fuzzer.
259 dat.size = 0;
260 // dat.chain = NULL;
261 dat_read_stream (&dat, stdin);
262 printf ("Fuzzing from stdin (%" PRIuSIZE ")\n", dat.size);
263 #elif FUZZ_MODE == FUZZ_FILE
264 dat.size = 0;
265 fp = fopen (argv[2], "rb");
266 if (!fp)
267 return 0;
268 dat_read_file (&dat, fp, argv[2]);
269 fclose (fp);
270 printf ("Fuzzing from file (%" PRIuSIZE ")\n", dat.size);
271 #else
272 # error Missing FUZZ_MODE
273 #endif
274 if (dat.size == 0)
275 exit (1);
276 if (dat.size < 100)
277 continue; // useful minimum input length
278 memset (&out_dat, 0, sizeof (out_dat));
279 bit_chain_set_version (&out_dat, &dat);
280 #ifdef _WIN32
281 out_dat.fh = fopen ("NUL", "w");
282 #else
283 out_dat.fh = fopen ("/dev/null", "w");
284 #endif
285
286 switch (mode)
287 {
288 case DWG:
289 if (dwg_decode (&dat, &dwg) >= DWG_ERR_CRITICAL)
290 exit (0);
291 break;
292 #if defined(USE_WRITE) && !defined(DISABLE_DXF)
293 case INDXF:
294 if (dwg_read_dxf (&dat, &dwg) < DWG_ERR_CRITICAL)
295 {
296 out_dat.version = R_2000;
297 if (dwg_encode (&dwg, &out_dat) >= DWG_ERR_CRITICAL)
298 exit (0);
299 free (out_dat.chain);
300 }
301 break;
302 #endif
303 #if defined(USE_WRITE)
304 case RW:
305 if (dwg_decode (&dat, &dwg) < DWG_ERR_CRITICAL)
306 {
307 out_dat.version = R_2000;
308 if (dwg_encode (&dwg, &out_dat) >= DWG_ERR_CRITICAL)
309 exit (0);
310 if (dwg_decode (&out_dat, &dwg) >= DWG_ERR_CRITICAL)
311 exit (0);
312 free (out_dat.chain);
313 }
314 break;
315 case ADD:
316 {
317 Dwg_Data *dwgp = &dwg;
318 if (dwg_fuzz_dat (&dwgp, &dat) == 0)
319 {
320 int error;
321 out_dat.byte = 0;
322 out_dat.bit = 0;
323 out_dat.from_version = dwg.header.from_version;
324 out_dat.version = dwg.header.version;
325 out_dat.opts = dwg.opts;
326 error = dwg_encode (&dwg, &out_dat); // dwg -> out_dat
327 if (error >= DWG_ERR_CRITICAL)
328 exit (0);
329
330 out_dat.byte = 0;
331 out_dat.bit = 0;
332 memset (&dwg, 0, sizeof (Dwg_Data));
333 error = dwg_decode (&out_dat, &dwg); // out_dat -> dwg
334 if (error >= DWG_ERR_CRITICAL)
335 exit (0);
336 }
337 }
338 break;
339 #endif
340 #if defined(USE_WRITE) && !defined(DISABLE_JSON)
341 case INJSON:
342 if (dwg_read_json (&dat, &dwg) < DWG_ERR_CRITICAL)
343 {
344 out_dat.version = R_2000;
345 if (dwg_encode (&dwg, &out_dat) >= DWG_ERR_CRITICAL)
346 exit (0);
347 }
348 break;
349 #endif
350 #ifndef DISABLE_DXF
351 case DXF:
352 if (dwg_decode (&dat, &dwg) < DWG_ERR_CRITICAL)
353 {
354 if (dwg_write_dxf (&out_dat, &dwg) >= DWG_ERR_CRITICAL)
355 exit (0);
356 }
357 break;
358 case DXFB:
359 if (dwg_decode (&dat, &dwg) < DWG_ERR_CRITICAL)
360 {
361 if (dwg_write_dxfb (&out_dat, &dwg) >= DWG_ERR_CRITICAL)
362 exit (0);
363 }
364 break;
365 #endif
366 #ifndef DISABLE_JSON
367 case JSON:
368 if (dwg_decode (&dat, &dwg) < DWG_ERR_CRITICAL)
369 {
370 if (dwg_write_json (&out_dat, &dwg) >= DWG_ERR_CRITICAL)
371 exit (0);
372 }
373 break;
374 case GEOJSON:
375 if (dwg_decode (&dat, &dwg) < DWG_ERR_CRITICAL)
376 {
377 if (dwg_write_geojson (&out_dat, &dwg) >= DWG_ERR_CRITICAL)
378 exit (0);
379 }
380 break;
381 #endif
382 case INVALID:
383 default:
384 exit (1);
385 }
386 free (out_dat.chain);
387 fclose (out_dat.fh);
388 }
389 dwg_free (&dwg);
390 return 0;
391 }
392
393 #if defined(USE_WRITE)
394
395 static dwg_point_2d *
396 scan_pts2d (unsigned num_pts, char **pp)
397 {
398 char *p = *pp;
399 dwg_point_2d *pts;
400
401 p = strchr (p, '(');
402 if (!p)
403 return NULL;
404 p++;
405 if (num_pts > 5000)
406 exit (0);
407 pts = calloc (num_pts, 16);
408 if (!pts)
409 exit (0);
410 for (unsigned i = 0; i < num_pts; i++)
411 {
412 if (sscanf (p, "(%lf %lf)", &pts[i].x, &pts[i].y))
413 {
414 p = strchr (p, ')');
415 if (!p)
416 break;
417 p++;
418 }
419 else
420 {
421 *pp = p;
422 p = NULL;
423 break;
424 }
425 }
426
427 if (p)
428 {
429 *pp = p;
430 return pts;
431 }
432 else
433 {
434 free (pts);
435 return NULL;
436 }
437 }
438
439 static dwg_point_3d *
440 scan_pts3d (unsigned num_pts, char **pp)
441 {
442 char *p = *pp;
443 dwg_point_3d *pts;
444
445 p = strchr (p, '(');
446 if (!p)
447 return NULL;
448 p++;
449 if (num_pts > 5000)
450 exit (0);
451 pts = calloc (num_pts, 24);
452 if (!pts)
453 exit (0);
454 for (unsigned i = 0; i < num_pts; i++)
455 {
456 if (sscanf (p, "(%lf %lf %lf)", &pts[i].x, &pts[i].y, &pts[i].z))
457 {
458 p = strchr (p, ')');
459 if (!p)
460 break;
461 p++;
462 }
463 else
464 {
465 *pp = p;
466 p = NULL;
467 break;
468 }
469 }
470
471 if (p && num_pts)
472 {
473 *pp = p;
474 return pts;
475 }
476 else
477 {
478 free (pts);
479 return NULL;
480 }
481 }
482
483 static char *
484 next_line (char *restrict p, const char *restrict end)
485 {
486 while (p < end && *p != '\n')
487 p++;
488 if (p < end)
489 p++;
490 return p;
491 }
492
493 int
494 dwg_fuzz_dat (Dwg_Data **restrict dwgp, Bit_Chain *restrict dat)
495 {
496 Dwg_Data *dwg;
497 Dwg_Object *mspace;
498 Dwg_Object_Ref *mspace_ref;
499 Dwg_Object_BLOCK_HEADER *hdr;
500 const char *end;
501 char *p;
502 Dwg_Version_Type version = R_INVALID;
503 int i = 0;
504 int imperial = 0;
505 BITCODE_BL orig_num;
506
507 if (!dat->chain)
508 abort ();
509 end = (char *)&dat->chain[dat->size - 1];
510 if ((p = strstr ((char *)dat->chain, "\nimperial\n")))
511 {
512 imperial = 1;
513 p += strlen ("\nimperial\n");
514 }
515 if ((p = strstr ((char *)dat->chain, "version")))
516 {
517 int i_ver;
518 char s_ver[16];
519 i = sscanf (p, "version %d", &i_ver);
520 if (i)
521 {
522 snprintf (s_ver, 16, "r%d", i_ver);
523 s_ver[15] = '\0';
524 version = dwg_version_as (s_ver);
525 p += strlen ("version ");
526 }
527 else
528 p += strlen ("version ");
529 p = next_line (p, end);
530 }
531 if (!i || version >= R_AFTER)
532 version = R_2000;
533
534 dwg = dwg_new_Document (version, imperial, 0);
535 *dwgp = dwg;
536 mspace = dwg_model_space_object (dwg);
537 mspace_ref = dwg_model_space_ref (dwg);
538 hdr = mspace->tio.object->tio.BLOCK_HEADER;
539 orig_num = dwg->num_objects;
540
541 // read dat line by line and call the matching add API
542 while (p && p < end)
543 {
544 char text[120], s1[120];
545 dwg_point_2d p2, p3, p4;
546 dwg_point_3d pt1, pt2, pt3, pt4, scale;
547 double height, rot, len, f1, f2;
548 int i1, i2;
549 unsigned u;
550 Dwg_Entity_VIEWPORT *viewport = NULL;
551 Dwg_Entity_MTEXT *mtext = NULL;
552 Dwg_Object_DICTIONARY *dictionary = NULL;
553 Dwg_Object_XRECORD *xrecord = NULL;
554 Dwg_Object_MLINESTYLE *mlinestyle = NULL;
555 Dwg_Object_DIMSTYLE *dimstyle = NULL;
556 Dwg_Object_UCS *ucs = NULL;
557 Dwg_Object_LAYOUT *layout = NULL;
558
559 // accepts only ASCII strings, for fuzzing only
560 # ifdef HAVE_SSCANF_S
561 # define SSCANF_S sscanf_s
562 # define SZ , 119
563 # define FMT_NAME "%[a-zA-Z0-9_]"
564 # define FMT_TBL "\"%[a-zA-Z0-9._ -]\""
565 # define FMT_PATH "\"%[a-zA-Z0-9_. \\-]\""
566 # define FMT_ANY "\"%s\""
567 # else
568 # define SSCANF_S sscanf
569 # define SZ
570 # define FMT_NAME "%119[a-zA-Z0-9_]"
571 # define FMT_TBL "\"%119[a-zA-Z0-9._ -]\""
572 # define FMT_PATH "\"%119[a-zA-Z0-9_. \\-]\""
573 # define FMT_ANY "\"%119s\""
574 # endif
575
576 # define SET_ENT(var, name) \
577 if (!var) \
578 ; \
579 else if (SSCANF_S (p, #var "." FMT_NAME " = %d", &s1[0] SZ, &i1)) \
580 dwg_dynapi_entity_set_value (var, #name, s1, &i1, 0); \
581 else if (SSCANF_S (p, #var "." FMT_NAME " = %lf", &s1[0] SZ, &f1)) \
582 dwg_dynapi_entity_set_value (var, #name, s1, &f1, 0); \
583 else if (SSCANF_S (p, #var "." FMT_NAME " = " FMT_ANY, &s1[0] SZ, \
584 &text[0] SZ)) \
585 dwg_dynapi_entity_set_value (var, #name, s1, text, 1)
586
587 if (SSCANF_S (p, "line (%lf %lf %lf) (%lf %lf %lf)", &pt1.x, &pt1.y,
588 &pt1.z, &pt2.x, &pt2.y, &pt2.z))
589 dwg_add_LINE (hdr, &pt1, &pt2);
590 else if (SSCANF_S (p, "ray (%lf %lf %lf) (%lf %lf %lf)", &pt1.x, &pt1.y,
591 &pt1.z, &pt2.x, &pt2.y, &pt2.z))
592 dwg_add_RAY (hdr, &pt1, &pt2);
593 else if (SSCANF_S (p, "xline (%lf %lf %lf) (%lf %lf %lf)", &pt1.x,
594 &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z))
595 dwg_add_XLINE (hdr, &pt1, &pt2);
596 else if (SSCANF_S (p, "text " FMT_ANY " (%lf %lf %lf) %lf", &text[0] SZ,
597 &pt1.x, &pt1.y, &pt1.z, &height))
598 dwg_add_TEXT (hdr, text, &pt1, height);
599 else if (SSCANF_S (p, "mtext (%lf %lf %lf) %lf " FMT_ANY, &pt1.x, &pt1.y,
600 &pt1.z, &height, &text[0] SZ))
601 mtext = dwg_add_MTEXT (hdr, &pt1, height, text);
602 else
603 SET_ENT (mtext, MTEXT);
604 else if (SSCANF_S (p, "block " FMT_TBL, &text[0] SZ))
605 dwg_add_BLOCK (hdr, text);
606 else if (memBEGINc (p, "endblk\n")) dwg_add_ENDBLK (hdr);
607 else if (SSCANF_S (p, "insert (%lf %lf %lf) " FMT_TBL " %lf %lf %lf %lf",
608 &pt1.x, &pt1.y, &pt1.z, &text[0] SZ, &scale.x,
609 &scale.y, &scale.z, &rot))
610 dwg_add_INSERT (hdr, &pt1, text, scale.x, scale.y, scale.z,
611 deg2rad (rot));
612 else if (SSCANF_S (p,
613 "minsert (%lf %lf %lf) " FMT_TBL
614 " %lf %lf %lf %lf %d %d "
615 "%lf %lf",
616 &pt1.x, &pt1.y, &pt1.z, &text[0] SZ, &scale.x,
617 &scale.y, &scale.z, &rot, &i1, &i2, &f1, &f2))
618 dwg_add_MINSERT (hdr, &pt1, text, scale.x, scale.y, scale.z,
619 deg2rad (rot), i1, i2, f1, f2);
620 else if (SSCANF_S (p, "point (%lf %lf %lf)", &pt1.x, &pt1.y, &pt1.z))
621 dwg_add_POINT (hdr, &pt1);
622 else if (SSCANF_S (p, "circle (%lf %lf %lf) %lf", &pt1.x, &pt1.y, &pt1.z,
623 &f1)) dwg_add_CIRCLE (hdr, &pt1, f1);
624 else if (SSCANF_S (p, "arc (%lf %lf %lf) %lf %lf %lf", &pt1.x, &pt1.y,
625 &pt1.z, &f1, &f2, &height))
626 dwg_add_ARC (hdr, &pt1, f1, f2, height);
627 else if (SSCANF_S (p,
628 "dimension_aligned (%lf %lf %lf) (%lf %lf %lf) (%lf "
629 "%lf %lf)",
630 &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z,
631 &pt3.x, &pt3.y, &pt3.z))
632 dwg_add_DIMENSION_ALIGNED (hdr, &pt1, &pt2, &pt3);
633 else if (SSCANF_S (
634 p,
635 "dimension_linear (%lf %lf %lf) (%lf %lf %lf) (%lf %lf "
636 "%lf) %lf",
637 &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &pt3.x,
638 &pt3.y, &pt3.z, &rot))
639 dwg_add_DIMENSION_LINEAR (hdr, &pt1, &pt2, &pt3, deg2rad (rot));
640 else if (SSCANF_S (
641 p,
642 "dimension_ang2ln (%lf %lf %lf) (%lf %lf %lf) (%lf %lf "
643 "%lf) (%lf %lf %lf)",
644 &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &pt3.x,
645 &pt3.y, &pt3.z, &pt4.x, &pt4.y, &pt4.z))
646 dwg_add_DIMENSION_ANG2LN (hdr, &pt1, &pt2, &pt3, &pt4);
647 else if (SSCANF_S (
648 p,
649 "dimension_ang3pt (%lf %lf %lf) (%lf %lf %lf) (%lf %lf "
650 "%lf) (%lf %lf %lf)",
651 &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &pt3.x,
652 &pt3.y, &pt3.z, &pt4.x, &pt4.y, &pt4.z))
653 dwg_add_DIMENSION_ANG3PT (hdr, &pt1, &pt2, &pt3, &pt4);
654 else if (SSCANF_S (p,
655 "dimension_diameter (%lf %lf %lf) (%lf %lf %lf) %lf",
656 &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &len))
657 dwg_add_DIMENSION_DIAMETER (hdr, &pt1, &pt2, len);
658 else if (SSCANF_S (p,
659 "dimension_ordinate (%lf %lf %lf) (%lf %lf %lf) %d",
660 &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &i1))
661 dwg_add_DIMENSION_ORDINATE (hdr, &pt1, &pt2, i1 ? true : false);
662 else if (SSCANF_S (p, "dimension_radius (%lf %lf %lf) (%lf %lf %lf) %lf",
663 &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &len))
664 dwg_add_DIMENSION_RADIUS (hdr, &pt1, &pt2, len);
665 else if (SSCANF_S (p,
666 "3dface (%lf %lf %lf) (%lf %lf %lf) (%lf %lf "
667 "%lf) (%lf %lf %lf)",
668 &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z,
669 &pt3.x, &pt3.y, &pt3.z, &pt4.x, &pt4.y, &pt4.z))
670 dwg_add_3DFACE (hdr, &pt1, &pt2, &pt3, &pt4);
671 else if (SSCANF_S (p,
672 "3dface (%lf %lf %lf) (%lf %lf %lf) (%lf %lf "
673 "%lf)",
674 &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z,
675 &pt3.x, &pt3.y, &pt3.z))
676 dwg_add_3DFACE (hdr, &pt1, &pt2, &pt3, NULL);
677 else if (SSCANF_S (
678 p, "solid (%lf %lf %lf) (%lf %lf) (%lf %lf) (%lf %lf)",
679 &pt1.x, &pt1.y, &pt1.z, &p2.x, &p2.y, &p3.x, &p3.y, &p4.x,
680 &p4.y)) dwg_add_SOLID (hdr, &pt1, &p2, &p3, &p4);
681 else if (SSCANF_S (
682 p, "trace (%lf %lf %lf) (%lf %lf) (%lf %lf) (%lf %lf)",
683 &pt1.x, &pt1.y, &pt1.z, &p2.x, &p2.y, &p3.x, &p3.y, &p4.x,
684 &p4.y)) dwg_add_TRACE (hdr, &pt1, &p2, &p3, &p4);
685 else if (SSCANF_S (p, "polyline_2d %d ((%lf %lf)", &i1, &pt1.x, &pt1.y))
686 {
687 dwg_point_2d *pts = scan_pts2d (i1, &p);
688 if (i1 && pts)
689 {
690 dwg_add_POLYLINE_2D (hdr, i1, pts);
691 free (pts);
692 }
693 }
694 else if (SSCANF_S (p, "polyline_3d %d ((%lf %lf %lf)", &i1, &pt1.x,
695 &pt1.y, &pt1.z))
696 {
697 dwg_point_3d *pts = scan_pts3d (i1, &p);
698 if (i1 && pts)
699 {
700 dwg_add_POLYLINE_3D (hdr, i1, pts);
701 free (pts);
702 }
703 }
704 else if (SSCANF_S (p, "polyline_mesh %d %d ((%lf %lf %lf)", &i1, &i2,
705 &pt1.x, &pt1.y, &pt1.z))
706 {
707 dwg_point_3d *pts = scan_pts3d (i1 * i2, &p);
708 if (i1 && i2 && pts)
709 {
710 dwg_add_POLYLINE_MESH (hdr, i1, i2, pts);
711 free (pts);
712 }
713 }
714 else if (SSCANF_S (p, "dictionary " FMT_TBL " " FMT_TBL " %u",
715 &text[0] SZ, &s1[0] SZ, &u)) dictionary
716 = dwg_add_DICTIONARY (dwg, text, s1, (unsigned long)u);
717 else if (dictionary
718 && SSCANF_S (p, "xrecord dictionary " FMT_TBL, &text[0] SZ))
719 xrecord
720 = dwg_add_XRECORD (dictionary, text);
721 else if (SSCANF_S (p, "shape " FMT_PATH " (%lf %lf %lf) %lf %lf",
722 &text[0] SZ, &pt1.x, &pt1.y, &pt1.z, &scale.x, &rot))
723 dwg_add_SHAPE (hdr, text, &pt1, scale.x, deg2rad (rot));
724 else if (SSCANF_S (p, "viewport " FMT_TBL, &text[0] SZ)) viewport
725 = dwg_add_VIEWPORT (hdr, text);
726 else SET_ENT (viewport, VIEWPORT);
727 else if (SSCANF_S (p, "ellipse (%lf %lf %lf) %lf %lf", &pt1.x, &pt1.y,
728 &pt1.z, &f1, &f2))
729 dwg_add_ELLIPSE (hdr, &pt1, f1, f2);
730 else if (SSCANF_S (p, "spline %d ((%lf %lf %lf)", &i1, &pt1.x, &pt1.y,
731 &pt1.z))
732 {
733 dwg_point_3d *fitpts = scan_pts3d (i1, &p);
734 if (i1 && fitpts
735 && sscanf (p, ") (%lf %lf %lf) (%lf %lf %lf)", &pt2.x, &pt2.y,
736 &pt2.z, &pt3.x, &pt3.y, &pt3.z))
737 {
738 dwg_add_SPLINE (hdr, i1, fitpts, &pt2, &pt3);
739 }
740 free (fitpts);
741 }
742 else if (mtext
743 && sscanf (p, "leader %d ((%lf %lf %lf)", &i1, &pt1.x, &pt1.y,
744 &pt1.z))
745 {
746 dwg_point_3d *pts = scan_pts3d (i1, &p);
747 if (i1 && pts && sscanf (p, ") mtext %d", &i2))
748 {
749 dwg_add_LEADER (hdr, i1, pts, mtext, i2);
750 }
751 free (pts);
752 }
753 else if (SSCANF_S (p,
754 "tolerance " FMT_TBL " (%lf %lf %lf) (%lf %lf %lf)",
755 &text[0] SZ, &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y,
756 &pt2.z)) dwg_add_TOLERANCE (hdr, text, &pt1, &pt2);
757 else if (SSCANF_S (p, "mlinestyle " FMT_TBL, &text[0] SZ)) mlinestyle
758 = dwg_add_MLINESTYLE (dwg, text);
759 else if (SSCANF_S (p, "dimstyle " FMT_TBL, &text[0] SZ)) dimstyle
760 = dwg_add_DIMSTYLE (dwg, text);
761 else SET_ENT (mlinestyle, MLINESTYLE);
762 else SET_ENT (dimstyle, DIMSTYLE);
763 else if (SSCANF_S (
764 p, "ucs (%lf %lf %lf) (%lf %lf %lf) (%lf %lf %lf) " FMT_TBL,
765 &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &pt3.x,
766 &pt3.y, &pt3.z, &text[0] SZ)) ucs
767 = dwg_add_UCS (dwg, &pt1, &pt2, &pt3, text);
768 else SET_ENT (ucs, UCS);
769 else if (viewport
770 && SSCANF_S (p, "layout viewport " FMT_TBL " " FMT_ANY,
771 &text[0] SZ, &s1[0] SZ))
772 {
773 int error;
774 Dwg_Object *obj = dwg_ent_generic_to_object (viewport, &error);
775 if (!error)
776 layout = dwg_add_LAYOUT (obj, text, s1);
777 }
778 else if (SSCANF_S (p, "torus (%lf %lf %lf) (%lf %lf %lf) %lf %lf",
779 &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &f1,
780 &f2)) dwg_add_TORUS (hdr, &pt1, &pt2, f1, f2);
781 else if (SSCANF_S (p, "sphere (%lf %lf %lf) (%lf %lf %lf) %lf", &pt1.x,
782 &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &f1))
783 dwg_add_SPHERE (hdr, &pt1, &pt2, f1);
784 else if (SSCANF_S (
785 p, "cylinder (%lf %lf %lf) (%lf %lf %lf) %lf %lf %lf %lf",
786 &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &height,
787 &f1, &f2, &len))
788 dwg_add_CYLINDER (hdr, &pt1, &pt2, height, f1, f2, len);
789 else if (SSCANF_S (p, "cone (%lf %lf %lf) (%lf %lf %lf) %lf %lf %lf %lf",
790 &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z,
791 &height, &f1, &f2, &len))
792 dwg_add_CONE (hdr, &pt1, &pt2, height, f1, f2, len);
793 else if (SSCANF_S (p, "wedge (%lf %lf %lf) (%lf %lf %lf) %lf %lf %lf",
794 &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &len,
795 &f1, &height))
796 dwg_add_WEDGE (hdr, &pt1, &pt2, len, f1, height);
797 else if (SSCANF_S (p, "box (%lf %lf %lf) (%lf %lf %lf) %lf %lf %lf",
798 &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &len,
799 &f1, &height))
800 dwg_add_BOX (hdr, &pt1, &pt2, len, f1, height);
801 else if (SSCANF_S (p,
802 "pyramid (%lf %lf %lf) (%lf %lf %lf) %lf %d %lf %lf",
803 &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z,
804 &height, &i1, &f1, &f2))
805 dwg_add_PYRAMID (hdr, &pt1, &pt2, height, i1, f1, f2);
806 else if (SSCANF_S (p, "HEADER." FMT_NAME " = %d", &s1[0] SZ, &i1))
807 dwg_dynapi_header_set_value (dwg, s1, &i1, 0);
808 else if (SSCANF_S (p, "HEADER." FMT_NAME " = %lf", &s1[0] SZ, &f1))
809 dwg_dynapi_header_set_value (dwg, s1, &f1, 0);
810 else if (SSCANF_S (p, "HEADER." FMT_NAME " = " FMT_ANY, &s1[0] SZ,
811 &text[0] SZ))
812 dwg_dynapi_header_set_value (dwg, s1, text, 1);
813
814 p = next_line (p, end);
815 }
816 // dwg_resolve_objectrefs_silent (orig_dwg);
817 // start fuzzing if at least 2 entities were added.
818 return (dwg->num_objects - orig_num > 2 ? 0 : 1);
819 }
820
821 #endif // USE_WRITE