Line | Count | Source |
1 | | /*****************************************************************************/ |
2 | | /* LibreDWG - free implementation of the DWG file format */ |
3 | | /* */ |
4 | | /* Copyright (C) 2009-2010,2018-2025 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 | | * dwg.c: main functions and API |
15 | | * written by Felipe Castro |
16 | | * modified by Felipe Corrêa da Silva Sances |
17 | | * modified by Rodrigo Rodrigues da Silva |
18 | | * modified by Anderson Pierre Cardoso |
19 | | * modified by Reini Urban |
20 | | */ |
21 | | |
22 | | #include "config.h" |
23 | | #include <stdio.h> |
24 | | #include <stdlib.h> |
25 | | #include <string.h> |
26 | | #include <stdbool.h> |
27 | | #include <assert.h> |
28 | | #include <math.h> |
29 | | #include "../programs/my_stat.h" |
30 | | // strings.h or string.h |
31 | | #ifdef AX_STRCASECMP_HEADER |
32 | | # include AX_STRCASECMP_HEADER |
33 | | #endif |
34 | | #ifdef HAVE_LIBGEN_H |
35 | | # include <libgen.h> // basename |
36 | | #else |
37 | | char *basename (char *); |
38 | | #endif |
39 | | |
40 | | #include "bits.h" |
41 | | #include "common.h" |
42 | | #include "decode.h" |
43 | | #include "dwg.h" |
44 | | #include "hash.h" |
45 | | #include "dynapi.h" |
46 | | #include "classes.h" |
47 | | #ifdef USE_WRITE |
48 | | # include "encode.h" |
49 | | #endif |
50 | | #include "free.h" |
51 | | |
52 | | #ifdef USE_TRACING |
53 | | /* This flag means we have checked the environment variable |
54 | | LIBREDWG_TRACE and set `loglevel' appropriately. */ |
55 | | static bool env_var_checked_p; |
56 | | #endif /* USE_TRACING */ |
57 | | #define DWG_LOGLEVEL loglevel |
58 | | #include "logging.h" |
59 | | |
60 | | /*------------------------------------------------------------------------------ |
61 | | * Imports bypassing its headers. |
62 | | * We dont want to import in_dxf.h as it is redefining FORMAT_BD. |
63 | | */ |
64 | | #ifndef DISABLE_DXF |
65 | | EXPORT int dwg_read_dxf (Bit_Chain *restrict dat, Dwg_Data *restrict dwg); |
66 | | EXPORT int dwg_read_dxfb (Bit_Chain *restrict dat, Dwg_Data *restrict dwg); |
67 | | #endif |
68 | | |
69 | | /*------------------------------------------------------------------------------ |
70 | | * Internal functions |
71 | | */ |
72 | | // used in in_dxf.c, encode.c |
73 | | BITCODE_H |
74 | | dwg_find_tablehandle_silent (Dwg_Data *restrict dwg, const char *restrict name, |
75 | | const char *restrict table); |
76 | | BITCODE_RLL dwg_new_handseed (Dwg_Data *restrict dwg); |
77 | | // used in encode.c |
78 | | void dwg_set_handle_size (Dwg_Handle *restrict hdl); |
79 | | void dwg_downgrade_MLINESTYLE (Dwg_Object_MLINESTYLE *o); |
80 | | void dwg_upgrade_MLINESTYLE (Dwg_Data *restrict dwg, |
81 | | Dwg_Object_MLINESTYLE *restrict o); |
82 | | |
83 | | void ordered_ref_add (Dwg_Data *dwg, Dwg_Object_Ref *ref); |
84 | | const Dwg_Object_Ref *ordered_ref_find (Dwg_Data *dwg, const BITCODE_RC code, |
85 | | const unsigned long absref); |
86 | | static void dwg_init_handseed (Dwg_Data *dwg); |
87 | | |
88 | | /*------------------------------------------------------------------------------ |
89 | | * Public functions |
90 | | */ |
91 | | |
92 | | EXPORT int |
93 | | dat_read_file (Bit_Chain *restrict dat, FILE *restrict fp, |
94 | | const char *restrict filename) |
95 | 0 | { |
96 | 0 | size_t size; |
97 | 0 | if (!dat->size && fp) |
98 | 0 | { |
99 | 0 | struct_stat_t attrib; |
100 | 0 | int fd = fileno (fp); |
101 | 0 | if (fd >= 0 && !fstat (fd, &attrib)) |
102 | 0 | dat->size = attrib.st_size; |
103 | 0 | } |
104 | 0 | dat->chain = (unsigned char *)calloc (1, dat->size + 1); |
105 | 0 | if (!dat->chain) |
106 | 0 | { |
107 | 0 | loglevel = dat->opts & DWG_OPTS_LOGLEVEL; |
108 | 0 | LOG_ERROR ("Not enough memory"); |
109 | 0 | fclose (fp); |
110 | 0 | dat->fh = NULL; |
111 | 0 | return DWG_ERR_OUTOFMEM; |
112 | 0 | } |
113 | | |
114 | 0 | size = fread (dat->chain, sizeof (char), dat->size, fp); |
115 | 0 | if (size != dat->size) |
116 | 0 | { |
117 | 0 | loglevel = dat->opts & DWG_OPTS_LOGLEVEL; |
118 | 0 | LOG_ERROR ("Could not read file (%" PRIuSIZE " out of %" PRIuSIZE |
119 | 0 | "): %s", |
120 | 0 | size, dat->size, filename); |
121 | 0 | fclose (fp); |
122 | 0 | free (dat->chain); |
123 | 0 | dat->chain = NULL; |
124 | 0 | dat->fh = NULL; |
125 | 0 | dat->size = 0; |
126 | 0 | return DWG_ERR_IOERROR; |
127 | 0 | } |
128 | | // ensure zero-termination for strstr, strtol, ... |
129 | 0 | dat->chain[dat->size] = '\0'; |
130 | 0 | return 0; |
131 | 0 | } |
132 | | |
133 | | // fast bulk-read when we known the size |
134 | | EXPORT int |
135 | | dat_read_size (Bit_Chain *restrict dat) |
136 | 0 | { |
137 | 0 | if (!dat->chain) |
138 | 0 | dat->chain = (unsigned char *)calloc (1, dat->size + 2); |
139 | 0 | else |
140 | 0 | dat->chain = (unsigned char *)realloc (dat->chain, dat->size + 2); |
141 | 0 | if (!dat->chain) |
142 | 0 | { |
143 | 0 | loglevel = dat->opts & DWG_OPTS_LOGLEVEL; |
144 | 0 | LOG_ERROR ("Not enough memory"); |
145 | 0 | fclose (dat->fh); |
146 | 0 | return DWG_ERR_OUTOFMEM; |
147 | 0 | } |
148 | 0 | if (fread (dat->chain, 1, dat->size, dat->fh) != dat->size) |
149 | 0 | { |
150 | 0 | fclose (dat->fh); |
151 | 0 | free (dat->chain); |
152 | 0 | dat->chain = NULL; |
153 | 0 | return DWG_ERR_IOERROR; |
154 | 0 | } |
155 | 0 | dat->chain[dat->size] = '\0'; // ensure zero-termination |
156 | 0 | return 0; |
157 | 0 | } |
158 | | |
159 | | EXPORT int |
160 | | dat_read_stream (Bit_Chain *restrict dat, FILE *restrict fp) |
161 | 0 | { |
162 | 0 | size_t size = 0; |
163 | 0 | loglevel = dat->opts & DWG_OPTS_LOGLEVEL; |
164 | |
|
165 | 0 | do |
166 | 0 | { |
167 | 0 | if (dat->chain) |
168 | 0 | dat->chain = (unsigned char *)realloc (dat->chain, dat->size + 4096); |
169 | 0 | else |
170 | 0 | { |
171 | 0 | dat->chain = (unsigned char *)calloc (1, 4096); |
172 | 0 | dat->size = 0; |
173 | 0 | } |
174 | 0 | if (!dat->chain) |
175 | 0 | { |
176 | 0 | LOG_ERROR ("Not enough memory.\n"); |
177 | 0 | fclose (fp); |
178 | 0 | dat->fh = NULL; |
179 | 0 | return DWG_ERR_OUTOFMEM; |
180 | 0 | } |
181 | 0 | size = fread (&dat->chain[dat->size], sizeof (char), 4096, fp); |
182 | 0 | dat->size += size; |
183 | 0 | } |
184 | 0 | while (size == 4096); |
185 | | |
186 | 0 | if (dat->size == 0) |
187 | 0 | { |
188 | 0 | LOG_ERROR ("Could not read from stream (%" PRIuSIZE " out of %" PRIuSIZE |
189 | 0 | ")\n", |
190 | 0 | size, dat->size); |
191 | 0 | fclose (fp); |
192 | 0 | free (dat->chain); |
193 | 0 | dat->fh = NULL; |
194 | 0 | dat->chain = NULL; |
195 | 0 | return DWG_ERR_IOERROR; |
196 | 0 | } |
197 | | |
198 | | // clear the slack and realloc |
199 | 0 | size = dat->size & 0xfff; |
200 | 0 | if (size) |
201 | 0 | memset (&dat->chain[dat->size], 0, 0xfff - size); |
202 | 0 | dat->chain = (unsigned char *)realloc (dat->chain, dat->size + 1); |
203 | | // ensure NULL termination, for sscanf, strtol and friends. |
204 | 0 | dat->chain[dat->size] = '\0'; |
205 | 0 | return 0; |
206 | 0 | } |
207 | | |
208 | | static void |
209 | | dwg_fixup_viewport_ids (Dwg_Data *restrict dwg) |
210 | 0 | { |
211 | 0 | BITCODE_BL i; |
212 | 0 | BITCODE_RS last_id = 0; |
213 | 0 | for (i = 0; i < dwg->num_objects; i++) |
214 | 0 | { |
215 | 0 | Dwg_Object *obj = &dwg->object[i]; |
216 | 0 | if (obj->supertype == DWG_SUPERTYPE_ENTITY |
217 | 0 | && obj->fixedtype == DWG_TYPE_VIEWPORT) |
218 | 0 | { |
219 | 0 | Dwg_Entity_VIEWPORT *_obj = obj->tio.entity->tio.VIEWPORT; |
220 | 0 | if (obj->tio.entity->entmode == 0) |
221 | 0 | { |
222 | 0 | _obj->on_off = 0; |
223 | 0 | _obj->id = 0; |
224 | 0 | last_id = 0; |
225 | 0 | } |
226 | 0 | else |
227 | 0 | { |
228 | 0 | _obj->on_off = 1; |
229 | 0 | last_id++; |
230 | 0 | _obj->id = last_id; |
231 | 0 | } |
232 | 0 | } |
233 | 0 | } |
234 | 0 | } |
235 | | |
236 | | /** dwg_read_file |
237 | | * returns 0 on success. |
238 | | * |
239 | | * everything in dwg is cleared |
240 | | * and then either read from dat, or set to a default. |
241 | | */ |
242 | | EXPORT int |
243 | | dwg_read_file (const char *restrict filename, Dwg_Data *restrict dwg) |
244 | 0 | { |
245 | 0 | FILE *fp; |
246 | 0 | struct_stat_t attrib; |
247 | 0 | Bit_Chain bit_chain = { 0 }; |
248 | 0 | int error; |
249 | |
|
250 | 0 | loglevel = dwg->opts & DWG_OPTS_LOGLEVEL; |
251 | 0 | memset (dwg, 0, sizeof (Dwg_Data)); |
252 | 0 | dwg->opts = loglevel; |
253 | |
|
254 | 0 | if (strEQc (filename, "-")) |
255 | 0 | { |
256 | 0 | fp = stdin; |
257 | 0 | } |
258 | 0 | else |
259 | 0 | { |
260 | 0 | if (stat (filename, &attrib)) |
261 | 0 | { |
262 | 0 | LOG_ERROR ("File not found: %s\n", filename); |
263 | 0 | return DWG_ERR_IOERROR; |
264 | 0 | } |
265 | 0 | if (!(S_ISREG (attrib.st_mode) |
266 | 0 | #ifndef _WIN32 |
267 | 0 | || S_ISLNK (attrib.st_mode) |
268 | 0 | #endif |
269 | 0 | )) |
270 | 0 | { |
271 | 0 | LOG_ERROR ("Illegal input file %s\n", filename); |
272 | 0 | return DWG_ERR_IOERROR; |
273 | 0 | } |
274 | 0 | fp = fopen (filename, "rb"); |
275 | 0 | } |
276 | 0 | if (!fp) |
277 | 0 | { |
278 | 0 | LOG_ERROR ("Could not open file: %s\n", filename); |
279 | 0 | return DWG_ERR_IOERROR; |
280 | 0 | } |
281 | | |
282 | | /* Load whole file into memory, even if streamed (for now) |
283 | | */ |
284 | 0 | memset (&bit_chain, 0, sizeof (Bit_Chain)); |
285 | 0 | if (fp == stdin) |
286 | 0 | { |
287 | 0 | error = dat_read_stream (&bit_chain, fp); |
288 | 0 | if (error >= DWG_ERR_CRITICAL) |
289 | 0 | return error; |
290 | 0 | } |
291 | 0 | else |
292 | 0 | { |
293 | 0 | #ifdef HAVE_SYS_STAT_H |
294 | 0 | bit_chain.size = attrib.st_size; |
295 | 0 | #endif |
296 | 0 | error = dat_read_file (&bit_chain, fp, filename); |
297 | 0 | if (error >= DWG_ERR_CRITICAL) |
298 | 0 | return error; |
299 | 0 | } |
300 | 0 | fclose (fp); |
301 | |
|
302 | 0 | if (bit_chain.size < 6) |
303 | 0 | { |
304 | 0 | LOG_ERROR ("File %s too small, %zu byte", filename, bit_chain.size); |
305 | 0 | free (bit_chain.chain); |
306 | 0 | bit_chain.chain = NULL; |
307 | 0 | return DWG_ERR_INVALIDDWG; |
308 | 0 | } |
309 | | |
310 | | /* Decode the dwg structure */ |
311 | 0 | error = dwg_decode (&bit_chain, dwg); |
312 | 0 | if (error >= DWG_ERR_CRITICAL) |
313 | 0 | { |
314 | 0 | LOG_ERROR ("Failed to decode file: %s 0x%x", filename, error); |
315 | 0 | free (bit_chain.chain); |
316 | 0 | bit_chain.chain = NULL; |
317 | 0 | bit_chain.size = 0; |
318 | 0 | return error; |
319 | 0 | } |
320 | | |
321 | | // TODO: does dwg hold any char* pointers to the bit_chain or are they all |
322 | | // copied? |
323 | 0 | free (bit_chain.chain); |
324 | 0 | bit_chain.chain = NULL; |
325 | 0 | bit_chain.size = 0; |
326 | |
|
327 | 0 | dwg_fixup_viewport_ids (dwg); |
328 | 0 | return error; |
329 | 0 | } |
330 | | |
331 | | #if !defined(DISABLE_DXF) && defined(USE_WRITE) |
332 | | /** dxf_read_file |
333 | | * returns 0 on success. |
334 | | * |
335 | | * detects binary or ascii file. |
336 | | * everything in dwg is cleared |
337 | | * and then either read from dat, or set to a default. |
338 | | */ |
339 | | EXPORT int |
340 | | dxf_read_file (const char *restrict filename, Dwg_Data *restrict dwg) |
341 | 0 | { |
342 | 0 | int error; |
343 | 0 | FILE *fp; |
344 | 0 | struct_stat_t attrib; |
345 | 0 | size_t size; |
346 | 0 | Bit_Chain dat = { 0 }; |
347 | 0 | Dwg_Version_Type version; |
348 | |
|
349 | 0 | loglevel = dwg->opts & DWG_OPTS_LOGLEVEL; |
350 | |
|
351 | 0 | if (!filename || stat (filename, &attrib)) |
352 | 0 | { |
353 | 0 | LOG_ERROR ("File not found: %s", filename ? filename : "(null)"); |
354 | 0 | return DWG_ERR_IOERROR; |
355 | 0 | } |
356 | 0 | if (!(S_ISREG (attrib.st_mode) |
357 | 0 | # ifndef _WIN32 |
358 | 0 | || S_ISLNK (attrib.st_mode) |
359 | 0 | # endif |
360 | 0 | )) |
361 | 0 | { |
362 | 0 | LOG_ERROR ("%s", filename); |
363 | 0 | return DWG_ERR_IOERROR; |
364 | 0 | } |
365 | 0 | fp = fopen (filename, "rb"); |
366 | 0 | if (!fp) |
367 | 0 | { |
368 | 0 | LOG_ERROR ("Could not open file: %s", filename); |
369 | 0 | return DWG_ERR_IOERROR; |
370 | 0 | } |
371 | | |
372 | | /* Load whole file into memory |
373 | | */ |
374 | 0 | version = dwg->header.version; |
375 | 0 | memset (dwg, 0, sizeof (Dwg_Data)); |
376 | 0 | dwg->opts = loglevel | DWG_OPTS_INDXF; |
377 | 0 | dwg->header.version = version; |
378 | |
|
379 | 0 | memset (&dat, 0, sizeof (Bit_Chain)); |
380 | 0 | # ifdef HAVE_SYS_STAT_H |
381 | 0 | dat.size = attrib.st_size; |
382 | 0 | # endif |
383 | 0 | dat.chain = (unsigned char *)calloc (1, dat.size + 2); |
384 | 0 | if (!dat.chain) |
385 | 0 | { |
386 | 0 | LOG_ERROR ("Not enough memory"); |
387 | 0 | fclose (fp); |
388 | 0 | return DWG_ERR_OUTOFMEM; |
389 | 0 | } |
390 | 0 | dat.byte = 0; |
391 | 0 | dat.bit = 0; |
392 | 0 | dat.from_version = dwg->header.from_version; |
393 | 0 | dat.version = dwg->header.version; |
394 | 0 | dat.opts = dwg->opts; |
395 | |
|
396 | 0 | size = fread (dat.chain, sizeof (char), dat.size, fp); |
397 | 0 | fclose (fp); |
398 | 0 | if (size != dat.size) |
399 | 0 | { |
400 | 0 | LOG_ERROR ("Could not read the entire file (%" PRIuSIZE |
401 | 0 | " out of %" PRIuSIZE "): %s", |
402 | 0 | size, dat.size, filename); |
403 | 0 | free (dat.chain); |
404 | 0 | dat.chain = NULL; |
405 | 0 | dat.size = 0; |
406 | 0 | return DWG_ERR_IOERROR; |
407 | 0 | } |
408 | | /* |
409 | | 0 |
410 | | SECTION |
411 | | 2 |
412 | | ENTITIES |
413 | | 0 |
414 | | ENDSEC |
415 | | */ |
416 | 0 | if (size < 31) |
417 | 0 | { |
418 | 0 | LOG_ERROR ("File %s too small, %" PRIuSIZE " byte.", filename, size); |
419 | 0 | free (dat.chain); |
420 | 0 | dat.chain = NULL; |
421 | 0 | dat.size = 0; |
422 | 0 | return DWG_ERR_IOERROR; |
423 | 0 | } |
424 | | /* properly end the buffer for strtol()/... readers. The NUL has to go after |
425 | | the newline we just appended, not on top of it: the chain is calloc'd with |
426 | | two spare bytes for exactly this. Overwriting it left the buffer ending in |
427 | | "...\n0\0" for a DXF without a trailing newline, and dxf_read_string |
428 | | bails out when it finds no '\n' in what is left -- so the file's last |
429 | | group pair was lost and the whole import failed. */ |
430 | 0 | if (dat.chain[size - 1] != '\n') |
431 | 0 | { |
432 | 0 | dat.chain[size++] = '\n'; |
433 | 0 | dat.size++; |
434 | 0 | } |
435 | 0 | dat.chain[size] = '\0'; |
436 | | |
437 | | /* Fail on DWG */ |
438 | 0 | if (!memcmp (dat.chain, "AC10", 4) || !memcmp (dat.chain, "AC1.", 4) |
439 | 0 | || !memcmp (dat.chain, "AC2.10", 4) || !memcmp (dat.chain, "MC0.0", 4)) |
440 | 0 | { |
441 | 0 | LOG_ERROR ("This is a DWG, not a DXF file: %s", filename); |
442 | 0 | free (dat.chain); |
443 | 0 | dat.chain = NULL; |
444 | 0 | dat.size = 0; |
445 | 0 | return DWG_ERR_INVALIDDWG; |
446 | 0 | } |
447 | | /* See if binary or ascii */ |
448 | 0 | if (!memcmp (dat.chain, "AutoCAD Binary DXF", |
449 | 0 | sizeof ("AutoCAD Binary DXF") - 1)) |
450 | 0 | { |
451 | 0 | dat.byte = 22; |
452 | 0 | error = dwg_read_dxfb (&dat, dwg); |
453 | 0 | } |
454 | 0 | else |
455 | 0 | error = dwg_read_dxf (&dat, dwg); |
456 | |
|
457 | 0 | dwg->opts |= (DWG_OPTS_INDXF | loglevel); |
458 | 0 | if (error >= DWG_ERR_CRITICAL) |
459 | 0 | { |
460 | 0 | LOG_ERROR ("Failed to decode DXF file: %s", filename); |
461 | 0 | free (dat.chain); |
462 | 0 | dat.chain = NULL; |
463 | 0 | dat.size = 0; |
464 | 0 | return error; |
465 | 0 | } |
466 | | |
467 | | // TODO: does dwg hold any char* pointers to the dat or are they all copied? |
468 | 0 | free (dat.chain); |
469 | 0 | dat.chain = NULL; |
470 | 0 | dat.size = 0; |
471 | |
|
472 | 0 | return 0; |
473 | 0 | } |
474 | | #endif /* DISABLE_DXF */ |
475 | | |
476 | | #ifdef USE_WRITE |
477 | | /** Encode the DWG struct into dat (in memory). |
478 | | * Needs 2x DWG heap, dwg + dat. |
479 | | */ |
480 | | EXPORT int |
481 | | dwg_write_file (const char *restrict filename, const Dwg_Data *restrict dwg) |
482 | 0 | { |
483 | 0 | FILE *fh; |
484 | 0 | struct_stat_t attrib; |
485 | 0 | Bit_Chain dat = { 0 }; |
486 | 0 | int error; |
487 | |
|
488 | 0 | loglevel = dwg->opts & DWG_OPTS_LOGLEVEL; |
489 | 0 | assert (filename); |
490 | 0 | assert (dwg); |
491 | 0 | dat.opts = dwg->opts; |
492 | 0 | dat.version = (Dwg_Version_Type)dwg->header.version; |
493 | 0 | dat.from_version = (Dwg_Version_Type)dwg->header.from_version; |
494 | 0 | dat.codepage = dwg->header.codepage; |
495 | | |
496 | | // json HACK. no wide chars from JSON, because we just encode to R_2000 |
497 | 0 | if (dwg->opts & (DWG_OPTS_INJSON | DWG_OPTS_INDXF)) |
498 | 0 | dat.from_version = dat.version; |
499 | |
|
500 | 0 | if (dwg->header.version <= R_2000 && dwg->header.from_version > R_2000) |
501 | 0 | dwg_fixup_BLOCKS_entities ((Dwg_Data *)dwg); |
502 | |
|
503 | 0 | dat.size = 0; |
504 | 0 | error = dwg_encode ((Dwg_Data *)dwg, &dat); |
505 | 0 | if (error >= DWG_ERR_CRITICAL) |
506 | 0 | { |
507 | 0 | LOG_ERROR ("Failed to encode Dwg_Data"); |
508 | | /* In development we want to look at the corpses */ |
509 | 0 | # ifdef IS_RELEASE |
510 | 0 | if (dat.size > 0) |
511 | 0 | { |
512 | 0 | free (dat.chain); |
513 | 0 | dat.chain = NULL; |
514 | 0 | dat.size = 0; |
515 | 0 | } |
516 | 0 | return error; |
517 | 0 | # endif |
518 | 0 | } |
519 | | |
520 | | // try opening the output file in write mode |
521 | 0 | if (!stat (filename, &attrib) |
522 | | # ifdef _WIN32 |
523 | | && strNE (filename, "NUL") && strNE (filename, "CON") |
524 | | # else |
525 | 0 | && strNE (filename, "/dev/null") && strNE (filename, "/dev/stdout") |
526 | 0 | # endif |
527 | 0 | ) |
528 | 0 | { |
529 | 0 | LOG_ERROR ("The file already exists. We won't overwrite it."); |
530 | 0 | return error | DWG_ERR_IOERROR; |
531 | 0 | } |
532 | 0 | fh = fopen (filename, "wb"); |
533 | 0 | if (!fh || !dat.chain) |
534 | 0 | { |
535 | 0 | LOG_ERROR ("Failed to create the file: %s", filename); |
536 | 0 | return error | DWG_ERR_IOERROR; |
537 | 0 | } |
538 | | |
539 | | // Write the data into the file |
540 | 0 | if (fwrite (dat.chain, sizeof (char), dat.size, fh) != dat.size) |
541 | 0 | { |
542 | 0 | LOG_ERROR ("Failed to write data into the file: %s", filename); |
543 | 0 | fclose (fh); |
544 | 0 | free (dat.chain); |
545 | 0 | dat.chain = NULL; |
546 | 0 | dat.size = 0; |
547 | 0 | return error | DWG_ERR_IOERROR; |
548 | 0 | } |
549 | 0 | fclose (fh); |
550 | |
|
551 | 0 | if (dat.size > 0) |
552 | 0 | { |
553 | 0 | free (dat.chain); |
554 | 0 | dat.chain = NULL; |
555 | 0 | dat.size = 0; |
556 | 0 | } |
557 | |
|
558 | 0 | return error; |
559 | 0 | } |
560 | | #endif /* USE_WRITE */ |
561 | | |
562 | | /* THUMBNAIL IMAGE DATA (R13C3+). |
563 | | Supports multiple preview pictures. |
564 | | Currently 3 types: BMP, WMF and PNG. returns the size of the image. |
565 | | */ |
566 | | EXPORT unsigned char * |
567 | | dwg_bmp (const Dwg_Data *restrict dwg, BITCODE_RL *restrict size, |
568 | | BITCODE_RC *restrict typep) |
569 | 1.85k | { |
570 | 1.85k | BITCODE_RC i, num_headers, type = 0; |
571 | 1.85k | int found; |
572 | 1.85k | BITCODE_RL header_size, address = 0, osize; |
573 | 1.85k | Bit_Chain dat = { 0 }; |
574 | | |
575 | 1.85k | loglevel = dwg->opts & DWG_OPTS_LOGLEVEL; |
576 | 1.85k | *size = 0; |
577 | 1.85k | assert (dwg); |
578 | | // copy the chain data. bit_* needs a full chain with opts and version |
579 | 1.85k | dat = *(Bit_Chain *)&dwg->thumbnail; |
580 | 1.85k | if (!dat.size || !dat.chain) |
581 | 1.85k | { |
582 | 1.85k | LOG_INFO ("no THUMBNAIL Image Data"); |
583 | 1.85k | return NULL; |
584 | 1.85k | } |
585 | | // dat.byte = 0; sentinel at 16 |
586 | 0 | dat.bit = 0; |
587 | 0 | dat.opts = dwg->opts; |
588 | 0 | dat.from_version = dwg->header.from_version; |
589 | 0 | dat.version = dwg->header.version; |
590 | 0 | dat.fh = NULL; |
591 | |
|
592 | | #ifdef USE_TRACING |
593 | | /* Before starting, set the logging level, but only do so once. */ |
594 | | if (!env_var_checked_p) |
595 | | { |
596 | | char *probe = getenv ("LIBREDWG_TRACE"); |
597 | | if (probe) |
598 | | loglevel = atoi (probe); |
599 | | env_var_checked_p = true; |
600 | | } |
601 | | #endif /* USE_TRACING */ |
602 | |
|
603 | 0 | LOG_TRACE ("Thumbnail: " FORMAT_RL "\n", dwg->header.thumbnail_address); |
604 | 0 | osize = bit_read_RL (&dat); /* overall size of all images */ |
605 | 0 | LOG_TRACE ("overall size: " FORMAT_RL " [RL]\n", osize); |
606 | 0 | if (dat.size < 5 || osize > dat.size - 4) |
607 | 0 | { |
608 | 0 | LOG_ERROR ("Preview overflow > %" PRIuSIZE, dat.size - 4); |
609 | 0 | return NULL; |
610 | 0 | } |
611 | 0 | num_headers = bit_read_RC (&dat); |
612 | 0 | LOG_INFO ("num_headers: %d [RC]\n", (int)num_headers); |
613 | |
|
614 | 0 | found = 0; |
615 | 0 | header_size = 0; |
616 | 0 | for (i = 0; i < num_headers; i++) |
617 | 0 | { |
618 | 0 | if (dat.byte >= dat.size) |
619 | 0 | { |
620 | 0 | LOG_ERROR ("Preview overflow"); |
621 | 0 | break; |
622 | 0 | } |
623 | 0 | type = bit_read_RC (&dat); |
624 | 0 | *typep = type; |
625 | 0 | LOG_TRACE ("\t[%i] Code: %i [RC]\n", i, type); |
626 | 0 | address = bit_read_RL (&dat); |
627 | 0 | if (type == 1) |
628 | 0 | { |
629 | 0 | BITCODE_RL h_size = bit_read_RL (&dat); |
630 | 0 | LOG_TRACE ("\t\tHeader data start: " FORMAT_RL " [RL]\n", address); |
631 | 0 | header_size += h_size; |
632 | 0 | LOG_TRACE ("\t\tHeader data size: " FORMAT_RL " [RL] (" FORMAT_RL |
633 | 0 | ")\n", |
634 | 0 | h_size, header_size); |
635 | 0 | } |
636 | 0 | else if (type == 2 && found == 0) |
637 | 0 | { |
638 | 0 | *size = bit_read_RL (&dat); |
639 | 0 | found = 1; |
640 | 0 | LOG_TRACE ("\t\tBMP data start: " FORMAT_RL " [RL]\n", address); |
641 | 0 | LOG_INFO ("\t\tBMP size: %i [RL]\n", *size); |
642 | 0 | if (*size > dat.size - dat.byte) |
643 | 0 | { |
644 | 0 | LOG_ERROR ("BMP thumbnail overflow > %" PRIuSIZE, |
645 | 0 | dat.size - dat.byte); |
646 | 0 | return NULL; |
647 | 0 | } |
648 | 0 | } |
649 | 0 | else if (type == 3) |
650 | 0 | { |
651 | 0 | osize = bit_read_RL (&dat); |
652 | 0 | *size = osize; |
653 | 0 | LOG_TRACE ("\t\tWMF data start: " FORMAT_RL " [RL]\n", address); |
654 | 0 | LOG_INFO ("\t\tWMF size: %i [RL]\n", osize); |
655 | 0 | } |
656 | 0 | else if (type == 6) // PNG default since r2013 |
657 | 0 | { |
658 | 0 | osize = bit_read_RL (&dat); |
659 | 0 | *size = osize; |
660 | 0 | LOG_TRACE ("\t\tPNG data start: " FORMAT_RL " [RL]\n", address); |
661 | 0 | LOG_INFO ("\t\tPNG size: %i [RL]\n", osize); |
662 | 0 | } |
663 | 0 | else |
664 | 0 | { |
665 | 0 | osize = bit_read_RL (&dat); |
666 | 0 | LOG_TRACE ("\t\tData start: " FORMAT_RL " [RL]\n", address); |
667 | 0 | LOG_TRACE ("\t\tSize of unknown type %i: %i [RL]\n", type, osize); |
668 | 0 | } |
669 | 0 | } |
670 | 0 | dat.byte += header_size; |
671 | 0 | if (*size) |
672 | 0 | LOG_TRACE ("Image offset: %" PRIuSIZE "\n", dat.byte); |
673 | 0 | if (dat.byte + *size > dat.size) |
674 | 0 | { |
675 | 0 | LOG_ERROR ("Preview overflow " FORMAT_RL " + %" PRIuSIZE " > %" PRIuSIZE, |
676 | 0 | *size, dat.byte, dat.size); |
677 | 0 | *size = 0; |
678 | 0 | return NULL; |
679 | 0 | } |
680 | | |
681 | 0 | if (*size > 0) |
682 | 0 | return (dat.chain + dat.byte); |
683 | 0 | else |
684 | 0 | return NULL; |
685 | 0 | } |
686 | | |
687 | | EXPORT double |
688 | | dwg_model_x_min (const Dwg_Data *dwg) |
689 | 0 | { |
690 | 0 | assert (dwg); |
691 | 0 | return dwg->header_vars.EXTMIN.x; |
692 | 0 | } |
693 | | |
694 | | EXPORT double |
695 | | dwg_model_x_max (const Dwg_Data *dwg) |
696 | 0 | { |
697 | 0 | assert (dwg); |
698 | 0 | return dwg->header_vars.EXTMAX.x; |
699 | 0 | } |
700 | | |
701 | | EXPORT double |
702 | | dwg_model_y_min (const Dwg_Data *dwg) |
703 | 0 | { |
704 | 0 | assert (dwg); |
705 | 0 | return dwg->header_vars.EXTMIN.y; |
706 | 0 | } |
707 | | |
708 | | EXPORT double |
709 | | dwg_model_y_max (const Dwg_Data *dwg) |
710 | 0 | { |
711 | 0 | assert (dwg); |
712 | 0 | return dwg->header_vars.EXTMAX.y; |
713 | 0 | } |
714 | | |
715 | | EXPORT double |
716 | | dwg_model_z_min (const Dwg_Data *dwg) |
717 | 0 | { |
718 | 0 | assert (dwg); |
719 | 0 | return dwg->header_vars.EXTMIN.z; |
720 | 0 | } |
721 | | |
722 | | EXPORT double |
723 | | dwg_model_z_max (const Dwg_Data *dwg) |
724 | 0 | { |
725 | 0 | assert (dwg); |
726 | 0 | return dwg->header_vars.EXTMAX.z; |
727 | 0 | } |
728 | | |
729 | | EXPORT double |
730 | | dwg_page_x_min (const Dwg_Data *dwg) |
731 | 0 | { |
732 | 0 | assert (dwg); |
733 | 0 | return dwg->header_vars.PEXTMIN.x; |
734 | 0 | } |
735 | | |
736 | | EXPORT double |
737 | | dwg_page_x_max (const Dwg_Data *dwg) |
738 | 0 | { |
739 | 0 | assert (dwg); |
740 | 0 | return dwg->header_vars.PEXTMAX.x; |
741 | 0 | } |
742 | | |
743 | | EXPORT double |
744 | | dwg_page_y_min (const Dwg_Data *dwg) |
745 | 0 | { |
746 | 0 | assert (dwg); |
747 | 0 | return dwg->header_vars.PEXTMIN.y; |
748 | 0 | } |
749 | | |
750 | | EXPORT double |
751 | | dwg_page_y_max (const Dwg_Data *dwg) |
752 | 0 | { |
753 | 0 | assert (dwg); |
754 | 0 | return dwg->header_vars.PEXTMAX.y; |
755 | 0 | } |
756 | | |
757 | | EXPORT unsigned int |
758 | | dwg_get_layer_count (const Dwg_Data *dwg) |
759 | 0 | { |
760 | 0 | Dwg_Object *ctrl; |
761 | 0 | assert (dwg); |
762 | 0 | ctrl = dwg_get_first_object (dwg, DWG_TYPE_LAYER_CONTROL); |
763 | 0 | if (ctrl && ctrl->tio.object && ctrl->tio.object->tio.LAYER_CONTROL) |
764 | 0 | return ctrl->tio.object->tio.LAYER_CONTROL->num_entries; |
765 | 0 | else |
766 | 0 | return 0; |
767 | 0 | } |
768 | | |
769 | | EXPORT Dwg_Object_LAYER ** |
770 | | dwg_get_layers (const Dwg_Data *dwg) |
771 | 0 | { |
772 | 0 | unsigned int i; |
773 | 0 | unsigned int num_layers = dwg_get_layer_count (dwg); |
774 | 0 | Dwg_Object_LAYER_CONTROL *_ctrl; |
775 | 0 | Dwg_Object_LAYER **layers; |
776 | 0 | Dwg_Object *ctrl; |
777 | |
|
778 | 0 | assert (dwg); |
779 | 0 | ctrl = dwg_get_first_object (dwg, DWG_TYPE_LAYER_CONTROL); |
780 | 0 | if (!ctrl || !ctrl->tio.object || !ctrl->tio.object->tio.LAYER_CONTROL) |
781 | 0 | return NULL; |
782 | 0 | _ctrl = ctrl->tio.object->tio.LAYER_CONTROL; |
783 | 0 | assert (_ctrl); |
784 | 0 | layers |
785 | 0 | = (Dwg_Object_LAYER **)calloc (num_layers, sizeof (Dwg_Object_LAYER *)); |
786 | 0 | for (i = 0; i < num_layers; i++) |
787 | 0 | { |
788 | 0 | Dwg_Object *obj = dwg_ref_object ((Dwg_Data *)dwg, _ctrl->entries[i]); |
789 | 0 | if (obj && obj->fixedtype == DWG_TYPE_LAYER) |
790 | 0 | layers[i] = obj->tio.object->tio.LAYER; |
791 | 0 | } |
792 | 0 | return layers; |
793 | 0 | } |
794 | | |
795 | | BITCODE_BL |
796 | | dwg_get_object_num_objects (const Dwg_Data *dwg) |
797 | 0 | { |
798 | 0 | assert (dwg); |
799 | 0 | return dwg->num_objects - dwg->num_entities; |
800 | 0 | } |
801 | | |
802 | | BITCODE_BL |
803 | | dwg_get_num_objects (const Dwg_Data *dwg) |
804 | 0 | { |
805 | 0 | assert (dwg); |
806 | 0 | return dwg->num_objects; |
807 | 0 | } |
808 | | |
809 | | BITCODE_BL |
810 | | dwg_get_num_entities (const Dwg_Data *dwg) |
811 | 0 | { |
812 | 0 | assert (dwg); |
813 | 0 | return dwg->num_entities; |
814 | 0 | } |
815 | | |
816 | | /** Returns a copy of all entities */ |
817 | | EXPORT Dwg_Object_Entity ** |
818 | | dwg_get_entities (const Dwg_Data *dwg) |
819 | 0 | { |
820 | 0 | BITCODE_BL i, ent_count = 0; |
821 | 0 | Dwg_Object_Entity **entities; |
822 | |
|
823 | 0 | assert (dwg); |
824 | 0 | entities = (Dwg_Object_Entity **)calloc (dwg_get_num_entities (dwg), |
825 | 0 | sizeof (Dwg_Object_Entity *)); |
826 | 0 | for (i = 0; i < dwg->num_objects; i++) |
827 | 0 | { |
828 | 0 | if (dwg->object[i].supertype == DWG_SUPERTYPE_ENTITY) |
829 | 0 | { |
830 | 0 | entities[ent_count] = dwg->object[i].tio.entity; |
831 | 0 | ent_count++; |
832 | 0 | assert (ent_count < dwg->num_objects); |
833 | 0 | } |
834 | 0 | } |
835 | 0 | return entities; |
836 | 0 | } |
837 | | |
838 | | EXPORT Dwg_Object_LAYER * |
839 | | dwg_get_entity_layer (const Dwg_Object_Entity *ent) |
840 | 0 | { |
841 | 0 | Dwg_Object *obj; |
842 | | // we'd really need the dwg_api or dwg to check dirty_refs |
843 | 0 | if (ent && ent->layer && (obj = ent->layer->obj) |
844 | 0 | && obj->fixedtype == DWG_TYPE_LAYER) |
845 | 0 | return obj->tio.object->tio.LAYER; |
846 | 0 | else |
847 | | // TODO: empty means default layer 0 |
848 | 0 | return NULL; |
849 | 0 | } |
850 | | |
851 | | EXPORT Dwg_Object * |
852 | | dwg_next_object (const Dwg_Object *obj) |
853 | 10.4M | { |
854 | 10.4M | Dwg_Data *dwg; |
855 | 10.4M | if (!obj) |
856 | 0 | return NULL; |
857 | 10.4M | dwg = obj->parent; |
858 | 10.4M | if ((obj->index + 1) > (dwg->num_objects - 1)) |
859 | 42.2k | return NULL; |
860 | 10.4M | return &dwg->object[obj->index + 1]; |
861 | 10.4M | } |
862 | | |
863 | | /** |
864 | | * Find an object given its handle |
865 | | */ |
866 | | EXPORT Dwg_Object * |
867 | | dwg_ref_object (Dwg_Data *restrict dwg, Dwg_Object_Ref *restrict ref) |
868 | 9.06M | { |
869 | 9.06M | if (!ref) |
870 | 34.1k | return NULL; |
871 | 9.02M | if (dwg->dirty_refs) |
872 | 22 | dwg_resolve_objectrefs_silent (dwg); |
873 | 9.02M | if (ref->obj && !dwg->dirty_refs) |
874 | 372k | { |
875 | 372k | if (ref->obj->handle.value |
876 | 372k | == ref->absolute_ref) // not a wrong sort_ents import |
877 | 372k | return ref->obj; |
878 | 2 | else |
879 | 2 | { |
880 | 2 | LOG_WARN ("Wrong ref_object: " FORMAT_HV " != " FORMAT_RLLx, |
881 | 2 | ref->obj->handle.value, ref->absolute_ref); |
882 | 2 | ref->obj = NULL; |
883 | | // dwg_resolve_objectrefs_silent (dwg); |
884 | 2 | } |
885 | 372k | } |
886 | | // if (dwg->header.from_version < R_12 && !ref->absolute_ref) |
887 | | // { // resolve r11_idx to absolute_ref, looking up in the table entries |
888 | | // LOG_WARN ("Cannot resolve r11_idx %u", ref->r11_idx); |
889 | | // } |
890 | | // Without obj we don't get an absolute_ref from relative OFFSETOBJHANDLE |
891 | | // handle types. |
892 | 8.65M | if ((ref->handleref.code < 6 && dwg_resolve_handleref (ref, NULL)) |
893 | 3.00M | || ref->absolute_ref) |
894 | 7.75M | { |
895 | 7.75M | Dwg_Object *obj = dwg_resolve_handle (dwg, ref->absolute_ref); |
896 | 7.75M | if (!dwg->dirty_refs && obj) |
897 | 95.0k | ref->obj = obj; |
898 | 7.75M | return obj; |
899 | 7.75M | } |
900 | 899k | else |
901 | 899k | return NULL; |
902 | 8.65M | } |
903 | | |
904 | | /** |
905 | | * Find an object given its handle and relative base object. |
906 | | * OFFSETOBJHANDLE, handleref.code > 6. |
907 | | */ |
908 | | EXPORT Dwg_Object * |
909 | | dwg_ref_object_relative (Dwg_Data *restrict dwg, Dwg_Object_Ref *restrict ref, |
910 | | const Dwg_Object *restrict obj) |
911 | 0 | { |
912 | 0 | if (ref->obj && !dwg->dirty_refs) |
913 | 0 | return ref->obj; |
914 | 0 | if (dwg_resolve_handleref (ref, obj)) |
915 | 0 | { |
916 | 0 | Dwg_Object *o = dwg_resolve_handle (dwg, ref->absolute_ref); |
917 | 0 | if (!dwg->dirty_refs && o) |
918 | 0 | ref->obj = o; |
919 | 0 | return o; |
920 | 0 | } |
921 | 0 | else |
922 | 0 | return NULL; |
923 | 0 | } |
924 | | |
925 | | /** |
926 | | * Find a pointer to an object given its absolute id (handle). |
927 | | * TODO: Check and update each handleref obj cache. |
928 | | * Note that absref 0 is illegal here, I think. |
929 | | */ |
930 | | EXPORT Dwg_Object * |
931 | | dwg_resolve_handle (const Dwg_Data *dwg, const BITCODE_RLL absref) |
932 | 72.9M | { |
933 | 72.9M | uint64_t i; |
934 | 72.9M | if (!absref) // illegal usage |
935 | 31.3M | return NULL; |
936 | 41.6M | loglevel = dwg->opts & DWG_OPTS_LOGLEVEL; |
937 | 41.6M | i = hash_get (dwg->object_map, absref); |
938 | 41.6M | if (i != HASH_NOT_FOUND) |
939 | 41.6M | LOG_HANDLE ("[object_map{" FORMAT_HV "} => " FORMAT_BLL "] ", absref, i); |
940 | 41.6M | if (i == HASH_NOT_FOUND |
941 | 3.08M | || (BITCODE_BL)i >= dwg->num_objects) // the latter being an invalid |
942 | | // handle (read from DWG) |
943 | 38.5M | { |
944 | | // ignore warning on invalid handles. These are warned earlier already |
945 | 38.5M | if (absref && dwg->header_vars.HANDSEED |
946 | 36.7M | && absref < dwg->header_vars.HANDSEED->absolute_ref) |
947 | 26.7M | { |
948 | 26.7M | LOG_WARN ("Object handle not found " FORMAT_BLL "/" FORMAT_RLL |
949 | 26.7M | " in " FORMAT_BL " objects of max " FORMAT_RLL " handles", |
950 | 26.7M | absref, absref, dwg->num_objects, |
951 | 26.7M | dwg->header_vars.HANDSEED->absolute_ref); |
952 | 26.7M | } |
953 | 11.8M | else |
954 | 11.8M | { |
955 | 11.8M | LOG_WARN ("Object handle not found " FORMAT_BLL "/" FORMAT_RLL, |
956 | 11.8M | absref, absref); |
957 | 11.8M | } |
958 | 38.5M | return NULL; |
959 | 38.5M | } |
960 | 3.08M | LOG_INSANE ("[resolve " FORMAT_HV " => " FORMAT_BLL "] ", absref, i); |
961 | 3.08M | return &dwg->object[i]; // allow value 0 |
962 | 41.6M | } |
963 | | |
964 | | /** |
965 | | * Silent variant of dwg_resolve_handle |
966 | | */ |
967 | | EXPORT Dwg_Object * |
968 | | dwg_resolve_handle_silent (const Dwg_Data *dwg, const BITCODE_RLL absref) |
969 | 19.3M | { |
970 | 19.3M | uint64_t i; |
971 | 19.3M | if (!absref) // illegal usage |
972 | 5.56M | return NULL; |
973 | 13.7M | i = hash_get (dwg->object_map, absref); |
974 | 13.7M | if (i == HASH_NOT_FOUND |
975 | 1.96M | || (BITCODE_BL)i >= dwg->num_objects) // the latter being an invalid |
976 | | // handle (read from DWG) |
977 | 11.8M | return NULL; |
978 | 1.96M | return &dwg->object[i]; // allow value 0 |
979 | 13.7M | } |
980 | | |
981 | | EXPORT Dwg_Object * |
982 | | dwg_ref_object_silent (Dwg_Data *restrict dwg, Dwg_Object_Ref *restrict ref) |
983 | 1.61k | { |
984 | 1.61k | if (!ref) |
985 | 0 | return NULL; |
986 | 1.61k | if (dwg->dirty_refs) |
987 | 0 | dwg_resolve_objectrefs_silent (dwg); |
988 | 1.61k | if (dwg->dirty_refs == 0 && ref->obj != NULL) |
989 | 1.39k | return ref->obj; |
990 | 224 | if ((ref->handleref.code < 6 |
991 | 117 | && dwg_resolve_handleref ((Dwg_Object_Ref *)ref, NULL)) |
992 | 107 | || ref->absolute_ref) |
993 | 224 | { |
994 | 224 | Dwg_Object *obj = dwg_resolve_handle_silent (dwg, ref->absolute_ref); |
995 | 224 | if (obj) |
996 | 0 | ref->obj = obj; |
997 | 224 | return obj; |
998 | 224 | } |
999 | 0 | else |
1000 | 0 | return NULL; |
1001 | 224 | } |
1002 | | |
1003 | | /* set ref->absolute_ref from obj, for a subsequent dwg_resolve_handle() */ |
1004 | | EXPORT int |
1005 | | dwg_resolve_handleref (Dwg_Object_Ref *restrict ref, |
1006 | | const Dwg_Object *restrict obj) |
1007 | 6.19M | { |
1008 | | /* |
1009 | | * With TYPEDOBJHANDLE 2-5 the code indicates the type of ownership: |
1010 | | * 2 Soft owner |
1011 | | * 3 Hard owner |
1012 | | * 4 Soft pointer |
1013 | | * 5 Hard pointer |
1014 | | * With OFFSETOBJHANDLE >5 the code 4 handle is stored as an offset from some |
1015 | | * other handle. |
1016 | | */ |
1017 | 6.19M | switch (ref->handleref.code) |
1018 | 6.19M | { |
1019 | | // implicit code: 4 |
1020 | 0 | case 6: |
1021 | 0 | ref->absolute_ref = (obj->handle.value + 1); |
1022 | 0 | break; |
1023 | 0 | case 8: |
1024 | 0 | ref->absolute_ref = (obj->handle.value - 1); |
1025 | 0 | break; |
1026 | 0 | case 10: |
1027 | 0 | ref->absolute_ref = (obj->handle.value + ref->handleref.value); |
1028 | 0 | break; |
1029 | 0 | case 12: |
1030 | 0 | ref->absolute_ref = (obj->handle.value - ref->handleref.value); |
1031 | 0 | break; |
1032 | 344k | case 2: |
1033 | 590k | case 3: |
1034 | 946k | case 4: |
1035 | 1.23M | case 5: |
1036 | 1.23M | ref->absolute_ref = ref->handleref.value; |
1037 | 1.23M | break; |
1038 | 4.41M | case 0: // ignore? |
1039 | 4.41M | ref->absolute_ref = ref->handleref.value; |
1040 | 4.41M | break; |
1041 | 542k | default: |
1042 | 542k | ref->absolute_ref = ref->handleref.value; |
1043 | 542k | if (!loglevel && obj && obj->parent) |
1044 | 0 | loglevel = obj->parent->opts & DWG_OPTS_LOGLEVEL; |
1045 | 542k | LOG_WARN ("Invalid handle pointer code %d", ref->handleref.code); |
1046 | 542k | return 0; |
1047 | 6.19M | } |
1048 | 5.64M | return 1; |
1049 | 6.19M | } |
1050 | | |
1051 | | /** Returns the block_control for the DWG, |
1052 | | containing the list of all blocks headers. |
1053 | | */ |
1054 | | EXPORT Dwg_Object_BLOCK_CONTROL * |
1055 | | dwg_block_control (Dwg_Data *dwg) |
1056 | 29.1k | { |
1057 | 29.1k | if (!dwg->block_control.parent) |
1058 | 5.47k | { |
1059 | 5.47k | Dwg_Object *obj; |
1060 | 5.47k | Dwg_Object_Ref *ctrl = dwg->header_vars.BLOCK_CONTROL_OBJECT; |
1061 | 5.47k | if (!ctrl) |
1062 | 4.83k | dwg->header_vars.BLOCK_CONTROL_OBJECT = ctrl |
1063 | 4.83k | = dwg_find_table_control (dwg, "BLOCK_CONTROL"); |
1064 | 5.47k | if (!ctrl || !(obj = dwg_ref_object (dwg, ctrl)) |
1065 | 2.90k | || obj->fixedtype != DWG_TYPE_BLOCK_CONTROL) |
1066 | 2.59k | { |
1067 | 2.59k | LOG_ERROR ( |
1068 | 2.59k | "dwg.block_control and HEADER.BLOCK_CONTROL_OBJECT missing"); |
1069 | 2.59k | return NULL; |
1070 | 2.59k | } |
1071 | 2.87k | else |
1072 | 2.87k | { |
1073 | 2.87k | dwg->block_control = *obj->tio.object->tio.BLOCK_CONTROL; |
1074 | 2.87k | } |
1075 | 5.47k | } |
1076 | 26.5k | return &(dwg->block_control); |
1077 | 29.1k | } |
1078 | | |
1079 | | /** Returns the model space block object for the DWG. |
1080 | | On r2010 and r2013 it could be different to the canonical |
1081 | | dwg->block_control.model_space. |
1082 | | */ |
1083 | | EXPORT Dwg_Object_Ref * |
1084 | | dwg_model_space_ref (Dwg_Data *dwg) |
1085 | 20.1k | { |
1086 | 20.1k | Dwg_Object *obj; |
1087 | 20.1k | Dwg_Object_BLOCK_CONTROL *block_control; |
1088 | 20.1k | if (dwg->dirty_refs) |
1089 | 0 | dwg_resolve_objectrefs_silent (dwg); |
1090 | 20.1k | if (dwg->header_vars.BLOCK_RECORD_MSPACE && !dwg->dirty_refs |
1091 | 13.3k | && dwg->header_vars.BLOCK_RECORD_MSPACE->obj) |
1092 | 10.7k | return dwg->header_vars.BLOCK_RECORD_MSPACE; |
1093 | 9.30k | if (dwg->block_control.model_space && !dwg->dirty_refs |
1094 | 1.42k | && dwg->block_control.model_space->obj) |
1095 | 18 | { |
1096 | 18 | dwg->header_vars.BLOCK_RECORD_MSPACE = dwg->block_control.model_space; |
1097 | 18 | return dwg->block_control.model_space; |
1098 | 18 | } |
1099 | 9.28k | block_control = dwg_block_control (dwg); |
1100 | 9.28k | if (block_control && block_control->model_space && !dwg->dirty_refs |
1101 | 1.42k | && block_control->model_space->obj) |
1102 | 0 | { |
1103 | 0 | dwg->block_control.model_space = block_control->model_space; |
1104 | 0 | dwg->header_vars.BLOCK_RECORD_MSPACE = block_control->model_space; |
1105 | 0 | return block_control->model_space; |
1106 | 0 | } |
1107 | 9.28k | obj = dwg_get_first_object (dwg, DWG_TYPE_BLOCK_CONTROL); |
1108 | 9.28k | if (!obj) |
1109 | 782 | return NULL; |
1110 | 8.50k | block_control = obj->tio.object->tio.BLOCK_CONTROL; |
1111 | 8.50k | if (block_control && block_control->model_space && !dwg->dirty_refs |
1112 | 1.47k | && block_control->model_space->obj) |
1113 | 0 | { |
1114 | 0 | dwg->block_control.model_space = block_control->model_space; |
1115 | 0 | dwg->header_vars.BLOCK_RECORD_MSPACE = block_control->model_space; |
1116 | 0 | return block_control->model_space; |
1117 | 0 | } |
1118 | 8.50k | return NULL; |
1119 | 8.50k | } |
1120 | | |
1121 | | /** Returns the paper space block object for the DWG. |
1122 | | */ |
1123 | | EXPORT Dwg_Object_Ref * |
1124 | | dwg_paper_space_ref (Dwg_Data *dwg) |
1125 | 15.0k | { |
1126 | 15.0k | if (dwg->dirty_refs) |
1127 | 0 | dwg_resolve_objectrefs_silent (dwg); |
1128 | 15.0k | if (dwg->header_vars.BLOCK_RECORD_PSPACE && !dwg->dirty_refs |
1129 | 2.59k | && dwg->header_vars.BLOCK_RECORD_PSPACE->obj) |
1130 | 14 | return dwg->header_vars.BLOCK_RECORD_PSPACE; |
1131 | 14.9k | return dwg->block_control.paper_space && !dwg->dirty_refs |
1132 | 1.57k | && dwg->block_control.paper_space->obj |
1133 | 14.9k | ? dwg->block_control.paper_space |
1134 | 14.9k | : NULL; |
1135 | 15.0k | } |
1136 | | |
1137 | | /** Returns the model space block object for the DWG. |
1138 | | */ |
1139 | | EXPORT Dwg_Object * |
1140 | | dwg_model_space_object (Dwg_Data *dwg) |
1141 | 13.9k | { |
1142 | 13.9k | Dwg_Object *obj; |
1143 | 13.9k | Dwg_Object_Ref *msref = dwg_model_space_ref (dwg); |
1144 | 13.9k | Dwg_Object_BLOCK_CONTROL *ctrl; |
1145 | | |
1146 | 13.9k | if (msref && (obj = dwg_ref_object (dwg, msref)) |
1147 | 5.08k | && obj->fixedtype == DWG_TYPE_BLOCK_HEADER) |
1148 | 4.90k | return obj; |
1149 | 9.08k | ctrl = dwg_block_control (dwg); |
1150 | 9.08k | msref = ctrl ? ctrl->model_space : NULL; |
1151 | 9.08k | if (msref && (obj = dwg_ref_object (dwg, msref)) |
1152 | 62 | && obj->fixedtype == DWG_TYPE_BLOCK_HEADER) |
1153 | 15 | { |
1154 | 15 | if (!dwg->header_vars.BLOCK_RECORD_MSPACE) |
1155 | 2 | dwg->header_vars.BLOCK_RECORD_MSPACE = msref; |
1156 | 15 | return obj; |
1157 | 15 | } |
1158 | 9.06k | msref = dwg->header_vars.BLOCK_RECORD_MSPACE; |
1159 | 9.06k | if (msref && (obj = dwg_ref_object (dwg, msref)) |
1160 | 186 | && obj->fixedtype == DWG_TYPE_BLOCK_HEADER) |
1161 | 0 | { |
1162 | 0 | if (ctrl) |
1163 | 0 | ctrl->model_space = msref; |
1164 | 0 | return obj; |
1165 | 0 | } |
1166 | 9.06k | if (!dwg->object_map) // for dwg_add_Document() |
1167 | 0 | dwg->object_map = hash_new (100); |
1168 | | // TODO <= r11 |
1169 | 9.06k | obj = dwg_resolve_handle (dwg, dwg->header.version >= R_2000 ? 0x1F : 0x17); |
1170 | 9.06k | if (obj && obj->fixedtype == DWG_TYPE_BLOCK_HEADER) |
1171 | 144 | return obj; |
1172 | 8.92k | obj = dwg_find_first_type (dwg, DWG_TYPE_BLOCK_HEADER); |
1173 | 8.92k | if (obj && obj->fixedtype == DWG_TYPE_BLOCK_HEADER) |
1174 | 8.83k | return obj; |
1175 | 85 | else |
1176 | 85 | return NULL; |
1177 | 8.92k | } |
1178 | | |
1179 | | /** Returns the paper space block object for the DWG. |
1180 | | */ |
1181 | | EXPORT Dwg_Object * |
1182 | | dwg_paper_space_object (Dwg_Data *dwg) |
1183 | 6.58k | { |
1184 | 6.58k | Dwg_Object *obj; |
1185 | 6.58k | Dwg_Object_Ref *psref = dwg_paper_space_ref (dwg); |
1186 | 6.58k | Dwg_Object_BLOCK_CONTROL *ctrl; |
1187 | | |
1188 | 6.58k | if (psref && (obj = dwg_ref_object (dwg, psref)) |
1189 | 54 | && obj->fixedtype == DWG_TYPE_BLOCK_HEADER) |
1190 | 7 | return obj; |
1191 | 6.57k | ctrl = dwg_block_control (dwg); |
1192 | 6.57k | psref = ctrl ? ctrl->paper_space : NULL; |
1193 | 6.57k | if (psref && (obj = dwg_ref_object (dwg, psref)) |
1194 | 59 | && obj->fixedtype == DWG_TYPE_BLOCK_HEADER) |
1195 | 1 | { |
1196 | 1 | if (!dwg->header_vars.BLOCK_RECORD_PSPACE) |
1197 | 1 | dwg->header_vars.BLOCK_RECORD_PSPACE = psref; |
1198 | 1 | return obj; |
1199 | 1 | } |
1200 | 6.57k | psref = dwg->header_vars.BLOCK_RECORD_PSPACE; |
1201 | 6.57k | if (psref && (obj = dwg_ref_object (dwg, psref)) |
1202 | 8 | && obj->fixedtype == DWG_TYPE_BLOCK_HEADER) |
1203 | 2 | { |
1204 | 2 | if (ctrl) |
1205 | 2 | ctrl->paper_space = psref; |
1206 | 2 | return obj; |
1207 | 2 | } |
1208 | 6.57k | else |
1209 | 6.57k | return NULL; |
1210 | 6.57k | } |
1211 | | |
1212 | | /** Returns the first entity owned by the block hdr, or NULL. |
1213 | | */ |
1214 | | EXPORT Dwg_Object * |
1215 | | get_first_owned_entity (const Dwg_Object *hdr) |
1216 | 35.9k | { |
1217 | 35.9k | const Dwg_Version_Type version = hdr->parent->header.version; |
1218 | 35.9k | Dwg_Object_BLOCK_HEADER *_hdr = hdr->tio.object->tio.BLOCK_HEADER; |
1219 | 35.9k | if (hdr->fixedtype != DWG_TYPE_BLOCK_HEADER) |
1220 | 0 | { |
1221 | 0 | LOG_ERROR ("Invalid BLOCK_HEADER type %d", hdr->fixedtype); |
1222 | 0 | return NULL; |
1223 | 0 | } |
1224 | | |
1225 | 35.9k | if (R_13b1 <= version && version <= R_2000) |
1226 | 35.3k | { |
1227 | 35.3k | Dwg_Data *dwg = hdr->parent; |
1228 | 35.3k | if (dwg->dirty_refs) |
1229 | 0 | dwg_resolve_objectrefs_silent (dwg); |
1230 | 35.3k | _hdr->__iterator = 0; /* reset step counter for cycle detection */ |
1231 | | /* With r2000 we rather follow the next_entity chain */ |
1232 | 35.3k | return _hdr->first_entity ? _hdr->first_entity->obj : NULL; |
1233 | 35.3k | } |
1234 | 512 | else if (version >= R_2004 || version < R_13b1) |
1235 | 512 | { |
1236 | 512 | _hdr->__iterator = 0; |
1237 | 512 | if (_hdr->entities && _hdr->num_owned && _hdr->entities[0]) |
1238 | 195 | { |
1239 | 195 | Dwg_Data *dwg = hdr->parent; |
1240 | 195 | Dwg_Object *obj = dwg_ref_object (dwg, _hdr->entities[0]); |
1241 | 195 | if (version < R_13b1 && obj && obj->fixedtype == DWG_TYPE_JUMP) |
1242 | 0 | return dwg_resolve_jump (obj); |
1243 | 195 | else |
1244 | 195 | return obj; |
1245 | 195 | } |
1246 | 317 | else |
1247 | 317 | return NULL; |
1248 | 512 | } |
1249 | | |
1250 | | // TODO: preR13 block table |
1251 | 0 | LOG_ERROR ("Unsupported version %s\n", dwg_version_type (version)); |
1252 | 0 | return NULL; |
1253 | 35.9k | } |
1254 | | |
1255 | | /** Returns the next entity owned by mspace or pspace or NULL. |
1256 | | */ |
1257 | | EXPORT Dwg_Object * |
1258 | | dwg_next_entity (const Dwg_Object *restrict obj) |
1259 | 240k | { |
1260 | 240k | Dwg_Object_Ref *restrict next; |
1261 | | |
1262 | 240k | if (obj == NULL || obj->parent == NULL |
1263 | 240k | || obj->supertype != DWG_SUPERTYPE_ENTITY) |
1264 | 191 | return NULL; |
1265 | 240k | if (obj->parent->header.version < R_2004 |
1266 | 240k | && obj->parent->header.version > R_12) |
1267 | 240k | { |
1268 | 240k | if (!obj->tio.entity) // decoding error |
1269 | 0 | goto next_obj; |
1270 | 240k | next = obj->tio.entity->next_entity; |
1271 | 240k | if (next && next->absolute_ref) |
1272 | 1.61k | { |
1273 | 1.61k | Dwg_Object *next_obj = dwg_ref_object_silent (obj->parent, next); |
1274 | 1.61k | return (next_obj == NULL || obj == next_obj |
1275 | 1.36k | || next_obj->supertype != DWG_SUPERTYPE_ENTITY) |
1276 | 1.61k | ? NULL |
1277 | 1.61k | : next_obj; |
1278 | 1.61k | } |
1279 | 239k | else |
1280 | 239k | goto next_obj; |
1281 | 240k | } |
1282 | 0 | else |
1283 | 0 | { |
1284 | 239k | next_obj: |
1285 | 239k | obj = dwg_next_object (obj); |
1286 | 1.49M | while (obj && obj->supertype != DWG_SUPERTYPE_ENTITY) |
1287 | 1.25M | { |
1288 | 1.25M | obj = dwg_next_object (obj); |
1289 | 1.25M | } |
1290 | 239k | return (Dwg_Object *)obj; |
1291 | 0 | } |
1292 | 240k | } |
1293 | | |
1294 | | /** Returns the next entity owned by the block hdr, or NULL. |
1295 | | * Not subentities: ATTRIB, VERTEX. |
1296 | | */ |
1297 | | EXPORT Dwg_Object * |
1298 | | get_next_owned_entity (const Dwg_Object *restrict hdr, |
1299 | | const Dwg_Object *restrict current) |
1300 | 0 | { |
1301 | 0 | Dwg_Data *dwg = hdr->parent; |
1302 | 0 | const Dwg_Version_Type version = dwg->header.version; |
1303 | 0 | Dwg_Object_BLOCK_HEADER *_hdr = hdr->tio.object->tio.BLOCK_HEADER; |
1304 | 0 | if (hdr->fixedtype != DWG_TYPE_BLOCK_HEADER) |
1305 | 0 | { |
1306 | 0 | LOG_ERROR ("Invalid BLOCK_HEADER type %d", hdr->fixedtype); |
1307 | 0 | return NULL; |
1308 | 0 | } |
1309 | | |
1310 | 0 | if (R_13b1 <= version && version <= R_2000) |
1311 | 0 | { |
1312 | 0 | Dwg_Object *obj; |
1313 | 0 | BITCODE_BL max_steps; |
1314 | 0 | if (_hdr->last_entity == NULL || current == _hdr->last_entity->obj) |
1315 | 0 | return NULL; |
1316 | | /* Cycle detection: __iterator was reset in get_first_owned_entity */ |
1317 | 0 | _hdr->__iterator++; |
1318 | 0 | max_steps = _hdr->num_owned ? _hdr->num_owned : hdr->parent->num_objects; |
1319 | 0 | if (_hdr->__iterator > max_steps) |
1320 | 0 | { |
1321 | 0 | LOG_WARN ("Cycle in entity link chain for BLOCK_HEADER " FORMAT_HV |
1322 | 0 | "\n", |
1323 | 0 | hdr->handle.value); |
1324 | 0 | return NULL; |
1325 | 0 | } |
1326 | 0 | obj = dwg_next_entity (current); |
1327 | 0 | while (obj |
1328 | 0 | && (obj->fixedtype == DWG_TYPE_ATTDEF |
1329 | 0 | || obj->fixedtype == DWG_TYPE_ATTRIB |
1330 | 0 | || obj->fixedtype == DWG_TYPE_VERTEX_2D |
1331 | 0 | || obj->fixedtype == DWG_TYPE_VERTEX_3D |
1332 | 0 | || obj->fixedtype == DWG_TYPE_VERTEX_MESH |
1333 | 0 | || obj->fixedtype == DWG_TYPE_VERTEX_PFACE |
1334 | 0 | || obj->fixedtype == DWG_TYPE_VERTEX_PFACE_FACE)) |
1335 | 0 | { |
1336 | 0 | if (obj |
1337 | 0 | == _hdr->last_entity->obj) // stop before skipping last_entity |
1338 | 0 | return obj; |
1339 | 0 | obj = dwg_next_entity (obj); |
1340 | | // this may happen with r2000 attribs |
1341 | 0 | if (obj && obj->tio.entity != NULL |
1342 | 0 | && obj->tio.entity->ownerhandle != NULL |
1343 | 0 | && obj->tio.entity->ownerhandle->absolute_ref |
1344 | 0 | != hdr->handle.value) |
1345 | 0 | obj = NULL; |
1346 | 0 | if (obj == _hdr->last_entity->obj) // early exit |
1347 | 0 | return obj; |
1348 | 0 | } |
1349 | 0 | return obj; |
1350 | 0 | } |
1351 | 0 | else if (version >= R_2004 || version < R_13b1) |
1352 | 0 | { |
1353 | 0 | Dwg_Object *obj; |
1354 | 0 | Dwg_Object_Ref *ref; |
1355 | 0 | _hdr->__iterator++; |
1356 | 0 | if (_hdr->__iterator == _hdr->num_owned) |
1357 | 0 | return NULL; |
1358 | 0 | ref = _hdr->entities ? _hdr->entities[_hdr->__iterator] : NULL; |
1359 | 0 | obj = ref ? dwg_ref_object (dwg, ref) : NULL; |
1360 | 0 | if (version < R_13b1 && obj && obj->fixedtype == DWG_TYPE_JUMP) |
1361 | 0 | return dwg_resolve_jump (obj); |
1362 | 0 | else |
1363 | 0 | return obj; |
1364 | 0 | } |
1365 | | |
1366 | 0 | LOG_ERROR ("Unsupported version %s\n", dwg_version_type (version)); |
1367 | 0 | return NULL; |
1368 | 0 | } |
1369 | | |
1370 | | /** Returns the first subentity owned by the insert or polyline. |
1371 | | */ |
1372 | | EXPORT Dwg_Object * |
1373 | | get_first_owned_subentity (const Dwg_Object *owner) |
1374 | 0 | { |
1375 | 0 | Dwg_Data *dwg = owner->parent; |
1376 | 0 | const Dwg_Version_Type version = dwg->header.version; |
1377 | 0 | const unsigned int type = owner->fixedtype; |
1378 | 0 | if (type == DWG_TYPE_INSERT) |
1379 | 0 | { |
1380 | 0 | Dwg_Entity_INSERT *_obj = owner->tio.entity->tio.INSERT; |
1381 | 0 | if (version >= R_13b1 && version <= R_2000) |
1382 | 0 | return _obj->first_attrib ? _obj->first_attrib->obj : NULL; |
1383 | 0 | else |
1384 | 0 | return _obj->attribs && _obj->attribs[0] |
1385 | 0 | ? dwg_ref_object (dwg, _obj->attribs[0]) |
1386 | 0 | : NULL; |
1387 | 0 | } |
1388 | 0 | else if (type == DWG_TYPE_MINSERT) |
1389 | 0 | { |
1390 | 0 | Dwg_Entity_MINSERT *_obj = owner->tio.entity->tio.MINSERT; |
1391 | 0 | if (version >= R_13b1 && version <= R_2000) |
1392 | 0 | return _obj->first_attrib ? dwg_ref_object (dwg, _obj->first_attrib) |
1393 | 0 | : NULL; |
1394 | 0 | else |
1395 | 0 | return _obj->attribs && _obj->attribs[0] |
1396 | 0 | ? dwg_ref_object (dwg, _obj->attribs[0]) |
1397 | 0 | : NULL; |
1398 | 0 | } |
1399 | 0 | else if (type == DWG_TYPE_POLYLINE_2D || type == DWG_TYPE_POLYLINE_3D |
1400 | 0 | || type == DWG_TYPE_POLYLINE_PFACE |
1401 | 0 | || type == DWG_TYPE_POLYLINE_MESH) |
1402 | 0 | { |
1403 | | // guaranteed structure |
1404 | 0 | Dwg_Entity_POLYLINE_2D *_obj = owner->tio.entity->tio.POLYLINE_2D; |
1405 | 0 | if (version >= R_13b1 && version <= R_2000) |
1406 | 0 | return _obj->first_vertex ? dwg_ref_object (dwg, _obj->first_vertex) |
1407 | 0 | : NULL; |
1408 | 0 | else |
1409 | 0 | return _obj->vertex && _obj->vertex[0] |
1410 | 0 | ? dwg_ref_object (dwg, _obj->vertex[0]) |
1411 | 0 | : NULL; |
1412 | 0 | } |
1413 | 0 | else |
1414 | 0 | { |
1415 | 0 | LOG_ERROR ("Wrong type %d, has no subentity", type); |
1416 | 0 | } |
1417 | 0 | return NULL; |
1418 | 0 | } |
1419 | | |
1420 | | /** Returns the next subentity owned by the object. |
1421 | | */ |
1422 | | EXPORT Dwg_Object * |
1423 | | get_next_owned_subentity (const Dwg_Object *restrict owner, |
1424 | | const Dwg_Object *restrict current) |
1425 | 0 | { |
1426 | 0 | Dwg_Data *dwg = owner->parent; |
1427 | 0 | Dwg_Version_Type version = dwg->header.version; |
1428 | 0 | const Dwg_Object_Type type = (const Dwg_Object_Type)owner->fixedtype; |
1429 | 0 | Dwg_Object_Entity *ent = owner->tio.entity; |
1430 | 0 | Dwg_Object *obj = dwg_next_object (current); |
1431 | |
|
1432 | 0 | if (type == DWG_TYPE_INSERT) |
1433 | 0 | { |
1434 | 0 | Dwg_Entity_INSERT *_obj = owner->tio.entity->tio.INSERT; |
1435 | 0 | if (version >= R_13b1 && version <= R_2000) |
1436 | 0 | return (_obj->last_attrib && current != _obj->last_attrib->obj |
1437 | 0 | && obj->fixedtype == DWG_TYPE_ATTRIB) |
1438 | 0 | ? obj |
1439 | 0 | : NULL; |
1440 | 0 | else |
1441 | 0 | { |
1442 | 0 | ent->__iterator++; |
1443 | 0 | if (ent->__iterator == _obj->num_owned) |
1444 | 0 | { |
1445 | 0 | ent->__iterator = 0; |
1446 | 0 | return NULL; |
1447 | 0 | } |
1448 | 0 | else |
1449 | 0 | return _obj->attribs |
1450 | 0 | ? dwg_ref_object (dwg, _obj->attribs[ent->__iterator]) |
1451 | 0 | : NULL; |
1452 | 0 | } |
1453 | 0 | } |
1454 | 0 | else if (type == DWG_TYPE_MINSERT) |
1455 | 0 | { |
1456 | 0 | Dwg_Entity_MINSERT *_obj = owner->tio.entity->tio.MINSERT; |
1457 | 0 | if (version >= R_13b1 && version <= R_2000) |
1458 | 0 | return (_obj->last_attrib && current != _obj->last_attrib->obj |
1459 | 0 | && obj->fixedtype == DWG_TYPE_ATTRIB) |
1460 | 0 | ? obj |
1461 | 0 | : NULL; |
1462 | 0 | else |
1463 | 0 | { |
1464 | 0 | ent->__iterator++; |
1465 | 0 | if (ent->__iterator == _obj->num_owned) |
1466 | 0 | { |
1467 | 0 | ent->__iterator = 0; |
1468 | 0 | return NULL; |
1469 | 0 | } |
1470 | 0 | else |
1471 | 0 | return _obj->attribs |
1472 | 0 | ? dwg_ref_object (dwg, _obj->attribs[ent->__iterator]) |
1473 | 0 | : NULL; |
1474 | 0 | } |
1475 | 0 | } |
1476 | 0 | else if (type == DWG_TYPE_POLYLINE_2D || type == DWG_TYPE_POLYLINE_3D |
1477 | 0 | || type == DWG_TYPE_POLYLINE_PFACE |
1478 | 0 | || type == DWG_TYPE_POLYLINE_MESH) |
1479 | 0 | { |
1480 | | // guaranteed structure |
1481 | 0 | Dwg_Entity_POLYLINE_2D *_obj = owner->tio.entity->tio.POLYLINE_2D; |
1482 | 0 | if (version >= R_13b1 && version <= R_2000) |
1483 | 0 | return (_obj->last_vertex && current != _obj->last_vertex->obj) ? obj |
1484 | 0 | : NULL; |
1485 | 0 | else |
1486 | 0 | { |
1487 | 0 | ent->__iterator++; |
1488 | 0 | if (ent->__iterator == _obj->num_owned) |
1489 | 0 | { |
1490 | 0 | ent->__iterator = 0; |
1491 | 0 | return NULL; |
1492 | 0 | } |
1493 | 0 | else |
1494 | 0 | return _obj->vertex |
1495 | 0 | ? dwg_ref_object (dwg, _obj->vertex[ent->__iterator]) |
1496 | 0 | : NULL; |
1497 | 0 | } |
1498 | 0 | } |
1499 | 0 | else |
1500 | 0 | { |
1501 | 0 | LOG_ERROR ("Wrong type %d, has no subentity", type); |
1502 | 0 | } |
1503 | 0 | return NULL; |
1504 | 0 | } |
1505 | | |
1506 | | /** Returns the BLOCK entity owned by the block hdr. |
1507 | | * Only NULL on illegal hdr argument or dwg version. |
1508 | | */ |
1509 | | EXPORT Dwg_Object * |
1510 | | get_first_owned_block (const Dwg_Object *hdr) |
1511 | 35.6k | { |
1512 | 35.6k | Dwg_Data *dwg = hdr->parent; |
1513 | 35.6k | Dwg_Version_Type version = dwg->header.version; |
1514 | 35.6k | const Dwg_Object_BLOCK_HEADER *restrict _hdr |
1515 | 35.6k | = hdr->tio.object->tio.BLOCK_HEADER; |
1516 | 35.6k | if (hdr->fixedtype != DWG_TYPE_BLOCK_HEADER) |
1517 | 0 | { |
1518 | 0 | LOG_ERROR ("Invalid BLOCK_HEADER type %d", hdr->fixedtype); |
1519 | 0 | return NULL; |
1520 | 0 | } |
1521 | | |
1522 | 35.6k | if (_hdr->block_entity) |
1523 | 13.1k | return dwg_ref_object (dwg, _hdr->block_entity); |
1524 | 22.5k | else |
1525 | 22.5k | { |
1526 | 22.5k | Dwg_Object *obj = (Dwg_Object *)hdr; |
1527 | 2.56M | while (obj && obj->fixedtype != DWG_TYPE_BLOCK) |
1528 | 2.54M | obj = dwg_next_object (obj); |
1529 | 22.5k | return obj; |
1530 | 22.5k | } |
1531 | 0 | LOG_ERROR ("Unsupported version %s\n", dwg_version_type (version)); |
1532 | 0 | return NULL; |
1533 | 35.6k | } |
1534 | | |
1535 | | /** Returns the next block object after current owned by the block hdr, or |
1536 | | * NULL. |
1537 | | */ |
1538 | | EXPORT Dwg_Object * |
1539 | | get_next_owned_block (const Dwg_Object *restrict hdr, |
1540 | | const Dwg_Object *restrict current) |
1541 | 0 | { |
1542 | 0 | Dwg_Data *dwg = hdr->parent; |
1543 | 0 | Dwg_Version_Type version = dwg->header.version; |
1544 | 0 | const Dwg_Object_BLOCK_HEADER *restrict _hdr |
1545 | 0 | = hdr->tio.object->tio.BLOCK_HEADER; |
1546 | 0 | if (hdr->fixedtype != DWG_TYPE_BLOCK_HEADER) |
1547 | 0 | { |
1548 | 0 | LOG_ERROR ("Invalid BLOCK_HEADER type %d", hdr->fixedtype); |
1549 | 0 | return NULL; |
1550 | 0 | } |
1551 | | |
1552 | 0 | if (1 || version >= R_13b1) |
1553 | 0 | { |
1554 | 0 | if (!_hdr->endblk_entity |
1555 | 0 | || current->handle.value >= _hdr->endblk_entity->absolute_ref) |
1556 | 0 | return NULL; |
1557 | 0 | return dwg_next_object (current); |
1558 | 0 | } |
1559 | | |
1560 | 0 | LOG_ERROR ("Unsupported version %s\n", dwg_version_type (version)); |
1561 | 0 | return NULL; |
1562 | 0 | } |
1563 | | |
1564 | | /** Returns the next block object until last_entity |
1565 | | * after current owned by the block hdr, or NULL. |
1566 | | */ |
1567 | | EXPORT Dwg_Object * |
1568 | | get_next_owned_block_entity (const Dwg_Object *restrict hdr, |
1569 | | const Dwg_Object *restrict current) |
1570 | 265k | { |
1571 | 265k | Dwg_Data *dwg; |
1572 | 265k | Dwg_Version_Type version; |
1573 | 265k | Dwg_Object_BLOCK_HEADER *restrict _hdr; |
1574 | | |
1575 | 265k | if (hdr->fixedtype != DWG_TYPE_BLOCK_HEADER) |
1576 | 0 | { |
1577 | 0 | LOG_ERROR ("Invalid BLOCK_HEADER type %d", hdr->fixedtype); |
1578 | 0 | return NULL; |
1579 | 0 | } |
1580 | | |
1581 | 265k | dwg = hdr->parent; |
1582 | 265k | version = dwg->header.version; |
1583 | 265k | _hdr = hdr->tio.object->tio.BLOCK_HEADER; |
1584 | | |
1585 | 265k | if (R_13b1 <= version && version <= R_2000) |
1586 | 241k | { |
1587 | 241k | Dwg_Object *obj; |
1588 | 241k | BITCODE_BL max_steps; |
1589 | | /* With r2000 we rather follow the next_entity chain. It may jump around |
1590 | | * the linked list. */ |
1591 | 241k | if (!_hdr->last_entity || current == _hdr->last_entity->obj) |
1592 | 241 | return NULL; |
1593 | | /* Cycle detection: __iterator was reset in get_first_owned_entity */ |
1594 | 240k | _hdr->__iterator++; |
1595 | 240k | max_steps = _hdr->num_owned ? _hdr->num_owned : dwg->num_objects; |
1596 | 240k | if (_hdr->__iterator > max_steps) |
1597 | 36 | { |
1598 | 36 | LOG_WARN ("Cycle in entity link chain for BLOCK_HEADER " FORMAT_HV |
1599 | 36 | "\n", |
1600 | 36 | hdr->handle.value); |
1601 | 36 | return NULL; |
1602 | 36 | } |
1603 | 240k | obj = dwg_next_entity (current); |
1604 | | /* Detect cycle: if the next entity's ownerhandle points to a different |
1605 | | block, the next_entity chain has crossed a block boundary. */ |
1606 | 240k | if (obj && obj->tio.entity && obj->tio.entity->ownerhandle |
1607 | 2.11k | && obj->tio.entity->ownerhandle->absolute_ref != hdr->handle.value) |
1608 | 1.37k | return NULL; |
1609 | 239k | return obj; |
1610 | 240k | } |
1611 | 24.2k | if (version > R_2000 || version < R_13b1) |
1612 | 24.2k | { |
1613 | 24.2k | Dwg_Object *obj; |
1614 | 24.2k | Dwg_Object_Ref *ref; |
1615 | 24.2k | _hdr->__iterator++; |
1616 | 24.2k | if (_hdr->__iterator == _hdr->num_owned) |
1617 | 187 | return NULL; |
1618 | 24.0k | ref = _hdr->entities ? _hdr->entities[_hdr->__iterator] : NULL; |
1619 | 24.0k | obj = ref ? dwg_ref_object (dwg, ref) : NULL; |
1620 | 24.0k | if (version < R_13b1 && obj && obj->fixedtype == DWG_TYPE_JUMP) |
1621 | 0 | return dwg_resolve_jump (obj); |
1622 | 24.0k | else |
1623 | 24.0k | return obj; |
1624 | 24.0k | } |
1625 | | |
1626 | 0 | LOG_ERROR ("Unsupported version %s\n", dwg_version_type (version)); |
1627 | 0 | return NULL; |
1628 | 24.2k | } |
1629 | | |
1630 | | /** Returns the last ENDBLK entity owned by the block hdr. |
1631 | | * Only NULL on illegal hdr argument or dwg version. |
1632 | | */ |
1633 | | EXPORT Dwg_Object * |
1634 | | get_last_owned_block (const Dwg_Object *restrict hdr) |
1635 | 35.6k | { |
1636 | 35.6k | Dwg_Data *dwg = hdr->parent; |
1637 | 35.6k | Dwg_Object_BLOCK_HEADER *restrict _hdr = hdr->tio.object->tio.BLOCK_HEADER; |
1638 | 35.6k | const Dwg_Version_Type version = dwg->header.version; |
1639 | 35.6k | if (hdr->fixedtype != DWG_TYPE_BLOCK_HEADER) |
1640 | 0 | { |
1641 | 0 | LOG_ERROR ("Invalid BLOCK_HEADER type %d", hdr->fixedtype); |
1642 | 0 | return NULL; |
1643 | 0 | } |
1644 | | |
1645 | 35.6k | if (1 || version >= R_13b1) |
1646 | 35.6k | { |
1647 | 35.6k | if (_hdr->endblk_entity && _hdr->endblk_entity->obj) |
1648 | 1.77k | return _hdr->endblk_entity->obj; |
1649 | 33.8k | else |
1650 | 33.8k | { |
1651 | 33.8k | Dwg_Object *obj = (Dwg_Object *)hdr; |
1652 | 5.40M | while (obj && obj->fixedtype != DWG_TYPE_ENDBLK) |
1653 | 5.36M | obj = dwg_next_object (obj); |
1654 | 33.8k | if (obj && obj->fixedtype == DWG_TYPE_ENDBLK) |
1655 | 11.7k | { |
1656 | 11.7k | if (!_hdr->endblk_entity) |
1657 | 6.89k | { |
1658 | 6.89k | _hdr->endblk_entity |
1659 | 6.89k | = (BITCODE_H)calloc (1, sizeof (Dwg_Object_Ref)); |
1660 | 6.89k | if (_hdr->endblk_entity) |
1661 | 6.89k | { |
1662 | 6.89k | _hdr->endblk_entity->obj = obj; |
1663 | 6.89k | _hdr->endblk_entity->handleref.value |
1664 | 6.89k | = _hdr->endblk_entity->absolute_ref |
1665 | 6.89k | = obj->handle.value; |
1666 | 6.89k | } |
1667 | 6.89k | } |
1668 | 4.89k | else if (!_hdr->endblk_entity->obj) |
1669 | 4.89k | _hdr->endblk_entity->obj = obj; |
1670 | 11.7k | } |
1671 | 33.8k | return obj; |
1672 | 33.8k | } |
1673 | 35.6k | } |
1674 | | |
1675 | 0 | LOG_ERROR ("Unsupported version %s\n", dwg_version_type (version)); |
1676 | 0 | return NULL; |
1677 | 35.6k | } |
1678 | | |
1679 | | EXPORT Dwg_Object * |
1680 | | dwg_get_first_object (const Dwg_Data *dwg, const Dwg_Object_Type type) |
1681 | 140k | { |
1682 | 12.5M | for (unsigned i = 0; i < dwg->num_objects; i++) |
1683 | 12.4M | { |
1684 | 12.4M | Dwg_Object *const obj = &dwg->object[i]; |
1685 | 12.4M | if (obj->fixedtype == type && obj->tio.object |
1686 | 73.8k | && obj->tio.object->tio.APPID) |
1687 | 73.8k | return obj; |
1688 | 12.4M | } |
1689 | 66.5k | return NULL; |
1690 | 140k | } |
1691 | | |
1692 | | EXPORT Dwg_Object * |
1693 | | dwg_get_next_object (const Dwg_Data *dwg, const Dwg_Object_Type type, |
1694 | | const BITCODE_RL index) |
1695 | 52.9k | { |
1696 | 7.95M | for (unsigned i = index; i < dwg->num_objects; i++) |
1697 | 7.93M | { |
1698 | 7.93M | Dwg_Object *const obj = &dwg->object[i]; |
1699 | 7.93M | if (obj->fixedtype == type && obj->tio.object |
1700 | 30.1k | && obj->tio.object->tio.APPID) |
1701 | 30.1k | return obj; |
1702 | 7.93M | } |
1703 | 22.7k | return NULL; |
1704 | 52.9k | } |
1705 | | |
1706 | | EXPORT int |
1707 | | dwg_class_is_entity (const Dwg_Class *restrict klass) |
1708 | 2.46k | { |
1709 | 2.46k | return (klass != NULL && (int)klass->item_class_id == 0x1f2) ? 1 : 0; |
1710 | 2.46k | } |
1711 | | |
1712 | | EXPORT int |
1713 | | dwg_obj_is_control (const Dwg_Object *obj) |
1714 | 34.7M | { |
1715 | 34.7M | const unsigned int type = obj->fixedtype; |
1716 | 34.7M | return (obj->supertype == DWG_SUPERTYPE_OBJECT) |
1717 | 9.22M | && (type == DWG_TYPE_BLOCK_CONTROL || type == DWG_TYPE_LAYER_CONTROL |
1718 | 9.11M | || type == DWG_TYPE_STYLE_CONTROL |
1719 | 9.05M | || type == DWG_TYPE_LTYPE_CONTROL || type == DWG_TYPE_VIEW_CONTROL |
1720 | 8.98M | || type == DWG_TYPE_UCS_CONTROL || type == DWG_TYPE_VPORT_CONTROL |
1721 | 8.89M | || type == DWG_TYPE_APPID_CONTROL |
1722 | 8.87M | || type == DWG_TYPE_DIMSTYLE_CONTROL |
1723 | 8.84M | || type == DWG_TYPE_VX_CONTROL); |
1724 | 34.7M | } |
1725 | | |
1726 | | EXPORT int |
1727 | | dwg_obj_is_table (const Dwg_Object *obj) |
1728 | 174 | { |
1729 | 174 | const unsigned int type = obj->fixedtype; |
1730 | 174 | return (obj->supertype == DWG_SUPERTYPE_OBJECT) |
1731 | 2 | && (type == DWG_TYPE_BLOCK_HEADER || type == DWG_TYPE_LAYER |
1732 | 2 | || type == DWG_TYPE_STYLE || type == DWG_TYPE_LTYPE |
1733 | 2 | || type == DWG_TYPE_VIEW || type == DWG_TYPE_UCS |
1734 | 2 | || type == DWG_TYPE_VPORT || type == DWG_TYPE_APPID |
1735 | 2 | || type == DWG_TYPE_DIMSTYLE || type == DWG_TYPE_VX_TABLE_RECORD); |
1736 | 174 | } |
1737 | | |
1738 | | EXPORT int |
1739 | | dwg_obj_is_subentity (const Dwg_Object *obj) |
1740 | 0 | { |
1741 | 0 | const unsigned int type = obj->fixedtype; |
1742 | 0 | return (obj->supertype == DWG_SUPERTYPE_ENTITY) |
1743 | 0 | && (type == DWG_TYPE_ATTRIB || type == DWG_TYPE_VERTEX_2D |
1744 | 0 | || type == DWG_TYPE_VERTEX_3D || type == DWG_TYPE_VERTEX_MESH |
1745 | 0 | || type == DWG_TYPE_VERTEX_PFACE |
1746 | 0 | || type == DWG_TYPE_VERTEX_PFACE_FACE); |
1747 | 0 | } |
1748 | | |
1749 | | EXPORT int |
1750 | | dwg_obj_has_subentity (const Dwg_Object *obj) |
1751 | 0 | { |
1752 | 0 | const unsigned int type = obj->fixedtype; |
1753 | 0 | return (obj->supertype == DWG_SUPERTYPE_ENTITY) |
1754 | 0 | && (type == DWG_TYPE_INSERT || type == DWG_TYPE_MINSERT |
1755 | 0 | || type == DWG_TYPE_POLYLINE_2D || type == DWG_TYPE_POLYLINE_3D |
1756 | 0 | || type == DWG_TYPE_POLYLINE_PFACE |
1757 | 0 | || type == DWG_TYPE_POLYLINE_MESH); |
1758 | 0 | } |
1759 | | |
1760 | | // All entities deriving from 3DSOLID/AcDbModelerGeometry |
1761 | | EXPORT int |
1762 | | dwg_obj_is_3dsolid (const Dwg_Object *obj) |
1763 | 7.71k | { |
1764 | 7.71k | const Dwg_Object_Type type = obj->fixedtype; |
1765 | 7.71k | return (obj->supertype == DWG_SUPERTYPE_OBJECT |
1766 | 890 | && (type == DWG_TYPE_ACSH_BREP_CLASS |
1767 | 884 | || type == DWG_TYPE_ASSOCASMBODYACTIONPARAM)) |
1768 | 7.70k | || (obj->supertype == DWG_SUPERTYPE_ENTITY |
1769 | 6.82k | && (type == DWG_TYPE__3DSOLID || type == DWG_TYPE_REGION |
1770 | 6.79k | || type == DWG_TYPE_BODY || type == DWG_TYPE_EXTRUDEDSURFACE |
1771 | 6.61k | || type == DWG_TYPE_LOFTEDSURFACE |
1772 | 6.61k | || type == DWG_TYPE_NURBSURFACE |
1773 | 6.61k | || type == DWG_TYPE_PLANESURFACE |
1774 | 6.16k | || type == DWG_TYPE_REVOLVEDSURFACE |
1775 | 6.16k | || type == DWG_TYPE_SWEPTSURFACE)); |
1776 | 7.71k | } |
1777 | | |
1778 | | EXPORT int |
1779 | | dwg_obj_is_acsh (const Dwg_Object *obj) |
1780 | 43.5k | { |
1781 | 43.5k | const Dwg_Object_Type type = obj->fixedtype; |
1782 | 43.5k | return (obj->supertype == DWG_SUPERTYPE_OBJECT |
1783 | 8.12k | && (type == DWG_TYPE_ACSH_BOOLEAN_CLASS |
1784 | 8.12k | || type == DWG_TYPE_ACSH_BOX_CLASS |
1785 | 8.12k | || type == DWG_TYPE_ACSH_BREP_CLASS |
1786 | 8.10k | || type == DWG_TYPE_ACSH_CHAMFER_CLASS |
1787 | 8.10k | || type == DWG_TYPE_ACSH_CONE_CLASS |
1788 | 8.10k | || type == DWG_TYPE_ACSH_CYLINDER_CLASS |
1789 | 8.10k | || type == DWG_TYPE_ACSH_EXTRUSION_CLASS |
1790 | 8.10k | || type == DWG_TYPE_ACSH_FILLET_CLASS |
1791 | 8.10k | || type == DWG_TYPE_ACSH_HISTORY_CLASS |
1792 | 8.10k | || type == DWG_TYPE_ACSH_LOFT_CLASS |
1793 | 8.10k | || type == DWG_TYPE_ACSH_PYRAMID_CLASS |
1794 | 8.10k | || type == DWG_TYPE_ACSH_REVOLVE_CLASS |
1795 | 8.10k | || type == DWG_TYPE_ACSH_SPHERE_CLASS |
1796 | 8.10k | || type == DWG_TYPE_ACSH_SWEEP_CLASS |
1797 | 8.10k | || type == DWG_TYPE_ACSH_TORUS_CLASS |
1798 | 8.10k | || type == DWG_TYPE_ACSH_WEDGE_CLASS)); |
1799 | 43.5k | } |
1800 | | |
1801 | | EXPORT Dwg_Section_Type |
1802 | | dwg_section_type (const char *restrict name) |
1803 | 0 | { |
1804 | 0 | if (name == NULL) |
1805 | 0 | return SECTION_UNKNOWN; // but could also be INFO or SYSTEM_MAP |
1806 | 0 | else if (strEQc (name, "AcDb:Header")) |
1807 | 0 | return SECTION_HEADER; |
1808 | 0 | else if (strEQc (name, "AcDb:Classes")) |
1809 | 0 | return SECTION_CLASSES; |
1810 | 0 | else if (strEQc (name, "AcDb:SummaryInfo")) |
1811 | 0 | return SECTION_SUMMARYINFO; |
1812 | 0 | else if (strEQc (name, "AcDb:Preview")) |
1813 | 0 | return SECTION_PREVIEW; |
1814 | 0 | else if (strEQc (name, "AcDb:VBAProject")) |
1815 | 0 | return SECTION_VBAPROJECT; |
1816 | 0 | else if (strEQc (name, "AcDb:AppInfo")) |
1817 | 0 | return SECTION_APPINFO; |
1818 | 0 | else if (strEQc (name, "AcDb:FileDepList")) |
1819 | 0 | return SECTION_FILEDEPLIST; |
1820 | 0 | else if (strEQc (name, "AcDb:RevHistory")) |
1821 | 0 | return SECTION_REVHISTORY; |
1822 | 0 | else if (strEQc (name, "AcDb:Security")) |
1823 | 0 | return SECTION_SECURITY; |
1824 | 0 | else if (strEQc (name, "AcDb:AcDbObjects")) |
1825 | 0 | return SECTION_OBJECTS; |
1826 | 0 | else if (strEQc (name, "AcDb:ObjFreeSpace")) |
1827 | 0 | return SECTION_OBJFREESPACE; |
1828 | 0 | else if (strEQc (name, "AcDb:Template")) |
1829 | 0 | return SECTION_TEMPLATE; |
1830 | 0 | else if (strEQc (name, "AcDb:Handles")) |
1831 | 0 | return SECTION_HANDLES; |
1832 | 0 | else if (strEQc (name, "AcDb:AcDsPrototype_1b")) |
1833 | | // r2013+ |
1834 | 0 | return SECTION_ACDS; // 0xc or 0xd |
1835 | 0 | else if (strEQc (name, "AcDb:AuxHeader")) |
1836 | 0 | return SECTION_AUXHEADER; |
1837 | 0 | else if (strEQc (name, "AcDb:Signature")) |
1838 | 0 | return SECTION_SIGNATURE; |
1839 | 0 | else if (strEQc (name, "AcDb:AppInfoHistory")) |
1840 | | // AC1021 |
1841 | 0 | return SECTION_APPINFOHISTORY; |
1842 | 0 | return SECTION_UNKNOWN; |
1843 | 0 | } |
1844 | | |
1845 | | EXPORT Dwg_Section_Type |
1846 | | dwg_section_wtype (const DWGCHAR *restrict wname) |
1847 | 0 | { |
1848 | 0 | DWGCHAR *wp; |
1849 | 0 | char name[24]; |
1850 | 0 | uint16_t c; |
1851 | 0 | int i = 0; |
1852 | |
|
1853 | 0 | if (wname == NULL) |
1854 | 0 | return SECTION_UNKNOWN; // but could also be INFO or SYSTEM_MAP |
1855 | 0 | wp = (DWGCHAR *)wname; |
1856 | 0 | while ((c = *wp++)) |
1857 | 0 | { |
1858 | 0 | name[i++] = (char)(c & 0xff); |
1859 | 0 | if (i >= 24) |
1860 | 0 | return SECTION_UNKNOWN; |
1861 | 0 | } |
1862 | 0 | name[i] = '\0'; |
1863 | 0 | return dwg_section_type (name); |
1864 | 0 | } |
1865 | | |
1866 | | static const char *const dwg_section_r2004_names[] = { |
1867 | | "UNKNOWN", // 0 |
1868 | | "AcDb:Header", // 1 |
1869 | | "AcDb:AuxHeader", // 2 |
1870 | | "AcDb:Classes", // 3 |
1871 | | "AcDb:Handles", // 4 |
1872 | | "AcDb:Template", // 5 |
1873 | | "AcDb:ObjFreeSpace", // 6 |
1874 | | "AcDb:AcDbObjects", // 7 |
1875 | | "AcDb:RevHistory", // 8 |
1876 | | "AcDb:SummaryInfo", // 9 |
1877 | | "AcDb:Preview", // 10 |
1878 | | "AcDb:AppInfo", // 11 |
1879 | | "AcDb:AppInfoHistory", // 12 |
1880 | | "AcDb:FileDepList", // 13 |
1881 | | "AcDb:Security", // 14 |
1882 | | "AcDb:VBAProject", // 15 |
1883 | | "AcDb:Signature", // 16 |
1884 | | "AcDb:AcDsPrototype_1b", // 17 |
1885 | | "INFO", // 18 |
1886 | | "SYSTEM_MAP", // 19 |
1887 | | }; |
1888 | | static const char *const dwg_section_r13_names[] = { |
1889 | | "Header", // 0 |
1890 | | "Classes", // 1 |
1891 | | "Handles", // 2 |
1892 | | "ObjFreeSpace", // 3 |
1893 | | "Template", // 4 |
1894 | | "AuxHeader", // 5 |
1895 | | "Thumbnail" // 6 |
1896 | | }; |
1897 | | static const char *const dwg_section_r11_names[] = { |
1898 | | "HEADER", // 0 |
1899 | | "BLOCK", // 1 |
1900 | | "LAYER", // 2 |
1901 | | "STYLE", // 3 |
1902 | | "LTYPE", // 4 |
1903 | | "VIEW", // 5 |
1904 | | "UCS", // 6 |
1905 | | "VPORT", // 7 |
1906 | | "APPID", // 8 |
1907 | | "DIMSTYLE", // 9 |
1908 | | "VX" // 10 |
1909 | | }; |
1910 | | |
1911 | | const char * |
1912 | | dwg_section_name (const Dwg_Data *dwg, const unsigned int sec_id) |
1913 | 181k | { |
1914 | 181k | if (dwg->header.version >= R_2004) |
1915 | 174k | { // Dwg_Section_Type |
1916 | 174k | return (sec_id <= SECTION_SYSTEM_MAP) ? dwg_section_r2004_names[sec_id] |
1917 | 174k | : NULL; |
1918 | 174k | } |
1919 | 6.57k | else if (dwg->header.version > R_11) |
1920 | 6.57k | { // Dwg_Section_Type_r13 |
1921 | 6.57k | return (sec_id <= SECTION_THUMBNAIL_R13) ? dwg_section_r13_names[sec_id] |
1922 | 6.57k | : NULL; |
1923 | 6.57k | } |
1924 | 0 | else |
1925 | 0 | { // Dwg_Section_Type_r11 |
1926 | 0 | return (sec_id <= SECTION_VX) ? dwg_section_r11_names[sec_id] : NULL; |
1927 | 0 | } |
1928 | 181k | } |
1929 | | |
1930 | | EXPORT enum RESBUF_VALUE_TYPE |
1931 | | dwg_resbuf_value_type (short gc) |
1932 | 5.94M | { |
1933 | 5.94M | if (gc >= 300) |
1934 | 25.0k | { |
1935 | 25.0k | if (gc >= 440) |
1936 | 10.5k | { |
1937 | 10.5k | if (gc >= 1000) // 1000-1071 |
1938 | 7.04k | { |
1939 | 7.04k | if (gc == 1004) |
1940 | 153 | return DWG_VT_BINARY; |
1941 | 6.89k | if (gc <= 1009) |
1942 | 2.06k | return DWG_VT_STRING; |
1943 | 4.82k | if (gc <= 1039) |
1944 | 266 | return DWG_VT_POINT3D; |
1945 | 4.56k | if (gc <= 1042) |
1946 | 30 | return DWG_VT_REAL; |
1947 | 4.53k | if (gc <= 1069) |
1948 | 0 | return DWG_VT_POINT3D; |
1949 | 4.53k | if (gc <= 1070) |
1950 | 381 | return DWG_VT_INT16; |
1951 | 4.14k | if (gc == 1071) |
1952 | 0 | return DWG_VT_INT32; |
1953 | 4.14k | } |
1954 | 3.49k | else // 440-999 |
1955 | 3.49k | { |
1956 | 3.49k | if (gc <= 459) |
1957 | 403 | return DWG_VT_INT32; |
1958 | 3.09k | if (gc <= 469) |
1959 | 50 | return DWG_VT_REAL; |
1960 | 3.04k | if (gc <= 479) |
1961 | 635 | return DWG_VT_STRING; |
1962 | 2.40k | if (gc <= 998) |
1963 | 2.30k | return DWG_VT_INVALID; |
1964 | 104 | if (gc == 999) |
1965 | 104 | return DWG_VT_STRING; // lgtm [cpp/constant-comparison] |
1966 | 104 | } |
1967 | 10.5k | } |
1968 | 14.4k | else // <440 |
1969 | 14.4k | { |
1970 | 14.4k | if (gc >= 390) // 390-439 |
1971 | 1.07k | { |
1972 | 1.07k | if (gc <= 399) |
1973 | 260 | return DWG_VT_HANDLE; |
1974 | 816 | if (gc <= 409) |
1975 | 0 | return DWG_VT_INT16; |
1976 | 816 | if (gc <= 419) |
1977 | 50 | return DWG_VT_STRING; |
1978 | 766 | if (gc <= 429) |
1979 | 11 | return DWG_VT_INT32; |
1980 | 755 | if (gc <= 439) |
1981 | 755 | return DWG_VT_STRING; // lgtm [cpp/constant-comparison] |
1982 | 755 | } |
1983 | 13.4k | else // 330-389 |
1984 | 13.4k | { |
1985 | 13.4k | if (gc <= 309) |
1986 | 232 | return DWG_VT_STRING; |
1987 | 13.1k | if (gc <= 319) |
1988 | 4.92k | return DWG_VT_BINARY; |
1989 | 8.26k | if (gc <= 329) |
1990 | 441 | return DWG_VT_HANDLE; |
1991 | | /* 330-340 SoftPointer, 340-349 HardPointer |
1992 | | 350-359 SoftOwner, 360-369 HardOwner */ |
1993 | 7.82k | if (gc <= 369) |
1994 | 3.53k | return DWG_VT_OBJECTID; |
1995 | 4.29k | if (gc <= 389) |
1996 | 4.29k | return DWG_VT_INT16; // lgtm [cpp/constant-comparison] |
1997 | 4.29k | } |
1998 | 14.4k | } |
1999 | 25.0k | } |
2000 | 5.91M | else if (gc >= 105) |
2001 | 47.1k | { |
2002 | 47.1k | if (gc >= 210) // 210-299 |
2003 | 33.0k | { |
2004 | 33.0k | if (gc <= 269) |
2005 | 8.97k | return DWG_VT_POINT3D; |
2006 | 24.1k | if (gc <= 279) |
2007 | 6.93k | return DWG_VT_INT16; |
2008 | 17.1k | if (gc <= 289) |
2009 | 11.2k | return DWG_VT_INT8; |
2010 | 5.90k | if (gc <= 299) |
2011 | 5.90k | return DWG_VT_BOOL; // lgtm [cpp/constant-comparison] |
2012 | 5.90k | } |
2013 | 14.0k | else // 105-209 |
2014 | 14.0k | { |
2015 | 14.0k | if (gc == 105) |
2016 | 0 | return DWG_VT_HANDLE; |
2017 | 14.0k | if (gc <= 109) |
2018 | 0 | return DWG_VT_INVALID; |
2019 | 14.0k | if (gc <= 139) |
2020 | 162 | return DWG_VT_POINT3D; |
2021 | 13.8k | if (gc <= 149) |
2022 | 163 | return DWG_VT_REAL; |
2023 | 13.6k | if (gc <= 169) // e.g. REQUIREDVERSIONS 160 r2013+ |
2024 | 7.59k | return DWG_VT_INT64; |
2025 | 6.09k | if (gc <= 179) |
2026 | 6.07k | return DWG_VT_INT16; |
2027 | 12 | if (gc <= 209) |
2028 | 12 | return DWG_VT_INVALID; // lgtm [cpp/constant-comparison] |
2029 | 12 | } |
2030 | 47.1k | } |
2031 | 5.86M | else // <105 |
2032 | 5.86M | { |
2033 | 5.86M | if (gc >= 38) // 38-102 |
2034 | 5.70M | { |
2035 | 5.70M | if (gc <= 59) |
2036 | 4.10k | return DWG_VT_REAL; |
2037 | 5.70M | if (gc <= 79) |
2038 | 4.48M | return DWG_VT_INT16; |
2039 | 1.21M | if (gc <= 99) |
2040 | 1.21M | return DWG_VT_INT32; |
2041 | 897 | if (gc <= 102) |
2042 | 897 | return DWG_VT_STRING; |
2043 | 897 | } |
2044 | 161k | else // 0-37 |
2045 | 161k | { |
2046 | 161k | if (gc < 0) |
2047 | 1.74k | return DWG_VT_HANDLE; |
2048 | 159k | if (gc <= 4) |
2049 | 140k | return DWG_VT_STRING; |
2050 | 19.3k | if (gc == 5) |
2051 | 6.53k | return DWG_VT_HANDLE; |
2052 | 12.7k | if (gc <= 9) |
2053 | 10.4k | return DWG_VT_STRING; // but 9 never TU |
2054 | 2.32k | if (gc <= 37) |
2055 | 2.32k | return DWG_VT_POINT3D; // lgtm [cpp/constant-comparison] |
2056 | 2.32k | } |
2057 | 5.86M | } |
2058 | 4.14k | return DWG_VT_INVALID; |
2059 | 5.94M | } |
2060 | | |
2061 | | // See acdb.h: 100th of a mm, enum of |
2062 | | const int lweights[] = { 0, |
2063 | | 5, |
2064 | | 9, |
2065 | | 13, |
2066 | | 15, |
2067 | | 18, |
2068 | | 20, |
2069 | | 25, |
2070 | | 30, |
2071 | | 35, |
2072 | | 40, |
2073 | | 50, |
2074 | | 53, |
2075 | | 60, |
2076 | | 70, |
2077 | | 80, |
2078 | | 90, |
2079 | | 100, |
2080 | | 106, |
2081 | | 120, |
2082 | | /*20:*/ 140, |
2083 | | 158, |
2084 | | 200, |
2085 | | 211, |
2086 | | /*illegal/reserved:*/ 0, |
2087 | | 0, |
2088 | | 0, |
2089 | | 0, |
2090 | | /*28:*/ 0, // 0x1c |
2091 | | /*29:*/ -1, // 0x1d BYLAYER |
2092 | | -2, // BYBLOCK |
2093 | | -3 }; // BYLWDEFAULT |
2094 | | |
2095 | | EXPORT int |
2096 | | dxf_cvt_lweight (const BITCODE_BSd value) |
2097 | 130k | { |
2098 | 130k | return lweights[value % 32]; |
2099 | 130k | } |
2100 | | |
2101 | | EXPORT BITCODE_BSd |
2102 | | dxf_revcvt_lweight (const int lw) |
2103 | 3.28k | { |
2104 | 8.53k | for (BITCODE_BSd i = 0; i < (BITCODE_BSd)ARRAY_SIZE (lweights); i++) |
2105 | 8.53k | if (lweights[i] == lw) |
2106 | 3.28k | return i; |
2107 | 0 | return 0; |
2108 | 3.28k | } |
2109 | | |
2110 | | void |
2111 | | dwg_set_handle_size (Dwg_Handle *restrict hdl) |
2112 | 2.93M | { |
2113 | 2.93M | if (hdl->value) |
2114 | 2.90M | { |
2115 | 2.90M | int i; |
2116 | 2.90M | unsigned char *val; |
2117 | 2.90M | memset (&val, 0, sizeof (val)); |
2118 | 2.90M | val = (unsigned char *)&hdl->value; |
2119 | | #ifdef WORDS_BIGENDIAN |
2120 | | // the first NULL |
2121 | | for (i = 0; i < (int)sizeof (hdl->value); i++) |
2122 | | if (!val[i]) |
2123 | | break; |
2124 | | #else |
2125 | | // vs. the last non-null |
2126 | 20.2M | for (i = sizeof (hdl->value) - 1; i >= 0; i--) |
2127 | 20.2M | if (val[i]) |
2128 | 2.90M | break; |
2129 | 2.90M | #endif |
2130 | 2.90M | hdl->size = i + 1; |
2131 | | // printf("handle_size %lu => %u\n", hdl->value, hdl->size); |
2132 | 2.90M | } |
2133 | 25.7k | else |
2134 | 25.7k | hdl->size = 0; |
2135 | 2.93M | } |
2136 | | |
2137 | | /** For encode: |
2138 | | * May need obj to shorten the code to a relative offset, but not in |
2139 | | * header_vars. There obj is NULL. |
2140 | | */ |
2141 | | EXPORT int |
2142 | | dwg_add_handle (Dwg_Handle *restrict hdl, const BITCODE_RC code, |
2143 | | const BITCODE_RLL absref, const Dwg_Object *restrict obj) |
2144 | 2.24M | { |
2145 | 2.24M | int offset = obj ? (absref - (int)obj->handle.value) : 0; |
2146 | 2.24M | hdl->code = code; |
2147 | 2.24M | hdl->value = absref; |
2148 | 2.24M | if (obj && (code == 0 || !offset) && absref) // only if same obj |
2149 | 863k | { |
2150 | 863k | Dwg_Data *dwg = obj->parent; |
2151 | 863k | uint64_t hashkey; |
2152 | 863k | assert (dwg); |
2153 | 863k | loglevel = dwg->opts & DWG_OPTS_LOGLEVEL; |
2154 | 863k | if (!dwg->object_map) // for dwg_add_document() |
2155 | 0 | dwg->object_map = hash_new (100); |
2156 | | // check if this handle already exists |
2157 | 863k | hashkey = hash_get (dwg->object_map, absref); |
2158 | 863k | if (HASH_NOT_FOUND != hashkey && hashkey != obj->index) |
2159 | 17.0k | { |
2160 | 17.0k | LOG_ERROR ("Duplicate handle " FORMAT_HV " for object " FORMAT_RL |
2161 | 17.0k | " already points to object %" PRIu64, |
2162 | 17.0k | absref, obj->index, hashkey); |
2163 | 17.0k | return 1; |
2164 | 17.0k | } |
2165 | 846k | else if (HASH_NOT_FOUND == hashkey) |
2166 | 825k | hash_set (dwg->object_map, absref, (uint64_t)obj->index); |
2167 | 846k | LOG_HANDLE ("object_map{" FORMAT_HV "} = %u\n", absref, obj->index); |
2168 | 846k | } |
2169 | | |
2170 | 2.22M | dwg_set_handle_size (hdl); |
2171 | 2.22M | if ((code == 4 || code > 5) && obj && absref) |
2172 | 663k | { |
2173 | | // change code to 6.0.0 or 8.0.0 |
2174 | 663k | if (offset == 1) |
2175 | 1.90k | { |
2176 | 1.90k | hdl->code = 6; |
2177 | 1.90k | hdl->value = 0; |
2178 | 1.90k | hdl->size = 0; |
2179 | 1.90k | } |
2180 | 661k | else if (offset == -1) |
2181 | 2.63k | { |
2182 | 2.63k | hdl->code = 8; |
2183 | 2.63k | hdl->value = 0; |
2184 | 2.63k | hdl->size = 0; |
2185 | 2.63k | } |
2186 | 658k | else if (offset > 0) |
2187 | 47.6k | { |
2188 | 47.6k | hdl->code = 10; |
2189 | 47.6k | hdl->value = offset; |
2190 | 47.6k | dwg_set_handle_size (hdl); |
2191 | 47.6k | } |
2192 | 611k | else if (offset < 0) |
2193 | 611k | { |
2194 | 611k | hdl->code = 12; |
2195 | 611k | if ((unsigned)offset == 0x80000000) // invalid negation |
2196 | 0 | { |
2197 | 0 | LOG_ERROR ("HANDLE 12 overflow for object " FORMAT_RL, |
2198 | 0 | obj->index); |
2199 | 0 | hdl->value = 0; |
2200 | 0 | return 1; |
2201 | 0 | } |
2202 | 611k | else |
2203 | 611k | hdl->value = -offset; |
2204 | 611k | dwg_set_handle_size (hdl); |
2205 | 611k | } |
2206 | 663k | } |
2207 | 2.22M | return 0; |
2208 | 2.22M | } |
2209 | | |
2210 | | // Returns an existing ref with the same ownership (hard/soft, owner/pointer) |
2211 | | // or creates it. May return a freshly allocated ref via dwg_new_ref. |
2212 | | EXPORT Dwg_Object_Ref * |
2213 | | dwg_add_handleref (Dwg_Data *restrict dwg, const BITCODE_RC code, |
2214 | | const BITCODE_RLL absref, const Dwg_Object *restrict obj) |
2215 | 1.52M | { |
2216 | 1.52M | Dwg_Object_Ref *ref; |
2217 | 1.52M | loglevel = dwg->opts & DWG_OPTS_LOGLEVEL; |
2218 | | // ENTITY, DICTIONARY, XRECORD or class may need to be relative. |
2219 | | // prev_entity/next_entity also |
2220 | | // GROUP needs to be absolute. DICTIONARYVAR absolute. |
2221 | | // skip the search for existing absolute ref then. |
2222 | 1.52M | if (code > 5 |
2223 | 1.52M | || (code == 4 && obj |
2224 | 663k | && ((obj->supertype == DWG_SUPERTYPE_ENTITY |
2225 | 21.2k | || obj->fixedtype == DWG_TYPE_DICTIONARY |
2226 | 21.2k | || obj->fixedtype == DWG_TYPE_XRECORD |
2227 | 21.2k | || (obj->fixedtype > DWG_TYPE_GROUP |
2228 | 0 | && obj->fixedtype != DWG_TYPE_DICTIONARYVAR))))) |
2229 | 642k | ; |
2230 | 883k | else if (dwg->header.from_version > R_12 || absref) |
2231 | 866k | { |
2232 | | // search of this code-absref pair already exists |
2233 | | // lsearch is slow,use bsearch |
2234 | | /* |
2235 | | for (BITCODE_BL i = 0; i < dwg->num_object_refs; i++) |
2236 | | { |
2237 | | Dwg_Object_Ref *refi = dwg->object_ref[i]; |
2238 | | if (refi->absolute_ref == absref && refi->handleref.code == code) |
2239 | | { |
2240 | | LOG_HANDLE ("[existing handleref " FORMAT_REF "][%u] ", |
2241 | | ARGS_REF (refi), (unsigned)i) |
2242 | | return refi; |
2243 | | } |
2244 | | } |
2245 | | */ |
2246 | 866k | Dwg_Object_Ref *refi |
2247 | 866k | = (Dwg_Object_Ref *)ordered_ref_find (dwg, code, absref); |
2248 | 866k | if (NULL != refi) |
2249 | 90.7k | { |
2250 | 90.7k | LOG_HANDLE ("[use handleref " FORMAT_REF "] ", ARGS_REF (refi)); |
2251 | 90.7k | return refi; |
2252 | 90.7k | } |
2253 | 866k | } |
2254 | | // else create a new global ref |
2255 | 1.43M | ref = dwg_new_ref (dwg); |
2256 | 1.43M | ref->handleref.is_global = 1; |
2257 | 1.43M | dwg_add_handle (&ref->handleref, code, absref, obj); |
2258 | 1.43M | if (dwg->header.from_version <= R_12) |
2259 | 1.42M | { |
2260 | 1.42M | ref->handleref.size = 2; |
2261 | 1.42M | if (dwg->header_vars.HANDSEED && dwg->header_vars.HANDSEED->absolute_ref |
2262 | 1.04M | && absref > dwg->header_vars.HANDSEED->absolute_ref |
2263 | 459k | && absref <= 0xFFFFFFFF) |
2264 | 321k | { |
2265 | 321k | dwg->header_vars.HANDSEED->absolute_ref = absref; |
2266 | 321k | } |
2267 | 1.42M | } |
2268 | 1.43M | ref->absolute_ref = absref; |
2269 | 1.43M | ref->obj = NULL; |
2270 | 1.43M | LOG_HANDLE ("[add handleref " FORMAT_REF "] ", ARGS_REF (ref)); |
2271 | | // fill ->obj later |
2272 | 1.43M | ordered_ref_add (dwg, ref); |
2273 | 1.43M | return ref; |
2274 | 1.52M | } |
2275 | | |
2276 | | /** Return a link to the global ref or a new one. Or a NULLHDL. */ |
2277 | | EXPORT Dwg_Object_Ref * |
2278 | | dwg_dup_handleref (Dwg_Data *restrict dwg, const Dwg_Object_Ref *restrict ref) |
2279 | 0 | { |
2280 | 0 | if (ref) |
2281 | 0 | return dwg_add_handleref (dwg, ref->handleref.code, ref->absolute_ref, |
2282 | 0 | NULL); |
2283 | 0 | else |
2284 | 0 | return dwg_add_handleref (dwg, 5, 0, NULL); |
2285 | 0 | } |
2286 | | |
2287 | | // Creates a non-global, free'able handle ref. |
2288 | | EXPORT Dwg_Object_Ref * |
2289 | | dwg_add_handleref_free (const BITCODE_RC code, const BITCODE_RLL absref) |
2290 | 0 | { |
2291 | 0 | Dwg_Object_Ref *ref = (Dwg_Object_Ref *)calloc (1, sizeof (Dwg_Object_Ref)); |
2292 | 0 | dwg_add_handle (&ref->handleref, code, absref, NULL); |
2293 | 0 | return ref; |
2294 | 0 | } |
2295 | | |
2296 | | BITCODE_RLL |
2297 | | dwg_new_handseed (Dwg_Data *restrict dwg) |
2298 | 2.41k | { |
2299 | 2.41k | if (!dwg->header_vars.HANDSEED) |
2300 | 819 | dwg_init_handseed (dwg); |
2301 | 2.41k | dwg->header_vars.HANDSEED->handleref.value++; |
2302 | 2.41k | dwg->header_vars.HANDSEED->absolute_ref++; |
2303 | 2.41k | return dwg->header_vars.HANDSEED->absolute_ref - 1; |
2304 | 2.41k | } |
2305 | | |
2306 | | // Not checking the header_vars entry, only searching the objects |
2307 | | // Returning a hardowner ref (code 3) to it, as stored in header_vars. |
2308 | | EXPORT BITCODE_H |
2309 | | dwg_find_table_control (Dwg_Data *restrict dwg, const char *restrict table) |
2310 | 111k | { |
2311 | 111k | BITCODE_BL i; |
2312 | 111k | loglevel = dwg->opts & DWG_OPTS_LOGLEVEL; |
2313 | 33.2M | for (i = 0; i < dwg->num_objects; i++) |
2314 | 33.1M | { |
2315 | 33.1M | if (dwg->object[i].name && strEQ (dwg->object[i].name, table)) |
2316 | 12.0k | { |
2317 | 12.0k | Dwg_Handle *hdl = &dwg->object[i].handle; |
2318 | 12.0k | if (hdl->value) |
2319 | 3.31k | return dwg_add_handleref (dwg, 3, hdl->value, NULL); |
2320 | 8.75k | else |
2321 | 8.75k | { |
2322 | | // probably importing from a minimal DXF |
2323 | 8.75k | LOG_TRACE ("dwg_find_table_control: table control object %s has " |
2324 | 8.75k | "no handle\n", |
2325 | 8.75k | table); |
2326 | 8.75k | return NULL; |
2327 | 8.75k | } |
2328 | 12.0k | } |
2329 | 33.1M | } |
2330 | | // if we haven't read all objects yet, ignore this error |
2331 | 99.0k | LOG_TRACE ("dwg_find_table_control: table control object %s not found\n", |
2332 | 99.0k | table); |
2333 | 99.0k | return NULL; |
2334 | 111k | } |
2335 | | |
2336 | | // Searching for a named dictionary entry, name is utf8. |
2337 | | // Returning a hardpointer ref (5) to it, as stored in header_vars. |
2338 | | // Usually another dictionary. |
2339 | | EXPORT BITCODE_H |
2340 | | dwg_find_dictionary (Dwg_Data *restrict dwg, const char *restrict name) |
2341 | 255 | { |
2342 | | // The NOD (Named Object Dict) must be always the very first DICTIONARY |
2343 | 255 | Dwg_Object_DICTIONARY *nod; |
2344 | 255 | Dwg_Object *obj = dwg_get_first_object (dwg, DWG_TYPE_DICTIONARY); |
2345 | 255 | loglevel = dwg->opts & DWG_OPTS_LOGLEVEL; |
2346 | 255 | if (!obj || !obj->tio.object || obj->fixedtype != DWG_TYPE_DICTIONARY) |
2347 | 192 | { |
2348 | 192 | LOG_ERROR ("dwg_find_dictionary: 1st NOD DICTIONARY not found"); |
2349 | 192 | return NULL; |
2350 | 192 | } |
2351 | 63 | nod = obj->tio.object->tio.DICTIONARY; |
2352 | 561 | for (BITCODE_BL j = 0; j < nod->numitems; j++) |
2353 | 498 | { |
2354 | 498 | ATTRIBUTE_ALIGNED (2) BITCODE_T u8; |
2355 | 498 | if (!nod->texts || !nod->itemhandles) |
2356 | 496 | continue; |
2357 | 2 | u8 = nod->texts[j]; |
2358 | 2 | if (!u8) |
2359 | 0 | continue; |
2360 | 2 | if (IS_FROM_TU_DWG (dwg)) |
2361 | 0 | u8 = bit_convert_TU ((BITCODE_TU)u8); |
2362 | 2 | if (u8 && strEQ (u8, name)) |
2363 | 0 | { |
2364 | 0 | Dwg_Object_Ref *ref = nod->itemhandles[j]; |
2365 | 0 | if (!ref) |
2366 | 0 | continue; |
2367 | | // relative? (8.0.0, 6.0.0, ...) |
2368 | 0 | dwg_resolve_handleref (ref, obj); |
2369 | 0 | if (IS_FROM_TU_DWG (dwg)) |
2370 | 0 | free (u8); |
2371 | 0 | return dwg_add_handleref (dwg, 5, ref->absolute_ref, NULL); |
2372 | 0 | } |
2373 | 2 | if (IS_FROM_TU_DWG (dwg)) |
2374 | 0 | free (u8); |
2375 | 2 | } |
2376 | 63 | LOG_TRACE ("dwg_find_dictionary: DICTIONARY with %s not found\n", name); |
2377 | 63 | return NULL; |
2378 | 63 | } |
2379 | | |
2380 | | // find the named dict entry |
2381 | | EXPORT BITCODE_H |
2382 | | dwg_find_dicthandle (Dwg_Data *restrict dwg, BITCODE_H dict, |
2383 | | const char *restrict name) |
2384 | 0 | { |
2385 | 0 | BITCODE_BL i; |
2386 | 0 | Dwg_Object_DICTIONARY *_obj; |
2387 | 0 | Dwg_Object *obj = dwg_resolve_handle (dwg, dict->absolute_ref); |
2388 | |
|
2389 | 0 | loglevel = dwg->opts & DWG_OPTS_LOGLEVEL; |
2390 | 0 | if (!obj || !obj->tio.object) |
2391 | 0 | { |
2392 | 0 | LOG_TRACE ("dwg_find_dicthandle: Could not resolve dict " FORMAT_REF |
2393 | 0 | "\n", |
2394 | 0 | ARGS_REF (dict)); |
2395 | 0 | return NULL; |
2396 | 0 | } |
2397 | 0 | if (obj->fixedtype != DWG_TYPE_DICTIONARY) |
2398 | 0 | { |
2399 | 0 | LOG_ERROR ("dwg_find_dicthandle: dict not a DICTIONARY\n"); |
2400 | 0 | return NULL; |
2401 | 0 | } |
2402 | | |
2403 | 0 | _obj = obj->tio.object->tio.DICTIONARY; |
2404 | 0 | if (!_obj->numitems) |
2405 | 0 | return NULL; |
2406 | 0 | for (i = 0; i < _obj->numitems; i++) |
2407 | 0 | { |
2408 | 0 | ATTRIBUTE_ALIGNED (2) BITCODE_T *texts = _obj->texts; |
2409 | 0 | BITCODE_H *hdlv = _obj->itemhandles; |
2410 | |
|
2411 | 0 | if (!hdlv || !texts || !texts[i]) |
2412 | 0 | continue; |
2413 | 0 | if (IS_FROM_TU_DWG (dwg)) |
2414 | 0 | { |
2415 | 0 | if (bit_eq_TU (name, (BITCODE_TU)texts[i])) |
2416 | 0 | return hdlv[i]; |
2417 | 0 | } |
2418 | 0 | else |
2419 | 0 | { |
2420 | 0 | if (strEQ (name, texts[i])) |
2421 | 0 | return hdlv[i]; |
2422 | 0 | } |
2423 | 0 | } |
2424 | 0 | return NULL; |
2425 | 0 | } |
2426 | | |
2427 | | // find dict entry and match its name |
2428 | | EXPORT BITCODE_H |
2429 | | dwg_find_dicthandle_objname (Dwg_Data *restrict dwg, BITCODE_H dict, |
2430 | | const char *restrict name) |
2431 | 0 | { |
2432 | 0 | BITCODE_BL i; |
2433 | 0 | Dwg_Object_DICTIONARY *_obj; |
2434 | 0 | Dwg_Object *obj = dwg_resolve_handle (dwg, dict->absolute_ref); |
2435 | |
|
2436 | 0 | loglevel = dwg->opts & DWG_OPTS_LOGLEVEL; |
2437 | 0 | if (!obj || !obj->tio.object) |
2438 | 0 | { |
2439 | 0 | LOG_TRACE ("dwg_find_dicthandle: Could not resolve dict " FORMAT_REF |
2440 | 0 | "\n", |
2441 | 0 | ARGS_REF (dict)); |
2442 | 0 | return NULL; |
2443 | 0 | } |
2444 | 0 | if (obj->fixedtype != DWG_TYPE_DICTIONARY) |
2445 | 0 | { |
2446 | 0 | LOG_ERROR ("dwg_find_dicthandle: dict not a DICTIONARY\n"); |
2447 | 0 | return NULL; |
2448 | 0 | } |
2449 | | |
2450 | 0 | _obj = obj->tio.object->tio.DICTIONARY; |
2451 | 0 | if (!_obj->numitems) |
2452 | 0 | return 0; |
2453 | 0 | for (i = 0; i < _obj->numitems; i++) |
2454 | 0 | { |
2455 | 0 | char *hdlname; |
2456 | 0 | BITCODE_H *hdlv = _obj->itemhandles; |
2457 | 0 | Dwg_Object *hobj; |
2458 | 0 | Dwg_Object_APPID *_o; // just some random type |
2459 | 0 | int isnew = 0; |
2460 | 0 | bool ok; |
2461 | |
|
2462 | 0 | if (!hdlv || !hdlv[i]) |
2463 | 0 | continue; |
2464 | 0 | hobj = dwg_resolve_handle (dwg, hdlv[i]->absolute_ref); |
2465 | 0 | if (!hobj || !hobj->tio.object || !hobj->tio.object->tio.APPID |
2466 | 0 | || !hobj->name) |
2467 | 0 | continue; |
2468 | 0 | _o = hobj->tio.object->tio.APPID; |
2469 | 0 | ok = dwg_dynapi_entity_utf8text (_o, hobj->name, "name", &hdlname, |
2470 | 0 | &isnew, NULL); |
2471 | 0 | LOG_HANDLE (" %s.%s[%d] => %s.name: %s\n", obj->name, "entries", i, |
2472 | 0 | hobj->name, hdlname ? hdlname : "NULL"); |
2473 | 0 | if (ok && hdlname |
2474 | 0 | && (strEQ (name, hdlname) || !strcasecmp (name, hdlname))) |
2475 | 0 | { |
2476 | 0 | if (isnew) |
2477 | 0 | free (hdlname); |
2478 | 0 | return hdlv[i]; |
2479 | 0 | } |
2480 | 0 | if (ok && isnew && hdlname) |
2481 | 0 | free (hdlname); |
2482 | 0 | } |
2483 | 0 | return NULL; |
2484 | 0 | } |
2485 | | |
2486 | | /* Return the first object of the given type. */ |
2487 | | Dwg_Object * |
2488 | | dwg_find_first_type (const Dwg_Data *restrict dwg, |
2489 | | const enum DWG_OBJECT_TYPE type) |
2490 | 13.2k | { |
2491 | 1.15M | for (BITCODE_BL i = 0; i < dwg->num_objects; i++) |
2492 | 1.15M | { |
2493 | 1.15M | if (dwg->object[i].fixedtype == type) |
2494 | 10.9k | return &dwg->object[i]; |
2495 | 1.15M | } |
2496 | 2.27k | return NULL; |
2497 | 13.2k | } |
2498 | | |
2499 | | /* Return the last object of the given type. */ |
2500 | | Dwg_Object * |
2501 | | dwg_find_last_type (const Dwg_Data *restrict dwg, |
2502 | | const enum DWG_OBJECT_TYPE type) |
2503 | 0 | { |
2504 | 0 | if (dwg->num_objects) |
2505 | 0 | { |
2506 | 0 | for (BITCODE_BL i = dwg->num_objects - 1; i != 0; i--) |
2507 | 0 | { |
2508 | 0 | if (dwg->object[i].fixedtype == type) |
2509 | 0 | return &dwg->object[i]; |
2510 | 0 | } |
2511 | 0 | if (dwg->object[0].fixedtype == type) |
2512 | 0 | return &dwg->object[0]; |
2513 | 0 | } |
2514 | 0 | return NULL; |
2515 | 0 | } |
2516 | | |
2517 | | /* Return the handle of the first object of the given type. */ |
2518 | | Dwg_Handle * |
2519 | | dwg_find_first_type_handle (const Dwg_Data *restrict dwg, |
2520 | | const enum DWG_OBJECT_TYPE type) |
2521 | 6.65k | { |
2522 | 2.35M | for (BITCODE_BL i = 0; i < dwg->num_objects; i++) |
2523 | 2.34M | { |
2524 | 2.34M | if (dwg->object[i].fixedtype == type) |
2525 | 0 | return &dwg->object[i].handle; |
2526 | 2.34M | } |
2527 | 6.65k | return NULL; |
2528 | 6.65k | } |
2529 | | |
2530 | | BITCODE_H |
2531 | | dwg_find_tablehandle_silent (Dwg_Data *restrict dwg, const char *restrict name, |
2532 | | const char *restrict table) |
2533 | 15.0k | { |
2534 | 15.0k | BITCODE_H ref; |
2535 | 15.0k | int oldopts = dwg->opts; |
2536 | 15.0k | dwg->opts &= ~(DWG_OPTS_LOGLEVEL); |
2537 | 15.0k | loglevel = 0; |
2538 | | |
2539 | 15.0k | ref = dwg_find_tablehandle (dwg, name, table); |
2540 | | |
2541 | 15.0k | dwg->opts = oldopts; |
2542 | 15.0k | loglevel = oldopts & DWG_OPTS_LOGLEVEL; |
2543 | 15.0k | return ref; |
2544 | 15.0k | } |
2545 | | |
2546 | | // return the matching _CONTROL table, DICTIONARY entry, or NULL |
2547 | | EXPORT BITCODE_H |
2548 | | dwg_ctrl_table (Dwg_Data *restrict dwg, const char *restrict table) |
2549 | 237k | { |
2550 | 237k | BITCODE_H ctrl = NULL; |
2551 | 237k | Dwg_Header_Variables *vars = &dwg->header_vars; |
2552 | | |
2553 | 237k | if (!dwg || !table) |
2554 | 0 | return NULL; |
2555 | 237k | if (strEQc (table, "BLOCK") || strEQc (table, "BLOCK_HEADER")) |
2556 | 33.9k | { |
2557 | 33.9k | if (!(ctrl = vars->BLOCK_CONTROL_OBJECT)) |
2558 | 4.14k | vars->BLOCK_CONTROL_OBJECT = ctrl |
2559 | 4.14k | = dwg_find_table_control (dwg, "BLOCK_CONTROL"); |
2560 | 33.9k | } |
2561 | 203k | else if (strEQc (table, "LAYER")) |
2562 | 5.69k | { |
2563 | 5.69k | if (!(ctrl = vars->LAYER_CONTROL_OBJECT)) |
2564 | 110 | vars->LAYER_CONTROL_OBJECT = ctrl |
2565 | 110 | = dwg_find_table_control (dwg, "LAYER_CONTROL"); |
2566 | 5.69k | } |
2567 | 197k | else if (strEQc (table, "STYLE")) |
2568 | 1.22k | { |
2569 | 1.22k | if (!(ctrl = vars->STYLE_CONTROL_OBJECT)) |
2570 | 1.11k | vars->STYLE_CONTROL_OBJECT = ctrl |
2571 | 1.11k | = dwg_find_table_control (dwg, "STYLE_CONTROL"); |
2572 | 1.22k | } |
2573 | 196k | else if (strEQc (table, "LTYPE")) |
2574 | 60.9k | { |
2575 | 60.9k | if (!(ctrl = vars->LTYPE_CONTROL_OBJECT)) |
2576 | 33.6k | vars->LTYPE_CONTROL_OBJECT = ctrl |
2577 | 33.6k | = dwg_find_table_control (dwg, "LTYPE_CONTROL"); |
2578 | 60.9k | } |
2579 | 135k | else if (strEQc (table, "VIEW")) |
2580 | 131k | { |
2581 | 131k | if (!(ctrl = vars->VIEW_CONTROL_OBJECT)) |
2582 | 66.2k | vars->VIEW_CONTROL_OBJECT = ctrl |
2583 | 66.2k | = dwg_find_table_control (dwg, "VIEW_CONTROL"); |
2584 | 131k | } |
2585 | 4.09k | else if (strEQc (table, "UCS")) |
2586 | 1.23k | { |
2587 | 1.23k | if (!(ctrl = vars->UCS_CONTROL_OBJECT)) |
2588 | 921 | vars->UCS_CONTROL_OBJECT = ctrl |
2589 | 921 | = dwg_find_table_control (dwg, "UCS_CONTROL"); |
2590 | 1.23k | } |
2591 | 2.85k | else if (strEQc (table, "VPORT")) |
2592 | 9 | { |
2593 | 9 | if (!(ctrl = vars->VPORT_CONTROL_OBJECT)) |
2594 | 3 | vars->VPORT_CONTROL_OBJECT = ctrl |
2595 | 3 | = dwg_find_table_control (dwg, "VPORT_CONTROL"); |
2596 | 9 | } |
2597 | 2.84k | else if (strEQc (table, "APPID")) |
2598 | 2.44k | { |
2599 | 2.44k | if (!(ctrl = vars->APPID_CONTROL_OBJECT)) |
2600 | 24 | vars->APPID_CONTROL_OBJECT = ctrl |
2601 | 24 | = dwg_find_table_control (dwg, "APPID_CONTROL"); |
2602 | 2.44k | } |
2603 | | // TODO ACAD_DSTYLE_DIM* are probably different handles |
2604 | 403 | else if (strEQc (table, "DIMSTYLE") || memBEGINc (table, "ACAD_DSTYLE_DIM")) |
2605 | 92 | { |
2606 | 92 | if (!(ctrl = vars->DIMSTYLE_CONTROL_OBJECT)) |
2607 | 15 | vars->DIMSTYLE_CONTROL_OBJECT = ctrl |
2608 | 15 | = dwg_find_table_control (dwg, "DIMSTYLE_CONTROL"); |
2609 | 92 | } |
2610 | 311 | else if (strEQc (table, "VX")) |
2611 | 0 | { |
2612 | 0 | if (!(ctrl = vars->VX_CONTROL_OBJECT)) |
2613 | 0 | vars->VX_CONTROL_OBJECT = ctrl |
2614 | 0 | = dwg_find_table_control (dwg, "VX_CONTROL"); |
2615 | 0 | } |
2616 | 311 | else if (strEQc (table, "GROUP")) |
2617 | 0 | { |
2618 | 0 | if (!(ctrl = vars->DICTIONARY_ACAD_GROUP)) |
2619 | 0 | vars->DICTIONARY_ACAD_GROUP = ctrl |
2620 | 0 | = dwg_find_dictionary (dwg, "ACAD_GROUP"); |
2621 | 0 | } |
2622 | 311 | else if (strEQc (table, "MLSTYLE") || strEQc (table, "MLINESTYLE")) |
2623 | 311 | { |
2624 | 311 | if (!(ctrl = vars->DICTIONARY_ACAD_MLINESTYLE)) |
2625 | 203 | vars->DICTIONARY_ACAD_MLINESTYLE = ctrl |
2626 | 203 | = dwg_find_dictionary (dwg, "ACAD_MLINESTYLE"); |
2627 | 311 | } |
2628 | 0 | else if (strEQc (table, "MLEADERSTYLE") || strEQc (table, "ACAD_MLEADERVER")) |
2629 | 0 | { |
2630 | 0 | ctrl = dwg_find_dictionary (dwg, "ACAD_MLEADERSTYLE"); |
2631 | 0 | } |
2632 | 0 | else if (strEQc (table, "NAMED_OBJECT")) |
2633 | | // The very first DICTIONARY 0.1.C with all the names |
2634 | 0 | { |
2635 | 0 | if (!(ctrl = vars->DICTIONARY_NAMED_OBJECT)) |
2636 | 0 | vars->DICTIONARY_NAMED_OBJECT = ctrl |
2637 | 0 | = dwg_add_handleref (dwg, 3, 0xC, NULL); |
2638 | 0 | } |
2639 | 0 | else if (strEQc (table, "LAYOUT")) |
2640 | 0 | { |
2641 | 0 | if (!(ctrl = vars->DICTIONARY_LAYOUT)) |
2642 | 0 | vars->DICTIONARY_LAYOUT = ctrl |
2643 | 0 | = dwg_find_dictionary (dwg, "ACAD_LAYOUT"); |
2644 | 0 | } |
2645 | 0 | else if (strEQc (table, "PLOTSETTINGS")) |
2646 | 0 | { |
2647 | 0 | if (!(ctrl = vars->DICTIONARY_PLOTSETTINGS)) |
2648 | 0 | vars->DICTIONARY_PLOTSETTINGS = ctrl |
2649 | 0 | = dwg_find_dictionary (dwg, "ACAD_PLOTSETTINGS"); |
2650 | 0 | } |
2651 | 0 | else if (strEQc (table, "PLOTSTYLENAME")) |
2652 | 0 | { |
2653 | 0 | if (!(ctrl = vars->DICTIONARY_PLOTSTYLENAME)) |
2654 | 0 | vars->DICTIONARY_PLOTSTYLENAME = ctrl |
2655 | 0 | = dwg_find_dictionary (dwg, "ACAD_PLOTSTYLENAME"); |
2656 | 0 | } |
2657 | | // TODO but maybe the mappers are different |
2658 | 0 | else if (strEQc (table, "MATERIAL") |
2659 | 0 | || memBEGINc (table, "ACAD_MATERIAL_MAPPER")) |
2660 | 0 | { |
2661 | 0 | if (!(ctrl = vars->DICTIONARY_MATERIAL)) |
2662 | 0 | vars->DICTIONARY_MATERIAL = ctrl |
2663 | 0 | = dwg_find_dictionary (dwg, "ACAD_MATERIAL"); |
2664 | 0 | } |
2665 | 0 | else if (strEQc (table, "COLOR")) |
2666 | 0 | { |
2667 | 0 | if (!(ctrl = vars->DICTIONARY_COLOR)) |
2668 | 0 | vars->DICTIONARY_COLOR = ctrl |
2669 | 0 | = dwg_find_dictionary (dwg, "ACAD_COLOR"); |
2670 | 0 | } |
2671 | 0 | else if (strEQc (table, "VISUALSTYLE")) |
2672 | 0 | { |
2673 | 0 | if (!(ctrl = vars->DICTIONARY_VISUALSTYLE)) |
2674 | 0 | vars->DICTIONARY_VISUALSTYLE = ctrl |
2675 | 0 | = dwg_find_dictionary (dwg, "ACAD_VISUALSTYLE"); |
2676 | 0 | } |
2677 | 0 | else if (strEQc (table, "LIGHTLIST")) |
2678 | 0 | { |
2679 | 0 | if (!(ctrl = vars->DICTIONARY_LIGHTLIST)) |
2680 | 0 | vars->DICTIONARY_LIGHTLIST = ctrl |
2681 | 0 | = dwg_find_dictionary (dwg, "ACAD_LIGHTLIST"); |
2682 | 0 | } |
2683 | 0 | else |
2684 | 0 | { |
2685 | 0 | LOG_ERROR ("dwg_ctrl_table: Unsupported table %s", table); |
2686 | 0 | return 0; |
2687 | 0 | } |
2688 | 237k | return ctrl; |
2689 | 237k | } |
2690 | | |
2691 | | // Search for name in associated table, and return its handle. |
2692 | | // Note that newer tables, like MATERIAL are stored in a DICTIONARY instead. |
2693 | | // Note that we cannot set the ref->obj here, as it may still move by realloc |
2694 | | // dwg->object[] |
2695 | | // See also the silent variant: dwg_find_tablehandle_silent() |
2696 | | EXPORT BITCODE_H |
2697 | | dwg_find_tablehandle (Dwg_Data *restrict dwg, const char *restrict name, |
2698 | | const char *restrict table) |
2699 | 147k | { |
2700 | 147k | BITCODE_BL i, num_entries = 0; |
2701 | 147k | BITCODE_H ctrl = NULL, *hdlv = NULL; |
2702 | 147k | Dwg_Object *obj; |
2703 | 147k | Dwg_Object_APPID_CONTROL *_obj; // just some random generic type |
2704 | 147k | Dwg_Header_Variables *vars = &dwg->header_vars; |
2705 | | |
2706 | 147k | loglevel = dwg->opts & DWG_OPTS_LOGLEVEL; |
2707 | 147k | if (!dwg || !name || !table) |
2708 | 27 | return NULL; |
2709 | | // look for the _CONTROL table, and search for name in all entries |
2710 | 147k | ctrl = dwg_ctrl_table (dwg, table); |
2711 | 147k | if (strEQc (table, "LTYPE")) |
2712 | 3.20k | { |
2713 | 3.20k | if (strEQc (name, "BYLAYER") || strEQc (name, "ByLayer")) |
2714 | 369 | { |
2715 | 369 | if (vars->LTYPE_BYLAYER) |
2716 | 0 | return vars->LTYPE_BYLAYER; |
2717 | 369 | } |
2718 | 2.84k | else if (strEQc (name, "BYBLOCK") || strEQc (name, "ByBlock")) |
2719 | 364 | { |
2720 | 364 | if (vars->LTYPE_BYBLOCK) |
2721 | 0 | return vars->LTYPE_BYBLOCK; |
2722 | 364 | } |
2723 | 2.47k | else if (strEQc (name, "CONTINUOUS") || strEQc (name, "Continuous")) |
2724 | 369 | { |
2725 | 369 | if (vars->LTYPE_CONTINUOUS) |
2726 | 0 | return vars->LTYPE_CONTINUOUS; |
2727 | 369 | } |
2728 | 3.20k | } |
2729 | 147k | if (!ctrl) |
2730 | 74.8k | { // TODO: silently search table_control. header_vars can be empty |
2731 | 74.8k | LOG_TRACE ("dwg_find_tablehandle: Empty header_vars table %s\n", table); |
2732 | 74.8k | return NULL; |
2733 | 74.8k | } |
2734 | 72.7k | obj = dwg_resolve_handle (dwg, ctrl->absolute_ref); |
2735 | 72.7k | if (!obj) |
2736 | 62.5k | { |
2737 | 62.5k | LOG_TRACE ("dwg_find_tablehandle: Could not resolve table %s\n", table); |
2738 | 62.5k | return NULL; |
2739 | 62.5k | } |
2740 | 10.2k | if (obj->fixedtype == DWG_TYPE_DICTIONARY) |
2741 | 0 | return dwg_find_dicthandle_objname (dwg, ctrl, name); |
2742 | 10.2k | if (!dwg_obj_is_control (obj)) |
2743 | 1.57k | { |
2744 | 1.57k | LOG_ERROR ("dwg_find_tablehandle: Could not resolve CONTROL object %s " |
2745 | 1.57k | "for table %s", |
2746 | 1.57k | obj->name, table); |
2747 | 1.57k | return NULL; |
2748 | 1.57k | } |
2749 | 8.70k | _obj = obj->tio.object->tio.APPID_CONTROL; // just random type |
2750 | 8.70k | if (strEQc (table, "APPID")) |
2751 | 518 | { |
2752 | 518 | num_entries = _obj->num_entries; |
2753 | 518 | hdlv = _obj->entries; |
2754 | 518 | } |
2755 | 8.18k | else |
2756 | 8.18k | { |
2757 | 8.18k | dwg_dynapi_entity_value (_obj, obj->name, "num_entries", &num_entries, |
2758 | 8.18k | NULL); |
2759 | 8.18k | dwg_dynapi_entity_value (_obj, obj->name, "entries", &hdlv, NULL); |
2760 | 8.18k | } |
2761 | 8.70k | if (!num_entries) |
2762 | 1.72k | return NULL; |
2763 | 6.98k | if (!hdlv) |
2764 | 8 | { |
2765 | 8 | LOG_ERROR ("No %s.entries but %u num_entries\n", table, |
2766 | 8 | (unsigned)num_entries); |
2767 | 8 | return NULL; |
2768 | 8 | } |
2769 | 14.0M | for (i = 0; i < num_entries; i++) |
2770 | 14.0M | { |
2771 | 14.0M | char *hdlname; |
2772 | 14.0M | Dwg_Object *hobj; |
2773 | 14.0M | Dwg_Object_APPID *_o; |
2774 | 14.0M | int isnew = 0; |
2775 | 14.0M | bool ok; |
2776 | | |
2777 | 14.0M | if (!hdlv[i]) |
2778 | 8.86M | continue; |
2779 | 5.21M | LOG_INSANE ("%s.entries[%u/%u]: resolve_handle " FORMAT_HV "\n", |
2780 | 5.21M | obj->name, i, num_entries, hdlv[i]->absolute_ref); |
2781 | 5.21M | hobj = dwg_resolve_handle (dwg, hdlv[i]->absolute_ref); |
2782 | 5.21M | if (!hobj || !hobj->tio.object || !hobj->tio.object->tio.APPID) |
2783 | 4.95M | continue; |
2784 | 262k | _o = hobj->tio.object->tio.APPID; |
2785 | 262k | ok = dwg_dynapi_entity_utf8text (_o, hobj->name, "name", &hdlname, |
2786 | 262k | &isnew, NULL); |
2787 | 262k | LOG_HANDLE (" %s.%s[%d] => %s.name: %s\n", obj->name, "entries", i, |
2788 | 262k | hobj->name, hdlname ? hdlname : "NULL"); |
2789 | 262k | if (ok && hdlname |
2790 | 189k | && (strEQ (name, hdlname) || !strcasecmp (name, hdlname))) |
2791 | 1.51k | { |
2792 | 1.51k | LOG_INSANE ("Found %s\n", name); |
2793 | 1.51k | if (isnew) |
2794 | 0 | free (hdlname); |
2795 | | |
2796 | 1.51k | if (strEQc (table, "LTYPE")) |
2797 | 0 | { |
2798 | 0 | if (strEQc (name, "BYLAYER") || strEQc (name, "ByLayer")) |
2799 | 0 | { |
2800 | 0 | if (!vars->LTYPE_BYLAYER) |
2801 | 0 | vars->LTYPE_BYLAYER = hdlv[i]; |
2802 | 0 | } |
2803 | 0 | else if (strEQc (name, "BYBLOCK") || strEQc (name, "ByBlock")) |
2804 | 0 | { |
2805 | 0 | if (!vars->LTYPE_BYBLOCK) |
2806 | 0 | vars->LTYPE_BYBLOCK = hdlv[i]; |
2807 | 0 | } |
2808 | 0 | else if (strEQc (name, "CONTINUOUS") |
2809 | 0 | || strEQc (name, "Continuous")) |
2810 | 0 | { |
2811 | 0 | if (!vars->LTYPE_CONTINUOUS) |
2812 | 0 | vars->LTYPE_CONTINUOUS = hdlv[i]; |
2813 | 0 | } |
2814 | 0 | } |
2815 | 1.51k | return hdlv[i]; |
2816 | 1.51k | } |
2817 | 261k | if (ok && isnew && hdlname) |
2818 | 0 | free (hdlname); |
2819 | 261k | } |
2820 | | |
2821 | 5.46k | LOG_INSANE ("Not found in %u APPID entries\n", num_entries); |
2822 | 5.46k | return NULL; |
2823 | 6.97k | } |
2824 | | |
2825 | | // Search for the table entry and return its handle. |
2826 | | // Note that newer tables, like MATERIAL are stored in a DICTIONARY instead. |
2827 | | EXPORT BITCODE_H |
2828 | | dwg_find_tablehandle_index (Dwg_Data *restrict dwg, const int index, |
2829 | | const char *restrict table) |
2830 | 51.3k | { |
2831 | 51.3k | BITCODE_BL num_entries = 0; |
2832 | 51.3k | BITCODE_H ctrl = NULL, *hdlv = NULL; |
2833 | 51.3k | Dwg_Object *obj; |
2834 | 51.3k | Dwg_Object_APPID_CONTROL *_obj; // just some random generic type |
2835 | 51.3k | Dwg_Header_Variables *vars = &dwg->header_vars; |
2836 | | |
2837 | 51.3k | loglevel = dwg->opts & DWG_OPTS_LOGLEVEL; |
2838 | 51.3k | if (!dwg || !table) |
2839 | 0 | return NULL; |
2840 | | // look for the _CONTROL table, and search for name in all entries |
2841 | 51.3k | ctrl = dwg_ctrl_table (dwg, table); |
2842 | 51.3k | if (strEQc (table, "LTYPE")) |
2843 | 51.3k | { |
2844 | 51.3k | if (index == 32767) |
2845 | 0 | { |
2846 | 0 | if (vars->LTYPE_BYLAYER) |
2847 | 0 | return vars->LTYPE_BYLAYER; |
2848 | 0 | } |
2849 | 51.3k | else if (index == 32766) |
2850 | 0 | { |
2851 | 0 | if (vars->LTYPE_BYBLOCK) |
2852 | 0 | return vars->LTYPE_BYBLOCK; |
2853 | 0 | } |
2854 | 51.3k | else if (index == 0) |
2855 | 0 | { |
2856 | 0 | if (vars->LTYPE_CONTINUOUS) |
2857 | 0 | return vars->LTYPE_CONTINUOUS; |
2858 | 0 | } |
2859 | 51.3k | } |
2860 | 51.3k | if (!ctrl) |
2861 | 30.4k | { // TODO: silently search table_control. header_vars can be empty |
2862 | 30.4k | LOG_TRACE ("dwg_find_tablehandle: Empty header_vars table %s\n", table); |
2863 | 30.4k | return NULL; |
2864 | 30.4k | } |
2865 | 20.8k | obj = dwg_resolve_handle (dwg, ctrl->absolute_ref); |
2866 | 20.8k | if (!obj) |
2867 | 12.8k | { |
2868 | 12.8k | LOG_TRACE ("dwg_find_tablehandle: Could not resolve table %s\n", table); |
2869 | 12.8k | return NULL; |
2870 | 12.8k | } |
2871 | | // if (obj->fixedtype == DWG_TYPE_DICTIONARY) |
2872 | | // return dwg_find_dicthandle_objname (dwg, ctrl, name); |
2873 | 7.99k | if (!dwg_obj_is_control (obj)) |
2874 | 337 | { |
2875 | 337 | LOG_ERROR ( |
2876 | 337 | "dwg_find_tablehandle_index: Could not resolve CONTROL object %s " |
2877 | 337 | "for table %s", |
2878 | 337 | obj->name, table); |
2879 | 337 | return NULL; |
2880 | 337 | } |
2881 | 7.65k | _obj = obj->tio.object->tio.APPID_CONTROL; // just random type |
2882 | 7.65k | if (strEQc (table, "APPID")) |
2883 | 0 | { |
2884 | 0 | num_entries = _obj->num_entries; |
2885 | 0 | hdlv = _obj->entries; |
2886 | 0 | } |
2887 | 7.65k | else |
2888 | 7.65k | { |
2889 | 7.65k | dwg_dynapi_entity_value (_obj, obj->name, "num_entries", &num_entries, |
2890 | 7.65k | NULL); |
2891 | 7.65k | dwg_dynapi_entity_value (_obj, obj->name, "entries", &hdlv, NULL); |
2892 | 7.65k | } |
2893 | 7.65k | if (!num_entries) |
2894 | 1.18k | return NULL; |
2895 | 6.47k | if (!hdlv) |
2896 | 0 | { |
2897 | 0 | LOG_ERROR ("No %s.entries but %u num_entries\n", table, |
2898 | 0 | (unsigned)num_entries); |
2899 | 0 | return NULL; |
2900 | 0 | } |
2901 | 6.47k | if (index < (int)num_entries) |
2902 | 4.65k | { |
2903 | 4.65k | if (hdlv[index]) |
2904 | 4.65k | LOG_INSANE ("%s.entries[%u/%u]: " FORMAT_HV "\n", obj->name, index, |
2905 | 4.65k | num_entries, hdlv[index]->absolute_ref); |
2906 | 4.65k | return hdlv[index]; |
2907 | 4.65k | } |
2908 | 1.81k | LOG_INSANE ("Not found in %u %s entries\n", num_entries, table); |
2909 | 1.81k | return NULL; |
2910 | 6.47k | } |
2911 | | |
2912 | | // Search for handle in associated table, and return its name. (as UTF-8) |
2913 | | // Always returns a copy. |
2914 | | EXPORT char * |
2915 | | dwg_handle_name (Dwg_Data *restrict dwg, const char *restrict table, |
2916 | | const BITCODE_H restrict handle) |
2917 | 54.6k | { |
2918 | 54.6k | BITCODE_BL i, num_entries = 0; |
2919 | 54.6k | BITCODE_H ctrl = NULL, *hdlv = NULL; |
2920 | 54.6k | Dwg_Object *obj; |
2921 | 54.6k | Dwg_Object_APPID_CONTROL *_obj; // just some random generic type |
2922 | | // Dwg_Header_Variables *vars = &dwg->header_vars; |
2923 | | |
2924 | 54.6k | if (!dwg || !table || !handle) |
2925 | 4.29k | return NULL; |
2926 | 50.3k | if (!handle->absolute_ref) |
2927 | 25.3k | { |
2928 | 25.3k | if (dwg->header.from_version > R_11) |
2929 | 13.8k | return NULL; |
2930 | 25.3k | } |
2931 | 36.4k | loglevel = dwg->opts & DWG_OPTS_LOGLEVEL; |
2932 | | // R11 special LTYPE sentinels: 32767=BYLAYER, 32766=BYBLOCK |
2933 | 36.4k | if (dwg->header.from_version <= R_12 && strEQc (table, "LTYPE")) |
2934 | 4.83k | { |
2935 | 4.83k | if (handle->r11_idx == 32767) |
2936 | 0 | return strdup ("BYLAYER"); |
2937 | 4.83k | else if (handle->r11_idx == 32766) |
2938 | 0 | return strdup ("BYBLOCK"); |
2939 | 4.83k | } |
2940 | | // look for the _CONTROL table, and search for name in all entries |
2941 | 36.4k | ctrl = dwg_ctrl_table (dwg, table); |
2942 | 36.4k | if (!ctrl) |
2943 | 632 | { // TODO: silently search table_control. header_vars can be empty |
2944 | 632 | LOG_TRACE ("dwg_handle_name: Empty header_vars table %s\n", table); |
2945 | 632 | return 0; |
2946 | 632 | } |
2947 | 35.8k | obj = dwg_resolve_handle (dwg, ctrl->absolute_ref); |
2948 | 35.8k | if (!obj) |
2949 | 382 | { |
2950 | 382 | LOG_TRACE ("dwg_handle_name: Could not resolve table %s\n", table); |
2951 | 382 | return 0; |
2952 | 382 | } |
2953 | | // if (obj->fixedtype == DWG_TYPE_DICTIONARY) |
2954 | | // return dwg_find_dicthandle_objname (dwg, ctrl, name); |
2955 | 35.4k | if (!dwg_obj_is_control (obj)) |
2956 | 10 | { |
2957 | 10 | LOG_ERROR ("dwg_handle_name: Could not resolve CONTROL object %s " |
2958 | 10 | "for table %s", |
2959 | 10 | obj->name, table); |
2960 | 10 | return 0; |
2961 | 10 | } |
2962 | 35.4k | _obj = obj->tio.object->tio.APPID_CONTROL; // just a random type |
2963 | 35.4k | dwg_dynapi_entity_value (_obj, obj->name, "num_entries", &num_entries, NULL); |
2964 | 35.4k | if (!num_entries) |
2965 | 20.3k | return NULL; |
2966 | 15.0k | dwg_dynapi_entity_value (_obj, obj->name, "entries", &hdlv, NULL); |
2967 | 15.0k | if (!hdlv) |
2968 | 0 | return NULL; |
2969 | 93.3M | for (i = 0; i < num_entries; i++) |
2970 | 93.3M | { |
2971 | 93.3M | char *hdlname, *name; |
2972 | 93.3M | Dwg_Object *hobj; |
2973 | 93.3M | Dwg_Object_APPID *_o; |
2974 | 93.3M | int isnew = 0; |
2975 | 93.3M | bool ok; |
2976 | | |
2977 | 93.3M | if (!hdlv[i]) |
2978 | 33.9M | continue; |
2979 | 59.3M | hobj = dwg_resolve_handle (dwg, hdlv[i]->absolute_ref); |
2980 | 59.3M | if (!hobj || !hobj->tio.object || !hobj->tio.object->tio.APPID) |
2981 | 56.8M | continue; |
2982 | 2.49M | if (dwg->header.from_version > R_12) |
2983 | 2.48M | { |
2984 | 2.48M | if (hdlv[i]->absolute_ref != handle->absolute_ref) |
2985 | 2.48M | continue; |
2986 | 2.48M | } |
2987 | 9.66k | else |
2988 | 9.66k | { |
2989 | 9.66k | if (i != (BITCODE_BL)handle->r11_idx) |
2990 | 9.45k | continue; |
2991 | 9.66k | } |
2992 | 1.47k | _o = hobj->tio.object->tio.APPID; |
2993 | 1.47k | name = hobj->name; |
2994 | | /* For BLOCK search the BLOCK entities instead. |
2995 | | The BLOCK_HEADER has only the abbreviated name, but we want "*D30", |
2996 | | not "*D" */ |
2997 | 1.47k | if (strEQc (table, "BLOCK") && hobj->fixedtype == DWG_TYPE_BLOCK_HEADER) |
2998 | 1 | { |
2999 | 1 | Dwg_Object_BLOCK_HEADER *_bh = hobj->tio.object->tio.BLOCK_HEADER; |
3000 | 1 | Dwg_Object *bo = dwg_ref_object (dwg, _bh->block_entity); |
3001 | 1 | if (bo != NULL && bo->fixedtype == DWG_TYPE_BLOCK) |
3002 | 0 | { |
3003 | 0 | _o = (Dwg_Object_APPID *)bo->tio.entity->tio.BLOCK; |
3004 | 0 | name = bo->name; |
3005 | 0 | } |
3006 | 1 | } |
3007 | 1.47k | ok = dwg_dynapi_entity_utf8text (_o, name, "name", &hdlname, &isnew, |
3008 | 1.47k | NULL); |
3009 | 1.47k | LOG_HANDLE (" %s.%s[%d] => %s.name: %s\n", obj->name, "entries", i, |
3010 | 1.47k | hobj->name, hdlname ? hdlname : "NULL"); |
3011 | 1.47k | if (ok) |
3012 | 241 | { |
3013 | 241 | if (!isnew && hdlname) |
3014 | 240 | return strdup (hdlname); |
3015 | 1 | else |
3016 | 1 | return hdlname; |
3017 | 241 | } |
3018 | 1.23k | else |
3019 | 1.23k | return NULL; |
3020 | 1.47k | } |
3021 | 13.6k | return NULL; |
3022 | 15.0k | } |
3023 | | |
3024 | | /* Returns the string value of the member of the AcDbVariableDictionary. |
3025 | | NULL if not found. |
3026 | | The name is ascii. E.g. LIGHTINGUNITS => "0" */ |
3027 | | EXPORT char * |
3028 | | dwg_variable_dict (Dwg_Data *restrict dwg, const char *restrict name) |
3029 | 0 | { |
3030 | 0 | BITCODE_H var_dict = NULL; |
3031 | 0 | BITCODE_H var; |
3032 | 0 | Dwg_Object *obj; |
3033 | 0 | Dwg_Object_DICTIONARYVAR *_obj; |
3034 | |
|
3035 | 0 | var_dict = dwg_find_dictionary (dwg, "AcDbVariableDictionary"); |
3036 | 0 | if (!var_dict) |
3037 | 0 | return NULL; |
3038 | 0 | var = dwg_find_dicthandle (dwg, var_dict, name); |
3039 | 0 | if (!var) |
3040 | 0 | return NULL; |
3041 | 0 | obj = dwg_ref_object_silent (dwg, var); |
3042 | 0 | if (!obj || obj->fixedtype != DWG_TYPE_DICTIONARYVAR) |
3043 | 0 | return NULL; |
3044 | 0 | _obj = obj->tio.object->tio.DICTIONARYVAR; |
3045 | 0 | return _obj->strvalue; |
3046 | 0 | } |
3047 | | |
3048 | | static bool |
3049 | | xdata_string_match (Dwg_Data *restrict dwg, Dwg_Resbuf *restrict xdata, |
3050 | | int type, char *restrict str) |
3051 | 0 | { |
3052 | 0 | if (xdata->type != type) |
3053 | 0 | return 0; |
3054 | 0 | if (!IS_FROM_TU_DWG (dwg)) |
3055 | 0 | { |
3056 | 0 | return strEQ (xdata->value.str.u.data, str); |
3057 | 0 | } |
3058 | 0 | else |
3059 | 0 | { |
3060 | 0 | return memcmp (xdata->value.str.u.wdata, str, xdata->value.str.size * 2) |
3061 | 0 | == 0; |
3062 | 0 | } |
3063 | 0 | } |
3064 | | |
3065 | | static bool |
3066 | | is_extnames_xrecord (Dwg_Data *restrict dwg, Dwg_Object *restrict xrec, |
3067 | | Dwg_Object *restrict xdic) |
3068 | 0 | { |
3069 | 0 | const int16_t w[8] = { 'E', 'X', 'T', 'N', 'A', 'M', 'E', 'S' }; |
3070 | 0 | const char *extnames |
3071 | 0 | = dwg->header.from_version < R_2007 ? "EXTNAMES" : (const char *)w; |
3072 | |
|
3073 | 0 | return (xrec && xdic && dwg && xrec->fixedtype == DWG_TYPE_XRECORD |
3074 | 0 | && xrec->tio.object->ownerhandle |
3075 | 0 | && xrec->tio.object->ownerhandle->absolute_ref == xdic->handle.value |
3076 | 0 | && xrec->tio.object->tio.XRECORD->num_xdata >= 2 |
3077 | 0 | && xrec->tio.object->tio.XRECORD->xdata |
3078 | 0 | && xdata_string_match (dwg, xrec->tio.object->tio.XRECORD->xdata, |
3079 | 0 | 102, (char *)extnames)); |
3080 | 0 | } |
3081 | | |
3082 | | // Return a table EXTNAME or NULL. extnames only exist for r13-r14 dwgs |
3083 | | EXPORT char * |
3084 | | dwg_find_table_extname (Dwg_Data *restrict dwg, Dwg_Object *restrict obj) |
3085 | 0 | { |
3086 | 0 | char *name; |
3087 | 0 | Dwg_Object *xdic; |
3088 | 0 | Dwg_Object_DICTIONARY *_xdic; |
3089 | 0 | Dwg_Object_Ref *xdicref; |
3090 | 0 | Dwg_Object *xrec = NULL; |
3091 | 0 | Dwg_Object_XRECORD *_xrec; |
3092 | 0 | Dwg_Resbuf *xdata; |
3093 | 0 | BITCODE_BL i; |
3094 | | |
3095 | | // (GH #167) via DICTIONARY ACAD_XREC_ROUNDTRIP to XRECORD EXTNAMES |
3096 | 0 | if (!dwg_obj_is_table (obj)) |
3097 | 0 | return NULL; |
3098 | | // HACK: we can guarantee that the table name is always the first field. See |
3099 | | // dwg_obj_table_get_name(). |
3100 | 0 | name = obj->tio.object->tio.LAYER->name; |
3101 | 0 | xdicref = obj->tio.object->xdicobjhandle; |
3102 | 0 | if (!xdicref) |
3103 | 0 | return NULL; |
3104 | 0 | xdic = dwg_ref_object (dwg, xdicref); |
3105 | 0 | if (!xdic || xdic->fixedtype != DWG_TYPE_DICTIONARY) |
3106 | 0 | return NULL; |
3107 | 0 | _xdic = xdic->tio.object->tio.DICTIONARY; |
3108 | 0 | if (_xdic->numitems < 1 || !_xdic->texts[0]) |
3109 | 0 | return NULL; |
3110 | 0 | if (xdic->tio.object->ownerhandle->absolute_ref != obj->handle.value) |
3111 | 0 | return NULL; |
3112 | 0 | for (i = 0; i < _xdic->numitems; i++) |
3113 | 0 | { |
3114 | 0 | if (strEQc (_xdic->texts[i], "ACAD_XREC_ROUNDTRIP")) |
3115 | 0 | break; |
3116 | 0 | } |
3117 | 0 | if (i == _xdic->numitems) // not found |
3118 | 0 | return NULL; |
3119 | 0 | xrec = dwg_ref_object (dwg, _xdic->itemhandles[i]); |
3120 | 0 | if (!xrec || !is_extnames_xrecord (dwg, xrec, xdic)) |
3121 | 0 | return NULL; |
3122 | | |
3123 | 0 | _xrec = xrec->tio.object->tio.XRECORD; |
3124 | 0 | xdata = _xrec->xdata; |
3125 | 0 | xdata = xdata->nextrb; |
3126 | 0 | if (xdata->type == 1) // pairs of 1: old name, 2: new name |
3127 | 0 | { |
3128 | | // step to the matching name |
3129 | 0 | cmp: |
3130 | 0 | if (!xdata_string_match (dwg, xdata, 1, name)) |
3131 | 0 | { |
3132 | 0 | xdata = xdata->nextrb; |
3133 | 0 | while (xdata && xdata->type != 1 && xdata->type != 102) |
3134 | 0 | xdata = xdata->nextrb; |
3135 | 0 | if (xdata) |
3136 | 0 | goto cmp; |
3137 | 0 | } |
3138 | 0 | if (!xdata) |
3139 | 0 | return NULL; |
3140 | 0 | xdata = xdata->nextrb; |
3141 | 0 | if (xdata->type == 2) // new name |
3142 | 0 | { |
3143 | 0 | if (!IS_FROM_TU_DWG (dwg)) |
3144 | 0 | return xdata->value.str.u.data; |
3145 | 0 | else |
3146 | 0 | return (char *)xdata->value.str.u.wdata; |
3147 | 0 | } |
3148 | 0 | } |
3149 | | |
3150 | 0 | return NULL; |
3151 | 0 | } |
3152 | | |
3153 | | static const Dwg_RGB_Palette rgb_palette[256] = { |
3154 | | { 0x00, 0x00, 0x00 }, // 0 |
3155 | | { 0xFF, 0x00, 0x00 }, { 0xFF, 0xFF, 0x00 }, { 0x00, 0xFF, 0x00 }, |
3156 | | { 0x00, 0xFF, 0xFF }, { 0x00, 0x00, 0xFF }, // 5 |
3157 | | { 0xFF, 0x00, 0xFF }, { 0xFF, 0xFF, 0xFF }, { 0x41, 0x41, 0x41 }, |
3158 | | { 0x80, 0x80, 0x80 }, { 0xFF, 0x00, 0x00 }, // 10 |
3159 | | { 0xFF, 0xAA, 0xAA }, { 0xBD, 0x00, 0x00 }, { 0xBD, 0x7E, 0x7E }, |
3160 | | { 0x81, 0x00, 0x00 }, { 0x81, 0x56, 0x56 }, // 15 |
3161 | | { 0x68, 0x00, 0x00 }, { 0x68, 0x45, 0x45 }, { 0x4F, 0x00, 0x00 }, |
3162 | | { 0x4F, 0x35, 0x35 }, { 0xFF, 0x3F, 0x00 }, // 20 |
3163 | | { 0xFF, 0xBF, 0xAA }, { 0xBD, 0x2E, 0x00 }, { 0xBD, 0x8D, 0x7E }, |
3164 | | { 0x81, 0x1F, 0x00 }, { 0x81, 0x60, 0x56 }, // 25 |
3165 | | { 0x68, 0x19, 0x00 }, { 0x68, 0x4E, 0x45 }, { 0x4F, 0x13, 0x00 }, |
3166 | | { 0x4F, 0x3B, 0x35 }, { 0xFF, 0x7F, 0x00 }, // 30 |
3167 | | { 0xFF, 0xD4, 0xAA }, { 0xBD, 0x5E, 0x00 }, { 0xBD, 0x9D, 0x7E }, |
3168 | | { 0x81, 0x40, 0x00 }, { 0x81, 0x6B, 0x56 }, // 35 |
3169 | | { 0x68, 0x34, 0x00 }, { 0x68, 0x56, 0x45 }, { 0x4F, 0x27, 0x00 }, |
3170 | | { 0x4F, 0x42, 0x35 }, { 0xFF, 0xBF, 0x00 }, // 40 |
3171 | | { 0xFF, 0xEA, 0xAA }, { 0xBD, 0x8D, 0x00 }, { 0xBD, 0xAD, 0x7E }, |
3172 | | { 0x81, 0x60, 0x00 }, { 0x81, 0x76, 0x56 }, // 45 |
3173 | | { 0x68, 0x4E, 0x00 }, { 0x68, 0x5F, 0x45 }, { 0x4F, 0x3B, 0x00 }, |
3174 | | { 0x4F, 0x49, 0x35 }, { 0xFF, 0xFF, 0x00 }, // 50 |
3175 | | { 0xFF, 0xFF, 0xAA }, { 0xBD, 0xBD, 0x00 }, { 0xBD, 0xBD, 0x7E }, |
3176 | | { 0x81, 0x81, 0x00 }, { 0x81, 0x81, 0x56 }, // 55 |
3177 | | { 0x68, 0x68, 0x00 }, { 0x68, 0x68, 0x45 }, { 0x4F, 0x4F, 0x00 }, |
3178 | | { 0x4F, 0x4F, 0x35 }, { 0xBF, 0xFF, 0x00 }, // 60 |
3179 | | { 0xEA, 0xFF, 0xAA }, { 0x8D, 0xBD, 0x00 }, { 0xAD, 0xBD, 0x7E }, |
3180 | | { 0x60, 0x81, 0x00 }, { 0x76, 0x81, 0x56 }, // 65 |
3181 | | { 0x4E, 0x68, 0x00 }, { 0x5F, 0x68, 0x45 }, { 0x3B, 0x4F, 0x00 }, |
3182 | | { 0x49, 0x4F, 0x35 }, { 0x7F, 0xFF, 0x00 }, // 70 |
3183 | | { 0xD4, 0xFF, 0xAA }, { 0x5E, 0xBD, 0x00 }, { 0x9D, 0xBD, 0x7E }, |
3184 | | { 0x40, 0x81, 0x00 }, { 0x6B, 0x81, 0x56 }, // 75 |
3185 | | { 0x34, 0x68, 0x00 }, { 0x56, 0x68, 0x45 }, { 0x27, 0x4F, 0x00 }, |
3186 | | { 0x42, 0x4F, 0x35 }, { 0x3F, 0xFF, 0x00 }, // 80 |
3187 | | { 0xBF, 0xFF, 0xAA }, { 0x2E, 0xBD, 0x00 }, { 0x8D, 0xBD, 0x7E }, |
3188 | | { 0x1F, 0x81, 0x00 }, { 0x60, 0x81, 0x56 }, // 85 |
3189 | | { 0x19, 0x68, 0x00 }, { 0x4E, 0x68, 0x45 }, { 0x13, 0x4F, 0x00 }, |
3190 | | { 0x3B, 0x4F, 0x35 }, { 0x00, 0xFF, 0x00 }, // 90 |
3191 | | { 0xAA, 0xFF, 0xAA }, { 0x00, 0xBD, 0x00 }, { 0x7E, 0xBD, 0x7E }, |
3192 | | { 0x00, 0x81, 0x00 }, { 0x56, 0x81, 0x56 }, // 95 |
3193 | | { 0x00, 0x68, 0x00 }, { 0x45, 0x68, 0x45 }, { 0x00, 0x4F, 0x00 }, |
3194 | | { 0x35, 0x4F, 0x35 }, { 0x00, 0xFF, 0x3F }, // 100 |
3195 | | { 0xAA, 0xFF, 0xBF }, { 0x00, 0xBD, 0x2E }, { 0x7E, 0xBD, 0x8D }, |
3196 | | { 0x00, 0x81, 0x1F }, { 0x56, 0x81, 0x60 }, // 105 |
3197 | | { 0x00, 0x68, 0x19 }, { 0x45, 0x68, 0x4E }, { 0x00, 0x4F, 0x13 }, |
3198 | | { 0x35, 0x4F, 0x3B }, { 0x00, 0xFF, 0x7F }, // 110 |
3199 | | { 0xAA, 0xFF, 0xD4 }, { 0x00, 0xBD, 0x5E }, { 0x7E, 0xBD, 0x9D }, |
3200 | | { 0x00, 0x81, 0x40 }, { 0x56, 0x81, 0x6B }, // 115 |
3201 | | { 0x00, 0x68, 0x34 }, { 0x45, 0x68, 0x56 }, { 0x00, 0x4F, 0x27 }, |
3202 | | { 0x35, 0x4F, 0x42 }, { 0x00, 0xFF, 0xBF }, // 120 |
3203 | | { 0xAA, 0xFF, 0xEA }, { 0x00, 0xBD, 0x8D }, { 0x7E, 0xBD, 0xAD }, |
3204 | | { 0x00, 0x81, 0x60 }, { 0x56, 0x81, 0x76 }, // 125 |
3205 | | { 0x00, 0x68, 0x4E }, { 0x45, 0x68, 0x5F }, { 0x00, 0x4F, 0x3B }, |
3206 | | { 0x35, 0x4F, 0x49 }, { 0x00, 0xFF, 0xFF }, // 130 |
3207 | | { 0xAA, 0xFF, 0xFF }, { 0x00, 0xBD, 0xBD }, { 0x7E, 0xBD, 0xBD }, |
3208 | | { 0x00, 0x81, 0x81 }, { 0x56, 0x81, 0x81 }, // 135 |
3209 | | { 0x00, 0x68, 0x68 }, { 0x45, 0x68, 0x68 }, { 0x00, 0x4F, 0x4F }, |
3210 | | { 0x35, 0x4F, 0x4F }, { 0x00, 0xBF, 0xFF }, // 140 |
3211 | | { 0xAA, 0xEA, 0xFF }, { 0x00, 0x8D, 0xBD }, { 0x7E, 0xAD, 0xBD }, |
3212 | | { 0x00, 0x60, 0x81 }, { 0x56, 0x76, 0x81 }, // 145 |
3213 | | { 0x00, 0x4E, 0x68 }, { 0x45, 0x5F, 0x68 }, { 0x00, 0x3B, 0x4F }, |
3214 | | { 0x35, 0x49, 0x4F }, { 0x00, 0x7F, 0xFF }, // 150 |
3215 | | { 0xAA, 0xD4, 0xFF }, { 0x00, 0x5E, 0xBD }, { 0x7E, 0x9D, 0xBD }, |
3216 | | { 0x00, 0x40, 0x81 }, { 0x56, 0x6B, 0x81 }, // 155 |
3217 | | { 0x00, 0x34, 0x68 }, { 0x45, 0x56, 0x68 }, { 0x00, 0x27, 0x4F }, |
3218 | | { 0x35, 0x42, 0x4F }, { 0x00, 0x3F, 0xFF }, // 160 |
3219 | | { 0xAA, 0xBF, 0xFF }, { 0x00, 0x2E, 0xBD }, { 0x7E, 0x8D, 0xBD }, |
3220 | | { 0x00, 0x1F, 0x81 }, { 0x56, 0x60, 0x81 }, // 165 |
3221 | | { 0x00, 0x19, 0x68 }, { 0x45, 0x4E, 0x68 }, { 0x00, 0x13, 0x4F }, |
3222 | | { 0x35, 0x3B, 0x4F }, { 0x00, 0x00, 0xFF }, // 170 |
3223 | | { 0xAA, 0xAA, 0xFF }, { 0x00, 0x00, 0xBD }, { 0x7E, 0x7E, 0xBD }, |
3224 | | { 0x00, 0x00, 0x81 }, { 0x56, 0x56, 0x81 }, // 175 |
3225 | | { 0x00, 0x00, 0x68 }, { 0x45, 0x45, 0x68 }, { 0x00, 0x00, 0x4F }, |
3226 | | { 0x35, 0x35, 0x4F }, { 0x3F, 0x00, 0xFF }, // 180 |
3227 | | { 0xBF, 0xAA, 0xFF }, { 0x2E, 0x00, 0xBD }, { 0x8D, 0x7E, 0xBD }, |
3228 | | { 0x1F, 0x00, 0x81 }, { 0x60, 0x56, 0x81 }, // 185 |
3229 | | { 0x19, 0x00, 0x68 }, { 0x4E, 0x45, 0x68 }, { 0x13, 0x00, 0x4F }, |
3230 | | { 0x3B, 0x35, 0x4F }, { 0x7F, 0x00, 0xFF }, // 190 |
3231 | | { 0xD4, 0xAA, 0xFF }, { 0x5E, 0x00, 0xBD }, { 0x9D, 0x7E, 0xBD }, |
3232 | | { 0x40, 0x00, 0x81 }, { 0x6B, 0x56, 0x81 }, // 195 |
3233 | | { 0x34, 0x00, 0x68 }, { 0x56, 0x45, 0x68 }, { 0x27, 0x00, 0x4F }, |
3234 | | { 0x42, 0x35, 0x4F }, { 0xBF, 0x00, 0xFF }, // 200 |
3235 | | { 0xEA, 0xAA, 0xFF }, { 0x8D, 0x00, 0xBD }, { 0xAD, 0x7E, 0xBD }, |
3236 | | { 0x60, 0x00, 0x81 }, { 0x76, 0x56, 0x81 }, // 205 |
3237 | | { 0x4E, 0x00, 0x68 }, { 0x5F, 0x45, 0x68 }, { 0x3B, 0x00, 0x4F }, |
3238 | | { 0x49, 0x35, 0x4F }, { 0xFF, 0x00, 0xFF }, // 210 |
3239 | | { 0xFF, 0xAA, 0xFF }, { 0xBD, 0x00, 0xBD }, { 0xBD, 0x7E, 0xBD }, |
3240 | | { 0x81, 0x00, 0x81 }, { 0x81, 0x56, 0x81 }, // 215 |
3241 | | { 0x68, 0x00, 0x68 }, { 0x68, 0x45, 0x68 }, { 0x4F, 0x00, 0x4F }, |
3242 | | { 0x4F, 0x35, 0x4F }, { 0xFF, 0x00, 0xBF }, // 220 |
3243 | | { 0xFF, 0xAA, 0xEA }, { 0xBD, 0x00, 0x8D }, { 0xBD, 0x7E, 0xAD }, |
3244 | | { 0x81, 0x00, 0x60 }, { 0x81, 0x56, 0x76 }, // 225 |
3245 | | { 0x68, 0x00, 0x4E }, { 0x68, 0x45, 0x5F }, { 0x4F, 0x00, 0x3B }, |
3246 | | { 0x4F, 0x35, 0x49 }, { 0xFF, 0x00, 0x7F }, // 230 |
3247 | | { 0xFF, 0xAA, 0xD4 }, { 0xBD, 0x00, 0x5E }, { 0xBD, 0x7E, 0x9D }, |
3248 | | { 0x81, 0x00, 0x40 }, { 0x81, 0x56, 0x6B }, // 235 |
3249 | | { 0x68, 0x00, 0x34 }, { 0x68, 0x45, 0x56 }, { 0x4F, 0x00, 0x27 }, |
3250 | | { 0x4F, 0x35, 0x42 }, { 0xFF, 0x00, 0x3F }, // 240 |
3251 | | { 0xFF, 0xAA, 0xBF }, { 0xBD, 0x00, 0x2E }, { 0xBD, 0x7E, 0x8D }, |
3252 | | { 0x81, 0x00, 0x1F }, { 0x81, 0x56, 0x60 }, // 245 |
3253 | | { 0x68, 0x00, 0x19 }, { 0x68, 0x45, 0x4E }, { 0x4F, 0x00, 0x13 }, |
3254 | | { 0x4F, 0x35, 0x3B }, { 0x33, 0x33, 0x33 }, // 250 |
3255 | | { 0x50, 0x50, 0x50 }, { 0x69, 0x69, 0x69 }, { 0x82, 0x82, 0x82 }, |
3256 | | { 0xBE, 0xBE, 0xBE }, { 0xFF, 0xFF, 0xFF } // 255 |
3257 | | }; |
3258 | | |
3259 | | EXPORT const Dwg_RGB_Palette * |
3260 | | dwg_rgb_palette (void) |
3261 | 0 | { |
3262 | 0 | return rgb_palette; |
3263 | 0 | } |
3264 | | |
3265 | | EXPORT BITCODE_BL |
3266 | | dwg_rgb_palette_index (BITCODE_BS index) |
3267 | 150k | { |
3268 | | // BS in unsigned |
3269 | 150k | if (index >= 256) |
3270 | 104k | return 0; |
3271 | 45.7k | else |
3272 | 45.7k | { |
3273 | 45.7k | Dwg_RGB_Palette rgb; |
3274 | 45.7k | assert (index < 256); |
3275 | 45.7k | rgb = rgb_palette[index]; |
3276 | 45.7k | return (rgb.r << 16) | (rgb.g << 8) | rgb.b; |
3277 | 45.7k | } |
3278 | 150k | } |
3279 | | |
3280 | | EXPORT BITCODE_BS |
3281 | | dwg_find_color_index (BITCODE_BL rgb) |
3282 | 0 | { |
3283 | 0 | Dwg_RGB_Palette pal; |
3284 | 0 | rgb &= 0x00ffffff; |
3285 | 0 | pal.r = (rgb >> 16) & 0xFF; |
3286 | 0 | pal.g = (rgb >> 8) & 0xFF; |
3287 | 0 | pal.b = rgb & 0xFF; |
3288 | | // linear search is good enough for 256. the palette is unsorted. |
3289 | 0 | for (BITCODE_BS i = 0; i < 256; i++) |
3290 | 0 | { |
3291 | 0 | if (memcmp (&pal, &rgb_palette[i], 3) == 0) |
3292 | 0 | return i; |
3293 | 0 | } |
3294 | 0 | return 256; |
3295 | 0 | } |
3296 | | |
3297 | | // print errors as string to stderr |
3298 | | EXPORT void |
3299 | | dwg_errstrings (int error) |
3300 | 0 | { |
3301 | 0 | if (error & 1) |
3302 | 0 | HANDLER (OUTPUT, "WRONGCRC "); |
3303 | 0 | if (error & 2) |
3304 | 0 | HANDLER (OUTPUT, "NOTYETSUPPORTED "); |
3305 | 0 | if (error & 4) |
3306 | 0 | HANDLER (OUTPUT, "UNHANDLEDCLASS "); |
3307 | 0 | if (error & 8) |
3308 | 0 | HANDLER (OUTPUT, "INVALIDTYPE "); |
3309 | 0 | if (error & 16) |
3310 | 0 | HANDLER (OUTPUT, "INVALIDHANDLE "); |
3311 | 0 | if (error & 32) |
3312 | 0 | HANDLER (OUTPUT, "INVALIDEED "); |
3313 | 0 | if (error & 64) |
3314 | 0 | HANDLER (OUTPUT, "VALUEOUTOFBOUNDS "); |
3315 | | // -- critical -- |
3316 | 0 | if (error > 127) |
3317 | 0 | HANDLER (OUTPUT, "\nCritical: "); |
3318 | 0 | if (error & 128) |
3319 | 0 | HANDLER (OUTPUT, "CLASSESNOTFOUND "); |
3320 | 0 | if (error & 256) |
3321 | 0 | HANDLER (OUTPUT, "SECTIONNOTFOUND "); |
3322 | 0 | if (error & 512) |
3323 | 0 | HANDLER (OUTPUT, "PAGENOTFOUND "); |
3324 | 0 | if (error & 1024) |
3325 | 0 | HANDLER (OUTPUT, "INTERNALERROR "); |
3326 | 0 | if (error & 2048) |
3327 | 0 | HANDLER (OUTPUT, "INVALIDDWG "); |
3328 | 0 | if (error & 4096) |
3329 | 0 | HANDLER (OUTPUT, "IOERROR "); |
3330 | 0 | if (error & 8192) |
3331 | 0 | HANDLER (OUTPUT, "OUTOFMEM "); |
3332 | 0 | HANDLER (OUTPUT, "\n"); |
3333 | 0 | } |
3334 | | |
3335 | | // return name of color.method |
3336 | | EXPORT const char * |
3337 | | dwg_color_method_name (unsigned m) |
3338 | 0 | { |
3339 | 0 | switch (m) |
3340 | 0 | { |
3341 | 0 | case 0xc0: |
3342 | 0 | return "ByLayer"; |
3343 | 0 | case 0xc1: |
3344 | 0 | return "ByBlock"; |
3345 | 0 | case 0xc2: |
3346 | 0 | return "entity (default)"; |
3347 | 0 | case 0xc3: |
3348 | 0 | return "Truecolor"; |
3349 | 0 | case 0xc5: |
3350 | 0 | return "Foreground"; |
3351 | 0 | case 0xc8: |
3352 | 0 | return "none"; |
3353 | 0 | default: |
3354 | 0 | return ""; |
3355 | 0 | } |
3356 | 0 | } |
3357 | | |
3358 | | // not utf-8 converted, native (TV or TU) |
3359 | | const char * |
3360 | | dwg_ref_objname (const Dwg_Data *restrict dwg, Dwg_Object_Ref *restrict ref) |
3361 | 0 | { |
3362 | 0 | Dwg_Object *restrict obj = dwg_ref_object_silent ((Dwg_Data *)dwg, ref); |
3363 | 0 | return obj ? obj->name : ""; |
3364 | 0 | } |
3365 | | |
3366 | | // supports tables entries and everything with a name. |
3367 | | // r2007 names are returned as malloc'ed utf-8 |
3368 | | // TV names in the resp. charset. |
3369 | | ATTRIBUTE_MALLOC |
3370 | | const char * |
3371 | | dwg_ref_tblname (const Dwg_Data *restrict dwg, Dwg_Object_Ref *restrict ref, |
3372 | | int *alloced) |
3373 | 0 | { |
3374 | 0 | const char *restrict name = dwg_dynapi_handle_name (dwg, ref, alloced); |
3375 | 0 | if (!name) |
3376 | 0 | *alloced = 0; |
3377 | 0 | return name ? name : ""; |
3378 | 0 | } |
3379 | | |
3380 | | static Dwg_Object * |
3381 | | search_r11_section (const Dwg_Data *dwg, |
3382 | | const Dwg_Entity_Sections jump_section, |
3383 | | const BITCODE_RL jump_address) |
3384 | 0 | { |
3385 | 0 | BITCODE_RL section_addr, abs_addr; |
3386 | 0 | switch (jump_section) |
3387 | 0 | { |
3388 | 0 | case DWG_ENTITY_SECTION: |
3389 | 0 | section_addr = dwg->header.entities_start; |
3390 | 0 | break; |
3391 | 0 | case DWG_BLOCKS_SECTION: |
3392 | 0 | section_addr = dwg->header.blocks_start; |
3393 | 0 | break; |
3394 | 0 | case DWG_EXTRA_SECTION: |
3395 | 0 | section_addr = dwg->header.extras_start; |
3396 | 0 | break; |
3397 | 0 | default: |
3398 | 0 | LOG_ERROR ("Invalid jump_section %u", jump_section); |
3399 | 0 | section_addr = 0; |
3400 | 0 | } |
3401 | 0 | abs_addr = jump_address + section_addr; |
3402 | 0 | loglevel = dwg->opts & DWG_OPTS_LOGLEVEL; |
3403 | 0 | LOG_HANDLE ("resolve JUMP %u %x => addr %x\n", jump_section, jump_address, |
3404 | 0 | abs_addr); |
3405 | 0 | for (BITCODE_BL i = 0; i < dwg->num_objects; i++) |
3406 | 0 | { |
3407 | 0 | Dwg_Object *obj = &dwg->object[i]; |
3408 | 0 | if (obj->address == abs_addr) |
3409 | 0 | return obj; |
3410 | 0 | } |
3411 | 0 | LOG_WARN ("JUMP %u %x not found", jump_section, jump_address); |
3412 | 0 | return NULL; |
3413 | 0 | } |
3414 | | |
3415 | | EXPORT Dwg_Object * |
3416 | | dwg_resolve_jump (const Dwg_Object *obj) |
3417 | 0 | { |
3418 | 0 | Dwg_Entity_JUMP *_obj = obj->tio.entity->tio.JUMP; |
3419 | 0 | if (obj->fixedtype != DWG_TYPE_JUMP) |
3420 | 0 | return (Dwg_Object *)obj; |
3421 | 0 | else |
3422 | 0 | return search_r11_section (obj->parent, _obj->jump_entity_section, |
3423 | 0 | _obj->jump_address); |
3424 | 0 | } |
3425 | | |
3426 | | EXPORT BITCODE_RLL |
3427 | | dwg_next_handseed (Dwg_Data *dwg) |
3428 | 38.0k | { |
3429 | 38.0k | if (dwg->header_vars.HANDSEED && dwg->header_vars.HANDSEED->absolute_ref) |
3430 | 28.7k | { |
3431 | 28.7k | BITCODE_RLL seed; |
3432 | 28.7k | seed = dwg->header_vars.HANDSEED->absolute_ref + 1; |
3433 | | // skip handles already in the object_map (GH #1229) |
3434 | 28.7k | if (dwg->object_map) |
3435 | 28.7k | { |
3436 | 28.7k | while (hash_get (dwg->object_map, seed) != HASH_NOT_FOUND) |
3437 | 0 | seed++; |
3438 | 28.7k | } |
3439 | 28.7k | dwg->header_vars.HANDSEED->absolute_ref |
3440 | 28.7k | = dwg->header_vars.HANDSEED->handleref.value = seed; |
3441 | 28.7k | dwg->auxheader.HANDSEED = seed; |
3442 | 28.7k | return seed; |
3443 | 28.7k | } |
3444 | 9.30k | else |
3445 | 9.30k | return dwg_next_handle (dwg); |
3446 | 38.0k | } |
3447 | | |
3448 | | EXPORT BITCODE_RLL |
3449 | | dwg_next_handle (const Dwg_Data *dwg) |
3450 | 1.06M | { |
3451 | 1.06M | long j; |
3452 | 1.06M | BITCODE_RLL seed = 0; |
3453 | | // check the objects for the highest handle |
3454 | 13.3M | for (j = dwg->num_objects; !seed && j > 0; j--) |
3455 | 13.3M | { |
3456 | 13.3M | Dwg_Object *o = j > 0 ? &dwg->object[j - 1] : NULL; |
3457 | 13.3M | if (o && o->handle.value) |
3458 | 1.06M | { |
3459 | 1.06M | seed = o->handle.value; |
3460 | 1.06M | break; |
3461 | 1.06M | } |
3462 | 13.3M | } |
3463 | | // compare against relative handles (deleted and purged?) |
3464 | 1.06M | LOG_INSANE ("compute HANDSEED " FORMAT_HV, seed); |
3465 | 5.86G | for (BITCODE_BL i = 0; i < dwg->num_object_refs; i++) |
3466 | 5.86G | { |
3467 | 5.86G | Dwg_Object_Ref *ref = dwg->object_ref[i]; |
3468 | 5.86G | if (ref && ref->absolute_ref > seed) |
3469 | 3.50M | seed = ref->absolute_ref; |
3470 | 5.86G | } |
3471 | 1.06M | LOG_INSANE (" => " FORMAT_HV "\n", seed + 1); |
3472 | 1.06M | return seed + 1; |
3473 | 1.06M | } |
3474 | | |
3475 | | // on init some handles have holes on purpose. |
3476 | | void dwg_set_next_hdl (Dwg_Data *dwg, const BITCODE_RLL value); |
3477 | | void dwg_set_next_objhandle (Dwg_Object *obj); |
3478 | | |
3479 | | void |
3480 | | dwg_set_next_hdl (Dwg_Data *dwg, const BITCODE_RLL value) |
3481 | 42.2k | { |
3482 | 42.2k | dwg->next_hdl = value; |
3483 | 42.2k | } |
3484 | | |
3485 | | static void |
3486 | | dwg_init_handseed (Dwg_Data *dwg) |
3487 | 819 | { |
3488 | 819 | if (!dwg->num_objects) |
3489 | 0 | { |
3490 | 0 | dwg->header_vars.HANDSEED = dwg_add_handleref (dwg, 0, 0xC, NULL); |
3491 | 0 | return; |
3492 | 0 | } |
3493 | 819 | else |
3494 | 819 | { |
3495 | 819 | Dwg_Object *lastobj = &dwg->object[dwg->num_objects - 1]; |
3496 | | /* ADD_OBJECT might have just added a zeroed object */ |
3497 | 819 | if (!lastobj->handle.value && dwg->num_objects > 1) |
3498 | 818 | lastobj = &dwg->object[dwg->num_objects - 2]; |
3499 | 819 | dwg->header_vars.HANDSEED |
3500 | 819 | = dwg_add_handleref (dwg, 0, lastobj->handle.value + 1, NULL); |
3501 | 819 | } |
3502 | 819 | } |
3503 | | |
3504 | | void |
3505 | | dwg_set_next_objhandle (Dwg_Object *obj) |
3506 | 48.1k | { |
3507 | 48.1k | Dwg_Data *dwg = obj->parent; |
3508 | 48.1k | BITCODE_RLL seed; |
3509 | 48.1k | if (dwg->next_hdl) |
3510 | 46.0k | { |
3511 | | /* Check that the candidate handle is not already in use. |
3512 | | When a table record is added after the main DXF import pass, |
3513 | | next_hdl may point to a handle already owned by another object. */ |
3514 | 46.0k | if (dwg->object_map |
3515 | 46.0k | && hash_get (dwg->object_map, dwg->next_hdl) != HASH_NOT_FOUND) |
3516 | 6 | { |
3517 | 6 | LOG_WARN ("next_hdl " FORMAT_HV " already in object_map", |
3518 | 6 | dwg->next_hdl); |
3519 | 6 | dwg->next_hdl = 0; |
3520 | 6 | } |
3521 | 46.0k | else |
3522 | 46.0k | { |
3523 | 46.0k | obj->handle.value = dwg->next_hdl; |
3524 | 46.0k | dwg_set_handle_size (&obj->handle); |
3525 | 46.0k | hash_set (dwg->object_map, obj->handle.value, (uint64_t)obj->index); |
3526 | 46.0k | dwg->next_hdl = 0; |
3527 | 46.0k | return; |
3528 | 46.0k | } |
3529 | 46.0k | } |
3530 | 2.11k | seed = dwg_new_handseed (dwg); |
3531 | 2.11k | if (!dwg->object_map) |
3532 | 0 | dwg->object_map = hash_new (200); |
3533 | 2.11k | else |
3534 | 2.11k | { |
3535 | 2.11k | bool found = true; |
3536 | 4.53k | while (found) |
3537 | 2.41k | { |
3538 | 2.41k | uint64_t i = hash_get (dwg->object_map, seed); |
3539 | 2.41k | if (i != HASH_NOT_FOUND) |
3540 | 305 | { |
3541 | 305 | LOG_WARN ("HANDSEED " FORMAT_HV " already exists: " FORMAT_BLL, |
3542 | 305 | seed, i); |
3543 | 305 | seed = dwg_new_handseed (dwg); |
3544 | 305 | } |
3545 | 2.11k | else |
3546 | 2.11k | found = false; |
3547 | 2.41k | } |
3548 | 2.11k | } |
3549 | 2.11k | obj->handle.value = seed; |
3550 | 2.11k | dwg_set_handle_size (&obj->handle); |
3551 | 2.11k | hash_set (dwg->object_map, obj->handle.value, (uint64_t)obj->index); |
3552 | 2.11k | } |
3553 | | |
3554 | | // <path-to>/dxf.ext => copy of "dxf", "ext" |
3555 | | // returns a malloc'ed copy of basename without extension, and |
3556 | | // sets ext to the char behind the last "." of basename |
3557 | | ATTRIBUTE_MALLOC |
3558 | | char * |
3559 | | split_filepath (const char *filepath, char **extp) |
3560 | 0 | { |
3561 | 0 | char *copy, *base, *dot; |
3562 | | // int len; |
3563 | | #ifndef HAVE_NONNULL |
3564 | | if (!filepath) |
3565 | | return NULL; |
3566 | | #endif |
3567 | 0 | copy = strdup (filepath); |
3568 | 0 | #ifdef HAVE_BASENAME |
3569 | 0 | base = basename (copy); |
3570 | | #else |
3571 | | base = strrchr (copy, '/'); |
3572 | | #endif |
3573 | 0 | if (!base) |
3574 | 0 | base = copy; |
3575 | | // len = strlen (base); |
3576 | 0 | if ((dot = strrchr (base, '.')) && *dot) |
3577 | 0 | { |
3578 | 0 | *extp = dot + 1; |
3579 | 0 | *dot = '\0'; |
3580 | 0 | } |
3581 | 0 | return base; |
3582 | 0 | } |
3583 | | |
3584 | | int |
3585 | | dwg_sections_init (Dwg_Data *dwg) |
3586 | 26.3k | { |
3587 | 26.3k | loglevel = dwg->opts & DWG_OPTS_LOGLEVEL; |
3588 | | // num_sections: how many sections we need to allocate internally (with |
3589 | | // holes) |
3590 | 26.3k | if (dwg->header.version < R_13b1) |
3591 | 4.19k | { |
3592 | 4.19k | if (!dwg->header.num_sections) |
3593 | 2.83k | dwg->header.num_sections = 5; |
3594 | 4.19k | if (!dwg->header.sections) |
3595 | 1.52k | dwg->header.sections = 5; |
3596 | | // HEADER.sections is always 3 or 5 even if it needs to be 8 or 10, |
3597 | | // probably because the additional sections are embedded in HEADER_VARS. |
3598 | | // 5 tables + header + block. VIEW = 6 |
3599 | 4.19k | if (dwg->header.numheader_vars) |
3600 | 2.63k | { |
3601 | 2.63k | if (dwg->header.numheader_vars > 129) // r10 |
3602 | | // UCS, VPORT |
3603 | 2.18k | dwg->header.num_sections += 2; |
3604 | 2.63k | if (dwg->header.numheader_vars > 158) // r10 one |
3605 | | // APPID |
3606 | 2.03k | dwg->header.num_sections += 1; |
3607 | 2.63k | if (dwg->header.numheader_vars > 160) // r11 |
3608 | | // DIMSTYLE, VX |
3609 | 2.00k | dwg->header.num_sections += 2; |
3610 | 2.63k | } |
3611 | 1.56k | else |
3612 | 1.56k | { |
3613 | 1.56k | if (dwg->header.version >= R_10) |
3614 | 484 | { |
3615 | 484 | dwg->header.numheader_vars = 160; |
3616 | 484 | dwg->header.num_sections += 3; |
3617 | 484 | } |
3618 | 1.56k | if (dwg->header.version >= R_11) |
3619 | 352 | { |
3620 | 352 | dwg->header.numheader_vars = 205; |
3621 | 352 | dwg->header.num_sections += 2; |
3622 | 352 | } |
3623 | 1.56k | } |
3624 | | // and there is one hole 1,2,3,5,6 we need to skip over. |
3625 | 4.19k | dwg->header.num_sections += 1; |
3626 | 4.19k | } |
3627 | 22.1k | else |
3628 | 22.1k | { |
3629 | | /* section 0: header vars |
3630 | | * 1: class section |
3631 | | * 2: object map (i.e. handles) |
3632 | | * 3: optional ObjFreeSpace (r13+, no sentinels) + 2ndheader |
3633 | | * (r13+, sentinels) 4: optional: Template (MEASUREMENT) 5: optional: |
3634 | | * AuxHeader (no sentinels, since R_2000b) 6: optional: THUMBNAIL (not a |
3635 | | * section, but treated as one) |
3636 | | */ |
3637 | 22.1k | if (!dwg->header.num_sections |
3638 | 2.49k | || ((dwg->header.from_version > R_2000) |
3639 | 2.49k | != (dwg->header.version > R_2000))) |
3640 | 20.0k | { |
3641 | 20.0k | dwg->header.num_sections = dwg->header.version < R_13c3 ? 3 |
3642 | 20.0k | : dwg->header.version < R_2000b ? 5 |
3643 | 19.5k | : 6; |
3644 | 20.0k | if (dwg->header.num_sections == 3 && dwg->objfreespace.numnums) |
3645 | 0 | dwg->header.num_sections = 5; |
3646 | 20.0k | } |
3647 | 22.1k | if (!dwg->header.sections |
3648 | 21.6k | || ((dwg->header.from_version > R_2000) |
3649 | 21.6k | != (dwg->header.version > R_2000))) |
3650 | | // ODA writes zeros |
3651 | 907 | dwg->header.sections = dwg->header.num_sections; |
3652 | | // newer DWG's have proper HEADER.sections |
3653 | 22.1k | if (dwg->header.num_sections != dwg->header.sections) |
3654 | 18.6k | dwg->header.num_sections = dwg->header.sections; |
3655 | 22.1k | } |
3656 | 26.3k | LOG_TRACE ("num_sections => " FORMAT_RL "\n", dwg->header.num_sections); |
3657 | 26.3k | if (dwg->header.num_sections < 3) |
3658 | 0 | { |
3659 | 0 | LOG_ERROR ("Not enough sections: " FORMAT_RL, dwg->header.num_sections); |
3660 | 0 | return DWG_ERR_INVALIDDWG; |
3661 | 0 | } |
3662 | 26.3k | else if (dwg->header.num_sections > 28) |
3663 | 1 | { |
3664 | 1 | LOG_ERROR ("Too many sections: " FORMAT_RL, dwg->header.num_sections); |
3665 | 1 | return DWG_ERR_INVALIDDWG; |
3666 | 1 | } |
3667 | | |
3668 | 26.3k | free (dwg->header.section); |
3669 | | // zero-based, including THUMBNAIL |
3670 | 26.3k | dwg->header.section = (Dwg_Section *)calloc (dwg->header.num_sections + 2, |
3671 | 26.3k | sizeof (Dwg_Section)); |
3672 | 26.3k | if (!dwg->header.section) |
3673 | 0 | { |
3674 | 0 | LOG_ERROR ("Out of memory"); |
3675 | 0 | return DWG_ERR_OUTOFMEM; |
3676 | 0 | } |
3677 | 26.3k | return 0; |
3678 | 26.3k | } |
3679 | | |
3680 | | void |
3681 | | dwg_log_proxyflag (const int _loglevel, const int maxlevel, |
3682 | | const BITCODE_BS flag) |
3683 | 862 | { |
3684 | 862 | if (flag > 0 && _loglevel >= maxlevel) |
3685 | 0 | { |
3686 | 0 | if (flag & 1) |
3687 | 0 | HANDLER (OUTPUT, " erase allowed (1)\n"); |
3688 | 0 | if (flag & 2) |
3689 | 0 | HANDLER (OUTPUT, " transform allowed (2)\n"); |
3690 | 0 | if (flag & 4) |
3691 | 0 | HANDLER (OUTPUT, " color change allowed (4)\n"); |
3692 | 0 | if (flag & 8) |
3693 | 0 | HANDLER (OUTPUT, " layer change allowed (8)\n"); |
3694 | 0 | if (flag & 16) |
3695 | 0 | HANDLER (OUTPUT, " LTYPE change allowed (16)\n"); |
3696 | 0 | if (flag & 32) |
3697 | 0 | HANDLER (OUTPUT, " LTYPE.scale change allowed (32)\n"); |
3698 | 0 | if (flag & 64) |
3699 | 0 | HANDLER (OUTPUT, " visibility change allowed (64)\n"); |
3700 | 0 | if (flag & 128) |
3701 | 0 | HANDLER (OUTPUT, " PLOTSTYLE.name change allowed (128)\n"); |
3702 | 0 | if (flag & 256) |
3703 | 0 | HANDLER (OUTPUT, " layer change allowed (256)\n"); |
3704 | 0 | if (flag & 512) |
3705 | 0 | HANDLER (OUTPUT, " layer change allowed (512)\n"); |
3706 | 0 | if (flag & 1024) |
3707 | 0 | HANDLER (OUTPUT, " Disables proxy warning dialog (1024)\n"); |
3708 | 0 | if (flag == 32768) |
3709 | 0 | HANDLER (OUTPUT, " is R13 format proxy (32768)\n"); |
3710 | 0 | } |
3711 | 862 | } |
3712 | | |
3713 | | void |
3714 | | dwg_log_dataflags (const int _loglevel, const int maxlevel, |
3715 | | const BITCODE_RC flag) |
3716 | 76.2k | { |
3717 | 76.2k | if (flag > 0 && _loglevel >= maxlevel) |
3718 | 0 | { |
3719 | 0 | if (flag & 1) |
3720 | 0 | HANDLER (OUTPUT, " elevation (1)\n"); |
3721 | 0 | if (flag & 2) |
3722 | 0 | HANDLER (OUTPUT, " alignment_pt (2)\n"); |
3723 | 0 | if (flag & 4) |
3724 | 0 | HANDLER (OUTPUT, " oblique_angle (4)\n"); |
3725 | 0 | if (flag & 8) |
3726 | 0 | HANDLER (OUTPUT, " rotation (8)\n"); |
3727 | 0 | if (flag & 16) |
3728 | 0 | HANDLER (OUTPUT, " width_factor (16)\n"); |
3729 | 0 | if (flag & 32) |
3730 | 0 | HANDLER (OUTPUT, " generation (32)\n"); |
3731 | 0 | if (flag & 64) |
3732 | 0 | HANDLER (OUTPUT, " horiz_alignment (64)\n"); |
3733 | 0 | if (flag & 128) |
3734 | 0 | HANDLER (OUTPUT, " vert_alignment (128)\n"); |
3735 | 0 | } |
3736 | 76.2k | } |
3737 | | |
3738 | | bool |
3739 | | dwg_has_eed_appid (Dwg_Object_Object *restrict obj, const BITCODE_RLL absref) |
3740 | 0 | { |
3741 | 0 | if (!obj->num_eed) |
3742 | 0 | return false; |
3743 | 0 | for (unsigned i = 0; i < obj->num_eed; i++) |
3744 | 0 | if (obj->eed[i].handle.value == absref) |
3745 | 0 | return true; |
3746 | 0 | return false; |
3747 | 0 | } |
3748 | | |
3749 | | // Note that ODA doesn't spec it. ODA's code does take bit 1 from |
3750 | | // path_type instead |
3751 | | // Hook lines appears if the last leader line segment is at an angle |
3752 | | // greater than 15 degrees from horizontal. If the leader has no |
3753 | | // annotation (annot_type & 0x3) or a spline path (path_type & 0x1), |
3754 | | // it has no hook line. |
3755 | | void |
3756 | | dwg_calc_hookline_on (Dwg_Entity_LEADER *_obj) |
3757 | 21.7k | { |
3758 | 21.7k | const double hookline_offsetR = M_PI / 12; |
3759 | 21.7k | double angleR = M_PI / 2; |
3760 | 21.7k | if (_obj->num_points > 2) |
3761 | 3.48k | { |
3762 | 3.48k | BITCODE_3DPOINT pt1 = _obj->points[_obj->num_points - 2]; |
3763 | 3.48k | BITCODE_3DPOINT pt2 = _obj->points[_obj->num_points - 1]; |
3764 | 3.48k | angleR = atan2 (pt1.y - pt2.y, pt1.x - pt2.x); |
3765 | 3.48k | } |
3766 | 21.7k | _obj->hookline_on = (_obj->annot_type & 0x3 || _obj->path_type & 0x1 |
3767 | 8.81k | || fabs (angleR) <= hookline_offsetR |
3768 | 7.81k | || fabs (angleR - M_PI) <= hookline_offsetR) |
3769 | 21.7k | ? 0 |
3770 | 21.7k | : 1; |
3771 | 21.7k | } |
3772 | | |
3773 | | EXPORT int |
3774 | | dwg_supports_eed (const Dwg_Data *dwg) |
3775 | 11.4k | { |
3776 | 11.4k | return dwg->header.version >= R_11; |
3777 | 11.4k | } |
3778 | | |
3779 | | EXPORT int |
3780 | | dwg_supports_obj (const Dwg_Data *restrict dwg, const Dwg_Object *restrict obj) |
3781 | 905k | { |
3782 | 905k | const Dwg_Object_Type type = obj->fixedtype; |
3783 | 905k | Dwg_Version_Type ver; |
3784 | 905k | if (type == DWG_TYPE_UNUSED || type == DWG_TYPE_UNKNOWN_OBJ |
3785 | 905k | || type == DWG_TYPE_UNKNOWN_ENT || type == DWG_TYPE_FREED) |
3786 | 160 | return 0; |
3787 | 905k | ver = dwg->header.version; |
3788 | 905k | if (type > DWG_TYPE_GROUP) |
3789 | 647k | { |
3790 | | // WIPEOUT causes hang, TABLEGEOMETRY crash on encode |
3791 | 647k | if (dwg->opts & DWG_OPTS_IN |
3792 | 512 | && (/*type == DWG_TYPE_WIPEOUT || */ type == DWG_TYPE_TABLEGEOMETRY)) |
3793 | 0 | return 0; |
3794 | 647k | return ver >= R_13b1 && is_type_stable (type); |
3795 | 647k | } |
3796 | 257k | else if (type == DWG_TYPE_GROUP) |
3797 | 3.24k | return ver >= R_13b1; |
3798 | | /* |
3799 | | else if (type == DWG_TYPE_LWPOLYLINE) |
3800 | | return ver >= R_13b1; |
3801 | | else if (type == DWG_TYPE_REGION || type == DWG_TYPE__3DSOLID |
3802 | | || type == DWG_TYPE_BODY) |
3803 | | return ver >= R_13b1; |
3804 | | else if (type == DWG_TYPE_RAY || type == DWG_TYPE_XLINE |
3805 | | || type == DWG_TYPE_ELLIPSE) |
3806 | | return ver >= R_13b1; |
3807 | | else if (type == DWG_TYPE_DICTIONARY || type == DWG_TYPE_OLEFRAME |
3808 | | || type == DWG_TYPE_MTEXT || type == DWG_TYPE_LEADER |
3809 | | || type == DWG_TYPE_TOLERANCE || type == DWG_TYPE_MLINE) |
3810 | | return ver >= R_13b1; |
3811 | | else if (type == DWG_TYPE_HATCH || type == DWG_TYPE_XRECORD |
3812 | | || type == DWG_TYPE_PLACEHOLDER || type == DWG_TYPE_VBA_PROJECT |
3813 | | || type == DWG_TYPE_LAYOUT || type == DWG_TYPE_PROXY_ENTITY |
3814 | | || type == DWG_TYPE_PROXY_OBJECT) |
3815 | | return ver >= R_13b1; |
3816 | | */ |
3817 | | // preR13: |
3818 | 254k | else if (type == DWG_TYPE_JUMP) |
3819 | 0 | return ver >= R_2_0b && ver < R_13b1; |
3820 | 254k | else if (type == DWG_TYPE__3DLINE) |
3821 | 0 | return ver >= R_2_4 && ver <= R_10; |
3822 | 254k | else if (type == DWG_TYPE_LOAD) |
3823 | 0 | return ver < R_2_0b; |
3824 | 254k | else if (type == DWG_TYPE_ENDREP || type == DWG_TYPE_REPEAT) |
3825 | 0 | return ver < R_2_10; |
3826 | 254k | else if (type == DWG_TYPE_ATTRIB || type == DWG_TYPE_ATTDEF) |
3827 | 9.02k | return ver >= R_2_0b; |
3828 | 245k | else if (type == DWG_TYPE_VPORT || type == DWG_TYPE_VPORT_CONTROL |
3829 | 204k | || type == DWG_TYPE_UCS || type == DWG_TYPE_UCS_CONTROL) |
3830 | 43.9k | return ver >= R_10; |
3831 | 201k | else if (type == DWG_TYPE_APPID || type == DWG_TYPE_APPID_CONTROL |
3832 | 200k | || type == DWG_TYPE_DIMSTYLE || type == DWG_TYPE_DIMSTYLE_CONTROL) |
3833 | 8.30k | return ver >= R_11; |
3834 | 193k | else if (type == DWG_TYPE_VX_TABLE_RECORD || type == DWG_TYPE_VX_CONTROL) |
3835 | 2.38k | return ver >= R_11 && ver < R_2004; |
3836 | 191k | else if (type == DWG_TYPE__3DFACE) |
3837 | 2.71k | return ver >= R_2_0b; |
3838 | 188k | else if (type == DWG_TYPE_DIMENSION_RADIUS |
3839 | 186k | || type == DWG_TYPE_DIMENSION_ORDINATE |
3840 | 180k | || type == DWG_TYPE_DIMENSION_LINEAR |
3841 | 168k | || type == DWG_TYPE_DIMENSION_ALIGNED |
3842 | 166k | || type == DWG_TYPE_DIMENSION_ANG3PT |
3843 | 164k | || type == DWG_TYPE_DIMENSION_ANG2LN |
3844 | 160k | || type == DWG_TYPE_DIMENSION_RADIUS |
3845 | 160k | || type == DWG_TYPE_DIMENSION_DIAMETER) |
3846 | 28.4k | return ver >= R_2_0b; |
3847 | 159k | else if (type == DWG_TYPE_POLYLINE_2D || type == DWG_TYPE_POLYLINE_3D |
3848 | 147k | || type == DWG_TYPE_POLYLINE_MESH || type == DWG_TYPE_POLYLINE_PFACE |
3849 | 142k | || type == DWG_TYPE_VERTEX_2D || type == DWG_TYPE_VERTEX_3D |
3850 | 141k | || type == DWG_TYPE_VERTEX_MESH || type == DWG_TYPE_VERTEX_PFACE |
3851 | 128k | || type == DWG_TYPE_VERTEX_PFACE_FACE || type == DWG_TYPE_SEQEND) |
3852 | 32.3k | return ver >= R_2_0b; |
3853 | 127k | else if (type == DWG_TYPE_MINSERT) |
3854 | 3.98k | return ver >= R_2_0b; |
3855 | 123k | else if (type == DWG_TYPE_SPLINE) |
3856 | 4.43k | return ver >= R_9; |
3857 | 119k | return 1; |
3858 | 905k | } |
3859 | | |
3860 | | /* from 2018 to earlier */ |
3861 | | void |
3862 | | dwg_downgrade_MLINESTYLE (Dwg_Object_MLINESTYLE *o) |
3863 | 0 | { |
3864 | 0 | BITCODE_BSd lt_index |
3865 | 0 | = strEQc (o->name, "CONTINUOUS") || strEQc (o->name, "Continuous") |
3866 | 0 | ? 0 |
3867 | 0 | : 32767; // or 32766 for BYBLOCK |
3868 | 0 | for (BITCODE_RC j = 0; j < o->num_lines; j++) |
3869 | 0 | { |
3870 | | // TODO lookup lt_ltype |
3871 | 0 | o->lines[j].lt_index = lt_index; |
3872 | 0 | } |
3873 | 0 | } |
3874 | | |
3875 | | /* to 2018 */ |
3876 | | void |
3877 | | dwg_upgrade_MLINESTYLE (Dwg_Data *restrict dwg, |
3878 | | Dwg_Object_MLINESTYLE *restrict o) |
3879 | 861 | { |
3880 | | // lookup on LTYPE_CONTROL list |
3881 | 87.5k | for (BITCODE_RC j = 0; j < o->num_lines; j++) |
3882 | 86.6k | { |
3883 | 86.6k | BITCODE_BSd lt_index = o->lines[j].lt_index; |
3884 | 86.6k | LOG_TRACE ("MLINESTYLE.lines[%d].lt_index = %d [BSd 6]\n", j, |
3885 | 86.6k | (int)lt_index); |
3886 | 86.6k | if (lt_index == 0) |
3887 | 28.3k | o->lines[j].lt_ltype = dwg->header_vars.LTYPE_CONTINUOUS; |
3888 | 58.3k | else if (lt_index == 32767) |
3889 | 0 | o->lines[j].lt_ltype = dwg->header_vars.LTYPE_BYLAYER; |
3890 | 58.3k | else if (lt_index == 32766) |
3891 | 0 | o->lines[j].lt_ltype = dwg->header_vars.LTYPE_BYBLOCK; |
3892 | 58.3k | else if (lt_index > 0) |
3893 | 51.3k | { |
3894 | 51.3k | BITCODE_H hdl |
3895 | 51.3k | = dwg_find_tablehandle_index (dwg, (int)lt_index, "LTYPE"); |
3896 | 51.3k | o->lines[j].lt_ltype |
3897 | 51.3k | = dwg_add_handleref (dwg, 5, hdl ? hdl->absolute_ref : 0, NULL); |
3898 | 51.3k | if (hdl) |
3899 | 51.3k | LOG_TRACE ("MLINESTYLE.lines[%d].lt_ltype %s => " FORMAT_REF |
3900 | 51.3k | " [H]\n", |
3901 | 51.3k | j, o->name, ARGS_REF (hdl)); |
3902 | 51.3k | } |
3903 | 7.02k | else |
3904 | 7.02k | o->lines[j].lt_ltype = dwg_add_handleref (dwg, 5, 0, NULL); |
3905 | 86.6k | } |
3906 | 861 | } |
3907 | | |
3908 | | static const void * |
3909 | | bsearch_ex (const void *pKey, const void *pBase, size_t numBase, |
3910 | | size_t nItemWidth, |
3911 | | int (*compare) (const void *pItemL, const void *pItemR), |
3912 | | const void **ppBefore) |
3913 | 772k | { |
3914 | 772k | size_t numNow = numBase; |
3915 | 772k | char *pLo = (char *)pBase; |
3916 | 772k | char *pHi; |
3917 | 772k | if (NULL != ppBefore) |
3918 | 772k | { |
3919 | 772k | *ppBefore = NULL; |
3920 | 772k | } |
3921 | 772k | if (0 == numBase) |
3922 | 8.19k | { |
3923 | 8.19k | return NULL; |
3924 | 8.19k | } |
3925 | 763k | pHi = (char *)pBase + (numNow - 1) * nItemWidth; |
3926 | 6.35M | for (; pLo <= pHi;) |
3927 | 6.25M | { |
3928 | 6.25M | if (0 == numNow) |
3929 | 0 | { |
3930 | 0 | break; |
3931 | 0 | } |
3932 | 6.25M | if (1 == numNow) |
3933 | 648k | { |
3934 | 648k | if (0 == compare (pKey, pLo)) |
3935 | 10.0k | { |
3936 | | // pKey == pLo |
3937 | 10.0k | return pLo; |
3938 | 10.0k | } |
3939 | 638k | break; |
3940 | 648k | } |
3941 | 5.60M | else |
3942 | 5.60M | { |
3943 | 5.60M | size_t numHalf; |
3944 | 5.60M | char *pMid = NULL; |
3945 | 5.60M | int result; |
3946 | | |
3947 | 5.60M | numHalf = numNow / 2; |
3948 | 5.60M | pMid = pLo + (numNow & 1 ? numHalf : (numHalf - 1)) * nItemWidth; |
3949 | 5.60M | result = compare (pKey, pMid); |
3950 | 5.60M | if (0 == result) |
3951 | 7.15k | { |
3952 | | // pKey == pMid |
3953 | 7.15k | return pMid; |
3954 | 7.15k | } |
3955 | 5.59M | if (result < 0) |
3956 | 823k | { |
3957 | | // pKey < pMid |
3958 | 823k | pHi = pMid - nItemWidth; |
3959 | 823k | numNow = numNow & 1 ? numHalf : numHalf - 1; |
3960 | 823k | } |
3961 | 4.77M | else |
3962 | 4.77M | { |
3963 | | // pKey > pMid |
3964 | 4.77M | pLo = pMid + nItemWidth; |
3965 | 4.77M | numNow = numHalf; |
3966 | 4.77M | } |
3967 | 5.59M | } |
3968 | 6.25M | } |
3969 | 746k | if (NULL != ppBefore) |
3970 | 746k | { |
3971 | 746k | if (compare (pKey, pLo) > 0) |
3972 | 247k | { |
3973 | | // pKey > pLo |
3974 | 247k | pLo += nItemWidth; |
3975 | 247k | if (pLo < (char *)pBase + numBase * nItemWidth) |
3976 | 228k | { |
3977 | 228k | *ppBefore = pLo; |
3978 | 228k | } |
3979 | 247k | } |
3980 | 499k | else |
3981 | 499k | { |
3982 | | // pKey < pLo |
3983 | 499k | *ppBefore = pLo; |
3984 | 499k | } |
3985 | 746k | } |
3986 | 746k | return NULL; |
3987 | 763k | } |
3988 | | |
3989 | | static int |
3990 | | Ref_cmp (const void *key, const void *elem) |
3991 | 115M | { |
3992 | 115M | const Dwg_Object_Ref *pKey = (const Dwg_Object_Ref *)key; |
3993 | 115M | const Dwg_Object_Ref *pR = *(const Dwg_Object_Ref **)elem; |
3994 | 115M | int retVal = (int)pKey->handleref.code - (int)pR->handleref.code; |
3995 | 115M | if (0 != retVal) |
3996 | 100M | return retVal; |
3997 | 14.6M | return pKey->absolute_ref > pR->absolute_ref ? 1 |
3998 | 14.6M | : pKey->absolute_ref == pR->absolute_ref ? 0 |
3999 | 4.33M | : -1; |
4000 | 115M | } |
4001 | | |
4002 | | void |
4003 | | ordered_ref_add (Dwg_Data *dwg, Dwg_Object_Ref *ref) |
4004 | 1.43M | { |
4005 | 1.43M | Dwg_Object_Ref **pBefore = NULL; |
4006 | 1.43M | Dwg_Object_Ref **pFound = NULL; |
4007 | 1.43M | if (DWG_HDL_OWNER != ref->handleref.code |
4008 | 1.43M | && DWG_HDL_SOFTOWN != ref->handleref.code |
4009 | 1.37M | && DWG_HDL_HARDOWN != ref->handleref.code |
4010 | 695k | && DWG_HDL_SOFTPTR != ref->handleref.code |
4011 | 680k | && DWG_HDL_HARDPTR != ref->handleref.code) |
4012 | 663k | { |
4013 | 663k | return; |
4014 | 663k | } |
4015 | 772k | if ((BITCODE_BL)-1 == dwg->num_object_ordered_refs) |
4016 | 0 | { |
4017 | 0 | return; |
4018 | 0 | } |
4019 | 772k | if (0 == dwg->num_object_ordered_refs) |
4020 | 8.19k | { |
4021 | 8.19k | dwg->object_ordered_ref = (Dwg_Object_Ref **)calloc ( |
4022 | 8.19k | REFS_PER_REALLOC, sizeof (Dwg_Object_Ref *)); |
4023 | 8.19k | } |
4024 | 763k | else |
4025 | 763k | { |
4026 | 763k | if (0 == (dwg->num_object_ordered_refs % REFS_PER_REALLOC)) |
4027 | 0 | { |
4028 | 0 | Dwg_Object_Ref **pNew = (Dwg_Object_Ref **)realloc ( |
4029 | 0 | dwg->object_ordered_ref, |
4030 | 0 | sizeof (Dwg_Object_Ref *) |
4031 | 0 | * (dwg->num_object_ordered_refs + REFS_PER_REALLOC)); |
4032 | 0 | if (NULL == pNew) |
4033 | 0 | { |
4034 | | // realloc failure,back to linear search |
4035 | 0 | if (NULL != dwg->object_ordered_ref) |
4036 | 0 | { |
4037 | 0 | free (dwg->object_ordered_ref); |
4038 | 0 | dwg->object_ordered_ref = NULL; |
4039 | 0 | } |
4040 | 0 | dwg->num_object_ordered_refs = (BITCODE_BL)-1; |
4041 | 0 | return; |
4042 | 0 | } |
4043 | 0 | else |
4044 | 0 | { |
4045 | 0 | dwg->object_ordered_ref = pNew; |
4046 | 0 | memset (&dwg->object_ordered_ref[dwg->num_object_ordered_refs], |
4047 | 0 | 0, REFS_PER_REALLOC * sizeof (Dwg_Object_Ref *)); |
4048 | 0 | } |
4049 | 0 | } |
4050 | 763k | } |
4051 | 772k | pFound = (Dwg_Object_Ref **)bsearch_ex ( |
4052 | 772k | ref, dwg->object_ordered_ref, dwg->num_object_ordered_refs, |
4053 | 772k | sizeof (Dwg_Object_Ref *), Ref_cmp, (const void **)&pBefore); |
4054 | 772k | if (NULL == pFound) |
4055 | 754k | { |
4056 | | // OK, no duplicates |
4057 | 754k | if (NULL != pBefore) |
4058 | 728k | { |
4059 | | // Find the insertion point and insert before it |
4060 | 728k | size_t numCopy = dwg->num_object_ordered_refs |
4061 | 728k | - (pBefore - dwg->object_ordered_ref); |
4062 | 728k | memmove (&pBefore[1], pBefore, sizeof (Dwg_Object_Ref *) * numCopy); |
4063 | 728k | *pBefore = ref; |
4064 | 728k | } |
4065 | 26.6k | else |
4066 | 26.6k | { |
4067 | | // The new key is the largest and attached to the last |
4068 | 26.6k | dwg->object_ordered_ref[dwg->num_object_ordered_refs] = ref; |
4069 | 26.6k | } |
4070 | 754k | dwg->num_object_ordered_refs++; |
4071 | 754k | } |
4072 | 17.1k | else |
4073 | 17.1k | { |
4074 | | // Duplicate (code, absref) pair. This DOES happen: dwg_add_handleref |
4075 | | // only dedupes via ordered_ref_find on some paths (e.g. obj == NULL), |
4076 | | // yet always calls ordered_ref_add. Disabling the index here demoted |
4077 | | // every later lookup to a linear scan over all refs — quadratic DXF |
4078 | | // import (minutes for a 19 MB file). Refs with the same key are |
4079 | | // interchangeable by design (the dedupe branch returns any of them), |
4080 | | // so just skip the duplicate and keep the index alive. |
4081 | 17.1k | return; |
4082 | 17.1k | } |
4083 | 772k | } |
4084 | | |
4085 | | const Dwg_Object_Ref * |
4086 | | ordered_ref_find (Dwg_Data *dwg, const BITCODE_RC code, |
4087 | | const unsigned long absref) |
4088 | 866k | { |
4089 | 866k | Dwg_Object_Ref nKey; |
4090 | 866k | if (0 == dwg->num_object_refs) |
4091 | 3.64k | { |
4092 | 3.64k | return NULL; |
4093 | 3.64k | } |
4094 | | |
4095 | 862k | nKey.handleref.code = code; |
4096 | 862k | nKey.absolute_ref = absref; |
4097 | | |
4098 | | // bsearch first, if possible and useful |
4099 | 862k | if (dwg->object_ordered_ref && dwg->num_object_ordered_refs > 4) |
4100 | 782k | { |
4101 | 782k | Dwg_Object_Ref **pFound = (Dwg_Object_Ref **)bsearch ( |
4102 | 782k | &nKey, dwg->object_ordered_ref, dwg->num_object_ordered_refs, |
4103 | 782k | sizeof (Dwg_Object_Ref *), Ref_cmp); |
4104 | 782k | if (NULL != pFound) |
4105 | 31.8k | { |
4106 | 31.8k | return *pFound; |
4107 | 31.8k | } |
4108 | 750k | return NULL; |
4109 | 782k | } |
4110 | | |
4111 | | // lsearch, if can't bsearch |
4112 | 102M | for (BITCODE_BL i = 0; i < dwg->num_object_refs; i++) |
4113 | 102M | { |
4114 | 102M | const Dwg_Object_Ref *pRef = dwg->object_ref[i]; |
4115 | 102M | if (0 == Ref_cmp (&nKey, &pRef)) |
4116 | 58.8k | { |
4117 | 58.8k | return pRef; |
4118 | 58.8k | } |
4119 | 102M | } |
4120 | | |
4121 | 21.2k | return NULL; |
4122 | 80.1k | } |