1 /*****************************************************************************/
2 /*  LibreDWG - free implementation of the DWG file format                    */
3 /*                                                                           */
4 /*  Copyright (C) 2018-2019 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  * dwglayers.c: print list of layers in a DWG
15  *
16  * written by Reini Urban
17  */
18 
19 #include "../src/config.h"
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <assert.h>
24 #include <getopt.h>
25 #ifdef HAVE_VALGRIND_VALGRIND_H
26 #  include <valgrind/valgrind.h>
27 #endif
28 
29 #include <dwg.h>
30 #include "common.h"
31 #include "bits.h"
32 #include "logging.h"
33 
34 static int
usage(void)35 usage (void)
36 {
37   printf ("\nUsage: dwglayers [-f|--flags] [--on] <input_file.dwg>\n");
38   return 1;
39 }
40 static int
opt_version(void)41 opt_version (void)
42 {
43   printf ("dwglayers %s\n", PACKAGE_VERSION);
44   return 0;
45 }
46 static int
help(void)47 help (void)
48 {
49   printf ("\nUsage: dwglayers [OPTION]... DWGFILE\n");
50   printf ("Print list of layers.\n"
51           "\n");
52 #ifdef HAVE_GETOPT_LONG
53   printf ("  -x, --extnames            prints EXTNAMES (r13-r14 only)\n"
54           "                i.e. space instead of _\n");
55   printf ("  -f, --flags               prints also flags:\n"
56           "                3 chars for: f for frozen, + or - for ON or OFF, l "
57           "for locked\n");
58   printf ("  -o, --on                  prints only ON layers\n");
59   printf ("  -h, --help                display this help and exit\n");
60   printf ("      --version             output version information and exit\n"
61           "\n");
62 #else
63   printf ("  -x            prints EXTNAMES (r13-r14 only)\n"
64           "                i.e. space instead of _\n");
65   printf ("  -f            prints also flags:\n"
66           "                3 chars for: f for frozen, + or - for ON or OFF, l "
67           "for locked\n");
68   printf ("  -o            prints only ON layers\n");
69   printf ("  -h            display this help and exit\n");
70   printf ("  -i            output version information and exit\n"
71           "\n");
72 #endif
73   printf ("GNU LibreDWG online manual: "
74           "<https://www.gnu.org/software/libredwg/>\n");
75   return 0;
76 }
77 
78 int
main(int argc,char * argv[])79 main (int argc, char *argv[])
80 {
81   int error;
82   long i = 1;
83   int flags = 0, on = 0, extnames = 0;
84   char *filename_in;
85   Dwg_Data dwg;
86   Dwg_Object *obj;
87   Dwg_Object_LAYER *layer;
88   Dwg_Object_LAYER_CONTROL *_ctrl;
89   int c;
90 #ifdef HAVE_GETOPT_LONG
91   int option_index = 0;
92   static struct option long_options[] = { { "flags", 0, 0, 'f' },
93                                           { "extnames", 0, 0, 'x' },
94                                           { "on", 0, 0, 'o' },
95                                           { "help", 0, 0, 0 },
96                                           { "version", 0, 0, 0 },
97                                           { NULL, 0, NULL, 0 } };
98 #endif
99 
100   while
101 #ifdef HAVE_GETOPT_LONG
102       ((c = getopt_long (argc, argv, "xfoh", long_options, &option_index))
103        != -1)
104 #else
105       ((c = getopt (argc, argv, "xfohi")) != -1)
106 #endif
107     {
108       if (c == -1)
109         break;
110       switch (c)
111         {
112 #ifdef HAVE_GETOPT_LONG
113         case 0:
114           if (!strcmp (long_options[option_index].name, "version"))
115             return opt_version ();
116           if (!strcmp (long_options[option_index].name, "help"))
117             return help ();
118           break;
119 #else
120         case 'i':
121           return opt_version ();
122 #endif
123         case 'x':
124           extnames = 1;
125           break;
126         case 'f':
127           flags = 1;
128           break;
129         case 'o':
130           on = 1;
131           break;
132         case 'h':
133           return help ();
134         case '?':
135           fprintf (stderr, "%s: invalid option '-%c' ignored\n", argv[0],
136                    optopt);
137           break;
138         default:
139           return usage ();
140         }
141     }
142   i = optind;
143   if (i >= argc)
144     return usage ();
145 
146   filename_in = argv[i];
147   memset (&dwg, 0, sizeof (Dwg_Data));
148   error = dwg_read_file (filename_in, &dwg);
149   if (error >= DWG_ERR_CRITICAL)
150     {
151       fprintf (stderr, "READ ERROR %s: 0x%x\n", filename_in, error);
152       goto done;
153     }
154 
155   obj = dwg_get_first_object (&dwg, DWG_TYPE_LAYER_CONTROL);
156   if (!obj)
157     {
158       fprintf (stderr, "No layers found\n");
159       goto done;
160     }
161   _ctrl = obj->tio.object->tio.LAYER_CONTROL;
162   for (i = 0; i < _ctrl->num_entries; i++)
163     {
164       char *name;
165       assert (_ctrl->entries);
166       assert (_ctrl->entries[i]);
167       obj = _ctrl->entries[i]->obj;
168       if (!obj || obj->type != DWG_TYPE_LAYER) // can be DICTIONARY also
169         continue;
170       assert (_ctrl->entries[i]->obj->tio.object);
171       layer = _ctrl->entries[i]->obj->tio.object->tio.LAYER;
172       if (on && (!layer->on || layer->frozen))
173         continue;
174       if (flags)
175         printf ("%s%s%s\t", layer->frozen ? "f" : " ", layer->on ? "+" : "-",
176                 layer->locked ? "l" : " ");
177       if (extnames && dwg.header.from_version >= R_13 && dwg.header.from_version < R_2000)
178         {
179           if (!(name = dwg_find_table_extname (&dwg, obj)))
180             name = layer->name;
181         }
182       else
183         name = layer->name;
184       if (!name)
185         {
186           LOG_ERROR ("Invalid layer %lX ignored, empty name",
187                      _ctrl->entries[i]->obj->handle.value)
188         }
189       else
190         {
191           // since r2007 unicode, converted to utf-8
192           if (dwg.header.from_version >= R_2007)
193             {
194               char *utf8 = bit_convert_TU ((BITCODE_TU)name);
195               printf ("%s\n", utf8);
196               free (utf8);
197             }
198           else
199             printf ("%s\n", name);
200         }
201       fflush (stdout);
202     }
203 
204  done:
205   // forget about valgrind. really huge DWG's need endlessly here.
206   if ((dwg.header.version && dwg.num_objects < 1000)
207 #if defined __SANITIZE_ADDRESS__ || __has_feature(address_sanitizer)
208       || 1
209 #endif
210 #ifdef HAVE_VALGRIND_VALGRIND_H
211       || (RUNNING_ON_VALGRIND)
212 #endif
213   )
214     dwg_free (&dwg);
215   return error >= DWG_ERR_CRITICAL ? 1 : 0;
216 }
217