r21484: Fix Needed* for nested datastructures.
[samba.git] / source4 / pidl / lib / Parse / Pidl / Samba4 / NDR / Parser.pm
index feab825a3f5d62fd1c1a86f512bddd0b60cac73d..2ae4a3b17ef9752b04724f58f708695b0f60c7a5 100644 (file)
@@ -7,11 +7,19 @@
 
 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 $res NeededInterface);
+
 use strict;
-use Parse::Pidl::Typelist qw(hasType getType mapType);
-use Parse::Pidl::Util qw(has_property ParseExpr print_uuid);
+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';
@@ -102,8 +110,8 @@ sub get_value_of($)
        }
 }
 
-my $res;
-my $deferred = "";
+our $res;
+my $deferred = [];
 my $tabs = "";
 
 ####################################
@@ -128,14 +136,16 @@ sub pidl_hdr ($) { my $d = shift; $res_hdr .= "$d\n"; }
 # 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) {
-               $deferred .= $tabs;
-               $deferred .= $d;
+               push(@$deferred, $defer_tabs.$d);
        }
-       $deferred .="\n";
 }
 
 ########################################
@@ -143,8 +153,9 @@ sub defer($)
 # output
 sub add_deferred()
 {
-       $res .= $deferred;
-       $deferred = "";
+       pidl $_ foreach (@$deferred);
+       $deferred = [];
+       $defer_tabs = "";
 }
 
 sub indent()
@@ -158,45 +169,15 @@ sub deindent()
 }
 
 #####################################################################
-# check that a variable we get from ParseExpr isn't a null pointer
-sub check_null_pointer($)
-{
-       my $size = shift;
-       if ($size =~ /^\*/) {
-               my $size2 = substr($size, 1);
-               pidl "if ($size2 == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;";
-       }
-}
-
-#####################################################################
-# check that a variable we get from ParseExpr isn't a null pointer, 
-# putting the check at the end of the structure/function
-sub check_null_pointer_deferred($)
+# declare a function public or static, depending on its attributes
+sub fn_declare($$$)
 {
-       my $size = shift;
-       if ($size =~ /^\*/) {
-               my $size2 = substr($size, 1);
-               defer "if ($size2 == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;";
-       }
-}
+       my ($type,$fn,$decl) = @_;
 
-#####################################################################
-# check that a variable we get from ParseExpr isn't a null pointer
-# void return varient
-sub check_null_pointer_void($)
-{
-       my $size = shift;
-       if ($size =~ /^\*/) {
-               my $size2 = substr($size, 1);
-               pidl "if ($size2 == NULL) return;";
+       if (has_property($fn, "no$type")) {
+               pidl_hdr "$decl;";
+               return 0;
        }
-}
-
-#####################################################################
-# declare a function public or static, depending on its attributes
-sub fn_declare($$)
-{
-       my ($fn,$decl) = @_;
 
        if (has_property($fn, "public")) {
                pidl_hdr "$decl;";
@@ -204,6 +185,8 @@ sub fn_declare($$)
        } else {
                pidl "static $decl";
        }
+
+       return 1;
 }
 
 ###################################################################
@@ -233,16 +216,16 @@ sub end_flags($)
        }
 }
 
-sub GenerateStructEnv($)
+sub GenerateStructEnv($$)
 {
-       my $x = shift;
+       my ($x, $v) = @_;
        my %env;
 
        foreach my $e (@{$x->{ELEMENTS}}) {
-               $env{$e->{NAME}} = "r->$e->{NAME}";
+               $env{$e->{NAME}} = "$v->$e->{NAME}";
        }
 
-       $env{"this"} = "r";
+       $env{"this"} = $v;
 
        return \%env;
 }
@@ -253,9 +236,9 @@ sub EnvSubstituteValue($$)
 
        # Substitute the value() values in the env
        foreach my $e (@{$s->{ELEMENTS}}) {
-               next unless (my $v = has_property($e, "value"));
+               next unless (defined(my $v = has_property($e, "value")));
                
-               $env->{$e->{NAME}} = ParseExpr($v, $env);
+               $env->{$e->{NAME}} = ParseExpr($v, $env, $e);
        }
 
        return $env;
@@ -307,8 +290,8 @@ sub ParseArrayPushHeader($$$$$)
                        $size = $length = "ndr_string_length($var_name, sizeof(*$var_name))";
                }
        } else {
-               $size = ParseExpr($l->{SIZE_IS}, $env);
-               $length = ParseExpr($l->{LENGTH_IS}, $env);
+               $size = ParseExpr($l->{SIZE_IS}, $env, $e);
+               $length = ParseExpr($l->{LENGTH_IS}, $env, $e);
        }
 
        if ((!$l->{IS_SURROUNDING}) and $l->{IS_CONFORMANT}) {
@@ -323,6 +306,106 @@ sub ParseArrayPushHeader($$$$$)
        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($$$$$)
@@ -337,21 +420,19 @@ sub ParseArrayPullHeader($$$$$)
        } elsif ($l->{IS_ZERO_TERMINATED}) { # Noheader arrays
                $length = $size = "ndr_get_string_size($ndr, sizeof(*$var_name))";
        } else {
-               $length = $size = ParseExpr($l->{SIZE_IS}, $env);
+               $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) .")";
        }
 
-       check_null_pointer($length);
-
        if ($length ne $size) {
                pidl "if ($length > $size) {";
                indent;
@@ -361,18 +442,22 @@ sub ParseArrayPullHeader($$$$$)
        }
 
        if ($l->{IS_CONFORMANT} and not $l->{IS_ZERO_TERMINATED}) {
-               my $size = ParseExpr($l->{SIZE_IS}, $env);
                defer "if ($var_name) {";
-               check_null_pointer_deferred($size);
+               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}) {
-               my $length = ParseExpr($l->{LENGTH_IS}, $env);
                defer "if ($var_name) {";
-               check_null_pointer_deferred($length);
+               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 "}"
        }
 
@@ -385,29 +470,26 @@ sub ParseArrayPullHeader($$$$$)
 
 sub compression_alg($$)
 {
-       my ($e,$l) = @_;
-       my $compression = $l->{COMPRESSION};
-       my ($alg, $clen, $dlen) = split(/ /, $compression);
+       my ($e, $l) = @_;
+       my ($alg, $clen, $dlen) = split(/ /, $l->{COMPRESSION});
 
        return $alg;
 }
 
 sub compression_clen($$$)
 {
-       my ($e,$l,$env) = @_;
-       my $compression = $l->{COMPRESSION};
-       my ($alg, $clen, $dlen) = split(/ /, $compression);
+       my ($e, $l, $env) = @_;
+       my ($alg, $clen, $dlen) = split(/ /, $l->{COMPRESSION});
 
-       return ParseExpr($clen, $env);
+       return ParseExpr($clen, $env, $e->{ORIGINAL});
 }
 
 sub compression_dlen($$$)
 {
        my ($e,$l,$env) = @_;
-       my $compression = $l->{COMPRESSION};
-       my ($alg, $clen, $dlen) = split(/ /, $compression);
+       my ($alg, $clen, $dlen) = split(/ /, $l->{COMPRESSION});
 
-       return ParseExpr($dlen, $env);
+       return ParseExpr($dlen, $env, $e->{ORIGINAL});
 }
 
 sub ParseCompressionPushStart($$$$)
@@ -464,47 +546,11 @@ sub ParseCompressionPullEnd($$$$)
        pidl "}";
 }
 
-sub ParseObfuscationPushStart($$)
-{
-       my ($e,$ndr) = @_;
-       my $obfuscation = has_property($e, "obfuscation");
-
-       pidl "NDR_CHECK(ndr_push_obfuscation_start($ndr, $obfuscation));";
-
-       return $ndr;
-}
-
-sub ParseObfuscationPushEnd($$)
-{
-       my ($e,$ndr) = @_;
-       my $obfuscation = has_property($e, "obfuscation");
-
-       pidl "NDR_CHECK(ndr_push_obfuscation_end($ndr, $obfuscation));";
-}
-
-sub ParseObfuscationPullStart($$)
-{
-       my ($e,$ndr) = @_;
-       my $obfuscation = has_property($e, "obfuscation");
-
-       pidl "NDR_CHECK(ndr_pull_obfuscation_start($ndr, $obfuscation));";
-
-       return $ndr;
-}
-
-sub ParseObfuscationPullEnd($$)
-{
-       my ($e,$ndr) = @_;
-       my $obfuscation = has_property($e, "obfuscation");
-
-       pidl "NDR_CHECK(ndr_pull_obfuscation_end($ndr, $obfuscation));";
-}
-
 sub ParseSubcontextPushStart($$$$)
 {
        my ($e,$l,$ndr,$env) = @_;
        my $subndr = "_ndr_$e->{NAME}";
-       my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE},$env);
+       my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
 
        pidl "{";
        indent;
