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