1################################################### 2# Samba4 NDR parser generator for IDL structures 3# Copyright tridge@samba.org 2000-2003 4# Copyright tpot@samba.org 2001 5# Copyright jelmer@samba.org 2004-2006 6# released under the GNU GPL 7 8package Parse::Pidl::Samba4::NDR::Parser; 9use parent Parse::Pidl::Base; 10 11require Exporter; 12push @ISA, qw(Exporter); 13@EXPORT_OK = qw(check_null_pointer NeededFunction NeededElement NeededType $res NeededInterface TypeFunctionName ParseElementPrint); 14 15use strict; 16use warnings; 17use Parse::Pidl::Typelist qw(hasType getType mapTypeName typeHasBody); 18use Parse::Pidl::Util qw(has_property 19 ParseExpr 20 ParseExprExt 21 print_uuid 22 unmake_str 23 parse_int 24 parse_range); 25use Parse::Pidl::CUtil qw(get_pointer_to get_value_of get_array_element); 26use Parse::Pidl::NDR qw(GetPrevLevel GetNextLevel ContainsDeferred ContainsPipe is_charset_array); 27use Parse::Pidl::Samba4 qw(is_intree choose_header ArrayDynamicallyAllocated); 28use Parse::Pidl::Samba4::Header qw(GenerateFunctionInEnv GenerateFunctionOutEnv EnvSubstituteValue GenerateStructEnv); 29use Parse::Pidl qw(warning); 30 31use vars qw($VERSION); 32$VERSION = '0.01'; 33 34# list of known types 35my %typefamily; 36 37sub new($$) { 38 my ($class) = @_; 39 my $self = { res => "", res_hdr => "", deferred => [], tabs => "", defer_tabs => "" }; 40 bless($self, $class); 41} 42 43sub get_typefamily($) 44{ 45 my $n = shift; 46 return $typefamily{$n}; 47} 48 49sub append_prefix($$) 50{ 51 my ($e, $var_name) = @_; 52 my $pointers = 0; 53 my $arrays = 0; 54 55 foreach my $l (@{$e->{LEVELS}}) { 56 if ($l->{TYPE} eq "POINTER") { 57 $pointers++; 58 } elsif ($l->{TYPE} eq "ARRAY") { 59 $arrays++; 60 if (($pointers == 0) and 61 (not $l->{IS_FIXED}) and 62 (not $l->{IS_INLINE})) { 63 return get_value_of($var_name); 64 } 65 } elsif ($l->{TYPE} eq "DATA") { 66 if (Parse::Pidl::Typelist::scalar_is_reference($l->{DATA_TYPE})) { 67 return get_value_of($var_name) unless ($pointers or $arrays); 68 } 69 } 70 } 71 72 return $var_name; 73} 74 75sub has_fast_array($$) 76{ 77 my ($e,$l) = @_; 78 79 return 0 if ($l->{TYPE} ne "ARRAY"); 80 81 my $nl = GetNextLevel($e,$l); 82 return 0 unless ($nl->{TYPE} eq "DATA"); 83 return 0 unless (hasType($nl->{DATA_TYPE})); 84 85 my $t = getType($nl->{DATA_TYPE}); 86 87 # Only uint8 has a fast array function at the moment 88 return ($t->{NAME} eq "uint8"); 89} 90 91sub is_public_struct 92{ 93 my ($d) = @_; 94 if (!has_property($d, "public")) { 95 return 0; 96 } 97 my $t = $d; 98 if ($d->{TYPE} eq "TYPEDEF") { 99 $t = $d->{DATA}; 100 } 101 return $t->{TYPE} eq "STRUCT"; 102} 103 104#################################### 105# defer() is like pidl(), but adds to 106# a deferred buffer which is then added to the 107# output buffer at the end of the structure/union/function 108# This is needed to cope with code that must be pushed back 109# to the end of a block of elements 110sub defer_indent($) { my ($self) = @_; $self->{defer_tabs}.="\t"; } 111sub defer_deindent($) { my ($self) = @_; $self->{defer_tabs}=substr($self->{defer_tabs}, 0, -1); } 112 113sub defer($$) 114{ 115 my ($self, $d) = @_; 116 if ($d) { 117 push(@{$self->{deferred}}, $self->{defer_tabs}.$d); 118 } 119} 120 121######################################## 122# add the deferred content to the current 123# output 124sub add_deferred($) 125{ 126 my ($self) = @_; 127 $self->pidl($_) foreach (@{$self->{deferred}}); 128 $self->{deferred} = []; 129 $self->{defer_tabs} = ""; 130} 131 132##################################################################### 133# declare a function public or static, depending on its attributes 134sub fn_declare($$$$) 135{ 136 my ($self,$type,$fn,$decl) = @_; 137 138 if (has_property($fn, "no$type")) { 139 $self->pidl_hdr("$decl;"); 140 return 0; 141 } 142 143 if (has_property($fn, "public")) { 144 $self->pidl_hdr("$decl;"); 145 $self->pidl("_PUBLIC_ $decl"); 146 } else { 147 $self->pidl("static $decl"); 148 } 149 150 return 1; 151} 152 153################################################################### 154# setup any special flags for an element or structure 155sub start_flags($$$) 156{ 157 my ($self, $e, $ndr) = @_; 158 my $flags = has_property($e, "flag"); 159 if (defined $flags) { 160 $self->pidl("{"); 161 $self->indent; 162 $self->pidl("uint32_t _flags_save_$e->{TYPE} = $ndr->flags;"); 163 $self->pidl("ndr_set_flags(&$ndr->flags, $flags);"); 164 } 165} 166 167################################################################### 168# end any special flags for an element or structure 169sub end_flags($$$) 170{ 171 my ($self, $e, $ndr) = @_; 172 my $flags = has_property($e, "flag"); 173 if (defined $flags) { 174 $self->pidl("$ndr->flags = _flags_save_$e->{TYPE};"); 175 $self->deindent; 176 $self->pidl("}"); 177 } 178} 179 180##################################################################### 181# parse the data of an array - push side 182sub ParseArrayPushHeader($$$$$$) 183{ 184 my ($self,$e,$l,$ndr,$var_name,$env) = @_; 185 186 my $size; 187 my $length; 188 189 if ($l->{IS_ZERO_TERMINATED}) { 190 if (has_property($e, "charset")) { 191 $size = $length = "ndr_charset_length($var_name, CH_$e->{PROPERTIES}->{charset})"; 192 } else { 193 $size = $length = "ndr_string_length($var_name, sizeof(*$var_name))"; 194 } 195 if (defined($l->{SIZE_IS})) { 196 $size = ParseExpr($l->{SIZE_IS}, $env, $e); 197 } 198 if (defined($l->{LENGTH_IS})) { 199 $length = ParseExpr($l->{LENGTH_IS}, $env, $e); 200 } 201 } else { 202 $size = ParseExpr($l->{SIZE_IS}, $env, $e); 203 $length = ParseExpr($l->{LENGTH_IS}, $env, $e); 204 } 205 206 if ((!$l->{IS_SURROUNDING}) and $l->{IS_CONFORMANT}) { 207 $self->pidl("NDR_CHECK(ndr_push_uint3264($ndr, NDR_SCALARS, $size));"); 208 } 209 210 if ($l->{IS_VARYING}) { 211 $self->pidl("NDR_CHECK(ndr_push_uint3264($ndr, NDR_SCALARS, 0));"); # array offset 212 $self->pidl("NDR_CHECK(ndr_push_uint3264($ndr, NDR_SCALARS, $length));"); 213 } 214 215 return $length; 216} 217 218sub check_fully_dereferenced($$) 219{ 220 my ($element, $env) = @_; 221 222 return sub ($) { 223 my $origvar = shift; 224 my $check = 0; 225 226 # Figure out the number of pointers in $ptr 227 my $expandedvar = $origvar; 228 $expandedvar =~ s/^(\**)//; 229 my $ptr = $1; 230 231 my $var = undef; 232 foreach (keys %$env) { 233 if ($env->{$_} eq $expandedvar) { 234 $var = $_; 235 last; 236 } 237 } 238 239 return($origvar) unless (defined($var)); 240 my $e; 241 foreach (@{$element->{PARENT}->{ELEMENTS}}) { 242 if ($_->{NAME} eq $var) { 243 $e = $_; 244 last; 245 } 246 } 247 248 $e or die("Environment doesn't match siblings"); 249 250 # See if pointer at pointer level $level 251 # needs to be checked. 252 my $nump = 0; 253 foreach (@{$e->{LEVELS}}) { 254 if ($_->{TYPE} eq "POINTER") { 255 $nump = $_->{POINTER_INDEX}+1; 256 } 257 } 258 warning($element->{ORIGINAL}, "Got pointer for `$e->{NAME}', expected fully dereferenced variable") if ($nump > length($ptr)); 259 return ($origvar); 260 } 261} 262 263sub check_null_pointer($$$$) 264{ 265 my ($element, $env, $print_fn, $return) = @_; 266 267 return sub ($) { 268 my $expandedvar = shift; 269 my $check = 0; 270 271 # Figure out the number of pointers in $ptr 272 $expandedvar =~ s/^(\**)//; 273 my $ptr = $1; 274 275 my $var = undef; 276 foreach (keys %$env) { 277 if ($env->{$_} eq $expandedvar) { 278 $var = $_; 279 last; 280 } 281 } 282 283 if (defined($var)) { 284 my $e; 285 # lookup ptr in $e 286 foreach (@{$element->{PARENT}->{ELEMENTS}}) { 287 if ($_->{NAME} eq $var) { 288 $e = $_; 289 last; 290 } 291 } 292 293 $e or die("Environment doesn't match siblings"); 294 295 # See if pointer at pointer level $level 296 # needs to be checked. 297 foreach my $l (@{$e->{LEVELS}}) { 298 if ($l->{TYPE} eq "POINTER" and 299 $l->{POINTER_INDEX} == length($ptr)) { 300 # No need to check ref pointers 301 $check = ($l->{POINTER_TYPE} ne "ref"); 302 last; 303 } 304 305 if ($l->{TYPE} eq "DATA") { 306 warning($element, "too much dereferences for `$var'"); 307 } 308 } 309 } else { 310 warning($element, "unknown dereferenced expression `$expandedvar'"); 311 $check = 1; 312 } 313 314 $print_fn->("if ($ptr$expandedvar == NULL) $return") if $check; 315 } 316} 317 318sub is_deferred_switch_non_empty($) 319{ 320 # 1 if there needs to be a deferred branch in an ndr_pull/push, 321 # 0 otherwise. 322 my ($e) = @_; 323 my $have_default = 0; 324 foreach my $el (@{$e->{ELEMENTS}}) { 325 if ($el->{CASE} eq "default") { 326 $have_default = 1; 327 } 328 if ($el->{TYPE} ne "EMPTY") { 329 if (ContainsDeferred($el, $el->{LEVELS}[0])) { 330 return 1; 331 } 332 } 333 } 334 return ! $have_default; 335} 336 337sub ParseArrayPullGetSize($$$$$$) 338{ 339 my ($self,$e,$l,$ndr,$var_name,$env) = @_; 340 341 my $size; 342 343 if ($l->{IS_CONFORMANT}) { 344 $size = "ndr_get_array_size($ndr, " . get_pointer_to($var_name) . ")"; 345 } elsif ($l->{IS_ZERO_TERMINATED} and $l->{SIZE_IS} == 0 and $l->{LENGTH_IS} == 0) { # Noheader arrays 346 $size = "ndr_get_string_size($ndr, sizeof(*$var_name))"; 347 } else { 348 $size = ParseExprExt($l->{SIZE_IS}, $env, $e->{ORIGINAL}, 349 check_null_pointer($e, $env, sub { $self->pidl(shift); }, 350 "return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for size_is()\");"), 351 check_fully_dereferenced($e, $env)); 352 } 353 354 $self->pidl("size_$e->{NAME}_$l->{LEVEL_INDEX} = $size;"); 355 my $array_size = "size_$e->{NAME}_$l->{LEVEL_INDEX}"; 356 357 if (my $range = has_property($e, "range")) { 358 my ($low, $high) = parse_range($range); 359 if ($low < 0) { 360 warning(0, "$low is invalid for the range of an array size"); 361 } 362 if ($low == 0) { 363 $self->pidl("if ($array_size > $high) {"); 364 } else { 365 $self->pidl("if ($array_size < $low || $array_size > $high) {"); 366 } 367 $self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_RANGE, \"value out of range\");"); 368 $self->pidl("}"); 369 } 370 371 return $array_size; 372} 373 374##################################################################### 375# parse an array - pull side 376sub ParseArrayPullGetLength($$$$$$;$) 377{ 378 my ($self,$e,$l,$ndr,$var_name,$env,$array_size) = @_; 379 380 if (not defined($array_size)) { 381 $array_size = $self->ParseArrayPullGetSize($e, $l, $ndr, $var_name, $env); 382 } 383 384 if (not $l->{IS_VARYING}) { 385 return $array_size; 386 } 387 388 my $length = "ndr_get_array_length($ndr, " . get_pointer_to($var_name) .")"; 389 $self->pidl("length_$e->{NAME}_$l->{LEVEL_INDEX} = $length;"); 390 my $array_length = "length_$e->{NAME}_$l->{LEVEL_INDEX}"; 391 392 if (my $range = has_property($e, "range")) { 393 my ($low, $high) = parse_range($range); 394 if ($low < 0) { 395 warning(0, "$low is invalid for the range of an array size"); 396 } 397 if ($low == 0) { 398 $self->pidl("if ($array_length > $high) {"); 399 } else { 400 $self->pidl("if ($array_length < $low || $array_length > $high) {"); 401 } 402 $self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_RANGE, \"value out of range\");"); 403 $self->pidl("}"); 404 } 405 406 return $array_length; 407} 408 409##################################################################### 410# parse an array - pull side 411sub ParseArrayPullHeader($$$$$$) 412{ 413 my ($self,$e,$l,$ndr,$var_name,$env) = @_; 414 415 if ((!$l->{IS_SURROUNDING}) and $l->{IS_CONFORMANT}) { 416 $self->pidl("NDR_CHECK(ndr_pull_array_size($ndr, " . get_pointer_to($var_name) . "));"); 417 } 418 419 if ($l->{IS_VARYING}) { 420 $self->pidl("NDR_CHECK(ndr_pull_array_length($ndr, " . get_pointer_to($var_name) . "));"); 421 } 422 423 my $array_size = $self->ParseArrayPullGetSize($e, $l, $ndr, $var_name, $env); 424 my $array_length = $self->ParseArrayPullGetLength($e, $l, $ndr, $var_name, $env, $array_size); 425 426 if ($array_length ne $array_size) { 427 $self->pidl("if ($array_length > $array_size) {"); 428 $self->indent; 429 $self->pidl("return ndr_pull_error($ndr, NDR_ERR_ARRAY_SIZE, \"Bad array size %u should exceed array length %u\", $array_size, $array_length);"); 430 $self->deindent; 431 $self->pidl("}"); 432 } 433 434 if ($l->{IS_CONFORMANT} and (defined($l->{SIZE_IS}) or not $l->{IS_ZERO_TERMINATED})) { 435 $self->defer("if ($var_name) {"); 436 $self->defer_indent; 437 my $size = ParseExprExt($l->{SIZE_IS}, $env, $e->{ORIGINAL}, 438 check_null_pointer($e, $env, sub { $self->defer(shift); }, 439 "return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for size_is()\");"), 440 check_fully_dereferenced($e, $env)); 441 $self->defer("NDR_CHECK(ndr_check_array_size($ndr, (void*)" . get_pointer_to($var_name) . ", $size));"); 442 $self->defer_deindent; 443 $self->defer("}"); 444 } 445 446 if ($l->{IS_VARYING} and (defined($l->{LENGTH_IS}) or not $l->{IS_ZERO_TERMINATED})) { 447 $self->defer("if ($var_name) {"); 448 $self->defer_indent; 449 my $length = ParseExprExt($l->{LENGTH_IS}, $env, $e->{ORIGINAL}, 450 check_null_pointer($e, $env, sub { $self->defer(shift); }, 451 "return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for length_is()\");"), 452 check_fully_dereferenced($e, $env)); 453 $self->defer("NDR_CHECK(ndr_check_array_length($ndr, (void*)" . get_pointer_to($var_name) . ", $length));"); 454 $self->defer_deindent; 455 $self->defer("}"); 456 } 457 458 if (ArrayDynamicallyAllocated($e,$l) and not is_charset_array($e,$l)) { 459 $self->AllocateArrayLevel($e,$l,$ndr,$var_name,$array_size); 460 } 461 462 return $array_length; 463} 464 465sub compression_alg($$) 466{ 467 my ($e, $l) = @_; 468 my ($alg, $clen, $dlen) = split(/,/, $l->{COMPRESSION}); 469 470 return $alg; 471} 472 473sub compression_clen($$$) 474{ 475 my ($e, $l, $env) = @_; 476 my ($alg, $clen, $dlen) = split(/,/, $l->{COMPRESSION}); 477 478 return ParseExpr($clen, $env, $e->{ORIGINAL}); 479} 480 481sub compression_dlen($$$) 482{ 483 my ($e,$l,$env) = @_; 484 my ($alg, $clen, $dlen) = split(/,/, $l->{COMPRESSION}); 485 486 return ParseExpr($dlen, $env, $e->{ORIGINAL}); 487} 488 489sub ParseCompressionPushStart($$$$$) 490{ 491 my ($self,$e,$l,$ndr,$env) = @_; 492 my $comndr = "$ndr\_compressed"; 493 my $alg = compression_alg($e, $l); 494 my $dlen = compression_dlen($e, $l, $env); 495 496 $self->pidl("{"); 497 $self->indent; 498 $self->pidl("struct ndr_push *$comndr;"); 499 $self->pidl("NDR_CHECK(ndr_push_compression_start($ndr, &$comndr, $alg, $dlen));"); 500 501 return $comndr; 502} 503 504sub ParseCompressionPushEnd($$$$$) 505{ 506 my ($self,$e,$l,$ndr,$env) = @_; 507 my $comndr = "$ndr\_compressed"; 508 my $alg = compression_alg($e, $l); 509 my $dlen = compression_dlen($e, $l, $env); 510 511 $self->pidl("NDR_CHECK(ndr_push_compression_end($ndr, $comndr, $alg, $dlen));"); 512 $self->deindent; 513 $self->pidl("}"); 514} 515 516sub ParseCompressionPullStart($$$$$) 517{ 518 my ($self,$e,$l,$ndr,$env) = @_; 519 my $comndr = "$ndr\_compressed"; 520 my $alg = compression_alg($e, $l); 521 my $dlen = compression_dlen($e, $l, $env); 522 my $clen = compression_clen($e, $l, $env); 523 524 $self->pidl("{"); 525 $self->indent; 526 $self->pidl("struct ndr_pull *$comndr;"); 527 $self->pidl("NDR_CHECK(ndr_pull_compression_start($ndr, &$comndr, $alg, $dlen, $clen));"); 528 529 return $comndr; 530} 531 532sub ParseCompressionPullEnd($$$$$) 533{ 534 my ($self,$e,$l,$ndr,$env) = @_; 535 my $comndr = "$ndr\_compressed"; 536 my $alg = compression_alg($e, $l); 537 my $dlen = compression_dlen($e, $l, $env); 538 539 $self->pidl("NDR_CHECK(ndr_pull_compression_end($ndr, $comndr, $alg, $dlen));"); 540 $self->deindent; 541 $self->pidl("}"); 542} 543 544sub ParseSubcontextPushStart($$$$$) 545{ 546 my ($self,$e,$l,$ndr,$env) = @_; 547 my $subndr = "_ndr_$e->{NAME}"; 548 my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL}); 549 550 $self->pidl("{"); 551 $self->indent; 552 $self->pidl("struct ndr_push *$subndr;"); 553 $self->pidl("NDR_CHECK(ndr_push_subcontext_start($ndr, &$subndr, $l->{HEADER_SIZE}, $subcontext_size));"); 554 555 if (defined $l->{COMPRESSION}) { 556 $subndr = $self->ParseCompressionPushStart($e, $l, $subndr, $env); 557 } 558 559 return $subndr; 560} 561 562sub ParseSubcontextPushEnd($$$$$) 563{ 564 my ($self,$e,$l,$ndr,$env) = @_; 565 my $subndr = "_ndr_$e->{NAME}"; 566 my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL}); 567 568 if (defined $l->{COMPRESSION}) { 569 $self->ParseCompressionPushEnd($e, $l, $subndr, $env); 570 } 571 572 $self->pidl("NDR_CHECK(ndr_push_subcontext_end($ndr, $subndr, $l->{HEADER_SIZE}, $subcontext_size));"); 573 $self->deindent; 574 $self->pidl("}"); 575} 576 577sub ParseSubcontextPullStart($$$$$) 578{ 579 my ($self,$e,$l,$ndr,$env) = @_; 580 my $subndr = "_ndr_$e->{NAME}"; 581 my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL}); 582 583 $self->pidl("{"); 584 $self->indent; 585 $self->pidl("struct ndr_pull *$subndr;"); 586 $self->pidl("NDR_CHECK(ndr_pull_subcontext_start($ndr, &$subndr, $l->{HEADER_SIZE}, $subcontext_size));"); 587 588 if (defined $l->{COMPRESSION}) { 589 $subndr = $self->ParseCompressionPullStart($e, $l, $subndr, $env); 590 } 591 592 return $subndr; 593} 594 595sub ParseSubcontextPullEnd($$$$$) 596{ 597 my ($self,$e,$l,$ndr,$env) = @_; 598 my $subndr = "_ndr_$e->{NAME}"; 599 my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL}); 600 601 if (defined $l->{COMPRESSION}) { 602 $self->ParseCompressionPullEnd($e, $l, $subndr, $env); 603 } 604 605 $self->pidl("NDR_CHECK(ndr_pull_subcontext_end($ndr, $subndr, $l->{HEADER_SIZE}, $subcontext_size));"); 606 $self->deindent; 607 $self->pidl("}"); 608} 609 610sub ParseElementPushLevel 611{ 612 my ($self,$e,$l,$ndr,$var_name,$env,$primitives,$deferred) = @_; 613 614 my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred); 615 616 if ($l->{TYPE} eq "ARRAY" and ($l->{IS_CONFORMANT} or $l->{IS_VARYING})) { 617 $var_name = get_pointer_to($var_name); 618 } 619 620 if (defined($ndr_flags)) { 621 if ($l->{TYPE} eq "SUBCONTEXT") { 622 my $subndr = $self->ParseSubcontextPushStart($e, $l, $ndr, $env); 623 $self->ParseElementPushLevel($e, GetNextLevel($e, $l), $subndr, $var_name, $env, 1, 1); 624 $self->ParseSubcontextPushEnd($e, $l, $ndr, $env); 625 } elsif ($l->{TYPE} eq "POINTER") { 626 $self->ParsePtrPush($e, $l, $ndr, $var_name); 627 } elsif ($l->{TYPE} eq "ARRAY") { 628 my $length = $self->ParseArrayPushHeader($e, $l, $ndr, $var_name, $env); 629 630 my $nl = GetNextLevel($e, $l); 631 632 # Allow speedups for arrays of scalar types 633 if (is_charset_array($e,$l)) { 634 if ($l->{IS_TO_NULL}) { 635 $self->pidl("NDR_CHECK(ndr_push_charset_to_null($ndr, $ndr_flags, $var_name, $length, sizeof(" . mapTypeName($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));"); 636 } else { 637 $self->pidl("NDR_CHECK(ndr_push_charset($ndr, $ndr_flags, $var_name, $length, sizeof(" . mapTypeName($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));"); 638 } 639 return; 640 } elsif (has_fast_array($e,$l)) { 641 $self->pidl("NDR_CHECK(ndr_push_array_$nl->{DATA_TYPE}($ndr, $ndr_flags, $var_name, $length));"); 642 return; 643 } 644 } elsif ($l->{TYPE} eq "DATA") { 645 $self->ParseDataPush($e, $l, $ndr, $var_name, $primitives, $deferred); 646 } elsif ($l->{TYPE} eq "TYPEDEF") { 647 $typefamily{$e->{DATA}->{TYPE}}->{PUSH_FN_BODY}->($self, $e->{DATA}, $ndr, $var_name); 648 } 649 } 650 651 if ($l->{TYPE} eq "POINTER" and $l->{POINTER_TYPE} eq "ignore") { 652 $self->pidl("/* [ignore] '$e->{NAME}' */"); 653 } elsif ($l->{TYPE} eq "POINTER" and $deferred) { 654 my $rel_var_name = $var_name; 655 if ($l->{POINTER_TYPE} ne "ref") { 656 $self->pidl("if ($var_name) {"); 657 $self->indent; 658 if ($l->{POINTER_TYPE} eq "relative") { 659 $self->pidl("NDR_CHECK(ndr_push_relative_ptr2_start($ndr, $rel_var_name));"); 660 } 661 if ($l->{POINTER_TYPE} eq "relative_short") { 662 $self->pidl("NDR_CHECK(ndr_push_short_relative_ptr2($ndr, $var_name));"); 663 } 664 } 665 $var_name = get_value_of($var_name); 666 $self->ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 1, 1); 667 668 if ($l->{POINTER_TYPE} ne "ref") { 669 if ($l->{POINTER_TYPE} eq "relative") { 670 $self->pidl("NDR_CHECK(ndr_push_relative_ptr2_end($ndr, $rel_var_name));"); 671 } 672 $self->deindent; 673 $self->pidl("}"); 674 } 675 } elsif ($l->{TYPE} eq "ARRAY" and not has_fast_array($e,$l) and 676 not is_charset_array($e, $l)) { 677 my $length = ParseExpr($l->{LENGTH_IS}, $env, $e->{ORIGINAL}); 678 my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}"; 679 680 my $array_pointless = ($length eq "0"); 681 682 if ($array_pointless) { 683 warning($e->{ORIGINAL}, "pointless array `$e->{NAME}' will always have size 0"); 684 } 685 686 $var_name = get_array_element($var_name, $counter); 687 688 if ((($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) and not $array_pointless) { 689 $self->pidl("for ($counter = 0; $counter < ($length); $counter++) {"); 690 $self->indent; 691 $self->ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 1, 0); 692 $self->deindent; 693 $self->pidl("}"); 694 } 695 696 if ($deferred and ContainsDeferred($e, $l) and not $array_pointless) { 697 $self->pidl("for ($counter = 0; $counter < ($length); $counter++) {"); 698 $self->indent; 699 $self->ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 0, 1); 700 $self->deindent; 701 $self->pidl("}"); 702 } 703 } elsif ($l->{TYPE} eq "SWITCH") { 704 my $nl = GetNextLevel($e,$l); 705 my $needs_deferred_switch = is_deferred_switch_non_empty($nl); 706 707 # Avoid setting a switch value if it will not be 708 # consumed again in the NDR_BUFFERS pull 709 if ($needs_deferred_switch or !$deferred) { 710 $self->ParseSwitchPush($e, $l, $ndr, $var_name, $env); 711 } 712 $self->ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, $primitives, $deferred); 713 } 714} 715 716##################################################################### 717# parse scalars in a structure element 718sub ParseElementPush($$$$$$) 719{ 720 my ($self,$e,$ndr,$env,$primitives,$deferred) = @_; 721 my $subndr = undef; 722 723 my $var_name = $env->{$e->{NAME}}; 724 725 if (has_property($e, "skip") or has_property($e, "skip_noinit")) { 726 $self->pidl("/* [skip] '$var_name' */"); 727 return; 728 } 729 730 return if ContainsPipe($e, $e->{LEVELS}[0]); 731 732 return unless $primitives or ($deferred and ContainsDeferred($e, $e->{LEVELS}[0])); 733 734 # Representation type is different from transmit_as 735 if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) { 736 $self->pidl("{"); 737 $self->indent; 738 my $transmit_name = "_transmit_$e->{NAME}"; 739 $self->pidl(mapTypeName($e->{TYPE}) ." $transmit_name;"); 740 $self->pidl("NDR_CHECK(ndr_$e->{REPRESENTATION_TYPE}_to_$e->{TYPE}($var_name, " . get_pointer_to($transmit_name) . "));"); 741 $var_name = $transmit_name; 742 } 743 744 $var_name = append_prefix($e, $var_name); 745 746 $self->start_flags($e, $ndr); 747 748 if (defined(my $value = has_property($e, "value"))) { 749 $var_name = ParseExpr($value, $env, $e->{ORIGINAL}); 750 } 751 752 $self->ParseElementPushLevel($e, $e->{LEVELS}[0], $ndr, $var_name, $env, $primitives, $deferred); 753 754 $self->end_flags($e, $ndr); 755 756 if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) { 757 $self->deindent; 758 $self->pidl("}"); 759 } 760} 761 762##################################################################### 763# parse a pointer in a struct element or function 764sub ParsePtrPush($$$$$) 765{ 766 my ($self,$e,$l,$ndr,$var_name) = @_; 767 768 if ($l->{POINTER_TYPE} eq "ref") { 769 if ($l->{LEVEL_INDEX} > 0) { 770 $self->pidl("if ($var_name == NULL) {"); 771 $self->indent; 772 $self->pidl("return ndr_push_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL [ref] pointer\");"); 773 $self->deindent; 774 $self->pidl("}"); 775 } 776 if ($l->{LEVEL} eq "EMBEDDED") { 777 $self->pidl("NDR_CHECK(ndr_push_ref_ptr(ndr)); /* $var_name */"); 778 } 779 } elsif ($l->{POINTER_TYPE} eq "relative") { 780 $self->pidl("NDR_CHECK(ndr_push_relative_ptr1($ndr, $var_name));"); 781 } elsif ($l->{POINTER_TYPE} eq "relative_short") { 782 $self->pidl("NDR_CHECK(ndr_push_short_relative_ptr1($ndr, $var_name));"); 783 } elsif ($l->{POINTER_TYPE} eq "unique") { 784 $self->pidl("NDR_CHECK(ndr_push_unique_ptr($ndr, $var_name));"); 785 } elsif ($l->{POINTER_TYPE} eq "full") { 786 $self->pidl("NDR_CHECK(ndr_push_full_ptr($ndr, $var_name));"); 787 } elsif ($l->{POINTER_TYPE} eq "ignore") { 788 # We don't want this pointer to appear on the wire at all 789 $self->pidl("NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, 0));"); 790 } else { 791 die("Unhandled pointer type $l->{POINTER_TYPE}"); 792 } 793} 794 795sub need_pointer_to($$$) 796{ 797 my ($e, $l, $scalar_only) = @_; 798 799 my $t; 800 if (ref($l->{DATA_TYPE})) { 801 $t = "$l->{DATA_TYPE}->{TYPE}_$l->{DATA_TYPE}->{NAME}"; 802 } else { 803 $t = $l->{DATA_TYPE}; 804 } 805 806 if (not Parse::Pidl::Typelist::is_scalar($t)) { 807 return 1 if $scalar_only; 808 } 809 810 my $arrays = 0; 811 812 foreach my $tl (@{$e->{LEVELS}}) { 813 last if $l == $tl; 814 if ($tl->{TYPE} eq "ARRAY") { 815 $arrays++; 816 } 817 } 818 819 if (Parse::Pidl::Typelist::scalar_is_reference($t)) { 820 return 1 unless $arrays; 821 } 822 823 return 0; 824} 825 826sub ParseDataPrint($$$$$) 827{ 828 my ($self, $e, $l, $ndr, $var_name) = @_; 829 830 if (not ref($l->{DATA_TYPE}) or defined($l->{DATA_TYPE}->{NAME})) { 831 832 if (need_pointer_to($e, $l, 1)) { 833 $var_name = get_pointer_to($var_name); 834 } 835 836 $self->pidl(TypeFunctionName("ndr_print", $l->{DATA_TYPE})."($ndr, \"$e->{NAME}\", $var_name);"); 837 } else { 838 $self->ParseTypePrint($l->{DATA_TYPE}, $ndr, $var_name); 839 } 840} 841 842##################################################################### 843# print scalars in a structure element 844sub ParseElementPrint($$$$$) 845{ 846 my($self, $e, $ndr, $var_name, $env) = @_; 847 848 return if (has_property($e, "noprint")); 849 my $cur_depth = 0; 850 my $ignore_depth = 0xFFFF; 851 852 $self->start_flags($e, $ndr); 853 if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) { 854 $self->pidl("ndr_print_$e->{REPRESENTATION_TYPE}($ndr, \"$e->{NAME}\", $var_name);"); 855 $self->end_flags($e, $ndr); 856 return; 857 } 858 859 $var_name = append_prefix($e, $var_name); 860 861 if (defined(my $value = has_property($e, "value"))) { 862 $var_name = "($ndr->flags & LIBNDR_PRINT_SET_VALUES)?" . ParseExpr($value,$env, $e->{ORIGINAL}) . ":$var_name"; 863 } 864 865 foreach my $l (@{$e->{LEVELS}}) { 866 $cur_depth += 1; 867 868 if ($cur_depth > $ignore_depth) { 869 next; 870 } 871 872 if ($l->{TYPE} eq "POINTER") { 873 $self->pidl("ndr_print_ptr($ndr, \"$e->{NAME}\", $var_name);"); 874 if ($l->{POINTER_TYPE} eq "ignore") { 875 $self->pidl("/* [ignore] '$e->{NAME}' */"); 876 $ignore_depth = $cur_depth; 877 last; 878 } 879 $self->pidl("$ndr->depth++;"); 880 if ($l->{POINTER_TYPE} ne "ref") { 881 $self->pidl("if ($var_name) {"); 882 $self->indent; 883 } 884 $var_name = get_value_of($var_name); 885 } elsif ($l->{TYPE} eq "ARRAY") { 886 my $length; 887 888 if ($l->{IS_CONFORMANT} or $l->{IS_VARYING}) { 889 $var_name = get_pointer_to($var_name); 890 } 891 892 if ($l->{IS_ZERO_TERMINATED} and not defined($l->{LENGTH_IS})) { 893 $length = "ndr_string_length($var_name, sizeof(*$var_name))"; 894 } else { 895 $length = ParseExprExt($l->{LENGTH_IS}, $env, $e->{ORIGINAL}, 896 check_null_pointer($e, $env, sub { $self->pidl(shift); }, "return;"), check_fully_dereferenced($e, $env)); 897 } 898 899 if (is_charset_array($e,$l)) { 900 $self->pidl("ndr_print_string($ndr, \"$e->{NAME}\", $var_name);"); 901 last; 902 } elsif (has_fast_array($e, $l)) { 903 my $nl = GetNextLevel($e, $l); 904 $self->pidl("ndr_print_array_$nl->{DATA_TYPE}($ndr, \"$e->{NAME}\", $var_name, $length);"); 905 last; 906 } else { 907 my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}"; 908 909 $self->pidl("$ndr->print($ndr, \"\%s: ARRAY(\%d)\", \"$e->{NAME}\", (int)$length);"); 910 $self->pidl("$ndr->depth++;"); 911 $self->pidl("for ($counter = 0; $counter < ($length); $counter++) {"); 912 $self->indent; 913 914 $var_name = get_array_element($var_name, $counter); 915 } 916 } elsif ($l->{TYPE} eq "DATA") { 917 $self->ParseDataPrint($e, $l, $ndr, $var_name); 918 } elsif ($l->{TYPE} eq "SWITCH") { 919 my $switch_var = ParseExprExt($l->{SWITCH_IS}, $env, $e->{ORIGINAL}, 920 check_null_pointer($e, $env, sub { $self->pidl(shift); }, "return;"), check_fully_dereferenced($e, $env)); 921 $self->pidl("ndr_print_set_switch_value($ndr, " . get_pointer_to($var_name) . ", $switch_var);"); 922 } 923 } 924 925 foreach my $l (reverse @{$e->{LEVELS}}) { 926 $cur_depth -= 1; 927 928 if ($cur_depth > $ignore_depth) { 929 next; 930 } 931 932 if ($l->{TYPE} eq "POINTER") { 933 if ($l->{POINTER_TYPE} eq "ignore") { 934 next; 935 } 936 937 if ($l->{POINTER_TYPE} ne "ref") { 938 $self->deindent; 939 $self->pidl("}"); 940 } 941 $self->pidl("$ndr->depth--;"); 942 } elsif (($l->{TYPE} eq "ARRAY") 943 and not is_charset_array($e,$l) 944 and not has_fast_array($e,$l)) { 945 $self->deindent; 946 $self->pidl("}"); 947 $self->pidl("$ndr->depth--;"); 948 } 949 } 950 951 $self->end_flags($e, $ndr); 952} 953 954##################################################################### 955# parse scalars in a structure element - pull size 956sub ParseSwitchPull($$$$$$) 957{ 958 my($self,$e,$l,$ndr,$var_name,$env) = @_; 959 my $switch_var = ParseExprExt($l->{SWITCH_IS}, $env, $e->{ORIGINAL}, 960 check_null_pointer($e, $env, sub { $self->pidl(shift); }, 961 "return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for switch_is()\");"), 962 check_fully_dereferenced($e, $env)); 963 964 $var_name = get_pointer_to($var_name); 965 $self->pidl("NDR_CHECK(ndr_pull_set_switch_value($ndr, $var_name, $switch_var));"); 966} 967 968##################################################################### 969# push switch element 970sub ParseSwitchPush($$$$$$) 971{ 972 my($self,$e,$l,$ndr,$var_name,$env) = @_; 973 my $switch_var = ParseExprExt($l->{SWITCH_IS}, $env, $e->{ORIGINAL}, 974 check_null_pointer($e, $env, sub { $self->pidl(shift); }, 975 "return ndr_push_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for switch_is()\");"), 976 check_fully_dereferenced($e, $env)); 977 978 $var_name = get_pointer_to($var_name); 979 $self->pidl("NDR_CHECK(ndr_push_set_switch_value($ndr, $var_name, $switch_var));"); 980} 981 982sub ParseDataPull($$$$$$$) 983{ 984 my ($self,$e,$l,$ndr,$var_name,$primitives,$deferred) = @_; 985 986 if (not ref($l->{DATA_TYPE}) or defined($l->{DATA_TYPE}->{NAME})) { 987 988 my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred); 989 990 if (need_pointer_to($e, $l, 0)) { 991 $var_name = get_pointer_to($var_name); 992 } 993 994 $var_name = get_pointer_to($var_name); 995 996 $self->pidl("NDR_CHECK(".TypeFunctionName("ndr_pull", $l->{DATA_TYPE})."($ndr, $ndr_flags, $var_name));"); 997 998 my $pl = GetPrevLevel($e, $l); 999 1000 my $range = has_property($e, "range"); 1001 if ($range and (not $pl or $pl->{TYPE} ne "ARRAY")) { 1002 $var_name = get_value_of($var_name); 1003 my $signed = Parse::Pidl::Typelist::is_signed($l->{DATA_TYPE}); 1004 my ($low, $high) = parse_range($range); 1005 if ($low < 0 and not $signed) { 1006 warning(0, "$low is invalid for the range of an unsigned type"); 1007 } 1008 if ($low == 0 and not $signed) { 1009 $self->pidl("if ($var_name > $high) {"); 1010 } else { 1011 $self->pidl("if ($var_name < $low || $var_name > $high) {"); 1012 } 1013 $self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_RANGE, \"value out of range\");"); 1014 $self->pidl("}"); 1015 } 1016 } else { 1017 $self->ParseTypePull($l->{DATA_TYPE}, $ndr, $var_name, $primitives, $deferred); 1018 } 1019} 1020 1021sub ParseDataPush($$$$$$$) 1022{ 1023 my ($self,$e,$l,$ndr,$var_name,$primitives,$deferred) = @_; 1024 1025 if (not ref($l->{DATA_TYPE}) or defined($l->{DATA_TYPE}->{NAME})) { 1026 1027 my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred); 1028 1029 # strings are passed by value rather than reference 1030 if (need_pointer_to($e, $l, 1)) { 1031 $var_name = get_pointer_to($var_name); 1032 } 1033 1034 $self->pidl("NDR_CHECK(".TypeFunctionName("ndr_push", $l->{DATA_TYPE})."($ndr, $ndr_flags, $var_name));"); 1035 } else { 1036 $self->ParseTypePush($l->{DATA_TYPE}, $ndr, $var_name, $primitives, $deferred); 1037 } 1038} 1039 1040sub CalcNdrFlags($$$) 1041{ 1042 my ($l,$primitives,$deferred) = @_; 1043 1044 my $scalars = 0; 1045 my $buffers = 0; 1046 1047 # Add NDR_SCALARS if this one is deferred 1048 # and deferreds may be pushed 1049 $scalars = 1 if ($l->{IS_DEFERRED} and $deferred); 1050 1051 # Add NDR_SCALARS if this one is not deferred and 1052 # primitives may be pushed 1053 $scalars = 1 if (!$l->{IS_DEFERRED} and $primitives); 1054 1055 # Add NDR_BUFFERS if this one contains deferred stuff 1056 # and deferreds may be pushed 1057 $buffers = 1 if ($l->{CONTAINS_DEFERRED} and $deferred); 1058 1059 return "NDR_SCALARS|NDR_BUFFERS" if ($scalars and $buffers); 1060 return "NDR_SCALARS" if ($scalars); 1061 return "NDR_BUFFERS" if ($buffers); 1062 return undef; 1063} 1064 1065sub ParseMemCtxPullFlags($$$$) 1066{ 1067 my ($self, $e, $l) = @_; 1068 1069 return undef unless ($l->{TYPE} eq "POINTER" or $l->{TYPE} eq "ARRAY"); 1070 return undef if (($l->{TYPE} eq "POINTER") and ($l->{POINTER_TYPE} eq "ignore")); 1071 1072 return undef unless ($l->{TYPE} ne "ARRAY" or ArrayDynamicallyAllocated($e,$l)); 1073 return undef if has_fast_array($e, $l); 1074 return undef if is_charset_array($e, $l); 1075 1076 my $mem_flags = "0"; 1077 1078 if (($l->{TYPE} eq "POINTER") and ($l->{POINTER_TYPE} eq "ref")) { 1079 my $nl = GetNextLevel($e, $l); 1080 return undef if ($nl->{TYPE} eq "PIPE"); 1081 return undef if ($nl->{TYPE} eq "ARRAY"); 1082 return undef if (($nl->{TYPE} eq "DATA") and ($nl->{DATA_TYPE} eq "string")); 1083 1084 if ($l->{LEVEL} eq "TOP") { 1085 $mem_flags = "LIBNDR_FLAG_REF_ALLOC"; 1086 } 1087 } 1088 1089 return $mem_flags; 1090} 1091 1092sub ParseMemCtxPullStart($$$$$) 1093{ 1094 my ($self, $e, $l, $ndr, $ptr_name) = @_; 1095 1096 my $mem_r_ctx = "_mem_save_$e->{NAME}_$l->{LEVEL_INDEX}"; 1097 my $mem_c_ctx = $ptr_name; 1098 my $mem_c_flags = $self->ParseMemCtxPullFlags($e, $l); 1099 1100 return unless defined($mem_c_flags); 1101 1102 $self->pidl("$mem_r_ctx = NDR_PULL_GET_MEM_CTX($ndr);"); 1103 $self->pidl("NDR_PULL_SET_MEM_CTX($ndr, $mem_c_ctx, $mem_c_flags);"); 1104} 1105 1106sub ParseMemCtxPullEnd($$$$) 1107{ 1108 my ($self, $e, $l, $ndr) = @_; 1109 1110 my $mem_r_ctx = "_mem_save_$e->{NAME}_$l->{LEVEL_INDEX}"; 1111 my $mem_r_flags = $self->ParseMemCtxPullFlags($e, $l); 1112 1113 return unless defined($mem_r_flags); 1114 1115 $self->pidl("NDR_PULL_SET_MEM_CTX($ndr, $mem_r_ctx, $mem_r_flags);"); 1116} 1117 1118sub CheckStringTerminator($$$$$) 1119{ 1120 my ($self,$ndr,$e,$l,$length) = @_; 1121 my $nl = GetNextLevel($e, $l); 1122 1123 # Make sure last element is zero! 1124 $self->pidl("NDR_CHECK(ndr_check_string_terminator($ndr, $length, sizeof($nl->{DATA_TYPE}_t)));"); 1125} 1126 1127sub ParseElementPullLevel 1128{ 1129 my($self,$e,$l,$ndr,$var_name,$env,$primitives,$deferred) = @_; 1130 1131 my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred); 1132 my $array_length = undef; 1133 1134 if (has_property($e, "skip") or has_property($e, "skip_noinit")) { 1135 $self->pidl("/* [skip] '$var_name' */"); 1136 if (not has_property($e, "skip_noinit")) { 1137 $self->pidl("NDR_ZERO_STRUCT($var_name);"); 1138 } 1139 return; 1140 } 1141 1142 if ($l->{TYPE} eq "ARRAY" and ($l->{IS_VARYING} or $l->{IS_CONFORMANT})) { 1143 $var_name = get_pointer_to($var_name); 1144 } 1145 1146 # Only pull something if there's actually something to be pulled 1147 if (defined($ndr_flags)) { 1148 if ($l->{TYPE} eq "SUBCONTEXT") { 1149 my $subndr = $self->ParseSubcontextPullStart($e, $l, $ndr, $env); 1150 $self->ParseElementPullLevel($e, GetNextLevel($e,$l), $subndr, $var_name, $env, 1, 1); 1151 $self->ParseSubcontextPullEnd($e, $l, $ndr, $env); 1152 } elsif ($l->{TYPE} eq "ARRAY") { 1153 my $length = $self->ParseArrayPullHeader($e, $l, $ndr, $var_name, $env); 1154 $array_length = $length; 1155 1156 my $nl = GetNextLevel($e, $l); 1157 1158 if (is_charset_array($e,$l)) { 1159 if ($l->{IS_ZERO_TERMINATED}) { 1160 $self->CheckStringTerminator($ndr, $e, $l, $length); 1161 } 1162 if ($l->{IS_TO_NULL}) { 1163 $self->pidl("NDR_CHECK(ndr_pull_charset_to_null($ndr, $ndr_flags, ".get_pointer_to($var_name).", $length, sizeof(" . mapTypeName($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));"); 1164 } else { 1165 $self->pidl("NDR_CHECK(ndr_pull_charset($ndr, $ndr_flags, ".get_pointer_to($var_name).", $length, sizeof(" . mapTypeName($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));"); 1166 } 1167 return; 1168 } elsif (has_fast_array($e, $l)) { 1169 if ($l->{IS_ZERO_TERMINATED}) { 1170 $self->CheckStringTerminator($ndr,$e,$l,$length); 1171 } 1172 $self->pidl("NDR_CHECK(ndr_pull_array_$nl->{DATA_TYPE}($ndr, $ndr_flags, $var_name, $length));"); 1173 return; 1174 } 1175 } elsif ($l->{TYPE} eq "POINTER") { 1176 $self->ParsePtrPull($e, $l, $ndr, $var_name); 1177 } elsif ($l->{TYPE} eq "DATA") { 1178 $self->ParseDataPull($e, $l, $ndr, $var_name, $primitives, $deferred); 1179 } elsif ($l->{TYPE} eq "TYPEDEF") { 1180 $typefamily{$e->{DATA}->{TYPE}}->{PULL_FN_BODY}->($self, $e->{DATA}, $ndr, $var_name); 1181 } 1182 } 1183 1184 # add additional constructions 1185 if ($l->{TYPE} eq "POINTER" and $l->{POINTER_TYPE} eq "ignore") { 1186 $self->pidl("/* [ignore] '$e->{NAME}' */"); 1187 } elsif ($l->{TYPE} eq "POINTER" and $deferred) { 1188 if ($l->{POINTER_TYPE} ne "ref") { 1189 $self->pidl("if ($var_name) {"); 1190 $self->indent; 1191 1192 if ($l->{POINTER_TYPE} eq "relative" or $l->{POINTER_TYPE} eq "relative_short") { 1193 $self->pidl("uint32_t _relative_save_offset;"); 1194 $self->pidl("_relative_save_offset = $ndr->offset;"); 1195 $self->pidl("NDR_CHECK(ndr_pull_relative_ptr2($ndr, $var_name));"); 1196 } 1197 } 1198 1199 $self->ParseMemCtxPullStart($e, $l, $ndr, $var_name); 1200 1201 $var_name = get_value_of($var_name); 1202 $self->ParseElementPullLevel($e, GetNextLevel($e,$l), $ndr, $var_name, $env, 1, 1); 1203 1204 $self->ParseMemCtxPullEnd($e, $l, $ndr); 1205 1206 if ($l->{POINTER_TYPE} ne "ref") { 1207 if ($l->{POINTER_TYPE} eq "relative" or $l->{POINTER_TYPE} eq "relative_short") { 1208 $self->pidl("if ($ndr->offset > $ndr->relative_highest_offset) {"); 1209 $self->indent; 1210 $self->pidl("$ndr->relative_highest_offset = $ndr->offset;"); 1211 $self->deindent; 1212 $self->pidl("}"); 1213 $self->pidl("$ndr->offset = _relative_save_offset;"); 1214 } 1215 $self->deindent; 1216 $self->pidl("}"); 1217 } 1218 } elsif ($l->{TYPE} eq "ARRAY" and 1219 not has_fast_array($e,$l) and not is_charset_array($e, $l)) { 1220 my $length = $array_length; 1221 my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}"; 1222 my $array_name = $var_name; 1223 1224 if (not defined($length)) { 1225 $length = $self->ParseArrayPullGetLength($e, $l, $ndr, $var_name, $env); 1226 } 1227 1228 $var_name = get_array_element($var_name, $counter); 1229 1230 $self->ParseMemCtxPullStart($e, $l, $ndr, $array_name); 1231 1232 if (($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) { 1233 my $nl = GetNextLevel($e,$l); 1234 1235 if ($l->{IS_ZERO_TERMINATED}) { 1236 $self->CheckStringTerminator($ndr,$e,$l,$length); 1237 } 1238 1239 $self->pidl("for ($counter = 0; $counter < ($length); $counter++) {"); 1240 $self->indent; 1241 $self->ParseElementPullLevel($e, $nl, $ndr, $var_name, $env, 1, 0); 1242 $self->deindent; 1243 $self->pidl("}"); 1244 } 1245 1246 if ($deferred and ContainsDeferred($e, $l)) { 1247 $self->pidl("for ($counter = 0; $counter < ($length); $counter++) {"); 1248 $self->defer("for ($counter = 0; $counter < ($length); $counter++) {"); 1249 $self->defer_indent; 1250 $self->indent; 1251 $self->ParseElementPullLevel($e,GetNextLevel($e,$l), $ndr, $var_name, $env, 0, 1); 1252 $self->deindent; 1253 $self->defer_deindent; 1254 $self->pidl("}"); 1255 $self->defer("}"); 1256 } 1257 1258 $self->ParseMemCtxPullEnd($e, $l, $ndr); 1259 1260 } elsif ($l->{TYPE} eq "SWITCH") { 1261 my $nl = GetNextLevel($e,$l); 1262 my $needs_deferred_switch = is_deferred_switch_non_empty($nl); 1263 1264 # Avoid setting a switch value if it will not be 1265 # consumed again in the NDR_BUFFERS pull 1266 if ($needs_deferred_switch or !$deferred) { 1267 $self->ParseSwitchPull($e, $l, $ndr, $var_name, $env); 1268 } 1269 $self->ParseElementPullLevel($e, $nl, $ndr, $var_name, $env, $primitives, $deferred); 1270 } 1271} 1272 1273##################################################################### 1274# parse scalars in a structure element - pull size 1275sub ParseElementPull($$$$$$) 1276{ 1277 my($self,$e,$ndr,$env,$primitives,$deferred) = @_; 1278 1279 my $var_name = $env->{$e->{NAME}}; 1280 my $represent_name; 1281 my $transmit_name; 1282 1283 return if ContainsPipe($e, $e->{LEVELS}[0]); 1284 1285 return unless $primitives or ($deferred and ContainsDeferred($e, $e->{LEVELS}[0])); 1286 1287 if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) { 1288 $self->pidl("{"); 1289 $self->indent; 1290 $represent_name = $var_name; 1291 $transmit_name = "_transmit_$e->{NAME}"; 1292 $var_name = $transmit_name; 1293 $self->pidl(mapTypeName($e->{TYPE})." $var_name;"); 1294 } 1295 1296 $var_name = append_prefix($e, $var_name); 1297 1298 $self->start_flags($e, $ndr); 1299 1300 $self->ParseElementPullLevel($e,$e->{LEVELS}[0],$ndr,$var_name,$env,$primitives,$deferred); 1301 1302 $self->end_flags($e, $ndr); 1303 1304 # Representation type is different from transmit_as 1305 if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) { 1306 $self->pidl("NDR_CHECK(ndr_$e->{TYPE}_to_$e->{REPRESENTATION_TYPE}($transmit_name, ".get_pointer_to($represent_name)."));"); 1307 $self->deindent; 1308 $self->pidl("}"); 1309 } 1310} 1311 1312##################################################################### 1313# parse a pointer in a struct element or function 1314sub ParsePtrPull($$$$$) 1315{ 1316 my($self, $e,$l,$ndr,$var_name) = @_; 1317 1318 my $nl = GetNextLevel($e, $l); 1319 my $next_is_array = ($nl->{TYPE} eq "ARRAY"); 1320 my $next_is_string = (($nl->{TYPE} eq "DATA") and 1321 ($nl->{DATA_TYPE} eq "string")); 1322 1323 if ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "TOP") { 1324 1325 if (!$next_is_array and !$next_is_string) { 1326 $self->pidl("if ($ndr->flags & LIBNDR_FLAG_REF_ALLOC) {"); 1327 $self->pidl("\tNDR_PULL_ALLOC($ndr, $var_name);"); 1328 $self->pidl("}"); 1329 } 1330 1331 return; 1332 } elsif ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "EMBEDDED") { 1333 $self->pidl("NDR_CHECK(ndr_pull_ref_ptr($ndr, &_ptr_$e->{NAME}));"); 1334 } elsif (($l->{POINTER_TYPE} eq "unique") or 1335 ($l->{POINTER_TYPE} eq "relative") or 1336 ($l->{POINTER_TYPE} eq "full")) { 1337 $self->pidl("NDR_CHECK(ndr_pull_generic_ptr($ndr, &_ptr_$e->{NAME}));"); 1338 } elsif ($l->{POINTER_TYPE} eq "relative_short") { 1339 $self->pidl("NDR_CHECK(ndr_pull_relative_ptr_short($ndr, &_ptr_$e->{NAME}));"); 1340 } elsif ($l->{POINTER_TYPE} eq "ignore") { 1341 #We want to consume the pointer bytes, but ignore the pointer value 1342 $self->pidl("NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &_ptr_$e->{NAME}));"); 1343 $self->pidl("_ptr_$e->{NAME} = 0;"); 1344 } else { 1345 die("Unhandled pointer type $l->{POINTER_TYPE}"); 1346 } 1347 1348 $self->pidl("if (_ptr_$e->{NAME}) {"); 1349 $self->indent; 1350 1351 if ($l->{POINTER_TYPE} eq "ignore") { 1352 # Don't do anything, we don't want to do the 1353 # allocation, as we forced it to NULL just above, and 1354 # we may not know the declared type anyway. 1355 } else { 1356 # Don't do this for arrays, they're allocated at the actual level 1357 # of the array 1358 unless ($next_is_array or $next_is_string) { 1359 $self->pidl("NDR_PULL_ALLOC($ndr, $var_name);"); 1360 } else { 1361 # FIXME: Yes, this is nasty. 1362 # We allocate an array twice 1363 # - once just to indicate that it's there, 1364 # - then the real allocation... 1365 $self->pidl("NDR_PULL_ALLOC($ndr, $var_name);"); 1366 } 1367 } 1368 1369 #$self->pidl("memset($var_name, 0, sizeof($var_name));"); 1370 if ($l->{POINTER_TYPE} eq "relative" or $l->{POINTER_TYPE} eq "relative_short") { 1371 $self->pidl("NDR_CHECK(ndr_pull_relative_ptr1($ndr, $var_name, _ptr_$e->{NAME}));"); 1372 } 1373 $self->deindent; 1374 $self->pidl("} else {"); 1375 $self->pidl("\t$var_name = NULL;"); 1376 $self->pidl("}"); 1377} 1378 1379sub CheckRefPtrs($$$$) 1380{ 1381 my ($self,$e,$ndr,$env) = @_; 1382 1383 return if ContainsPipe($e, $e->{LEVELS}[0]); 1384 return if ($e->{LEVELS}[0]->{TYPE} ne "POINTER"); 1385 return if ($e->{LEVELS}[0]->{POINTER_TYPE} ne "ref"); 1386 1387 my $var_name = $env->{$e->{NAME}}; 1388 $var_name = append_prefix($e, $var_name); 1389 1390 $self->pidl("if ($var_name == NULL) {"); 1391 $self->indent; 1392 $self->pidl("return ndr_push_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL [ref] pointer\");"); 1393 $self->deindent; 1394 $self->pidl("}"); 1395} 1396 1397sub ParseStructPushPrimitives($$$$$) 1398{ 1399 my ($self, $struct, $ndr, $varname, $env) = @_; 1400 1401 $self->CheckRefPtrs($_, $ndr, $env) foreach (@{$struct->{ELEMENTS}}); 1402 1403 # see if the structure contains a conformant array. If it 1404 # does, then it must be the last element of the structure, and 1405 # we need to push the conformant length early, as it fits on 1406 # the wire before the structure (and even before the structure 1407 # alignment) 1408 if (defined($struct->{SURROUNDING_ELEMENT})) { 1409 my $e = $struct->{SURROUNDING_ELEMENT}; 1410 1411 if (defined($e->{LEVELS}[0]) and 1412 $e->{LEVELS}[0]->{TYPE} eq "ARRAY") { 1413 my $size; 1414 1415 if ($e->{LEVELS}[0]->{IS_ZERO_TERMINATED}) { 1416 if (has_property($e, "charset")) { 1417 $size = "ndr_charset_length($varname->$e->{NAME}, CH_$e->{PROPERTIES}->{charset})"; 1418 } else { 1419 $size = "ndr_string_length($varname->$e->{NAME}, sizeof(*$varname->$e->{NAME}))"; 1420 } 1421 if (defined($e->{LEVELS}[0]->{SIZE_IS})) { 1422 $size = ParseExpr($e->{LEVELS}[0]->{SIZE_IS}, $env, $e->{ORIGINAL}); 1423 } 1424 } else { 1425 $size = ParseExpr($e->{LEVELS}[0]->{SIZE_IS}, $env, $e->{ORIGINAL}); 1426 } 1427 1428 $self->pidl("NDR_CHECK(ndr_push_uint3264($ndr, NDR_SCALARS, $size));"); 1429 } else { 1430 $self->pidl("NDR_CHECK(ndr_push_uint3264($ndr, NDR_SCALARS, ndr_string_array_size($ndr, $varname->$e->{NAME})));"); 1431 } 1432 } 1433 1434 $self->pidl("NDR_CHECK(ndr_push_align($ndr, $struct->{ALIGN}));"); 1435 1436 if (defined($struct->{PROPERTIES}{relative_base})) { 1437 # set the current offset as base for relative pointers 1438 # and store it based on the toplevel struct/union 1439 $self->pidl("NDR_CHECK(ndr_push_setup_relative_base_offset1($ndr, $varname, $ndr->offset));"); 1440 } 1441 1442 $self->ParseElementPush($_, $ndr, $env, 1, 0) foreach (@{$struct->{ELEMENTS}}); 1443 1444 $self->pidl("NDR_CHECK(ndr_push_trailer_align($ndr, $struct->{ALIGN}));"); 1445} 1446 1447sub ParseStructPushDeferred($$$$) 1448{ 1449 my ($self, $struct, $ndr, $varname, $env) = @_; 1450 if (defined($struct->{PROPERTIES}{relative_base})) { 1451 # retrieve the current offset as base for relative pointers 1452 # based on the toplevel struct/union 1453 $self->pidl("NDR_CHECK(ndr_push_setup_relative_base_offset2($ndr, $varname));"); 1454 } 1455 $self->ParseElementPush($_, $ndr, $env, 0, 1) foreach (@{$struct->{ELEMENTS}}); 1456} 1457 1458##################################################################### 1459# parse a struct 1460sub ParseStructPush($$$$) 1461{ 1462 my ($self, $struct, $ndr, $varname) = @_; 1463 1464 return unless defined($struct->{ELEMENTS}); 1465 1466 my $env = GenerateStructEnv($struct, $varname); 1467 1468 EnvSubstituteValue($env, $struct); 1469 1470 $self->DeclareArrayVariablesNoZero($_, $env) foreach (@{$struct->{ELEMENTS}}); 1471 1472 $self->start_flags($struct, $ndr); 1473 1474 $self->pidl("NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);"); 1475 $self->pidl("if (ndr_flags & NDR_SCALARS) {"); 1476 $self->indent; 1477 $self->ParseStructPushPrimitives($struct, $ndr, $varname, $env); 1478 $self->deindent; 1479 $self->pidl("}"); 1480 1481 $self->pidl("if (ndr_flags & NDR_BUFFERS) {"); 1482 $self->indent; 1483 $self->ParseStructPushDeferred($struct, $ndr, $varname, $env); 1484 $self->deindent; 1485 $self->pidl("}"); 1486 1487 $self->end_flags($struct, $ndr); 1488} 1489 1490##################################################################### 1491# generate a push function for an enum 1492sub ParseEnumPush($$$$) 1493{ 1494 my($self,$enum,$ndr,$varname) = @_; 1495 my($type_fn) = $enum->{BASE_TYPE}; 1496 1497 $self->start_flags($enum, $ndr); 1498 $self->pidl("NDR_CHECK(ndr_push_enum_$type_fn($ndr, NDR_SCALARS, $varname));"); 1499 $self->end_flags($enum, $ndr); 1500} 1501 1502##################################################################### 1503# generate a pull function for an enum 1504sub ParseEnumPull($$$$) 1505{ 1506 my($self,$enum,$ndr,$varname) = @_; 1507 my($type_fn) = $enum->{BASE_TYPE}; 1508 my($type_v_decl) = mapTypeName($type_fn); 1509 1510 $self->pidl("$type_v_decl v;"); 1511 $self->start_flags($enum, $ndr); 1512 $self->pidl("NDR_CHECK(ndr_pull_enum_$type_fn($ndr, NDR_SCALARS, &v));"); 1513 $self->pidl("*$varname = v;"); 1514 1515 $self->end_flags($enum, $ndr); 1516} 1517 1518##################################################################### 1519# generate a print function for an enum 1520sub ParseEnumPrint($$$$$) 1521{ 1522 my($self,$enum,$ndr,$name,$varname) = @_; 1523 1524 $self->pidl("const char *val = NULL;"); 1525 $self->pidl(""); 1526 1527 $self->start_flags($enum, $ndr); 1528 1529 $self->pidl("switch ($varname) {"); 1530 $self->indent; 1531 my $els = \@{$enum->{ELEMENTS}}; 1532 foreach my $i (0 .. $#{$els}) { 1533 my $e = ${$els}[$i]; 1534 chomp $e; 1535 if ($e =~ /^(.*)=/) { 1536 $e = $1; 1537 } 1538 $self->pidl("case $e: val = \"$e\"; break;"); 1539 } 1540 1541 $self->deindent; 1542 $self->pidl("}"); 1543 1544 $self->pidl("ndr_print_enum($ndr, name, \"$enum->{TYPE}\", val, $varname);"); 1545 1546 $self->end_flags($enum, $ndr); 1547} 1548 1549sub DeclEnum($$$$) 1550{ 1551 my ($e,$t,$name,$varname) = @_; 1552 return "enum $name " . 1553 ($t eq "pull"?"*":"") . $varname; 1554} 1555 1556$typefamily{ENUM} = { 1557 DECL => \&DeclEnum, 1558 PUSH_FN_BODY => \&ParseEnumPush, 1559 PULL_FN_BODY => \&ParseEnumPull, 1560 PRINT_FN_BODY => \&ParseEnumPrint, 1561}; 1562 1563##################################################################### 1564# generate a push function for a bitmap 1565sub ParseBitmapPush($$$$) 1566{ 1567 my($self,$bitmap,$ndr,$varname) = @_; 1568 my($type_fn) = $bitmap->{BASE_TYPE}; 1569 1570 $self->start_flags($bitmap, $ndr); 1571 1572 $self->pidl("NDR_CHECK(ndr_push_$type_fn($ndr, NDR_SCALARS, $varname));"); 1573 1574 $self->end_flags($bitmap, $ndr); 1575} 1576 1577##################################################################### 1578# generate a pull function for an bitmap 1579sub ParseBitmapPull($$$$) 1580{ 1581 my($self,$bitmap,$ndr,$varname) = @_; 1582 my $type_fn = $bitmap->{BASE_TYPE}; 1583 my($type_decl) = mapTypeName($bitmap->{BASE_TYPE}); 1584 1585 $self->pidl("$type_decl v;"); 1586 $self->start_flags($bitmap, $ndr); 1587 $self->pidl("NDR_CHECK(ndr_pull_$type_fn($ndr, NDR_SCALARS, &v));"); 1588 $self->pidl("*$varname = v;"); 1589 1590 $self->end_flags($bitmap, $ndr); 1591} 1592 1593##################################################################### 1594# generate a print function for an bitmap 1595sub ParseBitmapPrintElement($$$$$$) 1596{ 1597 my($self,$e,$bitmap,$ndr,$name,$varname) = @_; 1598 my($type_decl) = mapTypeName($bitmap->{BASE_TYPE}); 1599 my($type_fn) = $bitmap->{BASE_TYPE}; 1600 my($flag); 1601 1602 if ($e =~ /^(\w+) .*$/) { 1603 $flag = "$1"; 1604 } else { 1605 die "Bitmap: \"$name\" invalid Flag: \"$e\""; 1606 } 1607 1608 $self->pidl("ndr_print_bitmap_flag($ndr, sizeof($type_decl), \"$flag\", $flag, $varname);"); 1609} 1610 1611##################################################################### 1612# generate a print function for an bitmap 1613sub ParseBitmapPrint($$$$$) 1614{ 1615 my($self,$bitmap,$ndr,$name,$varname) = @_; 1616 my($type_decl) = mapTypeName($bitmap->{TYPE}); 1617 my($type_fn) = $bitmap->{BASE_TYPE}; 1618 1619 $self->start_flags($bitmap, $ndr); 1620 1621 $self->pidl("ndr_print_$type_fn($ndr, name, $varname);"); 1622 1623 $self->pidl("$ndr->depth++;"); 1624 foreach my $e (@{$bitmap->{ELEMENTS}}) { 1625 $self->ParseBitmapPrintElement($e, $bitmap, $ndr, $name, $varname); 1626 } 1627 $self->pidl("$ndr->depth--;"); 1628 1629 $self->end_flags($bitmap, $ndr); 1630} 1631 1632sub DeclBitmap($$$$) 1633{ 1634 my ($e,$t,$name,$varname) = @_; 1635 return mapTypeName(Parse::Pidl::Typelist::bitmap_type_fn($e)) . 1636 ($t eq "pull"?" *":" ") . $varname; 1637} 1638 1639$typefamily{BITMAP} = { 1640 DECL => \&DeclBitmap, 1641 PUSH_FN_BODY => \&ParseBitmapPush, 1642 PULL_FN_BODY => \&ParseBitmapPull, 1643 PRINT_FN_BODY => \&ParseBitmapPrint, 1644}; 1645 1646##################################################################### 1647# generate a struct print function 1648sub ParseStructPrint($$$$$) 1649{ 1650 my($self,$struct,$ndr,$name,$varname) = @_; 1651 1652 return unless defined $struct->{ELEMENTS}; 1653 1654 my $env = GenerateStructEnv($struct, $varname); 1655 1656 $self->DeclareArrayVariables($_) foreach (@{$struct->{ELEMENTS}}); 1657 1658 $self->pidl("ndr_print_struct($ndr, name, \"$name\");"); 1659 $self->pidl("if (r == NULL) { ndr_print_null($ndr); return; }"); 1660 1661 $self->start_flags($struct, $ndr); 1662 1663 $self->pidl("$ndr->depth++;"); 1664 1665 $self->ParseElementPrint($_, $ndr, $env->{$_->{NAME}}, $env) 1666 foreach (@{$struct->{ELEMENTS}}); 1667 $self->pidl("$ndr->depth--;"); 1668 1669 $self->end_flags($struct, $ndr); 1670} 1671 1672sub DeclarePtrVariables($$) 1673{ 1674 my ($self,$e) = @_; 1675 1676 if (has_property($e, "skip") or has_property($e, "skip_noinit")) { 1677 return; 1678 } 1679 1680 foreach my $l (@{$e->{LEVELS}}) { 1681 my $size = 32; 1682 if ($l->{TYPE} eq "POINTER" and 1683 not ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "TOP")) { 1684 if ($l->{POINTER_TYPE} eq "relative_short") { 1685 $size = 16; 1686 } 1687 $self->pidl("uint${size}_t _ptr_$e->{NAME};"); 1688 last; 1689 } 1690 } 1691} 1692 1693sub DeclareArrayVariables($$;$) 1694{ 1695 my ($self,$e,$pull) = @_; 1696 1697 if (has_property($e, "skip") or has_property($e, "skip_noinit")) { 1698 return; 1699 } 1700 1701 foreach my $l (@{$e->{LEVELS}}) { 1702 next if ($l->{TYPE} ne "ARRAY"); 1703 if (defined($pull)) { 1704 $self->pidl("uint32_t size_$e->{NAME}_$l->{LEVEL_INDEX} = 0;"); 1705 if ($l->{IS_VARYING}) { 1706 $self->pidl("uint32_t length_$e->{NAME}_$l->{LEVEL_INDEX} = 0;"); 1707 } 1708 } 1709 next if has_fast_array($e,$l); 1710 next if is_charset_array($e,$l); 1711 $self->pidl("uint32_t cntr_$e->{NAME}_$l->{LEVEL_INDEX};"); 1712 } 1713} 1714 1715sub DeclareArrayVariablesNoZero($$$) 1716{ 1717 my ($self,$e,$env) = @_; 1718 1719 if (has_property($e, "skip") or has_property($e, "skip_noinit")) { 1720 return; 1721 } 1722 1723 foreach my $l (@{$e->{LEVELS}}) { 1724 next if ($l->{TYPE} ne "ARRAY"); 1725 next if has_fast_array($e,$l); 1726 next if is_charset_array($e,$l); 1727 my $length = ParseExpr($l->{LENGTH_IS}, $env, $e->{ORIGINAL}); 1728 if ($length eq "0") { 1729 warning($e->{ORIGINAL}, "pointless array cntr: 'cntr_$e->{NAME}_$l->{LEVEL_INDEX}': length=$length"); 1730 } else { 1731 $self->pidl("uint32_t cntr_$e->{NAME}_$l->{LEVEL_INDEX};"); 1732 } 1733 } 1734} 1735 1736sub DeclareMemCtxVariables($$) 1737{ 1738 my ($self,$e) = @_; 1739 1740 if (has_property($e, "skip") or has_property($e, "skip_noinit")) { 1741 return; 1742 } 1743 1744 foreach my $l (@{$e->{LEVELS}}) { 1745 my $mem_flags = $self->ParseMemCtxPullFlags($e, $l); 1746 1747 if (($l->{TYPE} eq "POINTER") and ($l->{POINTER_TYPE} eq "ignore")) { 1748 last; 1749 } 1750 1751 if (defined($mem_flags)) { 1752 $self->pidl("TALLOC_CTX *_mem_save_$e->{NAME}_$l->{LEVEL_INDEX} = NULL;"); 1753 } 1754 } 1755} 1756 1757sub ParseStructPullPrimitives($$$$$) 1758{ 1759 my($self,$struct,$ndr,$varname,$env) = @_; 1760 1761 if (defined $struct->{SURROUNDING_ELEMENT}) { 1762 $self->pidl("NDR_CHECK(ndr_pull_array_size($ndr, &$varname->$struct->{SURROUNDING_ELEMENT}->{NAME}));"); 1763 } 1764 1765 $self->pidl("NDR_CHECK(ndr_pull_align($ndr, $struct->{ALIGN}));"); 1766 1767 if (defined($struct->{PROPERTIES}{relative_base})) { 1768 # set the current offset as base for relative pointers 1769 # and store it based on the toplevel struct/union 1770 $self->pidl("NDR_CHECK(ndr_pull_setup_relative_base_offset1($ndr, $varname, $ndr->offset));"); 1771 } 1772 1773 $self->ParseElementPull($_, $ndr, $env, 1, 0) foreach (@{$struct->{ELEMENTS}}); 1774 1775 $self->add_deferred(); 1776 1777 $self->pidl("NDR_CHECK(ndr_pull_trailer_align($ndr, $struct->{ALIGN}));"); 1778} 1779 1780sub ParseStructPullDeferred($$$$$) 1781{ 1782 my ($self,$struct,$ndr,$varname,$env) = @_; 1783 1784 if (defined($struct->{PROPERTIES}{relative_base})) { 1785 # retrieve the current offset as base for relative pointers 1786 # based on the toplevel struct/union 1787 $self->pidl("NDR_CHECK(ndr_pull_setup_relative_base_offset2($ndr, $varname));"); 1788 } 1789 foreach my $e (@{$struct->{ELEMENTS}}) { 1790 $self->ParseElementPull($e, $ndr, $env, 0, 1); 1791 } 1792 1793 $self->add_deferred(); 1794} 1795 1796##################################################################### 1797# parse a struct - pull side 1798sub ParseStructPull($$$$) 1799{ 1800 my($self,$struct,$ndr,$varname) = @_; 1801 1802 return unless defined $struct->{ELEMENTS}; 1803 1804 # declare any internal pointers we need 1805 foreach my $e (@{$struct->{ELEMENTS}}) { 1806 $self->DeclarePtrVariables($e); 1807 $self->DeclareArrayVariables($e, "pull"); 1808 $self->DeclareMemCtxVariables($e); 1809 } 1810 1811 $self->start_flags($struct, $ndr); 1812 1813 my $env = GenerateStructEnv($struct, $varname); 1814 1815 $self->pidl("NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);"); 1816 $self->pidl("if (ndr_flags & NDR_SCALARS) {"); 1817 $self->indent; 1818 $self->ParseStructPullPrimitives($struct,$ndr,$varname,$env); 1819 $self->deindent; 1820 $self->pidl("}"); 1821 $self->pidl("if (ndr_flags & NDR_BUFFERS) {"); 1822 $self->indent; 1823 $self->ParseStructPullDeferred($struct,$ndr,$varname,$env); 1824 $self->deindent; 1825 $self->pidl("}"); 1826 1827 $self->end_flags($struct, $ndr); 1828} 1829 1830##################################################################### 1831# calculate size of ndr struct 1832sub ParseStructNdrSize($$$$) 1833{ 1834 my ($self,$t, $name, $varname) = @_; 1835 my $sizevar; 1836 1837 if (my $flags = has_property($t, "flag")) { 1838 $self->pidl("flags |= $flags;"); 1839 } 1840 $self->pidl("return ndr_size_struct($varname, flags, (ndr_push_flags_fn_t)ndr_push_$name);"); 1841} 1842 1843sub DeclStruct($$$$) 1844{ 1845 my ($e,$t,$name,$varname) = @_; 1846 if ($t eq "base") { 1847 return "struct $name $varname"; 1848 } 1849 return ($t ne "pull"?"const ":"") . "struct $name *$varname"; 1850} 1851 1852sub ArgsStructNdrSize($$$) 1853{ 1854 my ($d, $name, $varname) = @_; 1855 return "const struct $name *$varname, int flags"; 1856} 1857 1858$typefamily{STRUCT} = { 1859 PUSH_FN_BODY => \&ParseStructPush, 1860 DECL => \&DeclStruct, 1861 PULL_FN_BODY => \&ParseStructPull, 1862 PRINT_FN_BODY => \&ParseStructPrint, 1863 SIZE_FN_BODY => \&ParseStructNdrSize, 1864 SIZE_FN_ARGS => \&ArgsStructNdrSize, 1865}; 1866 1867##################################################################### 1868# calculate size of ndr struct 1869sub ParseUnionNdrSize($$$) 1870{ 1871 my ($self, $t, $name, $varname) = @_; 1872 my $sizevar; 1873 1874 if (my $flags = has_property($t, "flag")) { 1875 $self->pidl("flags |= $flags;"); 1876 } 1877 1878 $self->pidl("return ndr_size_union($varname, flags, level, (ndr_push_flags_fn_t)ndr_push_$name);"); 1879} 1880 1881sub ParseUnionPushPrimitives($$$$) 1882{ 1883 my ($self, $e, $ndr ,$varname) = @_; 1884 1885 my $have_default = 0; 1886 1887 if (defined($e->{SWITCH_TYPE})) { 1888 if (defined($e->{ALIGN})) { 1889 $self->pidl("NDR_CHECK(ndr_push_union_align($ndr, $e->{ALIGN}));"); 1890 } 1891 1892 $self->pidl("NDR_CHECK(ndr_push_$e->{SWITCH_TYPE}($ndr, NDR_SCALARS, level));"); 1893 } 1894 1895 if (defined($e->{ALIGN})) { 1896 if ($e->{IS_MS_UNION}) { 1897 $self->pidl("/* ms_union is always aligned to the largest union arm*/"); 1898 $self->pidl("NDR_CHECK(ndr_push_align($ndr, $e->{ALIGN}));"); 1899 } else { 1900 $self->pidl("NDR_CHECK(ndr_push_union_align($ndr, $e->{ALIGN}));"); 1901 } 1902 } 1903 1904 $self->pidl("switch (level) {"); 1905 $self->indent; 1906 foreach my $el (@{$e->{ELEMENTS}}) { 1907 if ($el->{CASE} eq "default") { 1908 $have_default = 1; 1909 } 1910 $self->pidl("$el->{CASE}: {"); 1911 1912 if ($el->{TYPE} ne "EMPTY") { 1913 $self->indent; 1914 if (defined($e->{PROPERTIES}{relative_base})) { 1915 $self->pidl("NDR_CHECK(ndr_push_align($ndr, $el->{ALIGN}));"); 1916 # set the current offset as base for relative pointers 1917 # and store it based on the toplevel struct/union 1918 $self->pidl("NDR_CHECK(ndr_push_setup_relative_base_offset1($ndr, $varname, $ndr->offset));"); 1919 } 1920 $self->DeclareArrayVariables($el); 1921 my $el_env = {$el->{NAME} => "$varname->$el->{NAME}"}; 1922 $self->CheckRefPtrs($el, $ndr, $el_env); 1923 $self->ParseElementPush($el, $ndr, $el_env, 1, 0); 1924 $self->deindent; 1925 } 1926 $self->pidl("break; }"); 1927 $self->pidl(""); 1928 } 1929 if (! $have_default) { 1930 $self->pidl("default:"); 1931 $self->pidl("\treturn ndr_push_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);"); 1932 } 1933 $self->deindent; 1934 $self->pidl("}"); 1935} 1936 1937sub ParseUnionPushDeferred($$$$) 1938{ 1939 my ($self,$e,$ndr,$varname) = @_; 1940 1941 my $have_default = 0; 1942 1943 if (defined($e->{PROPERTIES}{relative_base})) { 1944 # retrieve the current offset as base for relative pointers 1945 # based on the toplevel struct/union 1946 $self->pidl("NDR_CHECK(ndr_push_setup_relative_base_offset2($ndr, $varname));"); 1947 } 1948 $self->pidl("switch (level) {"); 1949 $self->indent; 1950 foreach my $el (@{$e->{ELEMENTS}}) { 1951 if ($el->{CASE} eq "default") { 1952 $have_default = 1; 1953 } 1954 1955 $self->pidl("$el->{CASE}:"); 1956 if ($el->{TYPE} ne "EMPTY") { 1957 $self->indent; 1958 $self->ParseElementPush($el, $ndr, {$el->{NAME} => "$varname->$el->{NAME}"}, 0, 1); 1959 $self->deindent; 1960 } 1961 $self->pidl("break;"); 1962 $self->pidl(""); 1963 } 1964 if (! $have_default) { 1965 $self->pidl("default:"); 1966 $self->pidl("\treturn ndr_push_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);"); 1967 } 1968 $self->deindent; 1969 $self->pidl("}"); 1970} 1971 1972##################################################################### 1973# parse a union - push side 1974sub ParseUnionPush($$$$) 1975{ 1976 my ($self,$e,$ndr,$varname) = @_; 1977 my $have_default = 0; 1978 1979 $self->pidl("uint32_t level;"); 1980 $self->start_flags($e, $ndr); 1981 1982 $self->pidl("NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);"); 1983 $self->pidl("if (ndr_flags & NDR_SCALARS) {"); 1984 $self->indent; 1985 $self->pidl("/* This token is not used again (except perhaps below in the NDR_BUFFERS case) */"); 1986 $self->pidl("NDR_CHECK(ndr_push_steal_switch_value($ndr, $varname, &level));"); 1987 1988 $self->ParseUnionPushPrimitives($e, $ndr, $varname); 1989 $self->deindent; 1990 $self->pidl("}"); 1991 if (is_deferred_switch_non_empty($e)) { 1992 $self->pidl("if (ndr_flags & NDR_BUFFERS) {"); 1993 $self->indent; 1994 # In case we had ndr_flags of NDR_SCALERS|NDR_BUFFERS 1995 $self->pidl("if (!(ndr_flags & NDR_SCALARS)) {"); 1996 $self->indent; 1997 $self->pidl("/* We didn't get it above, and the token is not needed after this. */"); 1998 $self->pidl("NDR_CHECK(ndr_push_steal_switch_value($ndr, $varname, &level));"); 1999 $self->deindent; 2000 $self->pidl("}"); 2001 $self->ParseUnionPushDeferred($e, $ndr, $varname); 2002 $self->deindent; 2003 $self->pidl("}"); 2004 } 2005 $self->end_flags($e, $ndr); 2006} 2007 2008##################################################################### 2009# print a union 2010sub ParseUnionPrint($$$$$) 2011{ 2012 my ($self,$e,$ndr,$name,$varname) = @_; 2013 my $have_default = 0; 2014 2015 $self->pidl("uint32_t level;"); 2016 foreach my $el (@{$e->{ELEMENTS}}) { 2017 $self->DeclareArrayVariables($el); 2018 } 2019 2020 $self->start_flags($e, $ndr); 2021 2022 $self->pidl("level = ndr_print_steal_switch_value($ndr, $varname);"); 2023 2024 $self->pidl("ndr_print_union($ndr, name, level, \"$name\");"); 2025 2026 $self->pidl("switch (level) {"); 2027 $self->indent; 2028 foreach my $el (@{$e->{ELEMENTS}}) { 2029 if ($el->{CASE} eq "default") { 2030 $have_default = 1; 2031 } 2032 $self->pidl("$el->{CASE}:"); 2033 if ($el->{TYPE} ne "EMPTY") { 2034 $self->indent; 2035 $self->ParseElementPrint($el, $ndr, "$varname->$el->{NAME}", {}); 2036 $self->deindent; 2037 } 2038 $self->pidl("break;"); 2039 $self->pidl(""); 2040 } 2041 if (! $have_default) { 2042 $self->pidl("default:"); 2043 $self->pidl("\tndr_print_bad_level($ndr, name, level);"); 2044 } 2045 $self->deindent; 2046 $self->pidl("}"); 2047 2048 $self->end_flags($e, $ndr); 2049} 2050 2051sub ParseUnionPullPrimitives($$$$$) 2052{ 2053 my ($self,$e,$ndr,$varname,$switch_type) = @_; 2054 my $have_default = 0; 2055 2056 2057 if (defined($switch_type)) { 2058 if (defined($e->{ALIGN})) { 2059 $self->pidl("NDR_CHECK(ndr_pull_union_align($ndr, $e->{ALIGN}));"); 2060 } 2061 2062 $self->pidl("NDR_CHECK(ndr_pull_$switch_type($ndr, NDR_SCALARS, &_level));"); 2063 $self->pidl("if (_level != level) {"); 2064 $self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value %u for $varname at \%s\", _level, __location__);"); 2065 $self->pidl("}"); 2066 } 2067 2068 if (defined($e->{ALIGN})) { 2069 if ($e->{IS_MS_UNION}) { 2070 $self->pidl("/* ms_union is always aligned to the largest union arm*/"); 2071 $self->pidl("NDR_CHECK(ndr_pull_align($ndr, $e->{ALIGN}));"); 2072 } else { 2073 $self->pidl("NDR_CHECK(ndr_pull_union_align($ndr, $e->{ALIGN}));"); 2074 } 2075 } 2076 2077 $self->pidl("switch (level) {"); 2078 $self->indent; 2079 foreach my $el (@{$e->{ELEMENTS}}) { 2080 if ($el->{CASE} eq "default") { 2081 $have_default = 1; 2082 } 2083 $self->pidl("$el->{CASE}: {"); 2084 2085 if ($el->{TYPE} ne "EMPTY") { 2086 $self->indent; 2087 if (defined($e->{PROPERTIES}{relative_base})) { 2088 $self->pidl("NDR_CHECK(ndr_pull_align($ndr, $el->{ALIGN}));"); 2089 # set the current offset as base for relative pointers 2090 # and store it based on the toplevel struct/union 2091 $self->pidl("NDR_CHECK(ndr_pull_setup_relative_base_offset1($ndr, $varname, $ndr->offset));"); 2092 } 2093 $self->ParseElementPull($el, $ndr, {$el->{NAME} => "$varname->$el->{NAME}"}, 1, 0); 2094 $self->deindent; 2095 } 2096 $self->pidl("break; }"); 2097 $self->pidl(""); 2098 } 2099 if (! $have_default) { 2100 $self->pidl("default:"); 2101 $self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u at \%s\", level, __location__);"); 2102 } 2103 $self->deindent; 2104 $self->pidl("}"); 2105} 2106 2107sub ParseUnionPullDeferred($$$$) 2108{ 2109 my ($self,$e,$ndr,$varname) = @_; 2110 my $have_default = 0; 2111 2112 $self->pidl("switch (level) {"); 2113 $self->indent; 2114 foreach my $el (@{$e->{ELEMENTS}}) { 2115 if ($el->{CASE} eq "default") { 2116 $have_default = 1; 2117 } 2118 2119 $self->pidl("$el->{CASE}:"); 2120 if ($el->{TYPE} ne "EMPTY") { 2121 $self->indent; 2122 if (defined($e->{PROPERTIES}{relative_base})) { 2123 # retrieve the current offset as base for relative pointers 2124 # based on the toplevel struct/union 2125 $self->pidl("NDR_CHECK(ndr_pull_setup_relative_base_offset2($ndr, $varname));"); 2126 } 2127 $self->ParseElementPull($el, $ndr, {$el->{NAME} => "$varname->$el->{NAME}"}, 0, 1); 2128 $self->deindent; 2129 } 2130 $self->pidl("break;"); 2131 $self->pidl(""); 2132 } 2133 if (! $have_default) { 2134 $self->pidl("default:"); 2135 $self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u at \%s\", level, __location__);"); 2136 } 2137 $self->deindent; 2138 $self->pidl("}"); 2139 2140 2141} 2142 2143##################################################################### 2144# parse a union - pull side 2145sub ParseUnionPull($$$$) 2146{ 2147 my ($self,$e,$ndr,$varname) = @_; 2148 my $switch_type = $e->{SWITCH_TYPE}; 2149 my $needs_deferred_switch = is_deferred_switch_non_empty($e); 2150 $self->pidl("uint32_t level;"); 2151 if (defined($switch_type)) { 2152 if (Parse::Pidl::Typelist::typeIs($switch_type, "ENUM")) { 2153 $switch_type = Parse::Pidl::Typelist::enum_type_fn(getType($switch_type)->{DATA}); 2154 } 2155 $self->pidl(mapTypeName($switch_type) . " _level;"); 2156 } 2157 2158 my %double_cases = (); 2159 foreach my $el (@{$e->{ELEMENTS}}) { 2160 next if ($el->{TYPE} eq "EMPTY"); 2161 next if ($double_cases{"$el->{NAME}"}); 2162 $self->DeclareMemCtxVariables($el); 2163 $self->DeclarePtrVariables($el); 2164 $self->DeclareArrayVariables($el, "pull"); 2165 $double_cases{"$el->{NAME}"} = 1; 2166 } 2167 2168 $self->start_flags($e, $ndr); 2169 2170 $self->pidl("NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);"); 2171 $self->pidl("if (ndr_flags & NDR_SCALARS) {"); 2172 $self->indent; 2173 $self->pidl("/* This token is not used again (except perhaps below in the NDR_BUFFERS case) */"); 2174 $self->pidl("NDR_CHECK(ndr_pull_steal_switch_value($ndr, $varname, &level));"); 2175 $self->ParseUnionPullPrimitives($e,$ndr,$varname,$switch_type); 2176 $self->deindent; 2177 $self->pidl("}"); 2178 if ($needs_deferred_switch) { 2179 $self->pidl("if (ndr_flags & NDR_BUFFERS) {"); 2180 $self->indent; 2181 # In case we had ndr_flags of NDR_SCALERS|NDR_BUFFERS 2182 $self->pidl("if (!(ndr_flags & NDR_SCALARS)) {"); 2183 $self->indent; 2184 $self->pidl("/* We didn't get it above, and the token is not needed after this. */"); 2185 $self->pidl("NDR_CHECK(ndr_pull_steal_switch_value($ndr, $varname, &level));"); 2186 $self->deindent; 2187 $self->pidl("}"); 2188 $self->ParseUnionPullDeferred($e,$ndr,$varname); 2189 $self->deindent; 2190 $self->pidl("}"); 2191 } 2192 $self->add_deferred(); 2193 2194 $self->end_flags($e, $ndr); 2195} 2196 2197sub DeclUnion($$$$) 2198{ 2199 my ($e,$t,$name,$varname) = @_; 2200 if ($t eq "base") { 2201 return "union $name $varname"; 2202 } 2203 return ($t ne "pull"?"const ":"") . "union $name *$varname"; 2204} 2205 2206sub ArgsUnionNdrSize($$) 2207{ 2208 my ($d,$name) = @_; 2209 return "const union $name *r, uint32_t level, int flags"; 2210} 2211 2212$typefamily{UNION} = { 2213 PUSH_FN_BODY => \&ParseUnionPush, 2214 DECL => \&DeclUnion, 2215 PULL_FN_BODY => \&ParseUnionPull, 2216 PRINT_FN_BODY => \&ParseUnionPrint, 2217 SIZE_FN_ARGS => \&ArgsUnionNdrSize, 2218 SIZE_FN_BODY => \&ParseUnionNdrSize, 2219}; 2220 2221##################################################################### 2222# parse a typedef - push side 2223sub ParseTypedefPush($$$$) 2224{ 2225 my($self,$e,$ndr,$varname) = @_; 2226 2227 my $env; 2228 2229 $env->{$e->{NAME}} = $varname; 2230 2231 $self->ParseElementPushLevel($e, $e->{LEVELS}[0], $ndr, $varname, $env, 1, 1); 2232} 2233 2234##################################################################### 2235# parse a typedef - pull side 2236sub ParseTypedefPull($$$$) 2237{ 2238 my($self,$e,$ndr,$varname) = @_; 2239 2240 my $env; 2241 2242 $env->{$e->{NAME}} = $varname; 2243 2244 $self->ParseElementPullLevel($e, $e->{LEVELS}[0], $ndr, $varname, $env, 1, 1); 2245} 2246 2247##################################################################### 2248# parse a typedef - print side 2249sub ParseTypedefPrint($$$$$) 2250{ 2251 my($self,$e,$ndr,$name,$varname) = @_; 2252 2253 $typefamily{$e->{DATA}->{TYPE}}->{PRINT_FN_BODY}->($self, $e->{DATA}, $ndr, $name, $varname); 2254} 2255 2256##################################################################### 2257## calculate the size of a structure 2258sub ParseTypedefNdrSize($$$$) 2259{ 2260 my($self,$t,$name,$varname) = @_; 2261 2262 $typefamily{$t->{DATA}->{TYPE}}->{SIZE_FN_BODY}->($self, $t->{DATA}, $name, $varname); 2263} 2264 2265sub DeclTypedef($$$$) 2266{ 2267 my ($e, $t, $name, $varname) = @_; 2268 2269 return $typefamily{$e->{DATA}->{TYPE}}->{DECL}->($e->{DATA}, $t, $name, $varname); 2270} 2271 2272sub ArgsTypedefNdrSize($$$) 2273{ 2274 my ($d, $name, $varname) = @_; 2275 return $typefamily{$d->{DATA}->{TYPE}}->{SIZE_FN_ARGS}->($d->{DATA}, $name, $varname); 2276} 2277 2278$typefamily{TYPEDEF} = { 2279 PUSH_FN_BODY => \&ParseTypedefPush, 2280 DECL => \&DeclTypedef, 2281 PULL_FN_BODY => \&ParseTypedefPull, 2282 PRINT_FN_BODY => \&ParseTypedefPrint, 2283 SIZE_FN_ARGS => \&ArgsTypedefNdrSize, 2284 SIZE_FN_BODY => \&ParseTypedefNdrSize, 2285}; 2286 2287sub ParsePipePushChunk($$) 2288{ 2289 my ($self, $t) = @_; 2290 2291 my $pipe = $t; 2292 $pipe = $t->{DATA} if ($t->{TYPE} eq "TYPEDEF"); 2293 my $struct = $pipe->{DATA}; 2294 2295 my $name = "$struct->{NAME}"; 2296 my $ndr = "ndr"; 2297 my $varname = "r"; 2298 2299 my $args = $typefamily{$struct->{TYPE}}->{DECL}->($struct, "push", $name, $varname); 2300 2301 $self->fn_declare("push", $struct, "enum ndr_err_code ndr_push_$name(struct ndr_push *$ndr, int ndr_flags, $args)") or return; 2302 2303 return if has_property($t, "nopush"); 2304 2305 $self->pidl("{"); 2306 $self->indent; 2307 2308 $self->ParseStructPush($struct, $ndr, $varname); 2309 $self->pidl(""); 2310 2311 $self->pidl("NDR_CHECK(ndr_push_pipe_chunk_trailer(ndr, ndr_flags, $varname->count));"); 2312 $self->pidl(""); 2313 2314 $self->pidl("return NDR_ERR_SUCCESS;"); 2315 $self->deindent; 2316 $self->pidl("}"); 2317 $self->pidl(""); 2318} 2319 2320sub ParsePipePullChunk($$) 2321{ 2322 my ($self, $t) = @_; 2323 2324 my $pipe = $t; 2325 $pipe = $t->{DATA} if ($t->{TYPE} eq "TYPEDEF"); 2326 my $struct = $pipe->{DATA}; 2327 2328 my $name = "$struct->{NAME}"; 2329 my $ndr = "ndr"; 2330 my $varname = "r"; 2331 2332 my $args = $typefamily{$struct->{TYPE}}->{DECL}->($struct, "pull", $name, $varname); 2333 2334 $self->fn_declare("pull", $struct, "enum ndr_err_code ndr_pull_$name(struct ndr_pull *$ndr, int ndr_flags, $args)") or return; 2335 2336 return if has_property($struct, "nopull"); 2337 2338 $self->pidl("{"); 2339 $self->indent; 2340 2341 $self->ParseStructPull($struct, $ndr, $varname); 2342 $self->pidl(""); 2343 2344 $self->pidl("NDR_CHECK(ndr_check_pipe_chunk_trailer($ndr, ndr_flags, $varname->count));"); 2345 $self->pidl(""); 2346 2347 $self->pidl("return NDR_ERR_SUCCESS;"); 2348 $self->deindent; 2349 $self->pidl("}"); 2350 $self->pidl(""); 2351} 2352 2353sub ParsePipePrintChunk($$) 2354{ 2355 my ($self, $t) = @_; 2356 2357 my $pipe = $t; 2358 $pipe = $t->{DATA} if ($t->{TYPE} eq "TYPEDEF"); 2359 my $struct = $pipe->{DATA}; 2360 2361 my $name = "$struct->{NAME}"; 2362 my $ndr = "ndr"; 2363 my $varname = "r"; 2364 2365 my $args = $typefamily{$struct->{TYPE}}->{DECL}->($struct, "print", $name, $varname); 2366 2367 $self->pidl_hdr("void ndr_print_$name(struct ndr_print *ndr, const char *name, $args);"); 2368 2369 return if (has_property($t, "noprint")); 2370 2371 $self->pidl("_PUBLIC_ void ndr_print_$name(struct ndr_print *$ndr, const char *name, $args)"); 2372 $self->pidl("{"); 2373 $self->indent; 2374 $self->ParseTypePrint($struct, $ndr, $varname); 2375 $self->deindent; 2376 $self->pidl("}"); 2377 $self->pidl(""); 2378} 2379 2380##################################################################### 2381# parse a function - print side 2382sub ParseFunctionPrint($$) 2383{ 2384 my($self, $fn) = @_; 2385 my $ndr = "ndr"; 2386 2387 $self->pidl_hdr("void ndr_print_$fn->{NAME}(struct ndr_print *$ndr, const char *name, int flags, const struct $fn->{NAME} *r);"); 2388 2389 return if has_property($fn, "noprint"); 2390 2391 $self->pidl("_PUBLIC_ void ndr_print_$fn->{NAME}(struct ndr_print *$ndr, const char *name, int flags, const struct $fn->{NAME} *r)"); 2392 $self->pidl("{"); 2393 $self->indent; 2394 2395 foreach my $e (@{$fn->{ELEMENTS}}) { 2396 $self->DeclareArrayVariables($e); 2397 } 2398 2399 $self->pidl("ndr_print_struct($ndr, name, \"$fn->{NAME}\");"); 2400 $self->pidl("if (r == NULL) { ndr_print_null($ndr); return; }"); 2401 $self->pidl("$ndr->depth++;"); 2402 2403 $self->pidl("if (flags & NDR_SET_VALUES) {"); 2404 $self->pidl("\t$ndr->flags |= LIBNDR_PRINT_SET_VALUES;"); 2405 $self->pidl("}"); 2406 2407 $self->pidl("if (flags & NDR_IN) {"); 2408 $self->indent; 2409 $self->pidl("ndr_print_struct($ndr, \"in\", \"$fn->{NAME}\");"); 2410 $self->pidl("$ndr->depth++;"); 2411 2412 my $env = GenerateFunctionInEnv($fn); 2413 2414 foreach my $e (@{$fn->{ELEMENTS}}) { 2415 if (grep(/in/,@{$e->{DIRECTION}})) { 2416 $self->ParseElementPrint($e, $ndr, $env->{$e->{NAME}}, $env); 2417 } 2418 } 2419 $self->pidl("$ndr->depth--;"); 2420 $self->deindent; 2421 $self->pidl("}"); 2422 2423 $self->pidl("if (flags & NDR_OUT) {"); 2424 $self->indent; 2425 $self->pidl("ndr_print_struct($ndr, \"out\", \"$fn->{NAME}\");"); 2426 $self->pidl("$ndr->depth++;"); 2427 2428 $env = GenerateFunctionOutEnv($fn); 2429 foreach my $e (@{$fn->{ELEMENTS}}) { 2430 if (grep(/out/,@{$e->{DIRECTION}})) { 2431 $self->ParseElementPrint($e, $ndr, $env->{$e->{NAME}}, $env); 2432 } 2433 } 2434 if ($fn->{RETURN_TYPE}) { 2435 $self->pidl("ndr_print_$fn->{RETURN_TYPE}($ndr, \"result\", r->out.result);"); 2436 } 2437 $self->pidl("$ndr->depth--;"); 2438 $self->deindent; 2439 $self->pidl("}"); 2440 2441 $self->pidl("$ndr->depth--;"); 2442 $self->deindent; 2443 $self->pidl("}"); 2444 $self->pidl(""); 2445} 2446 2447##################################################################### 2448# parse a function 2449sub ParseFunctionPush($$) 2450{ 2451 my($self, $fn) = @_; 2452 my $ndr = "ndr"; 2453 2454 $self->fn_declare("push", $fn, "enum ndr_err_code ndr_push_$fn->{NAME}(struct ndr_push *$ndr, int flags, const struct $fn->{NAME} *r)") or return; 2455 2456 return if has_property($fn, "nopush"); 2457 2458 $self->pidl("{"); 2459 $self->indent; 2460 2461 foreach my $e (@{$fn->{ELEMENTS}}) { 2462 $self->DeclareArrayVariables($e); 2463 } 2464 2465 $self->pidl("NDR_PUSH_CHECK_FN_FLAGS(ndr, flags);"); 2466 2467 $self->pidl("if (flags & NDR_IN) {"); 2468 $self->indent; 2469 2470 my $env = GenerateFunctionInEnv($fn); 2471 2472 EnvSubstituteValue($env, $fn); 2473 2474 foreach my $e (@{$fn->{ELEMENTS}}) { 2475 if (grep(/in/,@{$e->{DIRECTION}})) { 2476 $self->CheckRefPtrs($e, $ndr, $env); 2477 } 2478 } 2479 2480 foreach my $e (@{$fn->{ELEMENTS}}) { 2481 if (grep(/in/,@{$e->{DIRECTION}})) { 2482 $self->ParseElementPush($e, $ndr, $env, 1, 1); 2483 } 2484 } 2485 2486 $self->deindent; 2487 $self->pidl("}"); 2488 2489 $self->pidl("if (flags & NDR_OUT) {"); 2490 $self->indent; 2491 2492 $env = GenerateFunctionOutEnv($fn); 2493 EnvSubstituteValue($env, $fn); 2494 2495 foreach my $e (@{$fn->{ELEMENTS}}) { 2496 if (grep(/out/,@{$e->{DIRECTION}})) { 2497 $self->CheckRefPtrs($e, $ndr, $env); 2498 } 2499 } 2500 2501 foreach my $e (@{$fn->{ELEMENTS}}) { 2502 if (grep(/out/,@{$e->{DIRECTION}})) { 2503 $self->ParseElementPush($e, $ndr, $env, 1, 1); 2504 } 2505 } 2506 2507 if ($fn->{RETURN_TYPE}) { 2508 $self->pidl("NDR_CHECK(ndr_push_$fn->{RETURN_TYPE}($ndr, NDR_SCALARS, r->out.result));"); 2509 } 2510 2511 $self->deindent; 2512 $self->pidl("}"); 2513 $self->pidl("return NDR_ERR_SUCCESS;"); 2514 $self->deindent; 2515 $self->pidl("}"); 2516 $self->pidl(""); 2517} 2518 2519sub AllocateArrayLevel($$$$$$) 2520{ 2521 my ($self,$e,$l,$ndr,$var,$size) = @_; 2522 2523 my $pl = GetPrevLevel($e, $l); 2524 if (defined($pl) and 2525 $pl->{TYPE} eq "POINTER" and 2526 $pl->{POINTER_TYPE} eq "ref" 2527 and not $l->{IS_ZERO_TERMINATED}) { 2528 $self->pidl("if ($ndr->flags & LIBNDR_FLAG_REF_ALLOC) {"); 2529 $self->pidl("\tNDR_PULL_ALLOC_N($ndr, $var, $size);"); 2530 $self->pidl("}"); 2531 if (grep(/in/,@{$e->{DIRECTION}}) and 2532 grep(/out/,@{$e->{DIRECTION}})) { 2533 $self->pidl("memcpy(r->out.$e->{NAME}, r->in.$e->{NAME}, ($size) * sizeof(*r->in.$e->{NAME}));"); 2534 } 2535 return; 2536 } 2537 2538 $self->pidl("NDR_PULL_ALLOC_N($ndr, $var, $size);"); 2539} 2540 2541##################################################################### 2542# parse a function 2543sub ParseFunctionPull($$) 2544{ 2545 my($self,$fn) = @_; 2546 my $ndr = "ndr"; 2547 2548 # pull function args 2549 $self->fn_declare("pull", $fn, "enum ndr_err_code ndr_pull_$fn->{NAME}(struct ndr_pull *$ndr, int flags, struct $fn->{NAME} *r)") or return; 2550 2551 $self->pidl("{"); 2552 $self->indent; 2553 2554 # declare any internal pointers we need 2555 foreach my $e (@{$fn->{ELEMENTS}}) { 2556 $self->DeclarePtrVariables($e); 2557 $self->DeclareArrayVariables($e, "pull"); 2558 } 2559 2560 my %double_cases = (); 2561 foreach my $e (@{$fn->{ELEMENTS}}) { 2562 next if ($e->{TYPE} eq "EMPTY"); 2563 next if ($double_cases{"$e->{NAME}"}); 2564 $self->DeclareMemCtxVariables($e); 2565 $double_cases{"$e->{NAME}"} = 1; 2566 } 2567 2568 $self->pidl("NDR_PULL_CHECK_FN_FLAGS(ndr, flags);"); 2569 2570 $self->pidl("if (flags & NDR_IN) {"); 2571 $self->indent; 2572 2573 # auto-init the out section of a structure. I originally argued that 2574 # this was a bad idea as it hides bugs, but coping correctly 2575 # with initialisation and not wiping ref vars is turning 2576 # out to be too tricky (tridge) 2577 foreach my $e (@{$fn->{ELEMENTS}}) { 2578 next unless grep(/out/, @{$e->{DIRECTION}}); 2579 $self->pidl("NDR_ZERO_STRUCT(r->out);"); 2580 $self->pidl(""); 2581 last; 2582 } 2583 2584 my $env = GenerateFunctionInEnv($fn); 2585 2586 foreach my $e (@{$fn->{ELEMENTS}}) { 2587 next unless (grep(/in/, @{$e->{DIRECTION}})); 2588 $self->ParseElementPull($e, $ndr, $env, 1, 1); 2589 } 2590 2591 # allocate the "simple" out ref variables. FIXME: Shouldn't this have it's 2592 # own flag rather than be in NDR_IN ? 2593 2594 foreach my $e (@{$fn->{ELEMENTS}}) { 2595 next unless (grep(/out/, @{$e->{DIRECTION}})); 2596 next unless ($e->{LEVELS}[0]->{TYPE} eq "POINTER" and 2597 $e->{LEVELS}[0]->{POINTER_TYPE} eq "ref"); 2598 next if (($e->{LEVELS}[1]->{TYPE} eq "DATA") and 2599 ($e->{LEVELS}[1]->{DATA_TYPE} eq "string")); 2600 next if ($e->{LEVELS}[1]->{TYPE} eq "PIPE"); 2601 next if (($e->{LEVELS}[1]->{TYPE} eq "ARRAY") 2602 and $e->{LEVELS}[1]->{IS_ZERO_TERMINATED}); 2603 2604 if ($e->{LEVELS}[1]->{TYPE} eq "ARRAY") { 2605 my $size = ParseExprExt($e->{LEVELS}[1]->{SIZE_IS}, $env, $e->{ORIGINAL}, 2606 check_null_pointer($e, $env, sub { $self->pidl(shift); }, 2607 "return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for size_is()\");"), 2608 check_fully_dereferenced($e, $env)); 2609 $self->pidl("NDR_PULL_ALLOC_N($ndr, r->out.$e->{NAME}, $size);"); 2610 2611 if (grep(/in/, @{$e->{DIRECTION}})) { 2612 $self->pidl("memcpy(r->out.$e->{NAME}, r->in.$e->{NAME}, ($size) * sizeof(*r->in.$e->{NAME}));"); 2613 } else { 2614 $self->pidl("memset(r->out.$e->{NAME}, 0, ($size) * sizeof(*r->out.$e->{NAME}));"); 2615 } 2616 } elsif ($e->{LEVELS}[1]->{TYPE} eq "ARRAY") { 2617 if (grep(/in/, @{$e->{DIRECTION}})) { 2618 $self->pidl("r->out.$e->{NAME} = r->in.$e->{NAME};"); 2619 } else { 2620 $self->pidl("r->out.$e->{NAME} = NULL;"); 2621 } 2622 } else { 2623 $self->pidl("NDR_PULL_ALLOC($ndr, r->out.$e->{NAME});"); 2624 2625 if (grep(/in/, @{$e->{DIRECTION}})) { 2626 $self->pidl("*r->out.$e->{NAME} = *r->in.$e->{NAME};"); 2627 } else { 2628 $self->pidl("NDR_ZERO_STRUCTP(r->out.$e->{NAME});"); 2629 } 2630 } 2631 } 2632 2633 $self->add_deferred(); 2634 $self->deindent; 2635 $self->pidl("}"); 2636 2637 $self->pidl("if (flags & NDR_OUT) {"); 2638 $self->indent; 2639 2640 $self->pidl("#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION"); 2641 2642 # This for fuzzers of ndr_pull where the out elements refer to 2643 # in elements in size_is or length_is. 2644 # 2645 # Not actually very harmful but also not useful outsie a fuzzer 2646 foreach my $e (@{$fn->{ELEMENTS}}) { 2647 next unless (grep(/in/, @{$e->{DIRECTION}})); 2648 next unless ($e->{LEVELS}[0]->{TYPE} eq "POINTER" and 2649 $e->{LEVELS}[0]->{POINTER_TYPE} eq "ref"); 2650 next if (($e->{LEVELS}[1]->{TYPE} eq "DATA") and 2651 ($e->{LEVELS}[1]->{DATA_TYPE} eq "string")); 2652 next if ($e->{LEVELS}[1]->{TYPE} eq "PIPE"); 2653 next if ($e->{LEVELS}[1]->{TYPE} eq "ARRAY"); 2654 2655 $self->pidl("if (r->in.$e->{NAME} == NULL) {"); 2656 $self->indent; 2657 $self->pidl("NDR_PULL_ALLOC($ndr, r->in.$e->{NAME});"); 2658 $self->pidl("NDR_ZERO_STRUCTP(r->in.$e->{NAME});"); 2659 $self->deindent; 2660 $self->pidl("}"); 2661 } 2662 2663 $self->pidl("#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */"); 2664 2665 $env = GenerateFunctionOutEnv($fn); 2666 foreach my $e (@{$fn->{ELEMENTS}}) { 2667 next unless grep(/out/, @{$e->{DIRECTION}}); 2668 $self->ParseElementPull($e, $ndr, $env, 1, 1); 2669 } 2670 2671 if ($fn->{RETURN_TYPE}) { 2672 $self->pidl("NDR_CHECK(ndr_pull_$fn->{RETURN_TYPE}($ndr, NDR_SCALARS, &r->out.result));"); 2673 } 2674 2675 $self->add_deferred(); 2676 $self->deindent; 2677 $self->pidl("}"); 2678 2679 $self->pidl("return NDR_ERR_SUCCESS;"); 2680 $self->deindent; 2681 $self->pidl("}"); 2682 $self->pidl(""); 2683} 2684 2685sub AuthServiceStruct($$$) 2686{ 2687 my ($self, $ifacename, $authservice) = @_; 2688 my @a = split /,/, $authservice; 2689 my $authservice_count = $#a + 1; 2690 2691 $self->pidl("static const char * const $ifacename\_authservice_strings[] = {"); 2692 foreach my $ap (@a) { 2693 $self->pidl("\t$ap, "); 2694 } 2695 $self->pidl("};"); 2696 $self->pidl(""); 2697 2698 $self->pidl("static const struct ndr_interface_string_array $ifacename\_authservices = {"); 2699 $self->pidl("\t.count\t= $authservice_count,"); 2700 $self->pidl("\t.names\t= $ifacename\_authservice_strings"); 2701 $self->pidl("};"); 2702 $self->pidl(""); 2703} 2704 2705sub ParseGeneratePipeArray($$$) 2706{ 2707 my ($self, $fn, $direction) = @_; 2708 2709 $self->pidl("static const struct ndr_interface_call_pipe $fn->{NAME}\_$direction\_pipes[] = {"); 2710 $self->indent; 2711 2712 foreach my $e (@{$fn->{ELEMENTS}}) { 2713 next unless ContainsPipe($e, $e->{LEVELS}[0]); 2714 next unless (grep(/$direction/, @{$e->{DIRECTION}})); 2715 2716 my $cname = "$e->{TYPE}_chunk"; 2717 2718 $self->pidl("{"); 2719 $self->indent; 2720 $self->pidl("\"$direction.$e->{NAME}\","); 2721 $self->pidl("\"$cname\","); 2722 $self->pidl("sizeof(struct $cname),"); 2723 $self->pidl("(ndr_push_flags_fn_t) ndr_push_$cname,"); 2724 $self->pidl("(ndr_pull_flags_fn_t) ndr_pull_$cname,"); 2725 $self->pidl("(ndr_print_fn_t) ndr_print_$cname,"); 2726 $self->deindent; 2727 $self->pidl("},"); 2728 } 2729 $self->pidl("{ .name = NULL }"); 2730 $self->deindent; 2731 $self->pidl("};"); 2732 $self->pidl(""); 2733} 2734 2735sub FunctionCallPipes($$) 2736{ 2737 my ($self, $d) = @_; 2738 return if not defined($d->{OPNUM}); 2739 2740 my $in_pipes = 0; 2741 my $out_pipes = 0; 2742 2743 foreach my $e (@{$d->{ELEMENTS}}) { 2744 next unless ContainsPipe($e, $e->{LEVELS}[0]); 2745 2746 if (grep(/in/, @{$e->{DIRECTION}})) { 2747 $in_pipes++; 2748 } 2749 if (grep(/out/, @{$e->{DIRECTION}})) { 2750 $out_pipes++; 2751 } 2752 } 2753 2754 if ($in_pipes) { 2755 $self->ParseGeneratePipeArray($d, "in"); 2756 } 2757 2758 if ($out_pipes) { 2759 $self->ParseGeneratePipeArray($d, "out"); 2760 } 2761} 2762 2763sub FunctionCallEntry($$) 2764{ 2765 my ($self, $d) = @_; 2766 return 0 if not defined($d->{OPNUM}); 2767 2768 my $in_pipes = 0; 2769 my $out_pipes = 0; 2770 2771 foreach my $e (@{$d->{ELEMENTS}}) { 2772 next unless ContainsPipe($e, $e->{LEVELS}[0]); 2773 2774 if (grep(/in/, @{$e->{DIRECTION}})) { 2775 $in_pipes++; 2776 } 2777 if (grep(/out/, @{$e->{DIRECTION}})) { 2778 $out_pipes++; 2779 } 2780 } 2781 2782 my $in_pipes_ptr = "NULL"; 2783 my $out_pipes_ptr = "NULL"; 2784 2785 if ($in_pipes) { 2786 $in_pipes_ptr = "$d->{NAME}_in_pipes"; 2787 } 2788 2789 if ($out_pipes) { 2790 $out_pipes_ptr = "$d->{NAME}_out_pipes"; 2791 } 2792 2793 $self->pidl("\t{"); 2794 $self->pidl("\t\t\"$d->{NAME}\","); 2795 $self->pidl("\t\tsizeof(struct $d->{NAME}),"); 2796 $self->pidl("\t\t(ndr_push_flags_fn_t) ndr_push_$d->{NAME},"); 2797 $self->pidl("\t\t(ndr_pull_flags_fn_t) ndr_pull_$d->{NAME},"); 2798 $self->pidl("\t\t(ndr_print_function_t) ndr_print_$d->{NAME},"); 2799 $self->pidl("\t\t{ $in_pipes, $in_pipes_ptr },"); 2800 $self->pidl("\t\t{ $out_pipes, $out_pipes_ptr },"); 2801 $self->pidl("\t},"); 2802 return 1; 2803} 2804 2805sub StructEntry($$) 2806{ 2807 my ($self, $d) = @_; 2808 my $type_decl = $typefamily{$d->{TYPE}}->{DECL}->($d, "base", $d->{NAME}, ""); 2809 2810 $self->pidl("\t{"); 2811 $self->pidl("\t\t.name = \"$d->{NAME}\","); 2812 $self->pidl("\t\t.struct_size = sizeof($type_decl),"); 2813 $self->pidl("\t\t.ndr_push = (ndr_push_flags_fn_t) ndr_push_$d->{NAME},"); 2814 $self->pidl("\t\t.ndr_pull = (ndr_pull_flags_fn_t) ndr_pull_$d->{NAME},"); 2815 $self->pidl("\t\t.ndr_print = (ndr_print_function_t) ndr_print_flags_$d->{NAME},"); 2816 $self->pidl("\t},"); 2817 return 1; 2818} 2819 2820##################################################################### 2821# produce a function call table 2822sub FunctionTable($$) 2823{ 2824 my($self,$interface) = @_; 2825 my $count = 0; 2826 my $count_public_structs = 0; 2827 my $uname = uc $interface->{NAME}; 2828 2829 foreach my $d (@{$interface->{TYPES}}) { 2830 next unless (is_public_struct($d)); 2831 $count_public_structs += 1; 2832 } 2833 return if ($#{$interface->{FUNCTIONS}}+1 == 0 and 2834 $count_public_structs == 0); 2835 2836 foreach my $d (@{$interface->{INHERITED_FUNCTIONS}},@{$interface->{FUNCTIONS}}) { 2837 $self->FunctionCallPipes($d); 2838 } 2839 2840 $self->pidl("static const struct ndr_interface_public_struct $interface->{NAME}\_public_structs[] = {"); 2841 2842 foreach my $d (@{$interface->{TYPES}}) { 2843 next unless (is_public_struct($d)); 2844 $self->StructEntry($d); 2845 } 2846 $self->pidl("\t{ .name = NULL }"); 2847 $self->pidl("};"); 2848 $self->pidl(""); 2849 2850 $self->pidl("static const struct ndr_interface_call $interface->{NAME}\_calls[] = {"); 2851 2852 foreach my $d (@{$interface->{INHERITED_FUNCTIONS}},@{$interface->{FUNCTIONS}}) { 2853 $count += $self->FunctionCallEntry($d); 2854 } 2855 $self->pidl("\t{ .name = NULL }"); 2856 $self->pidl("};"); 2857 $self->pidl(""); 2858 2859 $self->pidl("static const char * const $interface->{NAME}\_endpoint_strings[] = {"); 2860 foreach my $ep (@{$interface->{ENDPOINTS}}) { 2861 $self->pidl("\t$ep, "); 2862 } 2863 my $endpoint_count = $#{$interface->{ENDPOINTS}}+1; 2864 2865 $self->pidl("};"); 2866 $self->pidl(""); 2867 2868 $self->pidl("static const struct ndr_interface_string_array $interface->{NAME}\_endpoints = {"); 2869 $self->pidl("\t.count\t= $endpoint_count,"); 2870 $self->pidl("\t.names\t= $interface->{NAME}\_endpoint_strings"); 2871 $self->pidl("};"); 2872 $self->pidl(""); 2873 2874 if (! defined $interface->{PROPERTIES}->{authservice}) { 2875 $interface->{PROPERTIES}->{authservice} = "\"host\""; 2876 } 2877 2878 $self->AuthServiceStruct($interface->{NAME}, 2879 $interface->{PROPERTIES}->{authservice}); 2880 2881 $self->pidl("\nconst struct ndr_interface_table ndr_table_$interface->{NAME} = {"); 2882 $self->pidl("\t.name\t\t= \"$interface->{NAME}\","); 2883 if (defined $interface->{PROPERTIES}->{uuid}) { 2884 $self->pidl("\t.syntax_id\t= {"); 2885 $self->pidl("\t\t" . print_uuid($interface->{UUID}) .","); 2886 $self->pidl("\t\tNDR_$uname\_VERSION"); 2887 $self->pidl("\t},"); 2888 $self->pidl("\t.helpstring\t= NDR_$uname\_HELPSTRING,"); 2889 } 2890 $self->pidl("\t.num_calls\t= $count,"); 2891 $self->pidl("\t.calls\t\t= $interface->{NAME}\_calls,"); 2892 $self->pidl("\t.num_public_structs\t= $count_public_structs,"); 2893 $self->pidl("\t.public_structs\t\t= $interface->{NAME}\_public_structs,"); 2894 $self->pidl("\t.endpoints\t= &$interface->{NAME}\_endpoints,"); 2895 $self->pidl("\t.authservices\t= &$interface->{NAME}\_authservices"); 2896 $self->pidl("};"); 2897 $self->pidl(""); 2898 2899} 2900 2901##################################################################### 2902# generate include statements for imported idl files 2903sub HeaderImport 2904{ 2905 my $self = shift; 2906 my @imports = @_; 2907 foreach (@imports) { 2908 $_ = unmake_str($_); 2909 s/\.idl$//; 2910 $self->pidl(choose_header("librpc/gen_ndr/ndr_$_\.h", "gen_ndr/ndr_$_.h")); 2911 } 2912} 2913 2914##################################################################### 2915# generate include statements for included header files 2916sub HeaderInclude 2917{ 2918 my $self = shift; 2919 my @includes = @_; 2920 foreach (@includes) { 2921 $self->pidl_hdr("#include $_"); 2922 } 2923} 2924 2925##################################################################### 2926# generate prototypes and defines for the interface definitions 2927# FIXME: these prototypes are for the DCE/RPC client functions, not the 2928# NDR parser and so do not belong here, technically speaking 2929sub HeaderInterface($$$) 2930{ 2931 my($self,$interface,$needed) = @_; 2932 2933 my $count = 0; 2934 2935 if ($needed->{"compression"}) { 2936 $self->pidl(choose_header("librpc/ndr/ndr_compression.h", "ndr/compression.h")); 2937 } 2938 2939 if (has_property($interface, "object")) { 2940 $self->pidl(choose_header("librpc/gen_ndr/ndr_orpc.h", "ndr/orpc.h")); 2941 } 2942 2943 if (defined $interface->{PROPERTIES}->{helper}) { 2944 $self->HeaderInclude(split /,/, $interface->{PROPERTIES}->{helper}); 2945 } 2946 2947 if (defined $interface->{PROPERTIES}->{uuid}) { 2948 my $name = uc $interface->{NAME}; 2949 $self->pidl_hdr("#define NDR_$name\_UUID " . 2950 Parse::Pidl::Util::make_str(lc($interface->{UUID}))); 2951 2952 $self->pidl_hdr("#define NDR_$name\_VERSION $interface->{VERSION}"); 2953 2954 $self->pidl_hdr("#define NDR_$name\_NAME \"$interface->{NAME}\""); 2955 2956 if(!defined $interface->{PROPERTIES}->{helpstring}) { $interface->{PROPERTIES}->{helpstring} = "NULL"; } 2957 $self->pidl_hdr("#define NDR_$name\_HELPSTRING $interface->{PROPERTIES}->{helpstring}"); 2958 } 2959 2960 my $count_public_structs = 0; 2961 foreach my $d (@{$interface->{TYPES}}) { 2962 next unless (has_property($d, "public")); 2963 $count_public_structs += 1; 2964 } 2965 if ($#{$interface->{FUNCTIONS}}+1 > 0 or 2966 $count_public_structs > 0) { 2967 $self->pidl_hdr("extern const struct ndr_interface_table ndr_table_$interface->{NAME};"); 2968 } 2969 2970 foreach (@{$interface->{FUNCTIONS}}) { 2971 next if has_property($_, "noopnum"); 2972 next if grep(/^$_->{NAME}$/,@{$interface->{INHERITED_FUNCTIONS}}); 2973 my $u_name = uc $_->{NAME}; 2974 2975 my $val = sprintf("0x%02x", $count); 2976 if (defined($interface->{BASE})) { 2977 $val .= " + NDR_" . uc $interface->{BASE} . "_CALL_COUNT"; 2978 } 2979 2980 $self->pidl_hdr("#define NDR_$u_name ($val)"); 2981 2982 $self->pidl_hdr(""); 2983 $count++; 2984 } 2985 2986 my $val = $count; 2987 2988 if (defined($interface->{BASE})) { 2989 $val .= " + NDR_" . uc $interface->{BASE} . "_CALL_COUNT"; 2990 } 2991 2992 $self->pidl_hdr("#define NDR_" . uc $interface->{NAME} . "_CALL_COUNT ($val)"); 2993 2994} 2995 2996sub ParseTypePush($$$$$$) 2997{ 2998 my ($self,$e, $ndr, $varname, $primitives, $deferred) = @_; 2999 3000 # save the old relative_base_offset 3001 $self->pidl("uint32_t _save_relative_base_offset = ndr_push_get_relative_base_offset($ndr);") if defined(has_property($e, "relative_base")); 3002 $typefamily{$e->{TYPE}}->{PUSH_FN_BODY}->($self, $e, $ndr, $varname); 3003 # restore the old relative_base_offset 3004 $self->pidl("ndr_push_restore_relative_base_offset($ndr, _save_relative_base_offset);") if defined(has_property($e, "relative_base")); 3005} 3006 3007sub ParseTypePushFunction($$$) 3008{ 3009 my ($self, $e, $varname) = @_; 3010 my $ndr = "ndr"; 3011 3012 my $args = $typefamily{$e->{TYPE}}->{DECL}->($e, "push", $e->{NAME}, $varname); 3013 3014 $self->fn_declare("push", $e, "enum ndr_err_code ".TypeFunctionName("ndr_push", $e)."(struct ndr_push *$ndr, int ndr_flags, $args)") or return; 3015 3016 $self->pidl("{"); 3017 $self->indent; 3018 $self->ParseTypePush($e, $ndr, $varname, 1, 1); 3019 $self->pidl("return NDR_ERR_SUCCESS;"); 3020 $self->deindent; 3021 $self->pidl("}"); 3022 $self->pidl("");; 3023} 3024 3025sub ParseTypePull($$$$$$) 3026{ 3027 my ($self, $e, $ndr, $varname, $primitives, $deferred) = @_; 3028 3029 # save the old relative_base_offset 3030 $self->pidl("uint32_t _save_relative_base_offset = ndr_pull_get_relative_base_offset($ndr);") if defined(has_property($e, "relative_base")); 3031 $typefamily{$e->{TYPE}}->{PULL_FN_BODY}->($self, $e, $ndr, $varname); 3032 # restore the old relative_base_offset 3033 $self->pidl("ndr_pull_restore_relative_base_offset($ndr, _save_relative_base_offset);") if defined(has_property($e, "relative_base")); 3034} 3035 3036sub ParseTypePullFunction($$) 3037{ 3038 my ($self, $e, $varname) = @_; 3039 my $ndr = "ndr"; 3040 3041 my $args = $typefamily{$e->{TYPE}}->{DECL}->($e, "pull", $e->{NAME}, $varname); 3042 3043 $self->fn_declare("pull", $e, "enum ndr_err_code ".TypeFunctionName("ndr_pull", $e)."(struct ndr_pull *$ndr, int ndr_flags, $args)") or return; 3044 3045 $self->pidl("{"); 3046 $self->indent; 3047 $self->ParseTypePull($e, $ndr, $varname, 1, 1); 3048 $self->pidl("return NDR_ERR_SUCCESS;"); 3049 $self->deindent; 3050 $self->pidl("}"); 3051 $self->pidl(""); 3052} 3053 3054sub ParseTypePrint($$$$) 3055{ 3056 my ($self, $e, $ndr, $varname) = @_; 3057 3058 $typefamily{$e->{TYPE}}->{PRINT_FN_BODY}->($self, $e, $ndr, $e->{NAME}, $varname); 3059} 3060 3061sub ParseTypePrintFunction($$$) 3062{ 3063 my ($self, $e, $varname) = @_; 3064 my $ndr = "ndr"; 3065 3066 my $args = $typefamily{$e->{TYPE}}->{DECL}->($e, "print", $e->{NAME}, $varname); 3067 3068 $self->pidl_hdr("void ".TypeFunctionName("ndr_print", $e)."(struct ndr_print *ndr, const char *name, $args);"); 3069 3070 if (is_public_struct($e)) { 3071 $self->pidl("static void ".TypeFunctionName("ndr_print_flags", $e). 3072 "(struct ndr_print *$ndr, const char *name, int unused, $args)" 3073 ); 3074 $self->pidl("{"); 3075 $self->indent; 3076 $self->pidl(TypeFunctionName("ndr_print", $e)."($ndr, name, $varname);"); 3077 $self->deindent; 3078 $self->pidl("}"); 3079 $self->pidl(""); 3080 } 3081 3082 return if (has_property($e, "noprint")); 3083 3084 $self->pidl("_PUBLIC_ void ".TypeFunctionName("ndr_print", $e)."(struct ndr_print *$ndr, const char *name, $args)"); 3085 $self->pidl("{"); 3086 $self->indent; 3087 $self->ParseTypePrint($e, $ndr, $varname); 3088 $self->deindent; 3089 $self->pidl("}"); 3090 $self->pidl(""); 3091} 3092 3093sub ParseTypeNdrSize($$) 3094{ 3095 my ($self,$t) = @_; 3096 3097 my $varname = "r"; 3098 my $tf = $typefamily{$t->{TYPE}}; 3099 my $args = $tf->{SIZE_FN_ARGS}->($t, $t->{NAME}, $varname); 3100 3101 $self->fn_declare("size", $t, "size_t ndr_size_$t->{NAME}($args)") or return; 3102 3103 $self->pidl("{"); 3104 $self->indent; 3105 $typefamily{$t->{TYPE}}->{SIZE_FN_BODY}->($self,$t, $t->{NAME}, $varname); 3106 $self->deindent; 3107 $self->pidl("}"); 3108 $self->pidl(""); 3109} 3110 3111##################################################################### 3112# parse the interface definitions 3113sub ParseInterface($$$) 3114{ 3115 my($self,$interface,$needed) = @_; 3116 3117 $self->pidl_hdr("#ifndef _HEADER_NDR_$interface->{NAME}"); 3118 $self->pidl_hdr("#define _HEADER_NDR_$interface->{NAME}"); 3119 3120 $self->pidl_hdr(""); 3121 3122 $self->HeaderInterface($interface, $needed); 3123 3124 # Typedefs 3125 foreach my $d (@{$interface->{TYPES}}) { 3126 if (Parse::Pidl::Typelist::typeIs($d, "PIPE")) { 3127 ($needed->{TypeFunctionName("ndr_push", $d)}) && 3128 $self->ParsePipePushChunk($d); 3129 ($needed->{TypeFunctionName("ndr_pull", $d)}) && 3130 $self->ParsePipePullChunk($d); 3131 ($needed->{TypeFunctionName("ndr_print", $d)}) && 3132 $self->ParsePipePrintChunk($d); 3133 3134 $needed->{TypeFunctionName("ndr_pull", $d)} = 0; 3135 $needed->{TypeFunctionName("ndr_push", $d)} = 0; 3136 $needed->{TypeFunctionName("ndr_print", $d)} = 0; 3137 next; 3138 } 3139 3140 next unless(typeHasBody($d)); 3141 3142 ($needed->{TypeFunctionName("ndr_push", $d)}) && $self->ParseTypePushFunction($d, "r"); 3143 ($needed->{TypeFunctionName("ndr_pull", $d)}) && $self->ParseTypePullFunction($d, "r"); 3144 ($needed->{TypeFunctionName("ndr_print", $d)}) && $self->ParseTypePrintFunction($d, "r"); 3145 3146 # Make sure we don't generate a function twice... 3147 $needed->{TypeFunctionName("ndr_push", $d)} = 3148 $needed->{TypeFunctionName("ndr_pull", $d)} = 3149 $needed->{TypeFunctionName("ndr_print", $d)} = 0; 3150 3151 ($needed->{"ndr_size_$d->{NAME}"}) && $self->ParseTypeNdrSize($d); 3152 } 3153 3154 # Functions 3155 foreach my $d (@{$interface->{FUNCTIONS}}) { 3156 ($needed->{"ndr_push_$d->{NAME}"}) && $self->ParseFunctionPush($d); 3157 ($needed->{"ndr_pull_$d->{NAME}"}) && $self->ParseFunctionPull($d); 3158 ($needed->{"ndr_print_$d->{NAME}"}) && $self->ParseFunctionPrint($d); 3159 } 3160 3161 # Allow compilation of generated files where replacement functions 3162 # for structures declared nopull/nopush have not been provided. 3163 # 3164 # This makes sense when only the print functions are used 3165 # 3166 # Otherwise the ndr_table XXX will reference these 3167 3168 $self->pidl("#ifndef SKIP_NDR_TABLE_$interface->{NAME}"); 3169 $self->FunctionTable($interface); 3170 $self->pidl("#endif /* SKIP_NDR_TABLE_$interface->{NAME} */"); 3171 3172 $self->pidl_hdr("#endif /* _HEADER_NDR_$interface->{NAME} */"); 3173} 3174 3175sub GenerateIncludes($) 3176{ 3177 my ($self) = @_; 3178 if (is_intree()) { 3179 $self->pidl("#include \"includes.h\""); 3180 } else { 3181 $self->pidl("#ifndef _GNU_SOURCE"); 3182 $self->pidl("#define _GNU_SOURCE"); 3183 $self->pidl("#endif"); 3184 $self->pidl("#include <stdint.h>"); 3185 $self->pidl("#include <stdlib.h>"); 3186 $self->pidl("#include <stdio.h>"); 3187 $self->pidl("#include <stdbool.h>"); 3188 $self->pidl("#include <stdarg.h>"); 3189 $self->pidl("#include <string.h>"); 3190 } 3191} 3192 3193##################################################################### 3194# parse a parsed IDL structure back into an IDL file 3195sub Parse($$$$) 3196{ 3197 my($self, $ndr,$gen_header,$ndr_header) = @_; 3198 3199 $self->pidl_hdr("/* header auto-generated by pidl */"); 3200 $self->pidl_hdr(""); 3201 $self->pidl_hdr(choose_header("librpc/ndr/libndr.h", "ndr.h")); 3202 $self->pidl_hdr("#include \"$gen_header\"") if ($gen_header); 3203 $self->pidl_hdr(""); 3204 3205 $self->pidl("/* parser auto-generated by pidl */"); 3206 $self->pidl(""); 3207 $self->GenerateIncludes(); 3208 $self->pidl("#include \"$ndr_header\"") if ($ndr_header); 3209 $self->pidl(""); 3210 3211 my %needed = (); 3212 3213 foreach (@{$ndr}) { 3214 ($_->{TYPE} eq "INTERFACE") && NeededInterface($_, \%needed); 3215 } 3216 3217 foreach (@{$ndr}) { 3218 ($_->{TYPE} eq "INTERFACE") && $self->ParseInterface($_, \%needed); 3219 ($_->{TYPE} eq "IMPORT") && $self->HeaderImport(@{$_->{PATHS}}); 3220 ($_->{TYPE} eq "INCLUDE") && $self->HeaderInclude(@{$_->{PATHS}}); 3221 } 3222 3223 return ($self->{res_hdr}, $self->{res}); 3224} 3225 3226sub NeededElement($$$) 3227{ 3228 my ($e, $dir, $needed) = @_; 3229 3230 return if ($e->{TYPE} eq "EMPTY"); 3231 3232 return if (ref($e->{TYPE}) eq "HASH" and 3233 not defined($e->{TYPE}->{NAME})); 3234 3235 my ($t, $rt); 3236 if (ref($e->{TYPE}) eq "HASH") { 3237 $t = $e->{TYPE}->{TYPE}."_".$e->{TYPE}->{NAME}; 3238 } else { 3239 $t = $e->{TYPE}; 3240 } 3241 3242 if (ref($e->{REPRESENTATION_TYPE}) eq "HASH") { 3243 $rt = $e->{REPRESENTATION_TYPE}->{TYPE}."_".$e->{REPRESENTATION_TYPE}->{NAME}; 3244 } else { 3245 $rt = $e->{REPRESENTATION_TYPE}; 3246 } 3247 3248 die ("$e->{NAME} $t, $rt FOO") unless ($rt ne ""); 3249 3250 my @fn = (); 3251 if ($dir eq "print") { 3252 push(@fn, TypeFunctionName("ndr_print", $e->{REPRESENTATION_TYPE})); 3253 } elsif ($dir eq "pull") { 3254 push (@fn, TypeFunctionName("ndr_pull", $e->{TYPE})); 3255 push (@fn, "ndr_$t\_to_$rt") 3256 if ($rt ne $t); 3257 } elsif ($dir eq "push") { 3258 push (@fn, TypeFunctionName("ndr_push", $e->{TYPE})); 3259 push (@fn, "ndr_$rt\_to_$t") 3260 if ($rt ne $t); 3261 } else { 3262 die("invalid direction `$dir'"); 3263 } 3264 3265 foreach (@fn) { 3266 unless (defined($needed->{$_})) { 3267 $needed->{$_} = 1; 3268 } 3269 } 3270} 3271 3272sub NeededFunction($$) 3273{ 3274 my ($fn,$needed) = @_; 3275 $needed->{"ndr_pull_$fn->{NAME}"} = 1; 3276 $needed->{"ndr_push_$fn->{NAME}"} = 1; 3277 $needed->{"ndr_print_$fn->{NAME}"} = 1; 3278 foreach my $e (@{$fn->{ELEMENTS}}) { 3279 $e->{PARENT} = $fn; 3280 NeededElement($e, $_, $needed) foreach ("pull", "push", "print"); 3281 } 3282} 3283 3284sub NeededType($$$) 3285{ 3286 sub NeededType($$$); 3287 my ($t,$needed,$req) = @_; 3288 3289 NeededType($t->{DATA}, $needed, $req) if ($t->{TYPE} eq "TYPEDEF"); 3290 NeededType($t->{DATA}, $needed, $req) if ($t->{TYPE} eq "PIPE"); 3291 3292 if ($t->{TYPE} eq "STRUCT" or $t->{TYPE} eq "UNION") { 3293 return unless defined($t->{ELEMENTS}); 3294 for my $e (@{$t->{ELEMENTS}}) { 3295 $e->{PARENT} = $t; 3296 if (has_property($e, "compression")) { 3297 $needed->{"compression"} = 1; 3298 } 3299 NeededElement($e, $req, $needed); 3300 NeededType($e->{TYPE}, $needed, $req) if (ref($e->{TYPE}) eq "HASH"); 3301 } 3302 } 3303} 3304 3305##################################################################### 3306# work out what parse functions are needed 3307sub NeededInterface($$) 3308{ 3309 my ($interface,$needed) = @_; 3310 NeededFunction($_, $needed) foreach (@{$interface->{FUNCTIONS}}); 3311 foreach (reverse @{$interface->{TYPES}}) { 3312 3313 if (has_property($_, "public")) { 3314 $needed->{TypeFunctionName("ndr_pull", $_)} = $needed->{TypeFunctionName("ndr_push", $_)} = 3315 $needed->{TypeFunctionName("ndr_print", $_)} = 1; 3316 } 3317 3318 NeededType($_, $needed, "pull") if ($needed->{TypeFunctionName("ndr_pull", $_)}); 3319 NeededType($_, $needed, "push") if ($needed->{TypeFunctionName("ndr_push", $_)}); 3320 NeededType($_, $needed, "print") if ($needed->{TypeFunctionName("ndr_print", $_)}); 3321 if (has_property($_, "gensize")) { 3322 $needed->{"ndr_size_$_->{NAME}"} = 1; 3323 } 3324 } 3325} 3326 3327sub TypeFunctionName($$) 3328{ 3329 my ($prefix, $t) = @_; 3330 3331 return "$prefix\_$t->{NAME}" if (ref($t) eq "HASH" and 3332 $t->{TYPE} eq "TYPEDEF"); 3333 return "$prefix\_$t->{TYPE}_$t->{NAME}" if (ref($t) eq "HASH"); 3334 return "$prefix\_$t"; 3335} 3336 33371; 3338