@@ -515,10 +561,6 @@ sub ParseSubcontextPushStart($$$$)
                $subndr = ParseCompressionPushStart($e, $l, $subndr, $env);
        }
 
-       if (defined $l->{OBFUSCATION}) {
-               $subndr = ParseObfuscationPushStart($e, $subndr);
-       }
-
        return $subndr;
 }
 
@@ -526,16 +568,12 @@ sub ParseSubcontextPushEnd($$$$)
 {
        my ($e,$l,$ndr,$env) = @_;
        my $subndr = "_ndr_$e->{NAME}";
-       my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE},$env);
+       my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
 
        if (defined $l->{COMPRESSION}) {
                ParseCompressionPushEnd($e, $l, $subndr, $env);
        }
 
-       if (defined $l->{OBFUSCATION}) {
-               ParseObfuscationPushEnd($e, $subndr);
-       }
-
        pidl "NDR_CHECK(ndr_push_subcontext_end($ndr, $subndr, $l->{HEADER_SIZE}, $subcontext_size));";
        deindent;
        pidl "}";
@@ -545,7 +583,7 @@ sub ParseSubcontextPullStart($$$$)
 {
        my ($e,$l,$ndr,$env) = @_;
        my $subndr = "_ndr_$e->{NAME}";
-       my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE},$env);
+       my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
 
        pidl "{";
        indent;
@@ -556,10 +594,6 @@ sub ParseSubcontextPullStart($$$$)
                $subndr = ParseCompressionPullStart($e, $l, $subndr, $env);
        }
 
-       if (defined $l->{OBFUSCATION}) {
-               $subndr = ParseObfuscationPullStart($e, $subndr);
-       }
-       
        return $subndr;
 }
 
@@ -567,16 +601,12 @@ sub ParseSubcontextPullEnd($$$$)
 {
        my ($e,$l,$ndr,$env) = @_;
        my $subndr = "_ndr_$e->{NAME}";
-       my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE},$env);
+       my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
 
        if (defined $l->{COMPRESSION}) {
                ParseCompressionPullEnd($e, $l, $subndr, $env);
        }
 
-       if (defined $l->{OBFUSCATION}) {
-               ParseObfuscationPullEnd($e, $subndr);
-       }
-
        pidl "NDR_CHECK(ndr_pull_subcontext_end($ndr, $subndr, $l->{HEADER_SIZE}, $subcontext_size));";
        deindent;
        pidl "}";
@@ -606,16 +636,16 @@ sub ParseElementPushLevel
 
                        # 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(" . mapType($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));";
+                               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);
+                       ParseSwitchPush($e, $l, $ndr, $var_name, $env);
                } elsif ($l->{TYPE} eq "DATA") {
-                       ParseDataPush($e, $l, $ndr, $var_name, $ndr_flags);
+                       ParseDataPush($e, $l, $ndr, $var_name, $primitives, $deferred);
                }
        }
 
@@ -636,7 +666,7 @@ sub ParseElementPushLevel
                }
        } 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);
+               my $length = ParseExpr($l->{LENGTH_IS}, $env, $e->{ORIGINAL});
                my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
 
                $var_name = $var_name . "[$counter]";
@@ -663,38 +693,38 @@ sub ParseElementPushLevel
 
 #####################################################################
 # parse scalars in a structure element
-sub ParseElementPush($$$$$$)
+sub ParseElementPush($$$$$)
 {
-       my ($e,$ndr,$var_prefix,$env,$primitives,$deferred) = @_;
+       my ($e,$ndr,$env,$primitives,$deferred) = @_;
        my $subndr = undef;
 
-       my $var_name = $var_prefix.$e->{NAME};
-
-       $var_name = append_prefix($e, $var_name);
+       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}) {
+       if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
                pidl "{";
                indent;
                my $transmit_name = "_transmit_$e->{NAME}";
-               pidl mapType($e->{TYPE}) ." $transmit_name;";
-               pidl "NDR_CHECK(ndr_$e->{REPRESENTATION_TYPE}_to_$e->{TYPE}($var_name, $transmit_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 (my $value = has_property($e, "value")) {
-               $var_name = ParseExpr($value, $env);
+       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}) {
+       if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
                deindent;
                pidl "}";
        }
@@ -707,33 +737,60 @@ 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, $var_name));";
-               } else {
-                       check_null_pointer(get_value_of($var_name));
+                       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 "sptr") {
-               pidl "NDR_CHECK(ndr_push_sptr_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}");
        }
 }
 
+sub ParseDataPrint($$$)
+{
+       my ($e, $l, $var_name) = @_;
+       
+       if (not ref($l->{DATA_TYPE}) or 
+               defined($l->{DATA_TYPE}->{NAME})) {
+               my $t;
+               if (ref($l->{DATA_TYPE})) {
+                       $t = "$l->{DATA_TYPE}->{TYPE}_$l->{DATA_TYPE}->{NAME}";
+               } else {
+                       $t = $l->{DATA_TYPE};
+               }
+               if (not Parse::Pidl::Typelist::is_scalar($t) or 
+                       Parse::Pidl::Typelist::scalar_is_reference($t)) {
+                       $var_name = get_pointer_to($var_name);
+               }
+               pidl "ndr_print_$t(ndr, \"$e->{NAME}\", $var_name);";
+       } else {
+               ParseTypePrint($l->{DATA_TYPE}, $var_name);
+       }
+}
+
 #####################################################################
 # print scalars in a structure element
 sub ParseElementPrint($$$)
 {
-       my($e,$var_name,$env) = @_;
+       my($e, $var_name, $env) = @_;
 
-       $var_name = append_prefix($e, $var_name);
        return if (has_property($e, "noprint"));
 
-       if (my $value = has_property($e, "value")) {
-               $var_name = "(ndr->flags & LIBNDR_PRINT_SET_VALUES)?" . ParseExpr($value,$env) . ":$var_name";
+       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}}) {
@@ -755,7 +812,8 @@ sub ParseElementPrint($$$)
                        if ($l->{IS_ZERO_TERMINATED}) {
                                $length = "ndr_string_length($var_name, sizeof(*$var_name))";
                        } else {
-                               $length = ParseExpr($l->{LENGTH_IS}, $env);
+                               $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)) {
@@ -780,13 +838,10 @@ sub ParseElementPrint($$$)
                                $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);";
+                       ParseDataPrint($e, $l, $var_name);
                } elsif ($l->{TYPE} eq "SWITCH") {
-                       my $switch_var = ParseExpr($l->{SWITCH_IS}, $env);
-                       check_null_pointer_void($switch_var);
+                       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);";
                } 
        }
@@ -813,12 +868,11 @@ sub ParseElementPrint($$$)
 
 #####################################################################
 # parse scalars in a structure element - pull size
-sub ParseSwitchPull($$$$$$)
+sub ParseSwitchPull($$$$$)
 {
-       my($e,$l,$ndr,$var_name,$ndr_flags,$env) = @_;
-       my $switch_var = ParseExpr($l->{SWITCH_IS}, $env);
-
-       check_null_pointer($switch_var);
+       my($e,$l,$ndr,$var_name,$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));";
@@ -826,47 +880,74 @@ sub ParseSwitchPull($$$$$$)
 
 #####################################################################
 # push switch element
-sub ParseSwitchPush($$$$$$)
+sub ParseSwitchPush($$$$$)
 {
-       my($e,$l,$ndr,$var_name,$ndr_flags,$env) = @_;
-       my $switch_var = ParseExpr($l->{SWITCH_IS}, $env);
+       my($e,$l,$ndr,$var_name,$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));
 
-       check_null_pointer($switch_var);
        $var_name = get_pointer_to($var_name);
        pidl "NDR_CHECK(ndr_push_set_switch_value($ndr, $var_name, $switch_var));";
 }
 
