(root)/
libredwg-0.13/
programs/
dwgread.c
       1  /*****************************************************************************/
       2  /*  LibreDWG - free implementation of the DWG file format                    */
       3  /*                                                                           */
       4  /*  Copyright (C) 2009-2023 Free Software Foundation, Inc.                   */
       5  /*  Copyright (C) 2010 Thien-Thi Nguyen                                      */
       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  /*
      15   * dwgread.c: read a DWG file, print verbose logging, and output to
      16   *            various formats.
      17   * written by Felipe Castro
      18   * modified by Felipe CorrĂȘa da Silva Sances
      19   * modified by Rodrigo Rodrigues da Silva
      20   * modified by Thien-Thi Nguyen
      21   * modified by Reini Urban
      22   */
      23  
      24  #include "../src/config.h"
      25  #include <stdlib.h>
      26  #include <stdio.h>
      27  #include <string.h>
      28  // strings.h or string.h
      29  #ifdef AX_STRCASECMP_HEADER
      30  #  include AX_STRCASECMP_HEADER
      31  #endif
      32  #include "my_getopt.h"
      33  #ifdef HAVE_VALGRIND_VALGRIND_H
      34  #  include <valgrind/valgrind.h>
      35  #endif
      36  
      37  #include "dwg.h"
      38  #include "common.h"
      39  #include "bits.h"
      40  #ifndef DISABLE_DXF
      41  #  include "out_dxf.h"
      42  #  ifndef DISABLE_JSON
      43  #    include "out_json.h"
      44  #  endif
      45  #endif
      46  
      47  #if !defined HAVE_STRCASECMP
      48  int strcasecmp (const char *a, const char *b);
      49  #endif
      50  
      51  static int opts = 1;
      52  
      53  static int
      54  usage (void)
      55  {
      56  #ifndef DISABLE_DXF
      57    printf ("\nUsage: dwgread [-v[0-9]] [-O FMT] [-o OUTFILE] [DWGFILE|-]\n");
      58  #else
      59    printf ("\nUsage: dwgread [-v[0-9]] [DWGFILE|-]\n");
      60  #endif
      61    return 1;
      62  }
      63  static int
      64  opt_version (void)
      65  {
      66    printf ("dwgread %s\n", PACKAGE_VERSION);
      67    return 0;
      68  }
      69  static int
      70  help (void)
      71  {
      72    printf ("\nUsage: dwgread [OPTION]... DWGFILE\n");
      73    printf ("Reads the DWG into some optional output format to stdout or some "
      74            "file,\n"
      75            "and prints error, success or verbose internal progress to stderr.\n"
      76            "\n");
      77  #ifdef HAVE_GETOPT_LONG
      78    printf ("  -v[0-9], --verbose [0-9]  verbosity\n");
      79  #  ifndef DISABLE_DXF
      80  #    ifndef DISABLE_JSON
      81    printf ("  -O fmt,  --format fmt     fmt: DXF, DXFB, JSON, GeoJSON\n");
      82  #    else
      83    printf ("  -O fmt,  --format fmt     fmt: DXF, DXFB\n");
      84  #    endif
      85    printf ("           Planned output formats:  YAML, XML/OGR, GPX, SVG, PS\n");
      86    printf ("  -o outfile                also defines the output fmt. Default: "
      87            "stdout\n");
      88  #  endif
      89    printf ("           --help           display this help and exit\n");
      90    printf ("           --version        output version information and exit\n"
      91            "\n");
      92  #else
      93    printf ("  -v[0-9]     verbosity\n");
      94  #  ifndef DISABLE_DXF
      95  #    ifndef DISABLE_JSON
      96    printf ("  -O fmt      fmt: DXF, DXFB, JSON, GeoJSON\n");
      97  #    else
      98    printf ("  -O fmt      fmt: DXF, DXFB\n");
      99  #    endif
     100    printf (
     101        "              Planned output formats:  YAML, XML/OGR, GPX, SVG, PS\n");
     102    printf ("  -o outfile  also defines the output fmt. Default: stdout\n");
     103  #  endif
     104    printf ("  -h          display this help and exit\n");
     105    printf ("  -i          output version information and exit\n"
     106            "\n");
     107  #endif
     108    printf ("GNU LibreDWG online manual: "
     109            "<https://www.gnu.org/software/libredwg/>\n");
     110    return 0;
     111  }
     112  
     113  int
     114  main (int argc, char *argv[])
     115  {
     116    int i = 1;
     117    int error;
     118    Dwg_Data dwg;
     119    const char *fmt = NULL;
     120    const char *outfile = NULL;
     121    int has_v = 0;
     122    int force_free = 0;
     123    int c;
     124  #ifdef HAVE_GETOPT_LONG
     125    int option_index = 0;
     126    static struct option long_options[]
     127        = { { "verbose", 1, &opts, 1 }, // optional
     128            { "format", 1, NULL, 'O' },   { "file", 1, NULL, 'o' },
     129            { "help", 0, NULL, 0 },       { "version", 0, NULL, 0 },
     130            { "force-free", 0, NULL, 0 }, { NULL, 0, NULL, 0 } };
     131  #endif
     132  
     133    if (argc < 2)
     134      return usage ();
     135  
     136    while (1)
     137      {
     138  #ifdef HAVE_GETOPT_LONG
     139        c = getopt_long (argc, argv, "v::O:o:h", long_options, &option_index);
     140  #else
     141        c = getopt (argc, argv, "v::O:o:hi");
     142  #endif
     143        if (c == -1)
     144          break;
     145        switch (c)
     146          {
     147          case ':': // missing arg
     148            if (optarg && !strcmp (optarg, "v"))
     149              {
     150                opts = 1;
     151                has_v = 1;
     152                break;
     153              }
     154            fprintf (stderr, "%s: option '-%c' requires an argument\n", argv[0],
     155                     optopt);
     156            break;
     157  #ifdef HAVE_GETOPT_LONG
     158          case 0:
     159            /* This option sets a flag */
     160            if (!strcmp (long_options[option_index].name, "verbose"))
     161              {
     162                if (opts < 0 || opts > 9)
     163                  return usage ();
     164  #  if defined(USE_TRACING) && defined(HAVE_SETENV)
     165                {
     166                  char v[2];
     167                  *v = opts + '0';
     168                  *(v + 1) = 0;
     169                  setenv ("LIBREDWG_TRACE", v, 1);
     170                }
     171  #  endif
     172                has_v = 1;
     173                break;
     174              }
     175            if (!strcmp (long_options[option_index].name, "version"))
     176              return opt_version ();
     177            if (!strcmp (long_options[option_index].name, "help"))
     178              return help ();
     179            if (!strcmp (long_options[option_index].name, "force-free"))
     180              force_free = 1;
     181            break;
     182  #else
     183          case 'i':
     184            return opt_version ();
     185  #endif
     186          case 'O':
     187            fmt = strdup (optarg);
     188            break;
     189          case 'o':
     190            outfile = strdup (optarg);
     191            if (!fmt && outfile != NULL)
     192              {
     193  #ifndef DISABLE_DXF
     194                if (strstr (outfile, ".dxf") || strstr (outfile, ".DXF"))
     195                  fmt = strdup ("dxf");
     196                else if (strstr (outfile, ".dxfb") || strstr (outfile, ".DXFB"))
     197                  fmt = strdup ("dxfb");
     198                else
     199  #endif
     200  #ifndef DISABLE_JSON
     201                    if (strstr (outfile, ".json") || strstr (outfile, ".JSON"))
     202                  fmt = strdup ("json");
     203                else if (strstr (outfile, ".geojson")
     204                         || strstr (outfile, ".GeoJSON"))
     205                  fmt = strdup ("geojson");
     206                else
     207  #endif
     208                  fprintf (stderr, "Unknown output format for %s\n", outfile);
     209              }
     210            break;
     211          case 'v': // support -v3 and -v
     212            i = (optind > 0 && optind < argc) ? optind - 1 : 1;
     213            if (!memcmp (argv[i], "-v", 2))
     214              {
     215                opts = argv[i][2] ? argv[i][2] - '0' : 1;
     216              }
     217            if (opts < 0 || opts > 9)
     218              return usage ();
     219  #if defined(USE_TRACING) && defined(HAVE_SETENV)
     220            {
     221              char v[2];
     222              *v = opts + '0';
     223              *(v + 1) = 0;
     224              setenv ("LIBREDWG_TRACE", v, 1);
     225            }
     226  #endif
     227            has_v = 1;
     228            break;
     229          case 'h':
     230            return help ();
     231          case '?':
     232            fprintf (stderr, "%s: invalid option '-%c' ignored\n", argv[0],
     233                     optopt);
     234            break;
     235          default:
     236            return usage ();
     237          }
     238      }
     239    i = optind;
     240  
     241    memset (&dwg, 0, sizeof (Dwg_Data));
     242    if (has_v || !fmt)
     243      dwg.opts = opts;
     244  #if defined(USE_TRACING) && defined(HAVE_SETENV)
     245    if (!has_v)
     246      setenv ("LIBREDWG_TRACE", "1", 0);
     247  #endif
     248  
     249    if (optind != argc)
     250      {
     251        if (opts > 1)
     252          fprintf (stderr, "Reading DWG file %s\n", argv[i]);
     253        error = dwg_read_file (argv[i], &dwg);
     254      }
     255    else
     256      {
     257        if (opts > 1)
     258          fprintf (stderr, "Reading DWG from stdin\n");
     259        error = dwg_read_file ("-", &dwg); // i.e. from stdin
     260      }
     261  
     262    if (error >= DWG_ERR_CRITICAL)
     263      goto done;
     264  
     265    if (fmt)
     266      {
     267        Bit_Chain dat = { 0 };
     268        if (outfile)
     269          dat.fh = fopen (outfile, "w");
     270        else
     271          dat.fh = stdout;
     272        fprintf (stderr, "\n");
     273        dat.version = dat.from_version = dwg.header.version;
     274        dat.codepage = dwg.header.codepage;
     275        // TODO --as-rNNNN version? for now not.
     276        // we want the native dump, converters are separate.
     277  #ifndef DISABLE_DXF
     278  #  ifndef DISABLE_JSON
     279        if (!strcasecmp (fmt, "json"))
     280          {
     281            if (opts > 1 && outfile)
     282              fprintf (stderr, "Writing JSON file %s\n", outfile);
     283            error = dwg_write_json (&dat, &dwg);
     284          }
     285        else
     286  #  endif
     287            if (!strcasecmp (fmt, "dxfb"))
     288          {
     289            if (opts > 1 && outfile)
     290              fprintf (stderr, "Writing Binary DXF file %s\n", outfile);
     291            error = dwg_write_dxfb (&dat, &dwg);
     292          }
     293        else if (!strcasecmp (fmt, "dxf"))
     294          {
     295            if (opts > 1 && outfile)
     296              fprintf (stderr, "Writing Binary DXF file %s\n", outfile);
     297            error = dwg_write_dxf (&dat, &dwg);
     298          }
     299  #  ifndef DISABLE_JSON
     300        else if (!strcasecmp (fmt, "geojson"))
     301          {
     302            if (opts > 1 && outfile)
     303              fprintf (stderr, "Writing GeoJSON file %s\n", outfile);
     304            error = dwg_write_geojson (&dat, &dwg);
     305          }
     306        else
     307  #  endif
     308  #endif
     309          fprintf (stderr, "Invalid output format '%s'\n", fmt);
     310  
     311        if (outfile)
     312          fclose (dat.fh);
     313      }
     314  
     315  done:
     316  #if defined __SANITIZE_ADDRESS__ || __has_feature(address_sanitizer)
     317    {
     318      char *asanenv = getenv ("ASAN_OPTIONS");
     319      if (!asanenv)
     320        force_free = 1;
     321      // detect_leaks is enabled by default. see if it's turned off
     322      else if (strstr (asanenv, "detect_leaks=0") == NULL) /* not found */
     323        force_free = 1;
     324    }
     325  #endif
     326  
     327    // forget about valgrind. really huge DWG's need endlessly here.
     328    if ((dwg.header.version && dwg.num_objects < 1000) || force_free
     329  #ifdef HAVE_VALGRIND_VALGRIND_H
     330        || (RUNNING_ON_VALGRIND)
     331  #endif
     332    )
     333      {
     334        if (fmt)
     335          free ((char *)fmt);
     336        if (outfile)
     337          free ((char *)outfile);
     338        dwg_free (&dwg);
     339      }
     340  
     341    if (error >= DWG_ERR_CRITICAL)
     342      {
     343        fprintf (stderr, "ERROR 0x%x\n", error);
     344        if (error && opts > 2)
     345          dwg_errstrings (error);
     346      }
     347    else
     348      {
     349        if (opts > 1)
     350          {
     351            fprintf (stderr, "SUCCESS 0x%x\n", error);
     352            if (error && opts > 2)
     353              dwg_errstrings (error);
     354          }
     355        else
     356          fprintf (stderr, "SUCCESS\n");
     357      }
     358  
     359    return error >= DWG_ERR_CRITICAL ? 1 : 0;
     360  }