1
0
mirror of https://github.com/samba-team/samba.git synced 2025-11-19 04:23:48 +03:00
Files
samba-mirror/source/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm
Jelmer Vernooij 1ad0f99a43 r21433: Get rid of the COM support code - it's not used and unmaintained. We can
always bring it back if we need to. This code was getting in the way while
refactoring.

Add some tests for TDR.

Get rid of typedef in lib/registry/tdr_regf.idl and fix the
TDR code to be able to deal with it.
2007-10-10 14:48:33 -05:00

2612 lines
66 KiB
Perl

###################################################
# Samba4 NDR parser generator for IDL structures
# Copyright tridge@samba.org 2000-2003
# Copyright tpot@samba.org 2001
# Copyright jelmer@samba.org 2004-2006
# released under the GNU GPL
package Parse::Pidl::Samba4::NDR::Parser;
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(is_charset_array);
@EXPORT_OK = qw(check_null_pointer GenerateFunctionInEnv
GenerateFunctionOutEnv EnvSubstituteValue GenerateStructEnv NeededFunction
NeededElement NeededType);
use strict;
use Parse::Pidl::Typelist qw(hasType getType mapTypeName);
use Parse::Pidl::Util qw(has_property ParseExpr ParseExprExt print_uuid);
use Parse::Pidl::NDR qw(GetPrevLevel GetNextLevel ContainsDeferred);
use Parse::Pidl::Samba4 qw(is_intree choose_header);
use Parse::Pidl qw(warning);
use vars qw($VERSION);
$VERSION = '0.01';
# list of known types
my %typefamily;
sub get_typefamily($)
{
my $n = shift;
return $typefamily{$n};
}
sub append_prefix($$)
{
my ($e, $var_name) = @_;
my $pointers = 0;
foreach my $l (@{$e->{LEVELS}}) {
if ($l->{TYPE} eq "POINTER") {
$pointers++;
} elsif ($l->{TYPE} eq "ARRAY") {
if (($pointers == 0) and
(not $l->{IS_FIXED}) and
(not $l->{IS_INLINE})) {
return get_value_of($var_name);
}
} elsif ($l->{TYPE} eq "DATA") {
if (Parse::Pidl::Typelist::scalar_is_reference($l->{DATA_TYPE})) {
return get_value_of($var_name) unless ($pointers);
}
}
}
return $var_name;
}
sub has_fast_array($$)
{
my ($e,$l) = @_;
return 0 if ($l->{TYPE} ne "ARRAY");
my $nl = GetNextLevel($e,$l);
return 0 unless ($nl->{TYPE} eq "DATA");
return 0 unless (hasType($nl->{DATA_TYPE}));
my $t = getType($nl->{DATA_TYPE});
# Only uint8 and string have fast array functions at the moment
return ($t->{NAME} eq "uint8") or ($t->{NAME} eq "string");
}
sub is_charset_array($$)
{
my ($e,$l) = @_;
return 0 if ($l->{TYPE} ne "ARRAY");
my $nl = GetNextLevel($e,$l);
return 0 unless ($nl->{TYPE} eq "DATA");
return has_property($e, "charset");
}
sub get_pointer_to($)
{
my $var_name = shift;
if ($var_name =~ /^\*(.*)$/) {
return $1;
} elsif ($var_name =~ /^\&(.*)$/) {
return "&($var_name)";
} else {
return "&$var_name";
}
}
sub get_value_of($)
{
my $var_name = shift;
if ($var_name =~ /^\&(.*)$/) {
return $1;
} else {
return "*$var_name";
}
}
my $res;
my $deferred = [];
my $tabs = "";
####################################
# pidl() is our basic output routine
sub pidl($)
{
my $d = shift;
if ($d) {
$res .= $tabs;
$res .= $d;
}
$res .="\n";
}
my $res_hdr;
sub pidl_hdr ($) { my $d = shift; $res_hdr .= "$d\n"; }
####################################
# defer() is like pidl(), but adds to
# a deferred buffer which is then added to the
# output buffer at the end of the structure/union/function
# This is needed to cope with code that must be pushed back
# to the end of a block of elements
my $defer_tabs = "";
sub defer_indent() { $defer_tabs.="\t"; }
sub defer_deindent() { $defer_tabs=substr($defer_tabs, 0, -1); }
sub defer($)
{
my $d = shift;
if ($d) {
push(@$deferred, $defer_tabs.$d);
}
}
########################################
# add the deferred content to the current
# output
sub add_deferred()
{
pidl $_ foreach (@$deferred);
$deferred = [];
$defer_tabs = "";
}
sub indent()
{
$tabs .= "\t";
}
sub deindent()
{
$tabs = substr($tabs, 0, -1);
}
#####################################################################
# declare a function public or static, depending on its attributes
sub fn_declare($$$)
{
my ($type,$fn,$decl) = @_;
if (has_property($fn, "no$type")) {
pidl_hdr "$decl;";
return 0;
}
if (has_property($fn, "public")) {
pidl_hdr "$decl;";
pidl "_PUBLIC_ $decl";
} else {
pidl "static $decl";
}
return 1;
}
###################################################################
# setup any special flags for an element or structure
sub start_flags($)
{
my $e = shift;
my $flags = has_property($e, "flag");
if (defined $flags) {
pidl "{";
indent;
pidl "uint32_t _flags_save_$e->{TYPE} = ndr->flags;";
pidl "ndr_set_flags(&ndr->flags, $flags);";
}
}
###################################################################
# end any special flags for an element or structure
sub end_flags($)
{
my $e = shift;
my $flags = has_property($e, "flag");
if (defined $flags) {
pidl "ndr->flags = _flags_save_$e->{TYPE};";
deindent;
pidl "}";
}
}
sub GenerateStructEnv($)
{
my $x = shift;
my %env;
foreach my $e (@{$x->{ELEMENTS}}) {
$env{$e->{NAME}} = "r->$e->{NAME}";
}
$env{"this"} = "r";
return \%env;
}
sub EnvSubstituteValue($$)
{
my ($env,$s) = @_;
# Substitute the value() values in the env
foreach my $e (@{$s->{ELEMENTS}}) {
next unless (defined(my $v = has_property($e, "value")));
$env->{$e->{NAME}} = ParseExpr($v, $env, $e);
}
return $env;
}
sub GenerateFunctionInEnv($)
{
my $fn = shift;
my %env;
foreach my $e (@{$fn->{ELEMENTS}}) {
if (grep (/in/, @{$e->{DIRECTION}})) {
$env{$e->{NAME}} = "r->in.$e->{NAME}";
}
}
return \%env;
}
sub GenerateFunctionOutEnv($)
{
my $fn = shift;
my %env;
foreach my $e (@{$fn->{ELEMENTS}}) {
if (grep (/out/, @{$e->{DIRECTION}})) {
$env{$e->{NAME}} = "r->out.$e->{NAME}";
} elsif (grep (/in/, @{$e->{DIRECTION}})) {
$env{$e->{NAME}} = "r->in.$e->{NAME}";
}
}
return \%env;
}
#####################################################################
# parse the data of an array - push side
sub ParseArrayPushHeader($$$$$)
{
my ($e,$l,$ndr,$var_name,$env) = @_;
my $size;
my $length;
if ($l->{IS_ZERO_TERMINATED}) {
if (has_property($e, "charset")) {
$size = $length = "ndr_charset_length($var_name, CH_$e->{PROPERTIES}->{charset})";
} else {
$size = $length = "ndr_string_length($var_name, sizeof(*$var_name))";
}
} else {
$size = ParseExpr($l->{SIZE_IS}, $env, $e);
$length = ParseExpr($l->{LENGTH_IS}, $env, $e);
}
if ((!$l->{IS_SURROUNDING}) and $l->{IS_CONFORMANT}) {
pidl "NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, $size));";
}
if ($l->{IS_VARYING}) {
pidl "NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, 0));"; # array offset
pidl "NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, $length));";
}
return $length;
}
sub check_fully_dereferenced($$)
{
my ($element, $env) = @_;
return sub ($) {
my $origvar = shift;
my $check = 0;
# Figure out the number of pointers in $ptr
my $expandedvar = $origvar;
$expandedvar =~ s/^(\**)//;
my $ptr = $1;
my $var = undef;
foreach (keys %$env) {
if ($env->{$_} eq $expandedvar) {
$var = $_;
last;
}
}
return($origvar) unless (defined($var));
my $e;
foreach (@{$element->{PARENT}->{ELEMENTS}}) {
if ($_->{NAME} eq $var) {
$e = $_;
last;
}
}
$e or die("Environment doesn't match siblings");
# See if pointer at pointer level $level
# needs to be checked.
my $nump = 0;
foreach (@{$e->{LEVELS}}) {
if ($_->{TYPE} eq "POINTER") {
$nump = $_->{POINTER_INDEX}+1;
}
}
warning($element->{ORIGINAL}, "Got pointer for `$e->{NAME}', expected fully derefenced variable") if ($nump > length($ptr));
return ($origvar);
}
}
sub check_null_pointer($$$$)
{
my ($element, $env, $print_fn, $return) = @_;
return sub ($) {
my $expandedvar = shift;
my $check = 0;
# Figure out the number of pointers in $ptr
$expandedvar =~ s/^(\**)//;
my $ptr = $1;
my $var = undef;
foreach (keys %$env) {
if ($env->{$_} eq $expandedvar) {
$var = $_;
last;
}
}
if (defined($var)) {
my $e;
# lookup ptr in $e
foreach (@{$element->{PARENT}->{ELEMENTS}}) {
if ($_->{NAME} eq $var) {
$e = $_;
last;
}
}
$e or die("Environment doesn't match siblings");
# See if pointer at pointer level $level
# needs to be checked.
foreach my $l (@{$e->{LEVELS}}) {
if ($l->{TYPE} eq "POINTER" and
$l->{POINTER_INDEX} == length($ptr)) {
# No need to check ref pointers
$check = ($l->{POINTER_TYPE} ne "ref");
last;
}
if ($l->{TYPE} eq "DATA") {
warning($element, "too much dereferences for `$var'");
}
}
} else {
warning($element, "unknown dereferenced expression `$expandedvar'");
$check = 1;
}
$print_fn->("if ($ptr$expandedvar == NULL) $return") if $check;
}
}
#####################################################################
# parse an array - pull side
sub ParseArrayPullHeader($$$$$)
{
my ($e,$l,$ndr,$var_name,$env) = @_;
my $length;
my $size;
if ($l->{IS_CONFORMANT}) {
$length = $size = "ndr_get_array_size($ndr, " . get_pointer_to($var_name) . ")";
} elsif ($l->{IS_ZERO_TERMINATED}) { # Noheader arrays
$length = $size = "ndr_get_string_size($ndr, sizeof(*$var_name))";
} else {
$length = $size = ParseExprExt($l->{SIZE_IS}, $env, $e->{ORIGINAL},
check_null_pointer($e, $env, \&pidl, "return NT_STATUS_INVALID_PARAMETER_MIX;"), check_fully_dereferenced($e, $env));
}
if ((!$l->{IS_SURROUNDING}) and $l->{IS_CONFORMANT}) {
pidl "NDR_CHECK(ndr_pull_array_size(ndr, " . get_pointer_to($var_name) . "));";
}
if ($l->{IS_VARYING}) {
pidl "NDR_CHECK(ndr_pull_array_length($ndr, " . get_pointer_to($var_name) . "));";
$length = "ndr_get_array_length($ndr, " . get_pointer_to($var_name) .")";
}
if ($length ne $size) {
pidl "if ($length > $size) {";
indent;
pidl "return ndr_pull_error($ndr, NDR_ERR_ARRAY_SIZE, \"Bad array size %u should exceed array length %u\", $size, $length);";
deindent;
pidl "}";
}
if ($l->{IS_CONFORMANT} and not $l->{IS_ZERO_TERMINATED}) {
defer "if ($var_name) {";
defer_indent;
my $size = ParseExprExt($l->{SIZE_IS}, $env, $e->{ORIGINAL}, check_null_pointer($e, $env, \&defer, "return NT_STATUS_INVALID_PARAMETER_MIX;"), check_fully_dereferenced($e, $env));
defer "NDR_CHECK(ndr_check_array_size(ndr, (void*)" . get_pointer_to($var_name) . ", $size));";
defer_deindent;
defer "}";
}
if ($l->{IS_VARYING} and not $l->{IS_ZERO_TERMINATED}) {
defer "if ($var_name) {";
defer_indent;
my $length = ParseExprExt($l->{LENGTH_IS}, $env, $e->{ORIGINAL},
check_null_pointer($e, $env, \&defer, "return NT_STATUS_INVALID_PARAMETER_MIX;"),
check_fully_dereferenced($e, $env));
defer "NDR_CHECK(ndr_check_array_length(ndr, (void*)" . get_pointer_to($var_name) . ", $length));";
defer_deindent;
defer "}"
}
if (not $l->{IS_FIXED} and not is_charset_array($e, $l)) {
AllocateArrayLevel($e,$l,$ndr,$env,$size);
}
return $length;
}
sub compression_alg($$)
{
my ($e, $l) = @_;
my ($alg, $clen, $dlen) = split(/ /, $l->{COMPRESSION});
return $alg;
}
sub compression_clen($$$)
{
my ($e, $l, $env) = @_;
my ($alg, $clen, $dlen) = split(/ /, $l->{COMPRESSION});
return ParseExpr($clen, $env, $e->{ORIGINAL});
}
sub compression_dlen($$$)
{
my ($e,$l,$env) = @_;
my ($alg, $clen, $dlen) = split(/ /, $l->{COMPRESSION});
return ParseExpr($dlen, $env, $e->{ORIGINAL});
}
sub ParseCompressionPushStart($$$$)
{
my ($e,$l,$ndr,$env) = @_;
my $comndr = "$ndr\_compressed";
my $alg = compression_alg($e, $l);
my $dlen = compression_dlen($e, $l, $env);
pidl "{";
indent;
pidl "struct ndr_push *$comndr;";
pidl "NDR_CHECK(ndr_push_compression_start($ndr, &$comndr, $alg, $dlen));";
return $comndr;
}
sub ParseCompressionPushEnd($$$$)
{
my ($e,$l,$ndr,$env) = @_;
my $comndr = "$ndr\_compressed";
my $alg = compression_alg($e, $l);
my $dlen = compression_dlen($e, $l, $env);
pidl "NDR_CHECK(ndr_push_compression_end($ndr, $comndr, $alg, $dlen));";
deindent;
pidl "}";
}
sub ParseCompressionPullStart($$$$)
{
my ($e,$l,$ndr,$env) = @_;
my $comndr = "$ndr\_compressed";
my $alg = compression_alg($e, $l);
my $dlen = compression_dlen($e, $l, $env);
pidl "{";
indent;
pidl "struct ndr_pull *$comndr;";
pidl "NDR_CHECK(ndr_pull_compression_start($ndr, &$comndr, $alg, $dlen));";
return $comndr;
}
sub ParseCompressionPullEnd($$$$)
{
my ($e,$l,$ndr,$env) = @_;
my $comndr = "$ndr\_compressed";
my $alg = compression_alg($e, $l);
my $dlen = compression_dlen($e, $l, $env);
pidl "NDR_CHECK(ndr_pull_compression_end($ndr, $comndr, $alg, $dlen));";
deindent;
pidl "}";
}
sub ParseSubcontextPushStart($$$$)
{
my ($e,$l,$ndr,$env) = @_;
my $subndr = "_ndr_$e->{NAME}";
my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
pidl "{";
indent;
pidl "struct ndr_push *$subndr;";
pidl "NDR_CHECK(ndr_push_subcontext_start($ndr, &$subndr, $l->{HEADER_SIZE}, $subcontext_size));";
if (defined $l->{COMPRESSION}) {
$subndr = ParseCompressionPushStart($e, $l, $subndr, $env);
}
return $subndr;
}
sub ParseSubcontextPushEnd($$$$)
{
my ($e,$l,$ndr,$env) = @_;
my $subndr = "_ndr_$e->{NAME}";
my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
if (defined $l->{COMPRESSION}) {
ParseCompressionPushEnd($e, $l, $subndr, $env);
}
pidl "NDR_CHECK(ndr_push_subcontext_end($ndr, $subndr, $l->{HEADER_SIZE}, $subcontext_size));";
deindent;
pidl "}";
}
sub ParseSubcontextPullStart($$$$)
{
my ($e,$l,$ndr,$env) = @_;
my $subndr = "_ndr_$e->{NAME}";
my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
pidl "{";
indent;
pidl "struct ndr_pull *$subndr;";
pidl "NDR_CHECK(ndr_pull_subcontext_start($ndr, &$subndr, $l->{HEADER_SIZE}, $subcontext_size));";
if (defined $l->{COMPRESSION}) {
$subndr = ParseCompressionPullStart($e, $l, $subndr, $env);
}
return $subndr;
}
sub ParseSubcontextPullEnd($$$$)
{
my ($e,$l,$ndr,$env) = @_;
my $subndr = "_ndr_$e->{NAME}";
my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
if (defined $l->{COMPRESSION}) {
ParseCompressionPullEnd($e, $l, $subndr, $env);
}
pidl "NDR_CHECK(ndr_pull_subcontext_end($ndr, $subndr, $l->{HEADER_SIZE}, $subcontext_size));";
deindent;
pidl "}";
}
sub ParseElementPushLevel
{
my ($e,$l,$ndr,$var_name,$env,$primitives,$deferred) = @_;
my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
if ($l->{TYPE} eq "ARRAY" and ($l->{IS_CONFORMANT} or $l->{IS_VARYING})) {
$var_name = get_pointer_to($var_name);
}
if (defined($ndr_flags)) {
if ($l->{TYPE} eq "SUBCONTEXT") {
my $subndr = ParseSubcontextPushStart($e, $l, $ndr, $env);
ParseElementPushLevel($e, GetNextLevel($e, $l), $subndr, $var_name, $env, 1, 1);
ParseSubcontextPushEnd($e, $l, $ndr, $env);
} elsif ($l->{TYPE} eq "POINTER") {
ParsePtrPush($e, $l, $var_name);
} elsif ($l->{TYPE} eq "ARRAY") {
my $length = ParseArrayPushHeader($e, $l, $ndr, $var_name, $env);
my $nl = GetNextLevel($e, $l);
# Allow speedups for arrays of scalar types
if (is_charset_array($e,$l)) {
pidl "NDR_CHECK(ndr_push_charset($ndr, $ndr_flags, $var_name, $length, sizeof(" . mapTypeName($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));";
return;
} elsif (has_fast_array($e,$l)) {
pidl "NDR_CHECK(ndr_push_array_$nl->{DATA_TYPE}($ndr, $ndr_flags, $var_name, $length));";
return;
}
} elsif ($l->{TYPE} eq "SWITCH") {
ParseSwitchPush($e, $l, $ndr, $var_name, $ndr_flags, $env);
} elsif ($l->{TYPE} eq "DATA") {
ParseDataPush($e, $l, $ndr, $var_name, $ndr_flags);
}
}
if ($l->{TYPE} eq "POINTER" and $deferred) {
if ($l->{POINTER_TYPE} ne "ref") {
pidl "if ($var_name) {";
indent;
if ($l->{POINTER_TYPE} eq "relative") {
pidl "NDR_CHECK(ndr_push_relative_ptr2(ndr, $var_name));";
}
}
$var_name = get_value_of($var_name);
ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 1, 1);
if ($l->{POINTER_TYPE} ne "ref") {
deindent;
pidl "}";
}
} elsif ($l->{TYPE} eq "ARRAY" and not has_fast_array($e,$l) and
not is_charset_array($e, $l)) {
my $length = ParseExpr($l->{LENGTH_IS}, $env, $e->{ORIGINAL});
my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
$var_name = $var_name . "[$counter]";
if (($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) {
pidl "for ($counter = 0; $counter < $length; $counter++) {";
indent;
ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 1, 0);
deindent;
pidl "}";
}
if ($deferred and ContainsDeferred($e, $l)) {
pidl "for ($counter = 0; $counter < $length; $counter++) {";
indent;
ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 0, 1);
deindent;
pidl "}";
}
} elsif ($l->{TYPE} eq "SWITCH") {
ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, $primitives, $deferred);
}
}
#####################################################################
# parse scalars in a structure element
sub ParseElementPush($$$$$)
{
my ($e,$ndr,$env,$primitives,$deferred) = @_;
my $subndr = undef;
my $var_name = $env->{$e->{NAME}};
return unless $primitives or ($deferred and ContainsDeferred($e, $e->{LEVELS}[0]));
# Representation type is different from transmit_as
if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
pidl "{";
indent;
my $transmit_name = "_transmit_$e->{NAME}";
pidl mapTypeName($e->{TYPE}) ." $transmit_name;";
pidl "NDR_CHECK(ndr_$e->{REPRESENTATION_TYPE}_to_$e->{TYPE}($var_name, " . get_pointer_to($transmit_name) . "));";
$var_name = $transmit_name;
}
$var_name = append_prefix($e, $var_name);
start_flags($e);
if (defined(my $value = has_property($e, "value"))) {
$var_name = ParseExpr($value, $env, $e->{ORIGINAL});
}
ParseElementPushLevel($e, $e->{LEVELS}[0], $ndr, $var_name, $env, $primitives, $deferred);
end_flags($e);
if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
deindent;
pidl "}";
}
}
#####################################################################
# parse a pointer in a struct element or function
sub ParsePtrPush($$$)
{
my ($e,$l,$var_name) = @_;
if ($l->{POINTER_TYPE} eq "ref") {
pidl "if ($var_name == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;";
if ($l->{LEVEL} eq "EMBEDDED") {
pidl "NDR_CHECK(ndr_push_ref_ptr(ndr));";
}
} elsif ($l->{POINTER_TYPE} eq "relative") {
pidl "NDR_CHECK(ndr_push_relative_ptr1(ndr, $var_name));";
} elsif ($l->{POINTER_TYPE} eq "unique") {
pidl "NDR_CHECK(ndr_push_unique_ptr(ndr, $var_name));";
} elsif ($l->{POINTER_TYPE} eq "full") {
pidl "NDR_CHECK(ndr_push_full_ptr(ndr, $var_name));";
} else {
die("Unhandled pointer type $l->{POINTER_TYPE}");
}
}
#####################################################################
# print scalars in a structure element
sub ParseElementPrint($$$)
{
my($e, $var_name, $env) = @_;
return if (has_property($e, "noprint"));
if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
pidl "ndr_print_$e->{REPRESENTATION_TYPE}(ndr, \"$e->{NAME}\", $var_name);";
return;
}
$var_name = append_prefix($e, $var_name);
if (defined(my $value = has_property($e, "value"))) {
$var_name = "(ndr->flags & LIBNDR_PRINT_SET_VALUES)?" . ParseExpr($value,$env, $e->{ORIGINAL}) . ":$var_name";
}
foreach my $l (@{$e->{LEVELS}}) {
if ($l->{TYPE} eq "POINTER") {
pidl "ndr_print_ptr(ndr, \"$e->{NAME}\", $var_name);";
pidl "ndr->depth++;";
if ($l->{POINTER_TYPE} ne "ref") {
pidl "if ($var_name) {";
indent;
}
$var_name = get_value_of($var_name);
} elsif ($l->{TYPE} eq "ARRAY") {
my $length;
if ($l->{IS_CONFORMANT} or $l->{IS_VARYING}) {
$var_name = get_pointer_to($var_name);
}
if ($l->{IS_ZERO_TERMINATED}) {
$length = "ndr_string_length($var_name, sizeof(*$var_name))";
} else {
$length = ParseExprExt($l->{LENGTH_IS}, $env, $e->{ORIGINAL},
check_null_pointer($e, $env, \&pidl, "return;"), check_fully_dereferenced($e, $env));
}
if (is_charset_array($e,$l)) {
pidl "ndr_print_string(ndr, \"$e->{NAME}\", $var_name);";
last;
} elsif (has_fast_array($e, $l)) {
my $nl = GetNextLevel($e, $l);
pidl "ndr_print_array_$nl->{DATA_TYPE}(ndr, \"$e->{NAME}\", $var_name, $length);";
last;
} else {
my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
pidl "ndr->print(ndr, \"\%s: ARRAY(\%d)\", \"$e->{NAME}\", $length);";
pidl 'ndr->depth++;';
pidl "for ($counter=0;$counter<$length;$counter++) {";
indent;
pidl "char *idx_$l->{LEVEL_INDEX}=NULL;";
pidl "asprintf(&idx_$l->{LEVEL_INDEX}, \"[\%d]\", $counter);";
pidl "if (idx_$l->{LEVEL_INDEX}) {";
indent;
$var_name = $var_name . "[$counter]";
}
} elsif ($l->{TYPE} eq "DATA") {
if (not Parse::Pidl::Typelist::is_scalar($l->{DATA_TYPE}) or Parse::Pidl::Typelist::scalar_is_reference($l->{DATA_TYPE})) {
$var_name = get_pointer_to($var_name);
}
pidl "ndr_print_$l->{DATA_TYPE}(ndr, \"$e->{NAME}\", $var_name);";
} elsif ($l->{TYPE} eq "SWITCH") {
my $switch_var = ParseExprExt($l->{SWITCH_IS}, $env, $e->{ORIGINAL},
check_null_pointer($e, $env, \&pidl, "return;"), check_fully_dereferenced($e, $env));
pidl "ndr_print_set_switch_value(ndr, " . get_pointer_to($var_name) . ", $switch_var);";
}
}
foreach my $l (reverse @{$e->{LEVELS}}) {
if ($l->{TYPE} eq "POINTER") {
if ($l->{POINTER_TYPE} ne "ref") {
deindent;
pidl "}";
}
pidl "ndr->depth--;";
} elsif (($l->{TYPE} eq "ARRAY")
and not is_charset_array($e,$l)
and not has_fast_array($e,$l)) {
pidl "free(idx_$l->{LEVEL_INDEX});";
deindent;
pidl "}";
deindent;
pidl "}";
pidl "ndr->depth--;";
}
}
}
#####################################################################
# parse scalars in a structure element - pull size
sub ParseSwitchPull($$$$$$)
{
my($e,$l,$ndr,$var_name,$ndr_flags,$env) = @_;
my $switch_var = ParseExprExt($l->{SWITCH_IS}, $env, $e->{ORIGINAL},
check_null_pointer($e, $env, \&pidl, "return NT_STATUS_INVALID_PARAMETER_MIX;"), check_fully_dereferenced($e, $env));
$var_name = get_pointer_to($var_name);
pidl "NDR_CHECK(ndr_pull_set_switch_value($ndr, $var_name, $switch_var));";
}
#####################################################################
# push switch element
sub ParseSwitchPush($$$$$$)
{
my($e,$l,$ndr,$var_name,$ndr_flags,$env) = @_;
my $switch_var = ParseExprExt($l->{SWITCH_IS}, $env, $e->{ORIGINAL},
check_null_pointer($e, $env, \&pidl, "return NT_STATUS_INVALID_PARAMETER_MIX;"), check_fully_dereferenced($e, $env));
$var_name = get_pointer_to($var_name);
pidl "NDR_CHECK(ndr_push_set_switch_value($ndr, $var_name, $switch_var));";
}
sub ParseDataPull($$$$$)
{
my ($e,$l,$ndr,$var_name,$ndr_flags) = @_;
if (Parse::Pidl::Typelist::scalar_is_reference($l->{DATA_TYPE})) {
$var_name = get_pointer_to($var_name);
}
$var_name = get_pointer_to($var_name);
pidl "NDR_CHECK(ndr_pull_$l->{DATA_TYPE}($ndr, $ndr_flags, $var_name));";
if (my $range = has_property($e, "range")) {
$var_name = get_value_of($var_name);
my ($low, $high) = split(/ /, $range, 2);
pidl "if ($var_name < $low || $var_name > $high) {";
pidl "\treturn ndr_pull_error($ndr, NDR_ERR_RANGE, \"value out of range\");";
pidl "}";
}
}
sub ParseDataPush($$$$$)
{
my ($e,$l,$ndr,$var_name,$ndr_flags) = @_;
# strings are passed by value rather than reference
if (not Parse::Pidl::Typelist::is_scalar($l->{DATA_TYPE}) or Parse::Pidl::Typelist::scalar_is_reference($l->{DATA_TYPE})) {
$var_name = get_pointer_to($var_name);
}
pidl "NDR_CHECK(ndr_push_$l->{DATA_TYPE}($ndr, $ndr_flags, $var_name));";
}
sub CalcNdrFlags($$$)
{
my ($l,$primitives,$deferred) = @_;
my $scalars = 0;
my $buffers = 0;
# Add NDR_SCALARS if this one is deferred
# and deferreds may be pushed
$scalars = 1 if ($l->{IS_DEFERRED} and $deferred);
# Add NDR_SCALARS if this one is not deferred and
# primitives may be pushed
$scalars = 1 if (!$l->{IS_DEFERRED} and $primitives);
# Add NDR_BUFFERS if this one contains deferred stuff
# and deferreds may be pushed
$buffers = 1 if ($l->{CONTAINS_DEFERRED} and $deferred);
return "NDR_SCALARS|NDR_BUFFERS" if ($scalars and $buffers);
return "NDR_SCALARS" if ($scalars);
return "NDR_BUFFERS" if ($buffers);
return undef;
}
sub ParseMemCtxPullStart($$$)
{
my ($e, $l, $ptr_name) = @_;
my $mem_r_ctx = "_mem_save_$e->{NAME}_$l->{LEVEL_INDEX}";
my $mem_c_ctx = $ptr_name;
my $mem_c_flags = "0";
return if ($l->{TYPE} eq "ARRAY" and $l->{IS_FIXED});
if (($l->{TYPE} eq "POINTER") and ($l->{POINTER_TYPE} eq "ref")) {
my $nl = GetNextLevel($e, $l);
my $next_is_array = ($nl->{TYPE} eq "ARRAY");
my $next_is_string = (($nl->{TYPE} eq "DATA") and
($nl->{DATA_TYPE} eq "string"));
if ($next_is_array or $next_is_string) {
return;
} else {
$mem_c_flags = "LIBNDR_FLAG_REF_ALLOC";
}
}
pidl "$mem_r_ctx = NDR_PULL_GET_MEM_CTX(ndr);";
pidl "NDR_PULL_SET_MEM_CTX(ndr, $mem_c_ctx, $mem_c_flags);";
}
sub ParseMemCtxPullEnd($$)
{
my $e = shift;
my $l = shift;
my $mem_r_ctx = "_mem_save_$e->{NAME}_$l->{LEVEL_INDEX}";
my $mem_r_flags = "0";
return if ($l->{TYPE} eq "ARRAY" and $l->{IS_FIXED});
if (($l->{TYPE} eq "POINTER") and ($l->{POINTER_TYPE} eq "ref")) {
my $nl = GetNextLevel($e, $l);
my $next_is_array = ($nl->{TYPE} eq "ARRAY");
my $next_is_string = (($nl->{TYPE} eq "DATA") and
($nl->{DATA_TYPE} eq "string"));
if ($next_is_array or $next_is_string) {
return;
} else {
$mem_r_flags = "LIBNDR_FLAG_REF_ALLOC";
}
}
pidl "NDR_PULL_SET_MEM_CTX(ndr, $mem_r_ctx, $mem_r_flags);";
}
sub CheckStringTerminator($$$$)
{
my ($ndr,$e,$l,$length) = @_;
my $nl = GetNextLevel($e, $l);
# Make sure last element is zero!
pidl "NDR_CHECK(ndr_check_string_terminator($ndr, $length, sizeof($nl->{DATA_TYPE}_t)));";
}
sub ParseElementPullLevel
{
my($e,$l,$ndr,$var_name,$env,$primitives,$deferred) = @_;
my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
if ($l->{TYPE} eq "ARRAY" and ($l->{IS_VARYING} or $l->{IS_CONFORMANT})) {
$var_name = get_pointer_to($var_name);
}
# Only pull something if there's actually something to be pulled
if (defined($ndr_flags)) {
if ($l->{TYPE} eq "SUBCONTEXT") {
my $subndr = ParseSubcontextPullStart($e, $l, $ndr, $env);
ParseElementPullLevel($e, GetNextLevel($e,$l), $subndr, $var_name, $env, 1, 1);
ParseSubcontextPullEnd($e, $l, $ndr, $env);
} elsif ($l->{TYPE} eq "ARRAY") {
my $length = ParseArrayPullHeader($e, $l, $ndr, $var_name, $env);
my $nl = GetNextLevel($e, $l);
if (is_charset_array($e,$l)) {
if ($l->{IS_ZERO_TERMINATED}) {
CheckStringTerminator($ndr, $e, $l, $length);
}
pidl "NDR_CHECK(ndr_pull_charset($ndr, $ndr_flags, ".get_pointer_to($var_name).", $length, sizeof(" . mapTypeName($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));";
return;
} elsif (has_fast_array($e, $l)) {
if ($l->{IS_ZERO_TERMINATED}) {
CheckStringTerminator($ndr,$e,$l,$length);
}
pidl "NDR_CHECK(ndr_pull_array_$nl->{DATA_TYPE}($ndr, $ndr_flags, $var_name, $length));";
return;
}
} elsif ($l->{TYPE} eq "POINTER") {
ParsePtrPull($e, $l, $ndr, $var_name);
} elsif ($l->{TYPE} eq "SWITCH") {
ParseSwitchPull($e, $l, $ndr, $var_name, $ndr_flags, $env);
} elsif ($l->{TYPE} eq "DATA") {
ParseDataPull($e, $l, $ndr, $var_name, $ndr_flags);
}
}
# add additional constructions
if ($l->{TYPE} eq "POINTER" and $deferred) {
if ($l->{POINTER_TYPE} ne "ref") {
pidl "if ($var_name) {";
indent;
if ($l->{POINTER_TYPE} eq "relative") {
pidl "struct ndr_pull_save _relative_save;";
pidl "ndr_pull_save(ndr, &_relative_save);";
pidl "NDR_CHECK(ndr_pull_relative_ptr2(ndr, $var_name));";
}
}
ParseMemCtxPullStart($e, $l, $var_name);
$var_name = get_value_of($var_name);
ParseElementPullLevel($e, GetNextLevel($e,$l), $ndr, $var_name, $env, 1, 1);
ParseMemCtxPullEnd($e,$l);
if ($l->{POINTER_TYPE} ne "ref") {
if ($l->{POINTER_TYPE} eq "relative") {
pidl "ndr_pull_restore(ndr, &_relative_save);";
}
deindent;
pidl "}";
}
} elsif ($l->{TYPE} eq "ARRAY" and
not has_fast_array($e,$l) and not is_charset_array($e, $l)) {
my $length = ParseExpr($l->{LENGTH_IS}, $env, $e->{ORIGINAL});
my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
my $array_name = $var_name;
$var_name = $var_name . "[$counter]";
ParseMemCtxPullStart($e, $l, $array_name);
if (($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) {
my $nl = GetNextLevel($e,$l);
if ($l->{IS_ZERO_TERMINATED}) {
CheckStringTerminator($ndr,$e,$l,$length);
}
pidl "for ($counter = 0; $counter < $length; $counter++) {";
indent;
ParseElementPullLevel($e, $nl, $ndr, $var_name, $env, 1, 0);
deindent;
pidl "}";
}
if ($deferred and ContainsDeferred($e, $l)) {
pidl "for ($counter = 0; $counter < $length; $counter++) {";
indent;
ParseElementPullLevel($e,GetNextLevel($e,$l), $ndr, $var_name, $env, 0, 1);
deindent;
pidl "}";
}
ParseMemCtxPullEnd($e, $l);
} elsif ($l->{TYPE} eq "SWITCH") {
ParseElementPullLevel($e, GetNextLevel($e,$l), $ndr, $var_name, $env, $primitives, $deferred);
}
}
#####################################################################
# parse scalars in a structure element - pull size
sub ParseElementPull($$$$$)
{
my($e,$ndr,$env,$primitives,$deferred) = @_;
my $var_name = $env->{$e->{NAME}};
my $represent_name;
my $transmit_name;
return unless $primitives or ($deferred and ContainsDeferred($e, $e->{LEVELS}[0]));
if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
pidl "{";
indent;
$represent_name = $var_name;
$transmit_name = "_transmit_$e->{NAME}";
$var_name = $transmit_name;
pidl mapTypeName($e->{TYPE})." $var_name;";
}
$var_name = append_prefix($e, $var_name);
start_flags($e);
ParseElementPullLevel($e,$e->{LEVELS}[0],$ndr,$var_name,$env,$primitives,$deferred);
end_flags($e);
# Representation type is different from transmit_as
if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
pidl "NDR_CHECK(ndr_$e->{TYPE}_to_$e->{REPRESENTATION_TYPE}($transmit_name, ".get_pointer_to($represent_name)."));";
deindent;
pidl "}";
}
}
#####################################################################
# parse a pointer in a struct element or function
sub ParsePtrPull($$$$)
{
my($e,$l,$ndr,$var_name) = @_;
my $nl = GetNextLevel($e, $l);
my $next_is_array = ($nl->{TYPE} eq "ARRAY");
my $next_is_string = (($nl->{TYPE} eq "DATA") and
($nl->{DATA_TYPE} eq "string"));
if ($l->{POINTER_TYPE} eq "ref") {
if ($l->{LEVEL} eq "EMBEDDED") {
pidl "NDR_CHECK(ndr_pull_ref_ptr($ndr, &_ptr_$e->{NAME}));";
}
if (!$next_is_array and !$next_is_string) {
pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {";
pidl "\tNDR_PULL_ALLOC($ndr, $var_name);";
pidl "}";
}
return;
} elsif (($l->{POINTER_TYPE} eq "unique") or
($l->{POINTER_TYPE} eq "relative") or
($l->{POINTER_TYPE} eq "full")) {
pidl "NDR_CHECK(ndr_pull_generic_ptr($ndr, &_ptr_$e->{NAME}));";
pidl "if (_ptr_$e->{NAME}) {";
indent;
} else {
die("Unhandled pointer type $l->{POINTER_TYPE}");
}
# Don't do this for arrays, they're allocated at the actual level
# of the array
unless ($next_is_array or $next_is_string) {
pidl "NDR_PULL_ALLOC($ndr, $var_name);";
} else {
# FIXME: Yes, this is nasty.
# We allocate an array twice
# - once just to indicate that it's there,
# - then the real allocation...
pidl "NDR_PULL_ALLOC($ndr, $var_name);";
}
#pidl "memset($var_name, 0, sizeof($var_name));";
if ($l->{POINTER_TYPE} eq "relative") {
pidl "NDR_CHECK(ndr_pull_relative_ptr1($ndr, $var_name, _ptr_$e->{NAME}));";
}
deindent;
pidl "} else {";
pidl "\t$var_name = NULL;";
pidl "}";
}
#####################################################################
# parse a struct
sub ParseStructPush($$)
{
my($struct,$name) = @_;
return unless defined($struct->{ELEMENTS});
my $env = GenerateStructEnv($struct);
EnvSubstituteValue($env, $struct);
# save the old relative_base_offset
pidl "uint32_t _save_relative_base_offset = ndr_push_get_relative_base_offset(ndr);" if defined($struct->{PROPERTIES}{relative_base});
foreach my $e (@{$struct->{ELEMENTS}}) {
DeclareArrayVariables($e);
}
start_flags($struct);
# see if the structure contains a conformant array. If it
# does, then it must be the last element of the structure, and
# we need to push the conformant length early, as it fits on
# the wire before the structure (and even before the structure
# alignment)
if (defined($struct->{SURROUNDING_ELEMENT})) {
my $e = $struct->{SURROUNDING_ELEMENT};
if (defined($e->{LEVELS}[0]) and
$e->{LEVELS}[0]->{TYPE} eq "ARRAY") {
my $size;
if ($e->{LEVELS}[0]->{IS_ZERO_TERMINATED}) {
if (has_property($e, "charset")) {
$size = "ndr_charset_length(r->$e->{NAME}, CH_$e->{PROPERTIES}->{charset})";
} else {
$size = "ndr_string_length(r->$e->{NAME}, sizeof(*r->$e->{NAME}))";
}
} else {
$size = ParseExpr($e->{LEVELS}[0]->{SIZE_IS}, $env, $e->{ORIGINAL});
}
pidl "NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, $size));";
} else {
pidl "NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_string_array_size(ndr, r->$e->{NAME})));";
}
}
pidl "if (ndr_flags & NDR_SCALARS) {";
indent;
pidl "NDR_CHECK(ndr_push_align(ndr, $struct->{ALIGN}));";
if (defined($struct->{PROPERTIES}{relative_base})) {
# set the current offset as base for relative pointers
# and store it based on the toplevel struct/union
pidl "NDR_CHECK(ndr_push_setup_relative_base_offset1(ndr, r, ndr->offset));";
}
foreach my $e (@{$struct->{ELEMENTS}}) {
ParseElementPush($e, "ndr", $env, 1, 0);
}
deindent;
pidl "}";
pidl "if (ndr_flags & NDR_BUFFERS) {";
indent;
if (defined($struct->{PROPERTIES}{relative_base})) {
# retrieve the current offset as base for relative pointers
# based on the toplevel struct/union
pidl "NDR_CHECK(ndr_push_setup_relative_base_offset2(ndr, r));";
}
foreach my $e (@{$struct->{ELEMENTS}}) {
ParseElementPush($e, "ndr", $env, 0, 1);
}
deindent;
pidl "}";
end_flags($struct);
# restore the old relative_base_offset
pidl "ndr_push_restore_relative_base_offset(ndr, _save_relative_base_offset);" if defined($struct->{PROPERTIES}{relative_base});
}
#####################################################################
# generate a push function for an enum
sub ParseEnumPush($$)
{
my($enum,$name) = @_;
my($type_fn) = $enum->{BASE_TYPE};
start_flags($enum);
pidl "NDR_CHECK(ndr_push_$type_fn(ndr, NDR_SCALARS, r));";
end_flags($enum);
}
#####################################################################
# generate a pull function for an enum
sub ParseEnumPull($$)
{
my($enum,$name) = @_;
my($type_fn) = $enum->{BASE_TYPE};
my($type_v_decl) = mapTypeName($type_fn);
pidl "$type_v_decl v;";
start_flags($enum);
pidl "NDR_CHECK(ndr_pull_$type_fn(ndr, NDR_SCALARS, &v));";
pidl "*r = v;";
end_flags($enum);
}
#####################################################################
# generate a print function for an enum
sub ParseEnumPrint($$)
{
my($enum,$name) = @_;
pidl "const char *val = NULL;";
pidl "";
start_flags($enum);
pidl "switch (r) {";
indent;
my $els = \@{$enum->{ELEMENTS}};
foreach my $i (0 .. $#{$els}) {
my $e = ${$els}[$i];
chomp $e;
if ($e =~ /^(.*)=/) {
$e = $1;
}
pidl "case $e: val = \"$e\"; break;";
}
deindent;
pidl "}";
pidl "ndr_print_enum(ndr, name, \"$enum->{TYPE}\", val, r);";
end_flags($enum);
}
sub DeclEnum($$$)
{
my ($e,$t,$name) = @_;
return "enum $name " .
($t eq "pull"?"*":"") . "r";
}
$typefamily{ENUM} = {
DECL => \&DeclEnum,
PUSH_FN_BODY => \&ParseEnumPush,
PULL_FN_BODY => \&ParseEnumPull,
PRINT_FN_BODY => \&ParseEnumPrint,
};
#####################################################################
# generate a push function for a bitmap
sub ParseBitmapPush($$)
{
my($bitmap,$name) = @_;
my($type_fn) = $bitmap->{BASE_TYPE};
start_flags($bitmap);
pidl "NDR_CHECK(ndr_push_$type_fn(ndr, NDR_SCALARS, r));";
end_flags($bitmap);
}
#####################################################################
# generate a pull function for an bitmap
sub ParseBitmapPull($$)
{
my($bitmap,$name) = @_;
my $type_fn = $bitmap->{BASE_TYPE};
my($type_decl) = mapTypeName($bitmap->{BASE_TYPE});
pidl "$type_decl v;";
start_flags($bitmap);
pidl "NDR_CHECK(ndr_pull_$type_fn(ndr, NDR_SCALARS, &v));";
pidl "*r = v;";
end_flags($bitmap);
}
#####################################################################
# generate a print function for an bitmap
sub ParseBitmapPrintElement($$$)
{
my($e,$bitmap,$name) = @_;
my($type_decl) = mapTypeName($bitmap->{BASE_TYPE});
my($type_fn) = $bitmap->{BASE_TYPE};
my($flag);
if ($e =~ /^(\w+) .*$/) {
$flag = "$1";
} else {
die "Bitmap: \"$name\" invalid Flag: \"$e\"";
}
pidl "ndr_print_bitmap_flag(ndr, sizeof($type_decl), \"$flag\", $flag, r);";
}
#####################################################################
# generate a print function for an bitmap
sub ParseBitmapPrint($$)
{
my($bitmap,$name) = @_;
my($type_decl) = mapTypeName($bitmap->{TYPE});
my($type_fn) = $bitmap->{BASE_TYPE};
start_flags($bitmap);
pidl "ndr_print_$type_fn(ndr, name, r);";
pidl "ndr->depth++;";
foreach my $e (@{$bitmap->{ELEMENTS}}) {
ParseBitmapPrintElement($e, $bitmap, $name);
}
pidl "ndr->depth--;";
end_flags($bitmap);
}
sub DeclBitmap($$$)
{
my ($e,$t,$name) = @_;
return mapTypeName(Parse::Pidl::Typelist::bitmap_type_fn($e)) .
($t eq "pull"?" *":" ") . "r";
}
$typefamily{BITMAP} = {
DECL => \&DeclBitmap,
PUSH_FN_BODY => \&ParseBitmapPush,
PULL_FN_BODY => \&ParseBitmapPull,
PRINT_FN_BODY => \&ParseBitmapPrint,
};
#####################################################################
# generate a struct print function
sub ParseStructPrint($$)
{
my($struct,$name) = @_;
return unless defined $struct->{ELEMENTS};
my $env = GenerateStructEnv($struct);
EnvSubstituteValue($env, $struct);
DeclareArrayVariables($_) foreach (@{$struct->{ELEMENTS}});
pidl "ndr_print_struct(ndr, name, \"$name\");";
start_flags($struct);
pidl "ndr->depth++;";
ParseElementPrint($_, "r->$_->{NAME}", $env) foreach (@{$struct->{ELEMENTS}});
pidl "ndr->depth--;";
end_flags($struct);
}
sub DeclarePtrVariables($)
{
my $e = shift;
foreach my $l (@{$e->{LEVELS}}) {
if ($l->{TYPE} eq "POINTER" and
not ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "TOP")) {
pidl "uint32_t _ptr_$e->{NAME};";
last;
}
}
}
sub DeclareArrayVariables($)
{
my $e = shift;
foreach my $l (@{$e->{LEVELS}}) {
next if has_fast_array($e,$l);
next if is_charset_array($e,$l);
if ($l->{TYPE} eq "ARRAY") {
pidl "uint32_t cntr_$e->{NAME}_$l->{LEVEL_INDEX};";
}
}
}
sub need_decl_mem_ctx($$)
{
my ($e,$l) = @_;
return 0 if has_fast_array($e,$l);
return 0 if is_charset_array($e,$l);
return 1 if (($l->{TYPE} eq "ARRAY") and not $l->{IS_FIXED});
if (($l->{TYPE} eq "POINTER") and ($l->{POINTER_TYPE} eq "ref")) {
my $nl = GetNextLevel($e, $l);
my $next_is_array = ($nl->{TYPE} eq "ARRAY");
my $next_is_string = (($nl->{TYPE} eq "DATA") and
($nl->{DATA_TYPE} eq "string"));
return 0 if ($next_is_array or $next_is_string);
}
return 1 if ($l->{TYPE} eq "POINTER");
return 0;
}
sub DeclareMemCtxVariables($)
{
my $e = shift;
foreach my $l (@{$e->{LEVELS}}) {
if (need_decl_mem_ctx($e, $l)) {
pidl "TALLOC_CTX *_mem_save_$e->{NAME}_$l->{LEVEL_INDEX};";
}
}
}
#####################################################################
# parse a struct - pull side
sub ParseStructPull($$)
{
my($struct,$name) = @_;
return unless defined $struct->{ELEMENTS};
my $env = GenerateStructEnv($struct);
# declare any internal pointers we need
foreach my $e (@{$struct->{ELEMENTS}}) {
DeclarePtrVariables($e);
DeclareArrayVariables($e);
DeclareMemCtxVariables($e);
}
# save the old relative_base_offset
pidl "uint32_t _save_relative_base_offset = ndr_pull_get_relative_base_offset(ndr);" if defined($struct->{PROPERTIES}{relative_base});
start_flags($struct);
pidl "if (ndr_flags & NDR_SCALARS) {";
indent;
if (defined $struct->{SURROUNDING_ELEMENT}) {
pidl "NDR_CHECK(ndr_pull_array_size(ndr, &r->$struct->{SURROUNDING_ELEMENT}->{NAME}));";
}
pidl "NDR_CHECK(ndr_pull_align(ndr, $struct->{ALIGN}));";
if (defined($struct->{PROPERTIES}{relative_base})) {
# set the current offset as base for relative pointers
# and store it based on the toplevel struct/union
pidl "NDR_CHECK(ndr_pull_setup_relative_base_offset1(ndr, r, ndr->offset));";
}
foreach my $e (@{$struct->{ELEMENTS}}) {
ParseElementPull($e, "ndr", $env, 1, 0);
}
add_deferred();
deindent;
pidl "}";
pidl "if (ndr_flags & NDR_BUFFERS) {";
indent;
if (defined($struct->{PROPERTIES}{relative_base})) {
# retrieve the current offset as base for relative pointers
# based on the toplevel struct/union
pidl "NDR_CHECK(ndr_pull_setup_relative_base_offset2(ndr, r));";
}
foreach my $e (@{$struct->{ELEMENTS}}) {
ParseElementPull($e, "ndr", $env, 0, 1);
}
add_deferred();
deindent;
pidl "}";
end_flags($struct);
# restore the old relative_base_offset
pidl "ndr_pull_restore_relative_base_offset(ndr, _save_relative_base_offset);" if defined($struct->{PROPERTIES}{relative_base});
}
#####################################################################
# calculate size of ndr struct
sub ParseStructNdrSize($$)
{
my ($t, $name) = @_;
my $sizevar;
if (my $flags = has_property($t, "flag")) {
pidl "flags |= $flags;";
}
pidl "return ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_$name);";
}
sub DeclStruct($$$)
{
my ($e,$t,$name) = @_;
return ($t ne "pull"?"const ":"") . "struct $name *r";
}
sub ArgsStructNdrSize($$)
{
my ($d, $name) = @_;
return "const struct $name *r, int flags";
}
$typefamily{STRUCT} = {
PUSH_FN_BODY => \&ParseStructPush,
DECL => \&DeclStruct,
PULL_FN_BODY => \&ParseStructPull,
PRINT_FN_BODY => \&ParseStructPrint,
SIZE_FN_BODY => \&ParseStructNdrSize,
SIZE_FN_ARGS => \&ArgsStructNdrSize,
};
#####################################################################
# calculate size of ndr struct
sub ParseUnionNdrSize($$)
{
my ($t, $name) = @_;
my $sizevar;
if (my $flags = has_property($t, "flag")) {
pidl "flags |= $flags;";
}
pidl "return ndr_size_union(r, flags, level, (ndr_push_flags_fn_t)ndr_push_$name);";
}
#####################################################################
# parse a union - push side
sub ParseUnionPush($$)
{
my ($e,$name) = @_;
my $have_default = 0;
# save the old relative_base_offset
pidl "uint32_t _save_relative_base_offset = ndr_push_get_relative_base_offset(ndr);" if defined($e->{PROPERTIES}{relative_base});
pidl "int level;";
start_flags($e);
pidl "level = ndr_push_get_switch_value(ndr, r);";
pidl "if (ndr_flags & NDR_SCALARS) {";
indent;
if (defined($e->{SWITCH_TYPE})) {
pidl "NDR_CHECK(ndr_push_$e->{SWITCH_TYPE}(ndr, NDR_SCALARS, level));";
}
pidl "switch (level) {";
indent;
foreach my $el (@{$e->{ELEMENTS}}) {
if ($el->{CASE} eq "default") {
$have_default = 1;
}
pidl "$el->{CASE}:";
if ($el->{TYPE} ne "EMPTY") {
indent;
if (defined($e->{PROPERTIES}{relative_base})) {
pidl "NDR_CHECK(ndr_push_align(ndr, $el->{ALIGN}));";
# set the current offset as base for relative pointers
# and store it based on the toplevel struct/union
pidl "NDR_CHECK(ndr_push_setup_relative_base_offset1(ndr, r, ndr->offset));";
}
DeclareArrayVariables($el);
ParseElementPush($el, "ndr", {$el->{NAME} => "r->$el->{NAME}"}, 1, 0);
deindent;
}
pidl "break;";
pidl "";
}
if (! $have_default) {
pidl "default:";
pidl "\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
}
deindent;
pidl "}";
deindent;
pidl "}";
pidl "if (ndr_flags & NDR_BUFFERS) {";
indent;
if (defined($e->{PROPERTIES}{relative_base})) {
# retrieve the current offset as base for relative pointers
# based on the toplevel struct/union
pidl "NDR_CHECK(ndr_push_setup_relative_base_offset2(ndr, r));";
}
pidl "switch (level) {";
indent;
foreach my $el (@{$e->{ELEMENTS}}) {
pidl "$el->{CASE}:";
if ($el->{TYPE} ne "EMPTY") {
indent;
ParseElementPush($el, "ndr", {$el->{NAME} => "r->$el->{NAME}"}, 0, 1);
deindent;
}
pidl "break;";
pidl "";
}
if (! $have_default) {
pidl "default:";
pidl "\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
}
deindent;
pidl "}";
deindent;
pidl "}";
end_flags($e);
# restore the old relative_base_offset
pidl "ndr_push_restore_relative_base_offset(ndr, _save_relative_base_offset);" if defined($e->{PROPERTIES}{relative_base});
}
#####################################################################
# print a union
sub ParseUnionPrint($$)
{
my ($e,$name) = @_;
my $have_default = 0;
pidl "int level;";
foreach my $el (@{$e->{ELEMENTS}}) {
DeclareArrayVariables($el);
}
start_flags($e);
pidl "level = ndr_print_get_switch_value(ndr, r);";
pidl "ndr_print_union(ndr, name, level, \"$name\");";
pidl "switch (level) {";
indent;
foreach my $el (@{$e->{ELEMENTS}}) {
if ($el->{CASE} eq "default") {
$have_default = 1;
}
pidl "$el->{CASE}:";
if ($el->{TYPE} ne "EMPTY") {
indent;
ParseElementPrint($el, "r->$el->{NAME}", {});
deindent;
}
pidl "break;";
pidl "";
}
if (! $have_default) {
pidl "default:";
pidl "\tndr_print_bad_level(ndr, name, level);";
}
deindent;
pidl "}";
end_flags($e);
}
#####################################################################
# parse a union - pull side
sub ParseUnionPull($$)
{
my ($e,$name) = @_;
my $have_default = 0;
my $switch_type = $e->{SWITCH_TYPE};
# save the old relative_base_offset
pidl "uint32_t _save_relative_base_offset = ndr_pull_get_relative_base_offset(ndr);" if defined($e->{PROPERTIES}{relative_base});
pidl "int level;";
if (defined($switch_type)) {
if (Parse::Pidl::Typelist::typeIs($switch_type, "ENUM")) {
$switch_type = Parse::Pidl::Typelist::enum_type_fn(getType($switch_type)->{DATA});
}
pidl mapTypeName($switch_type) . " _level;";
}
my %double_cases = ();
foreach my $el (@{$e->{ELEMENTS}}) {
next if ($el->{TYPE} eq "EMPTY");
next if ($double_cases{"$el->{NAME}"});
DeclareMemCtxVariables($el);
$double_cases{"$el->{NAME}"} = 1;
}
start_flags($e);
pidl "level = ndr_pull_get_switch_value(ndr, r);";
pidl "if (ndr_flags & NDR_SCALARS) {";
indent;
if (defined($switch_type)) {
pidl "NDR_CHECK(ndr_pull_$switch_type(ndr, NDR_SCALARS, &_level));";
pidl "if (_level != level) {";
pidl "\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value %u for $name\", _level);";
pidl "}";
}
pidl "switch (level) {";
indent;
foreach my $el (@{$e->{ELEMENTS}}) {
if ($el->{CASE} eq "default") {
$have_default = 1;
}
pidl "$el->{CASE}: {";
if ($el->{TYPE} ne "EMPTY") {
indent;
DeclarePtrVariables($el);
DeclareArrayVariables($el);
if (defined($e->{PROPERTIES}{relative_base})) {
pidl "NDR_CHECK(ndr_pull_align(ndr, $el->{ALIGN}));";
# set the current offset as base for relative pointers
# and store it based on the toplevel struct/union
pidl "NDR_CHECK(ndr_pull_setup_relative_base_offset1(ndr, r, ndr->offset));";
}
ParseElementPull($el, "ndr", {$el->{NAME} => "r->$el->{NAME}"}, 1, 0);
deindent;
}
pidl "break; }";
pidl "";
}
if (! $have_default) {
pidl "default:";
pidl "\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
}
deindent;
pidl "}";
deindent;
pidl "}";
pidl "if (ndr_flags & NDR_BUFFERS) {";
indent;
if (defined($e->{PROPERTIES}{relative_base})) {
# retrieve the current offset as base for relative pointers
# based on the toplevel struct/union
pidl "NDR_CHECK(ndr_pull_setup_relative_base_offset2(ndr, r));";
}
pidl "switch (level) {";
indent;
foreach my $el (@{$e->{ELEMENTS}}) {
pidl "$el->{CASE}:";
if ($el->{TYPE} ne "EMPTY") {
indent;
ParseElementPull($el, "ndr", {$el->{NAME} => "r->$el->{NAME}"}, 0, 1);
deindent;
}
pidl "break;";
pidl "";
}
if (! $have_default) {
pidl "default:";
pidl "\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
}
deindent;
pidl "}";
deindent;
pidl "}";
add_deferred();
end_flags($e);
# restore the old relative_base_offset
pidl "ndr_pull_restore_relative_base_offset(ndr, _save_relative_base_offset);" if defined($e->{PROPERTIES}{relative_base});
}
sub DeclUnion($$$)
{
my ($e,$t,$name) = @_;
return ($t ne "pull"?"const ":"") . "union $name *r";
}
sub ArgsUnionNdrSize($$)
{
my ($d,$name) = @_;
return "const union $name *r, uint32_t level, int flags";
}
$typefamily{UNION} = {
PUSH_FN_BODY => \&ParseUnionPush,
DECL => \&DeclUnion,
PULL_FN_BODY => \&ParseUnionPull,
PRINT_FN_BODY => \&ParseUnionPrint,
SIZE_FN_ARGS => \&ArgsUnionNdrSize,
SIZE_FN_BODY => \&ParseUnionNdrSize,
};
#####################################################################
# parse a typedef - push side
sub ParseTypedefPush($$)
{
my($e,$name) = @_;
$typefamily{$e->{DATA}->{TYPE}}->{PUSH_FN_BODY}->($e->{DATA}, $name);
}
#####################################################################
# parse a typedef - pull side
sub ParseTypedefPull($$)
{
my($e,$name) = @_;
$typefamily{$e->{DATA}->{TYPE}}->{PULL_FN_BODY}->($e->{DATA}, $name);
}
#####################################################################
# parse a typedef - print side
sub ParseTypedefPrint($$)
{
my($e,$name) = @_;
$typefamily{$e->{DATA}->{TYPE}}->{PRINT_FN_BODY}->($e->{DATA}, $name);
}
#####################################################################
## calculate the size of a structure
sub ParseTypedefNdrSize($$)
{
my($t,$name) = @_;
$typefamily{$t->{DATA}->{TYPE}}->{SIZE_FN_BODY}->($t->{DATA}, $name);
}
sub DeclTypedef($$$)
{
my ($e, $t, $name) = @_;
return $typefamily{$e->{DATA}->{TYPE}}->{DECL}->($e->{DATA}, $t, $name);
}
sub ArgsTypedefNdrSize($$)
{
my ($d, $name) = @_;
return $typefamily{$d->{DATA}->{TYPE}}->{SIZE_FN_ARGS}->($d->{DATA}, $name);
}
$typefamily{TYPEDEF} = {
PUSH_FN_BODY => \&ParseTypedefPush,
DECL => \&DeclTypedef,
PULL_FN_BODY => \&ParseTypedefPull,
PRINT_FN_BODY => \&ParseTypedefPrint,
SIZE_FN_ARGS => \&ArgsTypedefNdrSize,
SIZE_FN_BODY => \&ParseTypedefNdrSize,
};
#####################################################################
# parse a function - print side
sub ParseFunctionPrint($)
{
my($fn) = shift;
pidl_hdr "void ndr_print_$fn->{NAME}(struct ndr_print *ndr, const char *name, int flags, const struct $fn->{NAME} *r);";
return if has_property($fn, "noprint");
pidl "_PUBLIC_ void ndr_print_$fn->{NAME}(struct ndr_print *ndr, const char *name, int flags, const struct $fn->{NAME} *r)";
pidl "{";
indent;
foreach my $e (@{$fn->{ELEMENTS}}) {
DeclareArrayVariables($e);
}
pidl "ndr_print_struct(ndr, name, \"$fn->{NAME}\");";
pidl "ndr->depth++;";
pidl "if (flags & NDR_SET_VALUES) {";
pidl "\tndr->flags |= LIBNDR_PRINT_SET_VALUES;";
pidl "}";
pidl "if (flags & NDR_IN) {";
indent;
pidl "ndr_print_struct(ndr, \"in\", \"$fn->{NAME}\");";
pidl "ndr->depth++;";
my $env = GenerateFunctionInEnv($fn);
EnvSubstituteValue($env, $fn);
foreach my $e (@{$fn->{ELEMENTS}}) {
if (grep(/in/,@{$e->{DIRECTION}})) {
ParseElementPrint($e, $env->{$e->{NAME}}, $env);
}
}
pidl "ndr->depth--;";
deindent;
pidl "}";
pidl "if (flags & NDR_OUT) {";
indent;
pidl "ndr_print_struct(ndr, \"out\", \"$fn->{NAME}\");";
pidl "ndr->depth++;";
$env = GenerateFunctionOutEnv($fn);
foreach my $e (@{$fn->{ELEMENTS}}) {
if (grep(/out/,@{$e->{DIRECTION}})) {
ParseElementPrint($e, $env->{$e->{NAME}}, $env);
}
}
if ($fn->{RETURN_TYPE}) {
pidl "ndr_print_$fn->{RETURN_TYPE}(ndr, \"result\", r->out.result);";
}
pidl "ndr->depth--;";
deindent;
pidl "}";
pidl "ndr->depth--;";
deindent;
pidl "}";
pidl "";
}
#####################################################################
# parse a function
sub ParseFunctionPush($)
{
my($fn) = shift;
fn_declare("push", $fn, "NTSTATUS ndr_push_$fn->{NAME}(struct ndr_push *ndr, int flags, const struct $fn->{NAME} *r)") or return;
return if has_property($fn, "nopush");
pidl "{";
indent;
foreach my $e (@{$fn->{ELEMENTS}}) {
DeclareArrayVariables($e);
}
pidl "if (flags & NDR_IN) {";
indent;
my $env = GenerateFunctionInEnv($fn);
EnvSubstituteValue($env, $fn);
foreach my $e (@{$fn->{ELEMENTS}}) {
if (grep(/in/,@{$e->{DIRECTION}})) {
ParseElementPush($e, "ndr", $env, 1, 1);
}
}
deindent;
pidl "}";
pidl "if (flags & NDR_OUT) {";
indent;
$env = GenerateFunctionOutEnv($fn);
foreach my $e (@{$fn->{ELEMENTS}}) {
if (grep(/out/,@{$e->{DIRECTION}})) {
ParseElementPush($e, "ndr", $env, 1, 1);
}
}
if ($fn->{RETURN_TYPE}) {
pidl "NDR_CHECK(ndr_push_$fn->{RETURN_TYPE}(ndr, NDR_SCALARS, r->out.result));";
}
deindent;
pidl "}";
pidl "return NT_STATUS_OK;";
deindent;
pidl "}";
pidl "";
}
sub AllocateArrayLevel($$$$$)
{
my ($e,$l,$ndr,$env,$size) = @_;
my $var = ParseExpr($e->{NAME}, $env, $e->{ORIGINAL});
my $pl = GetPrevLevel($e, $l);
if (defined($pl) and
$pl->{TYPE} eq "POINTER" and
$pl->{POINTER_TYPE} eq "ref"
and not $l->{IS_ZERO_TERMINATED}) {
pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {";
pidl "\tNDR_PULL_ALLOC_N($ndr, $var, $size);";
pidl "}";
if (grep(/in/,@{$e->{DIRECTION}}) and
grep(/out/,@{$e->{DIRECTION}})) {
pidl "memcpy(r->out.$e->{NAME}, r->in.$e->{NAME}, $size * sizeof(*r->in.$e->{NAME}));";
}
return;
}
pidl "NDR_PULL_ALLOC_N($ndr, $var, $size);";
}
#####################################################################
# parse a function
sub ParseFunctionPull($)
{
my($fn) = shift;
# pull function args
fn_declare("pull", $fn, "NTSTATUS ndr_pull_$fn->{NAME}(struct ndr_pull *ndr, int flags, struct $fn->{NAME} *r)") or return;
pidl "{";
indent;
# declare any internal pointers we need
foreach my $e (@{$fn->{ELEMENTS}}) {
DeclarePtrVariables($e);
DeclareArrayVariables($e);
}
my %double_cases = ();
foreach my $e (@{$fn->{ELEMENTS}}) {
next if ($e->{TYPE} eq "EMPTY");
next if ($double_cases{"$e->{NAME}"});
DeclareMemCtxVariables($e);
$double_cases{"$e->{NAME}"} = 1;
}
pidl "if (flags & NDR_IN) {";
indent;
# auto-init the out section of a structure. I originally argued that
# this was a bad idea as it hides bugs, but coping correctly
# with initialisation and not wiping ref vars is turning
# out to be too tricky (tridge)
foreach my $e (@{$fn->{ELEMENTS}}) {
next unless grep(/out/, @{$e->{DIRECTION}});
pidl "ZERO_STRUCT(r->out);";
pidl "";
last;
}
my $env = GenerateFunctionInEnv($fn);
foreach my $e (@{$fn->{ELEMENTS}}) {
next unless (grep(/in/, @{$e->{DIRECTION}}));
ParseElementPull($e, "ndr", $env, 1, 1);
}
# allocate the "simple" out ref variables. FIXME: Shouldn't this have it's
# own flag rather than be in NDR_IN ?
foreach my $e (@{$fn->{ELEMENTS}}) {
next unless (grep(/out/, @{$e->{DIRECTION}}));
next unless ($e->{LEVELS}[0]->{TYPE} eq "POINTER" and
$e->{LEVELS}[0]->{POINTER_TYPE} eq "ref");
next if (($e->{LEVELS}[1]->{TYPE} eq "DATA") and
($e->{LEVELS}[1]->{DATA_TYPE} eq "string"));
next if (($e->{LEVELS}[1]->{TYPE} eq "ARRAY")
and $e->{LEVELS}[1]->{IS_ZERO_TERMINATED});
if ($e->{LEVELS}[1]->{TYPE} eq "ARRAY") {
my $size = ParseExprExt($e->{LEVELS}[1]->{SIZE_IS}, $env, $e->{ORIGINAL}, check_null_pointer($e, $env, \&pidl, "return NT_STATUS_INVALID_PARAMETER_MIX;"),
check_fully_dereferenced($e, $env));
pidl "NDR_PULL_ALLOC_N(ndr, r->out.$e->{NAME}, $size);";
if (grep(/in/, @{$e->{DIRECTION}})) {
pidl "memcpy(r->out.$e->{NAME}, r->in.$e->{NAME}, $size * sizeof(*r->in.$e->{NAME}));";
} else {
pidl "memset(r->out.$e->{NAME}, 0, $size * sizeof(*r->out.$e->{NAME}));";
}
} else {
pidl "NDR_PULL_ALLOC(ndr, r->out.$e->{NAME});";
if (grep(/in/, @{$e->{DIRECTION}})) {
pidl "*r->out.$e->{NAME} = *r->in.$e->{NAME};";
} else {
pidl "ZERO_STRUCTP(r->out.$e->{NAME});";
}
}
}
add_deferred();
deindent;
pidl "}";
pidl "if (flags & NDR_OUT) {";
indent;
$env = GenerateFunctionOutEnv($fn);
foreach my $e (@{$fn->{ELEMENTS}}) {
next unless grep(/out/, @{$e->{DIRECTION}});
ParseElementPull($e, "ndr", $env, 1, 1);
}
if ($fn->{RETURN_TYPE}) {
pidl "NDR_CHECK(ndr_pull_$fn->{RETURN_TYPE}(ndr, NDR_SCALARS, &r->out.result));";
}
add_deferred();
deindent;
pidl "}";
pidl "return NT_STATUS_OK;";
deindent;
pidl "}";
pidl "";
}
#####################################################################
# produce a function call table
sub FunctionTable($)
{
my($interface) = shift;
my $count = 0;
my $uname = uc $interface->{NAME};
return if ($#{$interface->{FUNCTIONS}}+1 == 0);
return unless defined ($interface->{PROPERTIES}->{uuid});
pidl "static const struct dcerpc_interface_call $interface->{NAME}\_calls[] = {";
foreach my $d (@{$interface->{FUNCTIONS}}) {
next if not defined($d->{OPNUM});
pidl "\t{";
pidl "\t\t\"$d->{NAME}\",";
pidl "\t\tsizeof(struct $d->{NAME}),";
pidl "\t\t(ndr_push_flags_fn_t) ndr_push_$d->{NAME},";
pidl "\t\t(ndr_pull_flags_fn_t) ndr_pull_$d->{NAME},";
pidl "\t\t(ndr_print_function_t) ndr_print_$d->{NAME},";
pidl "\t\t".($d->{ASYNC}?"True":"False").",";
pidl "\t},";
$count++;
}
pidl "\t{ NULL, 0, NULL, NULL, NULL, False }";
pidl "};";
pidl "";
pidl "static const char * const $interface->{NAME}\_endpoint_strings[] = {";
foreach my $ep (@{$interface->{ENDPOINTS}}) {
pidl "\t$ep, ";
}
my $endpoint_count = $#{$interface->{ENDPOINTS}}+1;
pidl "};";
pidl "";
pidl "static const struct dcerpc_endpoint_list $interface->{NAME}\_endpoints = {";
pidl "\t.count\t= $endpoint_count,";
pidl "\t.names\t= $interface->{NAME}\_endpoint_strings";
pidl "};";
pidl "";
if (! defined $interface->{PROPERTIES}->{authservice}) {
$interface->{PROPERTIES}->{authservice} = "\"host\"";
}
my @a = split / /, $interface->{PROPERTIES}->{authservice};
my $authservice_count = $#a + 1;
pidl "static const char * const $interface->{NAME}\_authservice_strings[] = {";
foreach my $ap (@a) {
pidl "\t$ap, ";
}
pidl "};";
pidl "";
pidl "static const struct dcerpc_authservice_list $interface->{NAME}\_authservices = {";
pidl "\t.count\t= $endpoint_count,";
pidl "\t.names\t= $interface->{NAME}\_authservice_strings";
pidl "};";
pidl "";
pidl "\nconst struct dcerpc_interface_table dcerpc_table_$interface->{NAME} = {";
pidl "\t.name\t\t= \"$interface->{NAME}\",";
pidl "\t.syntax_id\t= {";
pidl "\t\t" . print_uuid($interface->{UUID}) .",";
pidl "\t\tDCERPC_$uname\_VERSION";
pidl "\t},";
pidl "\t.helpstring\t= DCERPC_$uname\_HELPSTRING,";
pidl "\t.num_calls\t= $count,";
pidl "\t.calls\t\t= $interface->{NAME}\_calls,";
pidl "\t.endpoints\t= &$interface->{NAME}\_endpoints,";
pidl "\t.authservices\t= &$interface->{NAME}\_authservices";
pidl "};";
pidl "";
}
#####################################################################
# generate include statements for imported idl files
sub HeaderImport
{
my @imports = @_;
foreach (@imports) {
s/\.idl\"$//;
s/^\"//;
pidl choose_header("librpc/gen_ndr/ndr_$_\.h", "gen_ndr/ndr_$_.h");
}
}
#####################################################################
# generate include statements for included header files
sub HeaderInclude
{
my @includes = @_;
foreach (@includes) {
pidl_hdr "#include $_";
}
}
#####################################################################
# generate prototypes and defines for the interface definitions
# FIXME: these prototypes are for the DCE/RPC client functions, not the
# NDR parser and so do not belong here, technically speaking
sub HeaderInterface($)
{
my($interface) = shift;
my $count = 0;
pidl_hdr choose_header("librpc/ndr/libndr.h", "ndr.h");
if (has_property($interface, "object")) {
pidl choose_header("librpc/gen_ndr/ndr_orpc.h", "ndr/orpc.h");
}
if (defined $interface->{PROPERTIES}->{helper}) {
HeaderInclude(split / /, $interface->{PROPERTIES}->{helper});
}
if (defined $interface->{PROPERTIES}->{uuid}) {
my $name = uc $interface->{NAME};
pidl_hdr "#define DCERPC_$name\_UUID " .
Parse::Pidl::Util::make_str(lc($interface->{PROPERTIES}->{uuid}));
if(!defined $interface->{PROPERTIES}->{version}) { $interface->{PROPERTIES}->{version} = "0.0"; }
pidl_hdr "#define DCERPC_$name\_VERSION $interface->{PROPERTIES}->{version}";
pidl_hdr "#define DCERPC_$name\_NAME \"$interface->{NAME}\"";
if(!defined $interface->{PROPERTIES}->{helpstring}) { $interface->{PROPERTIES}->{helpstring} = "NULL"; }
pidl_hdr "#define DCERPC_$name\_HELPSTRING $interface->{PROPERTIES}->{helpstring}";
pidl_hdr "extern const struct dcerpc_interface_table dcerpc_table_$interface->{NAME};";
pidl_hdr "NTSTATUS dcerpc_server_$interface->{NAME}_init(void);";
}
foreach (@{$interface->{FUNCTIONS}}) {
next if has_property($_, "noopnum");
next if grep(/$_->{NAME}/,@{$interface->{INHERITED_FUNCTIONS}});
my $u_name = uc $_->{NAME};
my $val = sprintf("0x%02x", $count);
if (defined($interface->{BASE})) {
$val .= " + DCERPC_" . uc $interface->{BASE} . "_CALL_COUNT";
}
pidl_hdr "#define DCERPC_$u_name ($val)";
pidl_hdr "";
$count++;
}
my $val = $count;
if (defined($interface->{BASE})) {
$val .= " + DCERPC_" . uc $interface->{BASE} . "_CALL_COUNT";
}
pidl_hdr "#define DCERPC_" . uc $interface->{NAME} . "_CALL_COUNT ($val)";
}
sub ParseTypePush($)
{
my ($e) = @_;
my $args = $typefamily{$e->{TYPE}}->{DECL}->($e, "push", $e->{NAME});
fn_declare("push", $e, "NTSTATUS ndr_push_$e->{NAME}(struct ndr_push *ndr, int ndr_flags, $args)") or return;
pidl "{";
indent;
$typefamily{$e->{TYPE}}->{PUSH_FN_BODY}->($e, $e->{NAME});
pidl "return NT_STATUS_OK;";
deindent;
pidl "}";
pidl "";;
}
sub ParseTypePull($)
{
my ($e) = @_;
my $args = $typefamily{$e->{TYPE}}->{DECL}->($e, "pull", $e->{NAME});
fn_declare("pull", $e, "NTSTATUS ndr_pull_$e->{NAME}(struct ndr_pull *ndr, int ndr_flags, $args)") or return;
pidl "{";
indent;
$typefamily{$e->{TYPE}}->{PULL_FN_BODY}->($e, $e->{NAME});
pidl "return NT_STATUS_OK;";
deindent;
pidl "}";
pidl "";
}
sub ParseTypePrint($)
{
my ($e) = @_;
my $args = $typefamily{$e->{TYPE}}->{DECL}->($e, "print", $e->{NAME});
pidl_hdr "void ndr_print_$e->{NAME}(struct ndr_print *ndr, const char *name, $args);";
return if (has_property($e, "noprint"));
pidl "_PUBLIC_ void ndr_print_$e->{NAME}(struct ndr_print *ndr, const char *name, $args)";
pidl "{";
indent;
$typefamily{$e->{TYPE}}->{PRINT_FN_BODY}->($e, $e->{NAME});
deindent;
pidl "}";
pidl "";
}
sub ParseTypeNdrSize($)
{
my ($t) = @_;
my $tf = $typefamily{$t->{TYPE}};
my $args = $tf->{SIZE_FN_ARGS}->($t, $t->{NAME});
fn_declare("size", $t, "size_t ndr_size_$t->{NAME}($args)") or return;
pidl "{";
indent;
$typefamily{$t->{TYPE}}->{SIZE_FN_BODY}->($t, $t->{NAME});
deindent;
pidl "}";
pidl "";
}
#####################################################################
# parse the interface definitions
sub ParseInterface($$)
{
my($interface,$needed) = @_;
pidl_hdr "#ifndef _HEADER_NDR_$interface->{NAME}";
pidl_hdr "#define _HEADER_NDR_$interface->{NAME}";
pidl_hdr "";
if ($needed->{"compression"}) {
pidl choose_header("librpc/ndr/ndr_compression.h", "ndr/compression.h");
}
HeaderInterface($interface);
# Typedefs
foreach my $d (@{$interface->{TYPES}}) {
($needed->{"push_$d->{NAME}"}) && ParseTypePush($d);
($needed->{"pull_$d->{NAME}"}) && ParseTypePull($d);
($needed->{"print_$d->{NAME}"}) && ParseTypePrint($d);
# Make sure we don't generate a function twice...
$needed->{"push_$d->{NAME}"} = $needed->{"pull_$d->{NAME}"} =
$needed->{"print_$d->{NAME}"} = 0;
($needed->{"ndr_size_$d->{NAME}"}) && ParseTypeNdrSize($d);
}
# Functions
foreach my $d (@{$interface->{FUNCTIONS}}) {
($needed->{"push_$d->{NAME}"}) && ParseFunctionPush($d);
($needed->{"pull_$d->{NAME}"}) && ParseFunctionPull($d);
($needed->{"print_$d->{NAME}"}) && ParseFunctionPrint($d);
# Make sure we don't generate a function twice...
$needed->{"push_$d->{NAME}"} = $needed->{"pull_$d->{NAME}"} =
$needed->{"print_$d->{NAME}"} = 0;
}
FunctionTable($interface);
pidl_hdr "#endif /* _HEADER_NDR_$interface->{NAME} */";
}
sub GenerateIncludes()
{
if (is_intree()) {
pidl "#include \"includes.h\"";
} else {
pidl "#define _GNU_SOURCE";
pidl "#include <stdint.h>";
pidl "#include <stdlib.h>";
pidl "#include <stdio.h>";
pidl "#include <stdbool.h>";
pidl "#include <stdarg.h>";
pidl "#include <string.h>";
}
# Samba3 has everything in include/includes.h
if (is_intree() != 3) {
pidl choose_header("libcli/util/nterr.h", "core/nterr.h");
pidl choose_header("librpc/gen_ndr/ndr_misc.h", "gen_ndr/ndr_misc.h");
pidl choose_header("librpc/gen_ndr/ndr_dcerpc.h", "gen_ndr/ndr_dcerpc.h");
pidl choose_header("librpc/rpc/dcerpc.h", "dcerpc.h"); #FIXME: This shouldn't be here!
}
}
#####################################################################
# parse a parsed IDL structure back into an IDL file
sub Parse($$$)
{
my($ndr,$gen_header,$ndr_header) = @_;
$tabs = "";
$res = "";
$res_hdr = "";
pidl_hdr "/* header auto-generated by pidl */";
pidl_hdr "";
pidl_hdr "#include \"$gen_header\"" if ($gen_header);
pidl_hdr "";
pidl "/* parser auto-generated by pidl */";
pidl "";
GenerateIncludes();
pidl "#include \"$ndr_header\"" if ($ndr_header);
pidl "";
my %needed = ();
foreach (@{$ndr}) {
($_->{TYPE} eq "INTERFACE") && NeededInterface($_, \%needed);
}
foreach (@{$ndr}) {
($_->{TYPE} eq "INTERFACE") && ParseInterface($_, \%needed);
($_->{TYPE} eq "IMPORT") && HeaderImport(@{$_->{PATHS}});
($_->{TYPE} eq "INCLUDE") && HeaderInclude(@{$_->{PATHS}});
}
return ($res_hdr, $res);
}
sub NeededElement($$$)
{
my ($e, $dir, $needed) = @_;
return if ($e->{TYPE} eq "EMPTY");
my @fn = ();
if ($dir eq "print") {
push(@fn, "print_$e->{REPRESENTATION_TYPE}");
} elsif ($dir eq "pull") {
push (@fn, "pull_$e->{TYPE}");
push (@fn, "ndr_$e->{TYPE}_to_$e->{REPRESENTATION_TYPE}")
if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE});
} elsif ($dir eq "push") {
push (@fn, "push_$e->{TYPE}");
push (@fn, "ndr_$e->{REPRESENTATION_TYPE}_to_$e->{TYPE}")
if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE});
} else {
die("invalid direction `$dir'");
}
foreach (@fn) {
unless (defined($needed->{$_})) {
$needed->{$_} = 1;
}
}
}
sub NeededFunction($$)
{
my ($fn,$needed) = @_;
$needed->{"pull_$fn->{NAME}"} = 1;
$needed->{"push_$fn->{NAME}"} = 1;
$needed->{"print_$fn->{NAME}"} = 1;
foreach my $e (@{$fn->{ELEMENTS}}) {
$e->{PARENT} = $fn;
NeededElement($e, $_, $needed) foreach ("pull", "push", "print");
}
}
sub NeededType($$)
{
my ($t,$needed) = @_;
if (has_property($t, "public")) {
$needed->{"pull_$t->{NAME}"} = 1;
$needed->{"push_$t->{NAME}"} = 1;
$needed->{"print_$t->{NAME}"} = 1;
}
if ($t->{DATA}->{TYPE} eq "STRUCT" or $t->{DATA}->{TYPE} eq "UNION") {
if (has_property($t, "gensize")) {
$needed->{"ndr_size_$t->{NAME}"} = 1;
}
for my $e (@{$t->{DATA}->{ELEMENTS}}) {
$e->{PARENT} = $t->{DATA};
if (has_property($e, "compression")) {
$needed->{"compression"} = 1;
}
NeededElement($e, "pull", $needed) if ($needed->{"pull_$t->{NAME}"});
NeededElement($e, "push", $needed) if ($needed->{"push_$t->{NAME}"});
NeededElement($e, "print", $needed) if ($needed->{"print_$t->{NAME}"});
}
}
}
#####################################################################
# work out what parse functions are needed
sub NeededInterface($$)
{
my ($interface,$needed) = @_;
NeededFunction($_, $needed) foreach (@{$interface->{FUNCTIONS}});
NeededType($_, $needed) foreach (reverse @{$interface->{TYPES}});
}
1;