-sub ParseDataPull($$$$$)
+sub ParseDataPull($$$$$$)
 {
-       my ($e,$l,$ndr,$var_name,$ndr_flags) = @_;
+       my ($e,$l,$ndr,$var_name,$primitives,$deferred) = @_;
 
-       if (Parse::Pidl::Typelist::scalar_is_reference($l->{DATA_TYPE})) {
-               $var_name = get_pointer_to($var_name);
-       }
+       if (not ref($l->{DATA_TYPE}) or 
+               defined($l->{DATA_TYPE}->{NAME})) {
 
-       $var_name = get_pointer_to($var_name);
+               my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
+               my $t;
+               if (ref($l->{DATA_TYPE}) eq "HASH") {
+                       $t = "$l->{DATA_TYPE}->{TYPE}_$l->{DATA_TYPE}->{NAME}";
+               } else {
+                       $t = $l->{DATA_TYPE};
+               }
+
+               if (Parse::Pidl::Typelist::scalar_is_reference($t)) {
+                       $var_name = get_pointer_to($var_name);
+               }
 
-       pidl "NDR_CHECK(ndr_pull_$l->{DATA_TYPE}($ndr, $ndr_flags, $var_name));";
+               $var_name = get_pointer_to($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 "}";
+               pidl "NDR_CHECK(ndr_pull_$t($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 "}";
+               }
+       } else {
+               ParseTypePull($l->{DATA_TYPE}, $var_name, $primitives, $deferred);
        }
 }
 
-sub ParseDataPush($$$$$)
+sub ParseDataPush($$$$$$)
 {
-       my ($e,$l,$ndr,$var_name,$ndr_flags) = @_;
+       my ($e,$l,$ndr,$var_name,$primitives,$deferred) = @_;
 
-       # strings are passed by value rather then 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);
-       }
+       if (not ref($l->{DATA_TYPE}) or defined($l->{DATA_TYPE}->{NAME})) {
+               my $t;
+               if (ref($l->{DATA_TYPE}) eq "HASH") {
+                       $t = "$l->{DATA_TYPE}->{TYPE}_$l->{DATA_TYPE}->{NAME}";
+               } else {
+                       $t = $l->{DATA_TYPE};
+               }
+                               
+               # strings are passed by value rather than reference
+               if (not Parse::Pidl::Typelist::is_scalar($t) or 
+                       Parse::Pidl::Typelist::scalar_is_reference($t)) {
+                       $var_name = get_pointer_to($var_name);
+               }
 
-       pidl "NDR_CHECK(ndr_push_$l->{DATA_TYPE}($ndr, $ndr_flags, $var_name));";
+               my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
+               pidl "NDR_CHECK(ndr_push_$t($ndr, $ndr_flags, $var_name));";
+       } else {
+               ParseTypePush($l->{DATA_TYPE}, $var_name, $primitives, $deferred);
+       }
 }
 
 sub CalcNdrFlags($$$)
@@ -896,9 +977,7 @@ sub CalcNdrFlags($$$)
 
 sub ParseMemCtxPullStart($$$)
 {
-       my $e = shift;
-       my $l = shift;
-       my $ptr_name = shift;
+       my ($e, $l, $ptr_name) = @_;
 
        my $mem_r_ctx = "_mem_save_$e->{NAME}_$l->{LEVEL_INDEX}";
        my $mem_c_ctx = $ptr_name;
@@ -981,7 +1060,7 @@ sub ParseElementPullLevel
                                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(" . mapType($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));";
+                               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}) {
@@ -993,9 +1072,9 @@ sub ParseElementPullLevel
                } 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);
+                       ParseSwitchPull($e, $l, $ndr, $var_name, $env);
                } elsif ($l->{TYPE} eq "DATA") {
-                       ParseDataPull($e, $l, $ndr, $var_name, $ndr_flags);
+                       ParseDataPull($e, $l, $ndr, $var_name, $primitives, $deferred);
                }
        }
 
@@ -1012,10 +1091,10 @@ sub ParseElementPullLevel
                        }
                }
 
-               ParseMemCtxPullStart($e,$l, $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);
+               ParseElementPullLevel($e, GetNextLevel($e,$l), $ndr, $var_name, $env, 1, 1);
 
                ParseMemCtxPullEnd($e,$l);
 
@@ -1028,13 +1107,13 @@ sub ParseElementPullLevel
                }
        } 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);
+               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);
+               ParseMemCtxPullStart($e, $l, $array_name);
 
                if (($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) {
                        my $nl = GetNextLevel($e,$l);
@@ -1058,30 +1137,32 @@ sub ParseElementPullLevel
                        pidl "}";
                }
 
-               ParseMemCtxPullEnd($e,$l);
+               ParseMemCtxPullEnd($e, $l);
 
        } elsif ($l->{TYPE} eq "SWITCH") {
-               ParseElementPullLevel($e,GetNextLevel($e,$l), $ndr, $var_name, $env, $primitives, $deferred);
+               ParseElementPullLevel($e, GetNextLevel($e,$l), $ndr, $var_name, $env, $primitives, $deferred);
        }
 }
 
 #####################################################################
 # parse scalars in a structure element - pull size
-sub ParseElementPull($$$$$$)
+sub ParseElementPull($$$$$)
 {
-       my($e,$ndr,$var_prefix,$env,$primitives,$deferred) = @_;
+       my($e,$ndr,$env,$primitives,$deferred) = @_;
 
-       my $var_name = $var_prefix.$e->{NAME};
+       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}) {
+       if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
                pidl "{";
                indent;
                $represent_name = $var_name;
-               $var_name = "_transmit_$e->{NAME}";
-               pidl mapType($e->{TYPE})." $var_name;";
+               $transmit_name = "_transmit_$e->{NAME}";
+               $var_name = $transmit_name;
+               pidl mapTypeName($e->{TYPE})." $var_name;";
        }
 
        $var_name = append_prefix($e, $var_name);
@@ -1093,8 +1174,8 @@ sub ParseElementPull($$$$$$)
        end_flags($e);
 
        # Representation type is different from transmit_as
-       if ($e->{REPRESENTATION_TYPE}) {
-               pidl "NDR_CHECK(ndr_$e->{TYPE}_to_$e->{REPRESENTATION_TYPE}($var_name, $represent_name));";
+       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 "}";
        }
