diff options
author | Jelmer Vernooij <jelmer@samba.org> | 2005-05-25 13:50:27 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:17:01 -0500 |
commit | e427f58622e3d88c59953d6c1fb583acfb046213 (patch) | |
tree | 4fe708ec07cdcb85dd3af028e158505e065ca59e /source4/build/pidl | |
parent | e7b3f91678a27d85791f7a62fc418988edc92214 (diff) | |
download | samba-e427f58622e3d88c59953d6c1fb583acfb046213.tar.gz samba-e427f58622e3d88c59953d6c1fb583acfb046213.tar.bz2 samba-e427f58622e3d88c59953d6c1fb583acfb046213.zip |
r6973: Merge new version of pidl into the main SAMBA_4_0 branch.
The main difference in this new version is the extra data structure generated
between the IDL data structure and the NDR parser:
IDL -> NDR -> { ndr_parser, ndr_header, eparser, etc }
This makes the ndr_parser.pm internals much more sane.
Other changes include:
- Remove unnecessary calls with NDR_BUFFERS (for example, GUID doesn't have any buffers, just scalars) as well as some (unnecessary) nested setting of flags.
- Parse array loops in the C code rather then calling ndr_pull_array(). This allows us to have, for example, arrays of pointers or arrays of pointers to arrays, etc..
- Use if() {} rather then if () goto foo; everywhere
- NDR_IN no longer implies LIBNDR_FLAG_REF_ALLOC
- By default, top level pointers are now "ref" (as is the default in
most other IDL compilers). This can be overridden using the
default_pointer_top() property.
- initial work on new ethereal parser generators by Alan DeKok and me
- pidl now writes errors in the standard format used by compilers, which
is parsable by most editors
- ability to warn about the fact that pidl extension(s) have been used,
useful for making sure IDL files work with other IDL compilers.
oh, and there's probably some other things I can't think of right now..
(This used to be commit 13cf227615f6b9e0e5fa62e59197024410254f01)
Diffstat (limited to 'source4/build/pidl')
-rw-r--r-- | source4/build/pidl/README | 4 | ||||
-rw-r--r-- | source4/build/pidl/com_header.pm | 4 | ||||
-rw-r--r-- | source4/build/pidl/compat.pm | 55 | ||||
-rw-r--r-- | source4/build/pidl/dcom_proxy.pm | 2 | ||||
-rw-r--r-- | source4/build/pidl/eparser.pm | 865 | ||||
-rw-r--r-- | source4/build/pidl/eth_header.pm | 102 | ||||
-rw-r--r-- | source4/build/pidl/eth_parser.pm | 1410 | ||||
-rw-r--r-- | source4/build/pidl/idl.pm | 159 | ||||
-rw-r--r-- | source4/build/pidl/idl.yp | 49 | ||||
-rw-r--r-- | source4/build/pidl/ndr.pm | 286 | ||||
-rw-r--r-- | source4/build/pidl/ndr_client.pm | 8 | ||||
-rw-r--r-- | source4/build/pidl/ndr_header.pm | 128 | ||||
-rw-r--r-- | source4/build/pidl/ndr_parser.pm | 1873 | ||||
-rw-r--r-- | source4/build/pidl/needed.pm | 80 | ||||
-rw-r--r-- | source4/build/pidl/odl.pm | 17 | ||||
-rwxr-xr-x | source4/build/pidl/pidl.pl | 62 | ||||
-rw-r--r-- | source4/build/pidl/test.pm | 2 | ||||
-rw-r--r-- | source4/build/pidl/typelist.pm | 219 | ||||
-rw-r--r-- | source4/build/pidl/validator.pm | 46 |
19 files changed, 3095 insertions, 2276 deletions
diff --git a/source4/build/pidl/README b/source4/build/pidl/README index e087888840..eac0674153 100644 --- a/source4/build/pidl/README +++ b/source4/build/pidl/README @@ -19,8 +19,8 @@ validator.pm - Validates the parse tree -- DCE/RPC+NDR -- ndr_client.pm - Generates client call functions in C using the NDR parser -eparser.pm - Generates a parser for the ethereal network sniffer by - applying regexes to the output of parser.pm +eth_parser.pm - Generates a parser for the ethereal network sniffer +eth_header.pm - Generates a header for ethereal swig.pm - Generates SWIG interface files (.i) ndr_header.pm - Generates a header file with structures ndr.pm - Generates pull/push functions for parsing NDR diff --git a/source4/build/pidl/com_header.pm b/source4/build/pidl/com_header.pm index 1c7194d85c..95bbc9c720 100644 --- a/source4/build/pidl/com_header.pm +++ b/source4/build/pidl/com_header.pm @@ -14,7 +14,7 @@ sub GetArgumentProtoList($) foreach my $a (@{$f->{ELEMENTS}}) { - $res .= ", " . typelist::mapType($a) . " "; + $res .= ", " . typelist::mapType($a->{TYPE}) . " "; my $l = $a->{POINTERS}; $l-- if ($a->{TYPE} eq "string"); @@ -61,7 +61,7 @@ sub HeaderVTable($) my $data = $interface->{DATA}; foreach my $d (@{$data}) { - $res .= "\t" . typelist::mapScalarType($d->{RETURN_TYPE}) . " (*$d->{NAME}) (struct $interface->{NAME} *d, TALLOC_CTX *mem_ctx" . GetArgumentProtoList($d) . ");\\\n" if ($d->{TYPE} eq "FUNCTION"); + $res .= "\t" . typelist::mapType($d->{RETURN_TYPE}) . " (*$d->{NAME}) (struct $interface->{NAME} *d, TALLOC_CTX *mem_ctx" . GetArgumentProtoList($d) . ");\\\n" if ($d->{TYPE} eq "FUNCTION"); } $res .= "\n"; $res .= "struct $interface->{NAME}_vtable {\n"; diff --git a/source4/build/pidl/compat.pm b/source4/build/pidl/compat.pm new file mode 100644 index 0000000000..3ab94b70f3 --- /dev/null +++ b/source4/build/pidl/compat.pm @@ -0,0 +1,55 @@ +################################################### +# IDL Compatibility checker +# Copyright jelmer@samba.org 2005 +# released under the GNU GPL + +package IDLCompat; + +use strict; + +my($res); + +sub warning($$) +{ + my $l = shift; + my $m = shift; + + print "$l->{FILE}:$l->{LINE}:$m\n"; +} + +sub CheckInterface($) +{ + my $if = shift; + if (util::has_property($if, "pointer_default_top")) { + warning($if, "pointer_default_top() is pidl-specific"); + } + + foreach my $x (@{$if->{DATA}}) { + if ($x->{TYPE} eq "DECLARE") { + warning($if, "the declare keyword is pidl-specific"); + next; + } + + if ($x->{TYPE} eq "TYPEDEF") { + if ($x->{DATA}->{TYPE} eq "UNION") { + if (util::has_property($x, "nodiscriminant")) { + warning($x, "nodiscriminant property is pidl-specific"); + } + } + } + } +} + +sub Check($) +{ + my $pidl = shift; + my $res = ""; + + foreach my $x (@{$pidl}) { + CheckInterface($x) if ($x->{TYPE} eq "INTERFACE"); + } + + return $res; +} + +1; diff --git a/source4/build/pidl/dcom_proxy.pm b/source4/build/pidl/dcom_proxy.pm index 8cc5547680..3d46064548 100644 --- a/source4/build/pidl/dcom_proxy.pm +++ b/source4/build/pidl/dcom_proxy.pm @@ -173,7 +173,7 @@ sub RegistrationFunction($$) next if $interface->{TYPE} ne "INTERFACE"; next if not util::has_property($interface, "object"); - my $data = $interface->{INHERITED_DATA}; + my $data = $interface->{DATA}; my $count = 0; foreach my $d (@{$data}) { if ($d->{TYPE} eq "FUNCTION") { $count++; } diff --git a/source4/build/pidl/eparser.pm b/source4/build/pidl/eparser.pm deleted file mode 100644 index 23ff8e7954..0000000000 --- a/source4/build/pidl/eparser.pm +++ /dev/null @@ -1,865 +0,0 @@ -################################################### -# Samba4 parser generator for IDL structures -# Copyright tridge@samba.org 2000-2003 -# Copyright tpot@samba.org 2001,2004-2005 -# released under the GNU GPL - -package IdlEParser; - -use ndr_parser; -use strict; - -# the list of needed functions -my %needed; -my %bitmaps; - -my $module; -my $if_uuid; -my $if_version; -my $if_endpoints; - -sub pidl($) -{ - print OUT shift; -} - -##################################################################### -# a list of annotations - -my $nopull_typedefs = { -# "policy_handle" => "1", -}; - -##################################################################### -# work out is a parse function should be declared static or not -sub fn_prefix($) -{ - my $fn = shift; - if ($fn->{TYPE} eq "TYPEDEF") { - if (util::has_property($fn, "public")) { - return ""; - } - } - - if ($fn->{TYPE} eq "FUNCTION") { - if (util::has_property($fn, "public")) { - return ""; - } - } - return "static "; -} - - -##################################################################### -# parse a function -sub ParseFunctionPull($) -{ - my($fn) = shift; - my $static = fn_prefix($fn); - - # request function - pidl "int $fn->{NAME}_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)\n{\n"; - - pidl "\tstruct pidl_pull *ndr = pidl_pull_init(tvb, offset, pinfo, drep);\n"; - pidl "\tstruct $fn->{NAME} *r = talloc(NULL, struct $fn->{NAME});\n"; - pidl "\tpidl_tree ptree;\n\n"; - - pidl "\tptree.proto_tree = tree;\n"; - pidl "\tptree.subtree_list = NULL;\n\n"; - - pidl "\tndr_pull_$fn->{NAME}(ndr, NDR_IN, &ptree, r);\n"; - - pidl "\n\treturn ndr->offset;\n"; - pidl "}\n\n"; - - # response function - pidl "int $fn->{NAME}_resp(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)\n{\n"; - - pidl "\tstruct pidl_pull *ndr = pidl_pull_init(tvb, offset, pinfo, drep);\n"; - pidl "\tstruct $fn->{NAME} *r = talloc(NULL, struct $fn->{NAME});\n"; - pidl "\tpidl_tree ptree;\n\n"; - - pidl "\tptree.proto_tree = tree;\n"; - pidl "\tptree.subtree_list = NULL;\n\n"; - - pidl "\tndr_pull_$fn->{NAME}(ndr, NDR_OUT, &ptree, r);\n"; - - pidl "\n\treturn ndr->offset;\n"; - pidl "}\n\n"; -} - -##################################################################### -# produce a function call table -sub FunctionTable($) -{ - my($interface) = shift; - my($data) = $interface->{DATA}; - - 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"; -} - -sub type2ft($) -{ - my($t) = shift; - - return "FT_UINT$1" if $t =~ /uint(8|16|32|64)/; - return "FT_INT$1" if $t =~ /int(8|16|32|64)/; - return "FT_UINT64", if $t eq "HYPER_T" or $t eq "NTTIME" - or $t eq "NTTIME_1sec" or $t eq "NTTIME_hyper"; - - # Type is an enum - - return "FT_UINT16"; -} - -# Determine the display base for an element - -sub elementbase($) -{ - my($e) = shift; - - if (my $base = util::has_property($e, "display")) { - return "BASE_" . uc($base); - } - - return "BASE_DEC", if $e->{TYPE} eq "ENUM"; - return "BASE_DEC", if $e->{TYPE} =~ /u?int(8|16|32|64)/; - return "BASE_DEC", if $e->{TYPE} eq "NTTIME" or $e->{TYPE} eq "HYPER_T"; - - # Probably an enum - - return "BASE_DEC"; -} - -# Convert a IDL structure field name (e.g access_mask) to a prettier -# string like 'Access Mask'. - -sub field2name($) -{ - my($field) = shift; - - $field =~ s/_/ /g; # Replace underscores with spaces - $field =~ s/(\w+)/\u\L$1/g; # Capitalise each word - - return $field; -} - -sub NeededFunction($) -{ - my $fn = shift; - - $needed{"pull_$fn->{NAME}"} = 1; - - # Add entries for function arguments - - foreach my $e (@{$fn->{ELEMENTS}}) { - - $e->{PARENT} = $fn; - $needed{"pull_$e->{TYPE}"} = 1; - - if (NdrParser::is_scalar_type($e->{TYPE})) { - - if (defined($e->{ARRAY_LEN}) or - util::has_property($e, "size_is")) { - - # Array of scalar types - - $needed{"hf_$fn->{NAME}_$e->{NAME}_array"} = { - 'name' => field2name($e->{NAME}), - 'type' => $e->{TYPE}, - 'ft' => "FT_BYTES", - 'base' => elementbase($e) - }; - - } else { - - $needed{"hf_$fn->{NAME}_$e->{NAME}"} = { - 'name' => field2name($e->{NAME}), - 'type' => $e->{TYPE}, - 'ft' => type2ft($e->{TYPE}), - 'base' => elementbase($e) - }; - - } - - $e->{PARENT} = $fn; - - } else { - $needed{"ett_$e->{TYPE}"} = 1; - } - } - - # Add entry for return value - - $needed{"hf_$fn->{NAME}_result"} = { - 'name' => field2name('result'), - 'type' => $fn->{RETURN_TYPE}, - 'ft' => type2ft($fn->{RETURN_TYPE}), - 'base' => elementbase($fn) - }; -} - -sub bitmapbase($) -{ - my $e = shift; - - return "16", if util::has_property($e->{DATA}, "bitmap16bit"); - return "8", if util::has_property($e->{DATA}, "bitmap8bit"); - - return "32"; -} - -sub NeededTypedef($) -{ - my $t = shift; - - if (util::has_property($t, "public")) { - $needed{"pull_$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 (NdrParser::is_scalar_type($e->{TYPE})) { - - if (defined($e->{ARRAY_LEN}) or - util::has_property($e, "size_is")) { - - # Arrays of scalar types are FT_BYTES - - $needed{"hf_$t->{NAME}_$e->{NAME}_array"} = { - 'name' => field2name($e->{NAME}), - 'type' => $e->{TYPE}, - 'ft' => "FT_BYTES", - 'base' => elementbase($e) - }; - - } else { - - $needed{"hf_$t->{NAME}_$e->{NAME}"} = { - 'name' => field2name($e->{NAME}), - 'type' => $e->{TYPE}, - 'ft' => type2ft($e->{TYPE}), - 'base' => elementbase($e) - }; - } - - $e->{PARENT} = $t->{DATA}; - - if ($needed{"pull_$t->{NAME}"}) { - $needed{"pull_$e->{TYPE}"} = 1; - } - - } else { - $needed{"ett_$e->{TYPE}"} = 1; - } - } - } - - if ($t->{DATA}->{TYPE} eq "UNION") { - for my $e (@{$t->{DATA}->{ELEMENTS}}) { - - $e->{PARENT} = $t->{DATA}; - - if ($needed{"pull_$t->{NAME}"}) { - $needed{"pull_$e->{TYPE}"} = 1; - } - - $needed{"ett_$e->{TYPE}"} = 1; - } - - $needed{"ett_$t->{NAME}"} = 1; - } - - if ($t->{DATA}->{TYPE} eq "ENUM") { - - $needed{"hf_$t->{NAME}"} = { - 'name' => field2name($t->{NAME}), - 'ft' => 'FT_UINT16', - 'base' => 'BASE_DEC', - 'strings' => "VALS($t->{NAME}_vals)" - }; - } - - if ($t->{DATA}->{TYPE} eq "BITMAP") { - - $bitmaps{$t->{NAME}} = $t; - - foreach my $e (@{$t->{DATA}{ELEMENTS}}) { - $e =~ /^(.*?) \( (.*?) \)$/; - $needed{"hf_$t->{NAME}_$1"} = { - 'name' => "$1", - 'ft' => "FT_BOOLEAN", - 'base' => bitmapbase($t), - 'bitmask' => "$2" - }; - } - - $needed{"ett_$t->{NAME}"} = 1; - } -} - -##################################################################### -# 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; - - $if_uuid = $h->{PROPERTIES}->{uuid}; - $if_version = $h->{PROPERTIES}->{version}; - $if_endpoints = $h->{PROPERTIES}->{endpoints}; -} - -##################################################################### -# Generate a header file that contains function prototypes for -# structs and typedefs. -sub ParseHeader($$) -{ - my($idl) = shift; - my($filename) = shift; - - open(OUT, ">$filename") || die "can't open $filename"; - - pidl "/* parser auto-generated by pidl */\n\n"; - - foreach my $x (@{$idl}) { - if ($x->{TYPE} eq "INTERFACE") { - foreach my $d (@{$x->{DATA}}) { - - # Make prototypes for [public] structures and - # unions. - - if ($d->{TYPE} eq "TYPEDEF" and - util::has_property($d, "public")) { - - if ($d->{DATA}{TYPE} eq "STRUCT") { - pidl "void ndr_pull_$d->{NAME}(struct ndr_pull *ndr, int ndr_flags, proto_tree *tree, struct $d->{NAME} *r);\n\n"; - } - - if ($d->{DATA}{TYPE} eq "UNION") { - pidl "void ndr_pull_$d->{NAME}(struct ndr_pull *ndr, int ndr_flags, proto_tree *tree, union $d->{NAME} *r, uint16 level);\n\n"; - } - } - } - } - } - - close(OUT); -} - -##################################################################### -# generate code to parse an enum - -sub ParseEnum($) -{ - my ($e) = shift; - - pidl "static const value_string $e->{PARENT}{NAME}_vals[] =\n"; - pidl "{\n"; - - foreach my $x (@{$e->{ELEMENTS}}) { - $x =~ /([^=]*)=(.*)/; - pidl "\t{ $1, \"$1\" },\n"; - } - - pidl "};\n\n"; -} - -##################################################################### -# rewrite autogenerated header file -sub RewriteHeader($$$) -{ - my($idl) = shift; - my($input) = shift; - my($output) = shift; - - NdrParser::Load($idl); - - %needed = (); - - # Open files - - open(IN, "<$input") || die "can't open $input for reading"; - open(OUT, ">$output") || die "can't open $output for writing"; - - # Read through file - - while(<IN>) { - - # Not interested in ndr_push or ndr_print routines as they - # define structures we aren't interested in. - - s/^NTSTATUS ndr_push.*?;\n//smg; - s/^void ndr_print.*?;\n//smg; - - # Get rid of async send and receive function. - - s/^NTSTATUS dcerpc_.*?;//smg; - s/^struct rpc_request.*?;//smg; - - # Rewrite librpc includes - - s/^\#include\ \"librpc\/gen_ndr\/ndr_(.*?).h\"$ - /\#include \"packet-dcerpc-$1.h\"/smgx; - - # Rename struct ndr_pull to struct pidl_pull - - s/struct ndr_pull \*ndr/struct pidl_pull \*ndr/smg; - - # Change prototypes for public functions - - s/(struct pidl_pull \*ndr, int ndr_flags)/$1, pidl_tree *tree/smg; - - # Bitmaps - - s/int ndr_flags, (pidl_tree \*tree), (uint32_t \*r\);)/$1, int hf, $2/smg; - - pidl $_; - } - - close(OUT); -} - -##################################################################### -# rewrite autogenerated C file -sub RewriteC($$$) -{ - my($idl) = shift; - my($input) = shift; - my($output) = shift; - - NdrParser::Load($idl); - - # Open files - - open(IN, "<$input") || die "can't open $input for reading"; - open(OUT, ">$output") || die "can't open $output for writing"; - - # Get name of module - - foreach my $x (@{$idl}) { - if ($x->{TYPE} eq "INTERFACE") { - ModuleHeader($x); - $module = $x->{NAME}; - BuildNeeded($x); - } - } - - pidl "#include \"eparser.h\"\n\n"; - - pidl "extern const value_string NT_errors[];\n\n"; - - # Declarations for hf variables - - pidl "static int hf_opnum = -1;\n"; - pidl "static int hf_ptr = -1;\n"; - pidl "static int hf_array_size = -1;\n"; - pidl "static int hf_result_NTSTATUS = -1;\n"; - - pidl "\n"; - - foreach my $y (keys(%needed)) { - pidl "static int $y = -1;\n", if $y =~ /^hf_/; - } - - pidl "\n"; - - foreach my $y (keys(%needed)) { - pidl "static gint $y = -1;\n", if $y =~ /^ett_/; - } - - pidl "\n"; - - # Read through file - - my $cur_fn = ""; - - while(<IN>) { - - # - # Regexps to do a first pass at removing stuff we aren't - # interested in for ethereal parsers. - # - - next, if /^\#include \"includes.h\"/; - - # Rewrite includes to packet-dcerpc-foo.h instead of ndr_foo.h - - s/^\#include \".*?ndr_(.*?).h\"$/\#include \"packet-dcerpc-$1.h\"/smg; - - if (/\.h\"$/) { - pidl $_; - foreach my $x (@{$idl}) { - if ($x->{TYPE} eq "INTERFACE") { - foreach my $y (@{$x->{INHERITED_DATA}}) { - if ($y->{TYPE} eq "TYPEDEF") { - ParseEnum($y->{DATA}), if $y->{DATA}{TYPE} eq "ENUM"; - } - } - } - } - next; - } - - # Remove the NDR_CHECK() macro calls. Ethereal take care of - # this for us as part of the tvbuff_t structure. - - s/NDR_CHECK\((.*)\)/$1/g; - - # We're not interested in ndr_{print,push,size} functions so - # just delete them. - - next, if /^(static )?NTSTATUS ndr_push/ .. /^}/; - next, if /^void ndr_print/ .. /^}/; - next, if /^size_t ndr_size/ .. /^}/; - - # get rid of the init functions - next, if /^NTSTATUS dcerpc_ndr_\w+_init/ .. /^}/; - - # Get rid of dcerpc interface structures and functions since - # they are also not very interesting. - - next, if /^static const struct dcerpc_interface_call/ .. /^};/; - next, if /^static const char \* const [a-z]+_endpoint_strings/ ../^};/; - next, if /^static const struct dcerpc_endpoint_list/ .. /^};/; - next, if /^const struct dcerpc_interface_table/ .. /^};/; - next, if /^static NTSTATUS dcerpc_ndr_[a-z]+_init/ .. /^}/; - next, if /^NTSTATUS dcerpc_[a-z]+_init/ .. /^}/; - - # - # Remember which structure or function we are processing. - # - - $cur_fn = $1, if /NTSTATUS ndr_pull_(.*?)\(struct/; - - # Skip functions we have marked as nopull - - my $skip_fn = 0; - - foreach my $f (keys(%{$nopull_typedefs})) { - $skip_fn = 1, if $cur_fn eq $f; - } - - $cur_fn = "", if /^}/; - - next, if $skip_fn; - - # - # OK start wrapping the ndr_pull functions that actually - # implement the NDR decoding routines. This mainly consists - # of adding a couple of parameters to each function call. - # - - # Add proto tree and name argument to ndr_pull_unique_ptr() calls. - - s/(ndr_pull_unique_ptr\(ndr,\ (&_ptr_([^\)]*?))\);) - /ndr_pull_ptr(ndr, tree, "$3", $2);/smgx; - - # Wrap ndr_pull_array_size() and ndr_pull_array_length() - # functions. Add leading space in front of first parameter so - # we won't get caught by later regexps. - - s/(ndr_pull_array_(size|length)\(ndr,\ ([^\)]*?)\);) - /ndr_pull_array_$2( ndr, tree, $3);/smgx; - - # Add tree argument to ndr_pull_array() and - # ndr_pull_array_foo() calls. - - s/(ndr_pull_array\( - ndr,\ - ([^,]*?),\ # NDR_SCALARS etc - (\(void\ \*\*\)r->(in|out|)\.?([^,]*?)),\ # Pointer to array entries - ([^\)].*?)\);) # All other arguments - /ndr_pull_array( ndr, $2, tree, $3, $6);/smgx; - - s/(ndr_pull_array_([^\(]*?)\( - ndr,\ - ([^,]*?),\ # NDR_SCALARS etc - (r->((in|out).)?([^,]*?)),\ # Pointer to array elements - (.*?)\);) # Number of elements - /ndr_pull_array_$2( ndr, $3, tree, hf_${cur_fn}_$7_array, $4, $8);/smgx; - - # Save ndr_pull_relative_ptr{1,2}() calls from being wrapped by the - # proceeding regexp by adding a leading space. - - s/ndr_pull_(relative_ptr1|relative_ptr2)\((.*?)\);/ - ndr_pull_$1( $2);/smgx; - - # Enums - - s/(^static\ NTSTATUS\ ndr_pull_(.+?),\ int\ ndr_flags,\ (enum\ .+?)\)) - /static NTSTATUS ndr_pull_$2, pidl_tree *tree, int hf, $3)/smgx; - s/uint(8|16|32) v;/uint$1_t v;/smg; - s/(ndr_pull_([^\(]+?)\(ndr,\ NDR_[^,]*,\ &_level\);) - /ndr_pull_$2(ndr, tree, hf_${cur_fn}_level, &_level);/smgx; - - # Bitmaps - - s/(^(static\ )?NTSTATUS\ ndr_pull_(.+?),\ int\ ndr_flags,\ uint(8|16|32)_t\ \*r\)) - /NTSTATUS ndr_pull_$3, pidl_tree *tree, int hf, uint$4_t *r)/smgx; - - if (/ndr_pull_([^\)]*?)\(ndr,\ NDR_[^,]*,\ &v\);/) { - - s/(ndr_pull_([^\)]*?)\(ndr,\ (NDR_[^,]*?),\ &v\);) - /ndr_pull_$2(ndr, tree, hf, &v);/smgx; - - pidl $_; - - if (defined($bitmaps{$cur_fn})) { - pidl "\t{\n\t\tproto_tree *subtree = NULL;\n\n"; - pidl "\t\tif (tree->proto_tree)\n\t\t\tsubtree = proto_item_add_subtree(tree->proto_tree->last_child, ett_$cur_fn);\n\n"; - foreach my $e (@{$bitmaps{$cur_fn}->{DATA}{ELEMENTS}}) { - $e =~ /^(.*?) \( (.*?) \)$/; - pidl "\t\tproto_tree_add_boolean(subtree, hf_${cur_fn}_$1, ndr->tvb, ndr->offset - sizeof(v), sizeof(v), v);\n"; - } - pidl "\t}\n"; - } - - next; - } - - # Call ethereal wrappers for pull of scalar values in - # structures and functions, e.g - # - # ndr_pull_uint32(ndr, &r->in.access_mask); - # ndr_pull_uint32(ndr, &r->idx); - - if (/(ndr_pull_([^\)]*?)\(ndr, NDR_[^,]*?, (&?r->((in|out)\.)?([^\)]*?))\);)/ and NdrParser::is_scalar_type($2)) { - - my $pull_type = "${cur_fn}_$6"; - - if (defined($needed{"hf_$2"})) { - $pull_type = "$2"; - } - - s/(ndr_pull_([^\)]*?)\( - ndr,\ - NDR_[^,]*?,\ - (&?r->((in|out)\.)? # Function args contain leading junk - ([^\)]*?)) # Element name - \);) - /ndr_pull_$2(ndr, tree, hf_$pull_type, $3);/smgx; - } - - # Add tree and hf argument to pulls of "internal" scalars like - # array sizes, levels, etc. - - s/(ndr_pull_(uint32|uint16)\( - ndr,\ - NDR_[^,]*?,\ - (&_([^\)]*?)) # Internal arg names have leading underscore - \);) - /ndr_pull_$2(ndr, tree, hf_$4, $3);/smgx; - - # Add subtree argument to calls dissecting structures/unions, e.g - # - # ndr_pull_string(ndr, NDR_SCALARS|NDR_BUFFERS, &r->command); - # ndr_pull_atsvc_enum_ctr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.ctr); - - # Three argument version is for structures - - if (/ndr_pull_([^\)]*?)\(ndr, (NDR_[^,]*?), ([^,]*?)\);/ and - not NdrParser::is_scalar_type($1)) { - s/(ndr_pull_([^\)]*?)\( - ndr,\ - (NDR_[^,]*?),\ - (&?r->((in|out)\.)?([^\(].*?))\);) - /ndr_pull_$2(ndr, $3, get_subtree(tree, \"$7\", ndr, ett_$2), $4); - /smgx; - } - - # Four argument version if for unions - if (/ndr_pull_([^\)]*?)\(ndr, (NDR_[SB][^,]*?), ([^,]*?), ([^,]*?)\);/ and - not NdrParser::is_scalar_type($1)) { - s/(ndr_pull_([^\)]*?)\( - ndr,\ - (NDR_[^,]*?),\ - (&?r->((in|out)\.)?([^\(].*?))\);) - /ndr_pull_$2(ndr, $3, get_subtree(tree, \"$2\", ndr, ett_$2), $4); - /smgx; - } - - # Add proto_tree parameter to pull function prototypes, e.g - # - # static NTSTATUS ndr_pull_atsvc_JobInfo(struct ndr_pull *ndr, - # int ndr_flags, struct atsvc_JobInfo *r) - - s/^((static\ )?NTSTATUS\ ndr_pull_([^\(]*?)\( - struct\ ndr_pull\ \*ndr,\ - int\ (ndr_)?flags) - /$1, proto_tree \*tree/smgx; - - # Add proto_tree parameter to ndr_pull_subcontext_flags_fn() - - s/(ndr_pull_subcontext_flags_fn\(ndr)(.*?);/$1, tree$2;/smg; - - # Get rid of ndr_pull_error() calls for the moment. Ethereal - # should take care of buffer overruns and inconsistent array - # sizes for us but it would be nice to have some error text in - # the dissection. - - s/(return ndr_pull_error([^;]*?);)/return NT_STATUS_OK; \/\/ $1/smg; - - # Rename proto_tree args to pidl_tree - - s/(int (ndr_)?flags), proto_tree \*tree/$1, pidl_tree \*tree/smg; - - # Rename struct ndr_pull to struct pidl_pull - - s/struct ndr_pull \*ndr/struct pidl_pull \*ndr/smg; - - # Fix some internal variable declarations - - s/(u?)int(8|16|32) _level;/$1int$2_t _level;/smg; - s/ndr_pull_([^\(]*)\(ndr,\ tree,\ hf_level,\ &_level\); - /ndr_pull_$1(ndr, tree, hf_level_$1, &_level);/smgx; - - # Set the end of a structure - - s/(ndr_pull_struct_end.*)/$1\tproto_item_set_end(tree->proto_tree, ndr->tvb, ndr->offset);\n/smg; - - pidl $_; - } - - # Function call table - - foreach my $x (@{$idl}) { - if ($x->{TYPE} eq "INTERFACE") { - foreach my $y (@{$x->{"INHERITED_DATA"}}) { - ($y->{TYPE} eq "FUNCTION") && ParseFunctionPull($y); - } - - FunctionTable($x); - } - } - - # Ethereal protocol registration - - pidl "int proto_dcerpc_pidl_$module = -1;\n\n"; - - pidl "static gint ett_dcerpc_$module = -1;\n\n"; - - if (defined($if_uuid)) { - - pidl "static e_uuid_t uuid_dcerpc_$module = {\n"; - pidl "\t0x" . substr($if_uuid, 1, 8); - pidl ", 0x" . substr($if_uuid, 10, 4); - pidl ", 0x" . substr($if_uuid, 15, 4) . ",\n"; - pidl "\t{ 0x" . substr($if_uuid, 20, 2); - pidl ", 0x" . substr($if_uuid, 22, 2); - pidl ", 0x" . substr($if_uuid, 25, 2); - pidl ", 0x" . substr($if_uuid, 27, 2); - pidl ", 0x" . substr($if_uuid, 29, 2); - pidl ", 0x" . substr($if_uuid, 31, 2); - pidl ", 0x" . substr($if_uuid, 33, 2); - pidl ", 0x" . substr($if_uuid, 35, 2) . " }\n"; - pidl "};\n\n"; - } - - if (defined($if_version)) { - pidl "static guint16 ver_dcerpc_$module = " . $if_version . ";\n\n"; - } - - pidl "void proto_register_dcerpc_pidl_$module(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_result_NTSTATUS, { \"Return code\", \"$module.rc\", FT_UINT32, BASE_HEX, VALS(NT_errors), 0x0, \"Return status code\", 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"; - $needed{$x}{strings} = "NULL", if !defined($needed{$x}{strings}); - $needed{$x}{bitmask} = "0", if !defined($needed{$x}{bitmask}); - pidl "\t { \"$needed{$x}{name}\", \"$x\", $needed{$x}{ft}, $needed{$x}{base}, $needed{$x}{strings}, $needed{$x}{bitmask}, \"$x\", HFILL }},\n"; - } - - pidl "\t};\n\n"; - - pidl "\tstatic gint *ett[] = {\n"; - pidl "\t\t&ett_dcerpc_$module,\n"; - foreach my $x (keys(%needed)) { - pidl "\t\t&$x,\n", if $x =~ /^ett_/; - } - pidl "\t};\n\n"; - - if (defined($if_uuid)) { - - # These can be changed to non-pidl names if the old dissectors - # in epan/dissctors are deleted. - - my $name = uc($module) . " (pidl)"; - my $short_name = "pidl_$module"; - my $filter_name = "pidl_$module"; - - pidl "\tproto_dcerpc_pidl_$module = proto_register_protocol(\"$name\", \"$short_name\", \"$filter_name\");\n\n"; - - pidl "\tproto_register_field_array(proto_dcerpc_pidl_$module, hf, array_length (hf));\n"; - pidl "\tproto_register_subtree_array(ett, array_length(ett));\n"; - - pidl "}\n\n"; - - pidl "void proto_reg_handoff_dcerpc_pidl_$module(void)\n"; - pidl "{\n"; - pidl "\tdcerpc_init_uuid(proto_dcerpc_pidl_$module, ett_dcerpc_$module, \n"; - pidl "\t\t&uuid_dcerpc_$module, ver_dcerpc_$module, \n"; - pidl "\t\tdcerpc_dissectors, hf_opnum);\n"; - pidl "}\n"; - - } else { - - pidl "\tint proto_dcerpc;\n\n"; - pidl "\tproto_dcerpc = proto_get_id_by_filter_name(\"dcerpc\");\n"; - pidl "\tproto_register_field_array(proto_dcerpc, hf, array_length(hf));\n"; - pidl "\tproto_register_subtree_array(ett, array_length(ett));\n"; - - pidl "}\n"; - - } - - close(OUT); -} - -1; diff --git a/source4/build/pidl/eth_header.pm b/source4/build/pidl/eth_header.pm new file mode 100644 index 0000000000..f0a5778854 --- /dev/null +++ b/source4/build/pidl/eth_header.pm @@ -0,0 +1,102 @@ +################################################### +# create C header files for an IDL structure +# Copyright tridge@samba.org 2000 +# Copyright jelmer@samba.org 2005 +# released under the GNU GPL + +package EthHeader; + +use strict; +use typelist; + +my($res); +my($tab_depth); + +sub pidl ($) +{ + $res .= shift; +} + +sub tabs() +{ + for (my($i)=0; $i < $tab_depth; $i++) { + pidl "\t"; + } +} + +##################################################################### +# prototype a typedef +sub HeaderTypedefProto($) +{ + my($d) = shift; + + my $tf = EthParser::get_typefamily($d->{DATA}{TYPE}); + + return unless util::has_property($d, "public"); + + unless (util::has_property($d, "nopull")) { + pidl "dcerpc_dissect_fnct_t $d->{NAME};\n"; + } +} + +##################################################################### +# parse a const +sub HeaderConst($) +{ + my($const) = shift; + if (!defined($const->{ARRAY_LEN})) { + pidl "#define $const->{NAME}\t( $const->{VALUE} )\n"; + } else { + pidl "#define $const->{NAME}\t $const->{VALUE}\n"; + } +} + +my %headerstructs = (); + +##################################################################### +# parse the interface definitions +sub HeaderInterface($) +{ + my($interface) = shift; + + my $count = 0; + + pidl "#ifndef _HEADER_NDR_$interface->{NAME}\n"; + pidl "#define _HEADER_NDR_$interface->{NAME}\n\n"; + + if (defined $interface->{PROPERTIES}->{depends}) { + my @d = split / /, $interface->{PROPERTIES}->{depends}; + foreach my $i (@d) { + pidl "#include \"packet-dcerpc-$i\.h\"\n"; + } + } + + foreach my $d (@{$interface->{CONSTS}}) { + HeaderConst($d); + } + + foreach my $d (@{$interface->{TYPEDEFS}}) { + HeaderTypedefProto($d); + } + + pidl "#endif /* _HEADER_NDR_$interface->{NAME} */\n"; +} + +##################################################################### +# parse a parsed IDL into a C header +sub Parse($) +{ + my($idl) = shift; + $tab_depth = 0; + + $res = ""; + pidl "/* header auto-generated by pidl */\n\n"; + foreach my $x (@{$idl}) { + if ($x->{TYPE} eq "INTERFACE") { + HeaderInterface($x); + } + } + return $res; +} + +1; diff --git a/source4/build/pidl/eth_parser.pm b/source4/build/pidl/eth_parser.pm new file mode 100644 index 0000000000..a2e1bf051c --- /dev/null +++ b/source4/build/pidl/eth_parser.pm @@ -0,0 +1,1410 @@ +################################################## +# Samba4 NDR parser generator for IDL structures +# Copyright tridge@samba.org 2000-2003 +# Copyright tpot@samba.org 2001 +# Copyright jelmer@samba.org 2004-2005 +# released under the GNU GPL + +package EthParser; + +use strict; +use typelist; +use ndr; + +# the list of needed functions + +# list of known types +my %typefamily; + + +sub NeededFunction($$) +{ + my $fn = shift; + my $needed = shift; + $needed->{"pull_$fn->{NAME}"} = 1; + foreach my $e (@{$fn->{ELEMENTS}}) { + $e->{PARENT} = $fn; + unless(defined($needed->{"pull_$e->{TYPE}"})) { + $needed->{"pull_$e->{TYPE}"} = 1; + } + + # for Ethereal + if (Ndr::is_scalar_type($e->{TYPE})) { + + if (defined($e->{ARRAY_LEN}) or + util::has_property($e, "size_is")) { + + # Array of scalar types + + $needed->{"hf_$fn->{NAME}_$e->{NAME}_array"} = { + 'name' => field2name($e->{NAME}), + 'type' => $e->{TYPE}, + 'ft' => "FT_BYTES", + 'base' => elementbase($e) + }; + + } else { + $needed->{"hf_$fn->{NAME}_$e->{NAME}"} = { + 'name' => field2name($e->{NAME}), + 'type' => $e->{TYPE}, + 'ft' => type2ft($e->{TYPE}), + 'base' => elementbase($e) + }; + } + } else { + $needed->{"hf_$fn->{NAME}_$e->{NAME}"} = { + 'name' => field2name($e->{NAME}), + 'type' => $e->{TYPE}, + 'ft' => type2ft($e->{TYPE}), + 'base' => elementbase($e) + }; + $needed->{"hf_$e->{TYPE}"} = { + 'name' => field2name($e->{NAME}), + 'type' => $e->{TYPE}, + 'ft' => type2ft($e->{TYPE}), + 'base' => elementbase($e) + }; + $needed->{"ett_$e->{TYPE}"} = 1; + } + } + + # Add entry for return value + if (defined($fn->{RETURN_TYPE})) { + $needed->{"hf_$fn->{NAME}_result"} = { + 'name' => field2name('result'), + 'type' => $fn->{RETURN_TYPE}, + 'ft' => type2ft($fn->{RETURN_TYPE}), + 'base' => elementbase($fn) + }; + } +} + +sub NeededTypedef($$) +{ + my $t = shift; + my $needed = shift; + + if (util::has_property($t, "public")) { + $needed->{"pull_$t->{NAME}"} = not util::has_property($t, "nopull"); + } + + if ($t->{DATA}->{TYPE} eq "STRUCT" or $t->{DATA}->{TYPE} eq "UNION") { + + for my $e (@{$t->{DATA}->{ELEMENTS}}) { + $e->{PARENT} = $t->{DATA}; + if ($needed->{"pull_$t->{NAME}"} and + not defined($needed->{"pull_$e->{TYPE}"})) { + $needed->{"pull_$e->{TYPE}"} = 1; + } + + if (Ndr::is_scalar_type($e->{TYPE})) { + if (defined($e->{ARRAY_LEN}) or + util::has_property($e, "size_is")) { + + # Arrays of scalar types are FT_BYTES + + $needed->{"hf_$t->{NAME}_$e->{NAME}_array"} = { + 'name' => field2name($e->{NAME}), + 'type' => $e->{TYPE}, + 'ft' => "FT_BYTES", + 'base' => elementbase($e) + }; + + } else { + $needed->{"hf_$t->{NAME}_$e->{NAME}"} = { + 'name' => field2name($e->{NAME}), + 'type' => $e->{TYPE}, + 'ft' => type2ft($e->{TYPE}), + 'base' => elementbase($e) + }; + } + + $e->{PARENT} = $t->{DATA}; + + if ($needed->{"pull_$t->{NAME}"}) { + $needed->{"pull_$e->{TYPE}"} = 1; + } + + } else { + $needed->{"hf_$t->{NAME}_$e->{NAME}"} = { + 'name' => field2name($e->{NAME}), + 'type' => $e->{TYPE}, + 'ft' => type2ft($e->{TYPE}), + 'base' => elementbase($e) + }; + $needed->{"ett_$e->{TYPE}"} = 1; + } + } + } + + if ($t->{DATA}->{TYPE} eq "ENUM") { + + $needed->{"hf_$t->{NAME}"} = { + 'name' => field2name($t->{NAME}), + 'ft' => 'FT_UINT16', + 'base' => 'BASE_DEC', + 'strings' => "VALS($t->{NAME}_vals)" + }; + $needed->{"ett_$t->{NAME}"} = 1; + } + + if ($t->{DATA}->{TYPE} eq "BITMAP") { + $needed->{BITMAPS}->{$t->{NAME}} = $t; + + foreach my $e (@{$t->{DATA}{ELEMENTS}}) { + $e =~ /^(.*?) \( (.*?) \)$/; + $needed->{"hf_$t->{NAME}_$1"} = { + 'name' => "$1", + 'ft' => "FT_BOOLEAN", + 'base' => bitmapbase($t), + 'bitmask' => "$2" + }; + } + $needed->{"ett_$t->{NAME}"} = 1; + } +} + +##################################################################### +# work out what parse functions are needed +sub NeededInterface($) +{ + my($interface) = shift; + my %needed = (); + + $needed{"hf_$interface->{NAME}_opnum"} = { + 'name' => "Operation", + 'ft' => "FT_UINT16", + 'base' => "BASE_DEC" + }; + + $needed{"ett_dcerpc_$interface->{NAME}"} = 1; + + foreach my $d (@{$interface->{FUNCTIONS}}) { + NeededFunction($d, \%needed); + } + foreach my $d (reverse @{$interface->{TYPEDEFS}}) { + NeededTypedef($d, \%needed); + } + + return \%needed; +} + +sub type2ft($) +{ + my($t) = shift; + + return "FT_UINT$1" if $t =~ /uint(8|16|32|64)/; + return "FT_INT$1" if $t =~ /int(8|16|32|64)/; + return "FT_UINT64", if $t eq "HYPER_T" or $t eq "NTTIME" + or $t eq "NTTIME_1sec" or $t eq "NTTIME_hyper" or $t eq "hyper"; + + # Type is an enum + + return "FT_UINT16"; +} + +# Determine the display base for an element + +sub elementbase($) +{ + my($e) = shift; + + if (my $base = util::has_property($e, "display")) { + return "BASE_" . uc($base); + } + + return "BASE_DEC", if $e->{TYPE} eq "ENUM"; + return "BASE_DEC", if $e->{TYPE} =~ /u?int(8|16|32|64)/; + return "BASE_DEC", if $e->{TYPE} eq "NTTIME" or $e->{TYPE} eq "HYPER_T"; + + # Probably an enum + + return "BASE_DEC"; +} + +# Convert a IDL structure field name (e.g access_mask) to a prettier +# string like 'Access Mask'. + +sub field2name($) +{ + my($field) = shift; + + $field =~ s/_/ /g; # Replace underscores with spaces + $field =~ s/(\w+)/\u\L$1/g; # Capitalise each word + + return $field; +} + +sub bitmapbase($) +{ + my $e = shift; + + return "16", if util::has_property($e->{DATA}, "bitmap16bit"); + return "8", if util::has_property($e->{DATA}, "bitmap8bit"); + + return "32"; +} + +sub get_typefamily($) +{ + my $n = shift; + return $typefamily{$n}; +} + +sub append_prefix($$) +{ + my $e = shift; + my $var_name = shift; + my $pointers = 0; + + foreach my $l (@{$e->{LEVELS}}) { + if ($l->{TYPE} eq "POINTER") { + $pointers++; + } elsif ($l->{TYPE} eq "ARRAY") { + if (($pointers == 0) and + (not $l->{IS_FIXED}) and + (not $l->{IS_INLINE})) { + return get_value_of($var_name) + } + } elsif ($l->{TYPE} eq "DATA") { + if ($l->{DATA_TYPE} eq "string" or + $l->{DATA_TYPE} eq "nbt_string") { + return get_value_of($var_name) unless ($pointers); + } + } + } + + return $var_name; +} + +# see if a variable needs to be allocated by the NDR subsystem on pull +sub need_alloc($) +{ + my $e = shift; + + return 0; +} + +sub get_pointer_to($) +{ + my $var_name = shift; + + if ($var_name =~ /^\*(.*)$/) { + return $1; + } elsif ($var_name =~ /^\&(.*)$/) { + return $var_name; +# return "&($var_name)"; + } else { + return "&$var_name"; + } +} + +sub get_value_of($) +{ + my $var_name = shift; + + if ($var_name =~ /^\&(.*)$/) { + return $1; + } else { + return "*$var_name"; + } +} + +my $res; +my $tabs = ""; +sub pidl($) +{ + my $d = shift; + if ($d) { + $res .= $tabs; + $res .= $d; + } + $res .="\n"; +} + +sub indent() +{ + $tabs .= "\t"; +} + +sub deindent() +{ + $tabs = substr($tabs, 0, -1); +} + +#################################################################### +# work out the name of a size_is() variable +sub ParseExpr($$) +{ + my($orig_expr) = shift; + my $varlist = shift; + + die("Undefined value in ParseExpr") if not defined($orig_expr); + + my $expr = $orig_expr; + + return $expr if (util::is_constant($expr)); + + my $prefix = ""; + my $postfix = ""; + + if ($expr =~ /\*(.*)/) { + $expr = $1; + $prefix = "*"; + } + + if ($expr =~ /^(.*)([\&\|\/+])(.*)$/) { + $postfix = $2.$3; + $expr = $1; + } + + if (defined($varlist->{$expr})) { + return $prefix.$varlist->{$expr}.$postfix; + } + + return $prefix.$expr.$postfix; +} + +##################################################################### +# 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 +# void return varient +sub check_null_pointer_void($) +{ + my $size = shift; + if ($size =~ /^\*/) { + my $size2 = substr($size, 1); + pidl "if ($size2 == NULL) return;"; + } +} + +##################################################################### +# work out is a parse function should be declared static or not +sub fn_prefix($) +{ + my $fn = shift; + + return "" if (util::has_property($fn, "public")); + return "static "; +} + +################################################################### +# setup any special flags for an element or structure +sub start_flags($) +{ + my $e = shift; + my $flags = util::has_property($e, "flag"); + if (defined $flags) { + pidl "{ uint32_t _flags_save_$e->{TYPE} = ndr->flags;"; + pidl "ndr_set_flags(&ndr->flags, $flags);"; + indent; + } +} + +################################################################### +# end any special flags for an element or structure +sub end_flags($) +{ + my $e = shift; + my $flags = util::has_property($e, "flag"); + if (defined $flags) { + pidl "ndr->flags = _flags_save_$e->{TYPE};\n\t}"; + deindent; + } +} + +sub GenerateStructEnv($) +{ + my $x = shift; + my %env; + + foreach my $e (@{$x->{ELEMENTS}}) { + $env{$e->{NAME}} = "r->$e->{NAME}"; + } + + $env{"this"} = "r"; + + return \%env; +} + +sub GenerateFunctionEnv($) +{ + my $fn = shift; + my %env; + + foreach my $e (@{$fn->{ELEMENTS}}) { + if (grep (/out/, @{$e->{DIRECTION}})) { + $env{$e->{NAME}} = "r->out.$e->{NAME}"; + } + if (grep (/in/, @{$e->{DIRECTION}})) { + $env{$e->{NAME}} = "r->in.$e->{NAME}"; + } + } + + return \%env; +} + +##################################################################### +sub ParseArrayPreceding($$$) +{ + my $e = shift; + my $l = shift; + my $var_name = shift; + + return if ($l->{NO_METADATA}); + + # non fixed arrays encode the size just before the array + pidl "ndr_pull_array_size(ndr, tree, " . get_pointer_to($var_name) . ");"; +} + +sub compression_alg($$) +{ + my $e = shift; + my $l = shift; + my $compression = $l->{COMPRESSION}; + my ($alg, $clen, $dlen) = split(/ /, $compression); + + return $alg; +} + +sub compression_clen($$$) +{ + my $e = shift; + my $l = shift; + my $env = shift; + my $compression = $l->{COMPRESSION}; + my ($alg, $clen, $dlen) = split(/ /, $compression); + + return ParseExpr($clen, $env); +} + +sub compression_dlen($$$) +{ + my $e = shift; + my $l = shift; + my $env = shift; + my $compression = $l->{COMPRESSION}; + my ($alg, $clen, $dlen) = split(/ /, $compression); + + return ParseExpr($dlen, $env); +} + +sub ParseCompressionStart($$$$) +{ + my $e = shift; + my $l = shift; + my $subndr = shift; + my $env = shift; + my $comndr = $subndr."_compressed"; + my $alg = compression_alg($e, $l); + my $dlen = compression_dlen($e, $l, $env); + + pidl "{"; + indent; + pidl "struct pidl_pull *$comndr;"; + pidl "NDR_ALLOC($subndr, $comndr);"; + pidl "ndr_pull_compression($subndr, $comndr, $alg, $dlen);"; + + return $comndr; +} + +sub ParseCompressionEnd($$$) +{ + my $e = shift; + my $l = shift; + my $subndr = shift; + my $comndr = $subndr."_compressed"; + + deindent; + pidl "}"; +} + +sub ParseObfuscationStart($$) +{ + my $e = shift; + my $ndr = shift; + my $obfuscation = util::has_property($e, "obfuscation"); + + pidl "ndr_pull_obfuscation($ndr, $obfuscation);"; + + return $ndr; +} + +sub ParseObfuscationEnd($$) +{ + my $e = shift; + my $ndr = shift; + + # nothing to do here +} + +sub ParseSubcontextStart($$$$$$) +{ + my $e = shift; + my $l = shift; + my $ndr = shift; + my $var_name = shift; + my $ndr_flags = shift; + my $env = shift; + my $retndr = "_ndr_$e->{NAME}"; + + pidl "/* NDR_FLAGS $ndr_flags */"; + pidl "if ((ndr_flags) & NDR_SCALARS) {"; + indent; + pidl "struct pidl_pull *$retndr;"; + pidl "NDR_ALLOC(ndr, $retndr);"; + pidl "ndr_pull_subcontext_header($ndr, $l->{HEADER_SIZE}, $l->{SUBCONTEXT_SIZE}, $retndr);"; + + if (defined $l->{COMPRESSION}) { + $retndr = ParseCompressionStart($e, $l, $retndr, $env); + } + + if (defined $l->{OBFUSCATION}) { + $retndr = ParseObfuscationStart($e, $retndr); + } + + return ($retndr,$var_name); +} + +sub ParseSubcontextEnd($$) +{ + my $e = shift; + my $l = shift; + my $ndr = "_ndr_$e->{NAME}"; + + if (defined $l->{COMPRESSION}) { + ParseCompressionEnd($e, $l, $ndr); + } + + if (defined $l->{OBFUSCATION}) { + ParseObfuscationEnd($e, $ndr); + } + + my $advance; + if (defined($l->{SUBCONTEXT_SIZE}) and ($l->{SUBCONTEXT_SIZE} ne "-1")) { + $advance = $l->{SUBCONTEXT_SIZE}; + } elsif ($l->{HEADER_SIZE}) { + $advance = "$ndr->data_size"; + } else { + $advance = "$ndr->offset"; + } + pidl "ndr_pull_advance(ndr, $advance);"; + deindent; + pidl "}"; +} + +##################################################################### +# parse scalars in a structure element - pull size +sub ParseSwitch($$$$$$) +{ + my($e) = shift; + my $l = shift; + my $ndr = shift; + my($var_name) = shift; + my($ndr_flags) = shift; + my $env = shift; + my $switch_var = ParseExpr($l->{SWITCH_IS}, $env); + + check_null_pointer($switch_var); + + $var_name = get_pointer_to($var_name); + pidl "ndr_pull_set_switch_value($ndr, $var_name, $switch_var);"; + +} + +sub ParseData($$$$$) +{ + my $e = shift; + my $l = shift; + my $ndr = shift; + my $var_name = shift; + my $ndr_flags = shift; + + $var_name = get_pointer_to($var_name); + + # + # ALAND! for packet-dcerpc-lsa.c, uncommenting this code + # produces constructs like &(&r->string), to pass to another + # function, which gives compiler errors. + # + if ($l->{DATA_TYPE} eq "string" or + $l->{DATA_TYPE} eq "nbt_string") { + $var_name = get_pointer_to($var_name); + } + + pidl "offset += dissect_$l->{DATA_TYPE}(tvb, offset, pinfo, tree, drep, hf_FIXME, NULL);"; + + if (my $range = util::has_property($e, "range")) { + $var_name = get_value_of($var_name); + my ($low, $high) = split(/ /, $range, 2); + if (($l->{DATA_TYPE} =~ /^uint/) and ($low eq "0")) { + pidl "if ($var_name > $high) {"; + } else { + pidl "if ($var_name < $low || $var_name > $high) {"; + } + pidl "\treturn NT_STATUS_OK;"; + pidl "}"; + } +} + +sub CalcNdrFlags($$$) +{ + my $l = shift; + my $primitives = shift; + my $deferred = shift; + + my $scalars = 0; + my $buffers = 0; + + # Add NDR_SCALARS if this one is deferred + # and deferreds may be pushed + $scalars = 1 if ($l->{IS_DEFERRED} and $deferred); + + # Add NDR_SCALARS if this one is not deferred and + # primitives may be pushed + $scalars = 1 if (!$l->{IS_DEFERRED} and $primitives); + + # Add NDR_BUFFERS if this one contains deferred stuff + # and deferreds may be pushed + $buffers = 1 if ($l->{CONTAINS_DEFERRED} and $deferred); + + return "NDR_SCALARS|NDR_BUFFERS" if ($scalars and $buffers); + return "NDR_SCALARS" if ($scalars); + return "NDR_BUFFERS" if ($buffers); + return undef; +} + + +sub ParseElementLevel +{ + my($e) = shift; + my $l = shift; + my $ndr = shift; + my($var_name) = shift; + my $env = shift; + my $primitives = shift; + my $deferred = shift; + + my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred); + + # Only pull something if there's actually something to be pulled + if (defined($ndr_flags)) { + if ($l->{TYPE} eq "SUBCONTEXT") { + ($ndr,$var_name) = ParseSubcontextStart($e, $l, $ndr, $var_name, $ndr_flags, $env); + ParseElementLevel($e,Ndr::GetNextLevel($e,$l), $ndr, $var_name, $env, $primitives, $deferred); + ParseSubcontextEnd($e, $l); + } elsif ($l->{TYPE} eq "ARRAY") { + my $length = ParseArrayHeader($e, $l, $ndr, $var_name, $env); + } elsif ($l->{TYPE} eq "POINTER") { + ParsePtr($e, $l, $ndr, $var_name); + } elsif ($l->{TYPE} eq "SWITCH") { + ParseSwitch($e, $l, $ndr, $var_name, $ndr_flags, $env); + } elsif ($l->{TYPE} eq "DATA") { + ParseData($e, $l, $ndr, $var_name, $ndr_flags); + } + } + + # add additional constructions + if ($l->{TYPE} eq "POINTER" and $deferred) { + if ($l->{POINTER_TYPE} ne "ref") { + pidl "if ($var_name) {"; + indent; + + if ($l->{POINTER_TYPE} eq "relative") { + pidl "struct ndr_pull_save _relative_save;"; + pidl "ndr_pull_save(ndr, &_relative_save);"; + pidl "NDR_CHECK(ndr_pull_relative_ptr2(ndr, $var_name));"; + } + } + + $var_name = get_value_of($var_name); + ParseElementLevel($e,Ndr::GetNextLevel($e,$l), $ndr, $var_name, $env, $primitives, $deferred); + + if ($l->{POINTER_TYPE} ne "ref") { + if ($l->{POINTER_TYPE} eq "relative") { + pidl "ndr_pull_restore(ndr, &_relative_save);"; + } + deindent; + pidl "}"; + } + } elsif ($l->{TYPE} eq "ARRAY") { + my $length = ParseExpr($l->{LENGTH_IS}, $env); + my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}"; + + $var_name = $var_name . "[$counter]"; + unless ($l->{NO_METADATA}) { + $var_name = get_pointer_to($var_name); + } + + if (($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) { + pidl "for ($counter = 0; $counter < $length; $counter++) {"; + indent; + ParseElementLevel($e,Ndr::GetNextLevel($e,$l), $ndr, $var_name, $env, 1, 0); + deindent; + pidl "}"; + } + + if ($deferred and Ndr::ContainsDeferred($e, $l)) { + pidl "for ($counter = 0; $counter < $length; $counter++) {"; + indent; + ParseElementLevel($e,Ndr::GetNextLevel($e,$l), $ndr, $var_name, $env, 0, 1); + deindent; + pidl "}"; + } + } elsif ($l->{TYPE} eq "SWITCH") { + ParseElementLevel($e,Ndr::GetNextLevel($e,$l), $ndr, $var_name, $env, $primitives, $deferred); + } +} + +##################################################################### +# parse scalars in a structure element - pull size +sub ParseElement($$$$$$) +{ + my($e) = shift; + my $ndr = shift; + my($var_prefix) = shift; + my $env = shift; + my $primitives = shift; + my $deferred = shift; + + my $var_name = $var_prefix.$e->{NAME}; + + $var_name = append_prefix($e, $var_name); + + return unless $primitives or ($deferred and Ndr::ContainsDeferred($e, $e->{LEVELS}[0])); + + start_flags($e); + + ParseElementLevel($e,$e->{LEVELS}[0],$ndr,$var_name,$env,$primitives,$deferred); + + end_flags($e); +} + +##################################################################### +# parse a pointer in a struct element or function +sub ParsePtr($$$$) +{ + my($e) = shift; + my $l = shift; + my $ndr = shift; + my($var_name) = shift; + + my $nl = Ndr::GetNextLevel($e, $l); + my $next_is_array = ($nl->{TYPE} eq "ARRAY"); + + if ($l->{LEVEL} eq "EMBEDDED") { + pidl "dissect_ndr_embedded_pointer(FIXME);"; + } elsif ($l->{POINTER_TYPE} ne "ref") { + pidl "dissect_ndr_toplevel_pointer(FIXME);"; + } + + #pidl "memset($var_name, 0, sizeof($var_name));"; + if ($l->{POINTER_TYPE} eq "relative") { + pidl "ndr_pull_relative_ptr1($ndr, $var_name, _ptr_$e->{NAME});"; + } +} + +$typefamily{ENUM} = { + DECL => \&DeclEnum, +}; + +##################################################################### +# generate a pull function for an bitmap +sub ParseBitmap($$) +{ + my($bitmap) = shift; + my $name = shift; + my $type_fn = $bitmap->{BASE_TYPE}; + my($type_decl) = typelist::mapType($bitmap->{BASE_TYPE}); + + pidl "$type_decl v_bitmap;"; + start_flags($bitmap); + pidl "dissect_$type_fn(ndr, tree, hf, &v_bitmap);"; + + pidl "{\n\tproto_tree *subtree = NULL;"; + pidl ""; + pidl "\tif (tree->proto_tree)\n\t\tsubtree = proto_item_add_subtree(tree->proto_tree->last_child, ett_$name);"; + pidl ""; + foreach my $e (@{$bitmap->{DATA}{ELEMENTS}}) { + $e =~ /^(.*?) \( (.*?) \)$/; + pidl "\tproto_tree_add_boolean(subtree, hf_${name}_$1, ndr->tvb, ndr->offset - sizeof(v_bitmap), sizeof(v_bitmap), v_bitmap);"; + } + pidl "}"; + + pidl "*r = v_bitmap;"; + + end_flags($bitmap); +} + +$typefamily{BITMAP} = { + FN_BODY => \&ParseBitmap, +}; + +##################################################################### +# parse a struct - pull side +sub ParseStruct($$) +{ + my($struct) = shift; + my $name = shift; + my $conform_e; + + return unless defined $struct->{ELEMENTS}; + + my $env = GenerateStructEnv($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 pull the conformant length early, as it fits on + # the wire before the structure (and even before the structure + # alignment) + $conform_e = $struct->{SURROUNDING_ELEMENT}; + + # declare any internal pointers we need + foreach my $e (@{$struct->{ELEMENTS}}) { + foreach my $l (@{$e->{LEVELS}}) { + if ($l->{TYPE} eq "POINTER" and not ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "TOP")) { + pidl "uint32_t _ptr_$e->{NAME};"; + last; + } + } + } + + start_flags($struct); + + pidl "if (ndr_flags & NDR_SCALARS) {"; + indent; + + if (defined $conform_e) { + ParseArrayPreceding($conform_e, $conform_e->{LEVELS}[0], "r->$conform_e->{NAME}"); + } + + pidl "ndr_pull_align(ndr, $struct->{ALIGN});"; + + foreach my $e (@{$struct->{ELEMENTS}}) { + ParseElement($e, "ndr", "r->", $env, 1, 0); + } + deindent; + pidl "}"; + + pidl "if (ndr_flags & NDR_BUFFERS) {"; + indent; + foreach my $e (@{$struct->{ELEMENTS}}) { + ParseElement($e, "ndr", "r->", $env, 0, 0); + } + + pidl "proto_item_set_end(tree->proto_tree, ndr->tvb, ndr->offset);"; + deindent; + pidl "}"; + + end_flags($struct); +} + +$typefamily{STRUCT} = { + FN_BODY => \&ParseStruct, +}; + +##################################################################### +# parse a union - pull side +sub ParseUnion($$$) +{ + my $e = shift; + my $name = shift; + my $have_default = 0; + my $switch_type = $e->{SWITCH_TYPE}; + + pidl "int level;"; + if (defined($switch_type)) { + if (typelist::typeIs($switch_type, "ENUM")) { + $switch_type = typelist::enum_type_fn(typelist::getType($switch_type)); + } + pidl typelist::mapType($switch_type) . " _level;"; + } + + 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_pull_$switch_type(ndr, tree, hf_${name}, &_level);"; + pidl "if (_level != level) {"; + pidl "\treturn NT_STATUS_OK;"; + pidl "}"; + } + +# my $align = union_alignment($e); +# pidl "\tndr_pull_align(ndr, $align);\n"; + + 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; + foreach my $l (@{$el->{LEVELS}}) { + if ($l->{TYPE} eq "POINTER" and not ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "TOP")) { + pidl "uint32_t _ptr_$el->{NAME};"; + last; + } + } + ParseElement($el, "ndr", "r->", {}, 1, 0); + deindent; + } + pidl "break; }"; + pidl ""; + } + if (! $have_default) { + pidl "default:"; + pidl "\treturn NT_STATUS_OK;"; + } + deindent; + pidl "}"; + deindent; + pidl "}"; + pidl "if (ndr_flags & NDR_BUFFERS) {"; + indent; + pidl "switch (level) {"; + indent; + foreach my $el (@{$e->{ELEMENTS}}) { + pidl "$el->{CASE}:"; + if ($el->{TYPE} ne "EMPTY") { + indent; + ParseElement($el, "ndr", "r->", {}, 0, 1); + deindent; + } + pidl "break;"; + pidl ""; + } + if (! $have_default) { + pidl "default:"; + pidl "\treturn NT_STATUS_OK;"; + } + deindent; + pidl "}"; + pidl "proto_item_set_end(tree->proto_tree, ndr->tvb, ndr->offset);"; + deindent; + pidl "}"; + end_flags($e); +} + +$typefamily{UNION} = { + FN_BODY => \&ParseUnion, +}; + +##################################################################### +# parse an array +sub ParseArrayHeader($$$$$) +{ + my $e = shift; + my $l = shift; + my $ndr = shift; + my $var_name = shift; + my $env = shift; + + unless ($l->{NO_METADATA}) { + $var_name = get_pointer_to($var_name); + } + + # $var_name contains the name of the first argument here + + my $length = ParseExpr($l->{SIZE_IS}, $env); + my $size = $length; + + if ($l->{IS_CONFORMANT}) { + $length = $size = "ndr_get_array_size($ndr, " . get_pointer_to($var_name) . ")"; + } + + # if this is a conformant array then we use that size to allocate, and make sure + # we allocate enough to pull the elements + if (!$l->{IS_SURROUNDING}) { + ParseArrayPreceding($e, $l, $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; + pidl "return ndr_pull_error($ndr, NDR_ERR_ARRAY_SIZE, \"Bad array size %u should exceed array length %u\", $size, $length);"; + deindent; + pidl "}"; + } + + if ($l->{IS_CONFORMANT}) { + my $size = ParseExpr($l->{SIZE_IS}, $env); + check_null_pointer($size); + pidl "NDR_CHECK(ndr_check_array_size(ndr, (void*)" . get_pointer_to($var_name) . ", $size));"; + } + + if ($l->{IS_VARYING}) { + my $length = ParseExpr($l->{LENGTH_IS}, $env); + check_null_pointer($length); + pidl "NDR_CHECK(ndr_check_array_length(ndr, (void*)" . get_pointer_to($var_name) . ", $length));"; + } + + return $length; +} + +##################################################################### +# parse a typedef - pull side +sub ParseTypedef($) +{ + my($e) = shift; + + return unless (defined ($typefamily{$e->{DATA}->{TYPE}})); + + pidl fn_prefix($e) . "int dissect_$e->{NAME}(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, int hf_index, guint32 param)"; + + pidl "{"; + indent; + $typefamily{$e->{DATA}->{TYPE}}->{FN_BODY}->($e->{DATA}, $e->{NAME}); + pidl "return NT_STATUS_OK;"; + deindent; + pidl "}"; + pidl ""; +} + +##################################################################### +# parse a function +sub ParseFunctionRqst($) +{ + my($fn) = shift; + + my $env = GenerateFunctionEnv($fn); + + # request function + pidl "static int dissect_$fn->{NAME}_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)"; + pidl "{"; + indent; + + pidl "struct pidl_pull *ndr = pidl_pull_init(tvb, offset, pinfo, drep);"; + + # declare any internal pointers we need + foreach my $e (@{$fn->{ELEMENTS}}) { + next unless (grep (/in/, @{$e->{DIRECTIONS}})); + foreach my $l (@{$e->{LEVELS}}) { + if ($l->{TYPE} eq "POINTER" and + not ($l->{POINTER_TYPE} eq "ref" and + $l->{LEVEL} eq "TOP")) { + pidl "uint32_t _ptr_$e->{NAME};"; + last; + } + } + } + + foreach my $e (@{$fn->{ELEMENTS}}) { + next unless (grep(/in/, @{$e->{DIRECTION}})); + ParseElement($e, "ndr", "r->in.", $env, 1, 1); + } + + pidl "return offset;"; + deindent; + pidl "}"; + pidl ""; +} + +sub ParseFunctionResp($) +{ + my($fn) = shift; + + my $env = GenerateFunctionEnv($fn); + + # response function + pidl "static int dissect_$fn->{NAME}_resp(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)"; + pidl "{"; + indent; + + pidl "struct pidl_pull *ndr = pidl_pull_init(tvb, offset, pinfo, drep);"; + + # declare any internal pointers we need + foreach my $e (@{$fn->{ELEMENTS}}) { + next unless (grep (/out/, @{$e->{DIRECTIONS}})); + foreach my $l (@{$e->{LEVELS}}) { + if ($l->{TYPE} eq "POINTER" and + not ($l->{POINTER_TYPE} eq "ref" and + $l->{LEVEL} eq "TOP")) { + pidl "uint32_t _ptr_$e->{NAME};"; + last; + } + } + } + + foreach my $e (@{$fn->{ELEMENTS}}) { + next unless grep(/out/, @{$e->{DIRECTION}}); + ParseElement($e, "ndr", "r->out.", $env, 1, 1); + } + + if ($fn->{RETURN_TYPE}) { + pidl "dissect_$fn->{RETURN_TYPE}(ndr, tree, hf_$fn->{NAME}_result, drep);"; + } + + pidl "return offset;"; + deindent; + pidl "}"; + pidl ""; +} + +##################################################################### +# produce a function call table +sub FunctionTable($) +{ + my($interface) = shift; + + pidl "static dcerpc_sub_dissector dcerpc_dissectors[] = {"; + my $num = 0; + foreach my $d (@{$interface->{FUNCTIONS}}) { + # Strip interface name from function name, if present + my($n) = $d->{NAME}; + $n = substr($d->{NAME}, length($interface->{NAME}) + 1), + if $interface->{NAME} eq substr($d->{NAME}, 0, length($interface->{NAME})); + pidl "\t{ $num, \"$n\","; + pidl "\t\tdissect_$d->{NAME}_rqst,"; + pidl "\t\tdissect_$d->{NAME}_resp },"; + $num++; + } + pidl "};\n"; +} + +##################################################################### +# parse the interface definitions +sub ParseInterface($$) +{ + my($interface) = shift; + my $needed = shift; + + # Typedefs + foreach my $d (@{$interface->{TYPEDEFS}}) { + ($needed->{"pull_$d->{NAME}"}) && ParseTypedef($d); + # Make sure we don't generate a function twice... + $needed->{"pull_$d->{NAME}"} = 0; + } + + # Functions + foreach my $d (@{$interface->{FUNCTIONS}}) { + if ($needed->{"pull_$d->{NAME}"}) { + ParseFunctionRqst($d); + ParseFunctionResp($d); + } + + # Make sure we don't generate a function twice... + $needed->{"pull_$d->{NAME}"} = 0; + } +} + +##################################################################### +# generate code to parse an enum +sub DeclEnum($$) +{ + my ($e) = shift; + my $n = shift; + + pidl "static const value_string $n\_vals[] ="; + pidl "{"; + + foreach my $x (@{$e->{ELEMENTS}}) { + $x =~ /([^=]*)=(.*)/; + pidl "\t{ $1, \"$1\" },"; + } + + pidl "};\n"; +} + +sub DeclInterface($$) +{ + my($interface) = shift; + my $needed = shift; + + # Typedefs + foreach my $d (@{$interface->{TYPEDEFS}}) { + ($needed->{"pull_$d->{NAME}"}) && DeclTypedef($d); + + # Make sure we don't generate a function twice... + $needed->{"pull_$d->{NAME}"} = 0; + } +} + +sub DeclTypedef($) +{ + my $e = shift; + + if (defined($typefamily{$e->{DATA}->{TYPE}}->{DECL})) { + $typefamily{$e->{DATA}->{TYPE}}->{DECL}->($e->{DATA}, $e->{NAME}); + } +} + +sub RegisterInterface($$) +{ + my $x = shift; + my $needed = shift; + + pidl "void proto_register_dcerpc_pidl_$x->{NAME}(void)"; + pidl "{"; + indent; + + pidl "static hf_register_info hf[] = {"; + pidl "{ &hf_ptr, { \"Pointer\", \"$x->{NAME}.ptr\", FT_UINT32, BASE_HEX, NULL, 0x0, \"Pointer\", HFILL }},"; + + foreach my $x (sort keys(%{$needed})) { + next, if !($x =~ /^hf_/); + pidl "{ &$x,"; + $needed->{$x}->{strings} = "NULL", if !defined($needed->{$x}->{strings}); + $needed->{$x}->{bitmask} = "0", if !defined($needed->{$x}->{bitmask}); + pidl " { \"$needed->{$x}->{name}\", \"$x\", $needed->{$x}->{ft}, $needed->{$x}->{base}, $needed->{$x}->{strings}, $needed->{$x}->{bitmask}, \"$x\", HFILL }},"; + } + + pidl "};\n"; + + pidl "static gint *ett[] = {"; + indent; + foreach my $x (sort keys(%{$needed})) { + pidl "&$x,", if $x =~ /^ett_/; + } + deindent; + + pidl "};\n"; + + if (defined($x->{UUID})) { + # These can be changed to non-pidl names if the old dissectors + # in epan/dissctors are deleted. + + my $name = "\"" . uc($x->{NAME}) . " (pidl)\""; + if (util::has_property($x, "helpstring")) { + $name = $x->{PROPERTIES}->{helpstring}; + } + my $short_name = "pidl_$x->{NAME}"; + my $filter_name = "pidl_$x->{NAME}"; + + pidl "proto_dcerpc_pidl_$x->{NAME} = proto_register_protocol($name, \"$short_name\", \"$filter_name\");"; + + pidl "proto_register_field_array(proto_dcerpc_pidl_$x->{NAME}, hf, array_length (hf));"; + pidl "proto_register_subtree_array(ett, array_length(ett));"; + } else { + pidl "int proto_dcerpc;"; + pidl "proto_dcerpc = proto_get_id_by_filter_name(\"dcerpc\");"; + pidl "proto_register_field_array(proto_dcerpc, hf, array_length(hf));"; + pidl "proto_register_subtree_array(ett, array_length(ett));"; + } + + deindent; + pidl "}\n"; +} + +sub RegisterInterfaceHandoff($) +{ + my $x = shift; + pidl "void proto_reg_handoff_dcerpc_pidl_$x->{NAME}(void)"; + pidl "{"; + indent; + pidl "dcerpc_init_uuid(proto_dcerpc_pidl_$x->{NAME}, ett_dcerpc_$x->{NAME},"; + pidl "\t&uuid_dcerpc_$x->{NAME}, ver_dcerpc_$x->{NAME},"; + pidl "\tdcerpc_dissectors, hf_opnum);"; + deindent; + pidl "}"; +} + +sub ProcessInterface($) +{ + my $x = shift; + my $needed = NeededInterface($x); + + # Required global declarations + DeclInterface($x, $needed); + + foreach my $y (sort keys(%{$needed})) { + pidl "static int $y = -1;", if $y =~ /^hf_/; + } + pidl ""; + + foreach my $y (sort keys(%{$needed})) { + pidl "static gint $y = -1;", if $y =~ /^ett_/; + } + pidl ""; + + pidl "int proto_dcerpc_pidl_$x->{NAME} = -1;\n"; + + if (defined($x->{UUID})) { + my $if_uuid = $x->{UUID}; + + pidl "static e_uuid_t uuid_dcerpc_$x->{NAME} = {"; + pidl "\t0x" . substr($if_uuid, 1, 8) + . ", 0x" . substr($if_uuid, 10, 4) + . ", 0x" . substr($if_uuid, 15, 4) . ","; + pidl "\t{ 0x" . substr($if_uuid, 20, 2) + . ", 0x" . substr($if_uuid, 22, 2) + . ", 0x" . substr($if_uuid, 25, 2) + . ", 0x" . substr($if_uuid, 27, 2) + . ", 0x" . substr($if_uuid, 29, 2) + . ", 0x" . substr($if_uuid, 31, 2) + . ", 0x" . substr($if_uuid, 33, 2) + . ", 0x" . substr($if_uuid, 35, 2) . " }"; + pidl "};\n"; + + pidl "static guint16 ver_dcerpc_$x->{NAME} = $x->{VERSION};"; + } + + # dissect_* functions + ParseInterface($x, $needed); + + # Function call tables + FunctionTable($x); + + RegisterInterface($x, $needed); + RegisterInterfaceHandoff($x); +} + +##################################################################### +# parse a parsed IDL structure back into an IDL file +sub Parse($$$) +{ + my($ndr) = shift; + my $module = shift; + my($filename) = shift; + + $tabs = ""; + my $h_filename = $filename; + $res = ""; + + if ($h_filename =~ /(.*)\.c/) { + $h_filename = "$1.h"; + } + + pidl "/* parser auto-generated by pidl */"; + pidl "#include \"packet-dcerpc.h\""; + pidl "#include \"$h_filename\""; + pidl ""; + pidl "static int hf_ptr = -1;"; + pidl "static int hf_array_size = -1;"; + pidl ""; + +# print keys %{$needed->{hf_atsvc_JobGetInfo_result}}, "\n"; + + # Ethereal protocol registration + + ProcessInterface($_) foreach (@$ndr); + + return $res; +} + +1; diff --git a/source4/build/pidl/idl.pm b/source4/build/pidl/idl.pm index 53c06f22d8..d5100812ed 100644 --- a/source4/build/pidl/idl.pm +++ b/source4/build/pidl/idl.pm @@ -1808,6 +1808,8 @@ sub "PROPERTIES" => $_[1], "NAME" => $_[3], "DATA" => $_[5], + "FILE" => $_[0]->YYData->{INPUT_FILENAME}, + "LINE" => $_[0]->YYData->{LINE}, }} ], [#Rule 5 @@ -1816,19 +1818,21 @@ sub [#Rule 6 'interface_names', 4, sub -#line 34 "build/pidl/idl.yp" +#line 36 "build/pidl/idl.yp" { push(@{$_[1]}, $_[2]); $_[1] } ], [#Rule 7 'interface', 8, sub -#line 38 "build/pidl/idl.yp" +#line 40 "build/pidl/idl.yp" {$_[3] => { "TYPE" => "INTERFACE", "PROPERTIES" => $_[1], "NAME" => $_[3], "BASE" => $_[4], "DATA" => $_[6], + "FILE" => $_[0]->YYData->{INPUT_FILENAME}, + "LINE" => $_[0]->YYData->{LINE}, }} ], [#Rule 8 @@ -1837,19 +1841,19 @@ sub [#Rule 9 'base_interface', 2, sub -#line 49 "build/pidl/idl.yp" +#line 53 "build/pidl/idl.yp" { $_[2] } ], [#Rule 10 'definitions', 1, sub -#line 53 "build/pidl/idl.yp" +#line 57 "build/pidl/idl.yp" { [ $_[1] ] } ], [#Rule 11 'definitions', 2, sub -#line 54 "build/pidl/idl.yp" +#line 58 "build/pidl/idl.yp" { push(@{$_[1]}, $_[2]); $_[1] } ], [#Rule 12 @@ -1867,47 +1871,55 @@ sub [#Rule 16 'const', 6, sub -#line 62 "build/pidl/idl.yp" +#line 66 "build/pidl/idl.yp" {{ "TYPE" => "CONST", "DTYPE" => $_[2], "NAME" => $_[3], - "VALUE" => $_[5] + "VALUE" => $_[5], + "FILE" => $_[0]->YYData->{INPUT_FILENAME}, + "LINE" => $_[0]->YYData->{LINE}, }} ], [#Rule 17 'const', 7, sub -#line 69 "build/pidl/idl.yp" +#line 75 "build/pidl/idl.yp" {{ "TYPE" => "CONST", "DTYPE" => $_[2], "NAME" => $_[3], "ARRAY_LEN" => $_[4], "VALUE" => $_[6], + "FILE" => $_[0]->YYData->{INPUT_FILENAME}, + "LINE" => $_[0]->YYData->{LINE}, }} ], [#Rule 18 'function', 7, sub -#line 80 "build/pidl/idl.yp" +#line 88 "build/pidl/idl.yp" {{ "TYPE" => "FUNCTION", "NAME" => $_[3], "RETURN_TYPE" => $_[2], "PROPERTIES" => $_[1], - "ELEMENTS" => $_[5] - }} + "ELEMENTS" => $_[5], + "FILE" => $_[0]->YYData->{INPUT_FILENAME}, + "LINE" => $_[0]->YYData->{LINE}, + }} ], [#Rule 19 'declare', 5, sub -#line 90 "build/pidl/idl.yp" +#line 100 "build/pidl/idl.yp" {{ "TYPE" => "DECLARE", "PROPERTIES" => $_[2], "NAME" => $_[4], "DATA" => $_[3], + "FILE" => $_[0]->YYData->{INPUT_FILENAME}, + "LINE" => $_[0]->YYData->{LINE}, }} ], [#Rule 20 @@ -1919,7 +1931,7 @@ sub [#Rule 22 'decl_enum', 1, sub -#line 102 "build/pidl/idl.yp" +#line 114 "build/pidl/idl.yp" {{ "TYPE" => "ENUM" }} @@ -1927,7 +1939,7 @@ sub [#Rule 23 'decl_bitmap', 1, sub -#line 108 "build/pidl/idl.yp" +#line 120 "build/pidl/idl.yp" {{ "TYPE" => "BITMAP" }} @@ -1935,13 +1947,15 @@ sub [#Rule 24 'typedef', 6, sub -#line 114 "build/pidl/idl.yp" +#line 126 "build/pidl/idl.yp" {{ "TYPE" => "TYPEDEF", "PROPERTIES" => $_[2], "NAME" => $_[4], "DATA" => $_[3], - "ARRAY_LEN" => $_[5] + "ARRAY_LEN" => $_[5], + "FILE" => $_[0]->YYData->{INPUT_FILENAME}, + "LINE" => $_[0]->YYData->{LINE}, }} ], [#Rule 25 @@ -1962,28 +1976,28 @@ sub [#Rule 30 'type', 1, sub -#line 124 "build/pidl/idl.yp" +#line 138 "build/pidl/idl.yp" { "void" } ], [#Rule 31 'enum', 4, sub -#line 129 "build/pidl/idl.yp" +#line 143 "build/pidl/idl.yp" {{ - "TYPE" => "ENUM", + "TYPE" => "ENUM", "ELEMENTS" => $_[3] }} ], [#Rule 32 'enum_elements', 1, sub -#line 136 "build/pidl/idl.yp" +#line 150 "build/pidl/idl.yp" { [ $_[1] ] } ], [#Rule 33 'enum_elements', 3, sub -#line 137 "build/pidl/idl.yp" +#line 151 "build/pidl/idl.yp" { push(@{$_[1]}, $_[3]); $_[1] } ], [#Rule 34 @@ -1992,13 +2006,13 @@ sub [#Rule 35 'enum_element', 3, sub -#line 141 "build/pidl/idl.yp" +#line 155 "build/pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 36 'bitmap', 4, sub -#line 145 "build/pidl/idl.yp" +#line 159 "build/pidl/idl.yp" {{ "TYPE" => "BITMAP", "ELEMENTS" => $_[3] @@ -2007,25 +2021,25 @@ sub [#Rule 37 'bitmap_elements', 1, sub -#line 152 "build/pidl/idl.yp" +#line 166 "build/pidl/idl.yp" { [ $_[1] ] } ], [#Rule 38 'bitmap_elements', 3, sub -#line 153 "build/pidl/idl.yp" +#line 167 "build/pidl/idl.yp" { push(@{$_[1]}, $_[3]); $_[1] } ], [#Rule 39 'bitmap_element', 3, sub -#line 156 "build/pidl/idl.yp" +#line 170 "build/pidl/idl.yp" { "$_[1] ( $_[3] )" } ], [#Rule 40 'struct', 4, sub -#line 160 "build/pidl/idl.yp" +#line 174 "build/pidl/idl.yp" {{ "TYPE" => "STRUCT", "ELEMENTS" => $_[3] @@ -2034,12 +2048,14 @@ sub [#Rule 41 'empty_element', 2, sub -#line 167 "build/pidl/idl.yp" +#line 181 "build/pidl/idl.yp" {{ "NAME" => "", "TYPE" => "EMPTY", "PROPERTIES" => $_[1], - "POINTERS" => 0 + "POINTERS" => 0, + "FILE" => $_[0]->YYData->{INPUT_FILENAME}, + "LINE" => $_[0]->YYData->{LINE}, }} ], [#Rule 42 @@ -2051,7 +2067,7 @@ sub [#Rule 44 'optional_base_element', 2, sub -#line 178 "build/pidl/idl.yp" +#line 194 "build/pidl/idl.yp" { $_[2]->{PROPERTIES} = util::FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] } ], [#Rule 45 @@ -2060,13 +2076,13 @@ sub [#Rule 46 'union_elements', 2, sub -#line 183 "build/pidl/idl.yp" +#line 199 "build/pidl/idl.yp" { push(@{$_[1]}, $_[2]); $_[1] } ], [#Rule 47 'union', 4, sub -#line 187 "build/pidl/idl.yp" +#line 203 "build/pidl/idl.yp" {{ "TYPE" => "UNION", "ELEMENTS" => $_[3] @@ -2075,25 +2091,27 @@ sub [#Rule 48 'base_element', 5, sub -#line 194 "build/pidl/idl.yp" +#line 210 "build/pidl/idl.yp" {{ "NAME" => $_[4], "TYPE" => $_[2], "PROPERTIES" => $_[1], "POINTERS" => $_[3], - "ARRAY_LEN" => $_[5] + "ARRAY_LEN" => $_[5], + "FILE" => $_[0]->YYData->{INPUT_FILENAME}, + "LINE" => $_[0]->YYData->{LINE}, }} ], [#Rule 49 'pointers', 0, sub -#line 206 "build/pidl/idl.yp" +#line 224 "build/pidl/idl.yp" { 0 } ], [#Rule 50 'pointers', 2, sub -#line 207 "build/pidl/idl.yp" +#line 225 "build/pidl/idl.yp" { $_[1]+1 } ], [#Rule 51 @@ -2102,7 +2120,7 @@ sub [#Rule 52 'element_list1', 3, sub -#line 212 "build/pidl/idl.yp" +#line 230 "build/pidl/idl.yp" { push(@{$_[1]}, $_[2]); $_[1] } ], [#Rule 53 @@ -2114,13 +2132,13 @@ sub [#Rule 55 'element_list2', 1, sub -#line 218 "build/pidl/idl.yp" +#line 236 "build/pidl/idl.yp" { [ $_[1] ] } ], [#Rule 56 'element_list2', 3, sub -#line 219 "build/pidl/idl.yp" +#line 237 "build/pidl/idl.yp" { push(@{$_[1]}, $_[3]); $_[1] } ], [#Rule 57 @@ -2129,13 +2147,13 @@ sub [#Rule 58 'array_len', 2, sub -#line 224 "build/pidl/idl.yp" +#line 242 "build/pidl/idl.yp" { "*" } ], [#Rule 59 'array_len', 3, sub -#line 225 "build/pidl/idl.yp" +#line 243 "build/pidl/idl.yp" { "$_[2]" } ], [#Rule 60 @@ -2144,31 +2162,31 @@ sub [#Rule 61 'property_list', 4, sub -#line 231 "build/pidl/idl.yp" +#line 249 "build/pidl/idl.yp" { util::FlattenHash([$_[1],$_[3]]); } ], [#Rule 62 'properties', 1, sub -#line 234 "build/pidl/idl.yp" +#line 252 "build/pidl/idl.yp" { $_[1] } ], [#Rule 63 'properties', 3, sub -#line 235 "build/pidl/idl.yp" +#line 253 "build/pidl/idl.yp" { util::FlattenHash([$_[1], $_[3]]); } ], [#Rule 64 'property', 1, sub -#line 238 "build/pidl/idl.yp" +#line 256 "build/pidl/idl.yp" {{ "$_[1]" => "1" }} ], [#Rule 65 'property', 4, sub -#line 239 "build/pidl/idl.yp" +#line 257 "build/pidl/idl.yp" {{ "$_[1]" => "$_[3]" }} ], [#Rule 66 @@ -2177,7 +2195,7 @@ sub [#Rule 67 'listtext', 3, sub -#line 244 "build/pidl/idl.yp" +#line 262 "build/pidl/idl.yp" { "$_[1] $_[3]" } ], [#Rule 68 @@ -2186,13 +2204,13 @@ sub [#Rule 69 'commalisttext', 3, sub -#line 249 "build/pidl/idl.yp" +#line 267 "build/pidl/idl.yp" { "$_[1],$_[3]" } ], [#Rule 70 'anytext', 0, sub -#line 253 "build/pidl/idl.yp" +#line 271 "build/pidl/idl.yp" { "" } ], [#Rule 71 @@ -2207,67 +2225,67 @@ sub [#Rule 74 'anytext', 3, sub -#line 255 "build/pidl/idl.yp" +#line 273 "build/pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 75 'anytext', 3, sub -#line 256 "build/pidl/idl.yp" +#line 274 "build/pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 76 'anytext', 3, sub -#line 257 "build/pidl/idl.yp" +#line 275 "build/pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 77 'anytext', 3, sub -#line 258 "build/pidl/idl.yp" +#line 276 "build/pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 78 'anytext', 3, sub -#line 259 "build/pidl/idl.yp" +#line 277 "build/pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 79 'anytext', 3, sub -#line 260 "build/pidl/idl.yp" +#line 278 "build/pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 80 'anytext', 3, sub -#line 261 "build/pidl/idl.yp" +#line 279 "build/pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 81 'anytext', 3, sub -#line 262 "build/pidl/idl.yp" +#line 280 "build/pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 82 'anytext', 3, sub -#line 263 "build/pidl/idl.yp" +#line 281 "build/pidl/idl.yp" { "$_[1]$_[2]$_[3]" } ], [#Rule 83 'anytext', 5, sub -#line 264 "build/pidl/idl.yp" +#line 282 "build/pidl/idl.yp" { "$_[1]$_[2]$_[3]$_[4]$_[5]" } ], [#Rule 84 'anytext', 5, sub -#line 265 "build/pidl/idl.yp" +#line 283 "build/pidl/idl.yp" { "$_[1]$_[2]$_[3]$_[4]$_[5]" } ], [#Rule 85 @@ -2279,7 +2297,7 @@ sub [#Rule 87 'text', 1, sub -#line 274 "build/pidl/idl.yp" +#line 292 "build/pidl/idl.yp" { "\"$_[1]\"" } ], [#Rule 88 @@ -2293,13 +2311,13 @@ sub bless($self,$class); } -#line 285 "build/pidl/idl.yp" +#line 303 "build/pidl/idl.yp" use util; sub _Error { - if (exists $_[0]->YYData->{ERRMSG}) { + if (exists $_[0]->YYData->{ERRMSG}) { print $_[0]->YYData->{ERRMSG}; delete $_[0]->YYData->{ERRMSG}; return; @@ -2385,21 +2403,6 @@ sub parse_idl($$) my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error ); - foreach my $x (@{$idl}) { - # Do the inheritance - if (defined($x->{BASE}) and $x->{BASE} ne "") { - my $parent = util::get_interface($idl, $x->{BASE}); - - if(not defined($parent)) { - die("No such parent interface " . $x->{BASE}); - } - - @{$x->{INHERITED_DATA}} = (@{$parent->{INHERITED_DATA}}, @{$x->{DATA}}); - } else { - $x->{INHERITED_DATA} = $x->{DATA}; - } - } - return util::CleanData($idl); } diff --git a/source4/build/pidl/idl.yp b/source4/build/pidl/idl.yp index 186f003396..d58dc9d023 100644 --- a/source4/build/pidl/idl.yp +++ b/source4/build/pidl/idl.yp @@ -26,6 +26,8 @@ coclass: property_list 'coclass' identifier '{' interface_names '}' optional_sem "PROPERTIES" => $_[1], "NAME" => $_[3], "DATA" => $_[5], + "FILE" => $_[0]->YYData->{INPUT_FILENAME}, + "LINE" => $_[0]->YYData->{LINE}, }} ; @@ -41,6 +43,8 @@ interface: property_list 'interface' identifier base_interface '{' definitions ' "NAME" => $_[3], "BASE" => $_[4], "DATA" => $_[6], + "FILE" => $_[0]->YYData->{INPUT_FILENAME}, + "LINE" => $_[0]->YYData->{LINE}, }} ; @@ -63,7 +67,9 @@ const: 'const' identifier identifier '=' anytext ';' "TYPE" => "CONST", "DTYPE" => $_[2], "NAME" => $_[3], - "VALUE" => $_[5] + "VALUE" => $_[5], + "FILE" => $_[0]->YYData->{INPUT_FILENAME}, + "LINE" => $_[0]->YYData->{LINE}, }} | 'const' identifier identifier array_len '=' anytext ';' {{ @@ -72,6 +78,8 @@ const: 'const' identifier identifier '=' anytext ';' "NAME" => $_[3], "ARRAY_LEN" => $_[4], "VALUE" => $_[6], + "FILE" => $_[0]->YYData->{INPUT_FILENAME}, + "LINE" => $_[0]->YYData->{LINE}, }} ; @@ -82,8 +90,10 @@ function: property_list type identifier '(' element_list2 ')' ';' "NAME" => $_[3], "RETURN_TYPE" => $_[2], "PROPERTIES" => $_[1], - "ELEMENTS" => $_[5] - }} + "ELEMENTS" => $_[5], + "FILE" => $_[0]->YYData->{INPUT_FILENAME}, + "LINE" => $_[0]->YYData->{LINE}, + }} ; declare: 'declare' property_list decl_type identifier';' @@ -92,6 +102,8 @@ declare: 'declare' property_list decl_type identifier';' "PROPERTIES" => $_[2], "NAME" => $_[4], "DATA" => $_[3], + "FILE" => $_[0]->YYData->{INPUT_FILENAME}, + "LINE" => $_[0]->YYData->{LINE}, }} ; @@ -116,7 +128,9 @@ typedef: 'typedef' property_list type identifier array_len ';' "PROPERTIES" => $_[2], "NAME" => $_[4], "DATA" => $_[3], - "ARRAY_LEN" => $_[5] + "ARRAY_LEN" => $_[5], + "FILE" => $_[0]->YYData->{INPUT_FILENAME}, + "LINE" => $_[0]->YYData->{LINE}, }} ; @@ -127,7 +141,7 @@ type: struct | union | enum | bitmap | identifier enum: 'enum' '{' enum_elements '}' {{ - "TYPE" => "ENUM", + "TYPE" => "ENUM", "ELEMENTS" => $_[3] }} ; @@ -168,7 +182,9 @@ empty_element: property_list ';' "NAME" => "", "TYPE" => "EMPTY", "PROPERTIES" => $_[1], - "POINTERS" => 0 + "POINTERS" => 0, + "FILE" => $_[0]->YYData->{INPUT_FILENAME}, + "LINE" => $_[0]->YYData->{LINE}, }} ; @@ -196,7 +212,9 @@ base_element: property_list type pointers identifier array_len "TYPE" => $_[2], "PROPERTIES" => $_[1], "POINTERS" => $_[3], - "ARRAY_LEN" => $_[5] + "ARRAY_LEN" => $_[5], + "FILE" => $_[0]->YYData->{INPUT_FILENAME}, + "LINE" => $_[0]->YYData->{LINE}, }} ; @@ -287,7 +305,7 @@ optional_semicolon: use util; sub _Error { - if (exists $_[0]->YYData->{ERRMSG}) { + if (exists $_[0]->YYData->{ERRMSG}) { print $_[0]->YYData->{ERRMSG}; delete $_[0]->YYData->{ERRMSG}; return; @@ -373,20 +391,5 @@ sub parse_idl($$) my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error ); - foreach my $x (@{$idl}) { - # Do the inheritance - if (defined($x->{BASE}) and $x->{BASE} ne "") { - my $parent = util::get_interface($idl, $x->{BASE}); - - if(not defined($parent)) { - die("No such parent interface " . $x->{BASE}); - } - - @{$x->{INHERITED_DATA}} = (@{$parent->{INHERITED_DATA}}, @{$x->{DATA}}); - } else { - $x->{INHERITED_DATA} = $x->{DATA}; - } - } - return util::CleanData($idl); } diff --git a/source4/build/pidl/ndr.pm b/source4/build/pidl/ndr.pm index 3c75b29227..5c39578f40 100644 --- a/source4/build/pidl/ndr.pm +++ b/source4/build/pidl/ndr.pm @@ -23,40 +23,73 @@ sub GetElementLevelTable($) { my $e = shift; - return ($e->{NDR_ORDER_TABLE}) if (defined $e->{NDR_ORDER_TABLE}); - my $order = []; my $is_deferred = 0; - # FIXME: Process {ARRAY_SIZE} kinds of arrays + # FIXME: Process {ARRAY_LEN} kinds of arrays # First, all the pointers - foreach my $i (1..need_wire_pointer($e)) { + foreach my $i (1..$e->{POINTERS}) { + my $pt = pointer_type($e); + + my $level = "EMBEDDED"; + # Top level "ref" pointers do not have a referrent identifier + $level = "TOP" if ( defined($pt) + and $i == 1 + and $e->{PARENT}->{TYPE} eq "FUNCTION"); + push (@$order, { TYPE => "POINTER", # for now, there can only be one pointer type per element POINTER_TYPE => pointer_type($e), - IS_DEFERRED => "$is_deferred" + IS_DEFERRED => "$is_deferred", + LEVEL => $level }); # everything that follows will be deferred - $is_deferred = 1; + $is_deferred = 1 if ($e->{PARENT}->{TYPE} ne "FUNCTION"); # FIXME: Process array here possibly (in case of multi-dimensional arrays, etc) } - if (defined($e->{ARRAY_LEN})) { + if (defined($e->{ARRAY_LEN}) or util::has_property($e, "size_is")) { + my $length = util::has_property($e, "length_is"); + my $size = util::has_property($e, "size_is"); + + if (not defined($size) and defined($e->{ARRAY_LEN})) { + $size = $e->{ARRAY_LEN}; + } + + if (not defined($length)) { + $length = $size; + } + push (@$order, { TYPE => "ARRAY", - ARRAY_TYPE => array_type($e), - SIZE_IS => util::has_property($e, "size_is"), - LENGTH_IS => util::has_property($e, "length_is"), - IS_DEFERRED => "$is_deferred" + SIZE_IS => $size, + LENGTH_IS => $length, + IS_DEFERRED => "$is_deferred", + # Inline arrays (which are a pidl extension) are never encoded + # as surrounding the struct they're part of + IS_SURROUNDING => (is_surrounding_array($e) and not is_inline_array($e)), + IS_VARYING => is_varying_array($e), + IS_CONFORMANT => is_conformant_array($e), + IS_FIXED => is_fixed_array($e), + NO_METADATA => (is_inline_array($e) or is_fixed_array($e)), + IS_INLINE => is_inline_array($e) }); + + $is_deferred = 0; } - if (my $sub_size = util::has_property($e, "subcontext")) { + if (my $hdr_size = util::has_property($e, "subcontext")) { + my $subsize = util::has_property($e, "subcontext_size"); + if (not defined($subsize)) { + $subsize = -1; + } + push (@$order, { TYPE => "SUBCONTEXT", - SUBCONTEXT_SIZE => $sub_size, + HEADER_SIZE => $hdr_size, + SUBCONTEXT_SIZE => $subsize, IS_DEFERRED => $is_deferred, COMPRESSION => util::has_property($e, "compression") }); @@ -73,12 +106,13 @@ sub GetElementLevelTable($) push (@$order, { TYPE => "DATA", DATA_TYPE => $e->{TYPE}, - NAME => $e->{NAME}, IS_DEFERRED => $is_deferred, - CONTAINS_DEFERRED => can_contain_deferred($e) + CONTAINS_DEFERRED => can_contain_deferred($e), + IS_SURROUNDING => is_surrounding_string($e) }); - $e->{NDR_ORDER_TABLE} = $order; + my $i = 0; + foreach (@$order) { $_->{LEVEL_INDEX} = $i; $i+=1; } return $order; } @@ -107,7 +141,7 @@ sub is_scalar_type($) { my $type = shift; - return 0 unless typelist::hasType($type); + return 0 unless(typelist::hasType($type)); if (my $dt = typelist::getType($type)->{DATA}->{TYPE}) { return 1 if ($dt eq "SCALAR" or $dt eq "ENUM" or $dt eq "BITMAP"); @@ -152,9 +186,8 @@ sub is_conformant_array($) sub is_inline_array($) { my $e = shift; - my $len = $e->{"ARRAY_LEN"}; - if (is_fixed_array($e) || - defined $len && $len ne "*") { + my $len = $e->{ARRAY_LEN}; + if (defined $len && $len ne "*" && !is_fixed_array($e)) { return 1; } return 0; @@ -181,17 +214,15 @@ sub is_surrounding_array($) and $e->{PARENT}->{TYPE} ne "FUNCTION"); } -sub array_type($) +sub is_surrounding_string($) { my $e = shift; - return "conformant-varying" if (is_varying_array($e) and is_conformant_array($e)); - return "conformant" if (is_varying_array($e)); - return "varying" if (is_varying_array($e)); - return "inline" if (is_inline_array($e)); - return "fixed" if (is_fixed_array($e)); + return 0; #FIXME - return undef; + return ($e->{TYPE} eq "string") and ($e->{POINTERS} == 0) + and util::property_matches($e, "flag", ".*LIBNDR_FLAG_STR_CONFORMANT.*") + and $e->{PARENT}->{TYPE} ne "FUNCTION"; } ##################################################################### @@ -216,6 +247,35 @@ sub find_largest_alignment($) return $align; } +my %scalar_alignments = +( + "char" => 1, + "int8" => 1, + "uint8" => 1, + "short" => 2, + "wchar_t" => 2, + "int16" => 2, + "uint16" => 2, + "long" => 4, + "int32" => 4, + "uint32" => 4, + "dlong" => 4, + "udlong" => 4, + "udlongr" => 4, + "NTTIME" => 4, + "NTTIME_1sec" => 4, + "time_t" => 4, + "DATA_BLOB" => 4, + "error_status_t" => 4, + "WERROR" => 4, + "NTSTATUS" => 4, + "boolean32" => 4, + "unsigned32" => 4, + "ipv4address" => 4, + "hyper" => 8, + "NTTIME_hyper" => 8 +); + ##################################################################### # align a type sub align_type @@ -237,10 +297,10 @@ sub align_type } elsif (($dt->{TYPE} eq "STRUCT") or ($dt->{TYPE} eq "UNION")) { return find_largest_alignment($dt); } elsif ($dt->{TYPE} eq "SCALAR") { - return typelist::getScalarAlignment($dt->{NAME}); + return $scalar_alignments{$dt->{NAME}}; + } else { + die("Unknown data type type $dt->{TYPE}"); } - - die("Unknown data type type $dt->{TYPE}"); } # determine if an element needs a reference pointer on the wire @@ -269,6 +329,7 @@ sub ParseElement($) return { NAME => $e->{NAME}, + TYPE => $e->{TYPE}, PROPERTIES => $e->{PROPERTIES}, LEVELS => GetElementLevelTable($e) }; @@ -276,18 +337,31 @@ sub ParseElement($) sub ParseStruct($) { - my $e = shift; + my $struct = shift; my @elements = (); + my $surrounding = undef; - foreach my $x (@{$e->{ELEMENTS}}) + foreach my $x (@{$struct->{ELEMENTS}}) { push @elements, ParseElement($x); } + my $e = $elements[-1]; + if (defined($e) and defined($e->{LEVELS}[0]->{IS_SURROUNDING}) and + $e->{LEVELS}[0]->{IS_SURROUNDING}) { + $surrounding = $e; + } + + if (defined $e->{TYPE} && $e->{TYPE} eq "string" + && util::property_matches($e, "flag", ".*LIBNDR_FLAG_STR_CONFORMANT.*")) { + $surrounding = $struct->{ELEMENTS}[-1]; + } + return { TYPE => "STRUCT", + SURROUNDING_ELEMENT => $surrounding, ELEMENTS => \@elements, - PROPERTIES => $e->{PROPERTIES} + PROPERTIES => $struct->{PROPERTIES} }; } @@ -295,6 +369,10 @@ sub ParseUnion($) { my $e = shift; my @elements = (); + my $switch_type = util::has_property($e, "switch_type"); + unless (defined($switch_type)) { $switch_type = "uint32"; } + + if (util::has_property($e, "nodiscriminant")) { $switch_type = undef; } foreach my $x (@{$e->{ELEMENTS}}) { @@ -303,17 +381,20 @@ sub ParseUnion($) $t = { TYPE => "EMPTY" }; } else { $t = ParseElement($x); - if (util::has_property($t, "default")) { - $t->{DEFAULT} = "default"; - } else { - $t->{CASE} = $t->{PROPERTIES}->{CASE}; - } + } + if (util::has_property($x, "default")) { + $t->{CASE} = "default"; + } elsif (defined($x->{PROPERTIES}->{case})) { + $t->{CASE} = "case $x->{PROPERTIES}->{case}"; + } else { + die("Union element $x->{NAME} has neither default nor case property"); } push @elements, $t; } return { TYPE => "UNION", + SWITCH_TYPE => $switch_type, ELEMENTS => \@elements, PROPERTIES => $e->{PROPERTIES} }; @@ -325,6 +406,7 @@ sub ParseEnum($) return { TYPE => "ENUM", + BASE_TYPE => typelist::enum_type_fn($e), ELEMENTS => $e->{ELEMENTS}, PROPERTIES => $e->{PROPERTIES} }; @@ -336,11 +418,19 @@ sub ParseBitmap($) return { TYPE => "BITMAP", + BASE_TYPE => typelist::bitmap_type_fn($e), ELEMENTS => $e->{ELEMENTS}, PROPERTIES => $e->{PROPERTIES} }; } +sub ParseDeclare($$) +{ + my $ndr = shift; + my $d = shift; + +} + sub ParseTypedef($$) { my $ndr = shift; @@ -371,41 +461,56 @@ sub ParseTypedef($$) return { NAME => $d->{NAME}, - TYPE => "TYPEDEF", + TYPE => $d->{TYPE}, PROPERTIES => $d->{PROPERTIES}, DATA => $data }; } -sub ParseFunction($$) +sub ParseConst($$) { my $ndr = shift; my $d = shift; - my @in = (); - my @out = (); + + return $d; +} + +sub ParseFunction($$$) +{ + my $ndr = shift; + my $d = shift; + my $opnum = shift; + my @elements = (); + my $rettype = undef; CheckPointerTypes($d, - $ndr->{PROPERTIES}->{pointer_default} # MIDL defaults to "ref" + $ndr->{PROPERTIES}->{pointer_default_top} ); foreach my $x (@{$d->{ELEMENTS}}) { + my $e = ParseElement($x); if (util::has_property($x, "in")) { - push (@in, ParseElement($x)); + push (@{$e->{DIRECTION}}, "in"); } + if (util::has_property($x, "out")) { - push (@out, ParseElement($x)); + push (@{$e->{DIRECTION}}, "out"); } + + push (@elements, $e); + } + + if ($d->{RETURN_TYPE} ne "void") { + $rettype = $d->{RETURN_TYPE}; } return { NAME => $d->{NAME}, TYPE => "FUNCTION", - RETURN_TYPE => $d->{RETURN_TYPE}, + OPNUM => $opnum, + RETURN_TYPE => $rettype, PROPERTIES => $d->{PROPERTIES}, - ELEMENTS => { - IN => \@in, - OUT => \@out - } + ELEMENTS => \@elements }; } @@ -430,8 +535,12 @@ sub CheckPointerTypes($$) sub ParseInterface($) { my $idl = shift; - my @functions = (); my @typedefs = (); + my @consts = (); + my @functions = (); + my @endpoints; + my @declares = (); + my $opnum = 0; my $version; if (not util::has_property($idl, "pointer_default")) { @@ -440,22 +549,41 @@ sub ParseInterface($) $idl->{PROPERTIES}->{pointer_default} = "unique"; } + if (not util::has_property($idl, "pointer_default_top")) { + $idl->{PROPERTIES}->{pointer_default_top} = "ref"; + } + foreach my $d (@{$idl->{DATA}}) { - if ($d->{TYPE} eq "DECLARE" or $d->{TYPE} eq "TYPEDEF") { + if ($d->{TYPE} eq "TYPEDEF") { push (@typedefs, ParseTypedef($idl, $d)); } + if ($d->{TYPE} eq "DECLARE") { + push (@declares, ParseDeclare($idl, $d)); + } + if ($d->{TYPE} eq "FUNCTION") { - push (@functions, ParseFunction($idl, $d)); + push (@functions, ParseFunction($idl, $d, $opnum)); + $opnum+=1; + } + + if ($d->{TYPE} eq "CONST") { + push (@consts, ParseConst($idl, $d)); } } - + $version = "0.0"; if(defined $idl->{PROPERTIES}->{version}) { $version = $idl->{PROPERTIES}->{version}; } - + + # If no endpoint is set, default to the interface name as a named pipe + if (!defined $idl->{PROPERTIES}->{endpoint}) { + push @endpoints, "\"ncacn_np:[\\\\pipe\\\\" . $idl->{NAME} . "]\""; + } else { + @endpoints = split / /, $idl->{PROPERTIES}->{endpoint}; + } return { NAME => $idl->{NAME}, @@ -464,7 +592,10 @@ sub ParseInterface($) TYPE => "INTERFACE", PROPERTIES => $idl->{PROPERTIES}, FUNCTIONS => \@functions, - TYPEDEFS => \@typedefs + CONSTS => \@consts, + TYPEDEFS => \@typedefs, + DECLARES => \@declares, + ENDPOINTS => \@endpoints }; } @@ -503,4 +634,47 @@ sub Parse($) return \@ndr; } +sub GetNextLevel($$) +{ + my $e = shift; + my $fl = shift; + + my $seen = 0; + + foreach my $l (@{$e->{LEVELS}}) { + return $l if ($seen); + ($seen = 1) if ($l == $fl); + } + + return undef; +} + +sub GetPrevLevel($$) +{ + my $e = shift; + my $fl = shift; + my $prev = undef; + + foreach my $l (@{$e->{LEVELS}}) { + (return $prev) if ($l == $fl); + $prev = $l; + } + + return undef; +} + +sub ContainsDeferred($$) +{ + my $e = shift; + my $l = shift; + + do { + return 1 if ($l->{IS_DEFERRED}); + return 1 if ($l->{CONTAINS_DEFERRED}); + } while ($l = Ndr::GetNextLevel($e,$l)); + + return 0; +} + + 1; diff --git a/source4/build/pidl/ndr_client.pm b/source4/build/pidl/ndr_client.pm index e5d4cc1569..ca6fc22465 100644 --- a/source4/build/pidl/ndr_client.pm +++ b/source4/build/pidl/ndr_client.pm @@ -52,6 +52,7 @@ NTSTATUS dcerpc_$name(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name * "; } +my %done; ##################################################################### # parse the interface definitions @@ -60,9 +61,12 @@ sub ParseInterface($) my($interface) = shift; my($data) = $interface->{DATA}; $res = "/* Client functions generated by pidl */\n\n"; + foreach my $d (@{$data}) { - ($d->{TYPE} eq "FUNCTION") && - ParseFunction($interface, $d); + if (($d->{TYPE} eq "FUNCTION") and not $done{$d->{NAME}}) { + ParseFunction($interface, $d); + } + $done{$d->{NAME}} = 1; } return $res; } diff --git a/source4/build/pidl/ndr_header.pm b/source4/build/pidl/ndr_header.pm index 0c6291fca7..bebf6937ae 100644 --- a/source4/build/pidl/ndr_header.pm +++ b/source4/build/pidl/ndr_header.pm @@ -1,12 +1,12 @@ ################################################### # create C header files for an IDL structure # Copyright tridge@samba.org 2000 +# Copyright jelmer@samba.org 2005 # released under the GNU GPL package NdrHeader; use strict; -use needed; use typelist; my($res); @@ -60,17 +60,23 @@ sub HeaderElement($) pidl tabs(); HeaderType($element, $element->{TYPE}, ""); pidl " "; - if ($element->{POINTERS} && not $element->{TYPE} =~ "string") { - for (my($i)=$element->{POINTERS}; $i > 0; $i--) { + my $pointers = 0; + foreach my $l (@{$element->{LEVELS}}) + { + if (($l->{TYPE} eq "POINTER")) { + next if ($element->{TYPE} eq "string"); pidl "*"; - } - } elsif (Ndr::is_surrounding_array($element) || - defined $element->{ARRAY_LEN} && !util::is_constant($element->{ARRAY_LEN})) { - # surrounding arrays are ugly! I choose to implement them with - # pointers instead of the [1] method - pidl "*"; - } - pidl "$element->{NAME}"; + $pointers+=1; + } elsif ($l->{TYPE} eq "ARRAY") { + if (!$pointers and !$l->{IS_FIXED}) { pidl "*"; } + pidl "$element->{NAME}"; + if ($l->{IS_FIXED}) { pidl "[$l->{SIZE_IS}]"; } + last; #FIXME + } elsif ($l->{TYPE} eq "DATA") { + pidl "$element->{NAME}"; + } + } + if (defined $element->{ARRAY_LEN} && util::is_constant($element->{ARRAY_LEN})) { pidl "[$element->{ARRAY_LEN}]"; } @@ -106,24 +112,17 @@ sub HeaderEnum($$) { my($enum) = shift; my($name) = shift; + my $first = 1; pidl "\nenum $name {\n"; $tab_depth++; - my $els = \@{$enum->{ELEMENTS}}; - foreach my $i (0 .. $#{$els}-1) { - my $e = ${$els}[$i]; + foreach my $e (@{$enum->{ELEMENTS}}) { + unless ($first) { pidl ",\n"; } + $first = 0; tabs(); - chomp $e; - pidl "$e,\n"; - } - - my $e = ${$els}[$#{$els}]; - tabs(); - chomp $e; - if ($e !~ /^(.*?)\s*$/) { - die "Bad enum $name\n"; + pidl $e; } - pidl "$1\n"; + pidl "\n"; $tab_depth--; pidl "}"; } @@ -137,10 +136,8 @@ sub HeaderBitmap($$) pidl "\n/* bitmap $name */\n"; - my $els = \@{$bitmap->{ELEMENTS}}; - foreach my $i (0 .. $#{$els}) { - my $e = ${$els}[$i]; - chomp $e; + foreach my $e (@{$bitmap->{ELEMENTS}}) + { pidl "#define $e\n"; } @@ -180,18 +177,14 @@ sub HeaderType($$$) my($data) = shift; my($name) = shift; if (ref($data) eq "HASH") { - ($data->{TYPE} eq "ENUM") && - HeaderEnum($data, $name); - ($data->{TYPE} eq "BITMAP") && - HeaderBitmap($data, $name); - ($data->{TYPE} eq "STRUCT") && - HeaderStruct($data, $name); - ($data->{TYPE} eq "UNION") && - HeaderUnion($data, $name); + ($data->{TYPE} eq "ENUM") && HeaderEnum($data, $name); + ($data->{TYPE} eq "BITMAP") && HeaderBitmap($data, $name); + ($data->{TYPE} eq "STRUCT") && HeaderStruct($data, $name); + ($data->{TYPE} eq "UNION") && HeaderUnion($data, $name); return; } - pidl typelist::mapType($e); + pidl typelist::mapType($e->{TYPE}); } ##################################################################### @@ -211,7 +204,7 @@ sub HeaderTypedefProto($) my $tf = NdrParser::get_typefamily($d->{DATA}{TYPE}); - if (needed::is_needed("ndr_size_$d->{NAME}")) { + if (util::has_property($d, "gensize")) { my $size_args = $tf->{SIZE_FN_ARGS}->($d); pidl "size_t ndr_size_$d->{NAME}($size_args);\n"; } @@ -265,7 +258,7 @@ sub HeaderFunctionInOut_needed($$) my($fn) = shift; my($prop) = shift; - if ($prop eq "out" && $fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") { + if ($prop eq "out" && $fn->{RETURN_TYPE}) { return 1; } @@ -278,12 +271,18 @@ sub HeaderFunctionInOut_needed($$) return undef; } +my %headerstructs = (); + ##################################################################### # parse a function sub HeaderFunction($) { my($fn) = shift; + return if ($headerstructs{$fn->{NAME}}); + + $headerstructs{$fn->{NAME}} = 1; + pidl "\nstruct $fn->{NAME} {\n"; $tab_depth++; my $needed = 0; @@ -304,9 +303,9 @@ sub HeaderFunction($) pidl "struct {\n"; $tab_depth++; HeaderFunctionInOut($fn, "out"); - if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") { + if ($fn->{RETURN_TYPE}) { tabs(); - pidl typelist::mapScalarType($fn->{RETURN_TYPE}) . " result;\n"; + pidl typelist::mapType($fn->{RETURN_TYPE}) . " result;\n"; } $tab_depth--; tabs(); @@ -350,7 +349,6 @@ sub HeaderFnProto($$) sub HeaderInterface($) { my($interface) = shift; - my($data) = $interface->{DATA}; my $count = 0; @@ -364,11 +362,6 @@ sub HeaderInterface($) } } - # Object interfaces use ORPC - if (util::has_property($interface, "object")) { - pidl "#include \"librpc/gen_ndr/ndr_orpc.h\"\n"; - } - if (defined $interface->{PROPERTIES}->{uuid}) { my $name = uc $interface->{NAME}; pidl "#define DCERPC_$name\_UUID " . @@ -386,18 +379,16 @@ sub HeaderInterface($) pidl "NTSTATUS dcerpc_server_$interface->{NAME}_init(void);\n\n"; } - foreach my $d (@{$data}) { - if ($d->{TYPE} eq "FUNCTION") { - my $u_name = uc $d->{NAME}; - pidl "#define DCERPC_$u_name ("; + foreach my $d (@{$interface->{FUNCTIONS}}) { + my $u_name = uc $d->{NAME}; + pidl "#define DCERPC_$u_name ("; + + if (defined($interface->{BASE})) { + pidl "DCERPC_" . uc $interface->{BASE} . "_CALL_COUNT + "; + } - if (defined($interface->{BASE})) { - pidl "DCERPC_" . uc $interface->{BASE} . "_CALL_COUNT + "; - } - - pidl sprintf("0x%02x", $count) . ")\n"; - $count++; - } + pidl sprintf("0x%02x", $count) . ")\n"; + $count++; } pidl "\n#define DCERPC_" . uc $interface->{NAME} . "_CALL_COUNT ("; @@ -408,19 +399,21 @@ sub HeaderInterface($) pidl "$count)\n\n"; - foreach my $d (@{$data}) { - ($d->{TYPE} eq "CONST") && + foreach my $d (@{$interface->{CONSTS}}) { HeaderConst($d); - ($d->{TYPE} eq "TYPEDEF") && + } + + foreach my $d (@{$interface->{TYPEDEFS}}) { HeaderTypedef($d); - ($d->{TYPE} eq "TYPEDEF") && HeaderTypedefProto($d); - ($d->{TYPE} eq "FUNCTION") && + } + + foreach my $d (@{$interface->{FUNCTIONS}}) { HeaderFunction($d); - ($d->{TYPE} eq "FUNCTION") && HeaderFnProto($interface, $d); - } - + } + + pidl "#endif /* _HEADER_NDR_$interface->{NAME} */\n"; } @@ -431,13 +424,10 @@ sub Parse($) my($idl) = shift; $tab_depth = 0; - NdrParser::Load($idl); - $res = ""; pidl "/* header auto-generated by pidl */\n\n"; foreach my $x (@{$idl}) { if ($x->{TYPE} eq "INTERFACE") { - needed::BuildNeeded($x); HeaderInterface($x); } } diff --git a/source4/build/pidl/ndr_parser.pm b/source4/build/pidl/ndr_parser.pm index d0eba81bef..1abf8f7006 100644 --- a/source4/build/pidl/ndr_parser.pm +++ b/source4/build/pidl/ndr_parser.pm @@ -8,7 +8,6 @@ package NdrParser; use strict; -use needed; use typelist; use ndr; @@ -21,15 +20,30 @@ sub get_typefamily($) return $typefamily{$n}; } -# determine if an element needs a "buffers" section in NDR -sub need_buffers_section($) +sub append_prefix($$) { my $e = shift; - if (!Ndr::can_contain_deferred($e) && - !util::array_size($e)) { - return 0; + my $var_name = shift; + my $pointers = 0; + + foreach my $l (@{$e->{LEVELS}}) { + if ($l->{TYPE} eq "POINTER") { + $pointers++; + } elsif ($l->{TYPE} eq "ARRAY") { + if (($pointers == 0) and + (not $l->{IS_FIXED}) and + (not $l->{IS_INLINE})) { + return get_value_of($var_name) + } + } elsif ($l->{TYPE} eq "DATA") { + if ($l->{DATA_TYPE} eq "string" or + $l->{DATA_TYPE} eq "nbt_string") { + return get_value_of($var_name) unless ($pointers); + } + } } - return 1; + + return $var_name; } # see if a variable needs to be allocated by the NDR subsystem on pull @@ -37,63 +51,45 @@ sub need_alloc($) { my $e = shift; - return 0 if (util::has_property($e, "ref") && $e->{PARENT}->{TYPE} eq "FUNCTION"); - return 1 if ($e->{POINTERS} || util::array_size($e)); return 0; } -# Prefix to get the actual value of a variable -sub c_ptr_prefix($) +sub is_scalar_array($$) { my $e = shift; - my $pointers = ""; - foreach my $i (Ndr::need_wire_pointer($e)..$e->{POINTERS}-1) { $pointers.="*"; } - return $pointers; -} + my $l = shift; -# determine the C prefix used to refer to a variable when passing to a push -# function. This will be '*' for pointers to scalar types, '' for scalar -# types and normal pointers and '&' for pass-by-reference structures -sub c_push_prefix($) -{ - my $e = shift; + return 0 if ($l->{TYPE} ne "ARRAY"); - my $ret = ""; - - if ($e->{TYPE} =~ "string") { - $ret = ""; - } elsif (Ndr::is_scalar_type($e->{TYPE}) and $e->{POINTERS} and - !util::array_size($e)) { - $ret .="*"; - } elsif (!Ndr::is_scalar_type($e->{TYPE}) && - !$e->{POINTERS} && - !util::array_size($e)) { - return "&"; - } + my $nl = Ndr::GetNextLevel($e,$l); + return (($nl->{TYPE} eq "DATA") and + (Ndr::is_scalar_type($nl->{DATA_TYPE}))); +} - foreach my $i (2..$e->{POINTERS}) { $ret.="*"; } +sub get_pointer_to($) +{ + my $var_name = shift; - return $ret; + if ($var_name =~ /^\*(.*)$/) { + return $1; + } elsif ($var_name =~ /^\&(.*)$/) { + return "&($var_name)"; + } else { + return "&$var_name"; + } } -# determine the C prefix used to refer to a variable when passing to a pull -# return '&' or '' -sub c_pull_prefix($) +sub get_value_of($) { - my $e = shift; + my $var_name = shift; - if (!$e->{POINTERS} && !util::array_size($e)) { - return "&"; - } - - if ($e->{TYPE} =~ "string") { - return "&"; + if ($var_name =~ /^\&(.*)$/) { + return $1; + } else { + return "*$var_name"; } - - my $ret = ""; - foreach my $i (2..$e->{POINTERS}) { $ret.="*"; } - return $ret; } + my $res = ""; my $tabs = ""; sub pidl($) @@ -118,46 +114,35 @@ sub deindent() #################################################################### # work out the name of a size_is() variable -sub ParseExpr($$$) +sub ParseExpr($$) { - my($e) = shift; - my($size) = shift; - my($var_prefix) = shift; + my($orig_expr) = shift; + my $varlist = shift; - my($fn) = $e->{PARENT}; + die("Undefined value in ParseExpr") if not defined($orig_expr); - return $size if (util::is_constant($size)); + my $expr = $orig_expr; - return $size if ($size =~ /ndr->|\(/); + return $expr if (util::is_constant($expr)); my $prefix = ""; + my $postfix = ""; - if ($size =~ /\*(.*)/) { - $size = $1; + if ($expr =~ /\*(.*)/) { + $expr = $1; $prefix = "*"; } - if ($fn->{TYPE} ne "FUNCTION") { - return $prefix . "r->$size"; + if ($expr =~ /^(.*)([\&\|\/+])(.*)$/) { + $postfix = $2.$3; + $expr = $1; } - my $e2 = util::find_sibling($e, $size); - - die("Invalid sibling '$size'") unless defined($e2); - - 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"; + if (defined($varlist->{$expr})) { + return $prefix.$varlist->{$expr}.$postfix; } - die "invalid variable in $size for element $e->{NAME} in $fn->{NAME}\n"; + return $prefix.$expr.$postfix; } ##################################################################### @@ -189,11 +174,7 @@ sub fn_prefix($) { my $fn = shift; - if ($fn->{TYPE} eq "TYPEDEF" or - $fn->{TYPE} eq "FUNCTION") { - return "" if (util::has_property($fn, "public")); - } - + return "" if (util::has_property($fn, "public")); return "static "; } @@ -204,7 +185,9 @@ sub start_flags($) my $e = shift; my $flags = util::has_property($e, "flag"); if (defined $flags) { - pidl "{ uint32_t _flags_save_$e->{TYPE} = ndr->flags;"; + pidl "{"; + indent; + pidl "uint32_t _flags_save_$e->{TYPE} = ndr->flags;"; pidl "ndr_set_flags(&ndr->flags, $flags);"; } } @@ -216,150 +199,135 @@ sub end_flags($) my $e = shift; my $flags = util::has_property($e, "flag"); if (defined $flags) { - pidl "ndr->flags = _flags_save_$e->{TYPE};\n\t}"; + pidl "ndr->flags = _flags_save_$e->{TYPE};"; + deindent; + pidl "}"; } } -##################################################################### -# parse array preceding data - push side -sub ParseArrayPushPreceding($$$) +sub GenerateStructEnv($) { - my $e = shift; - my $var_prefix = shift; - my $ndr_flags = shift; - - my $size = ParseExpr($e, util::array_size($e), $var_prefix); + my $x = shift; + my %env; - if (!Ndr::is_inline_array($e)) { - # we need to emit the array size - pidl "NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, $size));"; + foreach my $e (@{$x->{ELEMENTS}}) { + $env{$e->{NAME}} = "r->$e->{NAME}"; } + + $env{"this"} = "r"; + + return \%env; } -##################################################################### -# parse the data of an array - push side -sub ParseArrayPush($$$$) +sub GenerateFunctionEnv($) { - my $e = shift; - my $ndr = shift; - my $var_prefix = shift; - my $ndr_flags = shift; - my $cprefix = c_push_prefix($e); - - my $size = ParseExpr($e, util::array_size($e), $var_prefix); + my $fn = shift; + my %env; - # See whether the array size has been pushed yet - if (!Ndr::is_surrounding_array($e)) { - ParseArrayPushPreceding($e, $var_prefix, $ndr_flags); - } - - if (Ndr::is_varying_array($e)) { - my $length = util::has_property($e, "length_is"); - $length = ParseExpr($e, $length, $var_prefix); - pidl "NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, 0));"; - pidl "NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, $length));"; - $size = $length; + foreach my $e (@{$fn->{ELEMENTS}}) { + if (grep (/out/, @{$e->{DIRECTION}})) { + $env{$e->{NAME}} = "r->out.$e->{NAME}"; + } + if (grep (/in/, @{$e->{DIRECTION}})) { + $env{$e->{NAME}} = "r->in.$e->{NAME}"; + } } - if (Ndr::is_scalar_type($e->{TYPE})) { - pidl "NDR_CHECK(ndr_push_array_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}, $size));"; - } else { - pidl "NDR_CHECK(ndr_push_array($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}, sizeof($cprefix$var_prefix$e->{NAME}\[0]), $size, (ndr_push_flags_fn_t)ndr_push_$e->{TYPE}));"; - } + return \%env; } ##################################################################### -# print an array -sub ParseArrayPrint($$) +# parse array preceding data - push side +sub ParseArrayPushPreceding($$$$) { my $e = shift; - my $var_prefix = shift; - my $size = ParseExpr($e, util::array_size($e), $var_prefix); - my $cprefix = c_push_prefix($e); + my $l = shift; + my $var_name = shift; + my $env = shift; - if (Ndr::is_varying_array($e)) { - $size = ParseExpr($e, util::has_property($e, "length_is"), $var_prefix); - } + return if ($l->{NO_METADATA}); - if (Ndr::is_scalar_type($e->{TYPE})) { - pidl "ndr_print_array_$e->{TYPE}(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME}, $size);"; - } else { - pidl "ndr_print_array(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME}, sizeof($cprefix$var_prefix$e->{NAME}\[0]), $size, (ndr_print_fn_t)ndr_print_$e->{TYPE});"; - } + my $size = ParseExpr($l->{SIZE_IS}, $env); + + # we need to emit the array size + pidl "NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, $size));"; } ##################################################################### -# check the size_is and length_is constraints -sub CheckArraySizes($$) +# parse the data of an array - push side +sub ParseArrayPushHeader($$$$$) { my $e = shift; - my $var_prefix = shift; + my $l = shift; + my $ndr = shift; + my $var_name = shift; + my $env = shift; - if (Ndr::is_conformant_array($e)) { - my $size = ParseExpr($e, util::array_size($e), $var_prefix); - pidl "if ($var_prefix$e->{NAME}) {"; - indent; - check_null_pointer($size); - pidl "NDR_CHECK(ndr_check_array_size(ndr, (void*)&$var_prefix$e->{NAME}, $size));"; - deindent; - pidl "}"; + if (!$l->{NO_METADATA}) { + $var_name = get_pointer_to($var_name); } - if (Ndr::is_varying_array($e)) { - my $length = util::has_property($e, "length_is"); - $length = ParseExpr($e, $length, $var_prefix); - pidl "if ($var_prefix$e->{NAME}) {"; - indent; - check_null_pointer($length); - pidl "NDR_CHECK(ndr_check_array_length(ndr, (void*)&$var_prefix$e->{NAME}, $length));"; - deindent; - pidl "}" + my $size = ParseExpr($l->{SIZE_IS}, $env); + my $length = ParseExpr($l->{LENGTH_IS}, $env); + + # See whether the array size has been pushed yet + if (!$l->{IS_SURROUNDING}) { + ParseArrayPushPreceding($e, $l, $var_name, $env); } + + if ($l->{IS_VARYING}) { + pidl "NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, 0));"; + pidl "NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, $length));"; + } + + return $length; } sub ParseArrayPullPreceding($$$) { my $e = shift; - my $var_prefix = shift; - my $ndr_flags = shift; + my $l = shift; + my $var_name = shift; - if (!Ndr::is_inline_array($e)) { - # non fixed arrays encode the size just before the array - pidl "NDR_CHECK(ndr_pull_array_size(ndr, &$var_prefix$e->{NAME}));"; - } + return if ($l->{NO_METADATA}); + + # non fixed arrays encode the size just before the array + pidl "NDR_CHECK(ndr_pull_array_size(ndr, " . get_pointer_to($var_name) . "));"; } ##################################################################### # parse an array - pull side -sub ParseArrayPull($$$$) +sub ParseArrayPullHeader($$$$$) { my $e = shift; + my $l = shift; my $ndr = shift; - my $var_prefix = shift; - my $ndr_flags = shift; + my $var_name = shift; + my $env = shift; - my $cprefix = c_pull_prefix($e); - my $length = ParseExpr($e, util::array_size($e), $var_prefix); + unless ($l->{NO_METADATA}) { + $var_name = get_pointer_to($var_name); + } + + # $var_name contains the name of the first argument here + + my $length = ParseExpr($l->{SIZE_IS}, $env); my $size = $length; - if (Ndr::is_conformant_array($e)) { - $length = $size = "ndr_get_array_size($ndr, &$var_prefix$e->{NAME})"; + if ($l->{IS_CONFORMANT}) { + $length = $size = "ndr_get_array_size($ndr, " . get_pointer_to($var_name) . ")"; } # if this is a conformant array then we use that size to allocate, and make sure # we allocate enough to pull the elements - if (!Ndr::is_inline_array($e) and not Ndr::is_surrounding_array($e)) { - if ($var_prefix =~ /^r->out/ && $length =~ /^\*r->in/) { - my $length2 = substr($length, 1); - pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) { NDR_ALLOC($ndr, $length2); }"; - } - - ParseArrayPullPreceding($e, $var_prefix, $ndr_flags); + if (!$l->{IS_SURROUNDING}) { + ParseArrayPullPreceding($e, $l, $var_name); } - if (Ndr::is_varying_array($e)) { - pidl "NDR_CHECK(ndr_pull_array_length($ndr, &$var_prefix$e->{NAME}));"; - $length = "ndr_get_array_length($ndr, &$var_prefix$e->{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); @@ -367,63 +335,66 @@ sub ParseArrayPull($$$$) if ($length ne $size) { pidl "if ($length > $size) {"; indent; - pidl "return ndr_pull_error($ndr, NDR_ERR_CONFORMANT_SIZE, \"Bad conformant size %u should be %u\", $size, $length);"; + pidl "return ndr_pull_error($ndr, NDR_ERR_ARRAY_SIZE, \"Bad array size %u should exceed array length %u\", $size, $length);"; deindent; pidl "}"; } - if ((need_alloc($e) && !Ndr::is_fixed_array($e)) || - ($var_prefix eq "r->in." && util::has_property($e, "ref"))) { - if (!Ndr::is_inline_array($e) || $ndr_flags eq "NDR_SCALARS") { - pidl "NDR_ALLOC_N($ndr, $var_prefix$e->{NAME}, $size);"; - } + if ($l->{IS_CONFORMANT}) { + my $size = ParseExpr($l->{SIZE_IS}, $env); + check_null_pointer($size); + pidl "NDR_CHECK(ndr_check_array_size(ndr, (void*)" . get_pointer_to($var_name) . ", $size));"; } - if (($var_prefix eq "r->out." && util::has_property($e, "ref"))) { - if (!Ndr::is_inline_array($e) || $ndr_flags eq "NDR_SCALARS") { - pidl "if ($ndr->flags & LIBNDR_FLAG_REF_ALLOC) {"; - pidl "\tNDR_ALLOC_N($ndr, $var_prefix$e->{NAME}, $size);"; - pidl "}"; - } + if ($l->{IS_VARYING}) { + my $length = ParseExpr($l->{LENGTH_IS}, $env); + check_null_pointer($length); + pidl "NDR_CHECK(ndr_check_array_length(ndr, (void*)" . get_pointer_to($var_name) . ", $length));"; } - if (Ndr::is_scalar_type($e->{TYPE})) { - pidl "NDR_CHECK(ndr_pull_array_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}, $length));"; - } else { - pidl "NDR_CHECK(ndr_pull_array($ndr, $ndr_flags, (void **)$cprefix$var_prefix$e->{NAME}, sizeof($cprefix$var_prefix$e->{NAME}\[0]), $length, (ndr_pull_flags_fn_t)ndr_pull_$e->{TYPE}));"; + if (!$l->{IS_FIXED}) { + AllocateArrayLevel($e,$l,$ndr,$env,$size); } + + return $length; } -sub compression_alg($) +sub compression_alg($$) { my $e = shift; - my $compression = util::has_property($e, "compression"); + my $l = shift; + my $compression = $l->{COMPRESSION}; my ($alg, $clen, $dlen) = split(/ /, $compression); return $alg; } -sub compression_clen($) +sub compression_clen($$$) { my $e = shift; - my $compression = util::has_property($e, "compression"); + my $l = shift; + my $env = shift; + my $compression = $l->{COMPRESSION}; my ($alg, $clen, $dlen) = split(/ /, $compression); - return ParseExpr($e, $clen, "r->"); + return ParseExpr($clen, $env); } -sub compression_dlen($) +sub compression_dlen($$$) { my $e = shift; - my $compression = util::has_property($e, "compression"); + my $l = shift; + my $env = shift; + my $compression = $l->{COMPRESSION}; my ($alg, $clen, $dlen) = split(/ /, $compression); - return ParseExpr($e, $dlen, "r->"); + return ParseExpr($dlen, $env); } -sub ParseCompressionPushStart($$) +sub ParseCompressionPushStart($$$) { my $e = shift; + my $l = shift; my $subndr = shift; my $comndr = $subndr."_compressed"; @@ -439,25 +410,28 @@ sub ParseCompressionPushStart($$) return $comndr; } -sub ParseCompressionPushEnd($$) +sub ParseCompressionPushEnd($$$) { my $e = shift; + my $l = shift; my $subndr = shift; my $comndr = $subndr."_compressed"; - my $alg = compression_alg($e); + my $alg = compression_alg($e, $l); pidl "NDR_CHECK(ndr_push_compression($subndr, $comndr, $alg));"; deindent; pidl "}"; } -sub ParseCompressionPullStart($$) +sub ParseCompressionPullStart($$$$) { my $e = shift; + my $l = shift; my $subndr = shift; + my $env = shift; my $comndr = $subndr."_compressed"; - my $alg = compression_alg($e); - my $dlen = compression_dlen($e); + my $alg = compression_alg($e, $l); + my $dlen = compression_dlen($e, $l, $env); pidl "{"; indent; @@ -468,9 +442,10 @@ sub ParseCompressionPullStart($$) return $comndr; } -sub ParseCompressionPullEnd($$) +sub ParseCompressionPullEnd($$$) { my $e = shift; + my $l = shift; my $subndr = shift; my $comndr = $subndr."_compressed"; @@ -516,113 +491,105 @@ sub ParseObfuscationPullEnd($$) # nothing to do here } -sub ParseSubcontextPushStart($$) +sub ParseSubcontextPushStart($$$$$) { my $e = shift; + my $l = shift; + my $ndr = shift; + my $var_name = shift; my $ndr_flags = shift; - my $compression = util::has_property($e, "compression"); - my $obfuscation = util::has_property($e, "obfuscation"); my $retndr = "_ndr_$e->{NAME}"; - pidl "if (($ndr_flags) & NDR_SCALARS) {"; + return unless ($ndr_flags =~ /NDR_SCALARS/); + + pidl "{"; indent; pidl "struct ndr_push *$retndr;"; pidl ""; - pidl "$retndr = ndr_push_init_ctx(ndr);"; + pidl "$retndr = ndr_push_init_ctx($ndr);"; pidl "if (!$retndr) return NT_STATUS_NO_MEMORY;"; - pidl "$retndr->flags = ndr->flags;"; + pidl "$retndr->flags = $ndr->flags;"; pidl ""; - if (defined $compression) { - $retndr = ParseCompressionPushStart($e, $retndr); + if (defined $l->{COMPRESSION}) { + $retndr = ParseCompressionPushStart($e, $l, $retndr); } - if (defined $obfuscation) { + if (defined $l->{OBFUSCATION}) { $retndr = ParseObfuscationPushStart($e, $retndr); } - return $retndr + return $retndr; } -sub ParseSubcontextPushEnd($) +sub ParseSubcontextPushEnd($$$) { my $e = shift; - my $header_size = util::has_property($e, "subcontext"); - my $size_is = util::has_property($e, "subcontext_size"); - my $compression = util::has_property($e, "compression"); - my $obfuscation = util::has_property($e, "obfuscation"); + my $l = shift; + my $ndr_flags = shift; my $ndr = "_ndr_$e->{NAME}"; - if (defined $obfuscation) { - ParseObfuscationPushEnd($e, $ndr); - } + return unless ($ndr_flags =~ /NDR_SCALARS/); - if (defined $compression) { - ParseCompressionPushEnd($e, $ndr); + if (defined $l->{COMPRESSION}) { + ParseCompressionPushEnd($e, $l, $ndr); } - if (not defined($size_is)) { - $size_is = "-1"; + if (defined $l->{OBFUSCATION}) { + ParseObfuscationPushEnd($e, $ndr); } - pidl "NDR_CHECK(ndr_push_subcontext_header(ndr, $header_size, $size_is, $ndr));"; + pidl "NDR_CHECK(ndr_push_subcontext_header(ndr, $l->{HEADER_SIZE}, $l->{SUBCONTEXT_SIZE}, $ndr));"; pidl "NDR_CHECK(ndr_push_bytes(ndr, $ndr->data, $ndr->offset));"; deindent; pidl "}"; } -sub ParseSubcontextPullStart($$) +sub ParseSubcontextPullStart($$$$$$) { my $e = shift; - my $ndr_flags = shift; - my $header_size = util::has_property($e, "subcontext"); - my $size_is = util::has_property($e, "subcontext_size"); - my $compression = util::has_property($e, "compression"); - my $obfuscation = util::has_property($e, "obfuscation"); + my $l = shift; + my $ndr = shift; + my $var_name = shift; + my $ndr_flags = shift; + my $env = shift; my $retndr = "_ndr_$e->{NAME}"; - if (not defined($size_is)) { - $size_is = "-1"; - } - pidl "if (($ndr_flags) & NDR_SCALARS) {"; indent; pidl "struct ndr_pull *$retndr;"; pidl "NDR_ALLOC(ndr, $retndr);"; - pidl "NDR_CHECK(ndr_pull_subcontext_header(ndr, $header_size, $size_is, $retndr));"; + pidl "NDR_CHECK(ndr_pull_subcontext_header($ndr, $l->{HEADER_SIZE}, $l->{SUBCONTEXT_SIZE}, $retndr));"; - if (defined $compression) { - $retndr = ParseCompressionPullStart($e, $retndr); + if (defined $l->{COMPRESSION}) { + $retndr = ParseCompressionPullStart($e, $l, $retndr, $env); } - if (defined $obfuscation) { + if (defined $l->{OBFUSCATION}) { $retndr = ParseObfuscationPullStart($e, $retndr); } - return $retndr; + return ($retndr,$var_name); } -sub ParseSubcontextPullEnd($) +sub ParseSubcontextPullEnd($$) { my $e = shift; - my $header_size = util::has_property($e, "subcontext"); - my $size_is = util::has_property($e, "subcontext_size"); - my $compression = util::has_property($e, "compression"); - my $obfuscation = util::has_property($e, "obfuscation"); + my $l = shift; my $ndr = "_ndr_$e->{NAME}"; - if (defined $obfuscation) { - ParseObfuscationPullEnd($e, $ndr); + if (defined $l->{COMPRESSION}) { + ParseCompressionPullEnd($e, $l, $ndr); } - if (defined $compression) { - ParseCompressionPullEnd($e, $ndr); + if (defined $l->{OBFUSCATION}) { + ParseObfuscationPullEnd($e, $ndr); } my $advance; - if (defined ($size_is)) { - $advance = "$size_is"; - } elsif ($header_size) { + if (defined($l->{SUBCONTEXT_SIZE}) and ($l->{SUBCONTEXT_SIZE} ne "-1")) { + $advance = $l->{SUBCONTEXT_SIZE}; + } elsif ($l->{HEADER_SIZE}) { $advance = "$ndr->data_size"; } else { $advance = "$ndr->offset"; @@ -632,369 +599,506 @@ sub ParseSubcontextPullEnd($) pidl "}"; } +sub ParseElementPushLevel +{ + my $e = shift; + my $l = shift; + my $ndr = shift; + my $var_name = shift; + my $env = shift; + my $primitives = shift; + my $deferred = shift; + + my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred); + + if (defined($ndr_flags)) { + if ($l->{TYPE} eq "SUBCONTEXT") { + $ndr = ParseSubcontextPushStart($e, $l, $ndr, $var_name, $ndr_flags); + ParseElementPushLevel($e, Ndr::GetNextLevel($e, $l), $ndr, $var_name, $env, $primitives, $deferred); + ParseSubcontextPushEnd($e, $l, $ndr_flags); + } elsif ($l->{TYPE} eq "POINTER") { + ParsePtrPush($e, $l, $var_name); + } elsif ($l->{TYPE} eq "ARRAY") { + my $length = ParseArrayPushHeader($e, $l, $ndr, $var_name, $env); + # Allow speedups for arrays of scalar types + if (is_scalar_array($e,$l)) { + unless ($l->{NO_METADATA}) { + $var_name = get_pointer_to($var_name); + } + + pidl "NDR_CHECK(ndr_push_array_$e->{TYPE}($ndr, $ndr_flags, $var_name, $length));"; + return; + } + } elsif ($l->{TYPE} eq "SWITCH") { + ParseSwitchPush($e, $l, $ndr, $var_name, $ndr_flags, $env); + } elsif ($l->{TYPE} eq "DATA") { + ParseDataPush($e, $l, $ndr, $var_name, $ndr_flags); + } + } + + if ($l->{TYPE} eq "POINTER" and $deferred) { + if ($l->{POINTER_TYPE} ne "ref") { + pidl "if ($var_name) {"; + indent; + if ($l->{POINTER_TYPE} eq "relative") { + pidl "NDR_CHECK(ndr_push_relative_ptr2(ndr, $var_name));"; + } + } + $var_name = get_value_of($var_name); + ParseElementPushLevel($e, Ndr::GetNextLevel($e, $l), $ndr, $var_name, $env, $primitives, $deferred); + + if ($l->{POINTER_TYPE} ne "ref") { + deindent; + pidl "}"; + } + } elsif ($l->{TYPE} eq "ARRAY" and not is_scalar_array($e,$l)) { + my $length = ParseExpr($l->{LENGTH_IS}, $env); + my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}"; + + $var_name = $var_name . "[$counter]"; + + unless ($l->{NO_METADATA}) { + $var_name = get_pointer_to($var_name); + } + + if (($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) { + pidl "for ($counter = 0; $counter < $length; $counter++) {"; + indent; + ParseElementPushLevel($e, Ndr::GetNextLevel($e, $l), $ndr, $var_name, $env, 1, 0); + deindent; + pidl "}"; + } + + if ($deferred and Ndr::ContainsDeferred($e, $l)) { + pidl "for ($counter = 0; $counter < $length; $counter++) {"; + indent; + ParseElementPushLevel($e, Ndr::GetNextLevel($e, $l), $ndr, $var_name, $env, 0, 1); + deindent; + pidl "}"; + } + } elsif ($l->{TYPE} eq "SWITCH") { + ParseElementPushLevel($e, Ndr::GetNextLevel($e, $l), $ndr, $var_name, $env, $primitives, $deferred); + } +} + ##################################################################### # parse scalars in a structure element -sub ParseElementPushScalar($$$) +sub ParseElementPush($$$$$$) { - my($e) = shift; - my($var_prefix) = shift; - my($ndr_flags) = shift; - my $cprefix = c_push_prefix($e); - my $ptr_prefix = c_ptr_prefix($e); - my $sub_size = util::has_property($e, "subcontext"); - my $ndr = "ndr"; + my $e = shift; + my $ndr = shift; + my $var_prefix = shift; + my $env = shift; + my $primitives = shift; + my $deferred = shift; my $subndr = undef; - start_flags($e); + my $var_name = $var_prefix.$e->{NAME}; - if (my $value = util::has_property($e, "value")) { - pidl "$cprefix$var_prefix$e->{NAME} = $value;"; - } + $var_name = append_prefix($e, $var_name); - if (defined $sub_size and $e->{POINTERS} == 0) { - $subndr = ParseSubcontextPushStart($e, "NDR_SCALARS"); - $ndr = $subndr; - } + return unless $primitives or ($deferred and Ndr::ContainsDeferred($e, $e->{LEVELS}[0])); - if (Ndr::need_wire_pointer($e)) { - ParsePtrPush($e, $ptr_prefix.$var_prefix); - } elsif (Ndr::is_inline_array($e)) { - ParseArrayPush($e, $ndr, "r->", "NDR_SCALARS"); - } elsif (need_alloc($e)) { - # no scalar component - } else { - if (my $switch = util::has_property($e, "switch_is")) { - ParseSwitchPush($e, $ndr, $var_prefix, $ndr_flags, $switch); - } + start_flags($e); - pidl "NDR_CHECK(ndr_push_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));"; + if (my $value = util::has_property($e, "value")) { + pidl "$var_name = $value;"; } - if (defined $sub_size and $e->{POINTERS} == 0) { - ParseSubcontextPushEnd($e); - } + ParseElementPushLevel($e, $e->{LEVELS}[0], $ndr, $var_name, $env, $primitives, $deferred); end_flags($e); } ##################################################################### # parse a pointer in a struct element or function -sub ParsePtrPush($$) +sub ParsePtrPush($$$) { my $e = shift; - my $var_prefix = shift; + my $l = shift; + my $var_name = shift; - if (util::has_property($e, "ref")) { - pidl "NDR_CHECK(ndr_push_ref_ptr(ndr, $var_prefix$e->{NAME}));"; - } elsif (util::has_property($e, "relative")) { - pidl "NDR_CHECK(ndr_push_relative_ptr1(ndr, $var_prefix$e->{NAME}));"; + if ($l->{POINTER_TYPE} eq "ref") { + if ($l->{LEVEL} eq "EMBEDDED") { + pidl "NDR_CHECK(ndr_push_ref_ptr(ndr, $var_name));"; + } else { + check_null_pointer(get_value_of($var_name)); + } + } elsif ($l->{POINTER_TYPE} eq "relative") { + pidl "NDR_CHECK(ndr_push_relative_ptr1(ndr, $var_name));"; + } elsif ($l->{POINTER_TYPE} eq "unique") { + pidl "NDR_CHECK(ndr_push_unique_ptr(ndr, $var_name));"; } else { - pidl "NDR_CHECK(ndr_push_unique_ptr(ndr, $var_prefix$e->{NAME}));"; + die("Unhandled pointer type $l->{POINTER_TYPE}"); } } ##################################################################### # print scalars in a structure element -sub ParseElementPrint($$) +sub ParseElementPrint($$$) { my($e) = shift; - my($var_prefix) = shift; - my $cprefix = c_push_prefix($e); - my $ptr_prefix = c_ptr_prefix($e); + my($var_name) = shift; + my $env = shift; + $var_name = append_prefix($e, $var_name); return if (util::has_property($e, "noprint")); if (my $value = util::has_property($e, "value")) { pidl "if (ndr->flags & LIBNDR_PRINT_SET_VALUES) {"; - pidl "\t$cprefix$var_prefix$e->{NAME} = $value;"; + pidl "\t$var_name = $value;"; pidl "}"; } - my $l = $e->{POINTERS}; - $l++ if (util::array_size($e) and $l == 0 and !Ndr::is_fixed_array($e)); + foreach my $l (@{$e->{LEVELS}}) { + if ($l->{TYPE} eq "POINTER") { + pidl "ndr_print_ptr(ndr, \"$e->{NAME}\", $var_name);"; + pidl "ndr->depth++;"; + if ($l->{POINTER_TYPE} ne "ref") { + pidl "if ($var_name) {"; + indent; + } + $var_name = get_value_of($var_name); + } elsif ($l->{TYPE} eq "ARRAY") { + my $length = ParseExpr($l->{LENGTH_IS}, $env); + + if (is_scalar_array($e, $l)) { + unless ($l->{NO_METADATA}){ + $var_name = get_pointer_to($var_name); + } + pidl "ndr_print_array_$e->{TYPE}(ndr, \"$e->{NAME}\", $var_name, $length);"; + last; + } + + my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}"; - foreach my $i (1..$l) { - pidl "ndr_print_ptr(ndr, \"$e->{NAME}\", $var_prefix$e->{NAME});"; - pidl "ndr->depth++;"; - if ($i > $l-Ndr::need_wire_pointer($e)) { - pidl "if ($ptr_prefix$var_prefix$e->{NAME}) {"; + pidl "ndr->print(ndr, \"\%s: ARRAY(\%d)\", \"$e->{NAME}\", $length);"; + pidl 'ndr->depth++;'; + pidl "for ($counter=0;$counter<$length;$counter++) {"; + indent; + pidl "char *idx_$l->{LEVEL_INDEX}=NULL;"; + pidl "asprintf(&idx_$l->{LEVEL_INDEX}, \"[\%d]\", $counter);"; + pidl "if (idx_$l->{LEVEL_INDEX}) {"; indent; - } - } - if (util::array_size($e)) { - ParseArrayPrint($e, $var_prefix) - } else { - if (my $switch = util::has_property($e, "switch_is")) { - my $switch_var = ParseExpr($e, $switch, $var_prefix); - check_null_pointer_void($switch_var); + $var_name = $var_name . "[$counter]"; - pidl "ndr_print_set_switch_value(ndr, $cprefix$var_prefix$e->{NAME}, $switch_var);"; - } + unless ($l->{NO_METADATA}){ $var_name = get_pointer_to($var_name); } - pidl "ndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME});"; + } elsif ($l->{TYPE} eq "DATA") { + if (not Ndr::is_scalar_type($l->{DATA_TYPE})) { + $var_name = get_pointer_to($var_name); + } + pidl "ndr_print_$l->{DATA_TYPE}(ndr, \"$e->{NAME}\", $var_name);"; + } elsif ($l->{TYPE} eq "SWITCH") { + my $switch_var = ParseExpr($l->{SWITCH_IS}, $env); + check_null_pointer_void($switch_var); + pidl "ndr_print_set_switch_value(ndr, " . get_pointer_to($var_name) . ", $switch_var);"; + } } - foreach my $i (1..$l) { - if ($i > $l-Ndr::need_wire_pointer($e)) { + foreach my $l (reverse @{$e->{LEVELS}}) { + if ($l->{TYPE} eq "POINTER") { + if ($l->{POINTER_TYPE} ne "ref") { + deindent; + pidl "}"; + } + pidl "ndr->depth--;"; + } elsif ($l->{TYPE} eq "ARRAY" and not is_scalar_array($e, $l)) { + pidl "free(idx_$l->{LEVEL_INDEX});"; + deindent; + pidl "}"; deindent; pidl "}"; + pidl "ndr->depth--;"; } - pidl "ndr->depth--;"; } } ##################################################################### # parse scalars in a structure element - pull size -sub ParseSwitchPull($$$$$) +sub ParseSwitchPull($$$$$$) { my($e) = shift; + my $l = shift; my $ndr = shift; - my($var_prefix) = shift; + my($var_name) = shift; my($ndr_flags) = shift; - my $switch = shift; - my $switch_var = ParseExpr($e, $switch, $var_prefix); - - my $cprefix = c_pull_prefix($e); - - my $utype = typelist::getType($e->{TYPE}); + my $env = shift; + my $switch_var = ParseExpr($l->{SWITCH_IS}, $env); check_null_pointer($switch_var); - pidl "NDR_CHECK(ndr_pull_set_switch_value($ndr, $cprefix$var_prefix$e->{NAME}, $switch_var));"; + $var_name = get_pointer_to($var_name); + pidl "NDR_CHECK(ndr_pull_set_switch_value($ndr, $var_name, $switch_var));"; } ##################################################################### # push switch element -sub ParseSwitchPush($$$$$) +sub ParseSwitchPush($$$$$$) { my($e) = shift; + my $l = shift; my $ndr = shift; - my($var_prefix) = shift; + my($var_name) = shift; my($ndr_flags) = shift; - my $switch = shift; - my $switch_var = ParseExpr($e, $switch, $var_prefix); - my $cprefix = c_push_prefix($e); + my $env = shift; + my $switch_var = ParseExpr($l->{SWITCH_IS}, $env); check_null_pointer($switch_var); - - pidl "NDR_CHECK(ndr_push_set_switch_value($ndr, $cprefix$var_prefix$e->{NAME}, $switch_var));"; - + $var_name = get_pointer_to($var_name); + pidl "NDR_CHECK(ndr_push_set_switch_value($ndr, $var_name, $switch_var));"; } -##################################################################### -# parse scalars in a structure element - pull size -sub ParseElementPullScalar($$$) +sub ParseDataPull($$$$$) { - my($e) = shift; - my($var_prefix) = shift; - my($ndr_flags) = shift; - my $cprefix = c_pull_prefix($e); - my $ptr_prefix = c_ptr_prefix($e); - my $sub_size = util::has_property($e, "subcontext"); - my $ndr = "ndr"; - my $subndr = undef; + my $e = shift; + my $l = shift; + my $ndr = shift; + my $var_name = shift; + my $ndr_flags = shift; - start_flags($e); + $var_name = get_pointer_to($var_name); - if (defined $sub_size && $e->{POINTERS} == 0) { - $subndr = ParseSubcontextPullStart($e, $ndr_flags); - $ndr = $subndr; - $ndr_flags = "NDR_SCALARS|NDR_BUFFERS"; + if ($l->{DATA_TYPE} eq "string" or + $l->{DATA_TYPE} eq "nbt_string") { + $var_name = get_pointer_to($var_name); } - if (Ndr::is_inline_array($e)) { - ParseArrayPull($e, $ndr, "r->", "NDR_SCALARS"); - } elsif (Ndr::need_wire_pointer($e)) { - ParsePtrPull($e, $ptr_prefix.$var_prefix); - } elsif (Ndr::is_surrounding_array($e)) { - } else { - if (my $switch = util::has_property($e, "switch_is")) { - ParseSwitchPull($e, $ndr, $var_prefix, $ndr_flags, $switch); - } - - pidl "NDR_CHECK(ndr_pull_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));"; - } + pidl "NDR_CHECK(ndr_pull_$l->{DATA_TYPE}($ndr, $ndr_flags, $var_name));"; if (my $range = util::has_property($e, "range")) { + $var_name = get_value_of($var_name); my ($low, $high) = split(/ /, $range, 2); - pidl "if ($var_prefix$e->{NAME} < $low || $var_prefix$e->{NAME} > $high) {"; + pidl "if ($var_name < $low || $var_name > $high) {"; pidl "\treturn ndr_pull_error($ndr, NDR_ERR_RANGE, \"value out of range\");"; pidl "}"; } - - if (defined $sub_size && $e->{POINTERS} == 0) { - ParseSubcontextPullEnd($e); - } - - end_flags($e); } -##################################################################### -# parse a pointer in a struct element or function -sub ParsePtrPull($$) +sub ParseDataPush($$$$$) { - my($e) = shift; - my($var_prefix) = shift; + my $e = shift; + my $l = shift; + my $ndr = shift; + my $var_name = shift; + my $ndr_flags = shift; - if (util::has_property($e, "ref")) { - pidl "NDR_CHECK(ndr_pull_ref_ptr(ndr, &_ptr_$e->{NAME}));"; - } else { - pidl "NDR_CHECK(ndr_pull_unique_ptr(ndr, &_ptr_$e->{NAME}));"; - } - pidl "if (_ptr_$e->{NAME}) {"; - indent; - pidl "NDR_ALLOC(ndr, $var_prefix$e->{NAME});"; - if (util::has_property($e, "relative")) { - pidl "NDR_CHECK(ndr_pull_relative_ptr1(ndr, $var_prefix$e->{NAME}, _ptr_$e->{NAME}));"; + # strings are passed by value rather then reference + if (not Ndr::is_scalar_type($l->{DATA_TYPE})) { + $var_name = get_pointer_to($var_name); } - deindent; - pidl "} else {"; - pidl "\t$var_prefix$e->{NAME} = NULL;"; - pidl "}"; + + pidl "NDR_CHECK(ndr_push_$l->{DATA_TYPE}($ndr, $ndr_flags, $var_name));"; } -##################################################################### -# parse buffers in a structure element -sub ParseElementPushBuffer($$) +sub CalcNdrFlags($$$) { - my($e) = shift; - my($var_prefix) = shift; - my $cprefix = c_push_prefix($e); - my $sub_size = util::has_property($e, "subcontext"); - my $ndr = "ndr"; - my $subndr = undef; + my $l = shift; + my $primitives = shift; + my $deferred = shift; - return unless (need_buffers_section($e)); + my $scalars = 0; + my $buffers = 0; - start_flags($e); + # Add NDR_SCALARS if this one is deferred + # and deferreds may be pushed + $scalars = 1 if ($l->{IS_DEFERRED} and $deferred); - my $pointers = c_ptr_prefix($e); - for my $i (1..Ndr::need_wire_pointer($e)) { - if ($i > 1) { - ParsePtrPush($e,$pointers.$var_prefix); - } - pidl "if ($pointers$var_prefix$e->{NAME}) {"; - indent; - $pointers.="*"; - } + # Add NDR_SCALARS if this one is not deferred and + # primitives may be pushed + $scalars = 1 if (!$l->{IS_DEFERRED} and $primitives); - if (util::has_property($e, "relative")) { - pidl "NDR_CHECK(ndr_push_relative_ptr2(ndr, $var_prefix$e->{NAME}));"; - } + # Add NDR_BUFFERS if this one contains deferred stuff + # and deferreds may be pushed + $buffers = 1 if ($l->{CONTAINS_DEFERRED} and $deferred); - my $ndr_flags = "NDR_BUFFERS"; - if ($e->{POINTERS} || (util::array_size($e) && !Ndr::is_inline_array($e))) - { - $ndr_flags="NDR_SCALARS|$ndr_flags" - } + return "NDR_SCALARS|NDR_BUFFERS" if ($scalars and $buffers); + return "NDR_SCALARS" if ($scalars); + return "NDR_BUFFERS" if ($buffers); + return undef; +} - if (defined $sub_size) { - $subndr = ParseSubcontextPushStart($e, $ndr_flags); - $ndr = $subndr; - $ndr_flags = "NDR_SCALARS|NDR_BUFFERS"; +sub ParseElementPullLevel +{ + my($e) = shift; + my $l = shift; + my $ndr = shift; + my($var_name) = shift; + my $env = shift; + my $primitives = shift; + my $deferred = shift; + + my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred); + + # Only pull something if there's actually something to be pulled + if (defined($ndr_flags)) { + if ($l->{TYPE} eq "SUBCONTEXT") { + ($ndr,$var_name) = ParseSubcontextPullStart($e, $l, $ndr, $var_name, $ndr_flags, $env); + ParseElementPullLevel($e,Ndr::GetNextLevel($e,$l), $ndr, $var_name, $env, $primitives, $deferred); + ParseSubcontextPullEnd($e, $l); + } elsif ($l->{TYPE} eq "ARRAY") { + my $length = ParseArrayPullHeader($e, $l, $ndr, $var_name, $env); + + # Speed things up a little - special array pull functions + # for scalars + if (is_scalar_array($e, $l)) { + unless ($l->{NO_METADATA}) { + $var_name = get_pointer_to($var_name); + } + + pidl "NDR_CHECK(ndr_pull_array_$e->{TYPE}($ndr, $ndr_flags, $var_name, $length));"; + return; + } + } elsif ($l->{TYPE} eq "POINTER") { + ParsePtrPull($e, $l, $ndr, $var_name); + } elsif ($l->{TYPE} eq "SWITCH") { + ParseSwitchPull($e, $l, $ndr, $var_name, $ndr_flags, $env); + } elsif ($l->{TYPE} eq "DATA") { + ParseDataPull($e, $l, $ndr, $var_name, $ndr_flags); + } } - if (util::array_size($e)) { - ParseArrayPush($e, $ndr, "r->", $ndr_flags); - } else { - if (my $switch = util::has_property($e, "switch_is")) { - ParseSwitchPush($e, $ndr, $var_prefix, $ndr_flags, $switch); + # add additional constructions + if ($l->{TYPE} eq "POINTER" and $deferred) { + if ($l->{POINTER_TYPE} ne "ref") { + pidl "if ($var_name) {"; + indent; + + if ($l->{POINTER_TYPE} eq "relative") { + pidl "struct ndr_pull_save _relative_save;"; + pidl "ndr_pull_save(ndr, &_relative_save);"; + pidl "NDR_CHECK(ndr_pull_relative_ptr2(ndr, $var_name));"; + } } - pidl "NDR_CHECK(ndr_push_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));"; - } + $var_name = get_value_of($var_name); + ParseElementPullLevel($e,Ndr::GetNextLevel($e,$l), $ndr, $var_name, $env, $primitives, $deferred); - if (defined $sub_size) { - ParseSubcontextPushEnd($e); - } + if ($l->{POINTER_TYPE} ne "ref") { + if ($l->{POINTER_TYPE} eq "relative") { + pidl "ndr_pull_restore(ndr, &_relative_save);"; + } + deindent; + pidl "}"; + } + } elsif ($l->{TYPE} eq "ARRAY" and not is_scalar_array($e,$l)) { + my $length = ParseExpr($l->{LENGTH_IS}, $env); + my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}"; - for my $i (1..Ndr::need_wire_pointer($e)) { - deindent; - pidl "}"; - } + $var_name = $var_name . "[$counter]"; + unless ($l->{NO_METADATA}) { + $var_name = get_pointer_to($var_name); + } - end_flags($e); + if (($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) { + pidl "for ($counter = 0; $counter < $length; $counter++) {"; + indent; + ParseElementPullLevel($e,Ndr::GetNextLevel($e,$l), $ndr, $var_name, $env, 1, 0); + deindent; + pidl "}"; + } + + if ($deferred and Ndr::ContainsDeferred($e, $l)) { + pidl "for ($counter = 0; $counter < $length; $counter++) {"; + indent; + ParseElementPullLevel($e,Ndr::GetNextLevel($e,$l), $ndr, $var_name, $env, 0, 1); + deindent; + pidl "}"; + } + } elsif ($l->{TYPE} eq "SWITCH") { + ParseElementPullLevel($e,Ndr::GetNextLevel($e,$l), $ndr, $var_name, $env, $primitives, $deferred); + } } ##################################################################### -# parse buffers in a structure element - pull side -sub ParseElementPullBuffer($$) +# parse scalars in a structure element - pull size +sub ParseElementPull($$$$$$) { my($e) = shift; + my $ndr = shift; my($var_prefix) = shift; - my $cprefix = c_pull_prefix($e); - my $sub_size = util::has_property($e, "subcontext"); - my $ndr = "ndr"; - my $subndr = undef; + my $env = shift; + my $primitives = shift; + my $deferred = shift; - return unless (need_buffers_section($e)); + my $var_name = $var_prefix.$e->{NAME}; + + $var_name = append_prefix($e, $var_name); + + return unless $primitives or ($deferred and Ndr::ContainsDeferred($e, $e->{LEVELS}[0])); start_flags($e); - my $pointers = c_ptr_prefix($e); - for my $i (1..Ndr::need_wire_pointer($e)) { - if ($i > 1) { - ParsePtrPull($e,$pointers.$var_prefix); - } - pidl "if ($pointers$var_prefix$e->{NAME}) {"; - indent; - $pointers.="*"; - } - - if (util::has_property($e, "relative")) { - pidl "struct ndr_pull_save _relative_save;"; - pidl "ndr_pull_save(ndr, &_relative_save);"; - pidl "NDR_CHECK(ndr_pull_relative_ptr2(ndr, $var_prefix$e->{NAME}));"; - } - - my $ndr_flags = "NDR_BUFFERS"; - if ($e->{POINTERS} || (util::array_size($e) && !Ndr::is_inline_array($e))) - { - $ndr_flags="NDR_SCALARS|$ndr_flags" - } - - if (defined $sub_size) { - $subndr = ParseSubcontextPullStart($e, $ndr_flags); - $ndr = $subndr; - $ndr_flags = "NDR_SCALARS|NDR_BUFFERS"; - } - - if (util::array_size($e)) { - ParseArrayPull($e, $ndr, "r->", $ndr_flags); - } else { - if (my $switch = util::has_property($e, "switch_is")) { - ParseSwitchPull($e, $ndr, $var_prefix, $ndr_flags, $switch); - } + ParseElementPullLevel($e,$e->{LEVELS}[0],$ndr,$var_name,$env,$primitives,$deferred); - pidl "NDR_CHECK(ndr_pull_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));"; - } + end_flags($e); +} - if (defined $sub_size) { - ParseSubcontextPullEnd($e); - } +##################################################################### +# parse a pointer in a struct element or function +sub ParsePtrPull($$$$) +{ + my($e) = shift; + my $l = shift; + my $ndr = shift; + my($var_name) = shift; + + my $nl = Ndr::GetNextLevel($e, $l); + my $next_is_array = ($nl->{TYPE} eq "ARRAY"); - if (util::has_property($e, "relative")) { - pidl "ndr_pull_restore(ndr, &_relative_save);"; + if ($l->{POINTER_TYPE} eq "ref") { + unless ($l->{LEVEL} eq "TOP") { + pidl "NDR_CHECK(ndr_pull_ref_ptr($ndr, &_ptr_$e->{NAME}));"; + } + + unless ($next_is_array) { + pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {"; + pidl "\tNDR_ALLOC($ndr, $var_name);"; + pidl "}"; + } + + return; + } else { + pidl "NDR_CHECK(ndr_pull_unique_ptr($ndr, &_ptr_$e->{NAME}));"; + pidl "if (_ptr_$e->{NAME}) {"; + indent; } - for my $i (1..Ndr::need_wire_pointer($e)) { - deindent; - pidl "}"; + # Don't do this for arrays, they're allocated at the actual level + # of the array + unless ($next_is_array) { + pidl "NDR_ALLOC($ndr, $var_name);"; + } else { + pidl "NDR_ALLOC_SIZE($ndr, $var_name, 1);"; # FIXME: Yes, this is nasty. We allocate an array twice - once just to indicate that it's there, then the real allocation... } - end_flags($e); + #pidl "memset($var_name, 0, sizeof($var_name));"; + if ($l->{POINTER_TYPE} eq "relative") { + pidl "NDR_CHECK(ndr_pull_relative_ptr1($ndr, $var_name, _ptr_$e->{NAME}));"; + } + deindent; + pidl "} else {"; + pidl "\t$var_name = NULL;"; + pidl "}"; } ##################################################################### # parse a struct -sub ParseStructPush($) +sub ParseStructPush($$) { my($struct) = shift; + my $name = shift; return unless defined($struct->{ELEMENTS}); + my $env = GenerateStructEnv($struct); + + foreach my $e (@{$struct->{ELEMENTS}}) { + DeclareArrayVariables($e); + } + start_flags($struct); # see if the structure contains a conformant array. If it @@ -1003,60 +1107,66 @@ sub ParseStructPush($) # the wire before the structure (and even before the structure # alignment) my $e = $struct->{ELEMENTS}[-1]; - if (Ndr::is_conformant_array($e) and Ndr::is_surrounding_array($e)) { - ParseArrayPushPreceding($e, "r->", "NDR_SCALARS"); - } + if (defined($struct->{SURROUNDING_ELEMENT})) { + my $e = $struct->{SURROUNDING_ELEMENT}; - if (defined $e->{TYPE} && $e->{TYPE} eq "string" - && util::property_matches($e, "flag", ".*LIBNDR_FLAG_STR_CONFORMANT.*")) { - pidl "NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_string_array_size(ndr, r->$e->{NAME})));"; + if (defined($e->{LEVELS}[0]) and + $e->{LEVELS}[0]->{TYPE} eq "ARRAY") { + ParseArrayPushPreceding($e, $e->{LEVELS}[0], "r->$e->{NAME}", $env); + } else { + pidl "NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_string_array_size(ndr, r->$e->{NAME})));"; + } } - pidl "if (!(ndr_flags & NDR_SCALARS)) goto buffers;"; + pidl "if (ndr_flags & NDR_SCALARS) {"; + indent; pidl "NDR_CHECK(ndr_push_struct_start(ndr));"; - my $align = Ndr::find_largest_alignment($struct); - pidl "NDR_CHECK(ndr_push_align(ndr, $align));"; + pidl "NDR_CHECK(ndr_push_align(ndr, $struct->{ALIGN}));"; foreach my $e (@{$struct->{ELEMENTS}}) { - ParseElementPushScalar($e, "r->", "NDR_SCALARS"); + ParseElementPush($e, "ndr", "r->", $env, 1, 0); } - pidl "buffers:"; - pidl "if (!(ndr_flags & NDR_BUFFERS)) goto done;"; + deindent; + pidl "}"; + + pidl "if (ndr_flags & NDR_BUFFERS) {"; + indent; foreach my $e (@{$struct->{ELEMENTS}}) { - ParseElementPushBuffer($e, "r->"); + ParseElementPush($e, "ndr", "r->", $env, 0, 1); } pidl "ndr_push_struct_end(ndr);"; - pidl "done:"; + deindent; + pidl "}"; end_flags($struct); } ##################################################################### # generate a push function for an enum -sub ParseEnumPush($) +sub ParseEnumPush($$) { my($enum) = shift; - my($type_fn) = typelist::enum_type_fn($enum); + my $name = shift; + my($type_fn) = $enum->{BASE_TYPE}; start_flags($enum); - pidl "NDR_CHECK(ndr_push_$type_fn(ndr, NDR_SCALARS, r));"; - end_flags($enum); } ##################################################################### # generate a pull function for an enum -sub ParseEnumPull($) +sub ParseEnumPull($$) { my($enum) = shift; - my($type_fn) = typelist::enum_type_fn($enum); - my($type_v_decl) = typelist::mapScalarType(typelist::enum_type_fn($enum)); + my $name = shift; + my($type_fn) = $enum->{BASE_TYPE}; + my($type_v_decl) = typelist::mapType($type_fn); pidl "$type_v_decl v;"; start_flags($enum); @@ -1068,9 +1178,10 @@ sub ParseEnumPull($) ##################################################################### # generate a print function for an enum -sub ParseEnumPrint($) +sub ParseEnumPrint($$) { my($enum) = shift; + my $name = shift; pidl "const char *val = NULL;"; pidl ""; @@ -1126,10 +1237,11 @@ $typefamily{ENUM} = { ##################################################################### # generate a push function for a bitmap -sub ParseBitmapPush($) +sub ParseBitmapPush($$) { my($bitmap) = shift; - my($type_fn) = typelist::bitmap_type_fn($bitmap); + my $name = shift; + my($type_fn) = $bitmap->{BASE_TYPE}; start_flags($bitmap); @@ -1140,11 +1252,12 @@ sub ParseBitmapPush($) ##################################################################### # generate a pull function for an bitmap -sub ParseBitmapPull($) +sub ParseBitmapPull($$) { my($bitmap) = shift; - my($type_fn) = typelist::bitmap_type_fn($bitmap); - my($type_decl) = typelist::mapType($bitmap); + my $name = shift; + my $type_fn = $bitmap->{BASE_TYPE}; + my($type_decl) = typelist::mapType($bitmap->{BASE_TYPE}); pidl "$type_decl v;"; start_flags($bitmap); @@ -1156,13 +1269,13 @@ sub ParseBitmapPull($) ##################################################################### # generate a print function for an bitmap -sub ParseBitmapPrintElement($$) +sub ParseBitmapPrintElement($$$) { my($e) = shift; my($bitmap) = shift; - my($type_decl) = typelist::mapType($bitmap); - my($type_fn) = typelist::bitmap_type_fn($bitmap); - my($name) = $bitmap->{PARENT}->{NAME}; + my($name) = shift; + my($type_decl) = typelist::mapType($bitmap->{BASE_TYPE}); + my($type_fn) = $bitmap->{BASE_TYPE}; my($flag); if ($e =~ /^(\w+) .*$/) { @@ -1176,11 +1289,12 @@ sub ParseBitmapPrintElement($$) ##################################################################### # generate a print function for an bitmap -sub ParseBitmapPrint($) +sub ParseBitmapPrint($$) { my($bitmap) = shift; - my($type_decl) = typelist::mapType($bitmap); - my($type_fn) = typelist::bitmap_type_fn($bitmap); + my $name = shift; + my($type_decl) = typelist::mapType($bitmap->{TYPE}); + my($type_fn) = $bitmap->{BASE_TYPE}; start_flags($bitmap); @@ -1188,7 +1302,7 @@ sub ParseBitmapPrint($) pidl "ndr->depth++;"; foreach my $e (@{$bitmap->{ELEMENTS}}) { - ParseBitmapPrintElement($e, $bitmap); + ParseBitmapPrintElement($e, $bitmap, $name); } pidl "ndr->depth--;"; @@ -1198,21 +1312,21 @@ sub ParseBitmapPrint($) sub ArgsBitmapPush($) { my $e = shift; - my $type_decl = typelist::mapType($e->{DATA}); + my $type_decl = typelist::mapType($e->{DATA}->{BASE_TYPE}); return "struct ndr_push *ndr, int ndr_flags, $type_decl r"; } sub ArgsBitmapPrint($) { my $e = shift; - my $type_decl = typelist::mapType($e->{DATA}); + my $type_decl = typelist::mapType($e->{DATA}->{BASE_TYPE}); return "struct ndr_print *ndr, const char *name, $type_decl r"; } sub ArgsBitmapPull($) { my $e = shift; - my $type_decl = typelist::mapType($e->{DATA}); + my $type_decl = typelist::mapType($e->{DATA}->{BASE_TYPE}); return "struct ndr_pull *ndr, int ndr_flags, $type_decl *r"; } @@ -1227,87 +1341,110 @@ $typefamily{BITMAP} = { ##################################################################### # generate a struct print function -sub ParseStructPrint($) +sub ParseStructPrint($$) { my($struct) = shift; - my($name) = $struct->{PARENT}->{NAME}; + my($name) = shift; return unless defined $struct->{ELEMENTS}; + my $env = GenerateStructEnv($struct); + + foreach my $e (@{$struct->{ELEMENTS}}) { + DeclareArrayVariables($e); + } + pidl "ndr_print_struct(ndr, name, \"$name\");"; start_flags($struct); pidl "ndr->depth++;"; foreach my $e (@{$struct->{ELEMENTS}}) { - ParseElementPrint($e, "r->"); + ParseElementPrint($e, "r->$e->{NAME}", $env); } pidl "ndr->depth--;"; end_flags($struct); } +sub DeclarePtrVariables($) +{ + my $e = shift; + foreach my $l (@{$e->{LEVELS}}) { + if ($l->{TYPE} eq "POINTER" and + not ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "TOP")) { + pidl "uint32_t _ptr_$e->{NAME};"; + last; + } + } +} + +sub DeclareArrayVariables($) +{ + my $e = shift; + + foreach my $l (@{$e->{LEVELS}}) { + next if (is_scalar_array($e,$l)); + if ($l->{TYPE} eq "ARRAY") { + pidl "uint32_t cntr_$e->{NAME}_$l->{LEVEL_INDEX};"; + } + } +} + ##################################################################### # parse a struct - pull side -sub ParseStructPull($) +sub ParseStructPull($$) { my($struct) = shift; + my $name = shift; my $conform_e; return unless defined $struct->{ELEMENTS}; + my $env = GenerateStructEnv($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 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 (Ndr::is_conformant_array($e) and Ndr::is_surrounding_array($e)) { - $conform_e = $e; - } - - if (defined $e->{TYPE} && $e->{TYPE} eq "string" - && util::property_matches($e, "flag", ".*LIBNDR_FLAG_STR_CONFORMANT.*")) { - $conform_e = $e; - } + $conform_e = $struct->{SURROUNDING_ELEMENT}; # declare any internal pointers we need foreach my $e (@{$struct->{ELEMENTS}}) { - if (Ndr::need_wire_pointer($e)) { - pidl "uint32_t _ptr_$e->{NAME};"; - } + DeclarePtrVariables($e); + DeclareArrayVariables($e); } start_flags($struct); - pidl "if (!(ndr_flags & NDR_SCALARS)) goto buffers;"; + pidl "if (ndr_flags & NDR_SCALARS) {"; + indent; pidl "NDR_CHECK(ndr_pull_struct_start(ndr));"; if (defined $conform_e) { - ParseArrayPullPreceding($conform_e, "r->", "NDR_SCALARS"); + ParseArrayPullPreceding($conform_e, $conform_e->{LEVELS}[0], "r->$conform_e->{NAME}"); } - my $align = Ndr::find_largest_alignment($struct); - pidl "NDR_CHECK(ndr_pull_align(ndr, $align));"; + pidl "NDR_CHECK(ndr_pull_align(ndr, $struct->{ALIGN}));"; foreach my $e (@{$struct->{ELEMENTS}}) { - ParseElementPullScalar($e, "r->", "NDR_SCALARS"); + ParseElementPull($e, "ndr", "r->", $env, 1, 0); } - pidl "buffers:\n"; - pidl "if (!(ndr_flags & NDR_BUFFERS)) goto done;"; - foreach my $e (@{$struct->{ELEMENTS}}) { - ParseElementPullBuffer($e, "r->"); - } - + deindent; + pidl "}"; + pidl "if (ndr_flags & NDR_BUFFERS) {"; + indent; foreach my $e (@{$struct->{ELEMENTS}}) { - CheckArraySizes($e, "r->"); + ParseElementPull($e, "ndr", "r->", $env, 0, 1); } pidl "ndr_pull_struct_end(ndr);"; - pidl "done:"; + deindent; + pidl "}"; end_flags($struct); } @@ -1317,7 +1454,6 @@ sub ParseStructPull($) sub ParseStructNdrSize($) { my $t = shift; - my $static = fn_prefix($t); my $sizevar; if (my $flags = util::has_property($t, "flag")) { @@ -1366,7 +1502,6 @@ $typefamily{STRUCT} = { sub ParseUnionNdrSize($) { my $t = shift; - my $static = fn_prefix($t); my $sizevar; if (my $flags = util::has_property($t, "flag")) { @@ -1378,23 +1513,24 @@ sub ParseUnionNdrSize($) ##################################################################### # parse a union - push side -sub ParseUnionPush($) +sub ParseUnionPush($$) { my $e = shift; + my $name = shift; my $have_default = 0; pidl "int level;"; + start_flags($e); pidl "level = ndr_push_get_switch_value(ndr, r);"; - pidl "if (!(ndr_flags & NDR_SCALARS)) goto buffers;"; + pidl "if (ndr_flags & NDR_SCALARS) {"; + indent; - if (!util::has_property($e, "nodiscriminant")) { - my $switch_type = util::has_property($e, "switch_type"); - $switch_type = "uint32" unless (defined ($switch_type)); - pidl "NDR_CHECK(ndr_push_$switch_type(ndr, NDR_SCALARS, level));"; + if (defined($e->{SWITCH_TYPE})) { + pidl "NDR_CHECK(ndr_push_$e->{SWITCH_TYPE}(ndr, NDR_SCALARS, level));"; } pidl "NDR_CHECK(ndr_push_struct_start(ndr));"; @@ -1405,16 +1541,15 @@ sub ParseUnionPush($) pidl "switch (level) {"; indent; foreach my $el (@{$e->{ELEMENTS}}) { - if (util::has_property($el, "default")) { - pidl "default:"; + if ($el->{CASE} eq "default") { $have_default = 1; - } else { - pidl "case $el->{PROPERTIES}->{case}:"; - } + pidl "$el->{CASE}:"; + if ($el->{TYPE} ne "EMPTY") { indent; - ParseElementPushScalar($el, "r->", "NDR_SCALARS"); + DeclareArrayVariables($el); + ParseElementPush($el, "ndr", "r->", {}, 1, 0); deindent; } pidl "break;"; @@ -1426,19 +1561,17 @@ sub ParseUnionPush($) } deindent; pidl "}"; - pidl "buffers:"; - pidl "if (!(ndr_flags & NDR_BUFFERS)) goto done;"; + deindent; + pidl "}"; + pidl "if (ndr_flags & NDR_BUFFERS) {"; + indent; pidl "switch (level) {"; indent; foreach my $el (@{$e->{ELEMENTS}}) { - if (util::has_property($el, "default")) { - pidl "default:"; - } else { - pidl "case $el->{PROPERTIES}->{case}:"; - } + pidl "$el->{CASE}:"; if ($el->{TYPE} ne "EMPTY") { indent; - ParseElementPushBuffer($el, "r->"); + ParseElementPush($el, "ndr", "r->", {}, 0, 1); deindent; } pidl "break;"; @@ -1451,35 +1584,38 @@ sub ParseUnionPush($) deindent; pidl "}"; pidl "ndr_push_struct_end(ndr);"; - pidl "done:"; + deindent; + pidl "}"; end_flags($e); } ##################################################################### # print a union -sub ParseUnionPrint($) +sub ParseUnionPrint($$) { my $e = shift; my $have_default = 0; - my($name) = $e->{PARENT}->{NAME}; + my $name = shift; pidl "int level = ndr_print_get_switch_value(ndr, r);"; + foreach my $el (@{$e->{ELEMENTS}}) { + DeclareArrayVariables($el); + } + pidl "ndr_print_union(ndr, name, level, \"$name\");"; start_flags($e); pidl "switch (level) {"; indent; foreach my $el (@{$e->{ELEMENTS}}) { - if (util::has_property($el, "default")) { + if ($el->{CASE} eq "default") { $have_default = 1; - pidl "default:"; - } else { - pidl "case $el->{PROPERTIES}->{case}:"; } + pidl "$el->{CASE}:"; if ($el->{TYPE} ne "EMPTY") { indent; - ParseElementPrint($el, "r->"); + ParseElementPrint($el, "r->$el->{NAME}", {}); deindent; } pidl "break;"; @@ -1497,31 +1633,32 @@ sub ParseUnionPrint($) ##################################################################### # parse a union - pull side -sub ParseUnionPull($) +sub ParseUnionPull($$) { my $e = shift; + my $name = shift; my $have_default = 0; - my $switch_type = util::has_property($e, "switch_type"); - $switch_type = "uint32" unless defined($switch_type); + my $switch_type = $e->{SWITCH_TYPE}; pidl "int level;"; - if (!util::has_property($e, "nodiscriminant")) { + if (defined($switch_type)) { if (typelist::typeIs($switch_type, "ENUM")) { $switch_type = typelist::enum_type_fn(typelist::getType($switch_type)); } - pidl typelist::mapScalarType($switch_type) . " _level;"; + pidl typelist::mapType($switch_type) . " _level;"; } start_flags($e); pidl "level = ndr_pull_get_switch_value(ndr, r);"; - pidl "if (!(ndr_flags & NDR_SCALARS)) goto buffers;"; + pidl "if (ndr_flags & NDR_SCALARS) {"; + indent; - if (!util::has_property($e, "nodiscriminant")) { + 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 $e->{PARENT}->{NAME}\", _level);"; + pidl "\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value %u for $name\", _level);"; pidl "}"; } @@ -1533,18 +1670,16 @@ sub ParseUnionPull($) pidl "switch (level) {"; indent; foreach my $el (@{$e->{ELEMENTS}}) { - if (util::has_property($el, "default")) { - pidl "default: {"; + if ($el->{CASE} eq "default") { $have_default = 1; - } else { - pidl "case $el->{PROPERTIES}->{case}: {"; - } + } + pidl "$el->{CASE}: {"; + if ($el->{TYPE} ne "EMPTY") { indent; - if ($el->{POINTERS}) { - pidl "uint32_t _ptr_$el->{NAME};"; - } - ParseElementPullScalar($el, "r->", "NDR_SCALARS"); + DeclarePtrVariables($el); + DeclareArrayVariables($el); + ParseElementPull($el, "ndr", "r->", {}, 1, 0); deindent; } pidl "break; }"; @@ -1556,19 +1691,17 @@ sub ParseUnionPull($) } deindent; pidl "}"; - pidl "buffers:"; - pidl "if (!(ndr_flags & NDR_BUFFERS)) goto done;"; + deindent; + pidl "}"; + pidl "if (ndr_flags & NDR_BUFFERS) {"; + indent; pidl "switch (level) {"; indent; foreach my $el (@{$e->{ELEMENTS}}) { - if (util::has_property($el, "default")) { - pidl "default:"; - } else { - pidl "case $el->{PROPERTIES}->{case}:"; - } + pidl "$el->{CASE}:"; if ($el->{TYPE} ne "EMPTY") { indent; - ParseElementPullBuffer($el, "r->"); + ParseElementPull($el, "ndr", "r->", {}, 0, 1); deindent; } pidl "break;"; @@ -1581,7 +1714,8 @@ sub ParseUnionPull($) deindent; pidl "}"; pidl "ndr_pull_struct_end(ndr);"; - pidl "done:"; + deindent; + pidl "}"; end_flags($e); } @@ -1625,39 +1759,32 @@ $typefamily{UNION} = { sub ParseTypedefPush($) { my($e) = shift; - my $static = fn_prefix($e); - - return unless needed::is_needed("push_$e->{NAME}"); my $args = $typefamily{$e->{DATA}->{TYPE}}->{PUSH_FN_ARGS}->($e); - pidl $static . "NTSTATUS ndr_push_$e->{NAME}($args)"; + pidl fn_prefix($e) . "NTSTATUS ndr_push_$e->{NAME}($args)"; pidl "{"; indent; - $typefamily{$e->{DATA}->{TYPE}}->{PUSH_FN_BODY}->($e->{DATA}); + $typefamily{$e->{DATA}->{TYPE}}->{PUSH_FN_BODY}->($e->{DATA}, $e->{NAME}); pidl "return NT_STATUS_OK;"; deindent; pidl "}"; pidl "";; } - ##################################################################### # parse a typedef - pull side sub ParseTypedefPull($) { my($e) = shift; - my $static = fn_prefix($e); - - return unless needed::is_needed("pull_$e->{NAME}"); my $args = $typefamily{$e->{DATA}->{TYPE}}->{PULL_FN_ARGS}->($e); - pidl $static . "NTSTATUS ndr_pull_$e->{NAME}($args)"; + pidl fn_prefix($e) . "NTSTATUS ndr_pull_$e->{NAME}($args)"; pidl "{"; indent; - $typefamily{$e->{DATA}->{TYPE}}->{PULL_FN_BODY}->($e->{DATA}); + $typefamily{$e->{DATA}->{TYPE}}->{PULL_FN_BODY}->($e->{DATA}, $e->{NAME}); pidl "return NT_STATUS_OK;"; deindent; pidl "}"; @@ -1672,12 +1799,10 @@ sub ParseTypedefPrint($) my $args = $typefamily{$e->{DATA}->{TYPE}}->{PRINT_FN_ARGS}->($e); - return unless !util::has_property($e, "noprint"); - pidl "void ndr_print_$e->{NAME}($args)"; pidl "{"; indent; - $typefamily{$e->{DATA}->{TYPE}}->{PRINT_FN_BODY}->($e->{DATA}); + $typefamily{$e->{DATA}->{TYPE}}->{PRINT_FN_BODY}->($e->{DATA}, $e->{NAME}); deindent; pidl "}"; pidl ""; @@ -1689,8 +1814,6 @@ sub ParseTypedefNdrSize($) { my($t) = shift; - return unless needed::is_needed("ndr_size_$t->{NAME}"); - my $tf = $typefamily{$t->{DATA}->{TYPE}}; my $args = $tf->{SIZE_FN_ARGS}->($t); @@ -1709,11 +1832,18 @@ sub ParseFunctionPrint($) { my($fn) = shift; - return unless !util::has_property($fn, "noprint"); + return if util::has_property($fn, "noprint"); + + my $env = GenerateFunctionEnv($fn); pidl "void ndr_print_$fn->{NAME}(struct ndr_print *ndr, const char *name, int flags, struct $fn->{NAME} *r)"; pidl "{"; indent; + + foreach my $e (@{$fn->{ELEMENTS}}) { + DeclareArrayVariables($e); + } + pidl "ndr_print_struct(ndr, name, \"$fn->{NAME}\");"; pidl "ndr->depth++;"; @@ -1727,8 +1857,8 @@ sub ParseFunctionPrint($) pidl "ndr->depth++;"; foreach my $e (@{$fn->{ELEMENTS}}) { - if (util::has_property($e, "in")) { - ParseElementPrint($e, "r->in."); + if (grep(/in/,@{$e->{DIRECTION}})) { + ParseElementPrint($e, "r->in.$e->{NAME}", $env); } } pidl "ndr->depth--;"; @@ -1740,14 +1870,12 @@ sub ParseFunctionPrint($) pidl "ndr_print_struct(ndr, \"out\", \"$fn->{NAME}\");"; pidl "ndr->depth++;"; foreach my $e (@{$fn->{ELEMENTS}}) { - if (util::has_property($e, "out")) { - ParseElementPrint($e, "r->out."); + if (grep(/out/,@{$e->{DIRECTION}})) { + ParseElementPrint($e, "r->out.$e->{NAME}", $env); } } - if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") { - my $cprefix = "&"; - $cprefix = "" if (Ndr::is_scalar_type($fn->{RETURN_TYPE})) ; # FIXME: Should really use util::c_push_prefix here - pidl "ndr_print_$fn->{RETURN_TYPE}(ndr, \"result\", $cprefix"."r->out.result);"; + if ($fn->{RETURN_TYPE}) { + pidl "ndr_print_$fn->{RETURN_TYPE}(ndr, \"result\", r->out.result);"; } pidl "ndr->depth--;"; deindent; @@ -1760,152 +1888,81 @@ sub ParseFunctionPrint($) } ##################################################################### -# parse a function element -sub ParseFunctionElementPush($$) -{ - my $e = shift; - my $inout = shift; - - if (util::array_size($e)) { - if (Ndr::need_wire_pointer($e)) { - ParsePtrPush($e, "r->$inout."); - pidl "if (r->$inout.$e->{NAME}) {"; - indent; - ParseArrayPush($e, "ndr", "r->$inout.", "NDR_SCALARS|NDR_BUFFERS"); - deindent; - pidl "}"; - } else { - ParseArrayPush($e, "ndr", "r->$inout.", "NDR_SCALARS|NDR_BUFFERS"); - } - } else { - ParseElementPushScalar($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS"); - if (Ndr::need_wire_pointer($e)) { - ParseElementPushBuffer($e, "r->$inout."); - } - } -} - -##################################################################### # parse a function sub ParseFunctionPush($) { my($fn) = shift; - my $static = fn_prefix($fn); - return unless !util::has_property($fn, "nopush"); + return if util::has_property($fn, "nopush"); + + my $env = GenerateFunctionEnv($fn); - pidl $static . "NTSTATUS ndr_push_$fn->{NAME}(struct ndr_push *ndr, int flags, struct $fn->{NAME} *r)"; + pidl fn_prefix($fn) . "NTSTATUS ndr_push_$fn->{NAME}(struct ndr_push *ndr, int flags, struct $fn->{NAME} *r)"; pidl "{"; indent; - pidl "if (!(flags & NDR_IN)) goto ndr_out;"; - pidl ""; + foreach my $e (@{$fn->{ELEMENTS}}) { + DeclareArrayVariables($e); + } + + pidl "if (flags & NDR_IN) {"; + indent; foreach my $e (@{$fn->{ELEMENTS}}) { - if (util::has_property($e, "in")) { - if (util::has_property($e, "ref")) { - check_null_pointer("*r->in.$e->{NAME}"); - } - ParseFunctionElementPush($e, "in"); - } + if (grep(/in/,@{$e->{DIRECTION}})) { + ParseElementPush($e, "ndr", "r->in.", $env, 1, 1); + } } - pidl "ndr_out:"; - pidl "if (!(flags & NDR_OUT)) goto done;"; - pidl ""; + deindent; + pidl "}"; + + pidl "if (flags & NDR_OUT) {"; + indent; foreach my $e (@{$fn->{ELEMENTS}}) { - if (util::has_property($e, "out")) { - if (util::has_property($e, "ref")) { - check_null_pointer("*r->out.$e->{NAME}"); - } - ParseFunctionElementPush($e, "out"); - } + if (grep(/out/,@{$e->{DIRECTION}})) { + ParseElementPush($e, "ndr", "r->out.", $env, 1, 1); + } } - if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") { + if ($fn->{RETURN_TYPE}) { pidl "NDR_CHECK(ndr_push_$fn->{RETURN_TYPE}(ndr, NDR_SCALARS, r->out.result));"; } - pidl "done:"; + deindent; + pidl "}"; pidl "return NT_STATUS_OK;"; deindent; pidl "}"; pidl ""; } -##################################################################### -# parse a function element -sub ParseFunctionElementPull($$) -{ - my $e = shift; - my $inout = shift; - - if (util::array_size($e)) { - if (Ndr::need_wire_pointer($e)) { - pidl "NDR_CHECK(ndr_pull_unique_ptr(ndr, &_ptr_$e->{NAME}));"; - pidl "r->$inout.$e->{NAME} = NULL;"; - pidl "if (_ptr_$e->{NAME}) {"; - indent; - } elsif ($inout eq "out" && util::has_property($e, "ref")) { - pidl "if (r->$inout.$e->{NAME}) {"; - indent; - } - - ParseArrayPull($e, "ndr", "r->$inout.", "NDR_SCALARS|NDR_BUFFERS"); - - if (Ndr::need_wire_pointer($e) or ($inout eq "out" and util::has_property($e, "ref"))) { - deindent; - pidl "}"; - } - } else { - if ($inout eq "out" && util::has_property($e, "ref")) { - pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {"; - pidl "\tNDR_ALLOC(ndr, r->out.$e->{NAME});"; - pidl "}"; - } - - if ($inout eq "in" && util::has_property($e, "ref")) { - pidl "NDR_ALLOC(ndr, r->in.$e->{NAME});"; - } - - ParseElementPullScalar($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS"); - if (Ndr::need_wire_pointer($e)) { - ParseElementPullBuffer($e, "r->$inout."); - } - } -} - -############################################################ -# allocate ref variables -sub AllocateRefVars($) +sub AllocateArrayLevel($$$$$) { my $e = shift; - my $asize = util::array_size($e); + my $l = shift; + my $ndr = shift; + my $env = shift; + my $size = shift; - # note that if the variable is also an "in" - # variable then we copy the initial value from - # the in side + my $var = ParseExpr($e->{NAME}, $env); - if (!defined $asize) { - # its a simple variable - pidl "NDR_ALLOC(ndr, r->out.$e->{NAME});"; - if (util::has_property($e, "in")) { - pidl "*r->out.$e->{NAME} = *r->in.$e->{NAME};"; - } else { - pidl "ZERO_STRUCTP(r->out.$e->{NAME});"; - } - return; - } - - # its an array - my $size = ParseExpr($e, $asize, "r->out."); check_null_pointer($size); - pidl "NDR_ALLOC_N(ndr, r->out.$e->{NAME}, $size);"; - if (util::has_property($e, "in")) { - pidl "memcpy(r->out.$e->{NAME},r->in.$e->{NAME},$size * sizeof(*r->in.$e->{NAME}));"; + my $pl = Ndr::GetPrevLevel($e, $l); + if (defined($pl) and + $pl->{TYPE} eq "POINTER" and + $pl->{POINTER_TYPE} eq "ref") { + pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {"; + pidl "\tNDR_ALLOC_N($ndr, $var, $size);"; + pidl "}"; } else { - pidl "memset(r->out.$e->{NAME}, 0, $size * sizeof(*r->out.$e->{NAME}));"; + pidl "NDR_ALLOC_N($ndr, $var, $size);"; + } + #pidl "memset($var, 0, $size * sizeof(" . $var . "[0]));"; + 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}));"; } } @@ -1914,76 +1971,89 @@ sub AllocateRefVars($) sub ParseFunctionPull($) { my($fn) = shift; - my $static = fn_prefix($fn); - return unless !util::has_property($fn, "nopull"); + return if util::has_property($fn, "nopull"); + + my $env = GenerateFunctionEnv($fn); # pull function args - pidl $static . "NTSTATUS ndr_pull_$fn->{NAME}(struct ndr_pull *ndr, int flags, struct $fn->{NAME} *r)"; + pidl fn_prefix($fn) . "NTSTATUS ndr_pull_$fn->{NAME}(struct ndr_pull *ndr, int flags, struct $fn->{NAME} *r)"; pidl "{"; indent; # declare any internal pointers we need - foreach my $e (@{$fn->{ELEMENTS}}) { - if (Ndr::need_wire_pointer($e)) { - pidl "uint32_t _ptr_$e->{NAME};"; - } + foreach my $e (@{$fn->{ELEMENTS}}) { + DeclarePtrVariables($e); + DeclareArrayVariables($e); } - pidl "if (!(flags & NDR_IN)) goto ndr_out;"; - pidl ""; + pidl "if (flags & NDR_IN) {"; + indent; # auto-init the out section of a structure. I originally argued that # this was a bad idea as it hides bugs, but coping correctly # with initialisation and not wiping ref vars is turning # out to be too tricky (tridge) foreach my $e (@{$fn->{ELEMENTS}}) { - if (util::has_property($e, "out")) { - pidl "ZERO_STRUCT(r->out);"; - pidl ""; - last; - } + next unless grep(/out/, @{$e->{DIRECTION}}); + pidl "ZERO_STRUCT(r->out);"; + pidl ""; + last; } foreach my $e (@{$fn->{ELEMENTS}}) { - if (util::has_property($e, "in")) { - ParseFunctionElementPull($e, "in"); - } - # we need to allocate any reference output variables, so that - # a dcerpc backend can be sure they are non-null - if (util::has_property($e, "out") && util::has_property($e, "ref")) { - AllocateRefVars($e); - } + next unless (grep(/in/, @{$e->{DIRECTION}})); + ParseElementPull($e, "ndr", "r->in.", $env, 1, 1); } + # allocate the "simple" out ref variables. FIXME: Shouldn't this have it's + # own flag rather then be in NDR_IN ? + foreach my $e (@{$fn->{ELEMENTS}}) { - if (util::has_property($e, "in")) { - CheckArraySizes($e, "r->in."); - } - } + next unless (grep(/out/, @{$e->{DIRECTION}})); + next unless ($e->{LEVELS}[0]->{TYPE} eq "POINTER" and + $e->{LEVELS}[0]->{POINTER_TYPE} eq "ref"); - pidl "ndr_out:"; - pidl "if (!(flags & NDR_OUT)) goto done;"; - pidl ""; - foreach my $e (@{$fn->{ELEMENTS}}) { - if (util::has_property($e, "out")) { - ParseFunctionElementPull($e, "out"); + if ($e->{LEVELS}[1]->{TYPE} eq "ARRAY") { + my $size = ParseExpr($e->{LEVELS}[1]->{SIZE_IS}, $env); + check_null_pointer($size); + + pidl "NDR_ALLOC_N(ndr, r->out.$e->{NAME}, $size);"; + + if (grep(/in/, @{$e->{DIRECTION}})) { + pidl "memcpy(r->out.$e->{NAME}, r->in.$e->{NAME}, $size * sizeof(*r->in.$e->{NAME}));"; + } else { + pidl "memset(r->out.$e->{NAME}, 0, $size * sizeof(*r->out.$e->{NAME}));"; + } + } else { + pidl "NDR_ALLOC(ndr, r->out.$e->{NAME});"; + + if (grep(/in/, @{$e->{DIRECTION}})) { + pidl "*r->out.$e->{NAME} = *r->in.$e->{NAME};"; + } else { + pidl "ZERO_STRUCTP(r->out.$e->{NAME});"; + } } } + deindent; + pidl "}"; + + pidl "if (flags & NDR_OUT) {"; + indent; + foreach my $e (@{$fn->{ELEMENTS}}) { - if (util::has_property($e, "out")) { - CheckArraySizes($e, "r->out."); - } + next unless grep(/out/, @{$e->{DIRECTION}}); + ParseElementPull($e, "ndr", "r->out.", $env, 1, 1); } - if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") { + if ($fn->{RETURN_TYPE}) { pidl "NDR_CHECK(ndr_pull_$fn->{RETURN_TYPE}(ndr, NDR_SCALARS, &r->out.result));"; } - pidl "done:"; - pidl ""; + deindent; + pidl "}"; pidl "return NT_STATUS_OK;"; deindent; pidl "}"; @@ -1995,44 +2065,33 @@ sub ParseFunctionPull($) sub FunctionTable($) { my($interface) = shift; - my($data) = $interface->{INHERITED_DATA}; my $count = 0; my $uname = uc $interface->{NAME}; - foreach my $d (@{$data}) { - if ($d->{TYPE} eq "FUNCTION") { $count++; } - } + $count = $#{$interface->{FUNCTIONS}}+1; return if ($count == 0); pidl "static const struct dcerpc_interface_call $interface->{NAME}\_calls[] = {"; - foreach my $d (@{$data}) { - if ($d->{TYPE} eq "FUNCTION") { - pidl "\t{"; - pidl "\t\t\"$d->{NAME}\","; - pidl "\t\tsizeof(struct $d->{NAME}),"; - pidl "\t\t(ndr_push_flags_fn_t) ndr_push_$d->{NAME},"; - pidl "\t\t(ndr_pull_flags_fn_t) ndr_pull_$d->{NAME},"; - pidl "\t\t(ndr_print_function_t) ndr_print_$d->{NAME}"; - pidl "\t},"; - } + foreach my $d (@{$interface->{FUNCTIONS}}) { + pidl "\t{"; + pidl "\t\t\"$d->{NAME}\","; + pidl "\t\tsizeof(struct $d->{NAME}),"; + pidl "\t\t(ndr_push_flags_fn_t) ndr_push_$d->{NAME},"; + pidl "\t\t(ndr_pull_flags_fn_t) ndr_pull_$d->{NAME},"; + pidl "\t\t(ndr_print_function_t) ndr_print_$d->{NAME}"; + pidl "\t},"; } pidl "\t{ NULL, 0, NULL, NULL, NULL }"; pidl "};"; pidl ""; - # If no endpoint is set, default to the interface name as a named pipe - if (! defined $interface->{PROPERTIES}->{endpoint}) { - $interface->{PROPERTIES}->{endpoint} = "\"ncacn_np:[\\\\pipe\\\\" . $interface->{NAME} . "]\""; - } - - my @e = split / /, $interface->{PROPERTIES}->{endpoint}; - my $endpoint_count = $#e + 1; - pidl "static const char * const $interface->{NAME}\_endpoint_strings[] = {"; - foreach my $ep (@e) { + foreach my $ep (@{$interface->{ENDPOINTS}}) { pidl "\t$ep, "; } + my $endpoint_count = $#{$interface->{ENDPOINTS}}+1; + pidl "};"; pidl ""; @@ -2083,27 +2142,33 @@ sub FunctionTable($) ##################################################################### # parse the interface definitions -sub ParseInterface($) +sub ParseInterface($$) { my($interface) = shift; - my($data) = $interface->{DATA}; - - # Push functions - foreach my $d (@{$data}) { - if ($d->{TYPE} eq "TYPEDEF") { - ParseTypedefPush($d); - ParseTypedefPull($d); - ParseTypedefPrint($d); - ParseTypedefNdrSize($d); - } + my $needed = shift; + + # Typedefs + foreach my $d (@{$interface->{TYPEDEFS}}) { + ($needed->{"push_$d->{NAME}"}) && ParseTypedefPush($d); + ($needed->{"pull_$d->{NAME}"}) && ParseTypedefPull($d); + ($needed->{"print_$d->{NAME}"}) && ParseTypedefPrint($d); + + # Make sure we don't generate a function twice... + $needed->{"push_$d->{NAME}"} = $needed->{"pull_$d->{NAME}"} = + $needed->{"print_$d->{NAME}"} = 0; + + ($needed->{"ndr_size_$d->{NAME}"}) && ParseTypedefNdrSize($d); } - foreach my $d (@{$data}) { - if ($d->{TYPE} eq "FUNCTION") { - ParseFunctionPush($d); - ParseFunctionPull($d); - ParseFunctionPrint($d); - } + # Functions + foreach my $d (@{$interface->{FUNCTIONS}}) { + ($needed->{"push_$d->{NAME}"}) && ParseFunctionPush($d); + ($needed->{"pull_$d->{NAME}"}) && ParseFunctionPull($d); + ($needed->{"print_$d->{NAME}"}) && ParseFunctionPrint($d); + + # Make sure we don't generate a function twice... + $needed->{"push_$d->{NAME}"} = $needed->{"pull_$d->{NAME}"} = + $needed->{"print_$d->{NAME}"} = 0; } FunctionTable($interface); @@ -2123,11 +2188,7 @@ sub RegistrationFunction($$) foreach my $interface (@{$idl}) { next if $interface->{TYPE} ne "INTERFACE"; - my $data = $interface->{INHERITED_DATA}; - my $count = 0; - foreach my $d (@{$data}) { - if ($d->{TYPE} eq "FUNCTION") { $count++; } - } + my $count = ($#{$interface->{FUNCTIONS}}+1); next if ($count == 0); @@ -2143,92 +2204,108 @@ sub RegistrationFunction($$) pidl ""; } -sub CheckPointerTypes($$) +##################################################################### +# parse a parsed IDL structure back into an IDL file +sub Parse($$) { - my $s = shift; - my $default = shift; + my($ndr) = shift; + my($filename) = shift; - foreach my $e (@{$s->{ELEMENTS}}) { - if ($e->{POINTERS}) { - if (not defined(Ndr::pointer_type($e))) { - $e->{PROPERTIES}->{$default} = 1; - } + $tabs = ""; + my $h_filename = $filename; + $res = ""; - if (Ndr::pointer_type($e) eq "ptr") { - print "Warning: ptr is not supported by pidl yet\n"; - } - } + if ($h_filename =~ /(.*)\.c/) { + $h_filename = "$1.h"; } -} -sub LoadInterface($) -{ - my $x = shift; + pidl "/* parser auto-generated by pidl */"; + pidl ""; + pidl "#include \"includes.h\""; + pidl "#include \"$h_filename\""; + pidl ""; + + my %needed = (); - if (not util::has_property($x, "pointer_default")) { - # MIDL defaults to "ptr" in DCE compatible mode (/osf) - # and "unique" in Microsoft Extensions mode (default) - $x->{PROPERTIES}->{pointer_default} = "unique"; + foreach my $x (@{$ndr}) { + ($x->{TYPE} eq "INTERFACE") && NeededInterface($x, \%needed); } - foreach my $d (@{$x->{DATA}}) { - if (($d->{TYPE} eq "DECLARE") or ($d->{TYPE} eq "TYPEDEF")) { - if ($d->{DATA}->{TYPE} eq "STRUCT" or $d->{DATA}->{TYPE} eq "UNION") { - CheckPointerTypes($d->{DATA}, $x->{PROPERTIES}->{pointer_default}); - } + foreach my $x (@{$ndr}) { + ($x->{TYPE} eq "INTERFACE") && ParseInterface($x, \%needed); + } - if (defined($d->{PROPERTIES}) && !defined($d->{DATA}->{PROPERTIES})) { - $d->{DATA}->{PROPERTIES} = $d->{PROPERTIES}; - } + RegistrationFunction($ndr, $filename); + + return $res; +} + +sub NeededFunction($$) +{ + my $fn = shift; + my $needed = shift; + $needed->{"pull_$fn->{NAME}"} = 1; + $needed->{"push_$fn->{NAME}"} = 1; + $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; } - if ($d->{TYPE} eq "FUNCTION") { - CheckPointerTypes($d, - $x->{PROPERTIES}->{pointer_default} # MIDL defaults to "ref" - ); + unless(defined($needed->{"print_$e->{TYPE}"})) { + $needed->{"print_$e->{TYPE}"} = 1; } } } -sub Load($) +sub NeededTypedef($$) { - my $idl = shift; + my $t = shift; + my $needed = shift; + if (util::has_property($t, "public")) { + $needed->{"pull_$t->{NAME}"} = not util::has_property($t, "nopull"); + $needed->{"push_$t->{NAME}"} = not util::has_property($t, "nopush"); + $needed->{"print_$t->{NAME}"} = not util::has_property($t, "noprint"); + } - foreach my $x (@{$idl}) { - LoadInterface($x); + if ($t->{DATA}->{TYPE} eq "STRUCT" or $t->{DATA}->{TYPE} eq "UNION") { + if (util::has_property($t, "gensize")) { + $needed->{"ndr_size_$t->{NAME}"} = 1; + } + + for my $e (@{$t->{DATA}->{ELEMENTS}}) { + $e->{PARENT} = $t->{DATA}; + 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; + } + } } } ##################################################################### -# parse a parsed IDL structure back into an IDL file -sub Parse($$) +# work out what parse functions are needed +sub NeededInterface($$) { - my($idl) = shift; - my($filename) = shift; - my $h_filename = $filename; - $res = ""; - - Load($idl); - - if ($h_filename =~ /(.*)\.c/) { - $h_filename = "$1.h"; + my ($interface) = shift; + my $needed = shift; + foreach my $d (@{$interface->{FUNCTIONS}}) { + NeededFunction($d, $needed); } - - pidl "/* parser auto-generated by pidl */"; - pidl ""; - pidl "#include \"includes.h\""; - pidl "#include \"$h_filename\""; - pidl ""; - - foreach my $x (@{$idl}) { - if ($x->{TYPE} eq "INTERFACE") { - needed::BuildNeeded($x); - ParseInterface($x); - } + foreach my $d (reverse @{$interface->{TYPEDEFS}}) { + NeededTypedef($d, $needed); } - - RegistrationFunction($idl, $filename); - - return $res; } 1; diff --git a/source4/build/pidl/needed.pm b/source4/build/pidl/needed.pm deleted file mode 100644 index ae8bf7f078..0000000000 --- a/source4/build/pidl/needed.pm +++ /dev/null @@ -1,80 +0,0 @@ -################################################### -# Samba4 parser generator for IDL structures -# Copyright tridge@samba.org 2000-2004 -# Copyright jelmer@samba.org 2004 -# released under the GNU GPL - -package needed; - -use strict; - -# the list of needed functions -my %needed; - -sub NeededFunction($) -{ - my $fn = shift; - $needed{"pull_$fn->{NAME}"} = 1; - $needed{"push_$fn->{NAME}"} = 1; - foreach my $e (@{$fn->{ELEMENTS}}) { - $e->{PARENT} = $fn; - $needed{"pull_$e->{TYPE}"} = 1; - $needed{"push_$e->{TYPE}"} = 1; - } -} - -sub NeededTypedef($) -{ - my $t = shift; - if (util::has_property($t, "public")) { - $needed{"pull_$t->{NAME}"} = 1; - $needed{"push_$t->{NAME}"} = 1; - } - - if (util::has_property($t, "nopull")) { - $needed{"pull_$t->{NAME}"} = 0; - } - if (util::has_property($t, "nopush")) { - $needed{"push_$t->{NAME}"} = 0; - } - - if ($t->{DATA}->{TYPE} eq "STRUCT" or $t->{DATA}->{TYPE} eq "UNION") { - if (util::has_property($t, "gensize")) { - $needed{"ndr_size_$t->{NAME}"} = 1; - } - - 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; - } - } - } -} - -##################################################################### -# 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); - } -} - -sub is_needed($) -{ - my $name = shift; - return $needed{$name}; -} - -1; diff --git a/source4/build/pidl/odl.pm b/source4/build/pidl/odl.pm index 95e81c07ce..5ed508dc93 100644 --- a/source4/build/pidl/odl.pm +++ b/source4/build/pidl/odl.pm @@ -43,12 +43,29 @@ sub ODL2IDL($) foreach my $x (@{$odl}) { # Add [in] ORPCTHIS *this, [out] ORPCTHAT *that + # and replace interfacepointers with MInterfacePointer # for 'object' interfaces if (util::has_property($x, "object")) { foreach my $e (@{$x->{DATA}}) { ($e->{TYPE} eq "FUNCTION") && FunctionAddObjArgs($e); ReplaceInterfacePointers($e); } + # Object interfaces use ORPC + my @depends = (); + if(util::has_property($x, "depends")) { + @depends = split /,/, $x->{PROPERTIES}->{depends}; + } + push @depends, "orpc"; + $x->{PROPERTIES}->{depends} = join(',',@depends); + } + + if ($x->{BASE}) { + my $base = util::get_interface($odl, $x->{BASE}); + + foreach my $fn (reverse @{$base->{DATA}}) { + next unless ($fn->{TYPE} eq "FUNCTION"); + unshift (@{$x->{DATA}}, $fn); + } } } diff --git a/source4/build/pidl/pidl.pl b/source4/build/pidl/pidl.pl index 2305d9243b..c7b98a0d34 100755 --- a/source4/build/pidl/pidl.pl +++ b/source4/build/pidl/pidl.pl @@ -14,9 +14,9 @@ use lib "$RealBin"; use lib "$RealBin/lib"; use Getopt::Long; use File::Basename; +use idl; use dump; use ndr_client; -use idl; use ndr_header; use ndr_parser; use server; @@ -24,12 +24,14 @@ use dcom_proxy; use dcom_stub; use com_header; use odl; -use eparser; +use eth_parser; +use eth_header; use validator; use typelist; use util; use template; use swig; +use compat; my($opt_help) = 0; my($opt_parse) = 0; @@ -40,7 +42,8 @@ my($opt_template) = 0; my($opt_client) = 0; my($opt_server) = 0; my($opt_parser); -my($opt_eparser) = 0; +my($opt_eth_parser); +my($opt_eth_header); my($opt_keep) = 0; my($opt_swig) = 0; my($opt_dcom_proxy) = 0; @@ -48,6 +51,7 @@ my($opt_com_header) = 0; my($opt_odl) = 0; my($opt_quiet) = 0; my($opt_output); +my($opt_warn_compat) = 0; my $idl_parser = new idl; @@ -71,13 +75,15 @@ sub ShowHelp() --client create a C NDR client --server create server boilerplate --template print a template for a pipe - --eparser create an ethereal parser + --eth-parser create an ethereal parser + --eth-header create an ethereal header file --swig create swig wrapper file --diff run diff on the idl and dumped output --keep keep the .pidl file --odl accept ODL input --dcom-proxy create DCOM proxy (implies --odl) --com-header create header for COM interfaces (implies --odl) + --warn-compat warn about incompatibility with other compilers --quiet be quiet \n"; exit(0); @@ -94,14 +100,16 @@ GetOptions ( 'template' => \$opt_template, 'parser:s' => \$opt_parser, 'client' => \$opt_client, - 'eparser' => \$opt_eparser, + 'eth-parser:s' => \$opt_eth_parser, + 'eth-header:s' => \$opt_eth_header, 'diff' => \$opt_diff, 'odl' => \$opt_odl, 'keep' => \$opt_keep, 'swig' => \$opt_swig, 'dcom-proxy' => \$opt_dcom_proxy, 'com-header' => \$opt_com_header, - 'quiet' => \$opt_quiet + 'quiet' => \$opt_quiet, + 'warn-compat' => \$opt_warn_compat ); if ($opt_help) { @@ -114,6 +122,7 @@ sub process_file($) my $idl_file = shift; my $output; my $pidl; + my $ndr; my $basename = basename($idl_file, ".idl"); @@ -175,21 +184,25 @@ sub process_file($) $opt_odl = 1; } + if ($opt_warn_compat) { + IDLCompat::Check($pidl); + } + if ($opt_odl) { $pidl = ODL::ODL2IDL($pidl); } + if (defined($opt_header) or defined($opt_eth_parser) or defined($opt_eth_header) or $opt_client or $opt_server or defined($opt_parser)) { + $ndr = Ndr::Parse($pidl); +# print util::MyDumper($ndr); + } + if (defined($opt_header)) { my $header = $opt_header; if ($header eq "") { $header = util::ChangeExtension($output, ".h"); } - - util::FileSave($header, NdrHeader::Parse($pidl)); - if ($opt_eparser) { - my($eparserhdr) = dirname($output) . "/packet-dcerpc-$basename.h"; - IdlEParser::RewriteHeader($pidl, $header, $eparserhdr); - } + util::FileSave($header, NdrHeader::Parse($ndr)); if ($opt_swig) { my($filename) = $output; $filename =~ s/\/ndr_/\//; @@ -198,6 +211,15 @@ sub process_file($) } } + if (defined($opt_eth_header)) { + my($eparserhdr) = $opt_eth_header; + if ($eparserhdr eq "") { + $eparserhdr = dirname($output) . "/packet-dcerpc-$basename.h"; + } + + util::FileSave($eparserhdr, EthHeader::Parse($ndr)); + } + if ($opt_client) { my ($client) = util::ChangeExtension($output, "_c.c"); my $res = ""; @@ -250,13 +272,19 @@ $dcom if ($parser eq "") { $parser = util::ChangeExtension($output, ".c"); } - util::FileSave($parser, NdrParser::Parse($pidl, $parser)); - if($opt_eparser) { - my($eparser) = dirname($output) . "/packet-dcerpc-$basename.c"; - IdlEParser::RewriteC($pidl, $parser, $eparser); - } + + util::FileSave($parser, NdrParser::Parse($ndr, $parser)); } + if (defined($opt_eth_parser)) { + my($eparser) = $opt_eth_parser; + if ($eparser eq "") { + $eparser = dirname($output) . "/packet-dcerpc-$basename.c"; + } + util::FileSave($eparser, EthParser::Parse($ndr, $basename, $eparser)); + } + + if ($opt_template) { print IdlTemplate::Parse($pidl); } diff --git a/source4/build/pidl/test.pm b/source4/build/pidl/test.pm index 920db52aa5..5f25d4195c 100644 --- a/source4/build/pidl/test.pm +++ b/source4/build/pidl/test.pm @@ -87,7 +87,7 @@ sub link_files($$) { my ($exe_name,$objs) = @_; - return system($cc, @ldflags, '-Lbin', '-o', $exe_name, @$objs, '-lrpc', '-ldl', '-lldap'); + return system($cc, @ldflags, '-Lbin', '-lrpc', '-o', $exe_name, @$objs); } sub test_idl($$$$) diff --git a/source4/build/pidl/typelist.pm b/source4/build/pidl/typelist.pm index 8559878a69..f5a0650006 100644 --- a/source4/build/pidl/typelist.pm +++ b/source4/build/pidl/typelist.pm @@ -9,147 +9,6 @@ use strict; my %typedefs = (); -# a list of known scalar types -my $scalars = { - # 0 byte types - "void" => { - C_TYPE => "void", - NDR_ALIGN => 0 - }, - - # 1 byte types - "char" => { - C_TYPE => "char", - NDR_ALIGN => 1 - }, - "int8" => { - C_TYPE => "int8_t", - NDR_ALIGN => 1 - }, - "uint8" => { - C_TYPE => "uint8_t", - NDR_ALIGN => 1 - }, - - # 2 byte types - "int16" => { - C_TYPE => "int16_t", - NDR_ALIGN => 2 - }, - "uint16" => { C_TYPE => "uint16_t", - NDR_ALIGN => 2 - }, - - # 4 byte types - "int32" => { - C_TYPE => "int32_t", - NDR_ALIGN => 4 - }, - "uint32" => { C_TYPE => "uint32_t", - NDR_ALIGN => 4 - }, - - # 8 byte types - "int64" => { - C_TYPE => "int64_t", - NDR_ALIGN => 8 - }, - "hyper" => { - C_TYPE => "uint64_t", - NDR_ALIGN => 8 - }, - "dlong" => { - C_TYPE => "int64_t", - NDR_ALIGN => 4 - }, - "udlong" => { - C_TYPE => "uint64_t", - NDR_ALIGN => 4 - }, - "udlongr" => { - C_TYPE => "uint64_t", - NDR_ALIGN => 4 - }, - - # DATA_BLOB types - "DATA_BLOB" => { - C_TYPE => "DATA_BLOB", - NDR_ALIGN => 4 - }, - - # string types - "string" => { - C_TYPE => "const char *", - NDR_ALIGN => 4 #??? - }, - "string_array" => { - C_TYPE => "const char **", - NDR_ALIGN => 4 #??? - }, - - # time types - "time_t" => { - C_TYPE => "time_t", - NDR_ALIGN => 4 - }, - "NTTIME" => { - C_TYPE => "NTTIME", - NDR_ALIGN => 4 - }, - "NTTIME_1sec" => { - C_TYPE => "NTTIME", - NDR_ALIGN => 4 - }, - "NTTIME_hyper" => { - C_TYPE => "NTTIME", - NDR_ALIGN => 8 - }, - - - # error code types - "WERROR" => { - C_TYPE => "WERROR", - NDR_ALIGN => 4 - }, - "NTSTATUS" => { - C_TYPE => "NTSTATUS", - NDR_ALIGN => 4 - }, - - # special types - "nbt_string" => { - C_TYPE => "const char *", - NDR_ALIGN => 4 #??? - }, - "ipv4address" => { - C_TYPE => "const char *", - NDR_ALIGN => 4 - } -}; - -# map from a IDL type to a C header type -sub mapScalarType($) -{ - my $name = shift; - - # it's a bug when a type is not in the list - # of known scalars or has no mapping - return $scalars->{$name}{C_TYPE} if defined($scalars->{$name}) and defined($scalars->{$name}{C_TYPE}); - - die("Unknown scalar type $name"); -} - -sub getScalarAlignment($) -{ - my $name = shift; - - # it's a bug when a type is not in the list - # of known scalars or has no mapping - return $scalars->{$name}{NDR_ALIGN} if defined($scalars->{$name}) and defined($scalars->{$name}{NDR_ALIGN}); - - die("Unknown scalar type $name"); -} - sub addType($) { my $t = shift; @@ -159,7 +18,7 @@ sub addType($) sub getType($) { my $t = shift; - return undef unless(defined($typedefs{$t})); + return undef if not hasType($t); return $typedefs{$t}; } @@ -179,9 +38,17 @@ sub hasType($) return 0; } -sub RegisterScalars() +sub RegisterPrimitives() { - foreach my $k (keys %{$scalars}) { + my @primitives = ( + "char", "int8", "uint8", "short", "wchar_t", + "int16", "uint16", "long", "int32", "uint32", + "dlong", "udlong", "udlongr", "NTTIME", "NTTIME_1sec", + "time_t", "DATA_BLOB", "error_status_t", "WERROR", + "NTSTATUS", "boolean32", "unsigned32", "ipv4address", + "hyper", "NTTIME_hyper"); + + foreach my $k (@primitives) { $typedefs{$k} = { NAME => $k, TYPE => "TYPEDEF", @@ -218,25 +85,66 @@ sub bitmap_type_fn($) return "uint32"; } +# provide mappings between IDL base types and types in our headers +my %scalar_type_mappings = + ( + "int8" => "int8_t", + "uint8" => "uint8_t", + "short" => "int16_t", + "wchar_t" => "uint16_t", + "int16" => "int16_t", + "uint16" => "uint16_t", + "int32" => "int32_t", + "uint32" => "uint32_t", + "int64" => "int64_t", + "dlong" => "int64_t", + "udlong" => "uint64_t", + "udlongr" => "uint64_t", + "hyper" => "uint64_t", + "NTTIME" => "NTTIME", + "NTTIME_1sec" => "NTTIME", + "time_t" => "time_t", + "NTTIME_hyper" => "NTTIME", + "NTSTATUS" => "NTSTATUS", + "WERROR" => "WERROR", + "DATA_BLOB" => "DATA_BLOB", + "ipv4address" => "const char *", + "nbt_string" => "const char *" + ); + +# map from a IDL type to a C header type +sub mapScalarType($) +{ + my $name = shift; + die("Undef passed to mapScalarType") unless defined($name); + if (defined($scalar_type_mappings{$name})) { + return $scalar_type_mappings{$name}; + } + die("Tried to map non-scalar type $name"); +} + sub mapType($) { - my $e = shift; + my $t = shift; + die("Undef passed to mapType") unless defined($t); my $dt; - if ($e->{TYPE} eq "ENUM" or $e->{TYPE} eq "BITMAP") { - $dt = getType($e->{PARENT}->{NAME}); - } - - unless ($dt or $dt = getType($e->{TYPE})) { + return "void" if ($t eq "void"); + return "const char *" if ($t =~ "string"); + + unless ($dt or ($dt = getType($t))) { # Best guess - return "struct $e->{TYPE}"; + return "struct $t"; } - return mapScalarType($e->{TYPE}) if ($dt->{DATA}->{TYPE} eq "SCALAR"); + return mapScalarType($t) if ($dt->{DATA}->{TYPE} eq "SCALAR"); return "enum $dt->{NAME}" if ($dt->{DATA}->{TYPE} eq "ENUM"); return "struct $dt->{NAME}" if ($dt->{DATA}->{TYPE} eq "STRUCT"); return "struct $dt->{NAME}" if ($dt->{DATA}->{TYPE} eq "INTERFACE"); return "union $dt->{NAME}" if ($dt->{DATA}->{TYPE} eq "UNION"); - return mapScalarType(bitmap_type_fn($dt->{DATA})) if ($dt->{DATA}->{TYPE} eq "BITMAP"); + + if ($dt->{DATA}->{TYPE} eq "BITMAP") { + return mapScalarType(bitmap_type_fn($dt->{DATA})); + } die("Unknown type $dt->{DATA}->{TYPE}"); } @@ -258,11 +166,12 @@ sub LoadIdl($) foreach my $y (@{$x->{DATA}}) { addType($y) if ( $y->{TYPE} eq "TYPEDEF" - or $y->{TYPE} eq "DECLARE"); + or $y->{TYPE} eq "DECLARE"); } } } -RegisterScalars(); +RegisterPrimitives(); + 1; diff --git a/source4/build/pidl/validator.pm b/source4/build/pidl/validator.pm index 42e9f699dc..bb86fcca50 100644 --- a/source4/build/pidl/validator.pm +++ b/source4/build/pidl/validator.pm @@ -10,11 +10,11 @@ use strict; ##################################################################### # signal a fatal validation error -sub fatal($) +sub fatal($$) { + my $pos = shift; my $s = shift; - print "$s\n"; - die "IDL is not valid\n"; + die("$pos->{FILE}:$pos->{LINE}:$s\n"); } sub el_name($) @@ -42,6 +42,7 @@ my %property_list = ( "uuid" => {}, "endpoint" => {}, "pointer_default" => {}, + "pointer_default_top" => {}, "depends" => {}, "authservice" => {}, @@ -103,7 +104,6 @@ my %property_list = ( "range" => {}, "size_is" => {}, "length_is" => {}, - "length_of" => {}, # what is that? --metze ); ##################################################################### @@ -116,7 +116,7 @@ sub ValidProperties($) foreach my $key (keys %{$e->{PROPERTIES}}) { if (not defined $property_list{$key}) { - fatal(el_name($e) . ": unknown property '$key'\n"); + fatal($e, el_name($e) . ": unknown property '$key'\n"); } } } @@ -130,7 +130,7 @@ sub ValidElement($) ValidProperties($e); if (util::has_property($e, "ptr")) { - fatal(el_name($e) . " : pidl does not support full NDR pointers yet\n"); + fatal($e, el_name($e) . " : pidl does not support full NDR pointers yet\n"); } # Check whether switches are used correctly. @@ -139,7 +139,7 @@ sub ValidElement($) my $type = typelist::getType($e->{TYPE}); if (defined($type) and $type->{DATA}->{TYPE} ne "UNION") { - fatal(el_name($e) . ": switch_is() used on non-union type $e->{TYPE} which is a $type->{DATA}->{TYPE}"); + fatal($e, el_name($e) . ": switch_is() used on non-union type $e->{TYPE} which is a $type->{DATA}->{TYPE}"); } if (!util::has_property($type, "nodiscriminant") and defined($e2)) { @@ -152,24 +152,16 @@ sub ValidElement($) } } - if (util::has_property($e, "size_is") and not defined ($e->{ARRAY_LEN})) { - fatal(el_name($e) . " : size_is() on non-array element"); - } - - if (util::has_property($e, "length_is") and not defined ($e->{ARRAY_LEN})) { - fatal(el_name($e) . " : length_is() on non-array element"); - } - if (defined (util::has_property($e, "subcontext_size")) and not defined(util::has_property($e, "subcontext"))) { - fatal(el_name($e) . " : subcontext_size() on non-subcontext element"); + fatal($e, el_name($e) . " : subcontext_size() on non-subcontext element"); } if (defined (util::has_property($e, "compression")) and not defined(util::has_property($e, "subcontext"))) { - fatal(el_name($e) . " : compression() on non-subcontext element"); + fatal($e, el_name($e) . " : compression() on non-subcontext element"); } if (defined (util::has_property($e, "obfuscation")) and not defined(util::has_property($e, "subcontext"))) { - fatal(el_name($e) . " : obfuscation() on non-subcontext element"); + fatal($e, el_name($e) . " : obfuscation() on non-subcontext element"); } if (!$e->{POINTERS} && ( @@ -177,7 +169,7 @@ sub ValidElement($) util::has_property($e, "unique") or util::has_property($e, "relative") or util::has_property($e, "ref"))) { - fatal(el_name($e) . " : pointer properties on non-pointer element\n"); + fatal($e, el_name($e) . " : pointer properties on non-pointer element\n"); } } @@ -204,7 +196,7 @@ sub ValidUnion($) ValidProperties($union); if (util::has_property($union->{PARENT}, "nodiscriminant") and util::has_property($union->{PARENT}, "switch_type")) { - fatal($union->{PARENT}->{NAME} . ": switch_type() on union without discriminant"); + fatal($union->{PARENT}, $union->{PARENT}->{NAME} . ": switch_type() on union without discriminant"); } foreach my $e (@{$union->{ELEMENTS}}) { @@ -212,16 +204,16 @@ sub ValidUnion($) if (defined($e->{PROPERTIES}->{default}) and defined($e->{PROPERTIES}->{case})) { - fatal "Union member $e->{NAME} can not have both default and case properties!\n"; + fatal $e, "Union member $e->{NAME} can not have both default and case properties!\n"; } unless (defined ($e->{PROPERTIES}->{default}) or defined ($e->{PROPERTIES}->{case})) { - fatal "Union member $e->{NAME} must have default or case property\n"; + fatal $e, "Union member $e->{NAME} must have default or case property\n"; } if (util::has_property($e, "ref")) { - fatal(el_name($e) . " : embedded ref pointers are not supported yet\n"); + fatal($e, el_name($e) . " : embedded ref pointers are not supported yet\n"); } @@ -262,7 +254,7 @@ sub ValidFunction($) foreach my $e (@{$fn->{ELEMENTS}}) { $e->{PARENT} = $fn; if (util::has_property($e, "ref") && !$e->{POINTERS}) { - fatal "[ref] variables must be pointers ($fn->{NAME}/$e->{NAME})\n"; + fatal $e, "[ref] variables must be pointers ($fn->{NAME}/$e->{NAME})\n"; } ValidElement($e); } @@ -279,18 +271,18 @@ sub ValidInterface($) if (util::has_property($interface, "pointer_default") && $interface->{PROPERTIES}->{pointer_default} eq "ptr") { - fatal "Full pointers are not supported yet\n"; + fatal $interface, "Full pointers are not supported yet\n"; } if (util::has_property($interface, "object")) { if (util::has_property($interface, "version") && $interface->{PROPERTIES}->{version} != 0) { - fatal "Object interfaces must have version 0.0 ($interface->{NAME})\n"; + fatal $interface, "Object interfaces must have version 0.0 ($interface->{NAME})\n"; } if (!defined($interface->{BASE}) && not ($interface->{NAME} eq "IUnknown")) { - fatal "Object interfaces must all derive from IUnknown ($interface->{NAME})\n"; + fatal $interface, "Object interfaces must all derive from IUnknown ($interface->{NAME})\n"; } } |