1#!/usr/bin/perl -w 2# Copyright (C) 2019-2020 Free Software Foundation, Inc., GPL3 3# 4# Generate src/dynapi.c and test/unit-testing/dynapi_test.c 5# C structs/arrays for all dwg objects and its fields for a dynamic API. 6# -> name, type, size, offset, dxfgroup, memory-type 7# Within each object linear search is good enough. 8# This is needed for in_dxf, dwgfilter, 9# a maintainable and shorter dwg_api and shorter language bindings. 10# Written by: Reini Urban 11 12#dwg.h: 13# typedef struct _dwg_header_variables 14# typedef struct _dwg_entity_(.*) 15# typedef struct _dwg_object_(.*) 16#subclasses, typically like 17# typedef struct _dwg_TYPE_subclass 18# typedef union _dwg_MLEADER_Content 19 20use strict; 21use warnings; 22use vars qw(@entity_names @object_names @subclasses 23 $max_entity_names $max_object_names $max_subclasses); 24use Convert::Binary::C; 25#use Data::Dumper; # if DEBUG 26#BEGIN { chdir 'src' if $0 =~ /src/; } 27 28# add gcc/clang -print-search-dirs paths 29my (@ccincdir, $srcdir, $topdir); 30if ($0 =~ m{(^\.\./.*src)/gen}) { 31 $srcdir = $1; 32 $topdir = "$srcdir/.."; 33 $topdir =~ s{^\.\./src/}{}; 34} elsif ($0 =~ m{^src/gen}) { 35 $srcdir = "src"; 36 $topdir = "."; 37} else { 38 $srcdir = "."; 39 $topdir = ".."; 40} 41my $CC = `grep '^CC =' Makefile`; 42if ($CC) { 43 $CC =~ s/^CC =//; 44 chomp $CC; 45 $CC =~ s/^\s+//; 46 if ($CC =~ /^afl-(gcc|clang)/) { 47 $ENV{AFL_QUIET} = 1; 48 } 49 my $out = `$CC -print-search-dirs`; 50 if ($out) { 51 if ($out =~ /^install: (.+?)$/m) { 52 my $d = $1; 53 $d =~ s/\/$//; 54 @ccincdir = ("$d/include") if -d "$d/include"; 55 } elsif ($out =~ /^libraries: =(.+?)$/m) { 56 @ccincdir = grep { -d "$_/include" ? "$_/include" : undef } 57 split ':', $1; 58 } 59 } 60} 61#__WORDSIZE=64 62# glibc quirks to include stdint.h and stddef.h directly with this old pre-C99 63# Convert::Binary::C preprocessor 64my @defines = ('__GNUC__=4', '__x86_64__', '__inline=inline', 65 '__THROW=', '__attribute__(x)='); 66if ($^O =~ /darwin|bsd/) { 67 push @defines, ('__signed=signed', '__builtin_va_list=void*', '__extension__='); 68} 69if (@ccincdir and join(" ",@ccincdir) =~ /clang/) { 70 push @defines, ('__has_feature(x)=0', '__has_include_next(x)=0', 71 '__INTPTR_TYPE__=long int', '__UINTPTR_TYPE__=unsigned long int', 72 '__INTMAX_TYPE__=long int', '__UINTMAX_TYPE__=unsigned long int', 73 '__gwchar_t=int', '____gwchar_t_defined', 74 ); 75} 76 77warn "using $CC with @ccincdir\n" if @ccincdir; 78my $c = Convert::Binary::C->new 79 ->Include('.', @ccincdir, '/usr/include') 80 ->Define(@defines); 81my $hdr = "$topdir/include/dwg.h"; 82$c->parse_file($hdr); 83 84#print Data::Dumper->Dump([$c->struct('_dwg_MLINESTYLE_line')], ['_dwg_MLINESTYLE_line']); 85#print Data::Dumper->Dump([$c->struct('_dwg_entity_TEXT')], ['_dwg_entity_TEXT']); 86#print Data::Dumper->Dump([$c->struct('struct _dwg_header_variables')], ['Dwg_Header_Variables']); 87 88my (%h, $n, %structs, %unions, %ENT, %DXF, %SIZE, %SUBCLASS, %SUBCLASSES, %DWG_TYPE, 89 @unhandled_names); 90local (@entity_names, @object_names, @subclasses, $max_entity_names, $max_object_names, 91 $max_subclasses); 92# todo: harmonize more subclasses, detect abstract classes with concrete typedefs 93for (sort $c->struct_names) { 94 if (/^_dwg_entity_([A-Z0-9_]+)$/) { 95 my $n = $1; 96 $structs{$n}++; 97 push @entity_names, $n; 98 } elsif (/^_dwg_object_([A-Z0-9_]+)$/) { 99 my $n = $1; 100 $structs{$n}++; 101 push @object_names, $n; 102 } elsif (/^_dwg_header_variables/) { 103 ; 104 } elsif (/^Dwg_([A-Z0-9]+)/) { # AuxHeader, Header, R2004_Header, SummaryInfo 105 my $n = $1; 106 next if length $n <= 1; 107 $structs{$n}++; 108 } elsif (/_dwg_([A-Z0-9_]+)/ && !/_dwg_ODA/) { 109 $structs{$_}++; 110 push @subclasses, $_; 111 } else { 112 warn "skip struct $_\n"; 113 } 114} 115for (sort $c->union_names) { 116 if (/_dwg_([A-Z0-9_]+)/) { 117 $structs{$_}++; 118 $unions{$_}++; 119 push @subclasses, $_; 120 } else { 121 warn "skip union $_\n"; 122 } 123} 124# typedefs as aliases: 125push @entity_names, qw(XLINE); # RAY 126push @entity_names, qw(VERTEX_MESH VERTEX_PFACE); # VERTEX_3D 127push @entity_names, qw(REGION BODY); # 3DSOLID 128$structs{abstractobject_UNDERLAYDEFINITION}++; 129$structs{abstractentity_UNDERLAY}++; 130push @entity_names, qw(PDFUNDERLAY DGNUNDERLAY DWFUNDERLAY); 131push @object_names, qw(PDFDEFINITION DGNDEFINITION DWFDEFINITION); 132push @object_names, qw(ASSOCARRAYMODIFYPARAMETERS 133 ASSOCARRAYPATHPARAMETERS 134 ASSOCARRAYPOLARPARAMETERS 135 ASSOCARRAYRECTANGULARPARAMETERS); 136$structs{abstractobject_ASSOCARRAYPARAMETERS}++; 137 138@entity_names = sort @entity_names; 139# get BITCODE_ macro types for each struct field 140open my $in, "<", $hdr or die "hdr: $!"; 141my $f; 142while (<$in>) { 143 if (!$n) { 144 if (/^typedef struct (_dwg_.+) \{/) { 145 $n = $1; 146 } elsif (/^typedef struct (_dwg_\S+)$/) { 147 $n = $1; 148 } elsif (/^typedef union (_dwg_\S+)$/) { 149 $n = $1; 150 } elsif (/^#define (COMMON_\w+)\((\w+)\)/) { # COMMON_TABLE_CONTROL_FIELDS 151 # BUG: Convert::Binary::C cannot separate H* from H, both are just Dwg_Object_Ref 152 # So we need to parse the defines 153 $n = $1; 154 $f = $2; 155 $h{$n}{reactors} = 'H*'; # has no ; 156 } elsif (/^#define (COMMON_\w+)/) { # COMMON_ENTITY_POLYLINE 157 $n = $1; 158 $h{$n}{seqend} = 'H' if $n eq 'COMMON_ENTITY_POLYLINE'; # has no ; 159 } 160 } elsif (/^\}/) { # close the struct 161 $n = ''; 162 } elsif ($n and $_ =~ /^ +BITCODE_([\w\*]+)\s+(\w.*);/) { 163 my $type = $1; 164 my $v = $2; 165 $v =~ s/^_3/3/; 166 $type =~ s/\s+$//; 167 if ($n eq 'COMMON_TABLE_CONTROL_FIELDS' && $v eq 'entries') { 168 $h{$n}{$_} = 'H*' 169 for qw(block_headers layers styles linetypes views ucs vports apps 170 dimstyles vport_entity_headers); 171 } 172 $h{$n}{$v} = $type; 173 } 174} 175#$h{Dwg_Bitcode_3BD} = '3BD'; 176#$h{Dwg_Bitcode_2BD} = '2BD'; 177#$h{Dwg_Bitcode_3RD} = '3RD'; 178#$h{Dwg_Bitcode_2RD} = '2RD'; 179$ENT{LAYER}->{flag} = 'BS'; 180$ENT{LAYER}->{name} = 'T'; 181$ENT{DIMSTYLE}->{name} = 'T'; 182$SUBCLASSES{DIMENSION_common} = [ qw(AcDbDimension) ]; 183$SUBCLASSES{ACTION_3DSOLID} = [ qw(AcDbModelerGeometry AcDb3dSolid) ]; 184$SUBCLASSES{TABLECONTENTs} = [ qw( AcDbLinkedTableData AcDbFormattedTableData AcDbTableContent) ]; 185#$ENT{LTYPE}->{strings_area} = 'TF'; 186close $in; 187my @old; 188 189sub expand_define { 190 my ($def, $n, $defined, $param) = @_; 191 if (exists $defined->{$def}) { 192 warn "expand defined $def fields"; 193 if (!$param) { # replace the macro arg with $param? no. for now ignore 194 for (keys %{$DXF{$def}}) { 195 $DXF{$n}->{$_} = $DXF{$def}->{$_}; 196 } 197 for (keys %{$ENT{$def}}) { 198 $ENT{$n}->{$_} = $ENT{$def}->{$_}; 199 } 200 } 201 my $aref = $SUBCLASSES{$n}; 202 for my $k (@{$SUBCLASSES{$def}}) { 203 # if defined subclass is not in the main subclass yet 204 if (!grep $_ eq $k, @$aref) { 205 if (@$aref) { 206 push @$aref, $k; 207 } else { 208 $aref = [ $k ]; 209 } 210 $SUBCLASSES{$n} = $aref; 211 } 212 } 213 } else { 214 unless (/(DXF|DECODE|ENCODE|JSON|FREE)_3DSOLID/) { 215 warn "TODO $def fields not defined"; 216 } else { 217 $n = 'ACTION_3DSOLID'; 218 $defined->{$n}++; 219 @old = (); # TODO pop 3DSOLID_material 220 } 221 } 222} 223 224sub embedded_struct { 225 my ($pre, $subclass) = @_; 226 if ($f =~ /^$pre\.(\w+)$/) { 227 $f = $1; 228 if ($n ne $subclass) { 229 push @old, $n; 230 warn "$n pushed"; 231 $n = $subclass; 232 } 233 } elsif ($n eq $subclass && $f !~ /\./) { 234 $n = pop @old; 235 warn "$n popped"; 236 } 237} 238 239# parse a spec for its objects, subclasses and dxf values 240sub dxf_in { 241 $in = shift; 242 my $v = qr /[\w\.\[\]]+/; 243 my $vx = qr /[\w\.\[\]>-]+/; 244 my $outdef; 245 my %defined; #define subclass_fields 246 while (<$in>) { 247 $f = ''; 248 s/DXF \{ //; 249 if (!$n) { 250 if (/^DWG_(ENTITY|OBJECT)\s?\((\w+)\)/) { 251 $n = $2; 252 $n =~ s/^_3/3/; 253 warn $n; 254 } elsif (/^\s*SECTION\s?\(HEADER\)/) { 255 $n = 'header_variables'; 256 warn $n; 257 } elsif (/^int DWG_FUNC_N\s?\(ACTION,_HATCH(\w+)\)/) { 258 $n = 'HATCH'; 259 warn $n; 260 } elsif (/^\#define (COMMON_ENTITY_POLYLINE)/) { 261 $n = $1; 262 warn "define $n"; 263 } elsif (/^\#define (COMMON_3DSOLID|ACTION_3DSOLID|COMMON_ENTITY_DIMENSION)/) { 264 $n = $1; 265 $defined{$n}++; 266 warn "define $n"; 267 } elsif (/^\#define (\w+)_fields/) { 268 $n = $1; 269 $defined{$n}++; 270 warn "define $n fields"; 271 } 272 } elsif (/^\#define (\w+)_fields/) { 273 $n = $1; 274 $defined{$n}++; 275 warn "define $n fields"; 276 # i.e. after #define 277 } elsif (/^DWG_(ENTITY|OBJECT)\s?\((\w+)\)/) { 278 $n = $2; 279 $n =~ s/^_3/3/; 280 warn $n; 281 } elsif (/^DWG_(ENTITY|OBJECT)_END/) { # close 282 $n = ''; 283 @old = (); 284 $outdef = 0; 285 } elsif (!$n) { 286 ; 287 #} elsif ($outdef) { 288 # ; 289 #} elsif (/^\s*\#ifdef IS_JSON/) { 290 # $outdef++; 291 #} elsif ($outdef && /^\s*\#endif/) { 292 # $outdef = 0; 293 # single-line REPEAT 294 } elsif (/^\s+REPEAT.*\($v,\s*$v,\s*(\w+)\)/) { 295 my $tmp = $1; # subclass? 296 if ($tmp =~ /^Dwg_(.*)/) { 297 push @old, $n; 298 $n = $1; # not _dwg_$1 299 warn "$n pushed"; 300 } else { 301 push @old, ''; 302 } 303 } elsif (/^\s+_REPEAT_C?N\s*\($vx,\s*$v,\s*(\w+),/) { 304 my $tmp = $1; # subclass? 305 if ($tmp =~ /^Dwg_(.*)/) { 306 push @old, $n; 307 $n = $1; 308 warn "$n pushed"; 309 } else { 310 push @old, ''; 311 } 312 # multiline REPEAT 313 } elsif (/^\s+REPEAT.*\($v,\s*$v,$/) { 314 $_ = <$in>; 315 if (/^\s+(\w+)\)/) { 316 my $tmp = $1; # subclass? 317 if ($tmp =~ /^Dwg_(.*)/) { 318 push @old, $n; 319 $n = $1; 320 warn "$n pushed"; 321 } else { 322 push @old, ''; 323 } 324 } 325 # skip END_REPEAT(paths); return DWG_ERR_VALUEOUTOFBOUNDS; 326 } elsif (/^\s+END_REPEAT\s*\(($vx)\);?$/) { # close 327 my $tmp = pop @old; 328 if ($tmp) { 329 $n = $tmp; 330 warn "$n popped"; 331 } elsif (!defined $tmp) { 332 # mostly due to type being a primitive, not a subclass (like T) 333 warn "missing REPEAT block in $n: $1"; 334 } 335 } elsif (/^\s+FIELD_HANDLE\s*\((\w+),\s*\d+,\s*(\d+)\)/) { 336 $f = $1; 337 if ($n eq 'MLEADER_AnnotContext' && $f eq 'mleaderstyle') { 338 $n = 'MULTILEADER'; # pop back 339 } 340 $DXF{$n}->{$f} = $2 if $2; 341 } elsif (/^\s+VALUE_HANDLE\s*\(.+,\s*(\w+),\s*\d,\s*(\d+)\)/) { 342 $f = $1; 343 $DXF{$n}->{$f} = $2 if $2; 344 } elsif (/^\s+FIELD_TF\s*\((\w+),\s*(\d*),\s*(\d+)\)/) { 345 my $type = 'TF'; 346 $f = $1; 347 $DXF{$n}->{$f} = $3 if $3; 348 $SIZE{$n}->{$f} = $2; 349 $ENT{$n}->{$f} = 'TF'; 350 } elsif (/^\s+FIELD_(.+?)\s*\(([\w\.]+),\s*(\d+)\)/) { 351 my $type = $1; 352 $f = $2; 353 my $dxf = $3; 354 $type =~ s/0$//; # strip ending 0, optional dxf (default 0 not printed) 355 $type =~ s/^BD1$/BD/; 356 # inlined unions 357 $f =~ s/^(?:fmt|sty|name|value)\.//; 358 # inlined struct: ctx. 359 if ($f =~ /^ctx\.(\w+)$/) { 360 $f = $1; 361 $n = 'MLEADER_AnnotContext'; 362 } 363 embedded_struct ('plotsettings', 'PLOTSETTINGS'); 364 embedded_struct ('cellstyle', 'TABLESTYLE_Cell'); 365 embedded_struct ('body', 'ACTIONBODY'); 366 embedded_struct ('ldata', 'LinkedData'); 367 embedded_struct ('tdata', 'LinkedTableData'); 368 embedded_struct ('fdata', 'FormattedTableData'); 369 embedded_struct ('dimension', 'OCD_Dimension'); 370 if ($n eq 'VISUALSTYLE') { 371 $DXF{$n}->{$f."_int"} = 176; 372 next if $DXF{$n}->{$f}; 373 } 374 # (scale.x, 41) as is 375 $DXF{$n}->{$f} = $dxf if $dxf; 376 $ENT{$n}->{$f} = 'TF' if $type eq 'BINARY'; 377 $ENT{$n}->{$f} = $type if $type =~ /^T/; 378 $ENT{$n}->{$f} = $type if $type =~ /^[23][RB]D_1/; 379 } elsif (@old && /^\s+SUB_FIELD_HANDLE\s*\($v,\s*(\w+),\s*\d+,\s*(\d+)\)/) { 380 my $type = $1; 381 $f = $1; 382 $DXF{$n}->{$f} = $2 if $2; 383 } elsif (@old && /^\s+SUB_FIELD_(.+?)\s*\($v,\s*(\w+),\s*(\d+)\)/) { 384 my $type = $1; 385 $f = $2; 386 $DXF{$n}->{$f} = $3 if $3; 387 } elsif (/^\s+FIELD_(?:CMC|ENC)\s*\((\w+),\s*(\d+)\)/) { 388 $f = $1; 389 if ($2) { 390 $DXF{$n}->{$f} = $2; 391 if ($2 < 90) { 392 $DXF{$n}->{"$f.index"} = $2; 393 $DXF{$n}->{"$f.rbg"} = $2 + 420 - 62; 394 $DXF{$n}->{"$f.name"} = $2 + 430 - 62; 395 $DXF{$n}->{"$f.book_name"} = $2 + 430 - 62; 396 $DXF{$n}->{"$f.alpha"} = $2 + 440 - 62; 397 } else { 398 $DXF{$n}->{"$f.rbg"} = $2; 399 } 400 } 401 } elsif (/^\s+FIELD_(.+?)\s*\((\w+),.*,\s*(\d+)\)/) { 402 my $type = $1; 403 $f = $2; 404 $DXF{$n}->{$f} = $3 if $3; 405 $ENT{$n}->{$f} = 'TF' if $type eq 'BINARY'; 406 $ENT{$n}->{$f} = $type if $type =~ /^T/; 407 $ENT{$n}->{$f} = $type if $type =~ /^[23][RB]D_1/; 408 } elsif (@old && /^\s+SUB_FIELD_(.+?)\s*\(\w+,\s*(\w+),.*,\s*(\d+)\)/) { 409 my $type = $1; 410 $f = $2; 411 $DXF{$n}->{$f} = $3 if $3; 412 $ENT{$n}->{$f} = 'TF' if $type eq 'BINARY'; 413 $ENT{$n}->{$f} = $type if $type =~ /^T/; 414 $ENT{$n}->{$f} = $type if $type =~ /^[23][RB]D_1/; 415 } elsif (/^\s+HANDLE_VECTOR(?:_N)?\s*\((\w+),.*?,\s*(\d+)\)/) { 416 $f = $1; 417 $DXF{$n}->{$f} = $2 if $2; 418 } elsif (/^\s+SUB_HANDLE_VECTOR\s*\([^,]+?, (\w+), .+, (\d+)\)/) { 419 $f = $1; 420 $DXF{$n}->{$f} = $2 if $2; 421 } elsif (/^\s+HEADER_.+\s*\((\w+),\s*(\d+)\)/) { # HEADER_RC 422 $f = $1; 423 $DXF{$n}->{$f} = $2 if $2; 424 } elsif (/^\s+HEADER_.+\s*\((\w+),\s*(\d+),\s*\w+\)/) { 425 $f = $1; 426 $DXF{$n}->{$f} = $2 if $2; 427 } elsif (/^\s+HEADER_.+\s*\((\w+),\s*\w+,\s*(\d+),\s*\D.+\)/) { 428 $f = $1; 429 #$f =~ s/^_3/3/; 430 $DXF{$n}->{$f} = $2 if $2; 431 } elsif (/^\s+HEADER_([23])D\s*\((\w+)\)/) { 432 $f = $2; 433 $DXF{$n}->{$f} = $1 eq '2' ? 20 : 30; 434 } elsif (/^\s+VALUE_(.+)\s*\((\w.+),.*,\s*(\d+)\)/) { 435 my $type = $1; 436 $f = $2; 437 $DXF{$n}->{$f} = $3 if $3; 438 $ENT{$n}->{$f} = $type if $type =~ /^T/; 439 } elsif (/^\s+SUBCLASS\s*\((\w.+)\)/) { 440 my $sc = $1; 441 if ($sc eq 'AcDbLayout') { # FIXME: pop PLOTSETTINGS earlier in LAYOUT 442 if (@old && $old[0] eq 'LAYOUT') { 443 $n = pop @old; 444 warn "$n popped"; 445 } 446 } 447 if (exists $SUBCLASSES{$n}) { 448 my $aref = $SUBCLASSES{$n}; 449 push @$aref, $sc; 450 $SUBCLASSES{$n} = $aref; 451 } else { 452 $SUBCLASSES{$n} = [ $sc ]; 453 } 454 } elsif (/^\s+(\w+)_fields;/) { 455 expand_define ($1, $n, \%defined); 456 } elsif (/^\s+(\w+_3DSOLID)/) { # special defines 457 expand_define ($1, $n, \%defined); 458 } elsif (/^\s+(\w+)_fields \((\w+)\)/) { # parametric macro 459 expand_define ($1, $n, \%defined, $2); 460 } elsif (/^\s+(COMMON_ENTITY_DIMENSION)/) { 461 expand_define ($1, $n, \%defined); 462 } elsif (/^$/ && $defined{$n}) { 463 warn "undef $n\n"; 464 @old = (); 465 undef $n; 466 } 467 if ($f and $n and exists $DXF{$n}->{$f}) { 468 warn " $f $DXF{$n}->{$f}\n"; 469 } 470 } 471} 472 473# get dxf group for each struct field 474sub dxfin_spec { 475 my $fn = shift; 476 open my $in, "<", $fn or die "$fn: $!"; 477 dxf_in ($in); 478 close $in; 479} 480dxfin_spec "$srcdir/dwg.spec"; 481$DXF{'BLOCK'}->{'name'} = 2; # and 3 482$DXF{'BLOCK'}->{'filename'} = 4; 483$DXF{'INSERT'}->{'block_header'} = 2; 484$DXF{'MINSERT'}->{'block_header'} = 2; 485$DXF{'POLYLINE_3D'}->{'flag'} = 70; 486$DXF{'POLYLINE_MESH'}->{'flag'} = 70; 487$DXF{'VISUALSTYLE'}->{'edge_hide_precision_flag'} = 290; 488$DXF{'VISUALSTYLE'}->{'is_internal_use_only'} = 291; 489# $DXF{'VISUALSTYLE'}->{'face_lighting_model'} = 71; 490$DXF{'DIMSTYLE_CONTROL'}->{'morehandles'} = 340; 491# $DXF{'DIMSTYLE'}->{'DIMFIT'} = 287; # <= r14 only 492$DXF{'PROXY_ENTITY'}->{'version'} = 95; # or 91 <= r14 493$DXF{'DIMASSOC'}->{'intsect_gsmarker'} = 92; 494$DXF{'DIMASSOC_Ref'}->{'xrefpaths'} = 301; 495$DXF{'DIMSTYLE'}->{'flag'} = 70; 496$DXF{'PLOTSETTINGS'}->{'plotview'} = 6; 497$DXF{'SORTENTSTABLE'}->{'ents'} = 331; 498$DXF{'SORTENTSTABLE'}->{'sort_ents'} = 5; 499$DXF{'PLOTSETTINGS'}->{'shadeplot'} = 333; 500$DXF{'OCD_Dimension'}->{'block'} = 2; 501$DXF{'TABLECONTENT'}->{'tablestyle'} = 340; 502$DXF{'TABLESTYLE'}->{'name'} = 3; # not 300 503$DXF{'TABLE_Cell'}->{'cell_flag_override'} = 177; 504$DXF{'ACSH_HistoryNode'}->{'trans'} = 40; # but inc by 1 for 16 505# $DXF{'DIMENSION_ORDINATE'}->{'def_pt'} = 10; 506# $DXF{'DIMENSION_ORDINATE'}->{'feature_location_pt'} = 13; 507# $DXF{'DIMENSION_ORDINATE'}->{'leader_endpt'} = 14; 508# $DXF{'DIMENSION_ORDINATE'}->{'flag2'} = 70; 509# $DXF{'DIMENSION_ORDINATE'}->{'dimstyle'} = 3; 510# $DXF{'DIMENSION_ORDINATE'}->{'block'} = 2; 511$DXF{$_}->{'class_version'} = 280 for qw(ATTRIB ATTDEF); #r2010 only 512$DXF{$_}->{'elevation'} = 30 for qw(TEXT ATTRIB ATTDEF); # not 31 513$DXF{$_}->{'has_attribs'} = 66 for qw(INSERT MINSERT); 514#$DXF{$_}->{'has_vertex'} = 66 for qw(POLYLINE_2D POLYLINE_3D POLYLINE_PFACE); 515$DXF{UNDERLAYDEFINITION}->{'filename'} = 1; 516$DXF{UNDERLAYDEFINITION}->{'name'} = 2; 517$DXF{$_}->{'flag'} = 70 for qw(VERTEX_3D VERTEX_MESH VERTEX_PFACE_FACE POLYLINE_PFACE); 518my @solids = qw(3DSOLID REGION BODY 519 EXTRUDEDSURFACE LOFTEDSURFACE NURBSURFACE PLANESURFACE REVOLVEDSURFACE SWEPTSURFACE 520 ACSH_BREP_CLASS); 521$DXF{$_}->{'version'} = 70 for @solids; 522$DXF{$_}->{'encr_sat_data'} = 1 for @solids; 523$DXF{$_}->{'history_id'} = 350 for @solids; 524$DXF{$_}->{'acis_empty'} = 290 for @solids; 525$DXF{$_}->{'revision_guid[39]'} = 2 for @solids; 526my @annotscale = qw (TEXTOBJECTCONTEXTDATA MTEXTOBJECTCONTEXTDATA ALDIMOBJECTCONTEXTDATA 527 MTEXTATTRIBUTEOBJECTCONTEXTDATA MLEADEROBJECTCONTEXTDATA LEADEROBJECTCONTEXTDATA 528 BLKREFOBJECTCONTEXTDATA); 529$DXF{$_}->{'class_version'} = 70 for @annotscale; 530$DXF{$_}->{'is_default'} = 290 for @annotscale; 531$DXF{$_}->{'scale'} = 340 for @annotscale; 532 533dxfin_spec "$srcdir/header_variables_dxf.spec"; 534$DXF{header_variables}->{'_3DDWFPREC'} = 40; 535 536$n = 'object_entity'; 537dxfin_spec "$srcdir/common_entity_data.spec"; 538dxfin_spec "$srcdir/common_entity_handle_data.spec"; 539$DXF{$n}->{'color'} = $DXF{$n}->{'color_r11'} = 62; 540$DXF{$n}->{'color.rgb'} = 420; # handle 420? 541$DXF{$n}->{'color.book'} = 430; 542$DXF{$n}->{'color.alpha'} = 440; 543$DXF{$n}->{'paper_r11'} = 67; 544$DXF{$n}->{'plotstyle'} = 390; 545$DXF{$n}->{'ownerhandle'} = 330; 546$DXF{$n}->{'xdicobjhandle'} = 360; 547$DXF{$n}->{'reactors'} = 330; 548$DXF{$n}->{'preview_size'} = 160; # or 92 549 550$n = 'object_object'; 551#dxfin_spec "$srcdir/common_object_handle_data.spec"; 552$DXF{$n}->{'ownerhandle'} = 330; 553$DXF{$n}->{'xdicobjhandle'} = 360; 554$DXF{$n}->{'reactors'} = 330; 555 556$n = 'summaryinfo'; 557dxfin_spec "$srcdir/summaryinfo.spec"; 558 559# dxfclassname for each of our classes and subclasses (not complete) 560# Our NAME => 100 561%SUBCLASS = ( 562 '3DSOLID' => "AcDbModelerGeometry", 563 DIMENSION_ALIGNED => "AcDbAlignedDimension", 564 DIMENSION_ORDINATE => "AcDbOrdinateDimension", 565 DIMENSION_ORDINATE => "AcDb2LineAngularDimension", 566 ARC_DIMENSION => "AcDbArcDimension", 567 LWPOLYLINE => "AcDbPolyline", 568 POLYLINE_3D => "AcDb3dPolyline", 569 #VERTEX => "AcDbVertex", 570 VERTEX_3D => "AcDb3dPolylineVertex", 571 HATCH => "AcDbHatch", 572 '3DFACE' => "AcDbFace", 573 DICTIONARYVAR => "DictionaryVariables", 574 575 "3DSOLID_silhouette" => "", 576 "3DSOLID_wire" => "", 577 "ACTIONBODY" => "AcDbAssocActionBody", 578 # AcDbAssocParamBasedActionBody? 579 # ASSOCDEPENDENCY AcDbAssocDependency 580 # ASSOCGEOMDEPENDENCY AcDbAssocDependency 581 # ASSOCGEOMDEPENDENCY AcDbAssocGeomDependency 582 # ASSOCOSNAPPOINTREFACTIONPARAM => AcDbAssocActionParam, 583 # ASSOCOSNAPPOINTREFACTIONPARAM => AcDbAssocCompoundActionParam, 584 # ASSOCVERTEXACTIONPARAM => AcDbAssocActionParam, 585 # ASSOCVERTEXACTIONPARAM => AcDbAssocSingleDependencyActionParam, 586 # ASSOCVERTEXACTIONPARAM => AcDbAssocVertexActionParam, 587 "CELLSTYLEMAP_Cell" => "", 588 "DIMASSOC_Ref" => "", 589 "DIMENSION_common" => "AcDbDimension", 590 "EVAL_Node" => "", 591 "FIELD_ChildValue" => "", 592 "GEODATA_meshface" => "", 593 "GEODATA_meshpt" => "", 594 "HATCH_DefLine" => "", 595 "HATCH_color" => "", 596 "HATCH_control_point" => "", 597 "HATCH_path" => "", 598 "HATCH_pathseg" => "", 599 "HATCH_polylinepath" => "", 600 "ACSH_HistoryNode," => 'AcDbShHistoryNode', 601 "LEADER_ArrowHead" => "", 602 "LEADER_BlockLabel" => "", 603 "LEADER_Break" => "", 604 "LEADER_Line" => "", 605 "LEADER_Node" => "", 606 "LTYPE_dash" => "", 607 "LWPOLYLINE_width" => "", 608 "MLEADER_Content" => "", 609 "MLEADER_AnnotContext" => "AcDbMLeaderAnnotContext", 610 "MLINESTYLE_line" => "", 611 "MLINE_line" => "", 612 "MLINE_vertex" => "", 613 # "OBJECTCONTEXTDATA" => "AcDbObjectContextData", # inlined, no subclass 614 "OCD_Dimension" => "AcDbDimensionObjectContextData", 615 "SPLINE_control_point" => "", 616 "SPLINE_point" => "", 617 "SUNSTUDY_Dates" => "", 618 "TABLEGEOMETRY_Cell" => "", 619 "TABLESTYLE_Cell" => "", 620 "TABLE_BreakHeight" => "", 621 "TABLE_BreakRow" => "", 622 "TABLE_CustomDataItem" => "", 623 "TABLE_cell" => "", 624 "TABLE_value" => "", 625 626 # TABLECONTENT => AcDbLinkedData 627 # TABLECONTENT => AcDbLinkedTableData 628 # TABLECONTENT => AcDbFormattedTableData 629 "TABLECONTENT" => "AcDbTableContent", 630 "TABLEGEOMETRY" => "AcDbTableGeometry", 631 "DATATABLE" => "ACDBDATATABLE", 632 # VIEWSTYLE_ModelDoc => "AcDbModelDocViewStyle", 633 DETAILVIEWSTYLE => "AcDbDetailViewStyle", 634 SECTIONVIEWSTYLE => "AcDbSectionViewStyle", 635 ASSOCGEOMDEPENDENCY => "AcDbAssocDependency", 636 ASSOCOSNAPPOINTREFACTIONPARAM => "ACDBASSOCOSNAPPOINTREFACTIONPARAM", 637 ASSOCALIGNEDDIMACTIONBODY => "ACDBASSOCALIGNEDDIMACTIONBODY", 638 ASSOCOSNAPPOINTREFACTIONPARAM => "ACDBASSOCOSNAPPOINTREFACTIONPARAM", 639 # ACSH_HISTORY_CLASS => AcDbShHistory 640 # ACSH_HISTORY_CLASS_Node => AcDbShHistoryNode 641 ); 642 643# 300 CONTEXT_DATA{ 644# unused 645my %SUBGROUP = ( 646 MLEADER_AnnotContext => "CONTEXT_DATA{", 647 LEADER => "LEADER{", 648 LEADER_Line => "LEADER_LINE{", 649 ); 650 651# DXFNAME 0 => our name 652my %DXFALIAS = # see also CLASS.dxfname 653 ( 654 ACDBDETAILVIEWSTYLE => "DETAILVIEWSTYLE", 655 ACDBSECTIONVIEWSTYLE => "SECTIONVIEWSTYLE", 656 ACDBPLACEHOLDER => "PLACEHOLDER", 657 ACDBASSOCACTION => "ASSOCACTION", 658 ACDBASSOCALIGNEDDIMACTIONBODY => "ASSOCALIGNEDDIMACTIONBODY", 659 ACDBASSOCGEOMDEPENDENCY => "ASSOCGEOMDEPENDENCY", 660 ACDBASSOCOSNAPPOINTREFACTIONPARAM => "ASSOCOSNAPPOINTREFACTIONPARAM", 661 ACDBASSOCALIGNEDDIMACTIONBODY => "ASSOCALIGNEDDIMACTIONBODY", 662 ACDBDATATABLE => "DATATABLE", 663 ); 664my %DXFNAME = 665 ( 666 POLYLINE_2D => "POLYLINE", 667 POLYLINE_3D => "POLYLINE", 668 POLYLINE_MESH => "POLYLINE", 669 POLYLINE_PFACE => "POLYLINE", 670 VERTEX_2D => "VERTEX", 671 VERTEX_3D => "VERTEX", 672 VERTEX_MESH => "VERTEX", 673 VERTEX_PFACE => "VERTEX", 674 VERTEX_PFACE_FACE => "VERTEX", 675 DIMENSION_ALIGNED => "DIMENSION", 676 DIMENSION_ANG2LN => "DIMENSION", 677 DIMENSION_ANG3PT => "DIMENSION", 678 DIMENSION_DIAMETER => "DIMENSION", 679 DIMENSION_LINEAR => "DIMENSION", 680 DIMENSION_ORDINATE => "DIMENSION", 681 DIMENSION_RADIUS => "DIMENSION", 682 TABLE => "ACAD_TABLE", 683 TABLECONTENT => "TABLE", 684 DETAILVIEWSTYLE => "ACDBDETAILVIEWSTYLE", 685 SECTIONVIEWSTYLE => "ACDBSECTIONVIEWSTYLE", 686 EVALUATION_GRAPH => "ACAD_EVALUATION_GRAPH", 687 DICTIONARYWDFLT => "ACDBDICTIONARYWDFLT", 688 PLACEHOLDER => "ACDBPLACEHOLDER", 689 CURVEPATH => "ACDBCURVEPATH", 690 MOTIONPATH => "ACDBMOTIONPATH", 691 POINTPATH => "ACDBPOINTPATH", 692 IBL_BACKGROUND => "RAPIDRTRENDERENVIRONMENT", 693 NAVISWORKSMODEL => "COORDINATION_MODEL", #? 694 PERSUBENTMGR => "ACDBPERSSUBENTMANAGER", 695 DYNAMICBLOCKPURGEPREVENTER => "ACDB_DYNAMICBLOCKPURGEPREVENTER_VERSION", 696 BLOCKREPRESENTATION => "ACDB_BLOCKREPRESENTATION_DATA", 697 DYNAMICBLOCKPROXYNODE => "ACAD_DYNAMICBLOCKPROXYNODE", 698 XREFPANELOBJECT => "EXACXREFPANELOBJECT", 699 GEOPOSITIONMARKER => "POSITIONMARKER", 700 PROXY_ENTITY => "ACAD_ENTITY_OBJECT", 701 PROXY_OBJECT => "ACAD_PROXY_OBJECT", 702 #PROXY_ENTITY => "ACAD_PROXY_ENTITY_WRAPPER", 703 #PROXY_OBJECT => "ACAD_PROXY_OBJECT_WRAPPER", 704 ); 705 706sub dxfname { 707 $_ = shift; 708 return $DXFNAME{$_} if exists $DXFNAME{$_}; 709 my $dxfname = $_; 710 if (/^(ASSOC|NAVISWORKS|POINTCLOUD)/) { 711 return "ACDB$dxfname"; 712 } 713 if (/OBJECTCONTEXTDATA$/) { 714 return "ACDB_${_}_CLASS"; 715 } 716 return $dxfname; 717} 718 719my $cfile = "$srcdir/dynapi.c"; 720chmod 0644, $cfile if -e $cfile; 721open my $fh, ">", $cfile or die "$cfile: $!"; 722 723# generate docs (GH #127) 724my $docfile = "$topdir/doc/dynapi.texi"; 725chmod 0644, $docfile if -e $docfile; 726open my $doc, ">", $docfile or die "$docfile: $!"; 727print $doc <<'EOF'; 728@c This file is automatically generated by src/gen-dynapi.pl. Do not modify here. 729@c It is intended to be included within the main document. 730 731EOF 732 733sub is_table { 734 return shift =~ /^(?:BLOCK_HEADER|LAYER|STYLE|LTYPE|VIEW|UCS| 735 VPORT|APPID|DIMSTYLE|VX_TABLE_RECORD)$/x; 736} 737 738sub is_table_control { 739 return shift =~ /^(?:BLOCK|LAYER|STYLE|LTYPE|VIEW|UCS| 740 VPORT|APPID|DIMSTYLE|VX)_CONTROL$/x; 741} 742 743sub out_declarator { 744 my ($d,$tmpl,$key,$prefix) = @_; 745 my $n = "_dwg_$key" unless $key =~ /^_dwg_/; 746 my $ns = $tmpl; 747 $ns =~ s/^struct //; 748 my $type = $d->{type}; 749 my $decl = $d->{declarators}->[0]; 750 my $name = $decl->{declarator}; 751 while ($name =~ /^\*/) { 752 $name =~ s/^\*//; 753 $type .= '*'; 754 } 755 if ($prefix) { # optional, for unions only 756 $name = $prefix . "." . $name; 757 } 758 # unexpand BITCODE_ macros: e.g. unsigned int -> BITCODE_BL 759 my $bc = exists $h{$ns} ? $h{$ns}{$name} : undef; 760 if (!$bc && $ns =~ /_CONTROL$/) { 761 $bc = $h{COMMON_TABLE_CONTROL_FIELDS}{$name}; 762 } elsif (!$bc && $ns =~ /_entity_POLYLINE_/) { 763 $bc = $h{COMMON_ENTITY_POLYLINE}{$name}; 764 } 765 $type = $bc if $bc; 766 if ($name eq 'encr_sat_data') { 767 $type = 'char **'; $bc = ''; 768 } 769 $type =~ s/\s+$//; 770 my $size = $bc ? "sizeof (BITCODE_$type)" : "sizeof ($type)"; 771 $type =~ s/BITCODE_//; 772 # TODO: DIMENSION_COMMON, _3DSOLID_FIELDS macros 773 if ($type eq 'unsigned char') { 774 $type = 'RC'; 775 } elsif ($type eq 'unsigned char*') { 776 $type = 'RC*'; 777 } elsif ($type eq 'double') { 778 $type = 'BD'; 779 } elsif ($type eq 'double*') { 780 $type = 'BD*'; 781 } elsif ($type =~ /^Dwg_Bitcode_(\w+)/) { 782 $type = $1; 783 } elsif ($type eq 'char*') { 784 $type = 'TV'; 785 } elsif ($type eq 'unsigned short int') { 786 $type = 'BS'; 787 } elsif ($type eq 'uint16_t') { 788 $type = 'BS'; 789 } elsif ($type eq 'unsigned int') { 790 $type = 'BL'; 791 } elsif ($type eq 'unsigned int*') { 792 $type = 'BL*'; 793 } elsif ($type eq 'uint32_t') { 794 $type = 'BL'; 795 } elsif ($type eq 'uint32_t*') { 796 $type = 'BL*'; 797 } elsif ($type eq 'Dwg_Object_Ref*') { 798 $type = 'H'; 799 } elsif ($type eq 'Dwg_Object_Ref**') { 800 $type = 'H*'; 801 } elsif ($type =~ /\b(unsigned|char|int|long|double)\b/) { 802 warn "unexpanded $type $n.$name\n"; 803 } elsif ($type =~ /^struct/) { 804 if ($type =~ /\*$/) { 805 $size = "sizeof (void *)"; 806 } else { 807 # e.g. MLEADER_Content.txt. 808 warn "inline struct $key.$name\n"; 809 for (@{$c->struct($d->{type})->{declarations}}) { 810 out_declarator ($_, $tmpl, $key, $name); 811 } 812 #next; 813 } 814 } elsif ($type =~ /^union/) { 815 warn "inline union $key.$name\n"; 816 for (@{$c->union($d->{type})->{declarations}}) { 817 out_declarator ($_, $tmpl, $key, $name); 818 } 819 #next; 820 } elsif ($type =~ /^HASH\(/) { # inlined struct or union 821 if ($type->{type} eq 'union' && $n !~ /^_dwg_object_/) { 822 # take all declarators and add the "$name." prefix 823 warn "note: union field $n.$name\n"; 824 for (@{$type->{declarations}}) { 825 out_declarator ($_, $tmpl, $key, $name); 826 } 827 next; 828 } else { 829 warn "ignore inlined field $n.$name\n"; 830 next; 831 } 832 } 833 if ($ENT{$key}->{$name}) { 834 $type = $ENT{$key}->{$name}; 835 } else { 836 $ENT{$key}->{$name} = $type; 837 } 838 my $is_malloc = ($type =~ /\*$/ or $type =~ /^(T$|T[UVF]|D2T)/) ? 1 : 0; 839 my $is_indirect = ($is_malloc or $type =~ /^(struct|[23T]|H$)/) ? 1 : 0; 840 my $is_string = ($is_malloc and $type =~ /^(T[UV]?|D2T)$/) ? 1 : 0; # not TF or TFF 841 my $sname = $name; 842 if ($name =~ /\[(\d+)\]$/) { 843 $is_malloc = 0; 844 $size = "$1 * $size"; 845 $sname =~ s/\[(\d+)\]$//; 846 $name = $sname if $sname eq 'conn_pts'; 847 } 848 if ($type =~ /^TF/ && exists $SIZE{$key}->{$name}) { 849 $size = $SIZE{$key}->{$name}; 850 } 851 my $dxf = $DXF{$key}->{$name}; 852 if (!$dxf && $key =~ /DIMENSION/) { 853 $dxf = $DXF{COMMON_ENTITY_DIMENSION}->{$name}; 854 } 855 if (!$dxf && $key =~ /ASSOC/) { 856 $dxf = $DXF{ASSOCACTION}->{$name}; 857 } 858 $dxf = 0 unless $dxf; 859 warn "no dxf for $key: $name 0\n" unless $dxf or 860 ($name eq 'parent') or 861 ($key eq 'header_variables' and $name eq lc($name)); 862 863 printf $fh " { \"%s\",\t\"%s\", %s, OFF (%s, %s),\n %d,%d,%d, %d },\n", 864 $name, $type, $size, $tmpl, $sname, $is_indirect, $is_malloc, $is_string, $dxf; 865 866 print $doc "\@item $name\n$type", $dxf ? ",\tDXF $dxf" : "", "\n"; 867} 868 869# until the type is a struct or union 870sub expand_typedef { 871 my $s = shift; 872 if ($s =~ /^(struct|union)/) { 873 return $s; 874 } 875 my $typedef = $c->typedef($s); 876 return undef unless $typedef; 877 my $type; 878 $s = $typedef->{type}; 879 while ($s and $s !~ /^(struct|union)/) { 880 $s = expand_typedef ($s); 881 } 882 return $s; 883} 884 885my %out_struct; 886sub out_struct { 887 my ($tmpl, $n) = @_; 888 #print $fh " /* ", Data::Dumper->Dump([$s], [$n]), "*/\n"; 889 my $key = $n; 890 my $sortedby = 'offset'; 891 my $s = $c->struct($tmpl); 892 unless ($s) { 893 $s = $c->union($tmpl); 894 } 895 unless ($s) { # resolve abstract typedef to struct|union 896 $s = expand_typedef ($tmpl); 897 $s = $c->struct($s) if $s; 898 } 899 unless ($s->{declarations}) { 900 delete $ENT{$n}; # don't show up in dynapi_test.c 901 return; 902 } 903 if (exists $out_struct{$tmpl}) { 904 warn "skip duplicate $tmpl\n"; 905 my $see = $out_struct{$tmpl}; 906 print $doc "\@indentedblock\n"; 907 print $doc "\@xref{$see}\n"; 908 print $doc "\@end indentedblock\n\n"; 909 return; 910 } 911 $out_struct{$tmpl} = $key; 912 $n = "_dwg_$n" unless $n =~ /^_dwg_/; 913 my @declarations = @{$s->{declarations}}; 914 if ($n =~ /^_dwg_(header_variables|object_object|object_entity)$/) { 915 @declarations = sort { 916 my $aname = $a->{declarators}->[0]->{declarator}; 917 my $bname = $b->{declarators}->[0]->{declarator}; 918 $aname =~ s/^\*//g; 919 $bname =~ s/^\*//g; 920 return $aname cmp $bname 921 } @declarations; 922 $sortedby = 'name'; 923 } 924 if ($tmpl =~ /_dwg_object_/) { 925 if (is_table($key)) { 926 print $doc "\@cindex table, $key\n\n"; 927 print $doc "$key is a table object.\n\n"; 928 } 929 elsif (is_table_control($key)) { 930 print $doc "\@cindex table_control, $key\n\n"; 931 print $doc "$key is a table_control object.\n\n"; 932 } 933 } 934 print $doc "\@indentedblock\n"; 935 print $doc "\@vtable \@code\n\n"; 936 print $fh "/* from typedef $tmpl: (sorted by $sortedby) */\n", 937 "static const Dwg_DYNAPI_field $n","_fields[] = {\n"; 938 for my $d (@declarations) { 939 out_declarator($d, $tmpl, $key); 940 } 941 print $fh " {NULL,\tNULL,\t0,\t0,\t0,0,0, 0},\n"; 942 print $fh "};\n"; 943 print $doc "\n\@end vtable\n"; 944 print $doc "\@end indentedblock\n\n"; 945} 946 947sub maxlen { 948 my $maxlen = 0; 949 for (@_) { 950 $maxlen = length($_) if $maxlen < length($_); 951 } 952 $maxlen 953} 954$max_entity_names = 1+maxlen(@entity_names); 955$max_object_names = 1+maxlen(@object_names); 956my %entity_names = map {$_ => 1} @entity_names; 957my %object_names = map {$_ => 1} @object_names; 958$max_subclasses = 0; 959for (keys %SUBCLASSES) { 960 if (!exists $entity_names{$_} and !exists $object_names{$_}) { 961 # FIXME: find parent class and add array to it. 962 # delete $SUBCLASSES{$_}; 963 } 964} 965for (sort @entity_names) { 966# FIXME: fixup duplicates in TEXT 967 if ($_ eq 'TEXT') { 968 $SUBCLASSES{$_} = [ 'AcDbText' ]; 969 } elsif (/^...UNDERLAY$/) { 970 $SUBCLASSES{$_} = [ 'AcDbUnderlayReference' ]; 971 } 972 my $aref = $SUBCLASSES{$_}; 973 unshift @$aref, 'AcDbEntity'; 974 $SUBCLASSES{$_} = $aref; # if it didnt exist 975 my $len = @$aref; 976 $max_subclasses = $len if $len > $max_subclasses; 977} 978# /^(BLOCK_HEADER|LAYER|STYLE|LTYPE|VIEW|UCS|VPORT|APPID|DIMSTYLE|VX_TABLE_RECORD)$/ 979my %table_dxfname = ( # See COMMON_TABLE_FLAGS 980 BLOCK_HEADER => 'Block', 981 LAYER => 'Layer', 982 STYLE => 'TextStyle', 983 LTYPE => 'Linetype', 984 VIEW => 'View', 985 UCS => 'UCS', 986 VPORT => 'Viewport', 987 APPID => 'RegApp', 988 DIMSTYLE => 'DimStyle', 989 VX_TABLE_RECORD => 'VX', 990); 991for (sort @object_names) { 992 my $aref = $SUBCLASSES{$_}; 993 if (is_table ($_)) { 994 unshift @$aref, ('AcDbSymbolTableRecord', 'AcDb' . $table_dxfname{$_} . 'TableRecord'); 995 } elsif (is_table_control ($_)) { 996 unshift @$aref, 'AcDbSymbolTable'; 997 } else { 998 unshift @$aref, 'AcDbObject'; 999 } 1000 $SUBCLASSES{$_} = $aref; # if it didnt exist 1001 my $len = @$aref; 1002 $max_subclasses = $len if $len > $max_subclasses; 1003} 1004 1005# --------------------------------------------------------------- 1006for (<DATA>) { 1007 # expand enum or struct 1008 if (/^(.*)\@\@(\w+ \w+)\@\@(.*)/) { 1009 my ($pre, $post) = ($1, $3); 1010 my $tmpl = $2; 1011 print $fh $pre; 1012 if ($tmpl =~ /^enum (\w+)/) { 1013 my $s = $c->enum($tmpl); 1014 #print $fh "\n/* "; 1015 #print $fh Data::Dumper->Dump([$s], [$1]); 1016 #print $fh "\n*/"; 1017 my $i = 0; 1018 my @keys = map { s/^DWG_TYPE__3D/DWG_TYPE_3D/; $_ } keys %{$s->{enumerators}}; 1019 for (sort @keys) { 1020 my ($k,$v) = ($_, $s->{enumerators}->{$_}); 1021 if ($tmpl eq 'enum DWG_OBJECT_TYPE') { 1022 $k =~ s/^DWG_TYPE_//; 1023 # Let the type rather be symbolic: DWG_TYPE_SOLID, not int 1024 my $vs = $_; 1025 if (!$v && $k =~ /^3D/) { 1026 $v = $s->{enumerators}->{'DWG_TYPE__'.$k}; 1027 $vs = 'DWG_TYPE__'.$k; 1028 } 1029 my $size = "0"; 1030 if ($c->struct("_dwg_entity_$k")) { 1031 $size = "sizeof (struct _dwg_entity_$k)"; 1032 } elsif ($c->struct("_dwg_object_$k")) { 1033 $size = "sizeof (struct _dwg_object_$k)"; 1034 #} elsif ($c->typedef("Dwg_Object_$k")) { 1035 # my $type = expand_typedef ("Dwg_Object_$k"); 1036 # if ($type) { 1037 # $size = "sizeof (Dwg_Object_$k)"; 1038 # $k = $type; 1039 # $k =~ s/struct //; 1040 # $k =~ s/_dwg_(?:abstract)?object_//; 1041 # $k =~ s/ //g; 1042 # } 1043 #} elsif ($c->typedef("Dwg_Entity_$k")) { 1044 # my $type = expand_typedef ("Dwg_Entity_$k"); 1045 # if ($type) { 1046 # $size = "sizeof (Dwg_Entity_$k)"; 1047 # $k = $type; 1048 # $k =~ s/struct //; 1049 # $k =~ s/_dwg_(?:abstract)?entity_//; 1050 # $k =~ s/ //g; 1051 # } 1052 } 1053 # see if the fields do exist: 1054 my $fields = exists $structs{$k} ? "_dwg_".$k."_fields" : "NULL"; 1055 if ($k =~ /^(BODY|REGION)$/) { 1056 $fields = "_dwg_3DSOLID_fields"; 1057 $size = "sizeof (struct _dwg_entity_3DSOLID)"; 1058 } elsif ($k eq 'XLINE') { 1059 $fields = "_dwg_RAY_fields"; 1060 $size = "sizeof (struct _dwg_entity_RAY)"; 1061 } elsif ($k =~ /^(PDF|DWF|DGN)DEFINITION$/) { 1062 $fields = "_dwg_UNDERLAYDEFINITION_fields"; 1063 $size = "sizeof (Dwg_Object_$k)"; 1064 } elsif ($k =~ /^(PDF|DWF|DGN)UNDERLAY$/) { 1065 $fields = "_dwg_UNDERLAY_fields"; 1066 $size = "sizeof (Dwg_Entity_$k)"; 1067 } elsif ($k =~ /^ASSOCARRAY(?:MODIFY|PATH|POLAR|RECTANGULAR)PARAMETERS$/) { 1068 $fields = "_dwg_ASSOCARRAYPARAMETERS_fields"; 1069 $size = "sizeof (Dwg_Object_ASSOCARRAYPARAMETERS)"; 1070 } elsif ($k =~ /^VERTEX_(MESH|PFACE)$/) { 1071 $fields = "_dwg_VERTEX_3D_fields"; 1072 $size = "sizeof (struct _dwg_entity_VERTEX_3D)"; 1073 } elsif ($k =~ /^PROXY_LWPOLYLINE$/) { # TODO subent, not entity 1074 $size = "sizeof (struct _dwg_entity_PROXY_LWPOLYLINE)"; 1075 } 1076 $DWG_TYPE{$k} = $vs; 1077 printf $fh " { \"%s\", %s /*(%d)*/, %s, %s },\t/* %d */\n", 1078 $k, $vs, $v, $fields, $size, $i++; 1079 } else { 1080 printf $fh " { \"%s\", %d },\t/* %d */\n", 1081 $k, $v, $i++; 1082 } 1083 } 1084 } elsif ($tmpl =~ /^list (\w+)/) { 1085 no strict 'refs'; 1086 my $n = $1; 1087 my $i = 0; 1088 my $maxlen = 0; 1089 for (@{$n}) { 1090 $maxlen = length($_) if $maxlen < length($_); 1091 } 1092 if ($n eq 'subclasses') { 1093 for (sort @{$n}) { 1094 if (/^_dwg_(.*)/) { 1095 my $n = $1; 1096 # find class type for this subclass. DWG_TYPE_parent if unique, or -1 1097 my $type = 0; 1098 for my $o (keys %DWG_TYPE) { 1099 my $match = qr '^' . $o . '_\w+'; 1100 if ($n =~ $match) { 1101 if ($type) { 1102 $type = '-1'; # multiple 1103 } else { 1104 $type = '(int)'.$DWG_TYPE{$o}; 1105 } 1106 } 1107 } 1108 my $size = "sizeof (Dwg_$n)"; 1109 if ($c->union("$_")) { 1110 $size = "sizeof (Dwg_$n)"; 1111 } 1112 my $subclass = $SUBCLASS{$n}; 1113 if ($subclass) { 1114 $subclass = '"' . $subclass . '"'; 1115 } else { 1116 $subclass = "NULL"; 1117 } 1118 printf $fh " { \"%s\", %s, %s, %s, %s },\t/* %d */\n", 1119 $n, $type, $subclass, $_ . "_fields", $size, $i++; 1120 } 1121 } 1122 } elsif ($n eq 'name_subclasses') { 1123 #print Dumper \%SUBCLASSES; 1124 for (sort keys %SUBCLASSES) { 1125 my $cl = $_; 1126 if (exists $entity_names{$cl} or exists $object_names{$cl}) { 1127 my $a = $SUBCLASSES{$cl}; 1128 # $cl =~ s/^3D/_3D/; 1129 printf $fh " { \"%s\", {", $cl; 1130 for (0 .. $max_subclasses-1) { 1131 if ($a->[$_]) { 1132 printf $fh "\"%s\"", $a->[$_]; 1133 } else { 1134 printf $fh "NULL"; 1135 } 1136 if ($_ < $max_subclasses - 1) { 1137 printf $fh ", "; 1138 } 1139 } 1140 printf $fh "} },\n"; 1141 } 1142 } 1143 } else { 1144 for (@{$n}) { 1145 my $len = length($_); 1146 printf $fh " \"%s\" \"%s\",\t/* %d */\n", $_, "\\0" x ($maxlen-$len), $i++; 1147 } 1148 } 1149 } elsif ($tmpl =~ /^scalar (\w+)/) { 1150 no strict 'refs'; 1151 my $n = $1; 1152 printf $fh ${$n}; 1153 } elsif ($tmpl =~ /^for dwg_entity_ENTITY/) { 1154 print $doc "\n\@node ENTITIES\n\@section ENTITIES\n\@cindex ENTITIES\n\n"; 1155 print $doc "All graphical objects with its fields. \@xref{Common Entity fields}\n\n"; 1156 for (@entity_names) { 1157 print $doc "\@strong{$_} \@anchor{$_}\n\@cindex entity, $_\n", 1158 "\@vindex $_\n" unless $_ eq 'DIMENSION_'; 1159 print $doc "\@anchor{UNDERLAY}\n\@vindex UNDERLAY\n" if /^DGNUNDERLAY/; 1160 print $doc "\n" unless $_ eq 'DIMENSION_'; 1161 my $typedef = $c->typedef("Dwg_Entity_$_"); 1162 # multiple type aliases, only emit one _field[] 1163 if ($typedef and $typedef->{type} ne "struct _dwg_entity_$_") { 1164 my $type = expand_typedef ($typedef->{type}); 1165 if ($type) { 1166 my $n = $type; 1167 $n =~ s/struct //; 1168 $n =~ s/_dwg_(?:abstract)?entity_//; 1169 $n =~ s/ //g; 1170 out_struct($type, $n); 1171 } else { 1172 out_struct("struct _dwg_entity_$_", $_); 1173 } 1174 } else { 1175 out_struct("struct _dwg_entity_$_", $_); 1176 } 1177 } 1178 } elsif ($tmpl =~ /^for dwg_object_OBJECT/) { 1179 print $doc "\n\@node OBJECTS\n\@section OBJECTS\n\@cindex OBJECTS\n\n"; 1180 print $doc "All non-graphical objects with its fields. \@xref{Common Object fields}\n\n"; 1181 for (@object_names) { 1182 print $doc "\@strong{$_} \@anchor{$_}\n\@cindex object, $_\n\@vindex $_\n"; 1183 print $doc "\@anchor{UNDERLAYDEFINITION}\n\@vindex UNDERLAYDEFINITION\n" if /^PDFDEFINITION/; 1184 print $doc "\@anchor{ASSOCARRAYPARAMETERS}\n\@vindex ASSOCARRAYPARAMETERS\n" if /^ASSOCARRAYMODIFYPARAMETERS/; 1185 print $doc "\n"; 1186 my $typedef = $c->typedef("Dwg_Object_$_"); 1187 if ($typedef and $typedef->{type} ne "struct _dwg_object_$_") { 1188 my $type = expand_typedef ($typedef->{type}); # unify to one struct 1189 if ($type) { 1190 my $n = $type; 1191 $n =~ s/struct //; 1192 $n =~ s/_dwg_(?:abstract)?object_//; 1193 $n =~ s/ //g; 1194 out_struct($type, $n); 1195 } else { 1196 out_struct("struct _dwg_object_$_", $_); 1197 } 1198 } else { 1199 out_struct("struct _dwg_object_$_", $_); 1200 } 1201 } 1202 } elsif ($tmpl =~ /^for dwg_subclasses/) { 1203 for (@subclasses) { 1204 my ($name) = $_ =~ /^_dwg_(.*)/; 1205 print $doc "\@strong{Dwg_$name} \@anchor{Dwg_$name}\n\@vindex Dwg_$name\n\n"; 1206 if ($unions{$_}) { 1207 out_struct("union $_", $name); 1208 } else { 1209 out_struct("struct $_", $name); 1210 } 1211 } 1212 } elsif ($tmpl =~ /^struct _dwg_(\w+)/) { 1213 if ($1 eq 'header_variables') { 1214 print $doc "\n\@node HEADER\n\@section HEADER\n\@cindex HEADER\n\n"; 1215 print $doc "All header variables.\n\n"; 1216 } elsif ($1 eq 'object_object') { 1217 print $doc "\@strong{Common Object fields} \@anchor{Common Object fields}\n"; 1218 print $doc "\@cindex Common Object fields\n\n"; 1219 } elsif ($1 eq 'object_entity') { 1220 print $doc "\@strong{Common Entity fields} \@anchor{Common Entity fields}\n"; 1221 print $doc "\@cindex Common Entity fields\n\n"; 1222 } elsif ($1 eq 'summaryinfo') { 1223 print $doc "\@strong{SummaryInfo fields} \@anchor{SummaryInfo fields}\n"; 1224 print $doc "\@cindex SummaryInfo fields\n\n"; 1225 print $doc "\@pxref{SummaryInfo}\n\n"; 1226 } else { 1227 print $doc "\@strong{$1}\n"; 1228 print $doc "\@vindex $1\n\n"; 1229 } 1230 out_struct($tmpl, $1); 1231 } elsif ($tmpl =~ /^struct Dwg_(\w+)/) { 1232 print $doc "\@strong{$1}\n"; 1233 print $doc "\@vindex $1\n\n"; 1234 out_struct($tmpl, $1); 1235 } 1236 print $fh $post,"\n"; 1237 } else { 1238 print $fh $_; 1239 } 1240} 1241chmod 0444, $fh; 1242close $fh; 1243chmod 0444, $doc; 1244close $doc; 1245 1246# TODO: use dwg.h formats 1247my %FMT = ( 1248 'double' => '%g', 1249 'unsigned char' => '%c', 1250 'unsigned int' => '%u', 1251 'unsigned long' => '%lu', 1252 'unsigned short int' => '%hu', 1253 'short' => '%hd', 1254 'long' => '%l', 1255 'char**' => '%p', 1256 'TV' => '%s', 1257 'T' => '%s', 1258 'D2T' => '%s', 1259 'TU' => '%ls', 1260 'TFF' => '%s', 1261 'BD' => '%g', 1262 'BL' => '%u', 1263 'BS' => '%hu', 1264 'RD' => '%g', 1265 'RL' => '%u', 1266 'RS' => '%hu', 1267 'RC' => '%u', 1268 'RC*' => '%s', 1269 ); 1270 1271# --------------------------------------------------------------- 1272# The simple list of macro defs (linear search) 1273my $objfile = "$srcdir/objects.inc"; 1274chmod 0644, $objfile if -e $objfile; 1275open my $inc, ">", "$objfile.tmp" or die "$objfile: $!"; 1276print $inc <<"EOF"; 1277/* ex: set ro ft=c: -*- mode: c; buffer-read-only: t -*- */ 1278/*****************************************************************************/ 1279/* LibreDWG - free implementation of the DWG file format */ 1280/* */ 1281/* Copyright (C) 2019-2020 Free Software Foundation, Inc. */ 1282/* */ 1283/* This library is free software, licensed under the terms of the GNU */ 1284/* General Public License as published by the Free Software Foundation, */ 1285/* either version 3 of the License, or (at your option) any later version. */ 1286/* You should have received a copy of the GNU General Public License */ 1287/* along with this program. If not, see <http://www.gnu.org/licenses/>. */ 1288/*****************************************************************************/ 1289 1290/* 1291 * objects.inc: define all object and entities 1292 * written by Reini Urban 1293 * generated by src/gen-dynapi.pl from include/dwg.h, do not modify. 1294 */ 1295 1296EOF 1297 1298for my $name (@entity_names) { 1299 my $xname = $name =~ /^3/ ? "_$name" : $name; # 3DFACE, 3DSOLID 1300 next if $name eq 'DIMENSION_'; 1301 next if $name eq 'PROXY_LWPOLYLINE'; 1302 print $inc "DWG_ENTITY ($xname)\n"; 1303} 1304print $inc "\n"; 1305for my $name (@object_names) { 1306 print $inc "DWG_OBJECT ($name)\n"; 1307} 1308close $inc; 1309mv_if_not_same ("$objfile.tmp", $objfile); 1310chmod 0444, $objfile; 1311 1312# --------------------------------------------------------------- 1313my $infile = "$topdir/test/unit-testing/dynapi_test.c.in"; 1314open $in, $infile or die "$infile: $!"; 1315$cfile = "$topdir/test/unit-testing/dynapi_test.c"; 1316chmod 0644, $cfile if -e $cfile; 1317open $fh, ">", $cfile or die "$cfile: $!"; 1318print $fh "/* ex: set ro ft=c: -*- mode: c; buffer-read-only: t -*- */\n"; 1319 1320for (<$in>) { 1321 print $fh $_; 1322 if (m{/\* \@\@for test_HEADER\@@ \*/}) { 1323 my $s = $c->struct('_dwg_header_variables'); 1324 for my $d (@{$s->{declarations}}) { 1325 my $type = $d->{type}; 1326 my $decl = $d->{declarators}->[0]; 1327 my $name = $decl->{declarator}; 1328 while ($name =~ /^\*/) { 1329 $name =~ s/^\*//; 1330 $type .= '*'; 1331 } 1332 $type =~ s/ $//g; 1333 my $xname = $name =~ /^3/ ? "_$name" : $name; 1334 my $lname = lc $xname; 1335 my $var = $lname; 1336 my $sname = $name; 1337 if (exists $ENT{header_variables}->{$name}) { 1338 $type = $ENT{header_variables}->{$name}; 1339 } 1340 $type =~ s/D_1$/D/; 1341 my $fmt = exists $FMT{$type} ? $FMT{$type} : undef; 1342 if (!$fmt) { 1343 if ($type =~ /[ \*]/ or $type eq 'H') { 1344 $fmt = '%p'; 1345 } else { 1346 $fmt = "\" FORMAT_$type \""; 1347 } 1348 } 1349 my $is_ptr = ($type =~ /^(struct|Dwg_)/ or 1350 $type =~ /^[23HT]/ or 1351 $type =~ /\*$/ or 1352 $var =~ /\[\d+\]$/ or 1353 $type =~ /^(BE|CMC)$/) 1354 ? 1 : 0; 1355 if ($var =~ /\[\d+\]$/) { 1356 $lname =~ s/\[\d+\]$//g; 1357 $sname =~ s/\[\d+\]$//g; 1358 } 1359 my $stype = $type; 1360 $type = 'BITCODE_'.$type unless ($type =~ /^(struct|Dwg_)/ or $type =~ /^[a-z]/); 1361 if (!$is_ptr) { 1362 print $fh <<"EOF"; 1363 { 1364 $type $var; 1365 if (dwg_dynapi_header_value (dwg, "$name", &$var, NULL) 1366 && $var == dwg->header_vars.$name) 1367 pass (); 1368 else 1369 fail ("HEADER.$name [$stype] $fmt != $fmt", dwg->header_vars.$sname, $var); 1370EOF 1371 if ($type =~ /(int|long|short|char ||double|_B\b|_B[BSLD]\b|_R[CSLD])/) { 1372 print $fh " $var++;\n"; 1373 } 1374 print $fh <<"EOF"; 1375 if (dwg_dynapi_header_set_value (dwg, "$name", &$var, 0) 1376 && $var == dwg->header_vars.$name) 1377 pass (); 1378 else 1379 fail ("HEADER.$name [$stype] set+1 $fmt != $fmt", 1380 dwg->header_vars.$sname, $var); 1381EOF 1382 if ($type =~ /(int|long|short|char ||double|_B\b|_B[BSLD]\b|_R[CSLD])/) { 1383 print $fh " $var--;\n"; 1384 print $fh " dwg_dynapi_header_set_value (dwg, \"$name\", &$var, 0);\n"; 1385 } 1386 print $fh "\n }\n"; 1387 } else { 1388 print $fh <<"EOF"; 1389 { 1390 $type $var; 1391 if (dwg_dynapi_header_value (dwg, "$name", &$lname, NULL) 1392EOF 1393 if ($type !~ /\*\*/) { 1394 print $fh <<"EOF"; 1395 && !memcmp (&$lname, &dwg->header_vars.$sname, sizeof (dwg->header_vars.$sname)) 1396EOF 1397 } 1398 print $fh <<"EOF"; 1399 ) 1400 pass (); 1401 else 1402 fail ("HEADER.$name [$stype]"); 1403 } 1404EOF 1405 } 1406 } 1407 } 1408 if (m{/\* \@\@for if_test_OBJECT\@\@ \*/}) { # The impl, inside test_object 1409 for my $name (@entity_names, @object_names) { 1410 my $xname = $name =~ /^3/ ? "_$name" : $name; # 3DFACE, 3DSOLID 1411 #next if $name eq 'DIMENSION_'; 1412 next if $name =~ /^(PROXY_LWPOLYLINE|UNKNOWN_)/; 1413 print $fh " else" if $name ne '3DFACE'; # the first 1414 print $fh <<"EOF"; 1415 if (obj->fixedtype == DWG_TYPE_$xname) 1416 error += test_$xname(obj); 1417EOF 1418 } 1419 } 1420 # The first, as decl 1421 if (m{/\* \@\@for test_OBJECT\@\@ \*/}) { 1422 for my $name (@entity_names, @object_names) { 1423 #next if $name eq 'DIMENSION_'; 1424 #TABLE is stored as fixedtype UNKNOWN_ENT, so the dynapi test would fail 1425 next if $name =~ /^(PROXY_LWPOLYLINE|UNKNOWN_)/; 1426 my $is_ent = grep { $name eq $_ } @entity_names; 1427 my ($Entity, $lentity) = $is_ent ? ('Entity', 'entity') : ('Object', 'object'); 1428 my $xname = $name =~ /^3/ ? "_$name" : $name; 1429 my $lname = lc $xname; 1430 my $struct = "Dwg_$Entity" . "_$xname"; 1431 print $fh <<"EOF"; 1432static int test_$xname (const Dwg_Object *obj) 1433{ 1434 int error = 0; 1435 const Dwg_Object_$Entity *restrict obj_obj = obj->tio.$lentity; 1436 $struct *restrict $lname = obj->tio.$lentity->tio.$xname; 1437 failed = 0; 1438 if (!obj_obj || !$lname) 1439 { 1440 fail ("NULL $xname"); 1441 return 1; 1442 } 1443EOF 1444 1445 for my $var (sort keys %{$ENT{$name}}) { 1446 my $type = $ENT{$name}->{$var}; 1447 # if 0 ignored in .spec 1448 # next if $type eq 'T' and $name eq 'LIGHT' and $var eq 'web_file'; 1449 # next if $type eq 'TF' and $name eq 'SUN' and $var eq 'bytes'; 1450 my $fmt = exists $FMT{$type} ? $FMT{$type} : undef; 1451 if (!$fmt) { 1452 if ($type =~ /[ \*]/ or $type eq 'H') { 1453 $fmt = '%p'; 1454 } else { 1455 $fmt = "\" FORMAT_$type \""; 1456 } 1457 } 1458 my $key = $var; 1459 my $svar = $var; 1460 my $skey = $var; 1461 my $is_ptr = ($type =~ /^(struct|Dwg_)/ or 1462 $type =~ /^[TH23]/ or 1463 $type =~ /\*$/ or 1464 $var =~ /\[\d+\]$/ or 1465 $type =~ /^(BE|CMC)$/) 1466 ? 1 : 0; 1467 if ($var =~ /\./) { # embedded structs, like ovr.name. some have fields, some not 1468 next if $var =~ /^ovr\./; 1469 $svar =~ s/\./_/g; 1470 $var = $svar; 1471 } 1472 if ($var =~ /\[\d+\]$/) { 1473 $svar =~ s/\[\d+\]$//g; 1474 $skey =~ s/\[\d+\]$//g; 1475 $var = $svar if $var =~ /^conn_pts\[\d\]$/; 1476 } 1477 next if $key eq 'evalexpr.value.text1'; # already handled by evalexpr memcmp 1478 my $stype = $type; 1479 $type =~ s/D_1$/D/; 1480 $type = 'BITCODE_'.$type unless ($type =~ /^(struct|Dwg_)/ or $type =~ /^[a-z]/); 1481 if (!$is_ptr) { 1482 # TODO DEBUGGING [BR]D can be nan 1483 print $fh <<"EOF"; 1484 { 1485 $type $var; 1486 if (dwg_dynapi_entity_value ($lname, "$name", "$key", &$svar, NULL) 1487 && $var == $lname->$key) 1488 pass (); 1489 else 1490 fail ("$name.$key [$stype] $fmt != $fmt", $lname->$key, $svar); 1491EOF 1492 if ($type =~ /(int|long|short|char|double|_B\b|_B[BSLD]\b|_R[CSLD])/) { 1493 print $fh " $svar++;\n"; 1494 } 1495 print $fh <<"EOF"; 1496 if (dwg_dynapi_entity_set_value ($lname, "$name", "$key", &$svar, 0) 1497 && $var == $lname->$key) 1498 pass (); 1499 else 1500 fail ("$name.$key [$stype] set+1 $fmt != $fmt", $lname->$key, $svar); 1501EOF 1502 if ($type =~ /(int|long|short|char ||double|_B\b|_B[BSLD]\b|_R[CSLD])/) { 1503 print $fh " $lname->$key--;"; 1504 } 1505 print $fh "\n }\n"; 1506 } elsif ($type =~ /\*$/ and $type !~ /(RC\*|struct _dwg_object_)/ 1507 # no countfield 1508 and $var !~ /^(ref|block_size|extra_acis_data|objid_object_handles)$/ 1509 # VECTOR_N 1510 and $var !~ /(_transform|_transmatrix1?|shhn_pts)$/) { 1511 my %countfield = ( 1512 attribs => 'num_owned', 1513 attribs => 'num_owned', # XXX TABLE 1514 vertex => 'num_owned', 1515 itemhandles => 'numitems', 1516 entities => 'num_owned', 1517 #inserts => 'num_inserts', 1518 #groups => 'num_groups', 1519 #field_handles => 'num_fields', 1520 sort_ents => 'num_ents', 1521 attr_def_id => 'num_attr_defs', 1522 layer_entries => 'num_entries', 1523 readdeps => 'num_deps', 1524 writedeps => 'num_deps', 1525 dashes_r11 => 'num_dashes', 1526 texts => 'numitems', 1527 encr_sat_data => 'num_blocks', 1528 ); 1529 my $countfield = exists $countfield{$var} ? $countfield{$var} : "num_$var"; 1530 $countfield = 'num_dashes' if $name eq 'LTYPE' and $var eq 'styles'; 1531 my $count = 1; 1532 if ($var eq 'encr_sat_data') { 1533 print $fh <<"EOF"; 1534 { 1535 $type $var; 1536 if (dwg_dynapi_entity_value ($lname, "$name", "$key", &$svar, NULL) 1537 && !memcmp (&$svar, &$lname->$skey, sizeof ($lname->$skey))) 1538 pass (); 1539 else 1540 fail ("$name.$key [$stype]"); 1541 } 1542EOF 1543 } 1544 elsif ($var eq 'reactors' and $type eq 'BITCODE_H*') { 1545 print $fh <<"EOF"; 1546 { 1547 $type $var; 1548 BITCODE_BL count = obj_obj->num_reactors; 1549 if (dwg_dynapi_entity_value ($lname, "$name", "$key", &$svar, NULL) 1550 && $svar == $lname->$key) 1551 pass (); 1552 else 1553 fail ("$name.$var [$stype] * %u $countfield", count); 1554 } 1555EOF 1556 } else { 1557 print $fh <<"EOF"; 1558 { 1559 $type $var; 1560 BITCODE_BL count = 0; 1561 if (dwg_dynapi_entity_value ($lname, "$name", "$countfield", &count, NULL) 1562 && dwg_dynapi_entity_value ($lname, "$name", "$var", &$svar, NULL) 1563EOF 1564 if ($type eq 'BITCODE_BD') { 1565 print $fh " && (isnan ($svar) || $svar == $lname->$svar)"; 1566 } 1567 elsif ($type !~ /\*\*/) { 1568 print $fh " && $svar == $lname->$svar"; 1569 } 1570 print $fh ")\n"; 1571 print $fh <<"EOF"; 1572 pass (); 1573 else 1574 fail ("$name.$var [$stype] * %u $countfield", count); 1575 } 1576EOF 1577 } 1578 } else { # is_ptr 1579 my $is_str; 1580 my $vardecl = $var; 1581 my $size = "sizeof ($type)"; 1582 if (0 and $stype =~ /^TF/) { 1583 my $_size = $SIZE{$name}->{$var}; 1584 if ($_size && $_size =~ /^\d+$/) { 1585 $type = 'char'; 1586 $size = $_size; 1587 $vardecl .= "[$size]"; 1588 if ($var eq 'strings_area') { 1589 $vardecl .= ";\n const Dwg_Data* dwg = obj->parent;"; 1590 $vardecl .= "\n const int size = dwg->header.version >= 2004 ? 512 : 256"; 1591 $size = 'size'; 1592 } 1593 } 1594 } 1595 print $fh <<"EOF"; 1596 { 1597 $type $vardecl; 1598 if (dwg_dynapi_entity_value ($lname, "$name", "$key", &$svar, NULL) 1599EOF 1600 if ($stype =~ /^(TV|T|TU|RC\*|unsigned char\*|char\*)$/) { 1601 $is_str = 1; 1602 print $fh " && $svar\n"; 1603 print $fh " ? strEQ ((char *)$svar, (char *)$lname->$key)\n"; 1604 print $fh " : !$lname->$key)\n"; 1605 } elsif (0 and $stype =~ /^TF/ and $size !~ /^sizeof/) { 1606 print $fh " && !memcmp ($svar, $lname->$skey, $size))\n"; 1607 } elsif ($type !~ /\*\*/) { 1608 print $fh " && !memcmp (&$svar, &$lname->$skey, $size))\n"; 1609 } else { 1610 print $fh ")\n"; 1611 } 1612 if ($is_str) { 1613 print $fh <<"EOF"; 1614 pass (); 1615 else 1616 fail ("$name.$key [$stype] '$fmt' <> '$fmt'", $svar, $lname->$skey); 1617 } 1618EOF 1619 } else { 1620 print $fh <<"EOF"; 1621 pass (); 1622 else 1623 fail ("$name.$key [$stype]"); 1624 } 1625EOF 1626 } 1627 } 1628 } 1629 print $fh <<"EOF"; 1630 if (failed && (is_class_unstable ("$name") || is_class_debugging ("$name"))) 1631 { 1632 ok ("%s failed %d tests (TODO unstable)", "$name", failed); 1633 failed = 0; 1634 } 1635 return failed; 1636} 1637EOF 1638 } 1639 } 1640 1641 if (m{/\* \@\@for if_test_OBJECT\@\@ \*/}) { 1642 for my $name (@entity_names, @object_names) { 1643 my $xname = $name =~ /^3/ ? "_$name" : $name; # 3DFACE, 3DSOLID 1644 next if $name eq 'DIMENSION_'; 1645 next if $name =~ /^(PROXY_LWPOLYLINE|UNKNOWN_)/; 1646 print $fh " else" if $name ne '3DFACE'; # the first 1647 print $fh <<"EOF"; 1648 if (obj->fixedtype == DWG_TYPE_$xname) 1649 error += test_$xname (obj); 1650EOF 1651 } 1652 } 1653 1654 if (m{/\* \@\@for test_SIZES\@\@ \*/}) { 1655 for my $name (@entity_names) { 1656 my $xname = $name =~ /^3/ ? "_$name" : $name; # 3DFACE, 3DSOLID 1657 print $fh <<"EOF"; 1658 size1 = sizeof (Dwg_Entity_$xname); 1659 size2 = dwg_dynapi_fields_size (\"$name\"); 1660 if (size1 != size2) 1661 { 1662 fprintf (stderr, "sizeof(Dwg_Entity_$xname): %d != " 1663 "dwg_dynapi_fields_size (\\\"$name\\\"): %d\\n", size1, size2); 1664 error++; 1665 } 1666EOF 1667 if ($name eq 'PROXY_LWPOLYLINE') { 1668 print $fh <<"EOF"; 1669 if (size1 != size2) // TODO 1670 error--; 1671EOF 1672 } 1673 } 1674 for my $name (@object_names) { 1675 my $xname = $name; 1676 print $fh <<"EOF"; 1677 size1 = sizeof (Dwg_Object_$xname); 1678 size2 = dwg_dynapi_fields_size (\"$name\"); 1679 if (size1 != size2) 1680 { 1681 fprintf (stderr, "sizeof(Dwg_Object_$xname): %d != " 1682 "dwg_dynapi_fields_size (\\\"$name\\\"): %d\\n", size1, size2); 1683 error++; 1684 } 1685EOF 1686 } 1687 for my $name (@subclasses) { 1688 my $xname = $name; 1689 my $struct = "struct $name"; 1690 if ($unions{$name}) { 1691 $struct = "union $name"; 1692 } 1693 $xname =~ s/^_dwg_//; 1694 print $fh <<"EOF"; 1695 size1 = sizeof ($struct); 1696 size2 = dwg_dynapi_fields_size (\"$xname\"); 1697 if (size1 != size2) 1698 { 1699 fprintf (stderr, "sizeof($struct): %d != " 1700 "dwg_dynapi_fields_size (\\\"$xname\\\"): %d\\n", size1, size2); 1701 error++; 1702 } 1703EOF 1704 } 1705 } 1706} 1707close $in; 1708chmod 0444, $fh; 1709close $fh; 1710 1711sub mv_if_not_same { 1712 my ($tmp, $orig) = @_; 1713 if (`cmp "$tmp" "$orig"`) { 1714 system("mv", "-f", $orig, "$orig.bak"); 1715 system("mv", "-f", $tmp, $orig); 1716 warn "new $orig\n"; 1717 } else { 1718 unlink $tmp; 1719 warn "keep $orig\n"; 1720 } 1721} 1722 1723# find DEBUGGING classes 1724my $classes_inc = "$srcdir/classes.inc"; 1725my (%STABLE, %UNSTABLE, %DEBUGGING, %UNHANDLED, %FIXED, %STABLEVAR); 1726open $in, "<", $classes_inc or die "$classes_inc: $!"; 1727while (<$in>) { 1728 if (/^\s*STABLE_CLASS(?:_DXF|_CPP|)\s*\(ACTION,\s+(.+?)[,\)]/) { 1729 $STABLE{$1}++; 1730 } 1731 elsif (/^\s*UNSTABLE_CLASS(?:_DXF|_CPP|)\s*\(ACTION,\s+(.+?)[,\)]/) { 1732 $UNSTABLE{$1}++; 1733 } 1734 elsif (/^\s*DEBUGGING_CLASS(?:_DXF|_CPP|)\s*\(ACTION,\s+(.+?)[,\)]/) { 1735 $DEBUGGING{$1}++; 1736 } 1737 elsif (/^\s*UNHANDLED_CLASS(?:_DXF|_CPP|)\s+\(ACTION,\s+(\S+?)[,\)]/) { 1738 $UNHANDLED{$1}++; 1739 } 1740} 1741delete $UNHANDLED{PROXY_LWPOLYLINE}; 1742close $in; 1743for (sort keys %UNHANDLED) { 1744 push @unhandled_names, $_ if !exists $entity_names{$_} and !exists $object_names{$_}; 1745} 1746# many stable/fixed names are not in classes.inc 1747for (@entity_names) { 1748 if (!$STABLE{$_} && !$UNSTABLE{$_} && !$DEBUGGING{$_} && !$UNHANDLED{$_}) { 1749 $FIXED{$_}++; 1750 $STABLE{$_}++; 1751 } 1752} 1753for (@object_names) { 1754 if (!$STABLE{$_} && !$UNSTABLE{$_} && !$DEBUGGING{$_} && !$UNHANDLED{$_}) { 1755 $FIXED{$_}++; 1756 $STABLE{$_}++; 1757 } 1758} 1759$STABLE{_3DSOLID}++; 1760$STABLE{_3DFACE}++; 1761$FIXED{_3DSOLID}++; 1762$FIXED{'_3DFACE'}++; 1763for (keys %STABLE) { 1764 $STABLEVAR{$_}++ unless $FIXED{$_}; 1765} 1766 1767sub stability { 1768 my $n = shift; 1769 return 'STABLE' if $STABLE{$n}; 1770 return 'STABLE' if $FIXED{$n}; 1771 return 'UNSTABLE' if $UNSTABLE{$n}; 1772 return 'DEBUGGING' if $DEBUGGING{$n}; 1773 return 'UNHANDLED' if $UNHANDLED{$n}; 1774 die "no stability class for $n"; 1775} 1776 1777# --------------------------------------------------------------- 1778# The gperf hash 1779my $ofile = "$srcdir/objects.in"; 1780chmod 0644, $ofile if -e $ofile; 1781open $inc, ">", "$ofile.tmp" or die "$ofile: $!"; 1782print $inc <<'EOF'; 1783%{ // -*- mode: c -*- 1784/*****************************************************************************/ 1785/* LibreDWG - free implementation of the DWG file format */ 1786/* */ 1787/* Copyright (C) 2020 Free Software Foundation, Inc. */ 1788/* */ 1789/* This library is free software, licensed under the terms of the GNU */ 1790/* General Public License as published by the Free Software Foundation, */ 1791/* either version 3 of the License, or (at your option) any later version. */ 1792/* You should have received a copy of the GNU General Public License */ 1793/* along with this program. If not, see <http://www.gnu.org/licenses/>. */ 1794/*****************************************************************************/ 1795 1796/* 1797 * objects.c: define all our entity and object names as hashmap, 1798 * generated via gperf from object.in, 1799 * which is generated by gen-dynapi.pl 1800 * 1801 * written Reini Urban 1802 */ 1803 1804#include <string.h> 1805#include "config.h" 1806#include "dwg.h" 1807#include "common.h" 1808#include "classes.h" 1809 1810// v3.1 changed len type from unsigned int to size_t (gperf d519d1a821511eaa22eae6d9019a548aea21e6) 1811#ifdef GPERF_VERSION 1812# if GPERF_VERSION < 301 1813# define SIZE_TYPE unsigned int 1814# else 1815# define SIZE_TYPE size_t 1816# endif 1817#else 1818# define SIZE_TYPE size_t 1819#endif 1820static const struct _dwg_dxfname * in_word_set (register const char *str, register SIZE_TYPE len); 1821 1822#define STABLE (unsigned)DWG_CLASS_STABLE 1823#define UNSTABLE (unsigned)DWG_CLASS_UNSTABLE 1824#define DEBUGGING (unsigned)DWG_CLASS_DEBUGGING 1825#define UNHANDLED (unsigned)DWG_CLASS_UNHANDLED 1826 1827%} 1828%7bit 1829%language=ANSI-C 1830%struct-type 1831%readonly-tables 1832%pic 1833 1834struct _dwg_dxfname {int name; const char *const dxfname; const Dwg_Object_Type type; const unsigned isent:1; const unsigned stability:4; }; 1835 1836%% 1837# Entities 1838EOF 1839$n = 28; 1840for my $name (@entity_names) { 1841 my $xname = $name =~ /^3/ ? "_$name" : $name; # 3DFACE, 3DSOLID 1842 #next if $name eq 'DIMENSION_'; 1843 #next if $name eq 'PROXY_LWPOLYLINE'; 1844 my $dxfname = dxfname($name); 1845 printf $inc "%-${n}s %-${n}s DWG_TYPE_%s,\t1,\t%s\n", "\"$name\",", "\"$dxfname\",", 1846 $xname, stability($xname); 1847} 1848print $inc "# Objects\n"; 1849$n = 35; 1850for my $name (sort @object_names) { 1851 my $dxfname = dxfname($name); 1852 printf $inc "%-${n}s %-${n}s DWG_TYPE_%s,\t0,\t%s\n", "\"$name\",", "\"$dxfname\",", 1853 $name, stability($name); 1854} 1855print $inc <<'EOF'; 1856%% 1857 1858/* Find if an object name (our internal name, not anything used elsewhere) 1859 is defined, and return our fixed type, the public dxfname and if it's an entity. */ 1860EXPORT int dwg_object_name (const char *const restrict name, 1861 const char **restrict dxfname, 1862 Dwg_Object_Type *restrict typep, int *restrict is_entp, 1863 Dwg_Class_Stability *restrict stabilityp) 1864{ 1865 const struct _dwg_dxfname* result; 1866 const size_t len = strlen (name); 1867 // only allow UPPERCASE 7-bit names 1868 if (strspn (name, "ABCDEFGHIJKLMNOPQRSTUVWXYZ_23") != len) 1869 return 0; 1870 result = in_word_set (name, len); 1871 if (result) 1872 { 1873 if (dxfname) 1874 *dxfname = result->dxfname; 1875 if (typep) 1876 *typep = result->type; 1877 if (is_entp) 1878 *is_entp = result->isent; 1879 if (stabilityp) 1880 *stabilityp = result->stability; 1881 return 1; 1882 } 1883 return 0; 1884} 1885 1886/* 1887 * Local variables: 1888 * c-file-style: "gnu" 1889 * End: 1890 * vim: expandtab shiftwidth=4 cinoptions='\:2=2' : 1891 */ 1892EOF 1893close $inc; 1894mv_if_not_same ("$ofile.tmp", $ofile); 1895chmod 0444, $ofile; 1896 1897sub out_classes { 1898 my ($fh, $names, $STABILITY, $tmpl) = @_; 1899 my $lname; 1900 for my $name (@$names) { 1901 if ($STABILITY->{$name}) { 1902 my $s = $tmpl; 1903 if ($name =~ /^3/) { 1904 $name =~ s/^3/_3/; 1905 } 1906 $s =~ s/\$name/$name/g; 1907 if ($s =~ /\$lname/) { 1908 $lname = lc $name; 1909 # skip typedefs of 1910 if ($lname =~ /^(xline|vertex_mesh|vertex_pface|region|body)$/) { 1911 next; 1912 } 1913 $lname =~ s/dimension_/dim_/; 1914 $lname =~ s/lwpolyline/lwpline/; 1915 $lname =~ s/multileader/mleader/; 1916 $lname =~ s/vertex_pface_face/vert_pface_face/; 1917 $s =~ s/\$lname/$lname/; 1918 } 1919 print $fh $s; 1920 } 1921 } 1922} 1923 1924# generate API's lists per stabilty 1925my $tmpl; 1926my $api_c = "$srcdir/dwg_api.c"; 1927open $in, "<", $api_c or die "$api_c: $!"; 1928open my $out, ">", "$api_c.tmp" or die "$api_c.tmp: $!"; 1929my $gen = 0; 1930while (<$in>) { 1931 if (m/^\/\* Start auto-generated/) { 1932 print $out $_; 1933 1934 $tmpl = "dwg_get_OBJECT (ent_\$lname, \$name)\n"; 1935 # out_classes ($out, \@entity_names, \%FIXED, $tmpl); 1936 print $out "/* untyped > 500 */\n"; 1937 out_classes ($out, \@entity_names, \%STABLEVAR, $tmpl); 1938 print $out "/* unstable */\n"; 1939 out_classes ($out, \@entity_names, \%UNSTABLE, $tmpl); 1940 print $out "#ifdef DEBUG_CLASSES\n"; 1941 out_classes ($out, \@entity_names, \%DEBUGGING, " ".$tmpl); 1942 out_classes ($out, \@entity_names, \%UNHANDLED, " //".$tmpl); 1943 print $out "#endif\n\n"; 1944 1945 $tmpl = "dwg_get_OBJECT (obj_\$lname, \$name)\n"; 1946 out_classes ($out, \@object_names, \%FIXED, $tmpl); 1947 print $out "/* untyped > 500 */\n"; 1948 out_classes ($out, \@object_names, \%STABLEVAR, $tmpl); 1949 print $out "/* unstable */\n"; 1950 out_classes ($out, \@object_names, \%UNSTABLE, $tmpl); 1951 print $out "#ifdef DEBUG_CLASSES\n"; 1952 out_classes ($out, \@object_names, \%DEBUGGING, " ".$tmpl); 1953 out_classes ($out, \@object_names, \%UNHANDLED, " //".$tmpl); 1954 out_classes ($out, \@unhandled_names, \%UNHANDLED, " //".$tmpl); 1955 print $out "#endif\n"; 1956 1957 print $out <<'EOF'; 1958 1959/******************************************************************** 1960 * Functions to return NULL-terminated array of all owned entities * 1961 ********************************************************************/ 1962 1963/** 1964 * \fn Dwg_Entity_ENTITY* dwg_getall_ENTITY(Dwg_Object_Ref *hdr) 1965 * \code Usage: Dwg_Entity_TEXT* texts = dwg_getall_TEXT(text, 1966 * dwg->header_vars.mspace_block); \endcode \param[in] hdr Dwg_Object_Ref * 1967 * to a BLOCK_CONTROL obj \return malloced NULL-terminated array 1968 * 1969 * Extracts all entities of this type from a block header (mspace or pspace), 1970 * and returns a malloced NULL-terminated array. 1971 */ 1972//< \fn Dwg_Entity_TEXT* dwg_getall_TEXT (Dwg_Object_Ref *hdr) 1973EOF 1974 1975 $tmpl = "DWG_GETALL_ENTITY (\$name)\n"; 1976 out_classes ($out, \@entity_names, \%STABLE, $tmpl); 1977 print $out "/* unstable */\n"; 1978 out_classes ($out, \@entity_names, \%UNSTABLE, $tmpl); 1979 print $out "/* debugging */\n"; 1980 out_classes ($out, \@entity_names, \%DEBUGGING, $tmpl); 1981 out_classes ($out, \@entity_names, \%UNHANDLED, "//".$tmpl); 1982 1983 print $out <<'EOF'; 1984 1985/******************************************************************** 1986 * Functions to return NULL-terminated array of all objects * 1987 ********************************************************************/ 1988 1989/** 1990 * \fn Dwg_Object_OBJECT dwg_getall_OBJECT(Dwg_Data *dwg) 1991 * Extracts all objects of this type from a dwg, and returns a malloced 1992 * NULL-terminated array. 1993 */ 1994 1995EOF 1996 1997 $tmpl = "DWG_GETALL_OBJECT (\$name)\n"; 1998 out_classes ($out, \@object_names, \%STABLE, $tmpl); 1999 print $out "/* unstable */\n"; 2000 out_classes ($out, \@object_names, \%UNSTABLE, $tmpl); 2001 print $out "#ifdef DEBUG_CLASSES\n"; 2002 out_classes ($out, \@object_names, \%DEBUGGING, " ".$tmpl); 2003 out_classes ($out, \@object_names, \%UNHANDLED, " //".$tmpl); 2004 out_classes ($out, \@unhandled_names, \%UNHANDLED, " //".$tmpl); 2005 print $out "#endif\n"; 2006 2007 print $out <<'EOF'; 2008 2009/******************************************************************* 2010 * Functions created from macro to cast dwg_object to entity * 2011 * Usage :- dwg_object_to_ENTITY(), * 2012 * where ENTITY can be LINE or CIRCLE * 2013 ********************************************************************/ 2014 2015/** 2016 * \fn Dwg_Entity_ENTITY *dwg_object_to_ENTITY(Dwg_Object *obj) 2017 * cast a Dwg_Object to Entity 2018 */ 2019/* fixed <500 */ 2020EOF 2021 2022 $tmpl = "CAST_DWG_OBJECT_TO_ENTITY (\$name)\n"; 2023 out_classes ($out, \@entity_names, \%FIXED, $tmpl); 2024 print $out "/* untyped > 500 */\n"; 2025 $tmpl = "CAST_DWG_OBJECT_TO_ENTITY_BYNAME (\$name)\n"; 2026 out_classes ($out, \@entity_names, \%STABLEVAR, $tmpl); 2027 print $out "/* unstable */\n"; 2028 out_classes ($out, \@entity_names, \%UNSTABLE, $tmpl); 2029 print $out "#ifdef DEBUG_CLASSES\n"; 2030 out_classes ($out, \@entity_names, \%DEBUGGING, " ".$tmpl); 2031 out_classes ($out, \@entity_names, \%UNHANDLED, " //".$tmpl); 2032 print $out "#endif\n"; 2033 2034 print $out <<'EOF'; 2035 2036/******************************************************************* 2037 * Functions created from macro to cast dwg object to object * 2038 * Usage :- dwg_object_to_OBJECT(), * 2039 * where OBJECT can be LAYER or BLOCK_HEADER * 2040 ********************************************************************/ 2041/** 2042 * \fn Dwg_Object_OBJECT *dwg_object_to_OBJECT(Dwg_Object *obj) 2043 * cast a Dwg_Object to Object 2044 */ 2045EOF 2046 2047 $tmpl = "CAST_DWG_OBJECT_TO_OBJECT (\$name)\n"; 2048 out_classes ($out, \@object_names, \%STABLE, $tmpl); 2049 print $out "/* unstable */\n"; 2050 out_classes ($out, \@object_names, \%UNSTABLE, $tmpl); 2051 print $out "#ifdef DEBUG_CLASSES\n"; 2052 out_classes ($out, \@object_names, \%DEBUGGING, " ".$tmpl); 2053 out_classes ($out, \@object_names, \%UNHANDLED, " //".$tmpl); 2054 out_classes ($out, \@unhandled_names, \%UNHANDLED, " //".$tmpl); 2055 print $out "#endif\n"; 2056 print $out "// clang-format: on\n"; 2057 print $out "/* End auto-generated content */\n"; 2058 $gen = 1; 2059 } 2060 if (!$gen) { 2061 print $out $_; 2062 } 2063 if (m/^\/\* End auto-generated/) { 2064 $gen = 0; 2065 } 2066} 2067close $in; 2068close $out; 2069mv_if_not_same ("$api_c.tmp", $api_c); 2070 2071my $api_h = "$topdir/include/dwg_api.h"; 2072open $in, "<", $api_h or die "$api_h: $!"; 2073open $out, ">", "$api_h.tmp" or die "$api_h.tmp: $!"; 2074$gen = 0; 2075while (<$in>) { 2076 if (m/^\/\* Start auto-generated/) { 2077 print $out $_; 2078 2079 $tmpl = "typedef struct _dwg_entity_\$name\t\tdwg_ent_\$lname;\n"; 2080 out_classes ($out, \@entity_names, \%FIXED, $tmpl); 2081 print $out "/* untyped > 500 */\n"; 2082 out_classes ($out, \@entity_names, \%STABLEVAR, $tmpl); 2083 print $out "/* unstable */\n"; 2084 out_classes ($out, \@entity_names, \%UNSTABLE, $tmpl); 2085 print $out "/* debugging */\n"; 2086 out_classes ($out, \@entity_names, \%DEBUGGING, $tmpl); 2087 out_classes ($out, \@entity_names, \%UNHANDLED, "//".$tmpl); 2088 2089 $tmpl = "typedef struct _dwg_object_\$name\t\tdwg_obj_\$lname;\n"; 2090 out_classes ($out, \@object_names, \%FIXED, $tmpl); 2091 print $out "/* untyped > 500 */\n"; 2092 # without UNDERLAYDEFINITION 2093 my %STABLEVAR1 = %STABLEVAR; 2094 delete %STABLEVAR1{qw(PDFDEFINITION DGNDEFINITION DWFDEFINITION)}; 2095 out_classes ($out, \@object_names, \%STABLEVAR1, $tmpl); 2096 my %STABLEVAR2 = map {$_ => 1} qw(PDFDEFINITION DGNDEFINITION DWFDEFINITION); 2097 $tmpl = "typedef struct _dwg_abstractobject_UNDERLAYDEFINITION\t\tdwg_obj_\$lname;\n"; 2098 out_classes ($out, \@object_names, \%STABLEVAR2, $tmpl); 2099 $tmpl = "typedef struct _dwg_object_\$name\t\tdwg_obj_\$lname;\n"; 2100 2101 print $out "/* unstable */\n"; 2102 # without ASSOCARRAYPARAMETERS 2103 my %UNSTABLE1 = %UNSTABLE; 2104 delete %UNSTABLE1{qw(ASSOCARRAYMODIFYPARAMETERS ASSOCARRAYPATHPARAMETERS 2105 ASSOCARRAYPOLARPARAMETERS ASSOCARRAYRECTANGULARPARAMETERS)}; 2106 out_classes ($out, \@object_names, \%UNSTABLE1, $tmpl); 2107 my %UNSTABLE2 = map {$_ => 1} qw(ASSOCARRAYMODIFYPARAMETERS ASSOCARRAYPATHPARAMETERS 2108 ASSOCARRAYPOLARPARAMETERS ASSOCARRAYRECTANGULARPARAMETERS); 2109 $tmpl = "typedef struct _dwg_abstractobject_ASSOCARRAYPARAMETERS\t\tdwg_obj_\$lname;\n"; 2110 out_classes ($out, \@object_names, \%UNSTABLE2, $tmpl); 2111 #out_classes ($out, \@object_names, \%UNSTABLE, $tmpl); 2112 print $out "/* debugging */\n"; 2113 $tmpl = "typedef struct _dwg_object_\$name\t\tdwg_obj_\$lname;\n"; 2114 out_classes ($out, \@object_names, \%DEBUGGING, $tmpl); 2115 out_classes ($out, \@object_names, \%UNHANDLED, "//".$tmpl); 2116 out_classes ($out, \@unhandled_names, \%UNHANDLED, "//".$tmpl); 2117 print $out "\n\n"; 2118 2119 $tmpl = "dwg_get_OBJECT_DECL (ent_\$lname, \$name);\n"; 2120 out_classes ($out, \@entity_names, \%FIXED, $tmpl); 2121 print $out "/* untyped > 500 */\n"; 2122 out_classes ($out, \@entity_names, \%STABLEVAR, $tmpl); 2123 print $out "/* unstable */\n"; 2124 out_classes ($out, \@entity_names, \%UNSTABLE, $tmpl); 2125 print $out "#ifdef DEBUG_CLASSES\n"; 2126 out_classes ($out, \@entity_names, \%DEBUGGING, " ".$tmpl); 2127 out_classes ($out, \@entity_names, \%UNHANDLED, " //".$tmpl); 2128 print $out "#endif\n\n"; 2129 2130 $tmpl = "dwg_get_OBJECT_DECL (obj_\$lname, \$name);\n"; 2131 out_classes ($out, \@object_names, \%FIXED, $tmpl); 2132 print $out "/* untyped > 500 */\n"; 2133 out_classes ($out, \@object_names, \%STABLEVAR, $tmpl); 2134 print $out "/* unstable */\n"; 2135 out_classes ($out, \@object_names, \%UNSTABLE, $tmpl); 2136 print $out "#ifdef DEBUG_CLASSES\n"; 2137 out_classes ($out, \@object_names, \%DEBUGGING, " ".$tmpl); 2138 out_classes ($out, \@object_names, \%UNHANDLED, " //".$tmpl); 2139 out_classes ($out, \@unhandled_names, \%UNHANDLED, " //".$tmpl); 2140 print $out "#endif\n"; 2141 2142 print $out <<'EOF'; 2143 2144/******************************************************************** 2145 * Functions to return NULL-terminated array of all owned entities * 2146 ********************************************************************/ 2147 2148/// extract all owned entities from a block header (mspace or pspace) 2149EOF 2150 2151 $tmpl = "DWG_GETALL_ENTITY_DECL (\$name);\n"; 2152 out_classes ($out, \@entity_names, \%FIXED, $tmpl); 2153 print $out "/* untyped > 500 */\n"; 2154 out_classes ($out, \@entity_names, \%STABLEVAR, $tmpl); 2155 print $out "/* unstable */\n"; 2156 out_classes ($out, \@entity_names, \%UNSTABLE, $tmpl); 2157 print $out "/* debugging */\n"; 2158 out_classes ($out, \@entity_names, \%DEBUGGING, $tmpl); 2159 out_classes ($out, \@entity_names, \%UNHANDLED, "//".$tmpl); 2160 2161 print $out <<'EOF'; 2162 2163/******************************************************************** 2164 * Functions to return NULL-terminated array of all objects * 2165 ********************************************************************/ 2166 2167/** 2168 * \fn Dwg_Object_OBJECT dwg_getall_OBJECT(Dwg_Data *dwg) 2169 * Extracts all objects of this type from a dwg, and returns a malloced 2170 * NULL-terminated array. 2171 */ 2172 2173EOF 2174 2175 $tmpl = "DWG_GETALL_OBJECT_DECL (\$name);\n"; 2176 out_classes ($out, \@object_names, \%FIXED, $tmpl); 2177 print $out "/* untyped > 500 */\n"; 2178 out_classes ($out, \@object_names, \%STABLEVAR, $tmpl); 2179 print $out "/* unstable */\n"; 2180 out_classes ($out, \@object_names, \%UNSTABLE, $tmpl); 2181 print $out "#ifdef DEBUG_CLASSES\n"; 2182 out_classes ($out, \@object_names, \%DEBUGGING, " ".$tmpl); 2183 out_classes ($out, \@object_names, \%UNHANDLED, " //".$tmpl); 2184 out_classes ($out, \@unhandled_names, \%UNHANDLED, " //".$tmpl); 2185 print $out "#endif\n"; 2186 2187 print $out <<'EOF'; 2188 2189/******************************************************************* 2190 * Functions created from macro to cast dwg_object to entity * 2191 * Usage :- dwg_object_to_ENTITY(), * 2192 * where ENTITY can be LINE or CIRCLE * 2193 ********************************************************************/ 2194 2195/** 2196 * \fn Dwg_Entity_ENTITY *dwg_object_to_ENTITY(Dwg_Object *obj) 2197 * cast a Dwg_Object to Entity 2198 */ 2199/* fixed <500 */ 2200EOF 2201 2202 $tmpl = "CAST_DWG_OBJECT_TO_ENTITY_DECL (\$name);\n"; 2203 out_classes ($out, \@entity_names, \%FIXED, $tmpl); 2204 print $out "/* untyped > 500 */\n"; 2205 $tmpl = "CAST_DWG_OBJECT_TO_ENTITY_BYNAME_DECL (\$name);\n"; 2206 out_classes ($out, \@entity_names, \%STABLEVAR, $tmpl); 2207 print $out "/* unstable */\n"; 2208 out_classes ($out, \@entity_names, \%UNSTABLE, $tmpl); 2209 print $out "#ifdef DEBUG_CLASSES\n"; 2210 out_classes ($out, \@entity_names, \%DEBUGGING, " ".$tmpl); 2211 out_classes ($out, \@entity_names, \%UNHANDLED, " //".$tmpl); 2212 print $out "#endif\n"; 2213 2214 print $out <<'EOF'; 2215 2216/******************************************************************* 2217 * Functions created from macro to cast dwg object to object * 2218 * Usage :- dwg_object_to_OBJECT(), * 2219 * where OBJECT can be LAYER or BLOCK_HEADER * 2220 ********************************************************************/ 2221/** 2222 * \fn Dwg_Object_OBJECT *dwg_object_to_OBJECT(Dwg_Object *obj) 2223 * cast a Dwg_Object to Object 2224 */ 2225EOF 2226 2227 $tmpl = "CAST_DWG_OBJECT_TO_OBJECT_DECL (\$name);\n"; 2228 out_classes ($out, \@object_names, \%FIXED, $tmpl); 2229 print $out "/* untyped > 500 */\n"; 2230 out_classes ($out, \@object_names, \%STABLEVAR, $tmpl); 2231 print $out "/* unstable */\n"; 2232 out_classes ($out, \@object_names, \%UNSTABLE, $tmpl); 2233 print $out "#ifdef DEBUG_CLASSES\n"; 2234 out_classes ($out, \@object_names, \%DEBUGGING, " ".$tmpl); 2235 out_classes ($out, \@object_names, \%UNHANDLED, " //".$tmpl); 2236 out_classes ($out, \@unhandled_names, \%UNHANDLED, " //".$tmpl); 2237 print $out "#endif\n"; 2238 2239 print $out "/* End auto-generated content */\n"; 2240 $gen = 1; 2241 } 2242 if (!$gen) { 2243 print $out $_; 2244 } 2245 if (m/^\/\* End auto-generated/) { 2246 $gen = 0; 2247 } 2248} 2249close $in; 2250close $out; 2251mv_if_not_same ("$api_h.tmp", $api_h); 2252 2253my $dwg_h = "$topdir/include/dwg.h"; 2254open $in, "<", $dwg_h or die "$dwg_h: $!"; 2255open $out, ">", "$dwg_h.tmp" or die "$dwg_h.tmp: $!"; 2256$gen = 0; 2257my $enum = 0; 2258my (@VARTYPES, %VARTYPES); 2259while (<$in>) { 2260 # generated sorted DWG_TYPE_ enum as array and hash. 2261 # from PROXY_OBJECT to FREED 2262 if ($enum and /^\s+DWG_TYPE_([^\t ,]+)/) { 2263 my $n = $1; 2264 if ($n =~ /^FREED\s?/) { 2265 $enum = 0; 2266 print $out $_; # because of the next shortcut 2267 next; 2268 } 2269 push @VARTYPES, $n; 2270 $VARTYPES{$n} = $enum++; 2271 } 2272 if (/^\s+DWG_TYPE_PROXY_OBJECT = 0x1f3/) { 2273 $enum = 500; 2274 } 2275 if (/^} Dwg_Object_Type/) { 2276 $enum = 0; 2277 } 2278 if (m/ \/\* Start auto-generated entity-union/) { 2279 print $out $_; 2280 $tmpl = " Dwg_Entity_\$name *\$name;\n"; 2281 out_classes ($out, \@entity_names, \%FIXED, $tmpl); 2282 print $out " /* untyped > 500 */\n"; 2283 out_classes ($out, \@entity_names, \%STABLEVAR, $tmpl); 2284 print $out " /* unstable */\n"; 2285 out_classes ($out, \@entity_names, \%UNSTABLE, $tmpl); 2286 print $out " /* debugging */\n"; 2287 #print $out "#ifdef DEBUG_CLASSES\n"; 2288 out_classes ($out, \@entity_names, \%DEBUGGING, $tmpl); 2289 out_classes ($out, \@entity_names, \%UNHANDLED, "//".$tmpl); 2290 #print $out "#endif\n"; 2291 print $out " /* End auto-generated entity-union */\n"; 2292 $gen = 1; 2293 } 2294 elsif (m/ \/\* Start auto-generated object-union/) { 2295 print $out $_; 2296 $tmpl = " Dwg_Object_\$name *\$name;\n"; 2297 out_classes ($out, \@object_names, \%FIXED, $tmpl); 2298 print $out " /* untyped > 500 */\n"; 2299 out_classes ($out, \@object_names, \%STABLEVAR, $tmpl); 2300 print $out " /* unstable */\n"; 2301 out_classes ($out, \@object_names, \%UNSTABLE, $tmpl); 2302 print $out " /* debugging */\n"; 2303 out_classes ($out, \@object_names, \%DEBUGGING, $tmpl); 2304 out_classes ($out, \@object_names, \%UNHANDLED, "//".$tmpl); 2305 out_classes ($out, \@unhandled_names, \%UNHANDLED, "//".$tmpl); 2306 print $out " /* End auto-generated object-union */\n"; 2307 $gen = 1; 2308 } 2309 elsif (m/^\/\* Start auto-generated content/) { 2310 print $out $_; 2311 2312 $tmpl = "EXPORT int dwg_setup_\$name (Dwg_Object *obj);\n"; 2313 out_classes ($out, \@entity_names, \%FIXED, $tmpl); 2314 out_classes ($out, \@object_names, \%FIXED, $tmpl); 2315 print $out "/* untyped > 500 */\n"; 2316 out_classes ($out, \@entity_names, \%STABLEVAR, $tmpl); 2317 out_classes ($out, \@object_names, \%STABLEVAR, $tmpl); 2318 print $out "/* unstable */\n"; 2319 out_classes ($out, \@entity_names, \%UNSTABLE, $tmpl); 2320 out_classes ($out, \@object_names, \%UNSTABLE, $tmpl); 2321 print $out "#ifdef DEBUG_CLASSES\n"; 2322 out_classes ($out, \@entity_names, \%DEBUGGING, " ".$tmpl); 2323 out_classes ($out, \@object_names, \%DEBUGGING, " ".$tmpl); 2324 out_classes ($out, \@entity_names, \%UNHANDLED, " //".$tmpl); 2325 out_classes ($out, \@object_names, \%UNHANDLED, " //".$tmpl); 2326 out_classes ($out, \@unhandled_names, \%UNHANDLED, " //".$tmpl); 2327 print $out "#endif\n"; 2328 2329 print $out "/* End auto-generated content */\n"; 2330 $gen = 1; 2331 } 2332 if (!$gen) { 2333 print $out $_; 2334 } 2335 if (m/^\s*\/\* End auto-generated/) { 2336 $gen = 0; 2337 } 2338} 2339close $in; 2340close $out; 2341mv_if_not_same ("$dwg_h.tmp", $dwg_h); 2342 2343if (0) { 2344my $free_h = "$topdir/src/free.h"; 2345open $in, "<", $free_h or die "$free_h: $!"; 2346open $out, ">", "$free_h.tmp" or die "$free_h.tmp: $!"; 2347$gen = 0; 2348while (<$in>) { 2349 if (m/^\/\* Start auto-generated content/) { 2350 print $out $_; 2351 2352 $tmpl = "int dwg_free_\$name (Bit_Chain *restrict dat, Dwg_Object *restrict obj);\n" . 2353 "int dwg_free_\$name_private (Bit_Chain *dat, Bit_Chain *hdl_dat, Bit_Chain *str_dat, Dwg_Object *restrict obj);\n"; 2354 out_classes ($out, \@entity_names, \%STABLE, $tmpl); 2355 out_classes ($out, \@object_names, \%STABLE, $tmpl); 2356 print $out "/* unstable */\n"; 2357 out_classes ($out, \@entity_names, \%UNSTABLE, $tmpl); 2358 out_classes ($out, \@object_names, \%UNSTABLE, $tmpl); 2359 print $out "/* DEBUG_CLASSES */\n"; 2360 my $dbgtmpl = $tmpl; 2361 $dbgtmpl =~ s/^int dwg_free/ int dwg_free/gmaa; 2362 out_classes ($out, \@entity_names, \%DEBUGGING, $dbgtmpl); 2363 out_classes ($out, \@object_names, \%DEBUGGING, $dbgtmpl); 2364 my $unhtmpl = $tmpl; 2365 $unhtmpl =~ s{^int dwg_free}{// int dwg_free}gmaa; 2366 out_classes ($out, \@entity_names, \%UNHANDLED, $unhtmpl); 2367 out_classes ($out, \@object_names, \%UNHANDLED, $unhtmpl); 2368 out_classes ($out, \@unhandled_names, \%UNHANDLED, $unhtmpl); 2369 print $out "/* End auto-generated content */\n"; 2370 $gen = 1; 2371 } 2372 if (!$gen) { 2373 print $out $_; 2374 } 2375 if (m/^\s*\/\* End auto-generated/) { 2376 $gen = 0; 2377 } 2378} 2379close $in; 2380close $out; 2381mv_if_not_same ("$free_h.tmp", $free_h); 2382} 2383 2384if (1) { 2385 my $file = "$topdir/src/classes.c"; 2386 open $in, "<", $file or die "$file: $!"; 2387 open $out, ">", "$file.tmp" or die "$file.tmp: $!"; 2388 $gen = 0; 2389 while (<$in>) { 2390 if (m/^\s+\/\* Start auto-generated variable/) { 2391 print $out $_; 2392 my $e = 500; 2393 for (@VARTYPES) { 2394 printf $out " %-40s /* %d */\n", "\"$_\",", $e++; 2395 } 2396 print $out " /* End auto-generated variable */\n"; 2397 $gen = 1; 2398 } 2399 if (m/^\s+\/\* Start auto-generated dxfnames/) { 2400 print $out $_; 2401 my $e = 500; 2402 for (@VARTYPES) { 2403 my $dxfname = dxfname $_; 2404 printf $out " %-40s /* %d */\n", "\"$dxfname\",", $e++; 2405 } 2406 print $out " /* End auto-generated dxfnames */\n"; 2407 $gen = 1; 2408 } 2409 if (!$gen) { 2410 print $out $_; 2411 } 2412 if (m/^\s*\/\* End auto-generated/) { 2413 $gen = 0; 2414 } 2415 } 2416 close $in; 2417 close $out; 2418 mv_if_not_same ("$file.tmp", $file); 2419} 2420 2421my $done = 0; 2422my $ifile = "$topdir/bindings/dwg.i"; 2423open $in, "<", $ifile or die "$ifile: $!"; 2424open $out, ">", "$ifile.tmp" or die "$ifile.tmp: $!"; 2425while (<$in>) { 2426 if (m/^\/\* Start auto-generated/) { 2427 print $out $_; 2428 print $out "/* dwg_getall_ API */\n"; 2429 $tmpl = "EXPORT Dwg_Entity_\$name** dwg_getall_\$name (Dwg_Object_Ref* hdr);\n"; 2430 out_classes ($out, \@entity_names, \%STABLE, $tmpl); 2431 print $out "/* unstable */\n"; 2432 out_classes ($out, \@entity_names, \%UNSTABLE, $tmpl); 2433 print $out "#ifdef DEBUG_CLASSES\n"; 2434 out_classes ($out, \@entity_names, \%DEBUGGING, " ".$tmpl); 2435 out_classes ($out, \@entity_names, \%UNHANDLED, " //".$tmpl); 2436 print $out "#endif\n"; 2437 print $out "\n"; 2438 2439 $tmpl = "EXPORT Dwg_Object_\$name** dwg_getall_\$name (Dwg_Data* dwg);\n"; 2440 out_classes ($out, \@object_names, \%STABLE, $tmpl); 2441 print $out "/* unstable */\n"; 2442 out_classes ($out, \@object_names, \%UNSTABLE, $tmpl); 2443 print $out "#ifdef DEBUG_CLASSES\n"; 2444 out_classes ($out, \@object_names, \%DEBUGGING, $tmpl); 2445 out_classes ($out, \@object_names, \%UNHANDLED, "//".$tmpl); 2446 out_classes ($out, \@unhandled_names, \%UNHANDLED, "//".$tmpl); 2447 print $out "#endif\n"; 2448 2449 print $out "\n/* dwg_object_to_ API */\n"; 2450 $tmpl = "EXPORT Dwg_Entity_\$name* dwg_object_to_\$name (Dwg_Object* obj);\n"; 2451 out_classes ($out, \@entity_names, \%STABLE, $tmpl); 2452 print $out "/* unstable */\n"; 2453 out_classes ($out, \@entity_names, \%UNSTABLE, $tmpl); 2454 print $out "#ifdef DEBUG_CLASSES\n"; 2455 out_classes ($out, \@entity_names, \%DEBUGGING, " ".$tmpl); 2456 out_classes ($out, \@entity_names, \%UNHANDLED, " //".$tmpl); 2457 print $out "#endif\n"; 2458 2459 $tmpl = "EXPORT Dwg_Object_\$name* dwg_object_to_\$name (Dwg_Object* obj);\n"; 2460 out_classes ($out, \@object_names, \%STABLE, $tmpl); 2461 print $out "/* unstable */\n"; 2462 out_classes ($out, \@object_names, \%UNSTABLE, $tmpl); 2463 print $out "#ifdef DEBUG_CLASSES\n"; 2464 out_classes ($out, \@object_names, \%DEBUGGING, " ".$tmpl); 2465 out_classes ($out, \@object_names, \%UNHANDLED, " //".$tmpl); 2466 out_classes ($out, \@unhandled_names, \%UNHANDLED, " //".$tmpl); 2467 print $out "#endif\n"; 2468 print $out "/* End auto-generated content */\n"; 2469 close $out; 2470 $done++; 2471 last; 2472 } 2473 if (!$done) { 2474 print $out $_; 2475 } 2476} 2477close $in; 2478close $out; 2479mv_if_not_same ("$ifile.tmp", $ifile); 2480 2481# NOTE: in the 2 #line's below use __LINE__ + 1 2482__DATA__ 2483/* ex: set ro ft=c: -*- mode: c; buffer-read-only: t -*- */ 2484#line 2458 "gen-dynapi.pl" 2485/*****************************************************************************/ 2486/* LibreDWG - free implementation of the DWG file format */ 2487/* */ 2488/* Copyright (C) 2018-2020 Free Software Foundation, Inc. */ 2489/* */ 2490/* This library is free software, licensed under the terms of the GNU */ 2491/* General Public License as published by the Free Software Foundation, */ 2492/* either version 3 of the License, or (at your option) any later version. */ 2493/* You should have received a copy of the GNU General Public License */ 2494/* along with this program. If not, see <http://www.gnu.org/licenses/>. */ 2495/*****************************************************************************/ 2496 2497/* 2498 * dynapi.c: dynamic access to all object and field names and types 2499 * written by Reini Urban 2500 * generated by src/gen-dynapi.pl from include/dwg.h, do not modify. 2501 */ 2502 2503#include "config.h" 2504#include <string.h> 2505#include <stdlib.h> 2506#include <assert.h> 2507#include "common.h" 2508#include "dynapi.h" 2509#define DWG_LOGLEVEL loglevel 2510#include "logging.h" 2511#include "decode.h" 2512#include "dwg.h" 2513#include "bits.h" 2514 2515#ifndef _DWG_API_H_ 2516Dwg_Object *dwg_obj_generic_to_object (const void *restrict obj, 2517 int *restrict error); 2518#endif 2519 2520@@struct _dwg_header_variables@@ 2521@@for dwg_entity_ENTITY@@ 2522@@for dwg_object_OBJECT@@ 2523@@for dwg_subclasses@@ 2524 2525/* common fields: */ 2526@@struct _dwg_object_entity@@ 2527@@struct _dwg_object_object@@ 2528 2529@@struct _dwg_summaryinfo@@ 2530 2531/* FIXME: Remove name. Get type via dwg_object_name() */ 2532struct _name_type_fields { 2533 const char *const name; 2534 const enum DWG_OBJECT_TYPE type; 2535 const Dwg_DYNAPI_field *const fields; 2536 const int size; 2537}; 2538 2539struct _name_subclass_fields { 2540 const char *const name; 2541 const int type; 2542 const char *const subclass; 2543 const Dwg_DYNAPI_field *const fields; 2544 const int size; 2545}; 2546 2547/* Generated fields for all the objects, sorted for bsearch. from enum DWG_OBJECT_TYPE. 2548 FIXME: Replace name by type. Get type via dwg_object_name(). 2549 Make it an array of type for O(1) lookup. 2550 */ 2551static const struct _name_type_fields dwg_name_types[] = { 2552@@enum DWG_OBJECT_TYPE@@ 2553}; 2554 2555/* Generated fields for all the subclasses, sorted for bsearch */ 2556static const struct _name_subclass_fields dwg_list_subclasses[] = { 2557@@list subclasses@@ 2558}; 2559 2560struct _name_subclasses { 2561 const char *const name; 2562 const char *const subclasses[@@scalar max_subclasses@@]; 2563}; 2564 2565/* List of all allowed subclasses per class. sorted for bsearch. */ 2566static const struct _name_subclasses dwg_name_subclasses[] = { 2567@@list name_subclasses@@ 2568}; 2569 2570#line 2544 "gen-dynapi.pl" 2571struct _name 2572{ 2573 const char *const name; 2574}; 2575 2576static int 2577_name_struct_cmp (const void *restrict key, const void *restrict elem) 2578{ 2579 //https://en.cppreference.com/w/c/algorithm/bsearch 2580 const struct _name *f = (struct _name *)elem; 2581 return strcmp ((const char *)key, f->name); //deref 2582} 2583 2584#define NUM_NAME_TYPES ARRAY_SIZE(dwg_name_types) 2585#define NUM_SUBCLASSES ARRAY_SIZE(dwg_list_subclasses) 2586 2587static 2588const struct _name_type_fields* 2589 __nonnull ((1)) 2590// FIXME: use type arg only 2591_find_entity (const char *name) 2592{ 2593 const char *p = (const char *)bsearch (name, dwg_name_types, NUM_NAME_TYPES, 2594 sizeof (dwg_name_types[0]), 2595 _name_struct_cmp); 2596 if (p) 2597 { 2598 const int i = (p - (char *)dwg_name_types) / sizeof (dwg_name_types[0]); 2599 return &dwg_name_types[i]; 2600 } 2601 else 2602 return NULL; 2603} 2604 2605static 2606const struct _name_subclass_fields* 2607 __nonnull ((1)) 2608_find_subclass (const char *name) 2609{ 2610 const char *p = (const char *)bsearch (name, dwg_list_subclasses, NUM_SUBCLASSES, 2611 sizeof (dwg_list_subclasses[0]), 2612 _name_struct_cmp); 2613 if (p) 2614 { 2615 const int i = (p - (char *)dwg_list_subclasses) / sizeof (dwg_list_subclasses[0]); 2616 return &dwg_list_subclasses[i]; 2617 } 2618 else 2619 return NULL; 2620} 2621 2622EXPORT bool 2623is_dwg_entity (const char *name) 2624{ 2625 int isent; 2626 return dwg_object_name (name, NULL, NULL, &isent, NULL) 2627 && isent; 2628} 2629 2630EXPORT bool 2631is_dwg_object (const char *name) 2632{ 2633 int isent; 2634 return dwg_object_name (name, NULL, NULL, &isent, NULL) 2635 && !isent; 2636} 2637 2638EXPORT const Dwg_DYNAPI_field * 2639dwg_dynapi_entity_fields (const char *name) 2640{ 2641 const struct _name_type_fields *f = _find_entity (name); 2642 return f ? f->fields : NULL; 2643} 2644 2645EXPORT const Dwg_DYNAPI_field * 2646dwg_dynapi_subclass_fields (const char *restrict name) 2647{ 2648 const struct _name_subclass_fields *f = _find_subclass (name); 2649 return f ? f->fields : NULL; 2650} 2651 2652EXPORT const Dwg_DYNAPI_field * 2653dwg_dynapi_common_entity_fields (void) 2654{ 2655 return _dwg_object_entity_fields; 2656} 2657 2658EXPORT const Dwg_DYNAPI_field * 2659dwg_dynapi_common_object_fields (void) 2660{ 2661 return _dwg_object_object_fields; 2662} 2663 2664EXPORT const Dwg_DYNAPI_field * 2665dwg_dynapi_entity_field (const char *restrict name, const char *restrict field) 2666{ 2667 const Dwg_DYNAPI_field *fields = dwg_dynapi_entity_fields (name); 2668 if (fields) 2669 { /* linear search (unsorted) */ 2670 Dwg_DYNAPI_field *f = (Dwg_DYNAPI_field *)fields; 2671 for (; f->name; f++) 2672 { 2673 if (strEQ (f->name, field)) 2674 return f; 2675 } 2676 } 2677 return NULL; 2678} 2679 2680EXPORT const Dwg_DYNAPI_field * 2681dwg_dynapi_subclass_field (const char *restrict name, const char *restrict field) 2682{ 2683 const Dwg_DYNAPI_field *fields = dwg_dynapi_subclass_fields (name); 2684 if (fields) 2685 { /* linear search (unsorted) */ 2686 Dwg_DYNAPI_field *f = (Dwg_DYNAPI_field *)fields; 2687 for (; f->name; f++) 2688 { 2689 if (strEQ (f->name, field)) 2690 return f; 2691 } 2692 } 2693 return NULL; 2694} 2695 2696EXPORT const Dwg_DYNAPI_field * 2697dwg_dynapi_header_field (const char *restrict fieldname) 2698{ 2699 return (Dwg_DYNAPI_field *)bsearch ( 2700 fieldname, _dwg_header_variables_fields, 2701 ARRAY_SIZE (_dwg_header_variables_fields) - 1, /* NULL terminated */ 2702 sizeof (_dwg_header_variables_fields[0]), _name_struct_cmp); 2703} 2704 2705EXPORT const Dwg_DYNAPI_field * 2706dwg_dynapi_common_entity_field (const char *restrict fieldname) 2707{ 2708 return (Dwg_DYNAPI_field *)bsearch ( 2709 fieldname, _dwg_object_entity_fields, 2710 ARRAY_SIZE (_dwg_object_entity_fields) - 1, /* NULL terminated */ 2711 sizeof (_dwg_object_entity_fields[0]), _name_struct_cmp); 2712} 2713 2714EXPORT const Dwg_DYNAPI_field * 2715dwg_dynapi_common_object_field (const char *restrict fieldname) 2716{ 2717 return (Dwg_DYNAPI_field *)bsearch ( 2718 fieldname, _dwg_object_object_fields, 2719 ARRAY_SIZE (_dwg_object_object_fields) - 1, /* NULL terminated */ 2720 sizeof (_dwg_object_object_fields[0]), _name_struct_cmp); 2721} 2722 2723// search field by dxf 2724EXPORT const Dwg_DYNAPI_field * 2725dwg_dynapi_field_dxf (const Dwg_DYNAPI_field *restrict fields, const int dxf, int *restrict unique) 2726{ 2727 const Dwg_DYNAPI_field *retval = NULL; 2728 if (fields) 2729 { /* linear search (unsorted) */ 2730 Dwg_DYNAPI_field *f = (Dwg_DYNAPI_field *)fields; 2731 *unique = 1; 2732 for (; f->name; f++) 2733 { 2734 if (f->dxf == dxf) 2735 { 2736 if (retval) 2737 unique = 0; 2738 else 2739 retval = f; 2740 } 2741 } 2742 } 2743 return retval; 2744} 2745 2746EXPORT int 2747dwg_dynapi_entity_size (const char *restrict name) 2748{ 2749 const struct _name_type_fields *f = _find_entity (name); 2750 return f ? f->size : 0; 2751} 2752 2753EXPORT int 2754dwg_dynapi_subclass_size (const char *restrict name) 2755{ 2756 const struct _name_subclass_fields *f = _find_subclass (name); 2757 return f ? f->size : 0; 2758} 2759 2760/* generic field getters */ 2761EXPORT bool 2762dwg_dynapi_entity_value (void *restrict _obj, const char *restrict name, 2763 const char *restrict fieldname, 2764 void *restrict out, Dwg_DYNAPI_field *restrict fp) 2765{ 2766#ifndef HAVE_NONNULL 2767 if (!_obj || !name || !fieldname || !out) 2768 return false; 2769#endif 2770 { 2771 int error; 2772 const Dwg_Object* obj = dwg_obj_generic_to_object (_obj, &error); 2773 // Here we need to ignore errors, because we allow subentities via 2774 // CHK_SUBCLASS_* e.g. layout->plotsetting via PLOTSETTING 2775 if (obj && strNE (obj->name, name)) // objid may be 0 2776 { 2777 const int loglevel = obj->parent->opts & DWG_OPTS_LOGLEVEL; 2778 LOG_ERROR ("%s: Invalid entity type %s, wanted %s", __FUNCTION__, 2779 obj->name, name); 2780 return false; 2781 } 2782 { 2783 const Dwg_DYNAPI_field *f = dwg_dynapi_entity_field (name, fieldname); 2784 if (!f) 2785 { 2786 int loglevel = (obj && obj->parent) ? obj->parent->opts & DWG_OPTS_LOGLEVEL 2787 : DWG_LOGLEVEL_ERROR; 2788 LOG_ERROR ("%s: Invalid %s field %s", __FUNCTION__, name, fieldname); 2789 return false; 2790 } 2791 if (fp) 2792 memcpy (fp, f, sizeof (Dwg_DYNAPI_field)); 2793 memcpy (out, &((char *)_obj)[f->offset], f->is_malloc ? sizeof(char*) : f->size); 2794 return true; 2795 } 2796 } 2797} 2798 2799EXPORT bool 2800dwg_dynapi_entity_utf8text (void *restrict _obj, const char *restrict name, 2801 const char *restrict fieldname, 2802 char **restrict out, int *isnew, 2803 Dwg_DYNAPI_field *restrict fp) 2804{ 2805 if (isnew) 2806 *isnew = 0; 2807#ifndef HAVE_NONNULL 2808 if (!_obj || !name || !fieldname || !out) 2809 return false; 2810#endif 2811 { 2812 int error; 2813 const Dwg_Object* obj = dwg_obj_generic_to_object (_obj, &error); 2814 // Here we need to ignore errors, because we allow subentities via 2815 // CHK_SUBCLASS_* e.g. layout->plotsetting via PLOTSETTING 2816 if (obj && strNE (obj->name, name)) // objid may be 0 2817 { 2818 const int loglevel = obj->parent->opts & DWG_OPTS_LOGLEVEL; 2819 LOG_ERROR ("%s: Invalid entity type %s, wanted %s", __FUNCTION__, 2820 obj->name, name); 2821 return false; 2822 } 2823 { 2824 const Dwg_DYNAPI_field *f = dwg_dynapi_entity_field (name, fieldname); 2825 const Dwg_Data *dwg = obj ? obj->parent : NULL; 2826 const bool is_tu = dwg ? IS_FROM_TU_DWG (dwg) : false; 2827 2828 if (!f || !f->is_string) 2829 { 2830 int loglevel = dwg ? dwg->opts & DWG_OPTS_LOGLEVEL : DWG_LOGLEVEL_ERROR; 2831 LOG_ERROR ("%s: Invalid %s text field %s", __FUNCTION__, name, fieldname); 2832 return false; 2833 } 2834 if (fp) 2835 memcpy (fp, f, sizeof (Dwg_DYNAPI_field)); 2836 2837 if (is_tu && strNE (f->type, "TF")) /* not TF */ 2838 { 2839 BITCODE_TU wstr = *(BITCODE_TU*)((char*)_obj + f->offset); 2840 char *utf8 = bit_convert_TU (wstr); 2841 if (wstr && !utf8) // some conversion error, invalid wchar (nyi) 2842 return false; 2843 *out = utf8; 2844 if (isnew) 2845 *isnew = 1; 2846 } 2847 else 2848 { 2849 char *utf8 = *(char **)((char*)_obj + f->offset); 2850 *out = utf8; 2851 } 2852 2853 return true; 2854 } 2855 } 2856} 2857 2858EXPORT bool 2859dwg_dynapi_header_value (const Dwg_Data *restrict dwg, 2860 const char *restrict fieldname, void *restrict out, 2861 Dwg_DYNAPI_field *restrict fp) 2862{ 2863#ifndef HAVE_NONNULL 2864 if (!dwg || !fieldname || !out) 2865 return false; 2866#endif 2867 { 2868 const Dwg_DYNAPI_field *f = dwg_dynapi_header_field (fieldname); 2869 if (f) 2870 { 2871 const Dwg_Header_Variables *const _obj = &dwg->header_vars; 2872 if (fp) 2873 memcpy (fp, f, sizeof (Dwg_DYNAPI_field)); 2874 memcpy (out, &((char*)_obj)[f->offset], f->size); 2875 return true; 2876 } 2877 else 2878 { 2879 const int loglevel = dwg->opts & DWG_OPTS_LOGLEVEL; 2880 LOG_ERROR ("%s: Invalid header field %s", __FUNCTION__, fieldname); 2881 return false; 2882 } 2883 } 2884} 2885 2886EXPORT bool 2887dwg_dynapi_header_utf8text (const Dwg_Data *restrict dwg, 2888 const char *restrict fieldname, 2889 char **restrict out, int *isnew, 2890 Dwg_DYNAPI_field *restrict fp) 2891{ 2892 if (isnew) 2893 *isnew = 0; 2894#ifndef HAVE_NONNULL 2895 if (!dwg || !fieldname || !out) 2896 return false; 2897#endif 2898 { 2899 const Dwg_DYNAPI_field *f = dwg_dynapi_header_field (fieldname); 2900 if (f && f->is_string) 2901 { 2902 const Dwg_Header_Variables *const _obj = &dwg->header_vars; 2903 const bool is_tu = IS_FROM_TU_DWG (dwg); 2904 2905 if (fp) 2906 memcpy (fp, f, sizeof (Dwg_DYNAPI_field)); 2907 2908 if (is_tu && strNE (f->type, "TF")) /* not TF */ 2909 { 2910 BITCODE_TU wstr = *(BITCODE_TU*)((char*)_obj + f->offset); 2911 char *utf8 = bit_convert_TU (wstr); 2912 if (wstr && !utf8) // some conversion error, invalid wchar (nyi) 2913 return false; 2914 *out = utf8; 2915 if (isnew) 2916 *isnew = 1; 2917 } 2918 else 2919 { 2920 char *utf8 = *(char **)((char*)_obj + f->offset); 2921 *out = utf8; 2922 } 2923 2924 return true; 2925 } 2926 else 2927 { 2928 const int loglevel = dwg->opts & DWG_OPTS_LOGLEVEL; 2929 LOG_ERROR ("%s: Invalid header text field %s", __FUNCTION__, fieldname); 2930 return false; 2931 } 2932 } 2933} 2934 2935EXPORT bool 2936dwg_dynapi_common_value(void *restrict _obj, const char *restrict fieldname, 2937 void *restrict out, Dwg_DYNAPI_field *restrict fp) 2938{ 2939#ifndef HAVE_NONNULL 2940 if (!_obj || !fieldname || !out) 2941 return false; 2942#endif 2943 { 2944 const Dwg_DYNAPI_field *f; 2945 int error; 2946 const Dwg_Object *obj = dwg_obj_generic_to_object (_obj, &error); 2947 if (!obj || error) 2948 { 2949 const int loglevel = DWG_LOGLEVEL_ERROR; 2950 LOG_ERROR ("%s: dwg_obj_generic_to_object failed", __FUNCTION__); 2951 return false; 2952 } 2953 2954 if (obj->supertype == DWG_SUPERTYPE_ENTITY) 2955 { 2956 f = dwg_dynapi_common_entity_field (fieldname); 2957 _obj = obj->tio.entity; 2958 } 2959 else if (obj->supertype == DWG_SUPERTYPE_OBJECT) 2960 { 2961 f = dwg_dynapi_common_object_field (fieldname); 2962 _obj = obj->tio.object; 2963 } 2964 else 2965 { 2966 const int loglevel = obj->parent->opts & DWG_OPTS_LOGLEVEL; // DWG_LOGLEVEL_ERROR; 2967 LOG_ERROR ("%s: Unhandled %s.supertype ", __FUNCTION__, obj->name); 2968 return false; 2969 } 2970 2971 if (f) 2972 { 2973 int size = f->size; 2974 if (fp) 2975 memcpy (fp, f, sizeof(Dwg_DYNAPI_field)); 2976 if (f->dxf == 160 && strEQc (fieldname, "preview_size") 2977 && obj->parent->header.version < R_2010) 2978 size = 4; 2979 memcpy (out, &((char *)_obj)[f->offset], size); 2980 return true; 2981 } 2982 else 2983 { 2984 const int loglevel = obj->parent->opts & DWG_OPTS_LOGLEVEL; 2985 LOG_ERROR ("%s: Invalid common field %s", __FUNCTION__, fieldname); 2986 return false; 2987 } 2988 } 2989} 2990 2991EXPORT bool 2992dwg_dynapi_common_utf8text(void *restrict _obj, const char *restrict fieldname, 2993 char **restrict out, int *isnew, Dwg_DYNAPI_field *restrict fp) 2994{ 2995 if (isnew) 2996 *isnew = 0; 2997#ifndef HAVE_NONNULL 2998 if (!_obj || !fieldname || !out) 2999 return false; 3000#endif 3001 { 3002 Dwg_DYNAPI_field *f; 3003 int error; 3004 const Dwg_Object *obj = dwg_obj_generic_to_object (_obj, &error); 3005 Dwg_Data *dwg = NULL; 3006 3007 if (!obj || error) 3008 { 3009 const int loglevel = DWG_LOGLEVEL_ERROR; 3010 LOG_ERROR ("%s: dwg_obj_generic_to_object failed", __FUNCTION__); 3011 return false; 3012 } 3013 if (obj->supertype == DWG_SUPERTYPE_ENTITY) 3014 { 3015 dwg = obj ? obj->parent : ((Dwg_Entity_UNKNOWN_ENT *)_obj)->parent->dwg; 3016 _obj = obj->tio.entity; 3017 f = (Dwg_DYNAPI_field *)bsearch ( 3018 fieldname, _dwg_object_entity_fields, 3019 ARRAY_SIZE (_dwg_object_entity_fields) - 1, /* NULL terminated */ 3020 sizeof (_dwg_object_entity_fields[0]), _name_struct_cmp); 3021 } 3022 else if (obj->supertype == DWG_SUPERTYPE_OBJECT) 3023 { 3024 dwg = obj ? obj->parent : ((Dwg_Object_UNKNOWN_OBJ *)_obj)->parent->dwg; 3025 _obj = obj->tio.object; 3026 f = (Dwg_DYNAPI_field *)bsearch ( 3027 fieldname, _dwg_object_object_fields, 3028 ARRAY_SIZE (_dwg_object_object_fields) - 1, /* NULL terminated */ 3029 sizeof (_dwg_object_object_fields[0]), _name_struct_cmp); 3030 } 3031 else 3032 { 3033 const int loglevel = DWG_LOGLEVEL_ERROR; 3034 LOG_ERROR ("%s: Unhandled %s.supertype ", __FUNCTION__, obj->name); 3035 return false; 3036 } 3037 3038 if (f && f->is_string) 3039 { 3040 const bool is_tu = IS_FROM_TU_DWG (dwg); 3041 3042 if (fp) 3043 memcpy (fp, f, sizeof(Dwg_DYNAPI_field)); 3044 3045 if (is_tu && strNE (f->type, "TF")) /* not TF */ 3046 { 3047 BITCODE_TU wstr = *(BITCODE_TU*)((char*)_obj + f->offset); 3048 char *utf8 = bit_convert_TU (wstr); 3049 if (wstr && !utf8) // some conversion error, invalid wchar (nyi) 3050 return false; 3051 *out = utf8; 3052 if (isnew) 3053 *isnew = 1; 3054 } 3055 else 3056 { 3057 char *utf8 = *(char **)((char*)_obj + f->offset); 3058 *out = utf8; 3059 } 3060 3061 return true; 3062 } 3063 else 3064 { 3065 const int loglevel = dwg ? dwg->opts & DWG_OPTS_LOGLEVEL : DWG_LOGLEVEL_ERROR; 3066 LOG_ERROR ("%s: Invalid common text field %s", __FUNCTION__, fieldname); 3067 return false; 3068 } 3069 } 3070} 3071 3072// create a fresh string 3073static void 3074dynapi_set_helper (void *restrict old, const Dwg_DYNAPI_field *restrict f, 3075 const Dwg_Version_Type dwg_version, 3076 const void *restrict value, const bool is_utf8) 3077{ 3078 // TODO: sanity checks. is_malloc (TF) 3079 // if text strcpy or wcscpy, or do utf8 conversion. 3080 //if ((char*)old && f->is_malloc) 3081 // free (old); 3082 if (f->is_malloc) 3083 { 3084 // NULL ptr 3085 if (!*(char**)value) 3086 memcpy (old, value, f->size); 3087 // ascii 3088 else if (strEQc (f->type, "TF") || (f->is_string && dwg_version < R_2007)) 3089 { 3090 char *str = (char *)malloc (strlen (*(char**)value)+1); 3091 strcpy (str, *(char**)value); 3092 memcpy (old, &str, sizeof (char*)); // size of ptr 3093 } 3094 // or wide 3095 else if (strNE (f->type, "TF") && (f->is_string && dwg_version >= R_2007)) 3096 { 3097 BITCODE_TU wstr; 3098 if (is_utf8) 3099 wstr = bit_utf8_to_TU (*(char **)value, 0); 3100 else // source is already TU 3101 { 3102#if defined(HAVE_WCHAR_H) && defined(SIZEOF_WCHAR_T) && SIZEOF_WCHAR_T == 2 3103 wstr = (BITCODE_TU)malloc (2 * (wcslen (*(wchar_t **)value) + 1)); 3104 wcscpy ((wchar_t *)wstr, *(wchar_t **)value); 3105#else 3106 int length = 0; 3107 for (; (*(BITCODE_TU*)value)[length]; length++) 3108 ; 3109 length++; 3110 wstr = (BITCODE_TU)malloc (2 * length); 3111 memcpy (wstr, value, length * 2); 3112#endif 3113 } 3114 memcpy (old, &wstr, sizeof (char*)); // size of ptr 3115 } 3116 else 3117 memcpy (old, value, sizeof (char*)); 3118 } 3119 else 3120 memcpy (old, value, f->size); 3121} 3122 3123/* generic field setters */ 3124EXPORT bool 3125dwg_dynapi_entity_set_value (void *restrict _obj, const char *restrict name, 3126 const char *restrict fieldname, 3127 const void *restrict value, const bool is_utf8) 3128{ 3129#ifndef HAVE_NONNULL 3130 if (!_obj || !fieldname || !value) // cannot set NULL value 3131 return false; 3132#endif 3133 { 3134 int error; 3135 const Dwg_Object *obj = dwg_obj_generic_to_object (_obj, &error); 3136 if (error) 3137 { 3138 const int loglevel = DWG_LOGLEVEL_ERROR; 3139 LOG_ERROR ("%s: dwg_obj_generic_to_object failed", __FUNCTION__); 3140 return false; 3141 } 3142 if (obj && strNE (obj->name, name)) 3143 { 3144 const int loglevel = obj->parent->opts & DWG_OPTS_LOGLEVEL; 3145 LOG_ERROR ("%s: Invalid entity type %s, wanted %s", __FUNCTION__, 3146 obj->name, name); 3147 return false; 3148 } 3149 { 3150 void *old; 3151 const Dwg_DYNAPI_field *f = dwg_dynapi_entity_field (name, fieldname); 3152 const Dwg_Data *dwg 3153 = obj ? obj->parent 3154 : ((Dwg_Object_UNKNOWN_OBJ *)_obj)->parent->dwg; 3155 const Dwg_Version_Type dwg_version = dwg ? dwg->header.from_version : R_INVALID; 3156 3157 if (!f) 3158 { 3159 const int loglevel = dwg ? dwg->opts & DWG_OPTS_LOGLEVEL : 0; 3160 LOG_ERROR ("%s: Invalid %s field %s", __FUNCTION__, name, fieldname); 3161 return false; 3162 } 3163 3164 old = &((char*)_obj)[f->offset]; 3165 dynapi_set_helper (old, f, dwg_version, value, is_utf8); 3166 return true; 3167 } 3168 } 3169} 3170 3171EXPORT bool 3172dwg_dynapi_header_set_value (Dwg_Data *restrict dwg, 3173 const char *restrict fieldname, 3174 const void *restrict value, const bool is_utf8) 3175{ 3176#ifndef HAVE_NONNULL 3177 if (!dwg || !fieldname || !value) // cannot set NULL value 3178 return false; 3179#endif 3180 { 3181 Dwg_DYNAPI_field *f = (Dwg_DYNAPI_field *)bsearch ( 3182 fieldname, _dwg_header_variables_fields, 3183 ARRAY_SIZE (_dwg_header_variables_fields) - 1, /* NULL terminated */ 3184 sizeof (_dwg_header_variables_fields[0]), _name_struct_cmp); 3185 if (f) 3186 { 3187 void *old; 3188 // there are no malloc'd fields in the HEADER, so no need to free(). 3189 const Dwg_Header_Variables *const _obj = &dwg->header_vars; 3190 3191 old = &((char*)_obj)[f->offset]; 3192 dynapi_set_helper (old, f, dwg->header.version, value, is_utf8); 3193 3194 // Set also FLAGS 3195 if (strEQc (fieldname, "CELWEIGHT")) 3196 { 3197 dwg->header_vars.FLAGS &= ~0x1f; // delete old, and set new 3198 dwg->header_vars.FLAGS |= dxf_revcvt_lweight (dwg->header_vars.CELWEIGHT); 3199 } 3200#define SET_HDR_FLAGS(name, bit, inverse) \ 3201 else if (strEQc (fieldname, #name)) \ 3202 { \ 3203 if (dwg->header_vars.name && !inverse) \ 3204 dwg->header_vars.FLAGS |= bit; \ 3205 else \ 3206 dwg->header_vars.FLAGS &= ~bit; \ 3207 } 3208 SET_HDR_FLAGS (ENDCAPS, 0x60, 0) 3209 SET_HDR_FLAGS (JOINSTYLE, 0x180, 0) 3210 SET_HDR_FLAGS (LWDISPLAY, 0x200, 1) 3211 SET_HDR_FLAGS (XEDIT, 0x400, 1) 3212 SET_HDR_FLAGS (EXTNAMES, 0x800, 0) 3213 SET_HDR_FLAGS (PSTYLEMODE, 0x2000, 0) 3214 SET_HDR_FLAGS (OLESTARTUP, 0x4000, 0) 3215 3216 return true; 3217 } 3218 else 3219 { 3220 const int loglevel = dwg->opts & DWG_OPTS_LOGLEVEL; 3221 LOG_ERROR ("%s: Invalid header field %s", __FUNCTION__, fieldname); 3222 return false; 3223 } 3224 } 3225} 3226 3227EXPORT bool 3228dwg_dynapi_common_set_value (void *restrict _obj, 3229 const char *restrict fieldname, 3230 const void *restrict value, const bool is_utf8) 3231{ 3232#ifndef HAVE_NONNULL 3233 if (!_obj || !fieldname || !value) 3234 return false; 3235#endif 3236 { 3237 Dwg_DYNAPI_field *f; 3238 int error; 3239 void *old; 3240 const Dwg_Object *obj = dwg_obj_generic_to_object (_obj, &error); 3241 Dwg_Data *dwg; 3242 if (!obj || error) 3243 { 3244 const int loglevel = DWG_LOGLEVEL_ERROR; 3245 LOG_ERROR ("%s: dwg_obj_generic_to_object failed", __FUNCTION__); 3246 return false; 3247 } 3248 dwg = obj->parent; 3249 if (obj->supertype == DWG_SUPERTYPE_ENTITY) 3250 { 3251 _obj = obj->tio.entity; 3252 f = (Dwg_DYNAPI_field *)bsearch ( 3253 fieldname, _dwg_object_entity_fields, 3254 ARRAY_SIZE (_dwg_object_entity_fields) - 1, /* NULL terminated */ 3255 sizeof (_dwg_object_entity_fields[0]), _name_struct_cmp); 3256 } 3257 else if (obj->supertype == DWG_SUPERTYPE_OBJECT) 3258 { 3259 _obj = obj->tio.object; 3260 f = (Dwg_DYNAPI_field *)bsearch ( 3261 fieldname, _dwg_object_object_fields, 3262 ARRAY_SIZE (_dwg_object_object_fields) - 1, /* NULL terminated */ 3263 sizeof (_dwg_object_object_fields[0]), _name_struct_cmp); 3264 } 3265 else 3266 { 3267 const int loglevel = DWG_LOGLEVEL_ERROR; 3268 LOG_ERROR ("%s: Unhandled %s.supertype ", __FUNCTION__, obj->name); 3269 return false; 3270 } 3271 3272 if (!f) 3273 { 3274 const int loglevel = obj->parent->opts & DWG_OPTS_LOGLEVEL; 3275 LOG_ERROR ("%s: Invalid %s common field %s", __FUNCTION__, obj->name, fieldname); 3276 return false; 3277 } 3278 3279 old = &((char*)_obj)[f->offset]; 3280 if (f->dxf == 160 && strEQc (fieldname, "preview_size")) 3281 { 3282 int size = f->size; 3283 if (dwg && dwg->header.version < R_2010) 3284 size = 4; 3285 memcpy (old, value, size); 3286 } 3287 else 3288 dynapi_set_helper (old, f, dwg ? dwg->header.version : R_INVALID, value, is_utf8); 3289 3290 if (dwg && obj->supertype == DWG_SUPERTYPE_ENTITY && strEQc (fieldname, "ltype")) 3291 { // set also isbylayerlt and ltype_flags 3292 BITCODE_H ltype = *(BITCODE_H*)value; 3293 Dwg_Object_Entity *ent = obj->tio.entity; 3294 if (!dwg->header_vars.LTYPE_BYLAYER || !ent->ltype) 3295 ; 3296 else if (ent->ltype->absolute_ref == dwg->header_vars.LTYPE_BYLAYER->absolute_ref) 3297 { 3298 ent->isbylayerlt = 1; // r13-r14 only 3299 ent->ltype_flags = 0; 3300 } 3301 else if (dwg->header_vars.LTYPE_BYBLOCK 3302 && ent->ltype->absolute_ref == dwg->header_vars.LTYPE_BYBLOCK->absolute_ref) 3303 { 3304 ent->isbylayerlt = 0; 3305 ent->ltype_flags = 1; 3306 } 3307 else if (dwg->header_vars.LTYPE_CONTINUOUS 3308 && ent->ltype->absolute_ref == dwg->header_vars.LTYPE_CONTINUOUS->absolute_ref) 3309 { 3310 ent->isbylayerlt = 0; 3311 ent->ltype_flags = 2; 3312 } 3313 else 3314 { 3315 ent->isbylayerlt = 0; 3316 ent->ltype_flags = 3; 3317 } 3318 } 3319 return true; 3320 } 3321} 3322 3323// arbitrary structs, no text 3324EXPORT bool 3325dwg_dynapi_subclass_value (const void *restrict ptr, 3326 const char *restrict subclass, 3327 const char *restrict fieldname, 3328 void *restrict out, Dwg_DYNAPI_field *restrict fp) 3329{ 3330 const Dwg_DYNAPI_field *f; 3331#ifndef HAVE_NONNULL 3332 if (!ptr || !subclass || !fieldname || !out) 3333 return false; 3334#endif 3335 f = dwg_dynapi_subclass_field (subclass, fieldname); 3336 if (!f) // TODO maybe search via dwg_dynapi_subclass_name () 3337 return false; 3338 memcpy (out, &((char*)ptr)[f->offset], f->size); 3339 if (fp) 3340 memcpy (fp, f, sizeof(Dwg_DYNAPI_field)); 3341 return true; 3342} 3343 3344// arbitrary structs, no text 3345EXPORT bool 3346dwg_dynapi_field_get_value (const void *restrict ptr, 3347 const Dwg_DYNAPI_field *restrict field, 3348 void *restrict out) 3349{ 3350#ifndef HAVE_NONNULL 3351 if (!ptr || !field || !out) 3352 return false; 3353#endif 3354 memcpy (out, &((char*)ptr)[field->offset], field->size); 3355 return true; 3356} 3357 3358// can do arbitrary structs, like subclasses 3359EXPORT bool 3360dwg_dynapi_field_set_value (const Dwg_Data *restrict dwg, /* only needed if unicode strings */ 3361 void *restrict ptr, 3362 const Dwg_DYNAPI_field *restrict field, 3363 const void *restrict value, 3364 const bool is_utf8) 3365{ 3366 void *off; 3367#ifndef HAVE_NONNULL 3368 if (!ptr || !field || !value) 3369 return false; 3370#endif 3371 off = &((char*)ptr)[field->offset]; 3372 dynapi_set_helper (off, field, dwg ? dwg->header.version : R_INVALID, value, is_utf8); 3373 return true; 3374} 3375 3376// check if the handle points to an object with a name. 3377// see also dwg_obj_table_get_name, which only supports tables. 3378EXPORT char* 3379dwg_dynapi_handle_name (const Dwg_Data *restrict dwg, Dwg_Object_Ref *restrict hdl) 3380{ 3381 const bool is_tu = IS_FROM_TU_DWG (dwg); 3382 Dwg_Object *obj; 3383 3384#ifndef HAVE_NONNULL 3385 if (!dwg || !hdl) 3386 return NULL; 3387#endif 3388 3389 obj = dwg_ref_object_silent (dwg, hdl); 3390 if (!obj) 3391 return NULL; 3392 { 3393 const Dwg_DYNAPI_field *f = dwg_dynapi_entity_field (obj->name, "name"); 3394 // just some random type is enough. 3395 Dwg_Object_STYLE *_obj = obj->tio.object->tio.STYLE; 3396 3397 if (!f || !f->is_string) 3398 return NULL; 3399 if (is_tu && strNE (f->type, "TF")) /* not TF */ 3400 { 3401 BITCODE_TU wstr = *(BITCODE_TU *)((char *)_obj + f->offset); 3402 return bit_convert_TU (wstr); 3403 } 3404 else 3405 { 3406 return *(char **)((char *)_obj + f->offset); 3407 } 3408 } 3409} 3410 3411// The sum of the size of all fields 3412int 3413_fields_size_sum (const Dwg_DYNAPI_field *restrict fields) 3414{ 3415 Dwg_DYNAPI_field *f = (Dwg_DYNAPI_field *)fields; 3416 int sum = 0; 3417 if (!f) 3418 return 0; 3419 for (; f->name; f++) 3420 { 3421 sum += f->size; 3422 } 3423 return sum; 3424} 3425 3426// The size of the entity or subclass struct, or the sum of the size of all fields. 3427EXPORT int 3428dwg_dynapi_fields_size (const char *restrict name) 3429{ 3430 const struct _name_type_fields *f; 3431#ifndef HAVE_NONNULL 3432 if (!name) 3433 return 0; 3434#endif 3435 3436 f = _find_entity (name); 3437 // TODO PROXY_LWPOLYLINE 3438 if (f) 3439 { 3440 if (f->size) 3441 return (int)f->size; 3442 else 3443 return _fields_size_sum (f->fields); // VERTEX_PFACE is not entity nor object yet 3444 } 3445 else 3446 { 3447 int size = dwg_dynapi_subclass_size (name); 3448 if (size) 3449 return size; 3450 else 3451 return _fields_size_sum (dwg_dynapi_subclass_fields (name)); 3452 } 3453} 3454 3455// Converts from the fields type, like "Dwg_MLINESTYLE_line*" to the 3456// subclass name, like "MLINESTYLE_line". 3457ATTRIBUTE_MALLOC char* 3458dwg_dynapi_subclass_name (const char *restrict type) 3459{ 3460 char *name = NULL; 3461 int len = strlen (type); 3462 if (memBEGINc (type, "Dwg_Object_")) 3463 { 3464 const int off = strlen ("Dwg_Object_"); // PLOTSETTINGS 3465 name = strdup (&type[off]); 3466 if (type[len - 1] == '*') 3467 name[len - off - 1] = '\0'; 3468 } 3469 else if (memBEGINc (type, "Dwg_Entity_")) 3470 { 3471 const int off = strlen ("Dwg_Entity_"); 3472 name = strdup (&type[off]); 3473 if (type[len - 1] == '*') 3474 name[len - off - 1] = '\0'; 3475 } 3476 else if (memBEGINc (type, "Dwg_")) 3477 { 3478 name = strdup (&type[4]); 3479 if (type[len - 1] == '*') 3480 name[len - 5] = '\0'; 3481 } 3482 else if (memBEGINc (type, "struct _dwg_entity_")) 3483 { 3484 const int off = strlen ("struct _dwg_entity_"); // TABLE 3485 name = strdup (&type[off]); 3486 if (type[len - 1] == '*') 3487 name[len - off - 1] = '\0'; 3488 } 3489 else if (memBEGINc (type, "struct _dwg_object_")) 3490 { 3491 const int off = strlen ("struct _dwg_object_"); // CELLSTYLEMAP*, EVALUATION_GRAPH, ... 3492 name = strdup (&type[off]); 3493 if (type[len - 1] == '*') 3494 name[len - off - 1] = '\0'; 3495 } 3496 else if (memBEGINc (type, "struct _dwg_")) // CellStyle* 3497 { 3498 const int off = strlen ("struct _dwg_"); 3499 name = strdup (&type[off]); 3500 if (type[len - 1] == '*') 3501 name[len - off - 1] = '\0'; 3502 } 3503 return name; 3504} 3505 3506EXPORT bool 3507dwg_has_subclass (const char *restrict classname, const char *restrict subclass) 3508{ 3509 struct _name_subclasses *f; 3510#ifndef HAVE_NONNULL 3511 if (!classname || !name) 3512 return false; 3513#endif 3514 f = (struct _name_subclasses *)bsearch (classname, dwg_name_subclasses, 3515 ARRAY_SIZE (dwg_name_subclasses), 3516 sizeof (dwg_name_subclasses[0]), 3517 _name_struct_cmp); 3518 if (f) { 3519 for (unsigned i = 0; i < @@scalar max_subclasses@@ /* max_subclasses */; i++) { 3520 if (!f->subclasses[i]) // already at NULL 3521 return false; 3522 if (strEQ (subclass, f->subclasses[i])) 3523 return true; 3524 } 3525 } 3526 return false; 3527} 3528/* Local Variables: */ 3529/* mode: c */ 3530/* End: */ 3531