@@ -1112,11 +1193,11 @@ sub ParsePtrPull($$$$)
                                                 ($nl->{DATA_TYPE} eq "string"));
 
        if ($l->{POINTER_TYPE} eq "ref") {
-               unless ($l->{LEVEL} eq "TOP") {
+               if ($l->{LEVEL} eq "EMBEDDED") {
                        pidl "NDR_CHECK(ndr_pull_ref_ptr($ndr, &_ptr_$e->{NAME}));";
                }
 
-               unless ($next_is_array or $next_is_string) {
+               if (!$next_is_array and !$next_is_string) {
                        pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {";
                        pidl "\tNDR_PULL_ALLOC($ndr, $var_name);"; 
                        pidl "}";
@@ -1125,7 +1206,7 @@ sub ParsePtrPull($$$$)
                return;
        } elsif (($l->{POINTER_TYPE} eq "unique") or 
                 ($l->{POINTER_TYPE} eq "relative") or
-                ($l->{POINTER_TYPE} eq "sptr")) {
+                ($l->{POINTER_TYPE} eq "full")) {
                pidl "NDR_CHECK(ndr_pull_generic_ptr($ndr, &_ptr_$e->{NAME}));";
                pidl "if (_ptr_$e->{NAME}) {";
                indent;
@@ -1142,7 +1223,7 @@ sub ParsePtrPull($$$$)
                # We allocate an array twice
                # - once just to indicate that it's there,
                # - then the real allocation...
-               pidl "NDR_PULL_ALLOC_SIZE($ndr, $var_name, 1);";
+               pidl "NDR_PULL_ALLOC($ndr, $var_name);";
        }
 
        #pidl "memset($var_name, 0, sizeof($var_name));";
@@ -1155,26 +1236,9 @@ sub ParsePtrPull($$$$)
        pidl "}";
 }
 
-#####################################################################
-# parse a struct
-sub ParseStructPush($$)
+sub ParseStructPushPrimitives($$$)
 {
-       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);
+       my ($struct, $varname, $env) = @_;
 
        # see if the structure contains a conformant array. If it
        # does, then it must be the last element of the structure, and
@@ -1190,66 +1254,82 @@ sub ParseStructPush($$)
                        
                        if ($e->{LEVELS}[0]->{IS_ZERO_TERMINATED}) {
                                if (has_property($e, "charset")) {
-                                       $size = "ndr_charset_length(r->$e->{NAME}, CH_$e->{PROPERTIES}->{charset})";
+                                       $size = "ndr_charset_length($varname->$e->{NAME}, CH_$e->{PROPERTIES}->{charset})";
                                } else {
-                                       $size = "ndr_string_length(r->$e->{NAME}, sizeof(*r->$e->{NAME}))";
+                                       $size = "ndr_string_length($varname->$e->{NAME}, sizeof(*$varname->$e->{NAME}))";
                                }
                        } else {
-                               $size = ParseExpr($e->{LEVELS}[0]->{SIZE_IS}, $env);
+                               $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 "NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_string_array_size(ndr, $varname->$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));";
+               pidl "NDR_CHECK(ndr_push_setup_relative_base_offset1(ndr, $varname, ndr->offset));";
        }
 
-       foreach my $e (@{$struct->{ELEMENTS}}) {
-               ParseElementPush($e, "ndr", "r->", $env, 1, 0);
-       }       
-
-       deindent;
-       pidl "}";
+       ParseElementPush($_, "ndr", $env, 1, 0) foreach (@{$struct->{ELEMENTS}});
+}
 
-       pidl "if (ndr_flags & NDR_BUFFERS) {";
-       indent;
+sub ParseStructPushDeferred($$$)
+{
+       my ($struct, $varname, $env) = @_;
        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", "r->", $env, 0, 1);
+               pidl "NDR_CHECK(ndr_push_setup_relative_base_offset2(ndr, $varname));";
        }
+       ParseElementPush($_, "ndr", $env, 0, 1) foreach (@{$struct->{ELEMENTS}});
+}
+
+#####################################################################
+# parse a struct
+sub ParseStructPush($$)
+{
+       my ($struct, $varname) = @_;
+       
+       return unless defined($struct->{ELEMENTS});
+
+       my $env = GenerateStructEnv($struct, $varname);
+
+       EnvSubstituteValue($env, $struct);
 
+       DeclareArrayVariables($_) foreach (@{$struct->{ELEMENTS}});
+
+       start_flags($struct);
+
+       pidl "if (ndr_flags & NDR_SCALARS) {";
+       indent;
+       ParseStructPushPrimitives($struct, $varname, $env);
+       deindent;
+       pidl "}";
+
+       pidl "if (ndr_flags & NDR_BUFFERS) {";
+       indent;
+       ParseStructPushDeferred($struct, $varname, $env);
        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($enum,$varname) = @_;
        my($type_fn) = $enum->{BASE_TYPE};
 
        start_flags($enum);
-       pidl "NDR_CHECK(ndr_push_$type_fn(ndr, NDR_SCALARS, r));";
+       pidl "NDR_CHECK(ndr_push_$type_fn(ndr, NDR_SCALARS, $varname));";
        end_flags($enum);
 }
 
@@ -1257,30 +1337,30 @@ sub ParseEnumPush($$)
 # generate a pull function for an enum
 sub ParseEnumPull($$)
 {
-       my($enum,$name) = @_;
+       my($enum,$varname) = @_;
        my($type_fn) = $enum->{BASE_TYPE};
-       my($type_v_decl) = mapType($type_fn);
+       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;";
+       pidl "*$varname = v;";
 
        end_flags($enum);
 }
 
 #####################################################################
 # generate a print function for an enum
-sub ParseEnumPrint($$)
+sub ParseEnumPrint($$$)
 {
-       my($enum,$name) = @_;
+       my($enum,$name,$varname) = @_;
 
        pidl "const char *val = NULL;";
        pidl "";
 
        start_flags($enum);
 
-       pidl "switch (r) {";
+       pidl "switch ($varname) {";
        indent;
        my $els = \@{$enum->{ELEMENTS}};
        foreach my $i (0 .. $#{$els}) {
@@ -1295,16 +1375,16 @@ sub ParseEnumPrint($$)
        deindent;
        pidl "}";
        
-       pidl "ndr_print_enum(ndr, name, \"$enum->{TYPE}\", val, r);";
+       pidl "ndr_print_enum(ndr, name, \"$enum->{TYPE}\", val, $varname);";
 
        end_flags($enum);
 }
 
-sub DeclEnum($)
+sub DeclEnum($$$$)
 {
-       my ($e,$t) = @_;
-       return "enum $e->{NAME} " . 
-               ($t eq "pull"?"*":"") . "r";
+       my ($e,$t,$name,$varname) = @_;
+       return "enum $name " . 
+               ($t eq "pull"?"*":"") . $varname;
 }
 
 $typefamily{ENUM} = {
@@ -1318,12 +1398,12 @@ $typefamily{ENUM} = {
 # generate a push function for a bitmap
 sub ParseBitmapPush($$)
 {
-       my($bitmap,$name) = @_;
+       my($bitmap,$varname) = @_;
        my($type_fn) = $bitmap->{BASE_TYPE};
 
        start_flags($bitmap);
 
-       pidl "NDR_CHECK(ndr_push_$type_fn(ndr, NDR_SCALARS, r));";
+       pidl "NDR_CHECK(ndr_push_$type_fn(ndr, NDR_SCALARS, $varname));";
 
        end_flags($bitmap);
 }
@@ -1332,24 +1412,24 @@ sub ParseBitmapPush($$)
 # generate a pull function for an bitmap
 sub ParseBitmapPull($$)
 {
-       my($bitmap,$name) = @_;
+       my($bitmap,$varname) = @_;
        my $type_fn = $bitmap->{BASE_TYPE};
-       my($type_decl) = mapType($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;";
+       pidl "*$varname = v;";
 
        end_flags($bitmap);
 }
 
 #####################################################################
 # generate a print function for an bitmap
-sub ParseBitmapPrintElement($$$)
+sub ParseBitmapPrintElement($$$$)
 {
-       my($e,$bitmap,$name) = @_;
-       my($type_decl) = mapType($bitmap->{BASE_TYPE});
+       my($e,$bitmap,$name,$varname) = @_;
+       my($type_decl) = mapTypeName($bitmap->{BASE_TYPE});
        my($type_fn) = $bitmap->{BASE_TYPE};
        my($flag);
 
@@ -1359,35 +1439,35 @@ sub ParseBitmapPrintElement($$$)
                die "Bitmap: \"$name\" invalid Flag: \"$e\"";
        }
 
-       pidl "ndr_print_bitmap_flag(ndr, sizeof($type_decl), \"$flag\", $flag, r);";
+       pidl "ndr_print_bitmap_flag(ndr, sizeof($type_decl), \"$flag\", $flag, $varname);";
 }
 
 #####################################################################
 # generate a print function for an bitmap
-sub ParseBitmapPrint($$)
+sub ParseBitmapPrint($$$)
 {
-       my($bitmap,$name) = @_;
-       my($type_decl) = mapType($bitmap->{TYPE});
+       my($bitmap,$name,$varname) = @_;
+       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_print_$type_fn(ndr, name, $varname);";
 
        pidl "ndr->depth++;";
        foreach my $e (@{$bitmap->{ELEMENTS}}) {
-               ParseBitmapPrintElement($e, $bitmap, $name);
+               ParseBitmapPrintElement($e, $bitmap, $name, $varname);
        }
        pidl "ndr->depth--;";
 
        end_flags($bitmap);
 }
 
-sub DeclBitmap($$)
+sub DeclBitmap($$$$)
 {
-       my ($e,$t) = @_;
-       return mapType(Parse::Pidl::Typelist::bitmap_type_fn($e->{DATA})) . 
-               ($t eq "pull"?" *":" ") . "r";
+       my ($e,$t,$name,$varname) = @_;
+       return mapTypeName(Parse::Pidl::Typelist::bitmap_type_fn($e)) . 
+               ($t eq "pull"?" *":" ") . $varname;
 }
 
 $typefamily{BITMAP} = {
@@ -1399,28 +1479,26 @@ $typefamily{BITMAP} = {
 
 #####################################################################
 # generate a struct print function
-sub ParseStructPrint($$)
+sub ParseStructPrint($$$)
 {
-       my($struct,$name) = @_;
+       my($struct,$name,$varname) = @_;
 
        return unless defined $struct->{ELEMENTS};
 
-       my $env = GenerateStructEnv($struct);
+       my $env = GenerateStructEnv($struct, $varname);
 
        EnvSubstituteValue($env, $struct);
 
-       foreach my $e (@{$struct->{ELEMENTS}}) {
-               DeclareArrayVariables($e);
-       }
+       DeclareArrayVariables($_) foreach (@{$struct->{ELEMENTS}});
 
        pidl "ndr_print_struct(ndr, name, \"$name\");";
 
        start_flags($struct);
 
        pidl "ndr->depth++;";
-       foreach my $e (@{$struct->{ELEMENTS}}) {
-               ParseElementPrint($e, "r->$e->{NAME}", $env);
-       }
+       
+       ParseElementPrint($_, $env->{$_->{NAME}}, $env) 
+               foreach (@{$struct->{ELEMENTS}});
        pidl "ndr->depth--;";
 
        end_flags($struct);
@@ -1453,8 +1531,7 @@ sub DeclareArrayVariables($)
 
 sub need_decl_mem_ctx($$)
 {
-       my $e = shift;
-       my $l = shift;
+       my ($e,$l) = @_;
 
        return 0 if has_fast_array($e,$l);
        return 0 if is_charset_array($e,$l);
@@ -1482,33 +1559,12 @@ sub DeclareMemCtxVariables($)
        }
 }
 
-#####################################################################
-# parse a struct - pull side
-sub ParseStructPull($$)
+sub ParseStructPullPrimitives($$$)
 {
-       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;
+       my($struct,$varname,$env) = @_;
 
        if (defined $struct->{SURROUNDING_ELEMENT}) {
-               pidl "NDR_CHECK(ndr_pull_array_size(ndr, &r->$struct->{SURROUNDING_ELEMENT}->{NAME}));";
+               pidl "NDR_CHECK(ndr_pull_array_size(ndr, &$varname->$struct->{SURROUNDING_ELEMENT}->{NAME}));";
        }
 
        pidl "NDR_CHECK(ndr_pull_align(ndr, $struct->{ALIGN}));";
@@ -1516,61 +1572,86 @@ sub ParseStructPull($$)
        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));";
+               pidl "NDR_CHECK(ndr_pull_setup_relative_base_offset1(ndr, $varname, ndr->offset));";
        }
 
-       foreach my $e (@{$struct->{ELEMENTS}}) {
-               ParseElementPull($e, "ndr", "r->", $env, 1, 0);
-       }       
+       ParseElementPull($_, "ndr", $env, 1, 0) foreach (@{$struct->{ELEMENTS}});
 
        add_deferred();
+}
+
+sub ParseStructPullDeferred($$$)
+{
+       my ($struct,$varname,$env) = @_;
 
-       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));";
+               pidl "NDR_CHECK(ndr_pull_setup_relative_base_offset2(ndr, $varname));";
        }
        foreach my $e (@{$struct->{ELEMENTS}}) {
-               ParseElementPull($e, "ndr", "r->", $env, 0, 1);
+               ParseElementPull($e, "ndr", $env, 0, 1);
        }
 
        add_deferred();
+}
+
+#####################################################################
+# parse a struct - pull side
+sub ParseStructPull($$)
+{
+       my($struct,$varname) = @_;
+
+       return unless defined $struct->{ELEMENTS};
+
+       # declare any internal pointers we need
+       foreach my $e (@{$struct->{ELEMENTS}}) {
+               DeclarePtrVariables($e);
+               DeclareArrayVariables($e);
+               DeclareMemCtxVariables($e);
+       }
+
+       start_flags($struct);
+
+       my $env = GenerateStructEnv($struct, $varname);
 
+       pidl "if (ndr_flags & NDR_SCALARS) {";
+       indent;
+       ParseStructPullPrimitives($struct,$varname,$env);
+       deindent;
+       pidl "}";
+       pidl "if (ndr_flags & NDR_BUFFERS) {";
+       indent;
+       ParseStructPullDeferred($struct,$varname,$env);
        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($)
+sub ParseStructNdrSize($$$)
 {
-       my $t = shift;
+       my ($t, $name, $varname) = @_;
        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_$t->{NAME});";
+       pidl "return ndr_size_struct($varname, flags, (ndr_push_flags_fn_t)ndr_push_$name);";
 }
 
