r21484: Fix Needed* for nested datastructures.
[samba.git] / source4 / pidl / lib / Parse / Pidl / Samba4 / NDR / Parser.pm
index 75f30f7370eca47f9a20c8e8cc27716fbf838770..2ae4a3b17ef9752b04724f58f708695b0f60c7a5 100644 (file)
@@ -10,12 +10,16 @@ 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';
@@ -106,7 +110,7 @@ sub get_value_of($)
        }
 }
 
-my $res;
+our $res;
 my $deferred = [];
 my $tabs = "";
 
@@ -164,29 +168,6 @@ sub deindent()
        $tabs = substr($tabs, 0, -1);
 }
 
-#####################################################################
-# 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($)
-{
-       my $size = shift;
-       if ($size =~ /^\*/) {
-               my $size2 = substr($size, 1);
-               defer "if ($size2 == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;";
-       }
-}
-
 #####################################################################
 # declare a function public or static, depending on its attributes
 sub fn_declare($$$)
@@ -235,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;
 }
@@ -255,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;
@@ -309,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}) {
@@ -325,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($$$$$)
@@ -339,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;
@@ -363,20 +442,20 @@ sub ParseArrayPullHeader($$$$$)
        }
 
        if ($l->{IS_CONFORMANT} and not $l->{IS_ZERO_TERMINATED}) {
-               my $size = ParseExpr($l->{SIZE_IS}, $env);
                defer "if ($var_name) {";
                defer_indent;
-               check_null_pointer_deferred($size);
+               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) {";
                defer_indent;
-               check_null_pointer_deferred($length);
+               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 "}"
@@ -391,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($$$$)
@@ -474,7 +550,7 @@ 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;
@@ -492,7 +568,7 @@ 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);
@@ -507,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;
@@ -525,7 +601,7 @@ 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);
@@ -560,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);
                }
        }
 
@@ -590,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]";
@@ -617,21 +693,21 @@ 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};
+       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 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;
        }
@@ -640,15 +716,15 @@ sub ParseElementPush($$$$$$)
 
        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 "}";
        }
@@ -661,7 +737,7 @@ sub ParsePtrPush($$$)
        my ($e,$l,$var_name) = @_;
 
        if ($l->{POINTER_TYPE} eq "ref") {
-               check_null_pointer(get_value_of($var_name));
+               pidl "if ($var_name == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;";
                if ($l->{LEVEL} eq "EMBEDDED") {
                        pidl "NDR_CHECK(ndr_push_ref_ptr(ndr));";
                }
@@ -669,30 +745,52 @@ sub ParsePtrPush($$$)
                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) = @_;
 
        return if (has_property($e, "noprint"));
 
-       if ($e->{REPRESENTATION_TYPE}) {
+       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 (my $value = has_property($e, "value")) {
-               $var_name = "(ndr->flags & LIBNDR_PRINT_SET_VALUES)?" . ParseExpr($value,$env) . ":$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}}) {
@@ -714,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)) {
@@ -739,12 +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);
+                       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);";
                } 
        }
@@ -771,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));";
@@ -784,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};
+               }
 
-       pidl "NDR_CHECK(ndr_pull_$l->{DATA_TYPE}($ndr, $ndr_flags, $var_name));";
+               if (Parse::Pidl::Typelist::scalar_is_reference($t)) {
+                       $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 "}";
+               $var_name = get_pointer_to($var_name);
+
+               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 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);
-       }
+       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($$$)
@@ -854,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;
@@ -939,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}) {
@@ -951,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);
                }
        }
 
@@ -970,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);
 
@@ -986,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);
@@ -1016,32 +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;
                $transmit_name = "_transmit_$e->{NAME}";
                $var_name = $transmit_name;
-               pidl mapType($e->{TYPE})." $var_name;";
+               pidl mapTypeName($e->{TYPE})." $var_name;";
        }
 
        $var_name = append_prefix($e, $var_name);
@@ -1053,7 +1174,7 @@ sub ParseElementPull($$$$$$)
        end_flags($e);
 
        # Representation type is different from transmit_as
-       if ($e->{REPRESENTATION_TYPE}) {
+       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 "}";
@@ -1085,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;
@@ -1115,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
@@ -1150,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);
 }
 
@@ -1217,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}) {
@@ -1255,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} = {
@@ -1278,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);
 }
@@ -1292,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);
 
@@ -1319,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} = {
@@ -1359,13 +1479,13 @@ $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);
 
@@ -1377,7 +1497,8 @@ sub ParseStructPrint($$)
 
        pidl "ndr->depth++;";
        
-       ParseElementPrint($_, "r->$_->{NAME}", $env) foreach (@{$struct->{ELEMENTS}});
+       ParseElementPrint($_, $env->{$_->{NAME}}, $env) 
+               foreach (@{$struct->{ELEMENTS}});
        pidl "ndr->depth--;";
 
        end_flags($struct);
@@ -1438,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}));";
@@ -1472,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} = {
@@ -1540,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 $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;";
+       my ($e, $varname) = @_;
 
-       start_flags($e);
+       my $have_default = 0;
 
-       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));";
@@ -1588,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;";
@@ -1603,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;";
@@ -1630,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;";
@@ -1652,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\");";
 
@@ -1665,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;";
@@ -1681,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 "}";
        }
 
@@ -1737,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; }";
@@ -1751,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;";
@@ -1779,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} = {
@@ -1812,81 +1968,62 @@ $typefamily{UNION} = {
        
 #####################################################################
 # parse a typedef - push side
-sub ParseTypedefPush($)
+sub ParseTypedefPush($$)
 {
-       my($e) = shift;
+       my($e,$varname) = @_;
 
-       my $args = $typefamily{$e->{DATA}->{TYPE}}->{DECL}->($e,"push");
-       fn_declare("push", $e, "NTSTATUS ndr_push_$e->{NAME}(struct ndr_push *ndr, int ndr_flags, $args)") or return;
-
-       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 $args = $typefamily{$e->{DATA}->{TYPE}}->{DECL}->($e,"pull");
-
-       fn_declare("pull", $e, "NTSTATUS ndr_pull_$e->{NAME}(struct ndr_pull *ndr, int ndr_flags, $args)") or return;
+       my($e,$varname) = @_;
 
-       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");
-
-       pidl_hdr "void ndr_print_$e->{NAME}(struct ndr_print *ndr, const char *name, $args);";
-
-       return if (has_property($e, "noprint"));
+       my($e,$name,$varname) = @_;
 
-       pidl "_PUBLIC_ 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("size", $t, "size_t ndr_size_$t->{NAME}($args)") or return;
+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($)
@@ -1922,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--;";
@@ -1937,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}) {
@@ -1979,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);
                }
        }
 
@@ -1992,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);
                }
        }
 
@@ -2012,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 
@@ -2025,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;
        }
@@ -2077,7 +2213,7 @@ 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
@@ -2093,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);";
 
@@ -2124,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}) {
@@ -2220,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 
@@ -2236,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}) {
@@ -2292,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($$)
@@ -2311,15 +2559,15 @@ sub ParseInterface($$)
 
        # 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
@@ -2390,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) = @_;
@@ -2403,49 +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}"} = 1;
-               $needed->{"push_$t->{NAME}"} = 1;
-               $needed->{"print_$t->{NAME}"} = 1;
-       }
+       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 ($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");
                }
        }
 }
@@ -2456,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;