(root)/
libredwg-0.13/
examples/
dwgfuzz.c
       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