-sub DeclStruct($)
+sub DeclStruct($$$$)
 {
-       my ($e,$t) = @_;
-       return ($t ne "pull"?"const ":"") . "struct $e->{NAME} *r";
+       my ($e,$t,$name,$varname) = @_;
+       return ($t ne "pull"?"const ":"") . "struct $name *$varname";
 }
 
-sub ArgsStructNdrSize($)
+sub ArgsStructNdrSize($$$)
 {
-       my $d = shift;
-       return "const struct $d->{NAME} *r, int flags";
+       my ($d, $name, $varname) = @_;
+       return "const struct $name *$varname, int flags";
 }
 
 $typefamily{STRUCT} = {
@@ -1584,35 +1665,25 @@ $typefamily{STRUCT} = {
 
 #####################################################################
 # calculate size of ndr struct
-sub ParseUnionNdrSize($)
+sub ParseUnionNdrSize($$$)
 {
-       my $t = shift;
+       my ($t, $name, $varname) = @_;
        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_$t->{NAME});";
+       pidl "return ndr_size_union($varname, flags, level, (ndr_push_flags_fn_t)ndr_push_$name);";
 }
 
-#####################################################################
-# parse a union - push side
-sub ParseUnionPush($$)
+sub ParseUnionPushPrimitives($$)
 {
-       my ($e,$name) = @_;
+       my ($e, $varname) = @_;
+
        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;
+       pidl "int level = ndr_push_get_switch_value(ndr, $varname);";
 
        if (defined($e->{SWITCH_TYPE})) {
                pidl "NDR_CHECK(ndr_push_$e->{SWITCH_TYPE}(ndr, NDR_SCALARS, level));";
@@ -1632,10 +1703,10 @@ sub ParseUnionPush($$)
                                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));";
+                               pidl "NDR_CHECK(ndr_push_setup_relative_base_offset1(ndr, $varname, ndr->offset));";
                        }
                        DeclareArrayVariables($el);
-                       ParseElementPush($el, "ndr", "r->", {}, 1, 0);
+                       ParseElementPush($el, "ndr", {$el->{NAME} => "$varname->$el->{NAME}"}, 1, 0);
                        deindent;
                }
                pidl "break;";
@@ -1647,22 +1718,31 @@ sub ParseUnionPush($$)
        }
        deindent;
        pidl "}";
-       deindent;
-       pidl "}";
-       pidl "if (ndr_flags & NDR_BUFFERS) {";
-       indent;
+}
+
+sub ParseUnionPushDeferred($$)
+{
+       my ($e, $varname) = @_;
+
+       my $have_default = 0;
+
+       pidl "int level = ndr_push_get_switch_value(ndr, $varname);";
        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 "NDR_CHECK(ndr_push_setup_relative_base_offset2(ndr, $varname));";
        }
        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;
-                       ParseElementPush($el, "ndr", "r->", {}, 0, 1);
+                       ParseElementPush($el, "ndr", {$el->{NAME} => "$varname->$el->{NAME}"}, 0, 1);
                        deindent;
                }
                pidl "break;";
@@ -1674,19 +1754,35 @@ sub ParseUnionPush($$)
        }
        deindent;
        pidl "}";
+}
+
+#####################################################################
+# parse a union - push side
+sub ParseUnionPush($$)
+{
+       my ($e,$varname) = @_;
+       my $have_default = 0;
 
+       start_flags($e);
+
+       pidl "if (ndr_flags & NDR_SCALARS) {";
+       indent;
+       ParseUnionPushPrimitives($e, $varname);
+       deindent;
+       pidl "}";
+       pidl "if (ndr_flags & NDR_BUFFERS) {";
+       indent;
+       ParseUnionPushDeferred($e, $varname);
        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($$)
+sub ParseUnionPrint($$$)
 {
-       my ($e,$name) = @_;
+       my ($e,$name,$varname) = @_;
        my $have_default = 0;
 
        pidl "int level;";
@@ -1696,7 +1792,7 @@ sub ParseUnionPrint($$)
 
        start_flags($e);
 
-       pidl "level = ndr_print_get_switch_value(ndr, r);";
+       pidl "level = ndr_print_get_switch_value(ndr, $varname);";
 
        pidl "ndr_print_union(ndr, name, level, \"$name\");";
 
@@ -1709,7 +1805,7 @@ sub ParseUnionPrint($$)
                pidl "$el->{CASE}:";
                if ($el->{TYPE} ne "EMPTY") {
                        indent;
-                       ParseElementPrint($el, "r->$el->{NAME}", {});
+                       ParseElementPrint($el, "$varname->$el->{NAME}", {});
                        deindent;
                }
                pidl "break;";
@@ -1725,43 +1821,15 @@ sub ParseUnionPrint($$)
        end_flags($e);
 }
 
-#####################################################################
-# parse a union - pull side
-sub ParseUnionPull($$)
+sub ParseUnionPullPrimitives($$$)
 {
-       my ($e,$name) = @_;
+       my ($e,$varname,$switch_type) = @_;
        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));
