Coverage Report

Created: 2026-10-05 07:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libredwg/src/dwg.c
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
}