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