-               }
-               pidl mapType($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 "\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value %u for $varname\", _level);";
                pidl "}";
        }
 
@@ -1781,9 +1849,9 @@ sub ParseUnionPull($$)
                                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));";
+                               pidl "NDR_CHECK(ndr_pull_setup_relative_base_offset1(ndr, $varname, ndr->offset));";
                        }
-                       ParseElementPull($el, "ndr", "r->", {}, 1, 0);
+                       ParseElementPull($el, "ndr", {$el->{NAME} => "$varname->$el->{NAME}"}, 1, 0);
                        deindent;
                }
                pidl "break; }";
@@ -1795,22 +1863,29 @@ sub ParseUnionPull($$)
        }
        deindent;
        pidl "}";
-       deindent;
-       pidl "}";
-       pidl "if (ndr_flags & NDR_BUFFERS) {";
-       indent;
+}
+
+sub ParseUnionPullDeferred($$)
+{
+       my ($e,$varname) = @_;
+       my $have_default = 0;
+
        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 "NDR_CHECK(ndr_pull_setup_relative_base_offset2(ndr, $varname));";
        }
        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;
-                       ParseElementPull($el, "ndr", "r->", {}, 0, 1);
+                       ParseElementPull($el, "ndr", {$el->{NAME} => "$varname->$el->{NAME}"}, 0, 1);
                        deindent;
                }
                pidl "break;";
@@ -1823,26 +1898,63 @@ sub ParseUnionPull($$)
        deindent;
        pidl "}";
 
+
+}
+
+#####################################################################
+# parse a union - pull side
+sub ParseUnionPull($$)
+{
+       my ($e,$varname) = @_;
+       my $switch_type = $e->{SWITCH_TYPE};
+
+       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, $varname);";
+
+       pidl "if (ndr_flags & NDR_SCALARS) {";
+       indent;
+       ParseUnionPullPrimitives($e,$varname,$switch_type);
+       deindent;
+       pidl "}";
+
+       pidl "if (ndr_flags & NDR_BUFFERS) {";
+       indent;
+       ParseUnionPullDeferred($e,$varname);
        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($$)
+sub DeclUnion($$$$)
 {
-       my ($e,$t) = @_;
-       return ($t ne "pull"?"const ":"") . "union $e->{NAME} *r";
+       my ($e,$t,$name,$varname) = @_;
+       return ($t ne "pull"?"const ":"") . "union $name *$varname";
 }
 
