/*****************************************************************************/ /* LibreDWG - free implementation of the DWG file format */ /* */ /* Copyright (C) 2020 Free Software Foundation, Inc. */ /* */ /* This library is free software, licensed under the terms of the GNU */ /* General Public License as published by the Free Software Foundation, */ /* either version 3 of the License, or (at your option) any later version. */ /* You should have received a copy of the GNU General Public License */ /* along with this program. If not, see . */ /*****************************************************************************/ /* * dwgfuzz.c: afl++/honggfuzz fuzzing for all in- and exporters. Just not the separate ones. * * Also usable like: ../configure --disable-shared --disable-bindings CC=hfuzz-clang CFLAGS='-O2 -g -fsanitize=address,undefined -fno-omit-frame-pointer -I/usr/local/include' && make -C src && make -C examples dwgfuzz honggfuzz -i ../.fuzz-in-dxf -- examples/dwgfuzz -indxf ___FILE___ * Also useful for debugging the fuzzers. AFL_DONT_OPTIMIZE=1 AFL_LLVM_INSTRIM=1 AFL_USE_ASAN=1 make -C examples dwgfuzz V=1 AFL_DEBUG=15 AFL_DEBUG_CHILD_OUTPUT=1 gdb --args afl-fuzz -m none -i ../.fuzz-in-dxf/ -o .fuzz-out/ examples/dwgfuzz (gdb) set follow-fork-mode child * written by Reini Urban */ #include "../src/config.h" #ifdef HAVE_SSCANF_S # define __STDC_WANT_LIB_EXT1__ 1 #endif #include #include #include #include #include #include #include #include #include "common.h" #include "decode.h" #include "encode.h" #include "bits.h" #ifndef DISABLE_DXF # include "out_dxf.h" # ifndef DISABLE_JSON # include "in_json.h" # include "out_json.h" # endif # include "in_dxf.h" #endif #define FUZZ_INMEM 0 #define FUZZ_STDIN 1 #define FUZZ_FILE 2 // defined by ./make-afl-clang-fast.sh for INMEM. defaults to FILE for // debugging #ifndef FUZZ_MODE # define FUZZ_MODE FUZZ_INMEM //#define FUZZ_MODE FUZZ_STDIN //#define FUZZ_MODE FUZZ_FILE #endif int dwg_fuzz_dat (Dwg_Data **restrict dwgp, Bit_Chain *restrict dat); static int version (void) { printf ("dwgfuzz %s INMEM\n", PACKAGE_VERSION); #ifndef __AFL_COMPILER printf ("not instrumented\n"); #else # ifdef __AFL_FUZZ_TESTCASE_BUF printf ("shared-memory instrumented\n"); # else printf ("instrumented\n"); # endif #endif return 0; } #ifndef __AFL_COMPILER # define __AFL_FUZZ_INIT() # if FUZZ_MODE == FUZZ_INMEM unsigned char *__AFL_FUZZ_TESTCASE_BUF; unsigned long __AFL_FUZZ_TESTCASE_LEN; # define __AFL_INIT() \ fp = fopen (argv[2], "rb"); \ if (!fp) \ return 0; \ __AFL_FUZZ_TESTCASE_LEN = dat.size; \ dat_read_file (&dat, fp, argv[2]); \ __AFL_FUZZ_TESTCASE_BUF = dat.chain; # else # define __AFL_INIT() # endif # define __AFL_FUZZ_TESTCASE_LEN dat.size # define __AFL_LOOP(i) 1 #endif __AFL_FUZZ_INIT (); static int help (void) { #if FUZZ_MODE == FUZZ_FILE printf ("\nUsage: dwgfuzz MODE @@\n"); #elif !defined __AFL_COMPILER printf ("\nUsage: dwgfuzz MODE ../.fuzz-in/INFILE\n"); #else printf ("\nUsage: dwgfuzz MODE\n"); #endif printf ("afl++ clang-fast shared-memory backend, using many importers and " "exporters.\n" "\n"); printf ("MODE:\n"); #ifdef USE_WRITE # ifndef DISABLE_DXF printf (" -indxf: import from DXF, export as r2000 DWG\n"); # endif # ifndef DISABLE_JSON printf (" -injson: import from JSON, export as r2000 DWG\n"); # endif printf (" -rw: import from DWG, export as r2000 DWG, re-import from " "this DWG (rewrite)\n"); printf (" -add: import from special add file, export as DWG and DXF, " "re-import from this\n"); #endif printf (" -dwg: import from DWG only\n"); #ifndef DISABLE_DXF printf (" -dxf: import from DWG, export as DXF\n"); printf (" -dxfb: import from DWG, export as binary DXF\n"); #endif #ifndef DISABLE_JSON printf (" -json: import from DWG, export as JSON\n"); printf (" -geojson: import from DWG, export as GeoJSON\n"); #endif printf ("\n" " --version display the version and exit\n"); printf (" --help display this help and exit\n"); return 0; } // for LLVMFuzzerTestOneInput see llvmfuzz.c int main (int argc, char *argv[]) { int i = 0; Dwg_Data dwg; Bit_Chain dat = { 0 }; Bit_Chain out_dat = { 0 }; FILE *fp; struct stat attrib; enum { INVALID, DWG, #if defined(USE_WRITE) && !defined(DISABLE_DXF) INDXF, #endif #if defined(USE_WRITE) && !defined(DISABLE_JSON) INJSON, #endif #if defined(USE_WRITE) RW, ADD, #endif #if !defined(DISABLE_DXF) DXF, DXFB, #endif #if !defined(DISABLE_JSON) JSON, GEOJSON, #endif } mode = INVALID; __AFL_INIT (); if (argc <= 1 || !*argv[1]) return 1; if (strEQc (argv[1], "-dwg")) mode = DWG; #ifdef USE_WRITE # ifndef DISABLE_DXF else if (strEQc (argv[1], "-indxf")) mode = INDXF; # endif # ifndef DISABLE_JSON else if (strEQc (argv[1], "-injson")) mode = INJSON; # endif else if (strEQc (argv[1], "-rw")) mode = RW; else if (strEQc (argv[1], "-add")) mode = ADD; #endif /* USE_WRITE */ #ifndef DISABLE_DXF else if (strEQc (argv[1], "-dxf")) mode = DXF; else if (strEQc (argv[1], "-dxfb")) mode = DXFB; #endif #ifndef DISABLE_JSON else if (strEQc (argv[1], "-json")) mode = JSON; else if (strEQc (argv[1], "-geojson")) mode = GEOJSON; #endif else if (strEQc (argv[1], "--version")) return version (); else if (strEQc (argv[1], "--help")) return help (); else return 1; if (mode == INVALID) return 1; #if FUZZ_MODE == FUZZ_FILE if (argc <= 2 || !*argv[2]) return 1; #endif #if FUZZ_MODE == FUZZ_INMEM && !defined(__AFL_COMPILER) if (argc <= 2 || !*argv[2]) return 1; #endif memset (&dwg, 0, sizeof (dwg)); dat.chain = NULL; // dat.opts = 3;; #if FUZZ_MODE == FUZZ_INMEM dat.chain = __AFL_FUZZ_TESTCASE_BUF; #endif while (__AFL_LOOP (10000)) { // llvm_mode persistent, non-forking mode i++; #ifndef __AFL_COMPILER # ifdef USE_WRITE if (mode == ADD && i > 1) break; # endif if (i > 3) break; #endif #if FUZZ_MODE == FUZZ_INMEM // fastest mode via shared mem if (!dat.chain) dat.chain = __AFL_FUZZ_TESTCASE_BUF; dat.size = __AFL_FUZZ_TESTCASE_LEN; printf ("Fuzzing from shared memory (%" PRIuSIZE ")\n", dat.size); #elif FUZZ_MODE == FUZZ_STDIN // still 10x faster than the old file-forking fuzzer. dat.size = 0; // dat.chain = NULL; dat_read_stream (&dat, stdin); printf ("Fuzzing from stdin (%" PRIuSIZE ")\n", dat.size); #elif FUZZ_MODE == FUZZ_FILE dat.size = 0; fp = fopen (argv[2], "rb"); if (!fp) return 0; dat_read_file (&dat, fp, argv[2]); fclose (fp); printf ("Fuzzing from file (%" PRIuSIZE ")\n", dat.size); #else # error Missing FUZZ_MODE #endif if (dat.size == 0) exit (1); if (dat.size < 100) continue; // useful minimum input length memset (&out_dat, 0, sizeof (out_dat)); bit_chain_set_version (&out_dat, &dat); #ifdef _WIN32 out_dat.fh = fopen ("NUL", "w"); #else out_dat.fh = fopen ("/dev/null", "w"); #endif switch (mode) { case DWG: if (dwg_decode (&dat, &dwg) >= DWG_ERR_CRITICAL) exit (0); break; #if defined(USE_WRITE) && !defined(DISABLE_DXF) case INDXF: if (dwg_read_dxf (&dat, &dwg) < DWG_ERR_CRITICAL) { out_dat.version = R_2000; if (dwg_encode (&dwg, &out_dat) >= DWG_ERR_CRITICAL) exit (0); free (out_dat.chain); } break; #endif #if defined(USE_WRITE) case RW: if (dwg_decode (&dat, &dwg) < DWG_ERR_CRITICAL) { out_dat.version = R_2000; if (dwg_encode (&dwg, &out_dat) >= DWG_ERR_CRITICAL) exit (0); if (dwg_decode (&out_dat, &dwg) >= DWG_ERR_CRITICAL) exit (0); free (out_dat.chain); } break; case ADD: { Dwg_Data *dwgp = &dwg; if (dwg_fuzz_dat (&dwgp, &dat) == 0) { int error; out_dat.byte = 0; out_dat.bit = 0; out_dat.from_version = dwg.header.from_version; out_dat.version = dwg.header.version; out_dat.opts = dwg.opts; error = dwg_encode (&dwg, &out_dat); // dwg -> out_dat if (error >= DWG_ERR_CRITICAL) exit (0); out_dat.byte = 0; out_dat.bit = 0; memset (&dwg, 0, sizeof (Dwg_Data)); error = dwg_decode (&out_dat, &dwg); // out_dat -> dwg if (error >= DWG_ERR_CRITICAL) exit (0); } } break; #endif #if defined(USE_WRITE) && !defined(DISABLE_JSON) case INJSON: if (dwg_read_json (&dat, &dwg) < DWG_ERR_CRITICAL) { out_dat.version = R_2000; if (dwg_encode (&dwg, &out_dat) >= DWG_ERR_CRITICAL) exit (0); } break; #endif #ifndef DISABLE_DXF case DXF: if (dwg_decode (&dat, &dwg) < DWG_ERR_CRITICAL) { if (dwg_write_dxf (&out_dat, &dwg) >= DWG_ERR_CRITICAL) exit (0); } break; case DXFB: if (dwg_decode (&dat, &dwg) < DWG_ERR_CRITICAL) { if (dwg_write_dxfb (&out_dat, &dwg) >= DWG_ERR_CRITICAL) exit (0); } break; #endif #ifndef DISABLE_JSON case JSON: if (dwg_decode (&dat, &dwg) < DWG_ERR_CRITICAL) { if (dwg_write_json (&out_dat, &dwg) >= DWG_ERR_CRITICAL) exit (0); } break; case GEOJSON: if (dwg_decode (&dat, &dwg) < DWG_ERR_CRITICAL) { if (dwg_write_geojson (&out_dat, &dwg) >= DWG_ERR_CRITICAL) exit (0); } break; #endif case INVALID: default: exit (1); } free (out_dat.chain); fclose (out_dat.fh); } dwg_free (&dwg); return 0; } #if defined(USE_WRITE) static dwg_point_2d * scan_pts2d (unsigned num_pts, char **pp) { char *p = *pp; dwg_point_2d *pts; p = strchr (p, '('); if (!p) return NULL; p++; if (num_pts > 5000) exit (0); pts = calloc (num_pts, 16); if (!pts) exit (0); for (unsigned i = 0; i < num_pts; i++) { if (sscanf (p, "(%lf %lf)", &pts[i].x, &pts[i].y)) { p = strchr (p, ')'); if (!p) break; p++; } else { *pp = p; p = NULL; break; } } if (p) { *pp = p; return pts; } else { free (pts); return NULL; } } static dwg_point_3d * scan_pts3d (unsigned num_pts, char **pp) { char *p = *pp; dwg_point_3d *pts; p = strchr (p, '('); if (!p) return NULL; p++; if (num_pts > 5000) exit (0); pts = calloc (num_pts, 24); if (!pts) exit (0); for (unsigned i = 0; i < num_pts; i++) { if (sscanf (p, "(%lf %lf %lf)", &pts[i].x, &pts[i].y, &pts[i].z)) { p = strchr (p, ')'); if (!p) break; p++; } else { *pp = p; p = NULL; break; } } if (p && num_pts) { *pp = p; return pts; } else { free (pts); return NULL; } } static char * next_line (char *restrict p, const char *restrict end) { while (p < end && *p != '\n') p++; if (p < end) p++; return p; } int dwg_fuzz_dat (Dwg_Data **restrict dwgp, Bit_Chain *restrict dat) { Dwg_Data *dwg; Dwg_Object *mspace; Dwg_Object_Ref *mspace_ref; Dwg_Object_BLOCK_HEADER *hdr; const char *end; char *p; Dwg_Version_Type version = R_INVALID; int i = 0; int imperial = 0; BITCODE_BL orig_num; if (!dat->chain) abort (); end = (char *)&dat->chain[dat->size - 1]; if ((p = strstr ((char *)dat->chain, "\nimperial\n"))) { imperial = 1; p += strlen ("\nimperial\n"); } if ((p = strstr ((char *)dat->chain, "version"))) { int i_ver; char s_ver[16]; i = sscanf (p, "version %d", &i_ver); if (i) { snprintf (s_ver, 16, "r%d", i_ver); s_ver[15] = '\0'; version = dwg_version_as (s_ver); p += strlen ("version "); } else p += strlen ("version "); p = next_line (p, end); } if (!i || version >= R_AFTER) version = R_2000; dwg = dwg_new_Document (version, imperial, 0); *dwgp = dwg; mspace = dwg_model_space_object (dwg); mspace_ref = dwg_model_space_ref (dwg); hdr = mspace->tio.object->tio.BLOCK_HEADER; orig_num = dwg->num_objects; // read dat line by line and call the matching add API while (p && p < end) { char text[120], s1[120]; dwg_point_2d p2, p3, p4; dwg_point_3d pt1, pt2, pt3, pt4, scale; double height, rot, len, f1, f2; int i1, i2; unsigned u; Dwg_Entity_VIEWPORT *viewport = NULL; Dwg_Entity_MTEXT *mtext = NULL; Dwg_Object_DICTIONARY *dictionary = NULL; Dwg_Object_XRECORD *xrecord = NULL; Dwg_Object_MLINESTYLE *mlinestyle = NULL; Dwg_Object_DIMSTYLE *dimstyle = NULL; Dwg_Object_UCS *ucs = NULL; Dwg_Object_LAYOUT *layout = NULL; // accepts only ASCII strings, for fuzzing only # ifdef HAVE_SSCANF_S # define SSCANF_S sscanf_s # define SZ , 119 # define FMT_NAME "%[a-zA-Z0-9_]" # define FMT_TBL "\"%[a-zA-Z0-9._ -]\"" # define FMT_PATH "\"%[a-zA-Z0-9_. \\-]\"" # define FMT_ANY "\"%s\"" # else # define SSCANF_S sscanf # define SZ # define FMT_NAME "%119[a-zA-Z0-9_]" # define FMT_TBL "\"%119[a-zA-Z0-9._ -]\"" # define FMT_PATH "\"%119[a-zA-Z0-9_. \\-]\"" # define FMT_ANY "\"%119s\"" # endif # define SET_ENT(var, name) \ if (!var) \ ; \ else if (SSCANF_S (p, #var "." FMT_NAME " = %d", &s1[0] SZ, &i1)) \ dwg_dynapi_entity_set_value (var, #name, s1, &i1, 0); \ else if (SSCANF_S (p, #var "." FMT_NAME " = %lf", &s1[0] SZ, &f1)) \ dwg_dynapi_entity_set_value (var, #name, s1, &f1, 0); \ else if (SSCANF_S (p, #var "." FMT_NAME " = " FMT_ANY, &s1[0] SZ, \ &text[0] SZ)) \ dwg_dynapi_entity_set_value (var, #name, s1, text, 1) if (SSCANF_S (p, "line (%lf %lf %lf) (%lf %lf %lf)", &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z)) dwg_add_LINE (hdr, &pt1, &pt2); else if (SSCANF_S (p, "ray (%lf %lf %lf) (%lf %lf %lf)", &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z)) dwg_add_RAY (hdr, &pt1, &pt2); else if (SSCANF_S (p, "xline (%lf %lf %lf) (%lf %lf %lf)", &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z)) dwg_add_XLINE (hdr, &pt1, &pt2); else if (SSCANF_S (p, "text " FMT_ANY " (%lf %lf %lf) %lf", &text[0] SZ, &pt1.x, &pt1.y, &pt1.z, &height)) dwg_add_TEXT (hdr, text, &pt1, height); else if (SSCANF_S (p, "mtext (%lf %lf %lf) %lf " FMT_ANY, &pt1.x, &pt1.y, &pt1.z, &height, &text[0] SZ)) mtext = dwg_add_MTEXT (hdr, &pt1, height, text); else SET_ENT (mtext, MTEXT); else if (SSCANF_S (p, "block " FMT_TBL, &text[0] SZ)) dwg_add_BLOCK (hdr, text); else if (memBEGINc (p, "endblk\n")) dwg_add_ENDBLK (hdr); else if (SSCANF_S (p, "insert (%lf %lf %lf) " FMT_TBL " %lf %lf %lf %lf", &pt1.x, &pt1.y, &pt1.z, &text[0] SZ, &scale.x, &scale.y, &scale.z, &rot)) dwg_add_INSERT (hdr, &pt1, text, scale.x, scale.y, scale.z, deg2rad (rot)); else if (SSCANF_S (p, "minsert (%lf %lf %lf) " FMT_TBL " %lf %lf %lf %lf %d %d " "%lf %lf", &pt1.x, &pt1.y, &pt1.z, &text[0] SZ, &scale.x, &scale.y, &scale.z, &rot, &i1, &i2, &f1, &f2)) dwg_add_MINSERT (hdr, &pt1, text, scale.x, scale.y, scale.z, deg2rad (rot), i1, i2, f1, f2); else if (SSCANF_S (p, "point (%lf %lf %lf)", &pt1.x, &pt1.y, &pt1.z)) dwg_add_POINT (hdr, &pt1); else if (SSCANF_S (p, "circle (%lf %lf %lf) %lf", &pt1.x, &pt1.y, &pt1.z, &f1)) dwg_add_CIRCLE (hdr, &pt1, f1); else if (SSCANF_S (p, "arc (%lf %lf %lf) %lf %lf %lf", &pt1.x, &pt1.y, &pt1.z, &f1, &f2, &height)) dwg_add_ARC (hdr, &pt1, f1, f2, height); else if (SSCANF_S (p, "dimension_aligned (%lf %lf %lf) (%lf %lf %lf) (%lf " "%lf %lf)", &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &pt3.x, &pt3.y, &pt3.z)) dwg_add_DIMENSION_ALIGNED (hdr, &pt1, &pt2, &pt3); else if (SSCANF_S ( p, "dimension_linear (%lf %lf %lf) (%lf %lf %lf) (%lf %lf " "%lf) %lf", &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &pt3.x, &pt3.y, &pt3.z, &rot)) dwg_add_DIMENSION_LINEAR (hdr, &pt1, &pt2, &pt3, deg2rad (rot)); else if (SSCANF_S ( p, "dimension_ang2ln (%lf %lf %lf) (%lf %lf %lf) (%lf %lf " "%lf) (%lf %lf %lf)", &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &pt3.x, &pt3.y, &pt3.z, &pt4.x, &pt4.y, &pt4.z)) dwg_add_DIMENSION_ANG2LN (hdr, &pt1, &pt2, &pt3, &pt4); else if (SSCANF_S ( p, "dimension_ang3pt (%lf %lf %lf) (%lf %lf %lf) (%lf %lf " "%lf) (%lf %lf %lf)", &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &pt3.x, &pt3.y, &pt3.z, &pt4.x, &pt4.y, &pt4.z)) dwg_add_DIMENSION_ANG3PT (hdr, &pt1, &pt2, &pt3, &pt4); else if (SSCANF_S (p, "dimension_diameter (%lf %lf %lf) (%lf %lf %lf) %lf", &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &len)) dwg_add_DIMENSION_DIAMETER (hdr, &pt1, &pt2, len); else if (SSCANF_S (p, "dimension_ordinate (%lf %lf %lf) (%lf %lf %lf) %d", &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &i1)) dwg_add_DIMENSION_ORDINATE (hdr, &pt1, &pt2, i1 ? true : false); else if (SSCANF_S (p, "dimension_radius (%lf %lf %lf) (%lf %lf %lf) %lf", &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &len)) dwg_add_DIMENSION_RADIUS (hdr, &pt1, &pt2, len); else if (SSCANF_S (p, "3dface (%lf %lf %lf) (%lf %lf %lf) (%lf %lf " "%lf) (%lf %lf %lf)", &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &pt3.x, &pt3.y, &pt3.z, &pt4.x, &pt4.y, &pt4.z)) dwg_add_3DFACE (hdr, &pt1, &pt2, &pt3, &pt4); else if (SSCANF_S (p, "3dface (%lf %lf %lf) (%lf %lf %lf) (%lf %lf " "%lf)", &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &pt3.x, &pt3.y, &pt3.z)) dwg_add_3DFACE (hdr, &pt1, &pt2, &pt3, NULL); else if (SSCANF_S ( p, "solid (%lf %lf %lf) (%lf %lf) (%lf %lf) (%lf %lf)", &pt1.x, &pt1.y, &pt1.z, &p2.x, &p2.y, &p3.x, &p3.y, &p4.x, &p4.y)) dwg_add_SOLID (hdr, &pt1, &p2, &p3, &p4); else if (SSCANF_S ( p, "trace (%lf %lf %lf) (%lf %lf) (%lf %lf) (%lf %lf)", &pt1.x, &pt1.y, &pt1.z, &p2.x, &p2.y, &p3.x, &p3.y, &p4.x, &p4.y)) dwg_add_TRACE (hdr, &pt1, &p2, &p3, &p4); else if (SSCANF_S (p, "polyline_2d %d ((%lf %lf)", &i1, &pt1.x, &pt1.y)) { dwg_point_2d *pts = scan_pts2d (i1, &p); if (i1 && pts) { dwg_add_POLYLINE_2D (hdr, i1, pts); free (pts); } } else if (SSCANF_S (p, "polyline_3d %d ((%lf %lf %lf)", &i1, &pt1.x, &pt1.y, &pt1.z)) { dwg_point_3d *pts = scan_pts3d (i1, &p); if (i1 && pts) { dwg_add_POLYLINE_3D (hdr, i1, pts); free (pts); } } else if (SSCANF_S (p, "polyline_mesh %d %d ((%lf %lf %lf)", &i1, &i2, &pt1.x, &pt1.y, &pt1.z)) { dwg_point_3d *pts = scan_pts3d (i1 * i2, &p); if (i1 && i2 && pts) { dwg_add_POLYLINE_MESH (hdr, i1, i2, pts); free (pts); } } else if (SSCANF_S (p, "dictionary " FMT_TBL " " FMT_TBL " %u", &text[0] SZ, &s1[0] SZ, &u)) dictionary = dwg_add_DICTIONARY (dwg, text, s1, (unsigned long)u); else if (dictionary && SSCANF_S (p, "xrecord dictionary " FMT_TBL, &text[0] SZ)) xrecord = dwg_add_XRECORD (dictionary, text); else if (SSCANF_S (p, "shape " FMT_PATH " (%lf %lf %lf) %lf %lf", &text[0] SZ, &pt1.x, &pt1.y, &pt1.z, &scale.x, &rot)) dwg_add_SHAPE (hdr, text, &pt1, scale.x, deg2rad (rot)); else if (SSCANF_S (p, "viewport " FMT_TBL, &text[0] SZ)) viewport = dwg_add_VIEWPORT (hdr, text); else SET_ENT (viewport, VIEWPORT); else if (SSCANF_S (p, "ellipse (%lf %lf %lf) %lf %lf", &pt1.x, &pt1.y, &pt1.z, &f1, &f2)) dwg_add_ELLIPSE (hdr, &pt1, f1, f2); else if (SSCANF_S (p, "spline %d ((%lf %lf %lf)", &i1, &pt1.x, &pt1.y, &pt1.z)) { dwg_point_3d *fitpts = scan_pts3d (i1, &p); if (i1 && fitpts && sscanf (p, ") (%lf %lf %lf) (%lf %lf %lf)", &pt2.x, &pt2.y, &pt2.z, &pt3.x, &pt3.y, &pt3.z)) { dwg_add_SPLINE (hdr, i1, fitpts, &pt2, &pt3); } free (fitpts); } else if (mtext && sscanf (p, "leader %d ((%lf %lf %lf)", &i1, &pt1.x, &pt1.y, &pt1.z)) { dwg_point_3d *pts = scan_pts3d (i1, &p); if (i1 && pts && sscanf (p, ") mtext %d", &i2)) { dwg_add_LEADER (hdr, i1, pts, mtext, i2); } free (pts); } else if (SSCANF_S (p, "tolerance " FMT_TBL " (%lf %lf %lf) (%lf %lf %lf)", &text[0] SZ, &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z)) dwg_add_TOLERANCE (hdr, text, &pt1, &pt2); else if (SSCANF_S (p, "mlinestyle " FMT_TBL, &text[0] SZ)) mlinestyle = dwg_add_MLINESTYLE (dwg, text); else if (SSCANF_S (p, "dimstyle " FMT_TBL, &text[0] SZ)) dimstyle = dwg_add_DIMSTYLE (dwg, text); else SET_ENT (mlinestyle, MLINESTYLE); else SET_ENT (dimstyle, DIMSTYLE); else if (SSCANF_S ( p, "ucs (%lf %lf %lf) (%lf %lf %lf) (%lf %lf %lf) " FMT_TBL, &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &pt3.x, &pt3.y, &pt3.z, &text[0] SZ)) ucs = dwg_add_UCS (dwg, &pt1, &pt2, &pt3, text); else SET_ENT (ucs, UCS); else if (viewport && SSCANF_S (p, "layout viewport " FMT_TBL " " FMT_ANY, &text[0] SZ, &s1[0] SZ)) { int error; Dwg_Object *obj = dwg_ent_generic_to_object (viewport, &error); if (!error) layout = dwg_add_LAYOUT (obj, text, s1); } else if (SSCANF_S (p, "torus (%lf %lf %lf) (%lf %lf %lf) %lf %lf", &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &f1, &f2)) dwg_add_TORUS (hdr, &pt1, &pt2, f1, f2); else if (SSCANF_S (p, "sphere (%lf %lf %lf) (%lf %lf %lf) %lf", &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &f1)) dwg_add_SPHERE (hdr, &pt1, &pt2, f1); else if (SSCANF_S ( p, "cylinder (%lf %lf %lf) (%lf %lf %lf) %lf %lf %lf %lf", &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &height, &f1, &f2, &len)) dwg_add_CYLINDER (hdr, &pt1, &pt2, height, f1, f2, len); else if (SSCANF_S (p, "cone (%lf %lf %lf) (%lf %lf %lf) %lf %lf %lf %lf", &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &height, &f1, &f2, &len)) dwg_add_CONE (hdr, &pt1, &pt2, height, f1, f2, len); else if (SSCANF_S (p, "wedge (%lf %lf %lf) (%lf %lf %lf) %lf %lf %lf", &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &len, &f1, &height)) dwg_add_WEDGE (hdr, &pt1, &pt2, len, f1, height); else if (SSCANF_S (p, "box (%lf %lf %lf) (%lf %lf %lf) %lf %lf %lf", &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &len, &f1, &height)) dwg_add_BOX (hdr, &pt1, &pt2, len, f1, height); else if (SSCANF_S (p, "pyramid (%lf %lf %lf) (%lf %lf %lf) %lf %d %lf %lf", &pt1.x, &pt1.y, &pt1.z, &pt2.x, &pt2.y, &pt2.z, &height, &i1, &f1, &f2)) dwg_add_PYRAMID (hdr, &pt1, &pt2, height, i1, f1, f2); else if (SSCANF_S (p, "HEADER." FMT_NAME " = %d", &s1[0] SZ, &i1)) dwg_dynapi_header_set_value (dwg, s1, &i1, 0); else if (SSCANF_S (p, "HEADER." FMT_NAME " = %lf", &s1[0] SZ, &f1)) dwg_dynapi_header_set_value (dwg, s1, &f1, 0); else if (SSCANF_S (p, "HEADER." FMT_NAME " = " FMT_ANY, &s1[0] SZ, &text[0] SZ)) dwg_dynapi_header_set_value (dwg, s1, text, 1); p = next_line (p, end); } // dwg_resolve_objectrefs_silent (orig_dwg); // start fuzzing if at least 2 entities were added. return (dwg->num_objects - orig_num > 2 ? 0 : 1); } #endif // USE_WRITE