/*****************************************************************************/ /* LibreDWG - free implementation of the DWG file format */ /* */ /* Copyright (C) 2009-2020 Free Software Foundation, Inc. */ /* Copyright (C) 2010 Thien-Thi Nguyen */ /* */ /* 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 . */ /*****************************************************************************/ /* * dwgread.c: read a DWG file, print verbose logging, and output to * various formats. * written by Felipe Castro * modified by Felipe CorrĂȘa da Silva Sances * modified by Rodrigo Rodrigues da Silva * modified by Thien-Thi Nguyen * modified by Reini Urban */ #include "../src/config.h" #include #include #include // strings.h or string.h #ifdef AX_STRCASECMP_HEADER # include AX_STRCASECMP_HEADER #endif #include #ifdef HAVE_VALGRIND_VALGRIND_H # include #endif #include "dwg.h" #include "common.h" #ifndef DISABLE_DXF # include "out_dxf.h" # ifndef DISABLE_JSON # include "out_json.h" # endif #endif static int opts = 1; static int usage (void) { #ifndef DISABLE_DXF printf ("\nUsage: dwgread [-v[0-9]] [-O FMT] [-o OUTFILE] [DWGFILE|-]\n"); #else printf ("\nUsage: dwgread [-v[0-9]] [DWGFILE|-]\n"); #endif return 1; } static int opt_version (void) { printf ("dwgread %s\n", PACKAGE_VERSION); return 0; } static int help (void) { printf ("\nUsage: dwgread [OPTION]... DWGFILE\n"); printf ("Reads the DWG into some optional output format to stdout or some " "file,\n" "and prints error, success or verbose internal progress to stderr.\n" "\n"); #ifdef HAVE_GETOPT_LONG printf (" -v[0-9], --verbose [0-9] verbosity\n"); #ifndef DISABLE_DXF # ifndef DISABLE_JSON printf (" -O fmt, --format fmt fmt: DXF, DXFB, JSON, GeoJSON\n"); # else printf (" -O fmt, --format fmt fmt: DXF, DXFB\n"); # endif printf (" Planned output formats: YAML, XML/OGR, GPX, SVG, PS\n"); printf (" -o outfile also defines the output fmt. Default: " "stdout\n"); #endif printf (" --help display this help and exit\n"); printf (" --version output version information and exit\n" "\n"); #else printf (" -v[0-9] verbosity\n"); #ifndef DISABLE_DXF # ifndef DISABLE_JSON printf (" -O fmt fmt: DXF, DXFB, JSON, GeoJSON\n"); # else printf (" -O fmt fmt: DXF, DXFB\n"); # endif printf (" Planned output formats: YAML, XML/OGR, GPX, SVG, PS\n"); printf (" -o outfile also defines the output fmt. Default: stdout\n"); #endif printf (" -h display this help and exit\n"); printf (" -i output version information and exit\n" "\n"); #endif printf ("GNU LibreDWG online manual: " "\n"); return 0; } int main (int argc, char *argv[]) { int i = 1; int error; Dwg_Data dwg; const char *fmt = NULL; const char *outfile = NULL; int has_v = 0; int force_free = 0; int c; #ifdef HAVE_GETOPT_LONG int option_index = 0; static struct option long_options[] = { { "verbose", 1, &opts, 1 }, // optional { "format", 1, 0, 'O' }, { "file", 1, 0, 'o' }, { "help", 0, 0, 0 }, { "version", 0, 0, 0 }, { "force-free", 0, 0, 0 }, { NULL, 0, NULL, 0 } }; #endif if (argc < 2) return usage (); while #ifdef HAVE_GETOPT_LONG ((c = getopt_long (argc, argv, ":v::O:o:h", long_options, &option_index)) != -1) #else ((c = getopt (argc, argv, ":v::O:o:hi")) != -1) #endif { if (c == -1) break; switch (c) { case ':': // missing arg if (optarg && !strcmp (optarg, "v")) { opts = 1; has_v = 1; break; } fprintf (stderr, "%s: option '-%c' requires an argument\n", argv[0], optopt); break; #ifdef HAVE_GETOPT_LONG case 0: /* This option sets a flag */ if (!strcmp (long_options[option_index].name, "verbose")) { if (opts < 0 || opts > 9) return usage (); # if defined(USE_TRACING) && defined(HAVE_SETENV) { char v[2]; *v = opts + '0'; *(v + 1) = 0; setenv ("LIBREDWG_TRACE", v, 1); } # endif has_v = 1; break; } if (!strcmp (long_options[option_index].name, "version")) return opt_version (); if (!strcmp (long_options[option_index].name, "help")) return help (); if (!strcmp (long_options[option_index].name, "force-free")) force_free = 1; break; #else case 'i': return opt_version (); #endif case 'O': fmt = optarg; break; case 'o': outfile = optarg; if (!fmt && outfile != NULL) { #ifndef DISABLE_DXF #ifndef DISABLE_JSON if (strstr (outfile, ".json") || strstr (outfile, ".JSON")) fmt = (char *)"json"; else #endif if (strstr (outfile, ".dxf") || strstr (outfile, ".DXF")) fmt = (char *)"dxf"; else if (strstr (outfile, ".dxfb") || strstr (outfile, ".DXFB")) fmt = (char *)"dxfb"; #ifndef DISABLE_JSON else if (strstr (outfile, ".geojson") || strstr (outfile, ".GeoJSON")) fmt = (char *)"geojson"; #endif else #endif fprintf (stderr, "Unknown output format for %s\n", outfile); } break; case 'v': // support -v3 and -v i = (optind > 0 && optind < argc) ? optind - 1 : 1; if (!memcmp (argv[i], "-v", 2)) { opts = argv[i][2] ? argv[i][2] - '0' : 1; } if (opts < 0 || opts > 9) return usage (); #if defined(USE_TRACING) && defined(HAVE_SETENV) { char v[2]; *v = opts + '0'; *(v + 1) = 0; setenv ("LIBREDWG_TRACE", v, 1); } #endif has_v = 1; break; case 'h': return help (); case '?': fprintf (stderr, "%s: invalid option '-%c' ignored\n", argv[0], optopt); break; default: return usage (); } } i = optind; memset (&dwg, 0, sizeof (Dwg_Data)); if (has_v || !fmt) dwg.opts = opts; #if defined(USE_TRACING) && defined(HAVE_SETENV) if (!has_v) setenv ("LIBREDWG_TRACE", "1", 0); #endif if (optind != argc) { if (opts > 1) fprintf (stderr, "Reading DWG file %s\n", argv[i]); error = dwg_read_file (argv[i], &dwg); } else { if (opts > 1) fprintf (stderr, "Reading DWG from stdin\n"); error = dwg_read_file ("-", &dwg); // i.e. from stdin } if (error >= DWG_ERR_CRITICAL) goto done; if (fmt) { Bit_Chain dat = { 0 }; if (outfile) dat.fh = fopen (outfile, "w"); else dat.fh = stdout; fprintf (stderr, "\n"); dat.version = dat.from_version = dwg.header.version; // TODO --as-rNNNN version? for now not. // we want the native dump, converters are separate. #ifndef DISABLE_DXF #ifndef DISABLE_JSON if (!strcasecmp (fmt, "json")) { if (opts > 1 && outfile) fprintf (stderr, "Writing JSON file %s\n", outfile); error = dwg_write_json (&dat, &dwg); } else #endif if (!strcasecmp (fmt, "dxfb")) { if (opts > 1 && outfile) fprintf (stderr, "Writing Binary DXF file %s\n", outfile); error = dwg_write_dxfb (&dat, &dwg); } else if (!strcasecmp (fmt, "dxf")) { if (opts > 1 && outfile) fprintf (stderr, "Writing Binary DXF file %s\n", outfile); error = dwg_write_dxf (&dat, &dwg); } #ifndef DISABLE_JSON else if (!strcasecmp (fmt, "geojson")) { if (opts > 1 && outfile) fprintf (stderr, "Writing GeoJSON file %s\n", outfile); error = dwg_write_geojson (&dat, &dwg); } else #endif #endif fprintf (stderr, "Invalid output format '%s'\n", fmt); if (outfile) fclose (dat.fh); } done: #if defined __SANITIZE_ADDRESS__ || __has_feature(address_sanitizer) { char *asanenv = getenv("ASAN_OPTIONS"); if (!asanenv) force_free = 1; // detect_leaks is enabled by default. see if it's turned off else if (strstr (asanenv, "detect_leaks=0") == NULL) /* not found */ force_free = 1; } #endif // forget about valgrind. really huge DWG's need endlessly here. if ((dwg.header.version && dwg.num_objects < 1000) || force_free #ifdef HAVE_VALGRIND_VALGRIND_H || (RUNNING_ON_VALGRIND) #endif ) { dwg_free (&dwg); } if (error >= DWG_ERR_CRITICAL) { fprintf (stderr, "ERROR 0x%x\n", error); if (error && opts > 2) dwg_errstrings (error); } else { if (opts > 1) { fprintf (stderr, "SUCCESS 0x%x\n", error); if (error && opts > 2) dwg_errstrings (error); } else fprintf (stderr, "SUCCESS\n"); } return error >= DWG_ERR_CRITICAL ? 1 : 0; }