-sub ArgsUnionNdrSize($)
+sub ArgsUnionNdrSize($$)
 {
-       my $d = shift;
-       return "const union $d->{NAME} *r, uint32_t level, int flags";
+       my ($d,$name) = @_;
+       return "const union $name *r, uint32_t level, int flags";
 }
 
 $typefamily{UNION} = {
@@ -1856,88 +1968,73 @@ $typefamily{UNION} = {
        
 #####################################################################
 # parse a typedef - push side
-sub ParseTypedefPush($)
+sub ParseTypedefPush($$)
 {
-       my($e) = shift;
-
-       my $args = $typefamily{$e->{DATA}->{TYPE}}->{DECL}->($e,"push");
-       fn_declare($e, "NTSTATUS ndr_push_$e->{NAME}(struct ndr_push *ndr, int ndr_flags, $args)");
+       my($e,$varname) = @_;
 
-       pidl "{";
-       indent;
-       $typefamily{$e->{DATA}->{TYPE}}->{PUSH_FN_BODY}->($e->{DATA}, $e->{NAME});
-       pidl "return NT_STATUS_OK;";
-       deindent;
-       pidl "}";
-       pidl "";;
+       $typefamily{$e->{DATA}->{TYPE}}->{PUSH_FN_BODY}->($e->{DATA}, $varname);
 }
 
 #####################################################################
 # parse a typedef - pull side
-sub ParseTypedefPull($)
+sub ParseTypedefPull($$)
 {
-       my($e) = shift;
+       my($e,$varname) = @_;
 
-       my $args = $typefamily{$e->{DATA}->{TYPE}}->{DECL}->($e,"pull");
-
-       fn_declare($e, "NTSTATUS ndr_pull_$e->{NAME}(struct ndr_pull *ndr, int ndr_flags, $args)");
-
-       pidl "{";
-       indent;
-       $typefamily{$e->{DATA}->{TYPE}}->{PULL_FN_BODY}->($e->{DATA}, $e->{NAME});
-       pidl "return NT_STATUS_OK;";
-       deindent;
-       pidl "}";
-       pidl "";
+       $typefamily{$e->{DATA}->{TYPE}}->{PULL_FN_BODY}->($e->{DATA}, $varname);
 }
 
 #####################################################################
 # parse a typedef - print side
-sub ParseTypedefPrint($)
+sub ParseTypedefPrint($$$)
 {
-       my($e) = shift;
-
-       my $args = $typefamily{$e->{DATA}->{TYPE}}->{DECL}->($e,"print");
+       my($e,$name,$varname) = @_;
 
-       pidl "_PUBLIC_ void ndr_print_$e->{NAME}(struct ndr_print *ndr, const char *name, $args)";
-       pidl_hdr "void ndr_print_$e->{NAME}(struct ndr_print *ndr, const char *name, $args);";
-       pidl "{";
-       indent;
-       $typefamily{$e->{DATA}->{TYPE}}->{PRINT_FN_BODY}->($e->{DATA}, $e->{NAME});
-       deindent;
-       pidl "}";
-       pidl "";
+       $typefamily{$e->{DATA}->{TYPE}}->{PRINT_FN_BODY}->($e->{DATA}, $name, $varname);
 }
 
 #####################################################################
 ## calculate the size of a structure
-sub ParseTypedefNdrSize($)
+sub ParseTypedefNdrSize($$$)
 {
-       my($t) = shift;
+       my($t,$name,$varname) = @_;
 
-       my $tf = $typefamily{$t->{DATA}->{TYPE}};
-       my $args = $tf->{SIZE_FN_ARGS}->($t);
+       $typefamily{$t->{DATA}->{TYPE}}->{SIZE_FN_BODY}->($t->{DATA}, $name, $varname);
+}
 
-       fn_declare($t, "size_t ndr_size_$t->{NAME}($args)");
+sub DeclTypedef($$$$)
+{
+       my ($e, $t, $name, $varname) = @_;
+       
+       return $typefamily{$e->{DATA}->{TYPE}}->{DECL}->($e->{DATA}, $t, $name, $varname);
+}
 
-       pidl "{";
-       indent;
-       $typefamily{$t->{DATA}->{TYPE}}->{SIZE_FN_BODY}->($t);
-       deindent;
-       pidl "}";
-       pidl "";
+sub ArgsTypedefNdrSize($$$)
+{
+       my ($d, $name, $varname) = @_;
+       return $typefamily{$d->{DATA}->{TYPE}}->{SIZE_FN_ARGS}->($d->{DATA}, $name, $varname);
 }
 
+$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_hdr "void ndr_print_$fn->{NAME}(struct ndr_print *ndr, const char *name, int flags, const struct $fn->{NAME} *r);";
        pidl "{";
        indent;
 
@@ -1962,7 +2059,7 @@ sub ParseFunctionPrint($)
 
        foreach my $e (@{$fn->{ELEMENTS}}) {
                if (grep(/in/,@{$e->{DIRECTION}})) {
-                       ParseElementPrint($e, "r->in.$e->{NAME}", $env);
+                       ParseElementPrint($e, $env->{$e->{NAME}}, $env);
                }
        }
        pidl "ndr->depth--;";
@@ -1977,7 +2074,7 @@ sub ParseFunctionPrint($)
        $env = GenerateFunctionOutEnv($fn);
        foreach my $e (@{$fn->{ELEMENTS}}) {
                if (grep(/out/,@{$e->{DIRECTION}})) {
-                       ParseElementPrint($e, "r->out.$e->{NAME}", $env);
+                       ParseElementPrint($e, $env->{$e->{NAME}}, $env);
                }
        }
        if ($fn->{RETURN_TYPE}) {
@@ -1999,9 +2096,9 @@ sub ParseFunctionPush($)
 { 
        my($fn) = shift;
 
-       return if has_property($fn, "nopush");
+       fn_declare("push", $fn, "NTSTATUS ndr_push_$fn->{NAME}(struct ndr_push *ndr, int flags, const struct $fn->{NAME} *r)") or return;
 
-       fn_declare($fn, "NTSTATUS ndr_push_$fn->{NAME}(struct ndr_push *ndr, int flags, const struct $fn->{NAME} *r)");
+       return if has_property($fn, "nopush");
 
        pidl "{";
        indent;
@@ -2019,7 +2116,7 @@ sub ParseFunctionPush($)
 
        foreach my $e (@{$fn->{ELEMENTS}}) {
                if (grep(/in/,@{$e->{DIRECTION}})) {
-                       ParseElementPush($e, "ndr", "r->in.", $env, 1, 1);
+                       ParseElementPush($e, "ndr", $env, 1, 1);
                }
        }
 
@@ -2032,7 +2129,7 @@ sub ParseFunctionPush($)
        $env = GenerateFunctionOutEnv($fn);
        foreach my $e (@{$fn->{ELEMENTS}}) {
                if (grep(/out/,@{$e->{DIRECTION}})) {
-                       ParseElementPush($e, "ndr", "r->out.", $env, 1, 1);
+                       ParseElementPush($e, "ndr", $env, 1, 1);
                }
        }
 
@@ -2052,9 +2149,8 @@ sub AllocateArrayLevel($$$$$)
 {
        my ($e,$l,$ndr,$env,$size) = @_;
 
-       my $var = ParseExpr($e->{NAME}, $env);
+       my $var = ParseExpr($e->{NAME}, $env, $e->{ORIGINAL});
 
-       check_null_pointer($size);
        my $pl = GetPrevLevel($e, $l);
        if (defined($pl) and 
            $pl->{TYPE} eq "POINTER" and 
@@ -2065,7 +2161,7 @@ sub AllocateArrayLevel($$$$$)
                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}));";
+                       pidl "memcpy(r->out.$e->{NAME}, r->in.$e->{NAME}, $size * sizeof(*r->in.$e->{NAME}));";
                }
                return;
        }
@@ -2079,10 +2175,9 @@ sub ParseFunctionPull($)
 { 
        my($fn) = shift;
 
-       return if has_property($fn, "nopull");
-
        # pull function args
-       fn_declare($fn, "NTSTATUS ndr_pull_$fn->{NAME}(struct ndr_pull *ndr, int flags, struct $fn->{NAME} *r)");
+       fn_declare("pull", $fn, "NTSTATUS ndr_pull_$fn->{NAME}(struct ndr_pull *ndr, int flags, struct $fn->{NAME} *r)") or return;
+
        pidl "{";
        indent;
 
@@ -2118,11 +2213,11 @@ sub ParseFunctionPull($)
 
        foreach my $e (@{$fn->{ELEMENTS}}) {
                next unless (grep(/in/, @{$e->{DIRECTION}}));
-               ParseElementPull($e, "ndr", "r->in.", $env, 1, 1);
+               ParseElementPull($e, "ndr", $env, 1, 1);
        }
 
        # allocate the "simple" out ref variables. FIXME: Shouldn't this have it's
-       # own flag rather then be in NDR_IN ?
+       # own flag rather than be in NDR_IN ?
 
        foreach my $e (@{$fn->{ELEMENTS}}) {
                next unless (grep(/out/, @{$e->{DIRECTION}}));
@@ -2134,8 +2229,8 @@ sub ParseFunctionPull($)
                        and   $e->{LEVELS}[1]->{IS_ZERO_TERMINATED});
 
                if ($e->{LEVELS}[1]->{TYPE} eq "ARRAY") {
-                       my $size = ParseExpr($e->{LEVELS}[1]->{SIZE_IS}, $env);
-                       check_null_pointer($size);
+                       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);";
 
@@ -2165,7 +2260,7 @@ sub ParseFunctionPull($)
        $env = GenerateFunctionOutEnv($fn);
        foreach my $e (@{$fn->{ELEMENTS}}) {
                next unless grep(/out/, @{$e->{DIRECTION}});
-               ParseElementPull($e, "ndr", "r->out.", $env, 1, 1);
+               ParseElementPull($e, "ndr", $env, 1, 1);
        }
 
        if ($fn->{RETURN_TYPE}) {
@@ -2247,8 +2342,10 @@ sub FunctionTable($)
 
        pidl "\nconst struct dcerpc_interface_table dcerpc_table_$interface->{NAME} = {";
        pidl "\t.name\t\t= \"$interface->{NAME}\",";
-       pidl "\t.uuid\t\t= ". print_uuid($interface->{UUID}) .",";
-       pidl "\t.if_version\t= DCERPC_$uname\_VERSION,";
+       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,";
@@ -2259,6 +2356,28 @@ sub FunctionTable($)
 
 }
 
+#####################################################################
+# 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 
@@ -2275,17 +2394,8 @@ sub HeaderInterface($)
                pidl choose_header("librpc/gen_ndr/ndr_orpc.h", "ndr/orpc.h");
        }
 
-       if (defined $interface->{PROPERTIES}->{depends}) {
-               my @d = split / /, $interface->{PROPERTIES}->{depends};
-               foreach my $i (@d) {
-                       pidl choose_header("librpc/gen_ndr/ndr_$i\.h", "gen_ndr/ndr_$i.h");
-               }
-       }
-
        if (defined $interface->{PROPERTIES}->{helper}) {
-               foreach (split / /, $interface->{PROPERTIES}->{helper}) {
-                       pidl_hdr "#include $_";
-               }
+               HeaderInclude(split / /, $interface->{PROPERTIES}->{helper});
        }
 
        if (defined $interface->{PROPERTIES}->{uuid}) {
@@ -2331,6 +2441,105 @@ sub HeaderInterface($)
 
 }
 
+sub ParseTypePush($$$$)
+{
+       my ($e, $varname, $primitives, $deferred) = @_;
+
+       # save the old relative_base_offset
+       pidl "uint32_t _save_relative_base_offset = ndr_push_get_relative_base_offset(ndr);" if defined(has_property($e, "relative_base"));
+       $typefamily{$e->{TYPE}}->{PUSH_FN_BODY}->($e, $varname);
+       # restore the old relative_base_offset
+       pidl "ndr_push_restore_relative_base_offset(ndr, _save_relative_base_offset);" if defined(has_property($e, "relative_base"));
+}
+
+sub ParseTypePushFunction($$)
+{
+       my ($e, $varname) = @_;
+
+       my $args = $typefamily{$e->{TYPE}}->{DECL}->($e, "push", $e->{NAME}, $varname);
+       fn_declare("push", $e, "NTSTATUS ndr_push_$e->{NAME}(struct ndr_push *ndr, int ndr_flags, $args)") or return;
+
+       pidl "{";
+       indent;
+       ParseTypePush($e, $varname, 1, 1);
+       pidl "return NT_STATUS_OK;";
+       deindent;
+       pidl "}";
+       pidl "";;
+}
+
+sub ParseTypePull($$$$)
+{
+       my ($e, $varname, $primitives, $deferred) = @_;
+
+       # save the old relative_base_offset
+       pidl "uint32_t _save_relative_base_offset = ndr_pull_get_relative_base_offset(ndr);" if defined(has_property($e, "relative_base"));
+       $typefamily{$e->{TYPE}}->{PULL_FN_BODY}->($e, $varname);
+       # restore the old relative_base_offset
+       pidl "ndr_pull_restore_relative_base_offset(ndr, _save_relative_base_offset);" if defined(has_property($e, "relative_base"));
+}
+
+
+sub ParseTypePullFunction($$)
+{
+       my ($e, $varname) = @_;
+
+       my $args = $typefamily{$e->{TYPE}}->{DECL}->($e, "pull", $e->{NAME}, $varname);
+
+       fn_declare("pull", $e, "NTSTATUS ndr_pull_$e->{NAME}(struct ndr_pull *ndr, int ndr_flags, $args)") or return;
+
+       pidl "{";
+       indent;
+       ParseTypePull($e, $varname, 1, 1);
+       pidl "return NT_STATUS_OK;";
+       deindent;
+       pidl "}";
+       pidl "";
+}
+
+sub ParseTypePrint($$)
+{
+       my ($e, $varname) = @_;
+
+       $typefamily{$e->{TYPE}}->{PRINT_FN_BODY}->($e, $e->{NAME}, $varname);
+}
+
+sub ParseTypePrintFunction($$)
+{
+       my ($e, $varname) = @_;
+       my $args = $typefamily{$e->{TYPE}}->{DECL}->($e, "print", $e->{NAME}, $varname);
+
+       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;
+       ParseTypePrint($e, $varname);
+       deindent;
+       pidl "}";
+       pidl "";
+}
+
+sub ParseTypeNdrSize($)
+{
+       my ($t) = @_;
+
+       my $varname = "r";
+       my $tf = $typefamily{$t->{TYPE}};
+       my $args = $tf->{SIZE_FN_ARGS}->($t, $t->{NAME}, $varname);
+
+       fn_declare("size", $t, "size_t ndr_size_$t->{NAME}($args)") or return;
+
+       pidl "{";
+       indent;
+       $typefamily{$t->{TYPE}}->{SIZE_FN_BODY}->($t, $t->{NAME}, $varname);
+       deindent;
+       pidl "}";
+       pidl "";
+}
+
 #####################################################################
 # parse the interface definitions
 sub ParseInterface($$)
@@ -2346,23 +2555,19 @@ sub ParseInterface($$)
                pidl choose_header("librpc/ndr/ndr_compression.h", "ndr/compression.h");
        }
 
