(root)/
libredwg-0.13/
programs/
dwgbmp.c
       1  /*****************************************************************************/
       2  /*  LibreDWG - free implementation of the DWG file format                    */
       3  /*                                                                           */
       4  /*  Copyright (C) 2009, 2018, 2019 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   * dwgbmp.c: get the bmp thumbnail in a dwg file.
      16   * not the WMF.
      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 <stdio.h>
      26  #include <stdlib.h>
      27  #include <string.h>
      28  #include "my_getopt.h"
      29  #ifdef HAVE_VALGRIND_VALGRIND_H
      30  #  include <valgrind/valgrind.h>
      31  #endif
      32  
      33  #include "common.h"
      34  #include <dwg.h>
      35  #include "suffix.inc"
      36  
      37  static int opts = 0;
      38  static int force_free = 0;
      39  
      40  static int
      41  usage (void)
      42  {
      43    printf ("\nUsage: dwgbmp [-v[0-9]] DWGFILE [BMPFILE]\n");
      44    return 1;
      45  }
      46  static int
      47  opt_version (void)
      48  {
      49    printf ("dwgbmp %s\n", PACKAGE_VERSION);
      50    return 0;
      51  }
      52  static int
      53  help (void)
      54  {
      55    printf ("\nUsage: dwgbmp [OPTION]... DWGFILE [thumbnailfile]\n");
      56    printf ("Extract the DWG thumbnail image as BMP, WMF or PNG.\n");
      57    printf ("Default thumbnailfile: DWGFILE with the proper extension.\n"
      58            "\n");
      59  #ifdef HAVE_GETOPT_LONG
      60    printf ("  -v[0-9], --verbose [0-9]  verbosity\n");
      61    printf ("           --help           display this help and exit\n");
      62    printf ("           --version        output version information and exit\n"
      63            "\n");
      64  #else
      65    printf ("  -v[0-9]     verbosity\n");
      66    printf ("  -h          display this help and exit\n");
      67    printf ("  -i          output version information and exit\n"
      68            "\n");
      69  #endif
      70    printf ("GNU LibreDWG online manual: "
      71            "<https://www.gnu.org/software/libredwg/>\n");
      72    return 0;
      73  }
      74  
      75  static void
      76  bmp_free_dwg (Dwg_Data *dwg)
      77  {
      78  #if defined __SANITIZE_ADDRESS__ || __has_feature(address_sanitizer)
      79    {
      80      char *asanenv = getenv ("ASAN_OPTIONS");
      81      if (!asanenv)
      82        force_free = 1;
      83      // detect_leaks is enabled by default. see if it's turned off
      84      else if (strstr (asanenv, "detect_leaks=0") == NULL) /* not found */
      85        force_free = 1;
      86    }
      87  #endif
      88    // really huge DWG's need endlessly here.
      89    if ((dwg->header.version && dwg->num_objects < 1000) || force_free
      90  #ifdef HAVE_VALGRIND_VALGRIND_H
      91        || (RUNNING_ON_VALGRIND)
      92  #endif
      93    )
      94      dwg_free (dwg);
      95  }
      96  
      97  #pragma pack(1)
      98  
      99  static int
     100  get_bmp (char *dwgfile, char *bmpfile, bool must_free)
     101  {
     102    unsigned char *data;
     103    int error;
     104    BITCODE_RL size;
     105    BITCODE_RC type = 0;
     106    size_t retval;
     107    FILE *fh;
     108    Dwg_Data dwg;
     109    struct _BITMAP_HEADER
     110    {
     111      char magic[2];
     112      BITCODE_RL file_size;
     113      BITCODE_RL reserved;
     114      BITCODE_RL offset;
     115    } bmp_h;
     116    const char *typenames[] = { "", "header", "bmp", "wmf", "", "", "png" };
     117    const char *typename;
     118  
     119    memset (&dwg, 0, sizeof (Dwg_Data));
     120    dwg.opts = opts;
     121    /* Read dwg data */
     122    error = dwg_read_file (dwgfile, &dwg);
     123    if (error >= DWG_ERR_CRITICAL)
     124      {
     125        fprintf (stderr, "Unable to read file %s. ERROR 0x%x\n", dwgfile, error);
     126        if (must_free)
     127          free (bmpfile);
     128        bmp_free_dwg (&dwg);
     129        return error;
     130      }
     131  
     132    /* Get DIB bitmap data */
     133    data = dwg_bmp (&dwg, &size, &type);
     134    if (type <= 6)
     135      typename = typenames[type];
     136    else
     137      typename = "";
     138    if (!data)
     139      {
     140        fprintf (stderr, "No thumbnail image in %s\n", dwgfile);
     141        if (must_free)
     142          free (bmpfile);
     143        bmp_free_dwg (&dwg);
     144        return 0;
     145      }
     146    if (!*typename)
     147      {
     148        fprintf (stderr, "Unknown thumbnail type %u in %s\n", type, dwgfile);
     149        bmp_free_dwg (&dwg);
     150        return 0;
     151      }
     152    if (size < 1)
     153      {
     154        fprintf (stderr, "Empty thumbnail data in %s\n", dwgfile);
     155        if (must_free)
     156          free (bmpfile);
     157        bmp_free_dwg (&dwg);
     158        return -3;
     159      }
     160    if (size > dwg.thumbnail.size)
     161      {
     162        fprintf (stderr,
     163                 "Invalid thumbnail data in %s,"
     164                 " size " FORMAT_RL " > %" PRIuSIZE "\n",
     165                 dwgfile, size, dwg.thumbnail.size);
     166        if (must_free)
     167          free (bmpfile);
     168        bmp_free_dwg (&dwg);
     169        return -3;
     170      }
     171    if (type != 2 && *typename)
     172      {
     173        if (must_free)
     174          free (bmpfile);
     175        bmpfile = suffix (dwgfile, typename);
     176      }
     177  
     178    fh = fopen (bmpfile, "w");
     179    if (!fh)
     180      {
     181        fprintf (stderr, "Unable to write thumbnail file '%s'\n", bmpfile);
     182        if (must_free)
     183          free (bmpfile);
     184        bmp_free_dwg (&dwg);
     185        return -4;
     186      }
     187  
     188    if (type == 2)
     189      {
     190        /* Write bmp file header */
     191        bmp_h.magic[0] = 'B';
     192        bmp_h.magic[1] = 'M';
     193        bmp_h.file_size = 14 + size; // file header + DIB data
     194        bmp_h.reserved = 0;
     195        bmp_h.offset
     196            = 14 + 40 + 4 * 256; // file header + DIB header + color table
     197        retval = fwrite (&bmp_h.magic[0], sizeof (char), 2, fh);
     198        if (!retval)
     199          {
     200            bmp_free_dwg (&dwg);
     201            perror ("writing BMP magic");
     202            fclose (fh);
     203            return 1;
     204          }
     205        retval = fwrite (&bmp_h.file_size, 4, 3, fh);
     206        if (!retval)
     207          {
     208            if (must_free)
     209              free (bmpfile);
     210            bmp_free_dwg (&dwg);
     211            perror ("writing BMP file_size");
     212            fclose (fh);
     213            return 1;
     214          }
     215      }
     216  
     217    /* Write data: DIB header + bitmap, resp. the others */
     218    retval = fwrite (data, sizeof (char), size, fh);
     219    fclose (fh);
     220    if (!retval)
     221      {
     222        if (must_free)
     223          free (bmpfile);
     224        bmp_free_dwg (&dwg);
     225        perror ("writing thumbnail data");
     226        return 1;
     227      }
     228  
     229    printf ("Success. Written thumbnail image to '%s'\n", bmpfile);
     230    bmp_free_dwg (&dwg);
     231    if (must_free)
     232      free (bmpfile);
     233    return 0;
     234  }
     235  
     236  int
     237  main (int argc, char *argv[])
     238  {
     239    int i = 1, error;
     240    char *dwgfile, *bmpfile;
     241    int c;
     242    bool must_free;
     243  #ifdef HAVE_GETOPT_LONG
     244    int option_index = 0;
     245    static struct option long_options[]
     246        = { { "verbose", 1, &opts, 1 }, // optional
     247            { "help", 0, 0, 0 },
     248            { "version", 0, 0, 0 },
     249            { "force-free", 0, 0, 0 },
     250            { NULL, 0, NULL, 0 } };
     251  #endif
     252  
     253    if (argc < 2)
     254      return usage ();
     255  
     256    while
     257  #ifdef HAVE_GETOPT_LONG
     258        ((c = getopt_long (argc, argv, ":v::h", long_options, &option_index))
     259         != -1)
     260  #else
     261        ((c = getopt (argc, argv, ":v::hi")) != -1)
     262  #endif
     263      {
     264        if (c == -1)
     265          break;
     266        switch (c)
     267          {
     268          case ':': // missing arg
     269            if (optarg && !strcmp (optarg, "v"))
     270              {
     271                opts = 1;
     272                break;
     273              }
     274            fprintf (stderr, "%s: option '-%c' requires an argument\n", argv[0],
     275                     optopt);
     276            break;
     277  #ifdef HAVE_GETOPT_LONG
     278          case 0:
     279            /* This option sets a flag */
     280            if (!strcmp (long_options[option_index].name, "verbose"))
     281              {
     282                if (opts < 0 || opts > 9)
     283                  return usage ();
     284  #  if defined(USE_TRACING) && defined(HAVE_SETENV)
     285                {
     286                  char v[2];
     287                  *v = opts + '0';
     288                  *(v + 1) = 0;
     289                  setenv ("LIBREDWG_TRACE", v, 1);
     290                }
     291  #  endif
     292                break;
     293              }
     294            if (!strcmp (long_options[option_index].name, "version"))
     295              return opt_version ();
     296            if (!strcmp (long_options[option_index].name, "help"))
     297              return help ();
     298            if (!strcmp (long_options[option_index].name, "force-free"))
     299              force_free = 1;
     300            break;
     301  #else
     302          case 'i':
     303            return opt_version ();
     304  #endif
     305          case 'v': // support -v3 and -v
     306            i = (optind > 0 && optind < argc) ? optind - 1 : 1;
     307            if (!memcmp (argv[i], "-v", 2))
     308              {
     309                opts = argv[i][2] ? argv[i][2] - '0' : 1;
     310              }
     311            if (opts < 0 || opts > 9)
     312              return usage ();
     313  #if defined(USE_TRACING) && defined(HAVE_SETENV)
     314            {
     315              char v[2];
     316              *v = opts + '0';
     317              *(v + 1) = 0;
     318              setenv ("LIBREDWG_TRACE", v, 1);
     319            }
     320  #endif
     321            break;
     322          case 'h':
     323            return help ();
     324          case '?':
     325            fprintf (stderr, "%s: invalid option '-%c' ignored\n", argv[0],
     326                     optopt);
     327            break;
     328          default:
     329            return usage ();
     330          }
     331      }
     332    i = optind;
     333    if (i >= argc)
     334      return usage ();
     335  
     336    dwgfile = argv[i];
     337    if (i == argc - 2)
     338      bmpfile = argv[i + 1];
     339    else
     340      bmpfile = suffix (dwgfile, "bmp");
     341    must_free = i != argc - 2;
     342    return get_bmp (dwgfile, bmpfile, must_free);
     343  }