r948: Tridge suggested that the best way to write the ethereal parser is to
authorTim Potter <tpot@samba.org>
Sun, 30 May 2004 12:02:57 +0000 (12:02 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:56:21 +0000 (12:56 -0500)
base it on the generator for the ndr pull/push code rather than trying
to get all the alignment and other junk sorted out by hand.

This commit (nearly) gets eparser to the same state it previously was
but based on parser.pm.  We correctly parse simple types, strings and
sids.

source/build/pidl/eparser.pm
source/build/pidl/pidl.pl

index 4650778096131d10fc0339189e8f87ba06817e37..5117f4349b617a65bd2220b6d6e9ecaa5745e2ca 100644 (file)
 ###################################################
-# parser generator for IDL structures
-# Copyright tpot@samba.org 2004
+# Samba4 parser generator for IDL structures
+# Copyright tridge@samba.org 2000-2003
+# Copyright tpot@samba.org 2001
 # released under the GNU GPL
 
 package IdlEParser;
 
 use strict;
-use dump;
-#use Data::Dumper;
+use client;
+use Data::Dumper;
+
+# the list of needed functions
+my %needed;
+my %structs;
+
+my $module = "samr";
+my $if_uuid;
+my $if_version;
+my $if_endpoints;
+
+sub pidl($)
+{
+       print OUT shift;
+}
 
 #####################################################################
-# Code for managing hf's
+# parse a properties list
+sub ParseProperties($)
+{
+    my($props) = shift;
+    foreach my $d (@{$props}) {
+       if (ref($d) ne "HASH") {
+           pidl "[$d] ";
+       } else {
+           foreach my $k (keys %{$d}) {
+               pidl "[$k($d->{$k})] ";
+           }
+       }
+    }
+}
 
-my %hf_info = ();
+###################################
+# find a sibling var in a structure
+sub find_sibling($$)
+{
+       my($e) = shift;
+       my($name) = shift;
+       my($fn) = $e->{PARENT};
 
-# Convert an idl type to an ethereal FT_* type
+       if ($name =~ /\*(.*)/) {
+               $name = $1;
+       }
 
-sub type2ft($)
+       if ($fn->{TYPE} eq "FUNCTION") {
+               for my $e2 (@{$fn->{DATA}}) {
+                       if ($e2->{NAME} eq $name) {
+                               return $e2;
+                       }
+               }
+       }
+
+       for my $e2 (@{$fn->{ELEMENTS}}) {
+               if ($e2->{NAME} eq $name) {
+                       return $e2;
+               }
+       }
+       die "invalid sibling '$name'";
+}
+
+####################################################################
+# work out the name of a size_is() variable
+sub find_size_var($$$)
 {
-    my($t) = shift;
+       my($e) = shift;
+       my($size) = shift;
+       my($var_prefix) = shift;
 
-    return "FT_UINT32", if ($t eq "uint32");
-    return "FT_UINT16", if ($t eq "uint16");
-    return "FT_BYTES";
+       my($fn) = $e->{PARENT};
+
+       if (util::is_constant($size)) {
+               return $size;
+       }
+
+       if ($size =~ /ndr->|\(/) {
+               return $size;
+       }
+
+       my $prefix = "";
+
+       if ($size =~ /\*(.*)/) {
+               $size = $1;
+               $prefix = "*";
+       }
+
+       if ($fn->{TYPE} ne "FUNCTION") {
+               return $prefix . "r->$size";
+       }
+
+       my $e2 = find_sibling($e, $size);
+
+       if (util::has_property($e2, "in") && util::has_property($e2, "out")) {
+               return $prefix . "$var_prefix$size";
+       }
+       if (util::has_property($e2, "in")) {
+               return $prefix . "r->in.$size";
+       }
+       if (util::has_property($e2, "out")) {
+               return $prefix . "r->out.$size";
+       }
+
+       die "invalid variable in $size for element $e->{NAME} in $fn->{NAME}\n";
 }
 
-# Select an ethereal BASE_* type for an idl type
 
-sub type2base($)
+#####################################################################
+# work out is a parse function should be declared static or not
+sub fn_prefix($)
 {
-    my($t) = shift;
+       my $fn = shift;
+       if ($fn->{TYPE} eq "TYPEDEF") {
+               if (util::has_property($fn->{DATA}, "public")) {
+                       return "";
+               }
+       }
 
-    return "BASE_DEC", if ($t eq "uint32") or ($t eq "uint16");
-    return "BASE_NONE";
+       if ($fn->{TYPE} eq "FUNCTION") {
+               if (util::has_property($fn, "public")) {
+                       return "";
+               }
+       }
+       return "static ";
 }
 
-# Create a new field.  The name of the field is hf_${name}_${type} where
-# name and type are taken from the IDL definition for the element.
 
-sub AddField($$)
+###################################################################
+# setup any special flags for an element or structure
+sub start_flags($)
 {
-    my($name) = shift;
-    my($type) = shift;
-    
-    my $hf_name = "${name}_${type}";
-    return, if defined $hf_info{$hf_name};
-    
-    $hf_info{$hf_name} = {
-       'name' => $name,                       # Field name
-       'type' => $type,                       # Field type
-       'ft'   => type2ft($type),              # Ethereal type
-       'base' => type2base($type),            # Base of type
-    };
+       my $e = shift;
+       my $flags = util::has_property($e, "flag");
+       if (defined $flags) {
+               pidl "\t{ guint32 _flags_save_$e->{TYPE} = flags;\n";
+               pidl "\tflags |= $flags;\n";
+       }
 }
 
-# Generate field definitions from %hf_info
-
-sub EtherealFieldDefinitions()
+###################################################################
+# end any special flags for an element or structure
+sub end_flags($)
 {
-    my($res) = "";
+       my $e = shift;
+       my $flags = util::has_property($e, "flag");
+       if (defined $flags) {
+               pidl "\tflags = _flags_save_$e->{TYPE};\n\t}\n";
+       }
+}
 
-    $res .= << "EOF";
-static int hf_opnum = -1;
-static int hf_rc = -1;
-static int hf_policy_handle = -1;
-EOF
 
-    foreach my $hf (keys(%hf_info)) {
-       my($hf_name) = "$hf_info{$hf}{name}_$hf_info{$hf}{type}";
-       $res .= "static int hf_$hf_name = -1;\n";
-    }
+#####################################################################
+# work out the correct alignment for a structure
+sub struct_alignment
+{
+       my $s = shift;
+
+       my $align = 1;
+       for my $e (@{$s->{ELEMENTS}}) {
+               my $a = 1;
+
+               if (!util::need_wire_pointer($e)
+                   && defined $structs{$e->{TYPE}}) {
+                       if ($structs{$e->{TYPE}}->{DATA}->{TYPE} eq "STRUCT") {
+                               $a = struct_alignment($structs{$e->{TYPE}}->{DATA});
+                       } elsif ($structs{$e->{TYPE}}->{DATA}->{TYPE} eq "UNION") {
+                               if (defined $structs{$e->{TYPE}}->{DATA}) {
+                                       $a = union_alignment($structs{$e->{TYPE}}->{DATA});
+                               }
+                       }
+               } else {
+                       $a = util::type_align($e);
+               }
 
-    return $res;
-}
+               if ($align < $a) {
+                       $align = $a;
+               }
+       }
 
-# Generate field initialisers
+       return $align;
+}
 
-sub EtherealFieldInitialisation($)
+#####################################################################
+# work out the correct alignment for a union
+sub union_alignment
 {
-    my($module) = shift;
-    my($res) = "";
+       my $u = shift;
 
-    # Fields present in all parsers
+       my $align = 1;
 
-    $res .= << "EOF";
-\t{ &hf_opnum,
-\t  { \"Operation\", \"$module.opnum\", FT_UINT16, BASE_DEC, NULL, 0x0, \"Operation\", HFILL }},
-\t{ &hf_policy_handle,
-\t  { \"Policy handle\", \"$module.policy\", FT_BYTES, BASE_NONE, NULL, 0x0, \"Policy handle\", HFILL }},
-\t{ &hf_rc,
-\t  { \"Return code\", \"$module.rc\", FT_UINT32, BASE_HEX, VALS(NT_errors), 0x0, \"Return status code\", HFILL }},
-EOF
+       foreach my $e (@{$u->{DATA}}) {
+               my $a = 1;
 
-    foreach my $hf (keys(%hf_info)) {
-       $res .= "\t{ &hf_$hf,\n";
-       $res .= "\t  { \"$hf_info{$hf}{name}\", \"$hf\", $hf_info{$hf}{ft}, $hf_info{$hf}{base},\n";
-       $res .= "\t  NULL, 0, \"$hf\", HFILL }},\n";
-    }   
+               if ($e->{TYPE} eq "EMPTY") {
+                       next;
+               }
 
-    return $res;
+               if (!util::need_wire_pointer($e)
+                   && defined $structs{$e->{DATA}->{TYPE}}) {
+                       my $s = $structs{$e->{DATA}->{TYPE}};
+                       if ($s->{DATA}->{TYPE} eq "STRUCT") {
+                               $a = struct_alignment($s->{DATA});
+                       } elsif ($s->{DATA}->{TYPE} eq "UNION") {
+                               $a = union_alignment($s->{DATA});
+                       }
+               } else {
+                       $a = util::type_align($e->{DATA});
+               }
+
+               if ($align < $a) {
+                       $align = $a;
+               }
+       }
+
+       return $align;
 }
 
 #####################################################################
-# Code for managing subtrees
-
-sub EtherealSubtreeDefinitions($)
+# parse an array - push side
+sub ParseArrayPush($$$)
 {
-    my($module) = shift;
-    my($res) = "";
+       my $e = shift;
+       my $var_prefix = shift;
+       my $ndr_flags = shift;
 
-    $res .= << "EOF";
-static gint ett_dcerpc_$module = -1;
-EOF
+       my $size = find_size_var($e, util::array_size($e), $var_prefix);
 
-    return $res;
-}
+       if (defined $e->{CONFORMANT_SIZE}) {
+               # the conformant size has already been pushed
+       } elsif (!util::is_inline_array($e)) {
+               # we need to emit the array size
+               pidl "\t\toffset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_array_size, NULL);\n";
+       }
 
-sub EtherealSubtreeInitialisation()
-{
-    my($res) = "";
-    return $res;
+       if (my $length = util::has_property($e, "length_is")) {
+               $length = find_size_var($e, $length, $var_prefix);
+               pidl "\t\toffset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_length_is, NULL);\n";
+               pidl "\t\toffset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_length_is, NULL);\n";
+               $size = $length;
+       }
+
+       if (util::is_scalar_type($e->{TYPE})) {
+               pidl "\t\t// ndr_push_array_$e->{TYPE}(ndr, $ndr_flags, $var_prefix$e->{NAME}, $size);\n";
+       } else {
+               pidl "\t\t// ndr_push_array(ndr, $ndr_flags, $var_prefix$e->{NAME}, sizeof($var_prefix$e->{NAME}\[0]), $size, (ndr_push_flags_fn_t)ndr_push_$e->{TYPE});\n";
+       }
 }
 
 #####################################################################
-# Generate dissection functions for NDR types
-
-sub ParamSimpleNdrType($)
+# parse an array - pull side
+sub ParseArrayPull($$$)
 {
-    my($p) = shift;
-    my($res);
+       my $e = shift;
+       my $var_prefix = shift;
+       my $ndr_flags = shift;
+
+       my $size = find_size_var($e, util::array_size($e), $var_prefix);
+       my $alloc_size = $size;
+
+       # if this is a conformant array then we use that size to allocate, and make sure
+       # we allocate enough to pull the elements
+       if (defined $e->{CONFORMANT_SIZE}) {
+               $alloc_size = $e->{CONFORMANT_SIZE};
+
+               pidl "\tif ($size > $alloc_size) {\n";
+               pidl "\t\treturn ndr_pull_error(ndr, NDR_ERR_CONFORMANT_SIZE, \"Bad conformant size %u should be %u\", $alloc_size, $size);\n";
+               pidl "\t}\n";
+       } elsif (!util::is_inline_array($e)) {
+               if ($var_prefix =~ /^r->out/ && $size =~ /^\*r->in/) {
+                       my $size2 = substr($size, 1);
+                       pidl "if (flags & LIBNDR_FLAG_REF_ALLOC) {      NDR_ALLOC(ndr, $size2); }\n";
+               }
 
-    $res .= "\toffset = dissect_ndr_$p->{TYPE}(tvb, offset, pinfo, tree, drep, hf_$p->{NAME}_$p->{TYPE}, NULL);\n";
+               # non fixed arrays encode the size just before the array
+               pidl "\t{\n";
+               pidl "\t\tuint32_t _array_size;\n";
+               pidl "\t\t(ndr_pull_uint32(ndr, &_array_size);\n";
+               if ($size =~ /r->in/) {
+                       pidl "\t\tif (!(flags & LIBNDR_FLAG_REF_ALLOC) && _array_size != $size) {\n";
+               } else {
+                       pidl "\t\tif ($size != _array_size) {\n";
+               }
+               pidl "\t\t\treturn ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, \"Bad array size %u should be %u\", _array_size, $size);\n";
+               pidl "\t\t}\n";
+               if ($size =~ /r->in/) {
+                       pidl "else { $size = _array_size; }\n";
+               }
+               pidl "\t}\n";
+       }
 
-    return $res;
-}
+       if ((util::need_alloc($e) && !util::is_fixed_array($e)) ||
+           ($var_prefix eq "r->in." && util::has_property($e, "ref"))) {
+               if (!util::is_inline_array($e) || $ndr_flags eq "NDR_SCALARS") {
+                       pidl "\t\tNDR_ALLOC_N(ndr, $var_prefix$e->{NAME}, MAX(1, $alloc_size));\n";
+               }
+       }
+
+       if (($var_prefix eq "r->out." && util::has_property($e, "ref"))) {
+               if (!util::is_inline_array($e) || $ndr_flags eq "NDR_SCALARS") {
+                       pidl "\tif (flags & LIBNDR_FLAG_REF_ALLOC) {";
+                       pidl "\t\tNDR_ALLOC_N(ndr, $var_prefix$e->{NAME}, MAX(1, $alloc_size));\n";
+                       pidl "\t}\n";
+               }
+       }
+
+       pidl "\t{\n";
+
+       if (my $length = util::has_property($e, "length_is")) {
+               $length = find_size_var($e, $length, $var_prefix);
+               pidl "\t\tuint32_t _offset, _length;\n";
+               pidl "\t\tndr_pull_uint32(ndr, &_offset);\n";
+               pidl "\t\tndr_pull_uint32(ndr, &_length);\n";
+               pidl "\t\tif (_offset != 0) return ndr_pull_error(ndr, NDR_ERR_OFFSET, \"Bad array offset 0x%08x\", _offset);\n";
+               pidl "\t\tif (_length > $size || _length != $length) return ndr_pull_error(ndr, NDR_ERR_LENGTH, \"Bad array length 0x%08x > size 0x%08x\", _offset, $size);\n\n";
+               $size = "_length";
+       }
 
+       if (util::is_scalar_type($e->{TYPE})) {
+               pidl "\t\tndr_pull_array_$e->{TYPE}(ndr, $ndr_flags, $var_prefix$e->{NAME}, $size);\n";
+       } else {
+               pidl "\t\tndr_pull_array(ndr, $ndr_flags, (void **)$var_prefix$e->{NAME}, sizeof($var_prefix$e->{NAME}\[0]), $size, (ndr_pull_flags_fn_t)ndr_pull_$e->{TYPE});\n";
+       }
+
+       pidl "\t}\n";
+}
 sub ParamPolicyHandle($)
 {
     my($p) = shift;
@@ -145,6 +341,7 @@ sub ParamPolicyHandle($)
     return $res;
 }
 
+
 sub ParamString($)
 {
     my($p) = shift;
@@ -155,16 +352,6 @@ sub ParamString($)
     return $res;
 }
 
-sub ParamStruct($)
-{
-    my($p) = shift;
-    my($res);
-
-    $res .= "\toffset = dissect_$p->{TYPE}(tvb, offset, pinfo, tree, drep);\n";
-
-    return $res;
-}
-
 sub ParamDomSID($)
 {
     my($p) = shift;
@@ -175,489 +362,997 @@ sub ParamDomSID($)
     return $res;
 }
 
-# Index of NDR types and functions to generate code to dissect that type
-
 my %param_handlers = (
-                     'uint8'         => \&ParamSimpleNdrType,
-                     'uint16'        => \&ParamSimpleNdrType,
-                     'uint32'        => \&ParamSimpleNdrType,
                      'policy_handle' => \&ParamPolicyHandle,
-                     'string'        => \&ParamString,
+                     'string' => \&ParamString,
                      'dom_sid2'      => \&ParamDomSID,
                      );
 
-sub PtrString($)
+####################################################################
+# parse scalars in a structure element
+sub ParseElementPushScalar($$$)
 {
-    my($p) = shift;
-    my($res) = "";
+       my($e) = shift;
+       my($var_prefix) = shift;
+       my($ndr_flags) = shift;
+       my $cprefix = util::c_push_prefix($e);
+       my $sub_size = util::has_property($e, "subcontext");
 
-    $res .= "/* pointer to string not supported */\n";
+       start_flags($e);
 
-    return $res;
+       if (my $value = util::has_property($e, "value")) {
+               pidl "\t$cprefix$var_prefix$e->{NAME} = $value;\n";
+       }
+
+       if (util::has_property($e, "relative")) {
+               pidl "\tndr_push_relative(ndr, NDR_SCALARS, $var_prefix$e->{NAME}, (ndr_push_const_fn_t) ndr_push_$e->{TYPE});\n";
+       } elsif (util::is_inline_array($e)) {
+               ParseArrayPush($e, "r->", "NDR_SCALARS");
+       } elsif (util::need_wire_pointer($e)) {
+           pidl "\toffset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_ptr, &ptr);\n";
+       } elsif (util::need_alloc($e)) {
+               # no scalar component
+       } elsif (my $switch = util::has_property($e, "switch_is")) {
+               ParseElementPushSwitch($e, $var_prefix, $ndr_flags, $switch);
+       } elsif (defined $sub_size) {
+               if (util::is_builtin_type($e->{TYPE})) {
+                       pidl "\tndr_push_subcontext_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_push_fn_t) ndr_push_$e->{TYPE});\n";
+               } else {
+                       pidl "\tndr_push_subcontext_flags_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_push_flags_fn_t) ndr_push_$e->{TYPE});\n";
+               }
+       } elsif (util::is_builtin_type($e->{TYPE})) {
+               pidl "\toffset = dissect_ndr_$e->{TYPE}(tvb, offset, pinfo, tree, drep, hf_$e->{NAME}_$e->{TYPE}, NULL);\n";
+       } else {
+           if (defined($param_handlers{$e->{TYPE}})) {
+               pidl &{$param_handlers{$e->{TYPE}}}($e);
+           } else {
+               pidl "\tproto_tree_add_text(tree, tvb, offset, -1, \"Unhandled IDL type '$e->{TYPE}'\");\n";
+           }
+       }
+
+       end_flags($e);
 }
 
-sub PtrSimpleNdrType($)
+#####################################################################
+# print scalars in a structure element
+sub ParseElementPrintScalar($$)
 {
-    my($p) = shift;
-    my($res) = "";
+       my($e) = shift;
+       my($var_prefix) = shift;
+       my $cprefix = util::c_push_prefix($e);
 
-    $res .= "/* pointer to $p->{TYPE} not supported */\n";
+       if (util::has_property($e, "noprint")) {
+               return;
+       }
 
-    return $res;
+       if (my $value = util::has_property($e, "value")) {
+               pidl "\tif (flags & LIBNDR_PRINT_SET_VALUES) {\n";
+               pidl "\t\t$cprefix$var_prefix$e->{NAME} = $value;\n";
+               pidl "\t}\n";
+       }
+
+       if (util::is_fixed_array($e)) {
+               ParseElementPrintBuffer($e, $var_prefix);
+       } elsif (util::has_direct_buffers($e)) {
+               pidl "\tndr_print_ptr(ndr, \"$e->{NAME}\", $var_prefix$e->{NAME});\n";
+               pidl "\tndr->depth++;\n";
+               ParseElementPrintBuffer($e, $var_prefix);
+               pidl "\tndr->depth--;\n";
+       } elsif (my $switch = util::has_property($e, "switch_is")) {
+               ParseElementPrintSwitch($e, $var_prefix, $switch);
+       } else {
+               pidl "\tndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME});\n";
+       }
 }
 
-sub PtrDomSID($)
+#####################################################################
+# parse scalars in a structure element - pull size
+sub ParseElementPullSwitch($$$$)
 {
-    my($p) = shift;
-    my($res) = "";
+       my($e) = shift;
+       my($var_prefix) = shift;
+       my($ndr_flags) = shift;
+       my $switch = shift;
+       my $switch_var = find_size_var($e, $switch, $var_prefix);
+
+       my $cprefix = util::c_pull_prefix($e);
+
+       my $utype = $structs{$e->{TYPE}};
+       if (!defined $utype ||
+           !util::has_property($utype->{DATA}, "nodiscriminant")) {
+               my $e2 = find_sibling($e, $switch);
+               pidl "\tif (($ndr_flags) & NDR_SCALARS) {\n";
+               pidl "\t\t $e2->{TYPE} _level;\n";
+               pidl "\t\tndr_pull_$e2->{TYPE}(ndr, &_level);\n";
+               if ($switch_var =~ /r->in/) {
+                       pidl "\t\tif (!(flags & LIBNDR_FLAG_REF_ALLOC) && _level != $switch_var) {\n";
+               } else {
+                       pidl "\t\tif (_level != $switch_var) {\n";
+               }
+               pidl "\t\t\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value %u in $e->{NAME}\");\t\t}\n";
+               if ($switch_var =~ /r->/) {
+                       pidl "else { $switch_var = _level; }\n";
+               }
+               pidl "\t}\n";
+       }
+
+       my $sub_size = util::has_property($e, "subcontext");
+       if (defined $sub_size) {
+               pidl "\tndr_pull_subcontext_union_fn(ndr, $sub_size, $switch_var, $cprefix$var_prefix$e->{NAME}, (ndr_pull_union_fn_t) ndr_pull_$e->{TYPE});\n";
+       } else {
+               pidl "\tndr_pull_$e->{TYPE}(ndr, $ndr_flags, $switch_var, $cprefix$var_prefix$e->{NAME});\n";
+       }
 
-    $res .= "/* pointer to dom_sid not supported */\n";
 
-    return $res;
 }
 
-sub PtrSecurityDescriptor($)
+#####################################################################
+# push switch element
+sub ParseElementPushSwitch($$$$)
 {
-    my($p) = shift;
-    my($res) = "";
-
-    $res .= "/* pointer to security descriptor not supported */\n";
+       my($e) = shift;
+       my($var_prefix) = shift;
+       my($ndr_flags) = shift;
+       my $switch = shift;
+       my $switch_var = find_size_var($e, $switch, $var_prefix);
+       my $cprefix = util::c_push_prefix($e);
+
+       my $utype = $structs{$e->{TYPE}};
+       if (!defined $utype ||
+           !util::has_property($utype->{DATA}, "nodiscriminant")) {
+               my $e2 = find_sibling($e, $switch);
+               pidl "\tif (($ndr_flags) & NDR_SCALARS) {\n";
+               pidl "\t\toffset = dissect_ndr_$e2->{TYPE}(tvb, offset, pinfo, tree, drep, hf_switch, NULL);\n";
+               pidl "\t}\n";
+       }
 
-    return $res;
+       my $sub_size = util::has_property($e, "subcontext");
+       if (defined $sub_size) {
+               pidl "\tndr_push_subcontext_union_fn(ndr, $sub_size, $switch_var, $cprefix$var_prefix$e->{NAME}, (ndr_push_union_fn_t) ndr_push_$e->{TYPE});\n";
+       } else {
+           if (defined($param_handlers{$e->{TYPE}})) {
+               pidl &{$param_handlers{$e->{TYPE}}}($e);
+           } else {
+               pidl "\tproto_tree_add_text(tree, tvb, offset, -1, \"Unhandled IDL type '$e->{TYPE}'\");\n";
+           }
+#              pidl "\tndr_push_$e->{TYPE}(ndr, $ndr_flags, $switch_var, $cprefix$var_prefix$e->{NAME});\n";
+       }
 }
 
-sub PtrNotImplemented($)
+#####################################################################
+# print scalars in a structure element 
+sub ParseElementPrintSwitch($$$)
 {
-    my($p) = shift;
-    my($res) = "";
+       my($e) = shift;
+       my($var_prefix) = shift;
+       my $switch = shift;
+       my $switch_var = find_size_var($e, $switch, $var_prefix);
+       my $cprefix = util::c_push_prefix($e);
 
-    $res .= "/* pointer to $p->{TYPE} not supported */\n";
-
-    return $res;
+       pidl "\tndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $switch_var, $cprefix$var_prefix$e->{NAME});\n";
 }
 
-my %ptr_handlers = (
-                   'uint8'               => \&PtrSimpleNdrType,
-                   'uint16'              => \&PtrSimpleNdrType,
-                   'uint32'              => \&PtrSimpleNdrType,
-                   'string'              => \&PtrString,
-                   'dom_sid2'            => \&PtrDomSID,
-                   'security_descriptor' => \&PtrSecurityDescriptor,
-                   'lsa_SidArray' => \&PtrNotImplemented,
-                   );
 
-# Generate a parser for a NDR parameter
+#####################################################################
+# parse scalars in a structure element - pull size
+sub ParseElementPullScalar($$$)
+{
+       my($e) = shift;
+       my($var_prefix) = shift;
+       my($ndr_flags) = shift;
+       my $cprefix = util::c_pull_prefix($e);
+       my $sub_size = util::has_property($e, "subcontext");
+
+       start_flags($e);
+
+       if (util::has_property($e, "relative")) {
+               pidl "\tndr_pull_relative(ndr, (const void **)&$var_prefix$e->{NAME}, sizeof(*$var_prefix$e->{NAME}), (ndr_pull_flags_fn_t)ndr_pull_$e->{TYPE});\n";
+       } elsif (util::is_inline_array($e)) {
+               ParseArrayPull($e, "r->", "NDR_SCALARS");
+       } elsif (util::need_wire_pointer($e)) {
+               pidl "\tndr_pull_uint32(ndr, &_ptr_$e->{NAME});\n";
+               pidl "\tif (_ptr_$e->{NAME}) {\n";
+               pidl "\t\tNDR_ALLOC(ndr, $var_prefix$e->{NAME});\n";
+               pidl "\t} else {\n";
+               pidl "\t\t$var_prefix$e->{NAME} = NULL;\n";
+               pidl "\t}\n";
+       } elsif (util::need_alloc($e)) {
+               # no scalar component
+       } elsif (my $switch = util::has_property($e, "switch_is")) {
+               ParseElementPullSwitch($e, $var_prefix, $ndr_flags, $switch);
+       } elsif (defined $sub_size) {
+               if (util::is_builtin_type($e->{TYPE})) {
+                       pidl "\tndr_pull_subcontext_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_pull_fn_t) ndr_pull_$e->{TYPE});\n";
+               } else {
+                       pidl "\tndr_pull_subcontext_flags_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_pull_flags_fn_t) ndr_pull_$e->{TYPE});\n";
+               }
+       } elsif (util::is_builtin_type($e->{TYPE})) {
+               pidl "\tndr_pull_$e->{TYPE}(ndr, $cprefix$var_prefix$e->{NAME});\n";
+       } else {
+               pidl "\tndr_pull_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME});\n";
+       }
 
-sub ParseParameter($)
-{ 
-    my($p) = shift;
-    my($res);
+       end_flags($e);
+}
 
-    # Call function registered for this type
+#####################################################################
+# parse buffers in a structure element
+sub ParseElementPushBuffer($$$)
+{
+       my($e) = shift;
+       my($var_prefix) = shift;
+       my($ndr_flags) = shift;
+       my $cprefix = util::c_push_prefix($e);
+       my $sub_size = util::has_property($e, "subcontext");
+
+       if (util::is_pure_scalar($e)) {
+               return;
+       }
 
-    if ($p->{POINTERS} == 1 && $p->{TYPE} ne "policy_handle") {
+       start_flags($e);
 
-       if (defined($ptr_handlers{$p->{TYPE}})) {
-           $res .= &{$ptr_handlers{$p->{TYPE}}}($p);
+       if (util::need_wire_pointer($e)) {
+               pidl "\tif (ptr) {\n";
+       }
+           
+       if (util::has_property($e, "relative")) {
+               pidl "\tndr_push_relative(ndr, NDR_BUFFERS, $cprefix$var_prefix$e->{NAME}, (ndr_push_const_fn_t) ndr_push_$e->{TYPE});\n";
+       } elsif (util::is_inline_array($e)) {
+               ParseArrayPush($e, "r->", "NDR_BUFFERS");
+       } elsif (util::array_size($e)) {
+               ParseArrayPush($e, "r->", "NDR_SCALARS|NDR_BUFFERS");
+       } elsif (my $switch = util::has_property($e, "switch_is")) {
+               if ($e->{POINTERS}) {
+                       ParseElementPushSwitch($e, $var_prefix, "NDR_BUFFERS|NDR_SCALARS", $switch);
+               } else {
+                       ParseElementPushSwitch($e, $var_prefix, "NDR_BUFFERS", $switch);
+               }
+       } elsif (defined $sub_size) {
+               if ($e->{POINTERS}) {
+                       if (util::is_builtin_type($e->{TYPE})) {
+                               pidl "\tndr_push_subcontext_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_push_fn_t) ndr_push_$e->{TYPE});\n";
+                       } else {
+                               pidl "\tndr_push_subcontext_flags_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_push_flags_fn_t) ndr_push_$e->{TYPE});\n";
+                       }
+               }
+       } elsif (util::is_builtin_type($e->{TYPE})) {
+               pidl "\toffset = dissect_ndr_$e->{TYPE}(tvb, offset, pinfo, tree, drep, hf_$e->{NAME}_$e->{TYPE}, NULL);\n";
+       } elsif ($e->{POINTERS}) {
+           if (defined($param_handlers{$e->{TYPE}})) {
+               pidl &{$param_handlers{$e->{TYPE}}}($e);
+           } else {
+               pidl "\t\toffset = dissect_$e->{TYPE}(tvb, offset, pinfo, tree, drep, NDR_SCALARS|NDR_BUFFERS);\n";
+           }
        } else {
-           $res .= "\toffset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep, dissect_$p->{TYPE}, NDR_POINTER_UNIQUE, \"$p->{TYPE} pointer\", -1);\n";
+           if (defined($param_handlers{$e->{TYPE}})) {
+               pidl &{$param_handlers{$e->{TYPE}}}($e);
+           } else {
+               pidl "\t\toffset = dissect__$e->{TYPE}(tvb, offset, pinfo, tree, drep, $ndr_flags);\n";
+           }
        }
 
-       return $res;
-    }
+       if (util::need_wire_pointer($e)) {
+               pidl "\t}\n";
+       }       
 
-    if (defined($param_handlers{$p->{TYPE}})) {
-       $res .= &{$param_handlers{$p->{TYPE}}}($p);
-       return $res;
-    }
+       end_flags($e);
+}
 
-    # Unknown type - make a note in the protocol tree
+#####################################################################
+# print buffers in a structure element
+sub ParseElementPrintBuffer($$)
+{
+       my($e) = shift;
+       my($var_prefix) = shift;
+       my $cprefix = util::c_push_prefix($e);
 
-    $res .= "\tproto_tree_add_text(tree, tvb, offset, -1, \"Unhandled IDL type '$p->{TYPE}'\");\n";
+       if (util::need_wire_pointer($e)) {
+               pidl "\tif ($var_prefix$e->{NAME}) {\n";
+       }
+           
+       if (util::array_size($e)) {
+               ParseArrayPrint($e, $var_prefix);
+       } elsif (my $switch = util::has_property($e, "switch_is")) {
+               ParseElementPrintSwitch($e, $var_prefix, $switch);
+       } else {
+               pidl "\t\tndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME});\n";
+       }
 
-    return $res;
+       if (util::need_wire_pointer($e)) {
+               pidl "\t}\n";
+       }       
 }
 
+
 #####################################################################
-# Generate code fragment for an IDL function
+# parse buffers in a structure element - pull side
+sub ParseElementPullBuffer($$$)
+{
+       my($e) = shift;
+       my($var_prefix) = shift;
+       my($ndr_flags) = shift;
+       my $cprefix = util::c_pull_prefix($e);
+       my $sub_size = util::has_property($e, "subcontext");
+
+       if (util::is_pure_scalar($e)) {
+               return;
+       }
 
-sub EtherealFunction($)
-{ 
-    my($f) = shift;
-    my($res);
+       if (util::has_property($e, "relative")) {
+               return;
+       }
 
-    # Comment displaying IDL for this function
+       start_flags($e);
 
-    $res .= "/*\n\n";
-    $res .= IdlDump::DumpFunction($f);
-    $res .= "*/\n\n";
+       if (util::need_wire_pointer($e)) {
+               pidl "\tif ($var_prefix$e->{NAME}) {\n";
+       }
+           
+       if (util::is_inline_array($e)) {
+               ParseArrayPull($e, "r->", "NDR_BUFFERS");
+       } elsif (util::array_size($e)) {
+               ParseArrayPull($e, "r->", "NDR_SCALARS|NDR_BUFFERS");
+       } elsif (my $switch = util::has_property($e, "switch_is")) {
+               if ($e->{POINTERS}) {
+                       ParseElementPullSwitch($e, $var_prefix, "NDR_SCALARS|NDR_BUFFERS", $switch);
+               } else {
+                       ParseElementPullSwitch($e, $var_prefix, "NDR_BUFFERS", $switch);
+               }
+       } elsif (defined $sub_size) {
+               if ($e->{POINTERS}) {
+                       if (util::is_builtin_type($e->{TYPE})) {
+                               pidl "\tndr_pull_subcontext_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_pull_fn_t) ndr_pull_$e->{TYPE});\n";
+                       } else {
+                               pidl "\tndr_pull_subcontext_flags_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_pull_flags_fn_t) ndr_pull_$e->{TYPE});\n";
+                       }
+               }
+       } elsif (util::is_builtin_type($e->{TYPE})) {
+               pidl "\t\tndr_pull_$e->{TYPE}(ndr, $cprefix$var_prefix$e->{NAME});\n";
+       } elsif ($e->{POINTERS}) {
+               pidl "\t\tndr_pull_$e->{TYPE}(ndr, NDR_SCALARS|NDR_BUFFERS, $cprefix$var_prefix$e->{NAME});\n";
+       } else {
+               pidl "\t\tndr_pull_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME});\n";
+       }
 
-    # Request function
+       if (util::need_wire_pointer($e)) {
+               pidl "\t}\n";
+       }       
 
-    $res .= "static int\n";
-    $res .= "$f->{NAME}_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)\n";
-    $res .= "{\n";
+       end_flags($e);
+}
 
-    my($d);
-    foreach $d (@{$f->{DATA}}) {
-       $res .= ParseParameter($d), if defined($d->{PROPERTIES}{in});
-    }
+#####################################################################
+# parse a struct
+sub ParseStructPush($)
+{
+       my($struct) = shift;
+       my $conform_e;
+       
+       if (! defined $struct->{ELEMENTS}) {
+               return;
+       }
 
-    $res .= "\n\treturn offset;\n";
-    $res .= "}\n\n";
+       start_flags($struct);
+
+       # see if the structure contains a conformant array. If it
+       # does, then it must be the last element of the structure, and
+       # we need to push the conformant length early, as it fits on
+       # the wire before the structure (and even before the structure
+       # alignment)
+       my $e = $struct->{ELEMENTS}[-1];
+       if (defined $e->{ARRAY_LEN} && $e->{ARRAY_LEN} eq "*") {
+               my $size = find_size_var($e, util::array_size($e), "r->");
+               $e->{CONFORMANT_SIZE} = $size;
+               $conform_e = $e;
+               pidl "\tndr_push_uint32(ndr, $size);\n";
+       }
 
-    # Response function
+       pidl "\tif (!(ndr_flags & NDR_SCALARS)) goto buffers;\n";
 
-    $res .= "static int\n";
-    $res .= "$f->{NAME}_resp(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)\n";
-    $res .= "{\n";
+       pidl "\tndr_push_struct_start(ndr);\n";
 
-    foreach $d (@{$f->{DATA}}) {
-       $res .= ParseParameter($d), if defined($d->{PROPERTIES}{out});
-    }
+       my $align = struct_alignment($struct);
+       pidl "\tndr_push_align(ndr, $align);\n";
 
-    $res .= "\n\toffset = dissect_ntstatus(tvb, offset, pinfo, tree, drep, hf_rc, NULL);\n\n";
+       foreach my $e (@{$struct->{ELEMENTS}}) {
+               ParseElementPushScalar($e, "r->", "NDR_SCALARS");
+       }       
 
-    $res .= "\treturn offset;\n";
-    $res .= "}\n\n";
+       pidl "buffers:\n";
+       pidl "\tif (!(ndr_flags & NDR_BUFFERS)) goto done;\n";
+       foreach my $e (@{$struct->{ELEMENTS}}) {
+               ParseElementPushBuffer($e, "r->", "NDR_BUFFERS");
+       }
 
-    return $res;
+       pidl "\tndr_push_struct_end(ndr);\n";
+
+       pidl "done:\n";
+
+       end_flags($struct);
 }
 
 #####################################################################
-# Generate code fragment for an IDL struct
+# parse a struct - pull side
+sub ParseStructPull($)
+{
+       my($struct) = shift;
+       my $conform_e;
 
-sub EtherealStruct($$)
-{ 
-    my($module) = shift;
-    my($struct) = shift;
-    my($res) = "";
+       if (! defined $struct->{ELEMENTS}) {
+               return;
+       }
 
-    $res .= "/*\n\n";
-    $res .= IdlDump::DumpStruct($struct->{DATA});
-    $res .= "\n\n*/\n\n";
+       # see if the structure contains a conformant array. If it
+       # does, then it must be the last element of the structure, and
+       # we need to pull the conformant length early, as it fits on
+       # the wire before the structure (and even before the structure
+       # alignment)
+       my $e = $struct->{ELEMENTS}[-1];
+       if (defined $e->{ARRAY_LEN} && $e->{ARRAY_LEN} eq "*") {
+               $conform_e = $e;
+               pidl "\tuint32_t _conformant_size;\n";
+               $conform_e->{CONFORMANT_SIZE} = "_conformant_size";
+       }
 
-    $res .= << "EOF";
-int dissect_$struct->{NAME}(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep)
-{
-    proto_item *item = NULL;
-    proto_tree *tree = NULL;
-    int old_offset = offset;
+       # declare any internal pointers we need
+       foreach my $e (@{$struct->{ELEMENTS}}) {
+               if (util::need_wire_pointer($e) &&
+                   !util::has_property($e, "relative")) {
+                       pidl "\tuint32_t _ptr_$e->{NAME};\n";
+               }
+       }
 
-    if (parent_tree) {
-       item = proto_tree_add_text(parent_tree, tvb, offset, -1, "$struct->{NAME}");
-       tree = proto_item_add_subtree(item, ett_dcerpc_$module);
-    }
+       start_flags($struct);
 
-EOF
+       pidl "\tif (!(ndr_flags & NDR_SCALARS)) goto buffers;\n";
 
-    # Parse elements
+       pidl "\tndr_pull_struct_start(ndr);\n";
 
-    foreach my $d (@{$struct->{DATA}->{ELEMENTS}}) {
-       $res .= ParseParameter($d);
-    }
+       if (defined $conform_e) {
+               pidl "\tndr_pull_uint32(ndr, &$conform_e->{CONFORMANT_SIZE});\n";
+       }
 
-$res .= << "EOF";    
+       my $align = struct_alignment($struct);
+       pidl "\tndr_pull_align(ndr, $align);\n";
 
-    proto_item_set_len(item, offset - old_offset);
+       foreach my $e (@{$struct->{ELEMENTS}}) {
+               ParseElementPullScalar($e, "r->", "NDR_SCALARS");
+       }       
 
-    return offset;
-}
+       pidl "buffers:\n";
+       pidl "\tif (!(ndr_flags & NDR_BUFFERS)) goto done;\n";
+       foreach my $e (@{$struct->{ELEMENTS}}) {
+               ParseElementPullBuffer($e, "r->", "NDR_BUFFERS");
+       }
 
-EOF
+       pidl "\tndr_pull_struct_end(ndr);\n";
 
-    return $res;
+       pidl "done:\n";
+
+       end_flags($struct);
 }
 
+
 #####################################################################
-# Generate code fragment for an IDL union
+# parse a union - push side
+sub ParseUnionPush($)
+{
+       my $e = shift;
+       my $have_default = 0;
 
-sub EtherealUnion($$)
-{ 
-    my($module) = shift;
-    my($union) = shift;
-    my($res) = "";
+       start_flags($e);
 
-    $res .= "/*\n\n";
-    $res .= IdlDump::DumpUnion($union->{DATA});
-    $res .= "\n\n*/\n\n";
+       pidl "\tif (!(ndr_flags & NDR_SCALARS)) goto buffers;\n";
 
-    $res .= << "EOF";
-int dissect_$union->{NAME}(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep)
-{
-    proto_item *item = NULL;
-    proto_tree *tree = NULL;
-    int old_offset = offset;
+       pidl "\tndr_push_struct_start(ndr);\n";
 
-    if (parent_tree) {
-       item = proto_tree_add_text(parent_tree, tvb, offset, -1, "$union->{NAME}");
-       tree = proto_item_add_subtree(item, ett_dcerpc_$module);
-    }
+#      my $align = union_alignment($e);
+#      pidl "\tndr_push_align(ndr, $align);\n";
 
-EOF
+       pidl "\tswitch (level) {\n";
+       foreach my $el (@{$e->{DATA}}) {
+               if ($el->{CASE} eq "default") {
+                       pidl "\tdefault:\n";
+                       $have_default = 1;
+               } else {
+                       pidl "\tcase $el->{CASE}:\n";
+               }
+               if ($el->{TYPE} eq "UNION_ELEMENT") {
+                       ParseElementPushScalar($el->{DATA}, "r->", "NDR_SCALARS");
+               }
+               pidl "\tbreak;\n\n";
+       }
+       if (! $have_default) {
+               pidl "\tdefault:\n";
+               pidl "\t\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);\n";
+       }
+       pidl "\t}\n";
+       pidl "buffers:\n";
+       pidl "\tif (!(ndr_flags & NDR_BUFFERS)) goto done;\n";
+       pidl "\tswitch (level) {\n";
+       foreach my $el (@{$e->{DATA}}) {
+               if ($el->{CASE} eq "default") {
+                       pidl "\tdefault:\n";
+               } else {
+                       pidl "\tcase $el->{CASE}:\n";
+               }
+               if ($el->{TYPE} eq "UNION_ELEMENT") {
+                       ParseElementPushBuffer($el->{DATA}, "r->", "NDR_BUFFERS");
+               }
+               pidl "\tbreak;\n\n";
+       }
+       if (! $have_default) {
+               pidl "\tdefault:\n";
+               pidl "\t\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);\n";
+       }
+       pidl "\t}\n";
+       pidl "\tndr_push_struct_end(ndr);\n";
+       pidl "done:\n";
+       end_flags($e);
+}
 
-    # TODO: Parse elements
+#####################################################################
+# parse a union - pull side
+sub ParseUnionPull($)
+{
+       my $e = shift;
+       my $have_default = 0;
 
-$res .= << "EOF";    
+       start_flags($e);
 
-    proto_item_set_len(item, offset - old_offset);
+       pidl "\tif (!(ndr_flags & NDR_SCALARS)) goto buffers;\n";
 
-    return offset;
-}
+       pidl "\tndr_pull_struct_start(ndr);\n";
 
-EOF
+#      my $align = union_alignment($e);
+#      pidl "\tndr_pull_align(ndr, $align);\n";
 
-    return $res;
+       pidl "\tswitch (level) {\n";
+       foreach my $el (@{$e->{DATA}}) {
+               if ($el->{CASE} eq "default") {
+                       pidl "\tdefault: {\n";
+                       $have_default = 1;
+               } else {
+                       pidl "\tcase $el->{CASE}: {\n";
+               }
+               if ($el->{TYPE} eq "UNION_ELEMENT") {
+                       my $e2 = $el->{DATA};
+                       if ($e2->{POINTERS}) {
+                               pidl "\t\tuint32_t _ptr_$e2->{NAME};\n";
+                       }
+                       ParseElementPullScalar($el->{DATA}, "r->", "NDR_SCALARS");
+               }
+               pidl "\tbreak; }\n\n";
+       }
+       if (! $have_default) {
+               pidl "\tdefault:\n";
+               pidl "\t\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);\n";
+       }
+       pidl "\t}\n";
+       pidl "buffers:\n";
+       pidl "\tif (!(ndr_flags & NDR_BUFFERS)) goto done;\n";
+       pidl "\tswitch (level) {\n";
+       foreach my $el (@{$e->{DATA}}) {
+               if ($el->{CASE} eq "default") {
+                       pidl "\tdefault:\n";
+               } else {
+                       pidl "\tcase $el->{CASE}:\n";
+               }
+               if ($el->{TYPE} eq "UNION_ELEMENT") {
+                       ParseElementPullBuffer($el->{DATA}, "r->", "NDR_BUFFERS");
+               }
+               pidl "\tbreak;\n\n";
+       }
+       if (! $have_default) {
+               pidl "\tdefault:\n";
+               pidl "\t\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);\n";
+       }
+       pidl "\t}\n";
+       pidl "\tndr_pull_struct_end(ndr);\n";
+       pidl "done:\n";
+       end_flags($e);
 }
 
 #####################################################################
-# Generate code fragment for an IDL typedef
-
-sub EtherealTypedef($$)
-{ 
-    my($module) = shift;
-    my($typedef) = shift;
-
-    return EtherealStruct($module, $typedef), 
-        if $typedef->{DATA}{TYPE} eq "STRUCT";
-
-    return EtherealUnion($module, $typedef),
-        if $typedef->{DATA}{TYPE} eq "UNION";
+# parse a type
+sub ParseTypePush($)
+{
+       my($data) = shift;
 
-    return "/* Unsupported typedef $typedef->{DATA}{TYPE} " .
-       "$typedef->{NAME}*/\n\n";
+       if (ref($data) eq "HASH") {
+               ($data->{TYPE} eq "STRUCT") &&
+                   ParseStructPush($data);
+               ($data->{TYPE} eq "UNION") &&
+                   ParseUnionPush($data);
+       }
 }
 
 #####################################################################
-# Generate code fragment for the start of the dissector
-
-sub EtherealHeader($)
+# parse a type
+sub ParseTypePull($)
 {
-    my($module) = shift;
-    my($res) = "";
-
-    $res .= << "EOF";
-/* parser auto-generated by pidl */
+       my($data) = shift;
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+       if (ref($data) eq "HASH") {
+               ($data->{TYPE} eq "STRUCT") &&
+                   ParseStructPull($data);
+               ($data->{TYPE} eq "UNION") &&
+                   ParseUnionPull($data);
+       }
+}
 
-#include "packet-dcerpc.h"
-#include "packet-dcerpc-nt.h"
+#####################################################################
+# parse a typedef
+sub ParseTypedefEthereal($)
+{
+       my($e) = shift;
+       my $static = fn_prefix($e);
+
+       if ($e->{DATA}->{TYPE} eq "STRUCT") {
+           pidl $static . "int dissect_$e->{NAME}(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int flags)\n";
+           pidl "\n{\n";
+#              ParseTypePush($e->{DATA});
+           pidl "\treturn offset;\n";
+           pidl "}\n\n";
+       }
 
-extern const value_string NT_errors[];
+       if ($e->{DATA}->{TYPE} eq "UNION") {
+           pidl $static . "int dissect_$e->{NAME}(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int flags)\n";
+               pidl "\n{\n";
+#              ParseTypePush($e->{DATA});
+           pidl "\treturn offset;\n";
+               pidl "}\n\n";
+       }
+}
 
-static int proto_dcerpc_$module = -1;
 
-EOF
+#####################################################################
+# parse a function element
+sub ParseFunctionElementPush($$)
+{ 
+       my $e = shift;
+       my $inout = shift;
+
+       if (util::array_size($e)) {
+               if (util::need_wire_pointer($e)) {
+                   pidl "\toffset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_ptr, &ptr);\n";
+                   pidl "\tif (ptr) {\n";
+                       ParseArrayPush($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
+                       pidl "\t}\n";
+               } else {
+                       ParseArrayPush($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
+               }
+       } else {
+               ParseElementPushScalar($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
+               if ($e->{POINTERS}) {
+                       ParseElementPushBuffer($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
+               }
+       }
+}      
 
-    return $res;
-}
+#####################################################################
+# parse a function
+sub ParseFunctionEthereal($)
+{ 
+       my($fn) = shift;
+       my $static = fn_prefix($fn);
 
-sub EtherealUuidRegistration($$$)
-{
-    my($module) = shift;
-    my($uuid) = shift;
-    my($uuid_version) = shift;
-    my($res) = "";
-
-    # Various objects for dissector initialisation
-
-    $res .= "static e_uuid_t uuid_dcerpc_$module = {\n";
-    $res .= "\t0x" . substr($uuid, 0, 8);
-    $res .= ", 0x" . substr($uuid, 9, 4);
-    $res .= ", 0x" . substr($uuid, 14, 4) . ",\n";
-    $res .= "\t{ 0x" . substr($uuid, 19, 2);
-    $res .= ", 0x" . substr($uuid, 21, 2);
-    $res .= ", 0x" . substr($uuid, 24, 2);
-    $res .= ", 0x" . substr($uuid, 26, 2);
-    $res .= ", 0x" . substr($uuid, 28, 2);
-    $res .= ", 0x" . substr($uuid, 30, 2);
-    $res .= ", 0x" . substr($uuid, 32, 2);
-    $res .= ", 0x" . substr($uuid, 34, 2) . " }\n";
-    $res .= "};\n\n";
+       # Comment displaying IDL for this function
        
-    $res .= "static guint16 ver_dcerpc_$module = " . $uuid_version . ";\n\n";
+       pidl "/*\n\n";
+       pidl IdlDump::DumpFunction($fn);
+       pidl "*/\n\n";
 
-    return $res;
-}
+       # Request
 
-#####################################################################
-# Generate code fragment for the tail of the dissector
+       pidl $static . "int $fn->{NAME}_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)\n";
+       pidl "{\n";
+       pidl "\tint flags = NDR_SCALARS|NDR_BUFFERS;\n\n";
+       pidl "\tguint32 ptr;\n\n";
 
-sub EtherealModuleRegistration($$$)
-{
-    my($module) = shift;
-    my($hf_register_info) = shift;
-    my($ett_info) = shift;
-    my($res) = "";
+       foreach my $e (@{$fn->{DATA}}) {
+               if (util::has_property($e, "in")) {
+                       ParseFunctionElementPush($e, "in");
+               }               
+       }
 
-    $res .= << "EOF";
-void
-proto_register_dcerpc_${module}(void)
-{
-        static hf_register_info hf[] = {
-$hf_register_info
-        };
+       pidl "\n\treturn offset;\n";
+       pidl "}\n\n";
 
-        static gint *ett[] = {
-                &ett_dcerpc_$module,
-$ett_info
-        };
+       # Response
 
-        proto_dcerpc_$module = proto_register_protocol("$module", "$module", "$module");
+       pidl $static . "int $fn->{NAME}_resp(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)\n";
+       pidl "{\n";
+       pidl "\tint flags = NDR_SCALARS|NDR_BUFFERS;\n\n";
+       pidl "\tguint32 ptr;\n\n";
 
-        proto_register_field_array(proto_dcerpc_$module, hf, array_length (hf));
-        proto_register_subtree_array(ett, array_length(ett));
+       foreach my $e (@{$fn->{DATA}}) {
+               if (util::has_property($e, "out")) {
+                       ParseFunctionElementPush($e, "out");
+               }               
+       }
 
+       if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
+           if ($fn->{RETURN_TYPE} eq "NTSTATUS") {
+               pidl "\n\toffset = dissect_ntstatus(tvb, offset, pinfo, tree, drep, hf_rc, NULL);\n";
+           } else {
+               pidl "\tproto_tree_add_text(tree, tvb, offset, -1, \"Unhandled return type '$fn->{RETURN_TYPE}'\");\n";
+           }
+       }
+
+       pidl "\n\treturn offset;\n";
+       pidl "}\n\n";
 }
 
-void
-proto_reg_handoff_dcerpc_$module(void)
+#####################################################################
+# produce a function call table
+sub FunctionTable($)
 {
-        dcerpc_init_uuid(proto_dcerpc_$module, ett_dcerpc_$module, 
-                        &uuid_dcerpc_$module, ver_dcerpc_$module, 
-                        dcerpc_${module}_dissectors, hf_opnum);
-}
-EOF
+       my($interface) = shift;
+       my($data) = $interface->{DATA};
+       my $count = 0;
+       my $uname = uc $interface->{NAME};
 
-    return $res;
-}
+       foreach my $d (@{$data}) {
+               if ($d->{TYPE} eq "FUNCTION") { $count++; }
+       }
 
-#####################################################################
-# Generate code fragment for DCERPC subdissector registration
+       if ($count == 0) {
+               return;
+       }
 
-sub EtherealSubdissectorRegistration($$)
-{
-    my($module) = shift;
-    my($functions) = shift;
-    my($res) = "";
+       pidl "static dcerpc_sub_dissector dcerpc_dissectors[] = {\n";
+       my $num = 0;
+       foreach my $d (@{$data}) {
+               if ($d->{TYPE} eq "FUNCTION") {
+                   # Strip module name from function name, if present
+                   my($n) = $d->{NAME};
+                   $n = substr($d->{NAME}, length($module) + 1),
+                       if $module eq substr($d->{NAME}, 0, length($module));
+                   pidl "\t{ $num, \"$n\",\n";
+                   pidl "\t\t$d->{NAME}_rqst,\n";
+                   pidl "\t\t$d->{NAME}_resp },\n";
+                   $num++;
+               }
+       }
+       pidl "};\n\n";
+}
 
-    $res .= "static dcerpc_sub_dissector dcerpc_${module}_dissectors[] = {\n";
 
-    my $num = 0;
+#####################################################################
+# parse the interface definitions
+sub ParseInterface($)
+{
+       my($interface) = shift;
+       my($data) = $interface->{DATA};
 
-    foreach my $name (@$functions) {
-       # Strip module name from function name, if present
-       my($n) = $name;
-       $n = substr($name, length($module) + 1),
-           if $module eq substr($name, 0, length($module));
-       
-       $res .= "\t{ $num, \"$n\",\n";
-       $res .= "\t\t${name}_rqst,\n";
-       $res .= "\t\t${name}_resp },\n";
-       $num++;
-    }
+       foreach my $d (@{$data}) {
+               if ($d->{TYPE} eq "TYPEDEF") {
+                   $structs{$d->{NAME}} = $d;
+           }
+       }
 
-    $res .= "};\n\n";
+       foreach my $d (@{$data}) {
+               ($d->{TYPE} eq "TYPEDEF") &&
+                   ParseTypedefEthereal($d);
+               ($d->{TYPE} eq "FUNCTION") && 
+                   ParseFunctionEthereal($d);
+       }
 
-    return $res;
+       FunctionTable($interface);
 }
 
-#####################################################################
-# Generate an ethereal dissector from an IDL syntax tree.
+# Convert an idl type to an ethereal FT_* type
 
-sub Parse($)
+sub type2ft($)
 {
-    my($idl) = shift;
-    my($res) = "";
+    my($t) = shift;
 
-    #
-    # Phase 1 : Gather information from IDL tree
-    #
+    return "FT_UINT32", if ($t eq "uint32");
+    return "FT_UINT16", if ($t eq "uint16");
+    return "FT_BYTES";
+}
 
-    my($module) = "";
-    my($uuid) = "";
-    my($uuid_version) = "";
-    my(@fns) = ();
+# Select an ethereal BASE_* type for an idl type
 
-    my($d, $e);
+sub type2base($)
+{
+    my($t) = shift;
 
-    foreach $d (@$idl) {
+    return "BASE_DEC", if ($t eq "uint32") or ($t eq "uint16");
+    return "BASE_NONE";
+}
 
-       # Get data from interface definition
+sub NeededFunction($)
+{
+       my $fn = shift;
+       $needed{"pull_$fn->{NAME}"} = 1;
+       $needed{"push_$fn->{NAME}"} = 1;
+       foreach my $e (@{$fn->{DATA}}) {
+           $needed{"hf_$e->{NAME}_$e->{TYPE}"} = {
+               'name' => $e->{NAME},
+               'type' => $e->{TYPE},
+               'ft'   => type2ft($e->{TYPE}),
+               'base' => type2base($e->{TYPE})
+               };
+           $e->{PARENT} = $fn;
+           $needed{"pull_$e->{TYPE}"} = 1;
+           $needed{"push_$e->{TYPE}"} = 1;
+       }
+}
 
-       $module = $d->{NAME}, if $d->{TYPE} eq "INTERFACE";
+sub NeededTypedef($)
+{
+       my $t = shift;
+       if (util::has_property($t->{DATA}, "public")) {
+               $needed{"pull_$t->{NAME}"} = 1;
+               $needed{"push_$t->{NAME}"} = 1;         
+       }
+       if ($t->{DATA}->{TYPE} eq "STRUCT") {
+               for my $e (@{$t->{DATA}->{ELEMENTS}}) {
+                       $e->{PARENT} = $t->{DATA};
+                       if ($needed{"pull_$t->{NAME}"}) {
+                               $needed{"pull_$e->{TYPE}"} = 1;
+                       }
+                       if ($needed{"push_$t->{NAME}"}) {
+                               $needed{"push_$e->{TYPE}"} = 1;
+                       }
+               }
+       }
+       if ($t->{DATA}->{TYPE} eq "UNION") {
+               for my $e (@{$t->{DATA}->{DATA}}) {
+                       $e->{PARENT} = $t->{DATA};
+                       if ($e->{TYPE} eq "UNION_ELEMENT") {
+                               if ($needed{"pull_$t->{NAME}"}) {
+                                       $needed{"pull_$e->{DATA}->{TYPE}"} = 1;
+                               }
+                               if ($needed{"push_$t->{NAME}"}) {
+                                       $needed{"push_$e->{DATA}->{TYPE}"} = 1;
+                               }
+                       }
+               }
+       }
+}
 
-       if ($d->{TYPE} eq "MODULEHEADER") {
-           $uuid = $d->{PROPERTIES}->{uuid}, 
-               if defined($d->{PROPERTIES}->{uuid});
-           $uuid_version = $d->{PROPERTIES}->{version};
+#####################################################################
+# work out what parse functions are needed
+sub BuildNeeded($)
+{
+       my($interface) = shift;
+       my($data) = $interface->{DATA};
+       foreach my $d (@{$data}) {
+               ($d->{TYPE} eq "FUNCTION") && 
+                   NeededFunction($d);
+       }
+       foreach my $d (reverse @{$data}) {
+               ($d->{TYPE} eq "TYPEDEF") &&
+                   NeededTypedef($d);
        }
+}
+
+#####################################################################
+# parse the interface definitions
+sub ModuleHeader($)
+{
+    my($h) = shift;
 
-       # Iterate over function definitions and register field info
+    $if_uuid = $h->{PROPERTIES}->{uuid};
+    $if_version = $h->{PROPERTIES}->{version};
+    $if_endpoints = $h->{PROPERTIES}->{endpoints};
+}
 
-       if ($d->{TYPE} eq "INTERFACE") {
+#####################################################################
+# parse a parsed IDL structure back into an IDL file
+sub Parse($$)
+{
+       my($idl) = shift;
+       my($filename) = shift;
 
-           foreach my $d (@{$d->{DATA}}) {
+       open(OUT, ">$filename") || die "can't open $filename";    
 
-               if ($d->{TYPE} eq "FUNCTION") {
+       pidl "/* parser auto-generated by pidl */\n\n";
+       pidl "#ifdef HAVE_CONFIG_H\n";
+       pidl "#include \"config.h\"\n";
+        pidl "#endif\n\n";
 
-                   # Register function name
+        pidl "#include \"packet-dcerpc.h\"\n";
+        pidl "#include \"packet-dcerpc-nt.h\"\n\n";
+        pidl "#include \"packet-dcerpc-common.h\"\n\n";
 
-                   $fns[$#fns + 1] = $d->{NAME};
+       pidl "#define NDR_SCALARS 1\n";
+       pidl "#define NDR_BUFFERS 2\n\n";
 
-                   # Register function fields (parameter names)
+       pidl "extern const value_string NT_errors[];\n\n";
 
-                   foreach $e (@{$d->{DATA}}) {
-                       AddField($e->{NAME}, $e->{TYPE});
-                   }
-               }
+       foreach my $x (@{$idl}) {
+           $module = $x->{NAME}, if $x->{TYPE} eq "INTERFACE";
+       }
 
-               if ($d->{TYPE} eq "TYPEDEF") {
+       pidl "static int proto_dcerpc_$module = -1;\n\n";
 
-                   # Register structure names
+       pidl "static gint ett_dcerpc_$module = -1;\n\n";
 
-                   $param_handlers{$d->{NAME}} = \&ParamStruct;
+       pidl "static int hf_opnum = -1;\n";
+       pidl "static int hf_rc = -1;\n";
+       pidl "static int hf_ptr = -1;\n";
+       pidl "static int hf_switch = -1;\n";
+       pidl "static int hf_policy_handle = -1;\n";
+       pidl "static int hf_array_size = -1;\n";
+       pidl "static int hf_length_is = -1;\n";
 
-                   # Register typedef fields (element names)
+       foreach my $x (@{$idl}) {
+           ($x->{TYPE} eq "MODULEHEADER") && 
+               ModuleHeader($x);
 
-                   if ($d->{DATA}->{TYPE} eq "STRUCT") {
-                       foreach $e (@{$d->{DATA}->{ELEMENTS}}) {
-                           AddField($e->{NAME}, $e->{TYPE});
-                       }
-                   }
+           if ($x->{TYPE} eq "INTERFACE") { 
+               BuildNeeded($x);
+
+               foreach my $y (keys(%needed)) {
+                   pidl "static int $y = -1;\n", if $y =~ /^hf_/;
                }
+
+               ParseInterface($x);
            }
        }
-    }
 
-    #
-    # Phase 2 : Spit out parser from fragments generated above
-    #
+       pidl "static e_uuid_t uuid_dcerpc_$module = {\n";
+       pidl "\t0x" . substr($if_uuid, 0, 8);
+       pidl ", 0x" . substr($if_uuid, 9, 4);
+       pidl ", 0x" . substr($if_uuid, 14, 4) . ",\n";
+       pidl "\t{ 0x" . substr($if_uuid, 19, 2);
+       pidl ", 0x" . substr($if_uuid, 21, 2);
+       pidl ", 0x" . substr($if_uuid, 24, 2);
+       pidl ", 0x" . substr($if_uuid, 26, 2);
+       pidl ", 0x" . substr($if_uuid, 28, 2);
+       pidl ", 0x" . substr($if_uuid, 30, 2);
+       pidl ", 0x" . substr($if_uuid, 32, 2);
+       pidl ", 0x" . substr($if_uuid, 34, 2) . " }\n";
+       pidl "};\n\n";
+
+       pidl "static guint16 ver_dcerpc_$module = " . $if_version . ";\n\n";
+
+
+       pidl "void proto_register_dcerpc_samr(void)\n";
+       pidl "{\n";
+        pidl "\tstatic hf_register_info hf[] = {\n";
+
+       pidl "\t{ &hf_opnum, { \"Operation\", \"$module.opnum\", FT_UINT16, BASE_DEC, NULL, 0x0, \"Operation\", HFILL }},\n";
+       pidl "\t{ &hf_policy_handle, { \"Policy handle\", \"$module.policy\", FT_BYTES, BASE_NONE, NULL, 0x0, \"Policy handle\", HFILL }},\n";
+       pidl "\t{ &hf_rc, { \"Return code\", \"$module.rc\", FT_UINT32, BASE_HEX, VALS(NT_errors), 0x0, \"Return status code\", HFILL }},\n";
+       pidl "\t{ &hf_switch, { \"Switch\", \"$module.switch\", FT_UINT16, BASE_DEC, NULL, 0x0, \"Switch\", HFILL }},\n";
+       pidl "\t{ &hf_array_size, { \"Array size\", \"$module.array_size\", FT_UINT32, BASE_DEC, NULL, 0x0, \"Array size\", HFILL }},\n";
+       pidl "\t{ &hf_length_is, { \"Length is\", \"$module.length_is\", FT_UINT32, BASE_DEC, NULL, 0x0, \"Length is\", HFILL }},\n";
+       pidl "\t{ &hf_ptr, { \"Pointer\", \"$module.ptr\", FT_UINT32, BASE_HEX, NULL, 0x0, \"Pointer\", HFILL }},\n";
+
+       foreach my $x (keys(%needed)) {
+           next, if !($x =~ /^hf_/);
+
+           pidl "\t{ &$x,\n";
+           pidl "\t  { \"$needed{$x}{name}\", \"$x\", $needed{$x}{ft}, $needed{$x}{base},\n";
+           pidl"\t  NULL, 0, \"$x\", HFILL }},\n";
+       }
 
-    $res .= EtherealHeader($module);
-    $res .= EtherealFieldDefinitions();
-    $res .= EtherealSubtreeDefinitions($module);
+       pidl "\t};\n\n";
 
-    foreach $d (@$idl) {
+        pidl "\tstatic gint *ett[] = {\n";
+       pidl "\t\t&ett_dcerpc_$module,\n";
+       pidl "\t};\n\n";
 
-       if ($d->{TYPE} eq "INTERFACE") {
-           foreach $d (@{$d->{DATA}}) {
+        pidl "\tproto_dcerpc_$module = proto_register_protocol(\"$module\", \"$module\", \"$module\");\n\n";
 
-               # Generate function code fragments
+       pidl "\tproto_register_field_array(proto_dcerpc_$module, hf, array_length (hf));\n";
+        pidl "\tproto_register_subtree_array(ett, array_length(ett));\n";
 
-               $res .= EtherealFunction($d), if $d->{TYPE} eq "FUNCTION";
+        pidl "}\n\n";
 
-               # Generate structure code fragments
+       pidl "void proto_reg_handoff_dcerpc_$module(void)\n";
+       pidl "{\n";
+        pidl "\tdcerpc_init_uuid(proto_dcerpc_$module, ett_dcerpc_$module, \n";
+       pidl "\t\t&uuid_dcerpc_$module, ver_dcerpc_$module, \n";
+       pidl "\t\tdcerpc_dissectors, hf_opnum);\n";
+        pidl "}\n";
 
-               $res .= EtherealTypedef($module, $d), 
-                   if $d->{TYPE} eq "TYPEDEF";
-           }
-       }
-    }
-
-    $res .= EtherealSubdissectorRegistration($module, \@fns);
-
-    if ($uuid ne "") {
-       $res .= EtherealUuidRegistration($module, $uuid, $uuid_version);
-       $res .= EtherealModuleRegistration
-           ($module, EtherealFieldInitialisation($module),
-            EtherealSubtreeInitialisation());
-    }
-
-    return $res;
+       close(OUT);
 }
 
 1;
index 6004ebb145a9df09209e5fd99f53e7488347d772..b3dc7c1b38de613de6045f343ad7a1e564575072 100755 (executable)
@@ -145,7 +145,7 @@ sub process_file($)
 
        if ($opt_eparser) {
                my($parser) = dirname($output) . "/packet-dcerpc-$basename.c";
-               util::FileSave($parser, IdlEParser::Parse($pidl));
+               IdlEParser::Parse($pidl, $parser);
        }
 
        if ($opt_diff) {