-       if ($needed->{"obfuscate"}) {
-               pidl "#include \"ndr_obfuscate.h\"";
-       }
-       
        HeaderInterface($interface);
 
        # Typedefs
        foreach my $d (@{$interface->{TYPES}}) {
-               ($needed->{"push_$d->{NAME}"}) && ParseTypedefPush($d);
-               ($needed->{"pull_$d->{NAME}"}) && ParseTypedefPull($d);
-               ($needed->{"print_$d->{NAME}"}) && ParseTypedefPrint($d);
+               ($needed->{"push_$d->{NAME}"}) && ParseTypePushFunction($d, "r");
+               ($needed->{"pull_$d->{NAME}"}) && ParseTypePullFunction($d, "r");
+               ($needed->{"print_$d->{NAME}"}) && ParseTypePrintFunction($d, "r");
 
                # 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}"}) && ParseTypedefNdrSize($d);
+               ($needed->{"ndr_size_$d->{NAME}"}) && ParseTypeNdrSize($d);
        }
 
        # Functions
@@ -2381,6 +2586,29 @@ sub ParseInterface($$)
        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($$$)
@@ -2398,21 +2626,8 @@ sub Parse($$$)
 
        pidl "/* parser auto-generated by pidl */";
        pidl "";
-       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 <stdarg.h>";
-               pidl "#include <string.h>";
-       }
-       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");
+       GenerateIncludes();
        pidl "#include \"$ndr_header\"" if ($ndr_header);
-       pidl choose_header("librpc/rpc/dcerpc.h", "dcerpc.h"); #FIXME: This shouldn't be here!
        pidl "";
 
        my %needed = ();
@@ -2423,11 +2638,56 @@ sub Parse($$$)
 
        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 ($t, $rt);
+       if (ref($e->{TYPE}) eq "HASH") {
+               $t = $e->{TYPE}->{TYPE}."_".$e->{TYPE}->{NAME};
+       } else {
+               $t = $e->{TYPE};
+       }
+
+       if (ref($e->{REPRESENTATION_TYPE}) eq "HASH") {
+               $rt = $e->{REPRESENTATION_TYPE}->{TYPE}."_".$e->{REPRESENTATION_TYPE}->{NAME};
+       } else {
+               $rt = $e->{REPRESENTATION_TYPE};
+       }
+
+       die ("$e->{NAME} $t, $rt FOO") unless ($rt ne "");
+
+       my @fn = ();
+       if ($dir eq "print") {
+               push(@fn, "print_$rt");
+       } elsif ($dir eq "pull") {
+               push (@fn, "pull_$t");
+               push (@fn, "ndr_$t\_to_$rt")
+                       if ($rt ne $t);
+       } elsif ($dir eq "push") {
+               push (@fn, "push_$t");
+               push (@fn, "ndr_$rt\_to_$t")
+                       if ($rt ne $t);
+       } else {
+               die("invalid direction `$dir'");
+       }
+
+       foreach (@fn) {
+               unless (defined($needed->{$_})) {
+                       $needed->{$_} = 1;
+               }
+       }
+}
+
 sub NeededFunction($$)
 {
        my ($fn,$needed) = @_;
@@ -2436,52 +2696,25 @@ sub NeededFunction($$)
        $needed->{"print_$fn->{NAME}"} = 1;
        foreach my $e (@{$fn->{ELEMENTS}}) {
                $e->{PARENT} = $fn;
-               unless(defined($needed->{"pull_$e->{TYPE}"})) {
-                       $needed->{"pull_$e->{TYPE}"} = 1;
-               }
-               unless(defined($needed->{"push_$e->{TYPE}"})) {
-                       $needed->{"push_$e->{TYPE}"} = 1;
-               }
-               unless(defined($needed->{"print_$e->{TYPE}"})) {
-                       $needed->{"print_$e->{TYPE}"} = 1;
-               }
+               NeededElement($e, $_, $needed) foreach ("pull", "push", "print");
        }
 }
 
-sub NeededTypedef($$)
+sub NeededType($$$)
 {
-       my ($t,$needed) = @_;
-       if (has_property($t, "public")) {
-               $needed->{"pull_$t->{NAME}"} = not has_property($t, "nopull");
-               $needed->{"push_$t->{NAME}"} = not has_property($t, "nopush");
-               $needed->{"print_$t->{NAME}"} = not has_property($t, "noprint");
-       }
+       sub NeededType($$$);
+       my ($t,$needed,$req) = @_;
 
-       if ($t->{DATA}->{TYPE} eq "STRUCT" or $t->{DATA}->{TYPE} eq "UNION") {
-               if (has_property($t, "gensize")) {
-                       $needed->{"ndr_size_$t->{NAME}"} = 1;
-               }
+       NeededType($t->{DATA}, $needed, $req) if ($t->{TYPE} eq "TYPEDEF");
 
-               for my $e (@{$t->{DATA}->{ELEMENTS}}) {
-                       $e->{PARENT} = $t->{DATA};
+       if ($t->{TYPE} eq "STRUCT" or $t->{TYPE} eq "UNION") {
+               for my $e (@{$t->{ELEMENTS}}) {
+                       $e->{PARENT} = $t;
                        if (has_property($e, "compression")) { 
                                $needed->{"compression"} = 1;
                        }
-                       if (has_property($e, "obfuscation")) {
-                               $needed->{"obfuscate"} = 1;
-                       }
-                       if ($needed->{"pull_$t->{NAME}"} and
-                               not defined($needed->{"pull_$e->{TYPE}"})) {
-                               $needed->{"pull_$e->{TYPE}"} = 1;
-                       }
-                       if ($needed->{"push_$t->{NAME}"} and
-                               not defined($needed->{"push_$e->{TYPE}"})) {
-                               $needed->{"push_$e->{TYPE}"} = 1;
-                       }
-                       if ($needed->{"print_$t->{NAME}"} and 
-                               not defined($needed->{"print_$e->{TYPE}"})) {
-                               $needed->{"print_$e->{TYPE}"} = 1;
-                       }
+                       NeededElement($e, $req, $needed);
+                       NeededType($e->{TYPE}, $needed, $req) if (ref($e->{TYPE}) eq "HASH");
                }
        }
 }
@@ -2492,7 +2725,19 @@ sub NeededInterface($$)
 {
        my ($interface,$needed) = @_;
        NeededFunction($_, $needed) foreach (@{$interface->{FUNCTIONS}});
-       NeededTypedef($_, $needed) foreach (reverse @{$interface->{TYPES}});
+       foreach (reverse @{$interface->{TYPES}}) {
+               if (has_property($_, "public")) {
+                       $needed->{"pull\_$_->{NAME}"} = $needed->{"push\_$_->{NAME}"} = 
+                               $needed->{"print\_$_->{NAME}"} = 1;
+               }
+
+               NeededType($_, $needed, "pull") if ($needed->{"pull_$_->{NAME}"});
+               NeededType($_, $needed, "push") if ($needed->{"push_$_->{NAME}"});
+               NeededType($_, $needed, "print") if ($needed->{"print_$_->{NAME}"});
+               if (has_property($_, "gensize")) {
+                       $needed->{"ndr_size_$_->{NAME}"} = 1;
+               }
+       }
 }
 
 1;