wmi-1.3.16 from opsview.com
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
MANIFEST
|
||||
tests/parse_idl.pl
|
||||
tests/Util.pm
|
||||
tests/ndr_refptr.pl
|
||||
tests/ndr_string.pl
|
||||
tests/ndr_simple.pl
|
||||
tests/ndr_align.pl
|
||||
tests/ndr_alloc.pl
|
||||
tests/ndr_array.pl
|
||||
lib/Parse/Pidl/Samba3/Client.pm
|
||||
lib/Parse/Pidl/Samba3/ClientNDR.pm
|
||||
lib/Parse/Pidl/Samba3/Header.pm
|
||||
lib/Parse/Pidl/Samba3/Parser.pm
|
||||
lib/Parse/Pidl/Samba3/Server.pm
|
||||
lib/Parse/Pidl/Samba3/Template.pm
|
||||
lib/Parse/Pidl/Samba3/Types.pm
|
||||
lib/Parse/Pidl/Samba4/NDR/Server.pm
|
||||
lib/Parse/Pidl/Samba4/NDR/Parser.pm
|
||||
lib/Parse/Pidl/Samba4/NDR/Client.pm
|
||||
lib/Parse/Pidl/Samba4/COM/Header.pm
|
||||
lib/Parse/Pidl/Samba4/COM/Stub.pm
|
||||
lib/Parse/Pidl/Samba4/COM/Proxy.pm
|
||||
lib/Parse/Pidl/Samba4/Header.pm
|
||||
lib/Parse/Pidl/Samba4/SWIG.pm
|
||||
lib/Parse/Pidl/Samba4/TDR.pm
|
||||
lib/Parse/Pidl/Samba4/Template.pm
|
||||
lib/Parse/Pidl/Samba4/EJS.pm
|
||||
lib/Parse/Pidl/Samba4.pm
|
||||
lib/Parse/Pidl/Wireshark/Conformance.pm
|
||||
lib/Parse/Pidl/Wireshark/NDR.pm
|
||||
lib/Parse/Pidl/Typelist.pm
|
||||
lib/Parse/Pidl/Dump.pm
|
||||
lib/Parse/Pidl/Compat.pm
|
||||
lib/Parse/Pidl/Util.pm
|
||||
lib/Parse/Pidl/ODL.pm
|
||||
lib/Parse/Pidl/NDR.pm
|
||||
lib/Parse/Pidl.pm
|
||||
Makefile.PL
|
||||
idl.yp
|
||||
TODO
|
||||
README
|
||||
pidl
|
||||
META.yml Module meta-data (added by MakeMaker)
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
use ExtUtils::MakeMaker;
|
||||
WriteMakefile(
|
||||
'NAME' => 'Parse::Pidl',
|
||||
'VERSION_FROM' => 'lib/Parse/Pidl.pm',
|
||||
'EXE_FILES' => [ 'pidl' ],
|
||||
'test' => { 'TESTS' => 'tests/*.pl' }
|
||||
);
|
||||
|
||||
sub MY::postamble {
|
||||
<<'EOT';
|
||||
lib/Parse/Pidl/IDL.pm: idl.yp
|
||||
yapp -s -m 'Parse::Pidl::IDL' -o lib/Parse/Pidl/IDL.pm idl.yp
|
||||
|
||||
EOT
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
Introduction:
|
||||
=============
|
||||
This directory contains the source code of the pidl (Perl IDL)
|
||||
compiler for Samba 4.
|
||||
|
||||
The main sources for pidl are available by Subversion on
|
||||
svn+ssh://svnanon.samba.org/samba/branches/SAMBA_4_0/source/pidl
|
||||
|
||||
Pidl works by building a parse tree from a .pidl file (a simple
|
||||
dump of it's internal parse tree) or a .idl file
|
||||
(a file format mostly like the IDL file format midl uses).
|
||||
The IDL file parser is in idl.yp (a yacc file converted to
|
||||
perl code by yapp)
|
||||
|
||||
After a parse tree is present, pidl will call one of it's backends
|
||||
(which one depends on the options given on the command-line). Here is
|
||||
a list of current backends:
|
||||
|
||||
Standalone installation:
|
||||
========================
|
||||
Run Makefile.PL to generate the Makefile.
|
||||
|
||||
Then run "make install" (as root) to install.
|
||||
|
||||
Internals overview:
|
||||
===================
|
||||
|
||||
-- Generic --
|
||||
Parse::Pidl::Dump - Converts the parse tree back to an IDL file
|
||||
Parse::Pidl::Samba4::Header - Generates header file with data structures defined in IDL file
|
||||
Parse::Pidl::NDR - Generates intermediate datastructures for use by NDR parses/generators
|
||||
Parse::Pidl::ODL - Generates IDL structures from ODL structures for use in the NDR parser generator
|
||||
Parse::Pidl::Test - Utility functions for use in pidl's testsuite
|
||||
|
||||
-- Samba NDR --
|
||||
Parse::Pidl::Samba4::NDR::Client - Generates client call functions in C using the NDR parser
|
||||
Parse::Pidl::Samba4::SWIG - Generates SWIG interface files (.i)
|
||||
Parse::Pidl::Samba4::NDR::Parser - Generates pull/push functions for parsing NDR
|
||||
Parse::Pidl::Samba4::NDR::Server - Generates server side implementation in C
|
||||
Parse::Pidl::Samba4::TDR - Parser generator for the "Trivial Data Representation"
|
||||
Parse::Pidl::Samba4::Template - Generates stubs in C for server implementation
|
||||
Parse::Pidl::Samba4::EJS - Generates bindings for Embedded JavaScript (EJS)
|
||||
|
||||
-- Samba COM / DCOM --
|
||||
Parse::Pidl::Samba4::COM::Proxy - Generates proxy object for DCOM (client-side)
|
||||
Parse::Pidl::Samba4::COM::Stub - Generates stub call handler for DCOM (server-side)
|
||||
Parse::Pidl::Samba4::COM::Header - Generates headers for COM
|
||||
|
||||
-- Wireshark --
|
||||
Parse::Pidl::Wireshark::NDR - Generates a parser for the Wireshark network sniffer
|
||||
Parse::Pidl::Wireshark::Conformance - Reads conformance files containing additional data for generating Wireshark parsers
|
||||
|
||||
-- Utility modules --
|
||||
Parse::Pidl::Util - Misc utility functions used by *.pm and pidl.pl
|
||||
Parse::Pidl::Typelist - Utility functions for keeping track of known types and their representation in C
|
||||
|
||||
Tips for hacking on pidl:
|
||||
- Look at the pidl's parse tree by using the --keep option and looking
|
||||
at the generated .pidl file.
|
||||
- The various backends have a lot in common, if you don't understand how one
|
||||
implements something, look at the others
|
||||
- See pidl(1) and the documentation on midl
|
||||
- See 'info bison' and yapp(1) for information on the file format of idl.yp
|
||||
@@ -0,0 +1,23 @@
|
||||
- EJS output backend shouldn't use the NDR levels stuff but instead
|
||||
as the "C levels" and NDR levels don't necessarily match.
|
||||
|
||||
- warn about [out] attributes on pointers (midl/samba3 compatibility)
|
||||
|
||||
- true multiple dimension array / strings in arrays support
|
||||
|
||||
- compatibility mode for generating MIDL-readable data:
|
||||
- strip out pidl-specific properties
|
||||
|
||||
- support nested elements
|
||||
- generate names for anonymous tagged types
|
||||
- support typedefs properly
|
||||
|
||||
- improve represent_as(): allow it to be used for arrays and other complex types
|
||||
|
||||
- --explain-ndr option that dumps out parse tree ?
|
||||
|
||||
- seperate tables for NDR and DCE/RPC
|
||||
|
||||
- allow data structures outside of interfaces
|
||||
|
||||
- mem_ctx in the interface rather than as struct ndr member.
|
||||
@@ -0,0 +1,560 @@
|
||||
########################
|
||||
# IDL Parse::Yapp parser
|
||||
# Copyright (C) Andrew Tridgell <tridge@samba.org>
|
||||
# released under the GNU GPL version 2 or later
|
||||
|
||||
|
||||
|
||||
# the precedence actually doesn't matter at all for this grammar, but
|
||||
# by providing a precedence we reduce the number of conflicts
|
||||
# enormously
|
||||
%left '-' '+' '&' '|' '*' '>' '.' '/' '(' ')' '[' ',' ';'
|
||||
|
||||
|
||||
################
|
||||
# grammar
|
||||
%%
|
||||
idl:
|
||||
#empty { {} }
|
||||
| idl interface { push(@{$_[1]}, $_[2]); $_[1] }
|
||||
| idl coclass { push(@{$_[1]}, $_[2]); $_[1] }
|
||||
| idl import { push(@{$_[1]}, $_[2]); $_[1] }
|
||||
| idl include { push(@{$_[1]}, $_[2]); $_[1] }
|
||||
| idl importlib { push(@{$_[1]}, $_[2]); $_[1] }
|
||||
;
|
||||
|
||||
import: 'import' commalist ';' {{
|
||||
"TYPE" => "IMPORT",
|
||||
"PATHS" => $_[2],
|
||||
"FILE" => $_[0]->YYData->{INPUT_FILENAME},
|
||||
"LINE" => $_[0]->YYData->{LINE}
|
||||
}}
|
||||
;
|
||||
include: 'include' commalist ';' {{
|
||||
"TYPE" => "INCLUDE",
|
||||
"PATHS" => $_[2],
|
||||
"FILE" => $_[0]->YYData->{INPUT_FILENAME},
|
||||
"LINE" => $_[0]->YYData->{LINE}
|
||||
}}
|
||||
;
|
||||
importlib: 'importlib' commalist ';' {{
|
||||
"TYPE" => "IMPORTLIB",
|
||||
"PATHS" => $_[2],
|
||||
"FILE" => $_[0]->YYData->{INPUT_FILENAME},
|
||||
"LINE" => $_[0]->YYData->{LINE}
|
||||
}}
|
||||
;
|
||||
|
||||
commalist:
|
||||
text { [ $_[1] ] }
|
||||
| commalist ',' text { push(@{$_[1]}, $_[3]); $_[1] }
|
||||
;
|
||||
|
||||
coclass: property_list 'coclass' identifier '{' interface_names '}' optional_semicolon
|
||||
{{
|
||||
"TYPE" => "COCLASS",
|
||||
"PROPERTIES" => $_[1],
|
||||
"NAME" => $_[3],
|
||||
"DATA" => $_[5],
|
||||
"FILE" => $_[0]->YYData->{INPUT_FILENAME},
|
||||
"LINE" => $_[0]->YYData->{LINE},
|
||||
}}
|
||||
;
|
||||
|
||||
interface_names:
|
||||
#empty { {} }
|
||||
| interface_names 'interface' identifier ';' { push(@{$_[1]}, $_[2]); $_[1] }
|
||||
;
|
||||
|
||||
interface: property_list 'interface' identifier base_interface '{' definitions '}' optional_semicolon
|
||||
{{
|
||||
"TYPE" => "INTERFACE",
|
||||
"PROPERTIES" => $_[1],
|
||||
"NAME" => $_[3],
|
||||
"BASE" => $_[4],
|
||||
"DATA" => $_[6],
|
||||
"FILE" => $_[0]->YYData->{INPUT_FILENAME},
|
||||
"LINE" => $_[0]->YYData->{LINE},
|
||||
}}
|
||||
;
|
||||
|
||||
base_interface:
|
||||
#empty
|
||||
| ':' identifier { $_[2] }
|
||||
;
|
||||
|
||||
definitions:
|
||||
definition { [ $_[1] ] }
|
||||
| definitions definition { push(@{$_[1]}, $_[2]); $_[1] }
|
||||
;
|
||||
|
||||
|
||||
definition: function | const | typedef | declare | typedecl
|
||||
;
|
||||
|
||||
const: 'const' identifier pointers identifier '=' anytext ';'
|
||||
{{
|
||||
"TYPE" => "CONST",
|
||||
"DTYPE" => $_[2],
|
||||
"POINTERS" => $_[3],
|
||||
"NAME" => $_[4],
|
||||
"VALUE" => $_[6],
|
||||
"FILE" => $_[0]->YYData->{INPUT_FILENAME},
|
||||
"LINE" => $_[0]->YYData->{LINE},
|
||||
}}
|
||||
| 'const' identifier pointers identifier array_len '=' anytext ';'
|
||||
{{
|
||||
"TYPE" => "CONST",
|
||||
"DTYPE" => $_[2],
|
||||
"POINTERS" => $_[3],
|
||||
"NAME" => $_[4],
|
||||
"ARRAY_LEN" => $_[5],
|
||||
"VALUE" => $_[7],
|
||||
"FILE" => $_[0]->YYData->{INPUT_FILENAME},
|
||||
"LINE" => $_[0]->YYData->{LINE},
|
||||
}}
|
||||
;
|
||||
|
||||
|
||||
function: property_list type identifier '(' element_list2 ')' ';'
|
||||
{{
|
||||
"TYPE" => "FUNCTION",
|
||||
"NAME" => $_[3],
|
||||
"RETURN_TYPE" => $_[2],
|
||||
"PROPERTIES" => $_[1],
|
||||
"ELEMENTS" => $_[5],
|
||||
"FILE" => $_[0]->YYData->{INPUT_FILENAME},
|
||||
"LINE" => $_[0]->YYData->{LINE},
|
||||
}}
|
||||
;
|
||||
|
||||
declare: 'declare' property_list decl_type identifier';'
|
||||
{{
|
||||
"TYPE" => "DECLARE",
|
||||
"PROPERTIES" => $_[2],
|
||||
"NAME" => $_[4],
|
||||
"DATA" => $_[3],
|
||||
"FILE" => $_[0]->YYData->{INPUT_FILENAME},
|
||||
"LINE" => $_[0]->YYData->{LINE},
|
||||
}}
|
||||
;
|
||||
|
||||
decl_type: decl_enum | decl_bitmap | decl_union
|
||||
;
|
||||
|
||||
decl_enum: 'enum'
|
||||
{{
|
||||
"TYPE" => "ENUM"
|
||||
}}
|
||||
;
|
||||
|
||||
decl_bitmap: 'bitmap'
|
||||
{{
|
||||
"TYPE" => "BITMAP"
|
||||
}}
|
||||
;
|
||||
|
||||
decl_union: 'union'
|
||||
{{
|
||||
"TYPE" => "UNION"
|
||||
}}
|
||||
;
|
||||
|
||||
typedef: 'typedef' property_list type identifier array_len ';'
|
||||
{{
|
||||
"TYPE" => "TYPEDEF",
|
||||
"PROPERTIES" => $_[2],
|
||||
"NAME" => $_[4],
|
||||
"DATA" => $_[3],
|
||||
"ARRAY_LEN" => $_[5],
|
||||
"FILE" => $_[0]->YYData->{INPUT_FILENAME},
|
||||
"LINE" => $_[0]->YYData->{LINE},
|
||||
}}
|
||||
| 'typedef' property_list existingtype declarator ';'
|
||||
{
|
||||
$_[4]->{TYPE} = "DECORATED";
|
||||
$_[4]->{DATA_TYPE} = $_[3];
|
||||
{
|
||||
"TYPE" => "TYPEDEF",
|
||||
"PROPERTIES" => $_[2],
|
||||
"NAME" => $_[4]->{NAME},
|
||||
"DATA" => $_[4],
|
||||
"FILE" => $_[0]->YYData->{INPUT_FILENAME},
|
||||
"LINE" => $_[0]->YYData->{LINE}
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
declarator: direct_declarator
|
||||
| '*' declarator
|
||||
{
|
||||
$_[2]->{LEVELS} = [] unless $_[2]->{LEVELS};
|
||||
push (@{$_[2]->{LEVELS}}, { "TYPE" => "POINTER" });
|
||||
$_[2]->{POINTERS}++;
|
||||
$_[2]
|
||||
}
|
||||
;
|
||||
|
||||
direct_declarator: identifier
|
||||
{{
|
||||
"NAME" => $_[1],
|
||||
"POINTERS" => 0
|
||||
}}
|
||||
| '(' declarator ')'
|
||||
| direct_declarator '[' anytext ']'
|
||||
{
|
||||
$_[1]->{LEVELS} = [] unless $_[1]->{LEVELS};
|
||||
push (@{$_[1]->{LEVELS}}, { 'TYPE' => 'ARRAY', 'SIZE_IS' => $_[3] });
|
||||
$_[1]->{ARRAY_LEN} = [] unless $_[1]->{ARRAY_LEN};
|
||||
push @{$_[1]->{ARRAY_LEN}}, ($_[3] ne '') ? $_[3] : '*';
|
||||
$_[1]
|
||||
}
|
||||
;
|
||||
|
||||
type_td: existingtype {{ "TYPE" => "SCALAR", "NAME" => $_[1], }} ;
|
||||
|
||||
usertype: struct | union | enum | bitmap;
|
||||
|
||||
typedecl: usertype ';' { $_[1] };
|
||||
|
||||
sign: 'signed' | 'unsigned';
|
||||
|
||||
existingtype:
|
||||
| sign identifier { "$_[1] $_[2]" }
|
||||
| identifier
|
||||
;
|
||||
|
||||
type: usertype | existingtype | void { "void" } ;
|
||||
|
||||
enum_body: '{' enum_elements '}' { $_[2] };
|
||||
opt_enum_body: | enum_body;
|
||||
enum: 'enum' optional_identifier opt_enum_body
|
||||
{{
|
||||
"TYPE" => "ENUM",
|
||||
"NAME" => $_[2],
|
||||
"ELEMENTS" => $_[3]
|
||||
}}
|
||||
;
|
||||
|
||||
enum_elements:
|
||||
enum_element { [ $_[1] ] }
|
||||
| enum_elements ',' enum_element { push(@{$_[1]}, $_[3]); $_[1] }
|
||||
;
|
||||
|
||||
enum_element: identifier
|
||||
| identifier '=' anytext { "$_[1]$_[2]$_[3]" }
|
||||
;
|
||||
|
||||
bitmap_body: '{' opt_bitmap_elements '}' { $_[2] };
|
||||
opt_bitmap_body: | bitmap_body;
|
||||
bitmap: 'bitmap' optional_identifier opt_bitmap_body
|
||||
{{
|
||||
"TYPE" => "BITMAP",
|
||||
"NAME" => $_[2],
|
||||
"ELEMENTS" => $_[3]
|
||||
}}
|
||||
;
|
||||
|
||||
bitmap_elements:
|
||||
bitmap_element { [ $_[1] ] }
|
||||
| bitmap_elements ',' bitmap_element { push(@{$_[1]}, $_[3]); $_[1] }
|
||||
;
|
||||
|
||||
opt_bitmap_elements: | bitmap_elements;
|
||||
|
||||
bitmap_element: identifier '=' anytext { "$_[1] ( $_[3] )" }
|
||||
;
|
||||
|
||||
struct_body: '{' element_list1 '}' { $_[2] };
|
||||
opt_struct_body: | struct_body;
|
||||
|
||||
struct: 'struct' optional_identifier opt_struct_body
|
||||
{{
|
||||
"TYPE" => "STRUCT",
|
||||
"NAME" => $_[2],
|
||||
"ELEMENTS" => $_[3]
|
||||
}}
|
||||
;
|
||||
|
||||
empty_element: property_list ';'
|
||||
{{
|
||||
"NAME" => "",
|
||||
"TYPE" => "EMPTY",
|
||||
"PROPERTIES" => $_[1],
|
||||
"POINTERS" => 0,
|
||||
"ARRAY_LEN" => [],
|
||||
"FILE" => $_[0]->YYData->{INPUT_FILENAME},
|
||||
"LINE" => $_[0]->YYData->{LINE},
|
||||
}}
|
||||
;
|
||||
|
||||
base_or_empty: base_element ';' | empty_element;
|
||||
|
||||
optional_base_element:
|
||||
property_list base_or_empty { $_[2]->{PROPERTIES} = FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] }
|
||||
;
|
||||
|
||||
union_elements:
|
||||
#empty
|
||||
| union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
|
||||
;
|
||||
|
||||
union_body: '{' union_elements '}' { $_[2] };
|
||||
opt_union_body: | union_body;
|
||||
|
||||
union: 'union' optional_identifier opt_union_body
|
||||
{{
|
||||
"TYPE" => "UNION",
|
||||
"NAME" => $_[2],
|
||||
"ELEMENTS" => $_[3]
|
||||
}}
|
||||
;
|
||||
|
||||
base_element: property_list type pointers identifier array_len
|
||||
{{
|
||||
"NAME" => $_[4],
|
||||
"TYPE" => $_[2],
|
||||
"PROPERTIES" => $_[1],
|
||||
"POINTERS" => $_[3],
|
||||
"ARRAY_LEN" => $_[5],
|
||||
"FILE" => $_[0]->YYData->{INPUT_FILENAME},
|
||||
"LINE" => $_[0]->YYData->{LINE},
|
||||
}}
|
||||
;
|
||||
|
||||
|
||||
pointers:
|
||||
#empty
|
||||
{ 0 }
|
||||
| pointers '*' { $_[1]+1 }
|
||||
;
|
||||
|
||||
element_list1:
|
||||
#empty
|
||||
| element_list1 base_element ';' { push(@{$_[1]}, $_[2]); $_[1] }
|
||||
;
|
||||
|
||||
element_list2:
|
||||
#empty
|
||||
| 'void'
|
||||
| base_element { [ $_[1] ] }
|
||||
| element_list2 ',' base_element { push(@{$_[1]}, $_[3]); $_[1] }
|
||||
;
|
||||
|
||||
array_len:
|
||||
#empty { [] }
|
||||
| '[' ']' array_len { push(@{$_[3]}, "*"); $_[3] }
|
||||
| '[' anytext ']' array_len { push(@{$_[4]}, "$_[2]"); $_[4] }
|
||||
;
|
||||
|
||||
|
||||
property_list:
|
||||
#empty
|
||||
| property_list '[' properties ']' { FlattenHash([$_[1],$_[3]]); }
|
||||
;
|
||||
|
||||
properties: property { $_[1] }
|
||||
| properties ',' property { FlattenHash([$_[1], $_[3]]); }
|
||||
;
|
||||
|
||||
property: identifier {{ "$_[1]" => "1" }}
|
||||
| identifier '(' commalisttext ')' {{ "$_[1]" => "$_[3]" }}
|
||||
;
|
||||
|
||||
listtext:
|
||||
anytext
|
||||
| listtext ',' anytext { "$_[1] $_[3]" }
|
||||
;
|
||||
|
||||
commalisttext:
|
||||
anytext
|
||||
| commalisttext ',' anytext { "$_[1],$_[3]" }
|
||||
;
|
||||
|
||||
anytext: #empty
|
||||
{ "" }
|
||||
| identifier | constant | text
|
||||
| anytext '-' anytext { "$_[1]$_[2]$_[3]" }
|
||||
| anytext '.' anytext { "$_[1]$_[2]$_[3]" }
|
||||
| anytext '*' anytext { "$_[1]$_[2]$_[3]" }
|
||||
| anytext '>' anytext { "$_[1]$_[2]$_[3]" }
|
||||
| anytext '<' anytext { "$_[1]$_[2]$_[3]" }
|
||||
| anytext '|' anytext { "$_[1]$_[2]$_[3]" }
|
||||
| anytext '&' anytext { "$_[1]$_[2]$_[3]" }
|
||||
| anytext '/' anytext { "$_[1]$_[2]$_[3]" }
|
||||
| anytext '?' anytext { "$_[1]$_[2]$_[3]" }
|
||||
| anytext ':' anytext { "$_[1]$_[2]$_[3]" }
|
||||
| anytext '=' anytext { "$_[1]$_[2]$_[3]" }
|
||||
| anytext '+' anytext { "$_[1]$_[2]$_[3]" }
|
||||
| anytext '~' anytext { "$_[1]$_[2]$_[3]" }
|
||||
| anytext '(' commalisttext ')' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
|
||||
| anytext '{' commalisttext '}' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
|
||||
;
|
||||
|
||||
identifier: IDENTIFIER
|
||||
;
|
||||
|
||||
optional_identifier:
|
||||
IDENTIFIER
|
||||
| #empty { undef }
|
||||
;
|
||||
|
||||
constant: CONSTANT
|
||||
;
|
||||
|
||||
text: TEXT { "\"$_[1]\"" }
|
||||
;
|
||||
|
||||
optional_semicolon:
|
||||
#empty
|
||||
| ';'
|
||||
;
|
||||
|
||||
|
||||
#####################################
|
||||
# start code
|
||||
%%
|
||||
|
||||
#####################################################################
|
||||
# flatten an array of hashes into a single hash
|
||||
sub FlattenHash($)
|
||||
{
|
||||
my $a = shift;
|
||||
my %b;
|
||||
for my $d (@{$a}) {
|
||||
for my $k (keys %{$d}) {
|
||||
$b{$k} = $d->{$k};
|
||||
}
|
||||
}
|
||||
return \%b;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#####################################################################
|
||||
# traverse a perl data structure removing any empty arrays or
|
||||
# hashes and any hash elements that map to undef
|
||||
sub CleanData($)
|
||||
{
|
||||
sub CleanData($);
|
||||
my($v) = shift;
|
||||
return undef if (not defined($v));
|
||||
if (ref($v) eq "ARRAY") {
|
||||
foreach my $i (0 .. $#{$v}) {
|
||||
CleanData($v->[$i]);
|
||||
if (ref($v->[$i]) eq "ARRAY" && $#{$v->[$i]}==-1) {
|
||||
$v->[$i] = undef;
|
||||
next;
|
||||
}
|
||||
}
|
||||
# this removes any undefined elements from the array
|
||||
@{$v} = grep { defined $_ } @{$v};
|
||||
} elsif (ref($v) eq "HASH") {
|
||||
foreach my $x (keys %{$v}) {
|
||||
CleanData($v->{$x});
|
||||
if (!defined $v->{$x}) { delete($v->{$x}); next; }
|
||||
if (ref($v->{$x}) eq "ARRAY" && $#{$v->{$x}}==-1) { delete($v->{$x}); next; }
|
||||
}
|
||||
}
|
||||
return $v;
|
||||
}
|
||||
|
||||
sub _Error {
|
||||
if (exists $_[0]->YYData->{ERRMSG}) {
|
||||
print $_[0]->YYData->{ERRMSG};
|
||||
delete $_[0]->YYData->{ERRMSG};
|
||||
return;
|
||||
};
|
||||
my $line = $_[0]->YYData->{LINE};
|
||||
my $last_token = $_[0]->YYData->{LAST_TOKEN};
|
||||
my $file = $_[0]->YYData->{INPUT_FILENAME};
|
||||
|
||||
print "$file:$line: Syntax error near '$last_token'\n";
|
||||
}
|
||||
|
||||
sub _Lexer($)
|
||||
{
|
||||
my($parser)=shift;
|
||||
|
||||
$parser->YYData->{INPUT} or return('',undef);
|
||||
|
||||
again:
|
||||
$parser->YYData->{INPUT} =~ s/^[ \t]*//;
|
||||
|
||||
for ($parser->YYData->{INPUT}) {
|
||||
if (/^\#/) {
|
||||
if (s/^\# (\d+) \"(.*?)\"( \d+|)//) {
|
||||
$parser->YYData->{LINE} = $1-1;
|
||||
$parser->YYData->{INPUT_FILENAME} = $2;
|
||||
goto again;
|
||||
}
|
||||
if (s/^\#line (\d+) \"(.*?)\"( \d+|)//) {
|
||||
$parser->YYData->{LINE} = $1-1;
|
||||
$parser->YYData->{INPUT_FILENAME} = $2;
|
||||
goto again;
|
||||
}
|
||||
if (s/^(\#.*)$//m) {
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
if (s/^(\n)//) {
|
||||
$parser->YYData->{LINE}++;
|
||||
goto again;
|
||||
}
|
||||
if (s/^\"(.*?)\"//) {
|
||||
$parser->YYData->{LAST_TOKEN} = $1;
|
||||
return('TEXT',$1);
|
||||
}
|
||||
if (s/^(\d+)(\W|$)/$2/) {
|
||||
$parser->YYData->{LAST_TOKEN} = $1;
|
||||
return('CONSTANT',$1);
|
||||
}
|
||||
if (s/^([\w_]+)//) {
|
||||
$parser->YYData->{LAST_TOKEN} = $1;
|
||||
if ($1 =~
|
||||
/^(coclass|interface|const|typedef|declare|union
|
||||
|struct|enum|bitmap|void|unsigned|signed|import|include
|
||||
|importlib)$/x) {
|
||||
return $1;
|
||||
}
|
||||
return('IDENTIFIER',$1);
|
||||
}
|
||||
if (s/^(.)//s) {
|
||||
$parser->YYData->{LAST_TOKEN} = $1;
|
||||
return($1,$1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub parse_string
|
||||
{
|
||||
my ($data,$filename) = @_;
|
||||
|
||||
my $self = new Parse::Pidl::IDL;
|
||||
|
||||
$self->YYData->{INPUT_FILENAME} = $filename;
|
||||
$self->YYData->{INPUT} = $data;
|
||||
$self->YYData->{LINE} = 0;
|
||||
$self->YYData->{LAST_TOKEN} = "NONE";
|
||||
|
||||
my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
|
||||
|
||||
return CleanData($idl);
|
||||
}
|
||||
|
||||
sub parse_file($$)
|
||||
{
|
||||
my ($filename,$incdirs) = @_;
|
||||
|
||||
my $saved_delim = $/;
|
||||
undef $/;
|
||||
my $cpp = $ENV{CPP};
|
||||
if (! defined $cpp) {
|
||||
$cpp = "cpp";
|
||||
}
|
||||
my $includes = join('',map { " -I$_" } @$incdirs);
|
||||
my $data = `$cpp -D__PIDL__$includes -xc $filename`;
|
||||
$/ = $saved_delim;
|
||||
|
||||
return parse_string($data, $filename);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
###################################################
|
||||
# package to parse IDL files and generate code for
|
||||
# rpc functions in Samba
|
||||
# Copyright tridge@samba.org 2000-2003
|
||||
# Copyright jelmer@samba.org 2005
|
||||
# released under the GNU GPL
|
||||
|
||||
package Parse::Pidl;
|
||||
|
||||
use strict;
|
||||
|
||||
use vars qw ( $VERSION );
|
||||
|
||||
$VERSION = '0.02';
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,180 @@
|
||||
###################################################
|
||||
# IDL Compatibility checker
|
||||
# Copyright jelmer@samba.org 2005
|
||||
# released under the GNU GPL
|
||||
|
||||
package Parse::Pidl::Compat;
|
||||
|
||||
use Parse::Pidl::Util qw(has_property);
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '0.01';
|
||||
|
||||
my %supported_properties = (
|
||||
# interface
|
||||
"helpstring" => ["INTERFACE", "FUNCTION"],
|
||||
"version" => ["INTERFACE"],
|
||||
"uuid" => ["INTERFACE"],
|
||||
"endpoint" => ["INTERFACE"],
|
||||
"pointer_default" => ["INTERFACE"],
|
||||
|
||||
# dcom
|
||||
"object" => ["INTERFACE"],
|
||||
"local" => ["INTERFACE", "FUNCTION"],
|
||||
"iid_is" => ["ELEMENT"],
|
||||
"call_as" => ["FUNCTION"],
|
||||
"idempotent" => ["FUNCTION"],
|
||||
|
||||
# function
|
||||
"in" => ["ELEMENT"],
|
||||
"out" => ["ELEMENT"],
|
||||
|
||||
# pointer
|
||||
"ref" => ["ELEMENT"],
|
||||
"ptr" => ["ELEMENT"],
|
||||
"unique" => ["ELEMENT"],
|
||||
"ignore" => ["ELEMENT"],
|
||||
|
||||
"value" => ["ELEMENT"],
|
||||
|
||||
# generic
|
||||
"public" => ["FUNCTION", "TYPEDEF"],
|
||||
"nopush" => ["FUNCTION", "TYPEDEF"],
|
||||
"nopull" => ["FUNCTION", "TYPEDEF"],
|
||||
"noprint" => ["FUNCTION", "TYPEDEF"],
|
||||
"noejs" => ["FUNCTION", "TYPEDEF"],
|
||||
|
||||
# union
|
||||
"switch_is" => ["ELEMENT"],
|
||||
"switch_type" => ["ELEMENT", "TYPEDEF"],
|
||||
"case" => ["ELEMENT"],
|
||||
"default" => ["ELEMENT"],
|
||||
|
||||
# subcontext
|
||||
"subcontext" => ["ELEMENT"],
|
||||
"subcontext_size" => ["ELEMENT"],
|
||||
|
||||
# enum
|
||||
"enum16bit" => ["TYPEDEF"],
|
||||
"v1_enum" => ["TYPEDEF"],
|
||||
|
||||
# bitmap
|
||||
"bitmap8bit" => ["TYPEDEF"],
|
||||
"bitmap16bit" => ["TYPEDEF"],
|
||||
"bitmap32bit" => ["TYPEDEF"],
|
||||
"bitmap64bit" => ["TYPEDEF"],
|
||||
|
||||
# array
|
||||
"range" => ["ELEMENT"],
|
||||
"size_is" => ["ELEMENT"],
|
||||
"string" => ["ELEMENT"],
|
||||
"noheader" => ["ELEMENT"],
|
||||
"charset" => ["ELEMENT"],
|
||||
"length_is" => ["ELEMENT"],
|
||||
);
|
||||
|
||||
sub warning($$)
|
||||
{
|
||||
my ($l,$m) = @_;
|
||||
|
||||
print STDERR "$l->{FILE}:$l->{LINE}:warning:$m\n";
|
||||
}
|
||||
|
||||
sub CheckTypedef($)
|
||||
{
|
||||
my ($td) = @_;
|
||||
|
||||
if (has_property($td, "nodiscriminant")) {
|
||||
warning($td, "nodiscriminant property not supported");
|
||||
}
|
||||
|
||||
if ($td->{TYPE} eq "BITMAP") {
|
||||
warning($td, "converting bitmap to scalar");
|
||||
#FIXME
|
||||
}
|
||||
|
||||
if (has_property($td, "gensize")) {
|
||||
warning($td, "ignoring gensize() property. ");
|
||||
}
|
||||
|
||||
if (has_property($td, "enum8bit") and has_property($td, "enum16bit")) {
|
||||
warning($td, "8 and 16 bit enums not supported, converting to scalar");
|
||||
#FIXME
|
||||
}
|
||||
|
||||
StripProperties($td);
|
||||
}
|
||||
|
||||
sub CheckElement($)
|
||||
{
|
||||
my $e = shift;
|
||||
|
||||
if (has_property($e, "noheader")) {
|
||||
warning($e, "noheader property not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_property($e, "subcontext")) {
|
||||
warning($e, "converting subcontext to byte array");
|
||||
#FIXME
|
||||
}
|
||||
|
||||
if (has_property($e, "compression")) {
|
||||
warning($e, "compression() property not supported");
|
||||
}
|
||||
|
||||
if (has_property($e, "sptr")) {
|
||||
warning($e, "sptr() pointer property not supported");
|
||||
}
|
||||
|
||||
if (has_property($e, "relative")) {
|
||||
warning($e, "relative() pointer property not supported");
|
||||
}
|
||||
|
||||
if (has_property($e, "flag")) {
|
||||
warning($e, "ignoring flag() property");
|
||||
}
|
||||
|
||||
if (has_property($e, "value")) {
|
||||
warning($e, "ignoring value() property");
|
||||
}
|
||||
}
|
||||
|
||||
sub CheckFunction($)
|
||||
{
|
||||
my $fn = shift;
|
||||
|
||||
if (has_property($fn, "noopnum")) {
|
||||
warning($fn, "noopnum not converted. Opcodes will be out of sync.");
|
||||
}
|
||||
}
|
||||
|
||||
sub CheckInterface($)
|
||||
{
|
||||
my $if = shift;
|
||||
|
||||
if (has_property($if, "pointer_default_top") and
|
||||
$if->{PROPERTIES}->{pointer_default_top} ne "ref") {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub Check($)
|
||||
{
|
||||
my $pidl = shift;
|
||||
my $nidl = [];
|
||||
|
||||
foreach (@{$pidl}) {
|
||||
push (@$nidl, CheckInterface($_)) if ($_->{TYPE} eq "INTERFACE");
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,292 @@
|
||||
###################################################
|
||||
# dump function for IDL structures
|
||||
# Copyright tridge@samba.org 2000
|
||||
# Copyright jelmer@samba.org 2005
|
||||
# released under the GNU GPL
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Parse::Pidl::Dump - Dump support
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module provides functions that can generate IDL code from
|
||||
internal pidl data structures.
|
||||
|
||||
=cut
|
||||
|
||||
package Parse::Pidl::Dump;
|
||||
|
||||
use Exporter;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '0.01';
|
||||
@ISA = qw(Exporter);
|
||||
@EXPORT_OK = qw(DumpTypedef DumpStruct DumpEnum DumpBitmap DumpUnion DumpFunction);
|
||||
|
||||
use strict;
|
||||
use Parse::Pidl::Util qw(has_property);
|
||||
|
||||
my($res);
|
||||
|
||||
#####################################################################
|
||||
# dump a properties list
|
||||
sub DumpProperties($)
|
||||
{
|
||||
my($props) = shift;
|
||||
my $res = "";
|
||||
|
||||
foreach my $d ($props) {
|
||||
foreach my $k (keys %{$d}) {
|
||||
if ($k eq "in") {
|
||||
$res .= "[in] ";
|
||||
next;
|
||||
}
|
||||
if ($k eq "out") {
|
||||
$res .= "[out] ";
|
||||
next;
|
||||
}
|
||||
if ($k eq "ref") {
|
||||
$res .= "[ref] ";
|
||||
next;
|
||||
}
|
||||
$res .= "[$k($d->{$k})] ";
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# dump a structure element
|
||||
sub DumpElement($)
|
||||
{
|
||||
my($element) = shift;
|
||||
my $res = "";
|
||||
|
||||
(defined $element->{PROPERTIES}) &&
|
||||
($res .= DumpProperties($element->{PROPERTIES}));
|
||||
$res .= DumpType($element->{TYPE});
|
||||
$res .= " ";
|
||||
for my $i (1..$element->{POINTERS}) {
|
||||
$res .= "*";
|
||||
}
|
||||
$res .= "$element->{NAME}";
|
||||
foreach (@{$element->{ARRAY_LEN}}) {
|
||||
$res .= "[$_]";
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# dump a struct
|
||||
sub DumpStruct($)
|
||||
{
|
||||
my($struct) = shift;
|
||||
my($res);
|
||||
|
||||
$res .= "struct {\n";
|
||||
if (defined $struct->{ELEMENTS}) {
|
||||
foreach (@{$struct->{ELEMENTS}}) {
|
||||
$res .= "\t" . DumpElement($_) . ";\n";
|
||||
}
|
||||
}
|
||||
$res .= "}";
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
#####################################################################
|
||||
# dump a struct
|
||||
sub DumpEnum($)
|
||||
{
|
||||
my($enum) = shift;
|
||||
my($res);
|
||||
|
||||
$res .= "enum {\n";
|
||||
|
||||
foreach (@{$enum->{ELEMENTS}}) {
|
||||
if (/^([A-Za-z0-9_]+)[ \t]*\((.*)\)$/) {
|
||||
$res .= "\t$1 = $2,\n";
|
||||
} else {
|
||||
$res .= "\t$_,\n";
|
||||
}
|
||||
}
|
||||
|
||||
$res.= "}";
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# dump a struct
|
||||
sub DumpBitmap($)
|
||||
{
|
||||
my($bitmap) = shift;
|
||||
my($res);
|
||||
|
||||
$res .= "bitmap {\n";
|
||||
|
||||
foreach (@{$bitmap->{ELEMENTS}}) {
|
||||
if (/^([A-Za-z0-9_]+)[ \t]*\((.*)\)$/) {
|
||||
$res .= "\t$1 = $2,\n";
|
||||
} else {
|
||||
die ("Bitmap $bitmap->{NAME} has field $_ without proper value");
|
||||
}
|
||||
}
|
||||
|
||||
$res.= "}";
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
#####################################################################
|
||||
# dump a union element
|
||||
sub DumpUnionElement($)
|
||||
{
|
||||
my($element) = shift;
|
||||
my($res);
|
||||
|
||||
if (has_property($element, "default")) {
|
||||
$res .= "[default] ;\n";
|
||||
} else {
|
||||
$res .= "[case($element->{PROPERTIES}->{case})] ";
|
||||
$res .= DumpElement($element), if defined($element);
|
||||
$res .= ";\n";
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# dump a union
|
||||
sub DumpUnion($)
|
||||
{
|
||||
my($union) = shift;
|
||||
my($res);
|
||||
|
||||
(defined $union->{PROPERTIES}) &&
|
||||
($res .= DumpProperties($union->{PROPERTIES}));
|
||||
$res .= "union {\n";
|
||||
foreach my $e (@{$union->{ELEMENTS}}) {
|
||||
$res .= DumpUnionElement($e);
|
||||
}
|
||||
$res .= "}";
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# dump a type
|
||||
sub DumpType($)
|
||||
{
|
||||
my($data) = shift;
|
||||
my($res);
|
||||
|
||||
if (ref($data) eq "HASH") {
|
||||
($data->{TYPE} eq "STRUCT") && ($res .= DumpStruct($data));
|
||||
($data->{TYPE} eq "UNION") && ($res .= DumpUnion($data));
|
||||
($data->{TYPE} eq "ENUM") && ($res .= DumpEnum($data));
|
||||
($data->{TYPE} eq "BITMAP") && ($res .= DumpBitmap($data));
|
||||
} else {
|
||||
$res .= "$data";
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# dump a typedef
|
||||
sub DumpTypedef($)
|
||||
{
|
||||
my($typedef) = shift;
|
||||
my($res);
|
||||
|
||||
$res .= "typedef ";
|
||||
$res .= DumpType($typedef->{DATA});
|
||||
$res .= " $typedef->{NAME};\n\n";
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# dump a typedef
|
||||
sub DumpFunction($)
|
||||
{
|
||||
my($function) = shift;
|
||||
my($first) = 1;
|
||||
my($res);
|
||||
|
||||
$res .= DumpType($function->{RETURN_TYPE});
|
||||
$res .= " $function->{NAME}(\n";
|
||||
for my $d (@{$function->{ELEMENTS}}) {
|
||||
unless ($first) { $res .= ",\n"; } $first = 0;
|
||||
$res .= DumpElement($d);
|
||||
}
|
||||
$res .= "\n);\n\n";
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# dump a module header
|
||||
sub DumpInterfaceProperties($)
|
||||
{
|
||||
my($header) = shift;
|
||||
my($data) = $header->{DATA};
|
||||
my($first) = 1;
|
||||
my($res);
|
||||
|
||||
$res .= "[\n";
|
||||
foreach my $k (keys %{$data}) {
|
||||
$first || ($res .= ",\n"); $first = 0;
|
||||
$res .= "$k($data->{$k})";
|
||||
}
|
||||
$res .= "\n]\n";
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# dump the interface definitions
|
||||
sub DumpInterface($)
|
||||
{
|
||||
my($interface) = shift;
|
||||
my($data) = $interface->{DATA};
|
||||
my($res);
|
||||
|
||||
$res .= DumpInterfaceProperties($interface->{PROPERTIES});
|
||||
|
||||
$res .= "interface $interface->{NAME}\n{\n";
|
||||
foreach my $d (@{$data}) {
|
||||
($d->{TYPE} eq "TYPEDEF") &&
|
||||
($res .= DumpTypedef($d));
|
||||
($d->{TYPE} eq "FUNCTION") &&
|
||||
($res .= DumpFunction($d));
|
||||
}
|
||||
$res .= "}\n";
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
#####################################################################
|
||||
# dump a parsed IDL structure back into an IDL file
|
||||
sub Dump($)
|
||||
{
|
||||
my($idl) = shift;
|
||||
my($res);
|
||||
|
||||
$res = "/* Dumped by pidl */\n\n";
|
||||
foreach my $x (@{$idl}) {
|
||||
($x->{TYPE} eq "INTERFACE") &&
|
||||
($res .= DumpInterface($x));
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
1;
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,101 @@
|
||||
##########################################
|
||||
# Converts ODL stuctures to IDL structures
|
||||
# (C) 2004-2005 Jelmer Vernooij <jelmer@samba.org>
|
||||
|
||||
package Parse::Pidl::ODL;
|
||||
|
||||
use Parse::Pidl::Util qw(has_property);
|
||||
use Parse::Pidl::Typelist qw(hasType getType);
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '0.01';
|
||||
|
||||
#####################################################################
|
||||
# find an interface in an array of interfaces
|
||||
sub get_interface($$)
|
||||
{
|
||||
my($if,$n) = @_;
|
||||
|
||||
foreach(@$if) {
|
||||
next if ($_->{TYPE} ne "INTERFACE");
|
||||
return $_ if($_->{NAME} eq $n);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub FunctionAddObjArgs($)
|
||||
{
|
||||
my $e = shift;
|
||||
|
||||
unshift(@{$e->{ELEMENTS}}, {
|
||||
'NAME' => 'ORPCthis',
|
||||
'POINTERS' => 0,
|
||||
'PROPERTIES' => { 'in' => '1' },
|
||||
'TYPE' => 'ORPCTHIS',
|
||||
'FILE' => $e->{FILE},
|
||||
'LINE' => $e->{LINE}
|
||||
});
|
||||
unshift(@{$e->{ELEMENTS}}, {
|
||||
'NAME' => 'ORPCthat',
|
||||
'POINTERS' => 1,
|
||||
'PROPERTIES' => { 'out' => '1', 'ref' => '1' },
|
||||
'TYPE' => 'ORPCTHAT',
|
||||
'FILE' => $e->{FILE},
|
||||
'LINE' => $e->{LINE}
|
||||
});
|
||||
}
|
||||
|
||||
sub ReplaceInterfacePointers($)
|
||||
{
|
||||
my $e = shift;
|
||||
foreach my $x (@{$e->{ELEMENTS}}) {
|
||||
next unless (hasType($x->{TYPE}));
|
||||
next unless getType($x->{TYPE})->{DATA}->{TYPE} eq "INTERFACE";
|
||||
|
||||
$x->{TYPE} = "MInterfacePointer";
|
||||
}
|
||||
}
|
||||
|
||||
# Add ORPC specific bits to an interface.
|
||||
sub ODL2IDL($)
|
||||
{
|
||||
my $odl = shift;
|
||||
my $addedorpc = 0;
|
||||
|
||||
foreach my $x (@$odl) {
|
||||
next if ($x->{TYPE} ne "INTERFACE");
|
||||
# Add [in] ORPCTHIS *this, [out] ORPCTHAT *that
|
||||
# and replace interfacepointers with MInterfacePointer
|
||||
# for 'object' interfaces
|
||||
if (has_property($x, "object")) {
|
||||
foreach my $e (@{$x->{DATA}}) {
|
||||
($e->{TYPE} eq "FUNCTION") && FunctionAddObjArgs($e);
|
||||
ReplaceInterfacePointers($e);
|
||||
}
|
||||
$addedorpc = 1;
|
||||
}
|
||||
|
||||
if ($x->{BASE}) {
|
||||
my $base = get_interface($odl, $x->{BASE});
|
||||
|
||||
foreach my $fn (reverse @{$base->{DATA}}) {
|
||||
next unless ($fn->{TYPE} eq "FUNCTION");
|
||||
unshift (@{$x->{DATA}}, $fn);
|
||||
push (@{$x->{INHERITED_FUNCTIONS}}, $fn->{NAME});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unshift (@$odl, {
|
||||
TYPE => "IMPORT",
|
||||
PATHS => [ "\"orpc.idl\"" ],
|
||||
FILE => undef,
|
||||
LINE => undef
|
||||
}) if ($addedorpc);
|
||||
|
||||
return $odl;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,149 @@
|
||||
###################################################
|
||||
# Samba3 client generator for IDL structures
|
||||
# on top of Samba4 style NDR functions
|
||||
# Copyright jelmer@samba.org 2005-2006
|
||||
# released under the GNU GPL
|
||||
|
||||
package Parse::Pidl::Samba3::ClientNDR;
|
||||
|
||||
use strict;
|
||||
use Parse::Pidl::Typelist qw(hasType getType mapType scalar_is_reference);
|
||||
use Parse::Pidl::Util qw(has_property ParseExpr is_constant);
|
||||
use Parse::Pidl::NDR qw(GetPrevLevel GetNextLevel ContainsDeferred);
|
||||
use Parse::Pidl::Samba4 qw(DeclLong_cli IsUniqueOut);
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '0.01';
|
||||
|
||||
my $res;
|
||||
my $res_hdr;
|
||||
my $tabs = "";
|
||||
sub indent() { $tabs.="\t"; }
|
||||
sub deindent() { $tabs = substr($tabs, 1); }
|
||||
sub pidl($) { $res .= $tabs.(shift)."\n"; }
|
||||
sub pidl_hdr($) { $res_hdr .= (shift)."\n"; }
|
||||
sub fatal($$) { my ($e,$s) = @_; die("$e->{ORIGINAL}->{FILE}:$e->{ORIGINAL}->{LINE}: $s\n"); }
|
||||
sub warning($$) { my ($e,$s) = @_; warn("$e->{ORIGINAL}->{FILE}:$e->{ORIGINAL}->{LINE}: $s\n"); }
|
||||
sub fn_declare($) { my ($n) = @_; pidl $n; pidl_hdr "$n;"; }
|
||||
|
||||
sub ParseFunction($$)
|
||||
{
|
||||
my ($if,$fn) = @_;
|
||||
|
||||
my $inargs = "";
|
||||
my $defargs = "";
|
||||
my $uif = uc($if->{NAME});
|
||||
my $ufn = "DCERPC_".uc($fn->{NAME});
|
||||
|
||||
foreach (@{$fn->{ELEMENTS}}) {
|
||||
$defargs .= ", " . DeclLong_cli($_);
|
||||
}
|
||||
fn_declare "NTSTATUS rpccli_$fn->{NAME}(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx$defargs)";
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "struct $fn->{NAME} r;";
|
||||
pidl "NTSTATUS status;";
|
||||
pidl "";
|
||||
pidl "/* In parameters */";
|
||||
|
||||
foreach (@{$fn->{ELEMENTS}}) {
|
||||
if (grep(/in/, @{$_->{DIRECTION}})) {
|
||||
if ( IsUniqueOut($_) ) {
|
||||
pidl "r.in.$_->{NAME} = *$_->{NAME};";
|
||||
}
|
||||
else {
|
||||
pidl "r.in.$_->{NAME} = $_->{NAME};";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pidl "";
|
||||
pidl "if (DEBUGLEVEL >= 10)";
|
||||
pidl "\tNDR_PRINT_IN_DEBUG($fn->{NAME}, &r);";
|
||||
pidl "";
|
||||
pidl "status = cli_do_rpc_ndr(cli, mem_ctx, PI_$uif, $ufn, &r, (ndr_pull_flags_fn_t)ndr_pull_$fn->{NAME}, (ndr_push_flags_fn_t)ndr_push_$fn->{NAME});";
|
||||
pidl "";
|
||||
|
||||
pidl "if ( !NT_STATUS_IS_OK(status) ) {";
|
||||
indent;
|
||||
pidl "return status;";
|
||||
deindent;
|
||||
pidl "}";
|
||||
|
||||
pidl "";
|
||||
pidl "if (DEBUGLEVEL >= 10)";
|
||||
pidl "\tNDR_PRINT_OUT_DEBUG($fn->{NAME}, &r);";
|
||||
pidl "";
|
||||
pidl "if (NT_STATUS_IS_ERR(status)) {";
|
||||
pidl "\treturn status;";
|
||||
pidl "}";
|
||||
pidl "";
|
||||
pidl "/* Return variables */";
|
||||
foreach my $e (@{$fn->{ELEMENTS}}) {
|
||||
next unless (grep(/out/, @{$e->{DIRECTION}}));
|
||||
|
||||
fatal($e, "[out] argument is not a pointer or array") if ($e->{LEVELS}[0]->{TYPE} ne "POINTER" and $e->{LEVELS}[0]->{TYPE} ne "ARRAY");
|
||||
|
||||
if ( IsUniqueOut($e) ) {
|
||||
pidl "*$e->{NAME} = r.out.$e->{NAME};";
|
||||
} else {
|
||||
pidl "*$e->{NAME} = *r.out.$e->{NAME};";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pidl"";
|
||||
pidl "/* Return result */";
|
||||
if (not $fn->{RETURN_TYPE}) {
|
||||
pidl "return NT_STATUS_OK;";
|
||||
} elsif ($fn->{RETURN_TYPE} eq "NTSTATUS") {
|
||||
pidl "return r.out.result;";
|
||||
} elsif ($fn->{RETURN_TYPE} eq "WERROR") {
|
||||
pidl "return werror_to_ntstatus(r.out.result);";
|
||||
} else {
|
||||
pidl "/* Sorry, don't know how to convert $fn->{RETURN_TYPE} to NTSTATUS */";
|
||||
pidl "return NT_STATUS_OK;";
|
||||
}
|
||||
|
||||
deindent;
|
||||
pidl "}";
|
||||
pidl "";
|
||||
}
|
||||
|
||||
sub ParseInterface($)
|
||||
{
|
||||
my $if = shift;
|
||||
|
||||
my $uif = uc($if->{NAME});
|
||||
|
||||
pidl_hdr "#ifndef __CLI_$uif\__";
|
||||
pidl_hdr "#define __CLI_$uif\__";
|
||||
ParseFunction($if, $_) foreach (@{$if->{FUNCTIONS}});
|
||||
pidl_hdr "#endif /* __CLI_$uif\__ */";
|
||||
}
|
||||
|
||||
sub Parse($$$)
|
||||
{
|
||||
my($ndr,$header,$ndr_header) = @_;
|
||||
|
||||
$res = "";
|
||||
$res_hdr = "";
|
||||
|
||||
pidl "/*";
|
||||
pidl " * Unix SMB/CIFS implementation.";
|
||||
pidl " * client auto-generated by pidl. DO NOT MODIFY!";
|
||||
pidl " */";
|
||||
pidl "";
|
||||
pidl "#include \"includes.h\"";
|
||||
pidl "#include \"$header\"";
|
||||
pidl_hdr "#include \"$ndr_header\"";
|
||||
pidl "";
|
||||
|
||||
foreach (@$ndr) {
|
||||
ParseInterface($_) if ($_->{TYPE} eq "INTERFACE");
|
||||
}
|
||||
|
||||
return ($res, $res_hdr);
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,230 @@
|
||||
###################################################
|
||||
# Samba3 server generator for IDL structures
|
||||
# on top of Samba4 style NDR functions
|
||||
# Copyright jelmer@samba.org 2005-2006
|
||||
# released under the GNU GPL
|
||||
|
||||
package Parse::Pidl::Samba3::ServerNDR;
|
||||
|
||||
use strict;
|
||||
use Parse::Pidl::Typelist qw(hasType getType mapType scalar_is_reference);
|
||||
use Parse::Pidl::Util qw(has_property ParseExpr is_constant);
|
||||
use Parse::Pidl::NDR qw(GetPrevLevel GetNextLevel ContainsDeferred);
|
||||
use Parse::Pidl::Samba4 qw(DeclLong);
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '0.01';
|
||||
|
||||
my $res;
|
||||
my $res_hdr;
|
||||
my $tabs = "";
|
||||
sub indent() { $tabs.="\t"; }
|
||||
sub deindent() { $tabs = substr($tabs, 1); }
|
||||
sub pidl($) { $res .= $tabs.(shift)."\n"; }
|
||||
sub pidl_hdr($) { $res_hdr .= (shift)."\n"; }
|
||||
sub fatal($$) { my ($e,$s) = @_; die("$e->{ORIGINAL}->{FILE}:$e->{ORIGINAL}->{LINE}: $s\n"); }
|
||||
sub warning($$) { my ($e,$s) = @_; warn("$e->{ORIGINAL}->{FILE}:$e->{ORIGINAL}->{LINE}: $s\n"); }
|
||||
sub fn_declare($) { my ($n) = @_; pidl $n; pidl_hdr "$n;"; }
|
||||
|
||||
sub AllocOutVar($$$$)
|
||||
{
|
||||
my ($e, $mem_ctx, $name, $env) = @_;
|
||||
|
||||
my $l = $e->{LEVELS}[0];
|
||||
|
||||
if ($l->{TYPE} eq "POINTER") {
|
||||
$l = GetNextLevel($e, $l);
|
||||
}
|
||||
|
||||
if ($l->{TYPE} eq "ARRAY") {
|
||||
my $size = ParseExpr($l->{SIZE_IS}, $env);
|
||||
pidl "$name = talloc_zero_size($mem_ctx, sizeof(*$name) * $size);";
|
||||
} else {
|
||||
pidl "$name = talloc_zero_size($mem_ctx, sizeof(*$name));";
|
||||
}
|
||||
|
||||
pidl "if ($name == NULL) {";
|
||||
pidl "\ttalloc_free(mem_ctx);";
|
||||
pidl "\treturn False;";
|
||||
pidl "}";
|
||||
pidl "";
|
||||
}
|
||||
|
||||
sub ParseFunction($$)
|
||||
{
|
||||
my ($if,$fn) = @_;
|
||||
|
||||
pidl "static BOOL api_$fn->{NAME}(pipes_struct *p)";
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "struct ndr_pull *pull;";
|
||||
pidl "struct ndr_push *push;";
|
||||
pidl "NTSTATUS status;";
|
||||
pidl "DATA_BLOB blob;";
|
||||
pidl "struct $fn->{NAME} r;";
|
||||
pidl "TALLOC_CTX *mem_ctx = talloc_init(\"api_$fn->{NAME}\");";
|
||||
pidl "";
|
||||
pidl "if (!prs_data_blob(&p->in_data.data, &blob, mem_ctx)) {";
|
||||
pidl "\ttalloc_free(mem_ctx);";
|
||||
pidl "\treturn False;";
|
||||
pidl "}";
|
||||
pidl "";
|
||||
pidl "pull = ndr_pull_init_blob(&blob, mem_ctx);";
|
||||
pidl "if (pull == NULL) {";
|
||||
pidl "\ttalloc_free(mem_ctx);";
|
||||
pidl "\treturn False;";
|
||||
pidl "}";
|
||||
pidl "";
|
||||
pidl "pull->flags |= LIBNDR_FLAG_REF_ALLOC;";
|
||||
pidl "status = ndr_pull_$fn->{NAME}(pull, NDR_IN, &r);";
|
||||
pidl "if (NT_STATUS_IS_ERR(status)) {";
|
||||
pidl "\ttalloc_free(mem_ctx);";
|
||||
pidl "\treturn False;";
|
||||
pidl "}";
|
||||
pidl "";
|
||||
pidl "if (DEBUGLEVEL >= 10)";
|
||||
pidl "\tNDR_PRINT_IN_DEBUG($fn->{NAME}, &r);";
|
||||
pidl "";
|
||||
|
||||
my %env = ();
|
||||
my $hasout = 0;
|
||||
foreach (@{$fn->{ELEMENTS}}) {
|
||||
if (grep(/out/, @{$_->{DIRECTION}})) { $hasout = 1; }
|
||||
next unless (grep (/in/, @{$_->{DIRECTION}}));
|
||||
$env{$_->{NAME}} = "r.in.$_->{NAME}";
|
||||
}
|
||||
|
||||
pidl "ZERO_STRUCT(r.out);" if ($hasout);
|
||||
|
||||
my $proto = "_$fn->{NAME}(pipes_struct *p";
|
||||
my $ret = "_$fn->{NAME}(p";
|
||||
foreach (@{$fn->{ELEMENTS}}) {
|
||||
my @dir = @{$_->{DIRECTION}};
|
||||
if (grep(/in/, @dir) and grep(/out/, @dir)) {
|
||||
pidl "r.out.$_->{NAME} = r.in.$_->{NAME};";
|
||||
} elsif (grep(/out/, @dir)) {
|
||||
AllocOutVar($_, "mem_ctx", "r.out.$_->{NAME}", \%env);
|
||||
}
|
||||
if (grep(/in/, @dir)) { $ret .= ", r.in.$_->{NAME}"; }
|
||||
else { $ret .= ", r.out.$_->{NAME}"; }
|
||||
|
||||
$proto .= ", " . DeclLong($_);
|
||||
}
|
||||
$ret .= ")";
|
||||
$proto .= ");";
|
||||
|
||||
if ($fn->{RETURN_TYPE}) {
|
||||
$ret = "r.out.result = $ret";
|
||||
$proto = "$fn->{RETURN_TYPE} $proto";
|
||||
} else {
|
||||
$proto = "void $proto";
|
||||
}
|
||||
|
||||
pidl_hdr "$proto";
|
||||
pidl "$ret;";
|
||||
|
||||
pidl "";
|
||||
pidl "if (p->rng_fault_state) {";
|
||||
pidl "\ttalloc_free(mem_ctx);";
|
||||
pidl "\t/* Return True here, srv_pipe_hnd.c will take care */";
|
||||
pidl "\treturn True;";
|
||||
pidl "}";
|
||||
pidl "";
|
||||
pidl "if (DEBUGLEVEL >= 10)";
|
||||
pidl "\tNDR_PRINT_OUT_DEBUG($fn->{NAME}, &r);";
|
||||
pidl "";
|
||||
pidl "push = ndr_push_init_ctx(mem_ctx);";
|
||||
pidl "if (push == NULL) {";
|
||||
pidl "\ttalloc_free(mem_ctx);";
|
||||
pidl "\treturn False;";
|
||||
pidl "}";
|
||||
pidl "";
|
||||
pidl "status = ndr_push_$fn->{NAME}(push, NDR_OUT, &r);";
|
||||
pidl "if (NT_STATUS_IS_ERR(status)) {";
|
||||
pidl "\ttalloc_free(mem_ctx);";
|
||||
pidl "\treturn False;";
|
||||
pidl "}";
|
||||
pidl "";
|
||||
pidl "blob = ndr_push_blob(push);";
|
||||
pidl "if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32)blob.length)) {";
|
||||
pidl "\ttalloc_free(mem_ctx);";
|
||||
pidl "\treturn False;";
|
||||
pidl "}";
|
||||
pidl "";
|
||||
pidl "talloc_free(mem_ctx);";
|
||||
pidl "";
|
||||
pidl "return True;";
|
||||
deindent;
|
||||
pidl "}";
|
||||
pidl "";
|
||||
}
|
||||
|
||||
sub ParseInterface($)
|
||||
{
|
||||
my $if = shift;
|
||||
|
||||
my $uif = uc($if->{NAME});
|
||||
|
||||
pidl_hdr "#ifndef __SRV_$uif\__";
|
||||
pidl_hdr "#define __SRV_$uif\__";
|
||||
ParseFunction($if, $_) foreach (@{$if->{FUNCTIONS}});
|
||||
|
||||
pidl "";
|
||||
pidl "/* Tables */";
|
||||
pidl "static struct api_struct api_$if->{NAME}_cmds[] = ";
|
||||
pidl "{";
|
||||
indent;
|
||||
|
||||
foreach (@{$if->{FUNCTIONS}}) {
|
||||
pidl "{\"" . uc($_->{NAME}) . "\", DCERPC_" . uc($_->{NAME}) . ", api_$_->{NAME}},";
|
||||
}
|
||||
|
||||
deindent;
|
||||
pidl "};";
|
||||
|
||||
pidl "";
|
||||
|
||||
pidl_hdr "void $if->{NAME}_get_pipe_fns(struct api_struct **fns, int *n_fns);";
|
||||
pidl "void $if->{NAME}_get_pipe_fns(struct api_struct **fns, int *n_fns)";
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "*fns = api_$if->{NAME}_cmds;";
|
||||
pidl "*n_fns = sizeof(api_$if->{NAME}_cmds) / sizeof(struct api_struct);";
|
||||
deindent;
|
||||
pidl "}";
|
||||
pidl "";
|
||||
|
||||
pidl_hdr "NTSTATUS rpc_$if->{NAME}_init(void);";
|
||||
pidl "NTSTATUS rpc_$if->{NAME}_init(void)";
|
||||
pidl "{";
|
||||
pidl "\treturn rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, \"$if->{NAME}\", \"$if->{NAME}\", api_$if->{NAME}_cmds, sizeof(api_$if->{NAME}_cmds) / sizeof(struct api_struct));";
|
||||
pidl "}";
|
||||
|
||||
pidl_hdr "#endif /* __SRV_$uif\__ */";
|
||||
}
|
||||
|
||||
sub Parse($$$)
|
||||
{
|
||||
my($ndr,$header,$ndr_header) = @_;
|
||||
|
||||
$res = "";
|
||||
$res_hdr = "";
|
||||
|
||||
pidl "/*";
|
||||
pidl " * Unix SMB/CIFS implementation.";
|
||||
pidl " * server auto-generated by pidl. DO NOT MODIFY!";
|
||||
pidl " */";
|
||||
pidl "";
|
||||
pidl "#include \"includes.h\"";
|
||||
pidl "#include \"$header\"";
|
||||
pidl_hdr "#include \"$ndr_header\"";
|
||||
pidl "";
|
||||
|
||||
foreach (@$ndr) {
|
||||
ParseInterface($_) if ($_->{TYPE} eq "INTERFACE");
|
||||
}
|
||||
|
||||
return ($res, $res_hdr);
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,94 @@
|
||||
###################################################
|
||||
# Common Samba4 functions
|
||||
# Copyright jelmer@samba.org 2006
|
||||
# released under the GNU GPL
|
||||
|
||||
package Parse::Pidl::Samba4;
|
||||
|
||||
require Exporter;
|
||||
@ISA = qw(Exporter);
|
||||
@EXPORT = qw(is_intree choose_header DeclLong DeclLong_cli IsUniqueOut);
|
||||
|
||||
use Parse::Pidl::Util qw(has_property is_constant);
|
||||
use Parse::Pidl::Typelist qw(mapType scalar_is_reference);
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '0.01';
|
||||
|
||||
sub is_intree()
|
||||
{
|
||||
return 4 if (-f "kdc/kdc.c");
|
||||
return 3 if (-f "include/smb.h");
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Return an #include line depending on whether this build is an in-tree
|
||||
# build or not.
|
||||
sub choose_header($$)
|
||||
{
|
||||
my ($in,$out) = @_;
|
||||
return "#include \"$in\"" if (is_intree());
|
||||
return "#include <$out>";
|
||||
}
|
||||
|
||||
sub IsUniqueOut($)
|
||||
{
|
||||
my ($e) = shift;
|
||||
|
||||
return grep(/out/, @{$e->{DIRECTION}}) &&
|
||||
((($e->{LEVELS}[0]->{TYPE} eq "POINTER") &&
|
||||
($e->{LEVELS}[0]->{POINTER_TYPE} eq "unique")) ||
|
||||
($e->{LEVELS}[0]->{TYPE} eq "ARRAY"));
|
||||
}
|
||||
|
||||
sub DeclLong_int($$)
|
||||
{
|
||||
my($element,$cli) = @_;
|
||||
my $ret = "";
|
||||
|
||||
if (has_property($element, "represent_as")) {
|
||||
$ret.=mapType($element->{PROPERTIES}->{represent_as})." ";
|
||||
} else {
|
||||
if (has_property($element, "charset")) {
|
||||
$ret.="const char";
|
||||
} else {
|
||||
$ret.=mapType($element->{TYPE});
|
||||
}
|
||||
|
||||
$ret.=" ";
|
||||
my $numstar = $element->{ORIGINAL}->{POINTERS};
|
||||
if ($numstar >= 1) {
|
||||
$numstar-- if scalar_is_reference($element->{TYPE});
|
||||
}
|
||||
foreach (@{$element->{ORIGINAL}->{ARRAY_LEN}})
|
||||
{
|
||||
next if is_constant($_) and
|
||||
not has_property($element, "charset");
|
||||
$numstar++;
|
||||
}
|
||||
if ($cli && IsUniqueOut($element)) {
|
||||
$numstar++;
|
||||
}
|
||||
$ret.="*" foreach (1..$numstar);
|
||||
}
|
||||
$ret.=$element->{NAME};
|
||||
foreach (@{$element->{ARRAY_LEN}}) {
|
||||
next unless (is_constant($_) and not has_property($element, "charset"));
|
||||
$ret.="[$_]";
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub DeclLong($)
|
||||
{
|
||||
return DeclLong_int($_, 0);
|
||||
}
|
||||
|
||||
sub DeclLong_cli($)
|
||||
{
|
||||
return DeclLong_int($_, 1);
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,184 @@
|
||||
# COM Header generation
|
||||
# (C) 2005 Jelmer Vernooij <jelmer@samba.org>
|
||||
|
||||
package Parse::Pidl::Samba4::COM::Header;
|
||||
|
||||
use Parse::Pidl::Typelist qw(mapType);
|
||||
use Parse::Pidl::Util qw(has_property is_constant);
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '0.01';
|
||||
|
||||
use strict;
|
||||
|
||||
sub HeaderType($)
|
||||
{
|
||||
my($e) = @_;
|
||||
if (has_property($e, "charset")) {
|
||||
return "const char";
|
||||
} else {
|
||||
return mapType($e->{TYPE});
|
||||
}
|
||||
}
|
||||
|
||||
sub GetArgumentProto($)
|
||||
{
|
||||
my $a = shift;
|
||||
my $res = HeaderType($a) . " ";
|
||||
|
||||
my $l = $a->{POINTERS};
|
||||
$l-- if (Parse::Pidl::Typelist::scalar_is_reference($a->{TYPE}));
|
||||
foreach my $i (1..$l) {
|
||||
$res .= "*";
|
||||
}
|
||||
|
||||
if (defined $a->{ARRAY_LEN}[0] && !is_constant($a->{ARRAY_LEN}[0]) &&
|
||||
!$a->{POINTERS}) {
|
||||
$res .= "*";
|
||||
}
|
||||
$res .= $a->{NAME};
|
||||
if (defined $a->{ARRAY_LEN}[0] && is_constant($a->{ARRAY_LEN}[0])) {
|
||||
$res .= "[$a->{ARRAY_LEN}[0]]";
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub GetArgumentProtoList
|
||||
{
|
||||
my ($f,$filter) = @_;
|
||||
my $res = "";
|
||||
|
||||
foreach my $a (@{$f->{ELEMENTS}}) {
|
||||
next if defined($filter) && !has_property($a, $filter);
|
||||
$res .= ", " . GetArgumentProto($a);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub GetArgumentList
|
||||
{
|
||||
my ($f,$filter) = @_;
|
||||
my $res = "";
|
||||
|
||||
foreach (@{$f->{ELEMENTS}}) {
|
||||
next if defined($filter) && !has_property($_, $filter);
|
||||
$res .= ", $_->{NAME}";
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# generate vtable structure for COM interface
|
||||
sub HeaderVTable($)
|
||||
{
|
||||
my $interface = shift;
|
||||
my $res;
|
||||
$res .= "#define " . uc($interface->{NAME}) . "_METHODS \\\n";
|
||||
if (defined($interface->{BASE})) {
|
||||
$res .= "\t" . uc($interface->{BASE} . "_METHODS") . "\\\n";
|
||||
}
|
||||
|
||||
my $data = $interface->{DATA};
|
||||
foreach my $d (@{$data}) {
|
||||
if ($d->{TYPE} eq "FUNCTION") {
|
||||
# $res .= "\t" . mapType($d->{RETURN_TYPE}) . " (*$d->{NAME}) (struct $interface->{NAME} *d, TALLOC_CTX *mem_ctx" . GetArgumentProtoList($d) . ");\\\n";
|
||||
$res .= "\tstruct composite_context *(*$d->{NAME}_send) (struct $interface->{NAME} *d, TALLOC_CTX *mem_ctx" . GetArgumentProtoList($d, "in") . ");\\\n";
|
||||
}
|
||||
}
|
||||
$res .= "\n";
|
||||
$res .= "struct $interface->{NAME}_vtable {\n";
|
||||
$res .= "\tstruct GUID iid;\n";
|
||||
$res .= "\t" . uc($interface->{NAME}) . "_METHODS\n";
|
||||
$res .= "};\n\n";
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub ParseInterface($)
|
||||
{
|
||||
my $if = shift;
|
||||
my $res;
|
||||
|
||||
$res .="\n\n/* $if->{NAME} */\n";
|
||||
|
||||
$res .="#define COM_" . uc($if->{NAME}) . "_UUID $if->{PROPERTIES}->{uuid}\n\n";
|
||||
|
||||
$res .="struct $if->{NAME}_vtable;\n\n";
|
||||
|
||||
$res .="struct $if->{NAME} {
|
||||
struct OBJREF obj;
|
||||
struct com_context *ctx;
|
||||
struct $if->{NAME}_vtable *vtable;
|
||||
void *object_data;
|
||||
};\n\n";
|
||||
|
||||
$res.=HeaderVTable($if);
|
||||
|
||||
foreach my $d (@{$if->{DATA}}) {
|
||||
next if ($d->{TYPE} ne "FUNCTION");
|
||||
|
||||
my $defname = ($d->{NAME} =~ /^$if->{NAME}_(.*)$/) ? $1 : $d->{NAME};
|
||||
# $res .= "#define $if->{NAME}_${defname}(interface, mem_ctx" . GetArgumentList($d) . ") ";
|
||||
# $res .= "((interface)->vtable->$d->{NAME}(interface, mem_ctx" . GetArgumentList($d) . "))";
|
||||
$res .= mapType($d->{RETURN_TYPE}) . " $if->{NAME}_${defname}(struct $if->{NAME} *interface, TALLOC_CTX *mem_ctx" . GetArgumentProtoList($d) . ");\n";
|
||||
$res .= "#define $if->{NAME}_${defname}_send(interface, mem_ctx" . GetArgumentList($d, "in") . ") ";
|
||||
$res .= "((interface)->vtable->$d->{NAME}_send(interface, mem_ctx" . GetArgumentList($d, "in") . "))";
|
||||
$res .="\n";
|
||||
# $res .= "#define $if->{NAME}_${defname}_recv(c" . GetArgumentList($d, "out") . ") ";
|
||||
# $res .= "((interface)->vtable->$d->{NAME}_recv(c" . GetArgumentList($d, "out") . "))";
|
||||
$res .= mapType($d->{RETURN_TYPE}) . " $if->{NAME}_${defname}_recv(struct composite_context *c" . GetArgumentProtoList($d, "out") . ");\n";
|
||||
$res .="\n";
|
||||
}
|
||||
$res .= "\nNTSTATUS dcom_proxy_$if->{NAME}_init(void);\n";
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub ParseCoClass($)
|
||||
{
|
||||
my $c = shift;
|
||||
my $res = "";
|
||||
$res .= "#define CLSID_" . uc($c->{NAME}) . " $c->{PROPERTIES}->{uuid}\n";
|
||||
if (has_property($c, "progid")) {
|
||||
$res .= "#define PROGID_" . uc($c->{NAME}) . " $c->{PROPERTIES}->{progid}\n";
|
||||
}
|
||||
$res .= "\n";
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub Parse($$)
|
||||
{
|
||||
my ($idl,$ndr_header) = @_;
|
||||
my $res = "";
|
||||
|
||||
$res .= "#include \"librpc/gen_ndr/orpc.h\"\n" .
|
||||
"#include \"$ndr_header\"\n\n";
|
||||
|
||||
foreach (@{$idl})
|
||||
{
|
||||
if ($_->{TYPE} eq "INTERFACE" && has_property($_, "object")) {
|
||||
$res.="struct $_->{NAME};\n";
|
||||
foreach my $s (@{$_->{DATA}}) {
|
||||
next if ($s->{TYPE} ne "TYPEDEF" || defined($s->{DATA_TYPE}) || $s->{DATA}{TYPE} ne "STRUCT");
|
||||
$res.="struct $s->{NAME};\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (@{$idl})
|
||||
{
|
||||
if ($_->{TYPE} eq "INTERFACE" && has_property($_, "object")) {
|
||||
$res.=ParseInterface($_);
|
||||
}
|
||||
|
||||
if ($_->{TYPE} eq "COCLASS") {
|
||||
$res.=ParseCoClass($_);
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,397 @@
|
||||
###################################################
|
||||
# DCOM parser for Samba
|
||||
# Basically the glue between COM and DCE/RPC with NDR
|
||||
# Copyright jelmer@samba.org 2003-2005
|
||||
# released under the GNU GPL
|
||||
|
||||
package Parse::Pidl::Samba4::COM::Proxy;
|
||||
|
||||
use Parse::Pidl::Samba4::COM::Header;
|
||||
use Parse::Pidl::Util qw(has_property);
|
||||
use Parse::Pidl::Typelist qw(mapType);
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '0.01';
|
||||
|
||||
use strict;
|
||||
|
||||
my($res);
|
||||
|
||||
sub ParseVTable($$)
|
||||
{
|
||||
my $interface = shift;
|
||||
my $name = shift;
|
||||
|
||||
# Generate the vtable
|
||||
$res .="\tstruct $interface->{NAME}_vtable $name = {";
|
||||
|
||||
if (defined($interface->{BASE})) {
|
||||
$res .= "\n\t\t{},";
|
||||
}
|
||||
|
||||
my $data = $interface->{DATA};
|
||||
|
||||
foreach my $d (@{$data}) {
|
||||
if ($d->{TYPE} eq "FUNCTION") {
|
||||
$res .= "\n\t\tdcom_proxy_$interface->{NAME}_$d->{NAME}";
|
||||
$res .= ",";
|
||||
}
|
||||
}
|
||||
|
||||
$res .= "\n\t};\n\n";
|
||||
}
|
||||
|
||||
sub ParseRegFunc($)
|
||||
{
|
||||
my $interface = shift;
|
||||
|
||||
$res .= "\nNTSTATUS dcom_proxy_$interface->{NAME}_init(void)
|
||||
{
|
||||
struct $interface->{NAME}_vtable *proxy_vtable = talloc(talloc_autofree_context(), struct $interface->{NAME}_vtable);
|
||||
";
|
||||
|
||||
if (defined($interface->{BASE})) {
|
||||
$res.= "
|
||||
struct GUID base_iid;
|
||||
const void *base_vtable;
|
||||
|
||||
base_iid = dcerpc_table_$interface->{BASE}.syntax_id.uuid;
|
||||
|
||||
base_vtable = dcom_proxy_vtable_by_iid(&base_iid);
|
||||
if (base_vtable == NULL) {
|
||||
DEBUG(0, (\"No proxy registered for base interface '$interface->{BASE}'\\n\"));
|
||||
return NT_STATUS_FOOBAR;
|
||||
}
|
||||
|
||||
memcpy(proxy_vtable, base_vtable, sizeof(struct $interface->{BASE}_vtable));
|
||||
|
||||
";
|
||||
}
|
||||
foreach my $x (@{$interface->{DATA}}) {
|
||||
next unless ($x->{TYPE} eq "FUNCTION");
|
||||
|
||||
# $res .= "\tproxy_vtable->$x->{NAME} = dcom_proxy_$interface->{NAME}_$x->{NAME};\n";
|
||||
$res .= "\tproxy_vtable->$x->{NAME}_send = dcom_proxy_$interface->{NAME}_$x->{NAME}_send;\n";
|
||||
}
|
||||
|
||||
$res.= "
|
||||
proxy_vtable->iid = dcerpc_table_$interface->{NAME}.syntax_id.uuid;
|
||||
|
||||
return dcom_register_proxy((struct IUnknown_vtable *)proxy_vtable);
|
||||
}\n\n";
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# parse a function
|
||||
sub ParseFunction($$)
|
||||
{
|
||||
my $interface = shift;
|
||||
my $fn = shift;
|
||||
my $name = $fn->{NAME};
|
||||
my $short_name = ($fn->{NAME} =~ /^$interface->{NAME}_(.*)$/) ? $1 : $fn->{NAME};
|
||||
my $uname = uc $name;
|
||||
my $args_in = 0;
|
||||
my $args_out = 0;
|
||||
my $if_in = 0;
|
||||
my $if_out = 0;
|
||||
|
||||
foreach my $a (@{$fn->{ELEMENTS}}) {
|
||||
$args_in++ if has_property($a, "in");
|
||||
$args_out++ if has_property($a, "out");
|
||||
$if_in++ if (Parse::Pidl::Typelist::typeIs($a->{TYPE}, "INTERFACE") && has_property($a, "in"));
|
||||
$if_out++ if (Parse::Pidl::Typelist::typeIs($a->{TYPE}, "INTERFACE") && has_property($a, "out"));
|
||||
}
|
||||
$args_out++ if $fn->{RETURN_TYPE} ne "void";
|
||||
|
||||
#### declarations ############################################
|
||||
$res.="
|
||||
static void dcom_proxy_$interface->{NAME}_${name}_recv_rpc(struct rpc_request *req);
|
||||
";
|
||||
##### *_out struct ###########################################
|
||||
if ($args_out > 0) {
|
||||
$res.="
|
||||
struct $interface->{NAME}_${name}_out {
|
||||
";
|
||||
foreach my $a (@{$fn->{ELEMENTS}}) {
|
||||
next unless (has_property($a, "out"));
|
||||
my $decl = Parse::Pidl::Samba4::COM::Header::GetArgumentProto($a);
|
||||
$decl =~ s/ \*/ /;
|
||||
$res.= "\t" . $decl . ";\n";
|
||||
}
|
||||
if ($fn->{RETURN_TYPE} ne "void") {
|
||||
$res.= "\t" . mapType($fn->{RETURN_TYPE}) . " result;\n";
|
||||
}
|
||||
$res.="};\n";
|
||||
}
|
||||
|
||||
#### *_send ##################################################
|
||||
$res.="
|
||||
static struct composite_context *dcom_proxy_$interface->{NAME}_${name}_send(struct $interface->{NAME} *d, TALLOC_CTX *mem_ctx" . Parse::Pidl::Samba4::COM::Header::GetArgumentProtoList($fn, "in") . ")
|
||||
{
|
||||
struct composite_context *c, *c_pipe;
|
||||
struct dcom_proxy_async_call_state *s;
|
||||
struct ${name} *r;
|
||||
" . ($if_in > 0 ? "\tNTSTATUS status;\n" : "" ) . "
|
||||
c = composite_create(mem_ctx, d->ctx->event_ctx);
|
||||
if (c == NULL) return NULL;
|
||||
|
||||
s = talloc_zero(c, struct dcom_proxy_async_call_state);
|
||||
if (composite_nomem(s, c)) return c;
|
||||
c->private_data = s;
|
||||
|
||||
r = talloc_zero(s, struct ${name});
|
||||
if (composite_nomem(r, c)) return c;
|
||||
|
||||
s->d = (struct IUnknown *)d;
|
||||
s->table = &dcerpc_table_$interface->{NAME};
|
||||
s->opnum = DCERPC_$uname;
|
||||
s->continuation = dcom_proxy_$interface->{NAME}_${name}_recv_rpc;
|
||||
s->mem_ctx = mem_ctx;
|
||||
s->r = r;
|
||||
|
||||
r->in.ORPCthis.version.MajorVersion = COM_MAJOR_VERSION;
|
||||
r->in.ORPCthis.version.MinorVersion = COM_MINOR_VERSION;
|
||||
r->in.ORPCthis.cid = GUID_random();
|
||||
";
|
||||
# Put arguments into r
|
||||
foreach my $a (@{$fn->{ELEMENTS}}) {
|
||||
next unless (has_property($a, "in"));
|
||||
if (Parse::Pidl::Typelist::typeIs($a->{TYPE}, "INTERFACE")) {
|
||||
my $varname;
|
||||
my $ctx = "mem_ctx";
|
||||
my $n;
|
||||
foreach $n (0..$a->{POINTERS}-1) {
|
||||
$res .=sprintf(("\t" x $n)."\tif (%s$a->{NAME}) {\n", ("*" x $n));
|
||||
$varname = ("*" x $n) . "r->in.$a->{NAME}";
|
||||
$res .=sprintf(("\t" x $n)."\t\t$varname = talloc_zero($ctx, struct MInterfacePointer%s);\n", ("*" x ($a->{POINTERS}-$n-1)));
|
||||
$ctx = $varname;
|
||||
}
|
||||
$n = $a->{POINTERS}-1;
|
||||
$res .=("\t" x $n)."\t\t(${varname})->size = sizeof(struct OBJREF);\n";
|
||||
$res .=sprintf(("\t" x $n)."\t\tstatus = dcom_OBJREF_from_IUnknown(&(*$varname).obj, (struct IUnknown *)%s$a->{NAME});\n", ("*" x ($a->{POINTERS}-1)));
|
||||
$res .= ("\t" x $n)."\t\tif (!NT_STATUS_IS_OK(status)) {\n"
|
||||
. ("\t" x $n)."\t\t\tcomposite_error(c, NT_STATUS_RPC_NT_CALL_FAILED);\n"
|
||||
. ("\t" x $n)."\t\t\treturn c;\n"
|
||||
. ("\t" x $n)."\t\t}\n";
|
||||
for ($n =$a->{POINTERS}; $n > 0; --$n) {
|
||||
$res .=("\t" x $n)."}\n";
|
||||
}
|
||||
} else {
|
||||
$res .= "\tr->in.$a->{NAME} = $a->{NAME};\n";
|
||||
}
|
||||
}
|
||||
|
||||
$res .="
|
||||
if (DEBUGLVL(12)) {
|
||||
NDR_PRINT_IN_DEBUG(${name}, r);
|
||||
}
|
||||
|
||||
c_pipe = dcom_get_pipe_send((struct IUnknown *)d, mem_ctx);
|
||||
composite_continue(c, c_pipe, dcom_proxy_async_call_recv_pipe_send_rpc, c);
|
||||
|
||||
return c;
|
||||
}
|
||||
";
|
||||
|
||||
#### *_recv_rpc ##############################################
|
||||
$res.="
|
||||
static void dcom_proxy_$interface->{NAME}_${name}_recv_rpc(struct rpc_request *req)
|
||||
{
|
||||
struct composite_context *c;
|
||||
struct dcom_proxy_async_call_state *s;
|
||||
struct $interface->{NAME}_${name}_out *out;
|
||||
struct ${name} *r;
|
||||
struct ORPCTHAT that;
|
||||
NTSTATUS status;
|
||||
";
|
||||
foreach my $a (@{$fn->{ELEMENTS}}) {
|
||||
next unless (has_property($a, "out"));
|
||||
if (Parse::Pidl::Typelist::typeIs($a->{TYPE}, "INTERFACE")) {
|
||||
$res.="\tstruct MInterfacePointer *mip_$a->{NAME};\n";
|
||||
}
|
||||
}
|
||||
|
||||
$res.="
|
||||
c = req->async.private;
|
||||
s = c->private_data;
|
||||
r = s->r;
|
||||
out = talloc_zero(c, struct $interface->{NAME}_${name}_out);
|
||||
if (composite_nomem(out, c)) return;
|
||||
c->private_data = out;
|
||||
|
||||
r->out.ORPCthat = &that;
|
||||
";
|
||||
foreach $a (@{$fn->{ELEMENTS}}) {
|
||||
next unless (has_property($a, "out"));
|
||||
|
||||
if (Parse::Pidl::Typelist::typeIs($a->{TYPE}, "INTERFACE")) {
|
||||
$res.="\tr->out.$a->{NAME} = &mip_$a->{NAME};\n";
|
||||
} else {
|
||||
$res.="\tr->out.$a->{NAME} = &out->$a->{NAME};\n";
|
||||
}
|
||||
}
|
||||
|
||||
$res.="
|
||||
status = dcerpc_ndr_request_recv(req);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
composite_error(c, NT_STATUS_RPC_NT_CALL_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUGLVL(12)) {
|
||||
NDR_PRINT_OUT_DEBUG(${name}, r);
|
||||
}
|
||||
";
|
||||
foreach $a (@{$fn->{ELEMENTS}}) {
|
||||
next unless (has_property($a, "out"));
|
||||
|
||||
if (Parse::Pidl::Typelist::typeIs($a->{TYPE}, "INTERFACE")) {
|
||||
$res .=
|
||||
" if (r->out.$a->{NAME} && *r->out.$a->{NAME}) {
|
||||
status = dcom_IUnknown_from_OBJREF(s->d->ctx, (struct IUnknown **)&out->$a->{NAME}, &(**r->out.$a->{NAME}).obj);
|
||||
if (*r->out.$a->{NAME}) talloc_free(*r->out.$a->{NAME});
|
||||
} else {
|
||||
out->$a->{NAME} = NULL;
|
||||
}
|
||||
";
|
||||
} elsif (defined($a->{POINTERS}) and $a->{POINTERS} > 1) {
|
||||
$res .=
|
||||
" talloc_steal(s->mem_ctx, out->$a->{NAME});
|
||||
";
|
||||
}
|
||||
}
|
||||
|
||||
if ($fn->{RETURN_TYPE} ne "void") {
|
||||
$res.="\tout->result = r->out.result;\n";
|
||||
}
|
||||
$res .="
|
||||
talloc_free(s);
|
||||
composite_done(c);
|
||||
}
|
||||
";
|
||||
|
||||
#### *_recv ##################################################
|
||||
$res.="
|
||||
" . mapType($fn->{RETURN_TYPE}) . " $interface->{NAME}_${name}_recv(struct composite_context *c" . Parse::Pidl::Samba4::COM::Header::GetArgumentProtoList($fn, "out") . ")
|
||||
{
|
||||
struct $interface->{NAME}_${name}_out *out;
|
||||
NTSTATUS status;
|
||||
" . (($fn->{RETURN_TYPE} ne "void") ? "\t" . mapType($fn->{RETURN_TYPE}) . " result;\n" : "") . "
|
||||
status = composite_wait(c);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
talloc_free(c);
|
||||
return";
|
||||
if ($fn->{RETURN_TYPE} eq "WERROR") {
|
||||
$res.=" ntstatus_to_werror(NT_STATUS_RPC_NT_CALL_FAILED)";
|
||||
} elsif($fn->{RETURN_TYPE} eq "uint32") {
|
||||
$res.=" 0";
|
||||
}
|
||||
$res .= ";
|
||||
}
|
||||
out = c->private_data;
|
||||
|
||||
";
|
||||
foreach $a (@{$fn->{ELEMENTS}}) {
|
||||
next unless (has_property($a, "out"));
|
||||
$res.="\tif ($a->{NAME}) *$a->{NAME} = out->$a->{NAME};\n";
|
||||
}
|
||||
if ($fn->{RETURN_TYPE} ne "void") {
|
||||
$res.="\tresult = out->result;\n";
|
||||
}
|
||||
$res .= "
|
||||
talloc_free(c);
|
||||
" . (($fn->{RETURN_TYPE} ne "void") ? "\treturn result;" : "") . "
|
||||
}
|
||||
";
|
||||
|
||||
#### * sync ##################################################
|
||||
$res.="
|
||||
" . mapType($fn->{RETURN_TYPE}) . " $interface->{NAME}_${short_name}(struct $interface->{NAME} *d, TALLOC_CTX *mem_ctx" . Parse::Pidl::Samba4::COM::Header::GetArgumentProtoList($fn) . ")
|
||||
{
|
||||
struct composite_context *c;
|
||||
|
||||
c = $interface->{NAME}_${short_name}_send(d, mem_ctx" . Parse::Pidl::Samba4::COM::Header::GetArgumentList($fn, "in") . ");
|
||||
if (c == NULL) return";
|
||||
if ($fn->{RETURN_TYPE} eq "WERROR") {
|
||||
$res.=" WERR_NOMEM";
|
||||
} elsif($fn->{RETURN_TYPE} eq "uint32") {
|
||||
$res.=" 0";
|
||||
}
|
||||
$res.=";
|
||||
|
||||
" . (($fn->{RETURN_TYPE} ne "void") ? "return " : "") . "$interface->{NAME}_${name}_recv(c" . Parse::Pidl::Samba4::COM::Header::GetArgumentList($fn, "out") . ");
|
||||
}
|
||||
";
|
||||
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# parse the interface definitions
|
||||
sub ParseInterface($)
|
||||
{
|
||||
my($interface) = shift;
|
||||
my($data) = $interface->{DATA};
|
||||
$res = "/* DCOM proxy for $interface->{NAME} generated by pidl */\n\n";
|
||||
foreach my $d (@{$data}) {
|
||||
($d->{TYPE} eq "FUNCTION") &&
|
||||
ParseFunction($interface, $d);
|
||||
}
|
||||
|
||||
ParseRegFunc($interface);
|
||||
}
|
||||
|
||||
sub RegistrationFunction($$)
|
||||
{
|
||||
my $idl = shift;
|
||||
my $basename = shift;
|
||||
|
||||
my $res = "\n\nNTSTATUS dcom_$basename\_init(void)\n";
|
||||
$res .= "{\n";
|
||||
$res .="\tNTSTATUS status = NT_STATUS_OK;\n";
|
||||
foreach my $interface (@{$idl}) {
|
||||
next if $interface->{TYPE} ne "INTERFACE";
|
||||
next if not has_property($interface, "object");
|
||||
|
||||
my $data = $interface->{DATA};
|
||||
my $count = 0;
|
||||
foreach my $d (@{$data}) {
|
||||
if ($d->{TYPE} eq "FUNCTION") { $count++; }
|
||||
}
|
||||
|
||||
next if ($count == 0);
|
||||
|
||||
$res .= "\tstatus = dcom_$interface->{NAME}_init();\n";
|
||||
$res .= "\tif (NT_STATUS_IS_ERR(status)) {\n";
|
||||
$res .= "\t\treturn status;\n";
|
||||
$res .= "\t}\n\n";
|
||||
}
|
||||
$res .= "\treturn status;\n";
|
||||
$res .= "}\n\n";
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub Parse($$)
|
||||
{
|
||||
my ($pidl,$comh_filename) = @_;
|
||||
my $res = "";
|
||||
|
||||
$res .= "#include \"includes.h\"\n" .
|
||||
"#include \"librpc/rpc/dcerpc.h\"\n" .
|
||||
"#include \"lib/com/dcom/dcom.h\"\n" .
|
||||
"#include \"$comh_filename\"\n" .
|
||||
"#include \"libcli/composite/composite.h\"\n";
|
||||
|
||||
|
||||
foreach (@{$pidl}) {
|
||||
next if ($_->{TYPE} ne "INTERFACE");
|
||||
next if has_property($_, "local");
|
||||
next unless has_property($_, "object");
|
||||
|
||||
$res .= ParseInterface($_);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,327 @@
|
||||
###################################################
|
||||
# DCOM stub boilerplate generator
|
||||
# Copyright jelmer@samba.org 2004-2005
|
||||
# Copyright tridge@samba.org 2003
|
||||
# Copyright metze@samba.org 2004
|
||||
# released under the GNU GPL
|
||||
|
||||
package Parse::Pidl::Samba4::COM::Stub;
|
||||
|
||||
use Parse::Pidl::Util qw(has_property);
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '0.01';
|
||||
|
||||
my($res);
|
||||
|
||||
sub pidl($)
|
||||
{
|
||||
$res .= shift;
|
||||
}
|
||||
|
||||
#####################################################
|
||||
# generate the switch statement for function dispatch
|
||||
sub gen_dispatch_switch($)
|
||||
{
|
||||
my $data = shift;
|
||||
|
||||
my $count = 0;
|
||||
foreach my $d (@{$data}) {
|
||||
next if ($d->{TYPE} ne "FUNCTION");
|
||||
|
||||
pidl "\tcase $count: {\n";
|
||||
if ($d->{RETURN_TYPE} && $d->{RETURN_TYPE} ne "void") {
|
||||
pidl "\t\tNTSTATUS result;\n";
|
||||
}
|
||||
pidl "\t\tstruct $d->{NAME} *r2 = r;\n";
|
||||
pidl "\t\tif (DEBUGLEVEL > 10) {\n";
|
||||
pidl "\t\t\tNDR_PRINT_FUNCTION_DEBUG($d->{NAME}, NDR_IN, r2);\n";
|
||||
pidl "\t\t}\n";
|
||||
if ($d->{RETURN_TYPE} && $d->{RETURN_TYPE} ne "void") {
|
||||
pidl "\t\tresult = vtable->$d->{NAME}(iface, mem_ctx, r2);\n";
|
||||
} else {
|
||||
pidl "\t\tvtable->$d->{NAME}(iface, mem_ctx, r2);\n";
|
||||
}
|
||||
pidl "\t\tif (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {\n";
|
||||
pidl "\t\t\tDEBUG(5,(\"function $d->{NAME} will reply async\\n\"));\n";
|
||||
pidl "\t\t}\n";
|
||||
pidl "\t\tbreak;\n\t}\n";
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
#####################################################
|
||||
# generate the switch statement for function reply
|
||||
sub gen_reply_switch($)
|
||||
{
|
||||
my $data = shift;
|
||||
|
||||
my $count = 0;
|
||||
foreach my $d (@{$data}) {
|
||||
next if ($d->{TYPE} ne "FUNCTION");
|
||||
|
||||
pidl "\tcase $count: {\n";
|
||||
pidl "\t\tstruct $d->{NAME} *r2 = r;\n";
|
||||
pidl "\t\tif (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {\n";
|
||||
pidl "\t\t\tDEBUG(5,(\"function $d->{NAME} replied async\\n\"));\n";
|
||||
pidl "\t\t}\n";
|
||||
pidl "\t\tif (DEBUGLEVEL > 10 && dce_call->fault_code == 0) {\n";
|
||||
pidl "\t\t\tNDR_PRINT_FUNCTION_DEBUG($d->{NAME}, NDR_OUT | NDR_SET_VALUES, r2);\n";
|
||||
pidl "\t\t}\n";
|
||||
pidl "\t\tif (dce_call->fault_code != 0) {\n";
|
||||
pidl "\t\t\tDEBUG(2,(\"dcerpc_fault %s in $d->{NAME}\\n\", dcerpc_errstr(mem_ctx, dce_call->fault_code)));\n";
|
||||
pidl "\t\t}\n";
|
||||
pidl "\t\tbreak;\n\t}\n";
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# produce boilerplate code for a interface
|
||||
sub Boilerplate_Iface($)
|
||||
{
|
||||
my($interface) = shift;
|
||||
my($data) = $interface->{DATA};
|
||||
my $name = $interface->{NAME};
|
||||
my $uname = uc $name;
|
||||
my $uuid = Parse::Pidl::Util::make_str($interface->{PROPERTIES}->{uuid});
|
||||
my $if_version = $interface->{PROPERTIES}->{version};
|
||||
|
||||
pidl "
|
||||
static NTSTATUS $name\__op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
|
||||
{
|
||||
#ifdef DCESRV_INTERFACE_$uname\_BIND
|
||||
return DCESRV_INTERFACE_$uname\_BIND(dce_call,iface);
|
||||
#else
|
||||
return NT_STATUS_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void $name\__op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)
|
||||
{
|
||||
#ifdef DCESRV_INTERFACE_$uname\_UNBIND
|
||||
DCESRV_INTERFACE_$uname\_UNBIND(context, iface);
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
static NTSTATUS $name\__op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
|
||||
{
|
||||
NTSTATUS status;
|
||||
uint16_t opnum = dce_call->pkt.u.request.opnum;
|
||||
|
||||
dce_call->fault_code = 0;
|
||||
|
||||
if (opnum >= dcerpc_table_$name.num_calls) {
|
||||
dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
|
||||
return NT_STATUS_NET_WRITE_FAULT;
|
||||
}
|
||||
|
||||
*r = talloc_size(mem_ctx, dcerpc_table_$name.calls[opnum].struct_size);
|
||||
NT_STATUS_HAVE_NO_MEMORY(*r);
|
||||
|
||||
/* unravel the NDR for the packet */
|
||||
status = dcerpc_table_$name.calls[opnum].ndr_pull(pull, NDR_IN, *r);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
dcerpc_log_packet(&dcerpc_table_$name, opnum, NDR_IN,
|
||||
&dce_call->pkt.u.request.stub_and_verifier);
|
||||
dce_call->fault_code = DCERPC_FAULT_NDR;
|
||||
return NT_STATUS_NET_WRITE_FAULT;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS $name\__op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
|
||||
{
|
||||
uint16_t opnum = dce_call->pkt.u.request.opnum;
|
||||
struct GUID ipid = dce_call->pkt.u.request.object.object;
|
||||
struct dcom_interface_p *iface = dcom_get_local_iface_p(&ipid);
|
||||
const struct dcom_$name\_vtable *vtable = iface->vtable;
|
||||
|
||||
switch (opnum) {
|
||||
";
|
||||
gen_dispatch_switch($data);
|
||||
|
||||
pidl "
|
||||
default:
|
||||
dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dce_call->fault_code != 0) {
|
||||
dcerpc_log_packet(&dcerpc_table_$name, opnum, NDR_IN,
|
||||
&dce_call->pkt.u.request.stub_and_verifier);
|
||||
return NT_STATUS_NET_WRITE_FAULT;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS $name\__op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
|
||||
{
|
||||
uint16_t opnum = dce_call->pkt.u.request.opnum;
|
||||
|
||||
switch (opnum) {
|
||||
";
|
||||
gen_reply_switch($data);
|
||||
|
||||
pidl "
|
||||
default:
|
||||
dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dce_call->fault_code != 0) {
|
||||
dcerpc_log_packet(&dcerpc_table_$name, opnum, NDR_IN,
|
||||
&dce_call->pkt.u.request.stub_and_verifier);
|
||||
return NT_STATUS_NET_WRITE_FAULT;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS $name\__op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)
|
||||
{
|
||||
NTSTATUS status;
|
||||
uint16_t opnum = dce_call->pkt.u.request.opnum;
|
||||
|
||||
status = dcerpc_table_$name.calls[opnum].ndr_push(push, NDR_OUT, r);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
dce_call->fault_code = DCERPC_FAULT_NDR;
|
||||
return NT_STATUS_NET_WRITE_FAULT;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static const struct dcesrv_interface $name\_interface = {
|
||||
.name = \"$name\",
|
||||
.uuid = $uuid,
|
||||
.if_version = $if_version,
|
||||
.bind = $name\__op_bind,
|
||||
.unbind = $name\__op_unbind,
|
||||
.ndr_pull = $name\__op_ndr_pull,
|
||||
.dispatch = $name\__op_dispatch,
|
||||
.reply = $name\__op_reply,
|
||||
.ndr_push = $name\__op_ndr_push
|
||||
};
|
||||
|
||||
";
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# produce boilerplate code for an endpoint server
|
||||
sub Boilerplate_Ep_Server($)
|
||||
{
|
||||
my($interface) = shift;
|
||||
my $name = $interface->{NAME};
|
||||
my $uname = uc $name;
|
||||
|
||||
pidl "
|
||||
static NTSTATUS $name\__op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;i<dcerpc_table_$name.endpoints->count;i++) {
|
||||
NTSTATUS ret;
|
||||
const char *name = dcerpc_table_$name.endpoints->names[i];
|
||||
|
||||
ret = dcesrv_interface_register(dce_ctx, name, &$name\_interface, NULL);
|
||||
if (!NT_STATUS_IS_OK(ret)) {
|
||||
DEBUG(1,(\"$name\_op_init_server: failed to register endpoint \'%s\'\\n\",name));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static BOOL $name\__op_interface_by_uuid(struct dcesrv_interface *iface, const char *uuid, uint32_t if_version)
|
||||
{
|
||||
if (dcerpc_table_$name.if_version == if_version &&
|
||||
strcmp(dcerpc_table_$name.uuid, uuid)==0) {
|
||||
memcpy(iface,&dcerpc_table_$name, sizeof(*iface));
|
||||
return True;
|
||||
}
|
||||
|
||||
return False;
|
||||
}
|
||||
|
||||
static BOOL $name\__op_interface_by_name(struct dcesrv_interface *iface, const char *name)
|
||||
{
|
||||
if (strcmp(dcerpc_table_$name.name, name)==0) {
|
||||
memcpy(iface,&dcerpc_table_$name, sizeof(*iface));
|
||||
return True;
|
||||
}
|
||||
|
||||
return False;
|
||||
}
|
||||
|
||||
NTSTATUS dcerpc_server_$name\_init(void)
|
||||
{
|
||||
NTSTATUS ret;
|
||||
struct dcesrv_endpoint_server ep_server;
|
||||
|
||||
/* fill in our name */
|
||||
ep_server.name = \"$name\";
|
||||
|
||||
/* fill in all the operations */
|
||||
ep_server.init_server = $name\__op_init_server;
|
||||
|
||||
ep_server.interface_by_uuid = $name\__op_interface_by_uuid;
|
||||
ep_server.interface_by_name = $name\__op_interface_by_name;
|
||||
|
||||
/* register ourselves with the DCERPC subsystem. */
|
||||
ret = dcerpc_register_ep_server(&ep_server);
|
||||
|
||||
if (!NT_STATUS_IS_OK(ret)) {
|
||||
DEBUG(0,(\"Failed to register \'$name\' endpoint server!\\n\"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
";
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# dcom interface stub from a parsed IDL structure
|
||||
sub ParseInterface($)
|
||||
{
|
||||
my($interface) = shift;
|
||||
|
||||
return "" if has_property($interface, "local");
|
||||
|
||||
my($data) = $interface->{DATA};
|
||||
my $count = 0;
|
||||
|
||||
$res = "";
|
||||
|
||||
if (!defined $interface->{PROPERTIES}->{uuid}) {
|
||||
return $res;
|
||||
}
|
||||
|
||||
if (!defined $interface->{PROPERTIES}->{version}) {
|
||||
$interface->{PROPERTIES}->{version} = "0.0";
|
||||
}
|
||||
|
||||
foreach my $d (@{$data}) {
|
||||
if ($d->{TYPE} eq "FUNCTION") { $count++; }
|
||||
}
|
||||
|
||||
if ($count == 0) {
|
||||
return $res;
|
||||
}
|
||||
|
||||
$res = "/* dcom interface stub generated by pidl */\n\n";
|
||||
Boilerplate_Iface($interface);
|
||||
Boilerplate_Ep_Server($interface);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,902 @@
|
||||
###################################################
|
||||
# EJS function wrapper generator
|
||||
# Copyright jelmer@samba.org 2005
|
||||
# Copyright Andrew Tridgell 2005
|
||||
# released under the GNU GPL
|
||||
|
||||
package Parse::Pidl::Samba4::EJS;
|
||||
|
||||
use strict;
|
||||
use Parse::Pidl::Typelist;
|
||||
use Parse::Pidl::Util qw(has_property);
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '0.01';
|
||||
|
||||
my $res;
|
||||
my $res_hdr;
|
||||
|
||||
my %constants;
|
||||
|
||||
my $tabs = "";
|
||||
|
||||
sub pidl_hdr ($)
|
||||
{
|
||||
$res_hdr .= shift;
|
||||
}
|
||||
|
||||
sub pidl($)
|
||||
{
|
||||
my $d = shift;
|
||||
if ($d) {
|
||||
$res .= $tabs;
|
||||
$res .= $d;
|
||||
}
|
||||
$res .= "\n";
|
||||
}
|
||||
|
||||
sub indent()
|
||||
{
|
||||
$tabs .= "\t";
|
||||
}
|
||||
|
||||
sub deindent()
|
||||
{
|
||||
$tabs = substr($tabs, 0, -1);
|
||||
}
|
||||
|
||||
# this should probably be in ndr.pm
|
||||
sub GenerateStructEnv($)
|
||||
{
|
||||
my $x = shift;
|
||||
my %env;
|
||||
|
||||
foreach my $e (@{$x->{ELEMENTS}}) {
|
||||
if ($e->{NAME}) {
|
||||
$env{$e->{NAME}} = "r->$e->{NAME}";
|
||||
}
|
||||
}
|
||||
|
||||
$env{"this"} = "r";
|
||||
|
||||
return \%env;
|
||||
}
|
||||
|
||||
sub GenerateFunctionInEnv($)
|
||||
{
|
||||
my $fn = shift;
|
||||
my %env;
|
||||
|
||||
foreach my $e (@{$fn->{ELEMENTS}}) {
|
||||
if (grep (/in/, @{$e->{DIRECTION}})) {
|
||||
$env{$e->{NAME}} = "r->in.$e->{NAME}";
|
||||
}
|
||||
}
|
||||
|
||||
return \%env;
|
||||
}
|
||||
|
||||
sub GenerateFunctionOutEnv($)
|
||||
{
|
||||
my $fn = shift;
|
||||
my %env;
|
||||
|
||||
foreach my $e (@{$fn->{ELEMENTS}}) {
|
||||
if (grep (/out/, @{$e->{DIRECTION}})) {
|
||||
$env{$e->{NAME}} = "r->out.$e->{NAME}";
|
||||
} elsif (grep (/in/, @{$e->{DIRECTION}})) {
|
||||
$env{$e->{NAME}} = "r->in.$e->{NAME}";
|
||||
}
|
||||
}
|
||||
|
||||
return \%env;
|
||||
}
|
||||
|
||||
sub get_pointer_to($)
|
||||
{
|
||||
my $var_name = shift;
|
||||
|
||||
if ($var_name =~ /^\*(.*)$/) {
|
||||
return $1;
|
||||
} elsif ($var_name =~ /^\&(.*)$/) {
|
||||
return "&($var_name)";
|
||||
} else {
|
||||
return "&$var_name";
|
||||
}
|
||||
}
|
||||
|
||||
sub get_value_of($)
|
||||
{
|
||||
my $var_name = shift;
|
||||
|
||||
if ($var_name =~ /^\&(.*)$/) {
|
||||
return $1;
|
||||
} else {
|
||||
return "*$var_name";
|
||||
}
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# 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;";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#####################################################################
|
||||
# work out is a parse function should be declared static or not
|
||||
sub fn_declare($$)
|
||||
{
|
||||
my ($fn,$decl) = @_;
|
||||
|
||||
if (has_property($fn, "public")) {
|
||||
pidl_hdr "$decl;\n";
|
||||
pidl "_PUBLIC_ $decl";
|
||||
} else {
|
||||
pidl "static $decl";
|
||||
}
|
||||
}
|
||||
|
||||
###########################
|
||||
# pull a scalar element
|
||||
sub EjsPullScalar($$$$$)
|
||||
{
|
||||
my ($e, $l, $var, $name, $env) = @_;
|
||||
|
||||
return if (has_property($e, "value"));
|
||||
|
||||
my $pl = Parse::Pidl::NDR::GetPrevLevel($e, $l);
|
||||
$var = get_pointer_to($var);
|
||||
# have to handle strings specially :(
|
||||
if ($e->{TYPE} eq "string" && $pl && $pl->{TYPE} eq "POINTER") {
|
||||
$var = get_pointer_to($var);
|
||||
}
|
||||
pidl "NDR_CHECK(ejs_pull_$e->{TYPE}(ejs, v, $name, $var));";
|
||||
}
|
||||
|
||||
###########################
|
||||
# pull a pointer element
|
||||
sub EjsPullPointer($$$$$)
|
||||
{
|
||||
my ($e, $l, $var, $name, $env) = @_;
|
||||
pidl "if (ejs_pull_null(ejs, v, $name)) {";
|
||||
indent;
|
||||
if ($l->{POINTER_TYPE} eq "ref") {
|
||||
pidl "return NT_STATUS_INVALID_PARAMETER_MIX;";
|
||||
} else {
|
||||
pidl "$var = NULL;";
|
||||
}
|
||||
deindent;
|
||||
pidl "} else {";
|
||||
indent;
|
||||
pidl "EJS_ALLOC(ejs, $var);";
|
||||
$var = get_value_of($var);
|
||||
EjsPullElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $var, $name, $env);
|
||||
deindent;
|
||||
pidl "}";
|
||||
}
|
||||
|
||||
###########################
|
||||
# pull a string element
|
||||
sub EjsPullString($$$$$)
|
||||
{
|
||||
my ($e, $l, $var, $name, $env) = @_;
|
||||
$var = get_pointer_to($var);
|
||||
pidl "NDR_CHECK(ejs_pull_string(ejs, v, $name, $var));";
|
||||
}
|
||||
|
||||
|
||||
###########################
|
||||
# pull an array element
|
||||
sub EjsPullArray($$$$$)
|
||||
{
|
||||
my ($e, $l, $var, $name, $env) = @_;
|
||||
my $nl = Parse::Pidl::NDR::GetNextLevel($e, $l);
|
||||
my $length = Parse::Pidl::Util::ParseExpr($l->{LENGTH_IS}, $env);
|
||||
my $size = Parse::Pidl::Util::ParseExpr($l->{SIZE_IS}, $env);
|
||||
my $pl = Parse::Pidl::NDR::GetPrevLevel($e, $l);
|
||||
if ($pl && $pl->{TYPE} eq "POINTER") {
|
||||
$var = get_pointer_to($var);
|
||||
}
|
||||
# uint8 arrays are treated as data blobs
|
||||
if ($nl->{TYPE} eq 'DATA' && $e->{TYPE} eq 'uint8') {
|
||||
if (!$l->{IS_FIXED}) {
|
||||
check_null_pointer($size);
|
||||
pidl "EJS_ALLOC_N(ejs, $var, $size);";
|
||||
}
|
||||
check_null_pointer($length);
|
||||
pidl "ejs_pull_array_uint8(ejs, v, $name, $var, $length);";
|
||||
return;
|
||||
}
|
||||
my $avar = $var . "[i]";
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "uint32_t i;";
|
||||
if (!$l->{IS_FIXED}) {
|
||||
pidl "EJS_ALLOC_N(ejs, $var, $size);";
|
||||
}
|
||||
pidl "for (i=0;i<$length;i++) {";
|
||||
indent;
|
||||
pidl "char *id = talloc_asprintf(ejs, \"%s.%u\", $name, i);";
|
||||
EjsPullElement($e, $nl, $avar, "id", $env);
|
||||
pidl "talloc_free(id);";
|
||||
deindent;
|
||||
pidl "}";
|
||||
pidl "ejs_push_uint32(ejs, v, $name \".length\", &i);";
|
||||
deindent;
|
||||
pidl "}";
|
||||
}
|
||||
|
||||
###########################
|
||||
# pull a switch element
|
||||
sub EjsPullSwitch($$$$$)
|
||||
{
|
||||
my ($e, $l, $var, $name, $env) = @_;
|
||||
my $switch_var = Parse::Pidl::Util::ParseExpr($l->{SWITCH_IS}, $env);
|
||||
pidl "ejs_set_switch(ejs, $switch_var);";
|
||||
EjsPullElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $var, $name, $env);
|
||||
}
|
||||
|
||||
###########################
|
||||
# pull a structure element
|
||||
sub EjsPullElement($$$$$)
|
||||
{
|
||||
my ($e, $l, $var, $name, $env) = @_;
|
||||
if (has_property($e, "charset")) {
|
||||
EjsPullString($e, $l, $var, $name, $env);
|
||||
} elsif ($l->{TYPE} eq "ARRAY") {
|
||||
EjsPullArray($e, $l, $var, $name, $env);
|
||||
} elsif ($l->{TYPE} eq "DATA") {
|
||||
EjsPullScalar($e, $l, $var, $name, $env);
|
||||
} elsif (($l->{TYPE} eq "POINTER")) {
|
||||
EjsPullPointer($e, $l, $var, $name, $env);
|
||||
} elsif (($l->{TYPE} eq "SWITCH")) {
|
||||
EjsPullSwitch($e, $l, $var, $name, $env);
|
||||
} else {
|
||||
pidl "return ejs_panic(ejs, \"unhandled pull type $l->{TYPE}\");";
|
||||
}
|
||||
}
|
||||
|
||||
#############################################
|
||||
# pull a structure/union element at top level
|
||||
sub EjsPullElementTop($$)
|
||||
{
|
||||
my $e = shift;
|
||||
my $env = shift;
|
||||
my $l = $e->{LEVELS}[0];
|
||||
my $var = Parse::Pidl::Util::ParseExpr($e->{NAME}, $env);
|
||||
my $name = "\"$e->{NAME}\"";
|
||||
EjsPullElement($e, $l, $var, $name, $env);
|
||||
}
|
||||
|
||||
###########################
|
||||
# pull a struct
|
||||
sub EjsStructPull($$)
|
||||
{
|
||||
my $name = shift;
|
||||
my $d = shift;
|
||||
my $env = GenerateStructEnv($d);
|
||||
fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, struct $name *r)");
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, name));";
|
||||
foreach my $e (@{$d->{ELEMENTS}}) {
|
||||
EjsPullElementTop($e, $env);
|
||||
}
|
||||
pidl "return NT_STATUS_OK;";
|
||||
deindent;
|
||||
pidl "}\n";
|
||||
}
|
||||
|
||||
###########################
|
||||
# pull a union
|
||||
sub EjsUnionPull($$)
|
||||
{
|
||||
my $name = shift;
|
||||
my $d = shift;
|
||||
my $have_default = 0;
|
||||
my $env = GenerateStructEnv($d);
|
||||
fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, union $name *r)");
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, name));";
|
||||
pidl "switch (ejs->switch_var) {";
|
||||
indent;
|
||||
foreach my $e (@{$d->{ELEMENTS}}) {
|
||||
if ($e->{CASE} eq "default") {
|
||||
$have_default = 1;
|
||||
}
|
||||
pidl "$e->{CASE}:";
|
||||
indent;
|
||||
if ($e->{TYPE} ne "EMPTY") {
|
||||
EjsPullElementTop($e, $env);
|
||||
}
|
||||
pidl "break;";
|
||||
deindent;
|
||||
}
|
||||
if (! $have_default) {
|
||||
pidl "default:";
|
||||
indent;
|
||||
pidl "return ejs_panic(ejs, \"Bad switch value\");";
|
||||
deindent;
|
||||
}
|
||||
deindent;
|
||||
pidl "}";
|
||||
pidl "return NT_STATUS_OK;";
|
||||
deindent;
|
||||
pidl "}";
|
||||
}
|
||||
|
||||
##############################################
|
||||
# put the enum elements in the constants array
|
||||
sub EjsEnumConstant($)
|
||||
{
|
||||
my $d = shift;
|
||||
my $v = 0;
|
||||
foreach my $e (@{$d->{ELEMENTS}}) {
|
||||
my $el = $e;
|
||||
chomp $el;
|
||||
if ($el =~ /^(.*)=\s*(.*)\s*$/) {
|
||||
$el = $1;
|
||||
$v = $2;
|
||||
}
|
||||
$constants{$el} = $v;
|
||||
$v++;
|
||||
}
|
||||
}
|
||||
|
||||
###########################
|
||||
# pull a enum
|
||||
sub EjsEnumPull($$)
|
||||
{
|
||||
my $name = shift;
|
||||
my $d = shift;
|
||||
EjsEnumConstant($d);
|
||||
fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, enum $name *r)");
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "unsigned e;";
|
||||
pidl "NDR_CHECK(ejs_pull_enum(ejs, v, name, &e));";
|
||||
pidl "*r = e;";
|
||||
pidl "return NT_STATUS_OK;";
|
||||
deindent;
|
||||
pidl "}\n";
|
||||
}
|
||||
|
||||
###########################
|
||||
# pull a bitmap
|
||||
sub EjsBitmapPull($$)
|
||||
{
|
||||
my $name = shift;
|
||||
my $d = shift;
|
||||
my $type_fn = $d->{BASE_TYPE};
|
||||
my($type_decl) = Parse::Pidl::Typelist::mapType($d->{BASE_TYPE});
|
||||
fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, $type_decl *r)");
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "return ejs_pull_$type_fn(ejs, v, name, r);";
|
||||
deindent;
|
||||
pidl "}";
|
||||
}
|
||||
|
||||
|
||||
###########################
|
||||
# generate a structure pull
|
||||
sub EjsTypedefPull($)
|
||||
{
|
||||
my $d = shift;
|
||||
return if (has_property($d, "noejs"));
|
||||
if ($d->{DATA}->{TYPE} eq 'STRUCT') {
|
||||
EjsStructPull($d->{NAME}, $d->{DATA});
|
||||
} elsif ($d->{DATA}->{TYPE} eq 'UNION') {
|
||||
EjsUnionPull($d->{NAME}, $d->{DATA});
|
||||
} elsif ($d->{DATA}->{TYPE} eq 'ENUM') {
|
||||
EjsEnumPull($d->{NAME}, $d->{DATA});
|
||||
} elsif ($d->{DATA}->{TYPE} eq 'BITMAP') {
|
||||
EjsBitmapPull($d->{NAME}, $d->{DATA});
|
||||
} elsif ($d->{DATA}->{TYPE} eq 'DECORATED') {
|
||||
} else {
|
||||
warn "Unhandled pull typedef $d->{NAME} of type $d->{DATA}->{TYPE}";
|
||||
}
|
||||
}
|
||||
|
||||
#####################
|
||||
# generate a function
|
||||
sub EjsPullFunction($)
|
||||
{
|
||||
my $d = shift;
|
||||
my $env = GenerateFunctionInEnv($d);
|
||||
my $name = $d->{NAME};
|
||||
|
||||
pidl "\nstatic NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, struct $name *r)";
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, \"input\"));";
|
||||
|
||||
# we pull non-array elements before array elements as arrays
|
||||
# may have length_is() or size_is() properties that depend
|
||||
# on the non-array elements
|
||||
foreach my $e (@{$d->{ELEMENTS}}) {
|
||||
next unless (grep(/in/, @{$e->{DIRECTION}}));
|
||||
next if (has_property($e, "length_is") || has_property($e, "size_is"));
|
||||
EjsPullElementTop($e, $env);
|
||||
}
|
||||
|
||||
foreach my $e (@{$d->{ELEMENTS}}) {
|
||||
next unless (grep(/in/, @{$e->{DIRECTION}}));
|
||||
next unless (has_property($e, "length_is") || has_property($e, "size_is"));
|
||||
EjsPullElementTop($e, $env);
|
||||
}
|
||||
|
||||
pidl "return NT_STATUS_OK;";
|
||||
deindent;
|
||||
pidl "}\n";
|
||||
}
|
||||
|
||||
|
||||
###########################
|
||||
# push a scalar element
|
||||
sub EjsPushScalar($$$$$)
|
||||
{
|
||||
my ($e, $l, $var, $name, $env) = @_;
|
||||
# have to handle strings specially :(
|
||||
my $pl = Parse::Pidl::NDR::GetPrevLevel($e, $l);
|
||||
if ($e->{TYPE} ne "string" || ($pl && $pl->{TYPE} eq "POINTER")) {
|
||||
$var = get_pointer_to($var);
|
||||
}
|
||||
pidl "NDR_CHECK(ejs_push_$e->{TYPE}(ejs, v, $name, $var));";
|
||||
}
|
||||
|
||||
###########################
|
||||
# push a string element
|
||||
sub EjsPushString($$$$$)
|
||||
{
|
||||
my ($e, $l, $var, $name, $env) = @_;
|
||||
pidl "NDR_CHECK(ejs_push_string(ejs, v, $name, $var));";
|
||||
}
|
||||
|
||||
###########################
|
||||
# push a pointer element
|
||||
sub EjsPushPointer($$$$$)
|
||||
{
|
||||
my ($e, $l, $var, $name, $env) = @_;
|
||||
pidl "if (NULL == $var) {";
|
||||
indent;
|
||||
if ($l->{POINTER_TYPE} eq "ref") {
|
||||
pidl "return NT_STATUS_INVALID_PARAMETER_MIX;";
|
||||
} else {
|
||||
pidl "NDR_CHECK(ejs_push_null(ejs, v, $name));";
|
||||
}
|
||||
deindent;
|
||||
pidl "} else {";
|
||||
indent;
|
||||
$var = get_value_of($var);
|
||||
EjsPushElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $var, $name, $env);
|
||||
deindent;
|
||||
pidl "}";
|
||||
}
|
||||
|
||||
###########################
|
||||
# push a switch element
|
||||
sub EjsPushSwitch($$$$$)
|
||||
{
|
||||
my ($e, $l, $var, $name, $env) = @_;
|
||||
my $switch_var = Parse::Pidl::Util::ParseExpr($l->{SWITCH_IS}, $env);
|
||||
pidl "ejs_set_switch(ejs, $switch_var);";
|
||||
EjsPushElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $var, $name, $env);
|
||||
}
|
||||
|
||||
|
||||
###########################
|
||||
# push an array element
|
||||
sub EjsPushArray($$$$$)
|
||||
{
|
||||
my ($e, $l, $var, $name, $env) = @_;
|
||||
my $nl = Parse::Pidl::NDR::GetNextLevel($e, $l);
|
||||
my $length = Parse::Pidl::Util::ParseExpr($l->{LENGTH_IS}, $env);
|
||||
my $pl = Parse::Pidl::NDR::GetPrevLevel($e, $l);
|
||||
if ($pl && $pl->{TYPE} eq "POINTER") {
|
||||
$var = get_pointer_to($var);
|
||||
}
|
||||
# uint8 arrays are treated as data blobs
|
||||
if ($nl->{TYPE} eq 'DATA' && $e->{TYPE} eq 'uint8') {
|
||||
check_null_pointer($length);
|
||||
pidl "ejs_push_array_uint8(ejs, v, $name, $var, $length);";
|
||||
return;
|
||||
}
|
||||
my $avar = $var . "[i]";
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "uint32_t i;";
|
||||
pidl "for (i=0;i<$length;i++) {";
|
||||
indent;
|
||||
pidl "const char *id = talloc_asprintf(ejs, \"%s.%u\", $name, i);";
|
||||
EjsPushElement($e, $nl, $avar, "id", $env);
|
||||
deindent;
|
||||
pidl "}";
|
||||
pidl "ejs_push_uint32(ejs, v, $name \".length\", &i);";
|
||||
deindent;
|
||||
pidl "}";
|
||||
}
|
||||
|
||||
################################
|
||||
# push a structure/union element
|
||||
sub EjsPushElement($$$$$)
|
||||
{
|
||||
my ($e, $l, $var, $name, $env) = @_;
|
||||
if (has_property($e, "charset")) {
|
||||
EjsPushString($e, $l, $var, $name, $env);
|
||||
} elsif ($l->{TYPE} eq "ARRAY") {
|
||||
EjsPushArray($e, $l, $var, $name, $env);
|
||||
} elsif ($l->{TYPE} eq "DATA") {
|
||||
EjsPushScalar($e, $l, $var, $name, $env);
|
||||
} elsif (($l->{TYPE} eq "POINTER")) {
|
||||
EjsPushPointer($e, $l, $var, $name, $env);
|
||||
} elsif (($l->{TYPE} eq "SWITCH")) {
|
||||
EjsPushSwitch($e, $l, $var, $name, $env);
|
||||
} else {
|
||||
pidl "return ejs_panic(ejs, \"unhandled push type $l->{TYPE}\");";
|
||||
}
|
||||
}
|
||||
|
||||
#############################################
|
||||
# push a structure/union element at top level
|
||||
sub EjsPushElementTop($$)
|
||||
{
|
||||
my $e = shift;
|
||||
my $env = shift;
|
||||
my $l = $e->{LEVELS}[0];
|
||||
my $var = Parse::Pidl::Util::ParseExpr($e->{NAME}, $env);
|
||||
my $name = "\"$e->{NAME}\"";
|
||||
EjsPushElement($e, $l, $var, $name, $env);
|
||||
}
|
||||
|
||||
###########################
|
||||
# push a struct
|
||||
sub EjsStructPush($$)
|
||||
{
|
||||
my $name = shift;
|
||||
my $d = shift;
|
||||
my $env = GenerateStructEnv($d);
|
||||
fn_declare($d, "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const struct $name *r)");
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, name));";
|
||||
foreach my $e (@{$d->{ELEMENTS}}) {
|
||||
EjsPushElementTop($e, $env);
|
||||
}
|
||||
pidl "return NT_STATUS_OK;";
|
||||
deindent;
|
||||
pidl "}\n";
|
||||
}
|
||||
|
||||
###########################
|
||||
# push a union
|
||||
sub EjsUnionPush($$)
|
||||
{
|
||||
my $name = shift;
|
||||
my $d = shift;
|
||||
my $have_default = 0;
|
||||
my $env = GenerateStructEnv($d);
|
||||
fn_declare($d, "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const union $name *r)");
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, name));";
|
||||
pidl "switch (ejs->switch_var) {";
|
||||
indent;
|
||||
foreach my $e (@{$d->{ELEMENTS}}) {
|
||||
if ($e->{CASE} eq "default") {
|
||||
$have_default = 1;
|
||||
}
|
||||
pidl "$e->{CASE}:";
|
||||
indent;
|
||||
if ($e->{TYPE} ne "EMPTY") {
|
||||
EjsPushElementTop($e, $env);
|
||||
}
|
||||
pidl "break;";
|
||||
deindent;
|
||||
}
|
||||
if (! $have_default) {
|
||||
pidl "default:";
|
||||
indent;
|
||||
pidl "return ejs_panic(ejs, \"Bad switch value\");";
|
||||
deindent;
|
||||
}
|
||||
deindent;
|
||||
pidl "}";
|
||||
pidl "return NT_STATUS_OK;";
|
||||
deindent;
|
||||
pidl "}";
|
||||
}
|
||||
|
||||
###########################
|
||||
# push a enum
|
||||
sub EjsEnumPush($$)
|
||||
{
|
||||
my $name = shift;
|
||||
my $d = shift;
|
||||
EjsEnumConstant($d);
|
||||
fn_declare($d, "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const enum $name *r)");
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "unsigned e = *r;";
|
||||
pidl "NDR_CHECK(ejs_push_enum(ejs, v, name, &e));";
|
||||
pidl "return NT_STATUS_OK;";
|
||||
deindent;
|
||||
pidl "}\n";
|
||||
}
|
||||
|
||||
###########################
|
||||
# push a bitmap
|
||||
sub EjsBitmapPush($$)
|
||||
{
|
||||
my $name = shift;
|
||||
my $d = shift;
|
||||
my $type_fn = $d->{BASE_TYPE};
|
||||
my($type_decl) = Parse::Pidl::Typelist::mapType($d->{BASE_TYPE});
|
||||
# put the bitmap elements in the constants array
|
||||
foreach my $e (@{$d->{ELEMENTS}}) {
|
||||
if ($e =~ /^(\w*)\s*(.*)\s*$/) {
|
||||
my $bname = $1;
|
||||
my $v = $2;
|
||||
$constants{$bname} = $v;
|
||||
}
|
||||
}
|
||||
fn_declare($d, "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const $type_decl *r)");
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "return ejs_push_$type_fn(ejs, v, name, r);";
|
||||
deindent;
|
||||
pidl "}";
|
||||
}
|
||||
|
||||
|
||||
###########################
|
||||
# generate a structure push
|
||||
sub EjsTypedefPush($)
|
||||
{
|
||||
my $d = shift;
|
||||
return if (has_property($d, "noejs"));
|
||||
|
||||
if ($d->{DATA}->{TYPE} eq 'STRUCT') {
|
||||
EjsStructPush($d->{NAME}, $d->{DATA});
|
||||
} elsif ($d->{DATA}->{TYPE} eq 'UNION') {
|
||||
EjsUnionPush($d->{NAME}, $d->{DATA});
|
||||
} elsif ($d->{DATA}->{TYPE} eq 'ENUM') {
|
||||
EjsEnumPush($d->{NAME}, $d->{DATA});
|
||||
} elsif ($d->{DATA}->{TYPE} eq 'BITMAP') {
|
||||
EjsBitmapPush($d->{NAME}, $d->{DATA});
|
||||
} elsif ($d->{DATA}->{TYPE} eq 'DECORATED') {
|
||||
} else {
|
||||
warn "Unhandled push typedef $d->{NAME} of type $d->{DATA}->{TYPE}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#####################
|
||||
# generate a function
|
||||
sub EjsPushFunction($)
|
||||
{
|
||||
my $d = shift;
|
||||
my $env = GenerateFunctionOutEnv($d);
|
||||
|
||||
pidl "\nstatic NTSTATUS ejs_push_$d->{NAME}(struct ejs_rpc *ejs, struct MprVar *v, const struct $d->{NAME} *r)";
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, \"output\"));";
|
||||
|
||||
foreach my $e (@{$d->{ELEMENTS}}) {
|
||||
next unless (grep(/out/, @{$e->{DIRECTION}}));
|
||||
EjsPushElementTop($e, $env);
|
||||
}
|
||||
|
||||
if ($d->{RETURN_TYPE}) {
|
||||
my $t = $d->{RETURN_TYPE};
|
||||
pidl "NDR_CHECK(ejs_push_$t(ejs, v, \"result\", &r->out.result));";
|
||||
}
|
||||
|
||||
pidl "return NT_STATUS_OK;";
|
||||
deindent;
|
||||
pidl "}\n";
|
||||
}
|
||||
|
||||
|
||||
#################################
|
||||
# generate a ejs mapping function
|
||||
sub EjsFunction($$)
|
||||
{
|
||||
my $d = shift;
|
||||
my $iface = shift;
|
||||
my $name = $d->{NAME};
|
||||
my $callnum = uc("DCERPC_$name");
|
||||
my $table = "&dcerpc_table_$iface";
|
||||
|
||||
pidl "static int ejs_$name(int eid, int argc, struct MprVar **argv)";
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "return ejs_rpc_call(eid, argc, argv, $table, $callnum, (ejs_pull_function_t)ejs_pull_$name, (ejs_push_function_t)ejs_push_$name);";
|
||||
deindent;
|
||||
pidl "}\n";
|
||||
}
|
||||
|
||||
###################
|
||||
# handle a constant
|
||||
sub EjsConst($)
|
||||
{
|
||||
my $const = shift;
|
||||
$constants{$const->{NAME}} = $const->{VALUE};
|
||||
}
|
||||
|
||||
sub EjsImport
|
||||
{
|
||||
my @imports = @_;
|
||||
foreach (@imports) {
|
||||
s/\.idl\"$//;
|
||||
s/^\"//;
|
||||
pidl_hdr "#include \"librpc/gen_ndr/ndr_$_\_ejs\.h\"\n";
|
||||
}
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# parse the interface definitions
|
||||
sub EjsInterface($$)
|
||||
{
|
||||
my($interface,$needed) = @_;
|
||||
my @fns = ();
|
||||
my $name = $interface->{NAME};
|
||||
|
||||
%constants = ();
|
||||
|
||||
pidl_hdr "#ifndef _HEADER_EJS_$interface->{NAME}\n";
|
||||
pidl_hdr "#define _HEADER_EJS_$interface->{NAME}\n\n";
|
||||
|
||||
pidl_hdr "\n";
|
||||
|
||||
foreach my $d (@{$interface->{TYPES}}) {
|
||||
($needed->{"push_$d->{NAME}"}) && EjsTypedefPush($d);
|
||||
($needed->{"pull_$d->{NAME}"}) && EjsTypedefPull($d);
|
||||
}
|
||||
|
||||
foreach my $d (@{$interface->{FUNCTIONS}}) {
|
||||
next if not defined($d->{OPNUM});
|
||||
next if has_property($d, "noejs");
|
||||
|
||||
EjsPullFunction($d);
|
||||
EjsPushFunction($d);
|
||||
EjsFunction($d, $name);
|
||||
|
||||
push (@fns, $d->{NAME});
|
||||
}
|
||||
|
||||
foreach my $d (@{$interface->{CONSTS}}) {
|
||||
EjsConst($d);
|
||||
}
|
||||
|
||||
pidl "static int ejs_$name\_init(int eid, int argc, struct MprVar **argv)";
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "struct MprVar *obj = mprInitObject(eid, \"$name\", argc, argv);";
|
||||
foreach (@fns) {
|
||||
pidl "mprSetCFunction(obj, \"$_\", ejs_$_);";
|
||||
}
|
||||
foreach my $v (keys %constants) {
|
||||
my $value = $constants{$v};
|
||||
if (substr($value, 0, 1) eq "\"") {
|
||||
pidl "mprSetVar(obj, \"$v\", mprString($value));";
|
||||
} else {
|
||||
pidl "mprSetVar(obj, \"$v\", mprCreateNumberVar($value));";
|
||||
}
|
||||
}
|
||||
pidl "return ejs_rpc_init(obj, \"$name\");";
|
||||
deindent;
|
||||
pidl "}\n";
|
||||
|
||||
pidl "NTSTATUS ejs_init_$name(void)";
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "ejsDefineCFunction(-1, \"$name\_init\", ejs_$name\_init, NULL, MPR_VAR_SCRIPT_HANDLE);";
|
||||
pidl "return NT_STATUS_OK;";
|
||||
deindent;
|
||||
pidl "}";
|
||||
|
||||
pidl_hdr "\n";
|
||||
pidl_hdr "#endif /* _HEADER_EJS_$interface->{NAME} */\n";
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# parse a parsed IDL into a C header
|
||||
sub Parse($$)
|
||||
{
|
||||
my($ndr,$hdr) = @_;
|
||||
|
||||
my $ejs_hdr = $hdr;
|
||||
$ejs_hdr =~ s/.h$/_ejs.h/;
|
||||
$res = "";
|
||||
$res_hdr = "";
|
||||
|
||||
pidl_hdr "/* header auto-generated by pidl */\n\n";
|
||||
|
||||
pidl "
|
||||
/* EJS wrapper functions auto-generated by pidl */
|
||||
#include \"includes.h\"
|
||||
#include \"librpc/rpc/dcerpc.h\"
|
||||
#include \"lib/appweb/ejs/ejs.h\"
|
||||
#include \"scripting/ejs/ejsrpc.h\"
|
||||
#include \"scripting/ejs/smbcalls.h\"
|
||||
#include \"librpc/gen_ndr/ndr_misc_ejs.h\"
|
||||
#include \"$hdr\"
|
||||
#include \"$ejs_hdr\"
|
||||
|
||||
";
|
||||
|
||||
my %needed = ();
|
||||
|
||||
foreach my $x (@{$ndr}) {
|
||||
($x->{TYPE} eq "INTERFACE") && NeededInterface($x, \%needed);
|
||||
}
|
||||
|
||||
foreach my $x (@$ndr) {
|
||||
($x->{TYPE} eq "INTERFACE") && EjsInterface($x, \%needed);
|
||||
($x->{TYPE} eq "IMPORT") && EjsImport(@{$x->{PATHS}});
|
||||
}
|
||||
|
||||
return ($res_hdr, $res);
|
||||
}
|
||||
|
||||
sub NeededFunction($$)
|
||||
{
|
||||
my ($fn,$needed) = @_;
|
||||
|
||||
$needed->{"pull_$fn->{NAME}"} = 1;
|
||||
$needed->{"push_$fn->{NAME}"} = 1;
|
||||
|
||||
foreach (@{$fn->{ELEMENTS}}) {
|
||||
next if (has_property($_, "subcontext")); #FIXME: Support subcontexts
|
||||
if (grep(/in/, @{$_->{DIRECTION}})) {
|
||||
$needed->{"pull_$_->{TYPE}"} = 1;
|
||||
}
|
||||
if (grep(/out/, @{$_->{DIRECTION}})) {
|
||||
$needed->{"push_$_->{TYPE}"} = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub NeededTypedef($$)
|
||||
{
|
||||
my ($t,$needed) = @_;
|
||||
|
||||
if (has_property($t, "public")) {
|
||||
$needed->{"pull_$t->{NAME}"} = not has_property($t, "noejs");
|
||||
$needed->{"push_$t->{NAME}"} = not has_property($t, "noejs");
|
||||
}
|
||||
|
||||
return if (($t->{DATA}->{TYPE} ne "STRUCT") and
|
||||
($t->{DATA}->{TYPE} ne "UNION"));
|
||||
|
||||
foreach (@{$t->{DATA}->{ELEMENTS}}) {
|
||||
next if (has_property($_, "subcontext")); #FIXME: Support subcontexts
|
||||
unless (defined($needed->{"pull_$_->{TYPE}"})) {
|
||||
$needed->{"pull_$_->{TYPE}"} = $needed->{"pull_$t->{NAME}"};
|
||||
}
|
||||
unless (defined($needed->{"push_$_->{TYPE}"})) {
|
||||
$needed->{"push_$_->{TYPE}"} = $needed->{"push_$t->{NAME}"};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# work out what parse functions are needed
|
||||
sub NeededInterface($$)
|
||||
{
|
||||
my ($interface,$needed) = @_;
|
||||
|
||||
NeededFunction($_, $needed) foreach (@{$interface->{FUNCTIONS}});
|
||||
NeededTypedef($_, $needed) foreach (reverse @{$interface->{TYPES}});
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,407 @@
|
||||
###################################################
|
||||
# create C header files for an IDL structure
|
||||
# Copyright tridge@samba.org 2000
|
||||
# Copyright jelmer@samba.org 2005
|
||||
# released under the GNU GPL
|
||||
|
||||
package Parse::Pidl::Samba4::Header;
|
||||
|
||||
use strict;
|
||||
use Parse::Pidl::Typelist qw(mapType);
|
||||
use Parse::Pidl::Util qw(has_property is_constant);
|
||||
use Parse::Pidl::NDR qw(GetNextLevel GetPrevLevel);
|
||||
use Parse::Pidl::Samba4 qw(is_intree);
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '0.01';
|
||||
|
||||
my($res);
|
||||
my($tab_depth);
|
||||
|
||||
sub pidl($) { $res .= shift; }
|
||||
|
||||
sub tabs()
|
||||
{
|
||||
my $res = "";
|
||||
$res .="\t" foreach (1..$tab_depth);
|
||||
return $res;
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# parse a properties list
|
||||
sub HeaderProperties($$)
|
||||
{
|
||||
my($props,$ignores) = @_;
|
||||
my $ret = "";
|
||||
|
||||
foreach my $d (keys %{$props}) {
|
||||
next if (grep(/^$d$/, @$ignores));
|
||||
if($props->{$d} ne "1") {
|
||||
$ret.= "$d($props->{$d}),";
|
||||
} else {
|
||||
$ret.="$d,";
|
||||
}
|
||||
}
|
||||
|
||||
if ($ret) {
|
||||
pidl "/* [" . substr($ret, 0, -1) . "] */";
|
||||
}
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# parse a structure element
|
||||
sub HeaderElement($)
|
||||
{
|
||||
my($element) = shift;
|
||||
|
||||
pidl tabs();
|
||||
if (has_property($element, "represent_as")) {
|
||||
pidl mapType($element->{PROPERTIES}->{represent_as})." ";
|
||||
} else {
|
||||
HeaderType($element, $element->{TYPE}, "");
|
||||
pidl " ";
|
||||
my $numstar = $element->{POINTERS};
|
||||
if ($numstar >= 1) {
|
||||
$numstar-- if Parse::Pidl::Typelist::scalar_is_reference($element->{TYPE});
|
||||
}
|
||||
foreach (@{$element->{ARRAY_LEN}})
|
||||
{
|
||||
next if is_constant($_) and
|
||||
not has_property($element, "charset");
|
||||
$numstar++;
|
||||
}
|
||||
pidl "*" foreach (1..$numstar);
|
||||
}
|
||||
pidl $element->{NAME};
|
||||
foreach (@{$element->{ARRAY_LEN}}) {
|
||||
next unless (is_constant($_) and
|
||||
not has_property($element, "charset"));
|
||||
pidl "[$_]";
|
||||
}
|
||||
|
||||
pidl ";";
|
||||
if (defined $element->{PROPERTIES}) {
|
||||
HeaderProperties($element->{PROPERTIES}, ["in", "out"]);
|
||||
}
|
||||
pidl "\n";
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# parse a struct
|
||||
sub HeaderStruct($$)
|
||||
{
|
||||
my($struct,$name) = @_;
|
||||
pidl "struct $name {\n";
|
||||
$tab_depth++;
|
||||
my $el_count=0;
|
||||
if (defined $struct->{ELEMENTS}) {
|
||||
foreach (@{$struct->{ELEMENTS}}) {
|
||||
HeaderElement($_);
|
||||
$el_count++;
|
||||
}
|
||||
}
|
||||
if ($el_count == 0) {
|
||||
# some compilers can't handle empty structures
|
||||
pidl tabs()."char _empty_;\n";
|
||||
}
|
||||
$tab_depth--;
|
||||
pidl tabs()."}";
|
||||
if (defined $struct->{PROPERTIES}) {
|
||||
HeaderProperties($struct->{PROPERTIES}, []);
|
||||
}
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# parse a enum
|
||||
sub HeaderEnum($$)
|
||||
{
|
||||
my($enum,$name) = @_;
|
||||
my $first = 1;
|
||||
|
||||
if (not Parse::Pidl::Util::useUintEnums()) {
|
||||
pidl "enum $name {\n";
|
||||
$tab_depth++;
|
||||
foreach my $e (@{$enum->{ELEMENTS}}) {
|
||||
unless ($first) { pidl ",\n"; }
|
||||
$first = 0;
|
||||
pidl tabs();
|
||||
pidl $e;
|
||||
}
|
||||
pidl "\n";
|
||||
$tab_depth--;
|
||||
pidl "}";
|
||||
} else {
|
||||
my $count = 0;
|
||||
pidl "enum $name { __donnot_use_enum_$name=0x7FFFFFFF};\n";
|
||||
my $with_val = 0;
|
||||
my $without_val = 0;
|
||||
foreach my $e (@{$enum->{ELEMENTS}}) {
|
||||
my $t = "$e";
|
||||
my $name;
|
||||
my $value;
|
||||
if ($t =~ /(.*)=(.*)/) {
|
||||
$name = $1;
|
||||
$value = $2;
|
||||
$with_val = 1;
|
||||
die ("you can't mix enum member with values and without values when using --uint-enums!")
|
||||
unless ($without_val == 0);
|
||||
} else {
|
||||
$name = $t;
|
||||
$value = $count++;
|
||||
$without_val = 1;
|
||||
die ("you can't mix enum member with values and without values when using --uint-enums!")
|
||||
unless ($with_val == 0);
|
||||
}
|
||||
pidl "#define $name ( $value )\n";
|
||||
}
|
||||
pidl "\n";
|
||||
}
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# parse a bitmap
|
||||
sub HeaderBitmap($$)
|
||||
{
|
||||
my($bitmap,$name) = @_;
|
||||
|
||||
pidl "/* bitmap $name */\n";
|
||||
pidl "#define $_\n" foreach (@{$bitmap->{ELEMENTS}});
|
||||
pidl "\n";
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# parse a union
|
||||
sub HeaderUnion($$)
|
||||
{
|
||||
my($union,$name) = @_;
|
||||
my %done = ();
|
||||
|
||||
pidl "union $name {\n";
|
||||
$tab_depth++;
|
||||
foreach my $e (@{$union->{ELEMENTS}}) {
|
||||
if ($e->{TYPE} ne "EMPTY") {
|
||||
if (! defined $done{$e->{NAME}}) {
|
||||
HeaderElement($e);
|
||||
}
|
||||
$done{$e->{NAME}} = 1;
|
||||
}
|
||||
}
|
||||
$tab_depth--;
|
||||
pidl "}";
|
||||
|
||||
if (defined $union->{PROPERTIES}) {
|
||||
HeaderProperties($union->{PROPERTIES}, []);
|
||||
}
|
||||
}
|
||||
|
||||
sub decorate($$)
|
||||
{
|
||||
my($name,$levels) = @_;
|
||||
my $prev_ptr = 0;
|
||||
foreach my $i (0..$#{$levels}) {
|
||||
if ($levels->[$i]{TYPE} eq "POINTER") {
|
||||
$name = "*$name";
|
||||
$prev_ptr = 1;
|
||||
} elsif ($levels->[$i]{TYPE} eq "ARRAY") {
|
||||
$name = ($prev_ptr ? "($name)" : $name) . "[$levels->[$i]{SIZE_IS}]";
|
||||
}
|
||||
}
|
||||
$name
|
||||
}
|
||||
|
||||
sub HeaderDecorated($$)
|
||||
{
|
||||
my($e,$name) = @_;
|
||||
$name = $e->{NAME} unless defined($name);
|
||||
pidl "typedef ";
|
||||
if (has_property($e, "charset")) {
|
||||
pidl "const char";
|
||||
} else {
|
||||
pidl mapType($e->{DATA}{DATA_TYPE});
|
||||
}
|
||||
pidl " " . decorate($name, $e->{DATA}{LEVELS});
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# parse a type
|
||||
sub HeaderType($$$)
|
||||
{
|
||||
my($e,$data,$name) = @_;
|
||||
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 "DECORATED") && HeaderDecorated($e, $name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_property($e, "charset") and $e->{TYPEREF}{DATA}{TYPE} ne "DECORATED") {
|
||||
pidl "const char";
|
||||
} else {
|
||||
pidl mapType($e->{TYPE});
|
||||
}
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# parse a typedef
|
||||
sub HeaderTypedef($)
|
||||
{
|
||||
my($typedef) = shift;
|
||||
HeaderType($typedef, $typedef->{DATA}, $typedef->{NAME});
|
||||
pidl ";\n\n" unless ($typedef->{DATA}->{TYPE} eq "BITMAP");
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# parse a const
|
||||
sub HeaderConst($)
|
||||
{
|
||||
my($const) = shift;
|
||||
if (!defined($const->{ARRAY_LEN}[0])) {
|
||||
pidl "#define $const->{NAME}\t( $const->{VALUE} )\n";
|
||||
} else {
|
||||
pidl "#define $const->{NAME}\t $const->{VALUE}\n";
|
||||
}
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# parse a function
|
||||
sub HeaderFunctionInOut($$)
|
||||
{
|
||||
my($fn,$prop) = @_;
|
||||
|
||||
foreach (@{$fn->{ELEMENTS}}) {
|
||||
HeaderElement($_) if (has_property($_, $prop));
|
||||
}
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# determine if we need an "in" or "out" section
|
||||
sub HeaderFunctionInOut_needed($$)
|
||||
{
|
||||
my($fn,$prop) = @_;
|
||||
|
||||
return 1 if ($prop eq "out" && $fn->{RETURN_TYPE} ne "void");
|
||||
|
||||
foreach (@{$fn->{ELEMENTS}}) {
|
||||
return 1 if (has_property($_, $prop));
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (HeaderFunctionInOut_needed($fn, "in")) {
|
||||
pidl tabs()."struct {\n";
|
||||
$tab_depth++;
|
||||
HeaderFunctionInOut($fn, "in");
|
||||
$tab_depth--;
|
||||
pidl tabs()."} in;\n\n";
|
||||
$needed++;
|
||||
}
|
||||
|
||||
if (HeaderFunctionInOut_needed($fn, "out")) {
|
||||
pidl tabs()."struct {\n";
|
||||
$tab_depth++;
|
||||
HeaderFunctionInOut($fn, "out");
|
||||
if ($fn->{RETURN_TYPE} ne "void") {
|
||||
pidl tabs().mapType($fn->{RETURN_TYPE}) . " result;\n";
|
||||
}
|
||||
$tab_depth--;
|
||||
pidl tabs()."} out;\n\n";
|
||||
$needed++;
|
||||
}
|
||||
|
||||
if (! $needed) {
|
||||
# sigh - some compilers don't like empty structures
|
||||
pidl tabs()."int _dummy_element;\n";
|
||||
}
|
||||
|
||||
$tab_depth--;
|
||||
pidl "};\n\n";
|
||||
}
|
||||
|
||||
sub HeaderImport
|
||||
{
|
||||
my @imports = @_;
|
||||
foreach (@imports) {
|
||||
s/\.idl\"$//;
|
||||
s/^\"//;
|
||||
pidl "#include \"librpc/gen_ndr/$_\.h\"\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub HeaderInclude
|
||||
{
|
||||
my @includes = @_;
|
||||
foreach (@includes) {
|
||||
pidl "#include $_\n";
|
||||
}
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# parse the interface definitions
|
||||
sub HeaderInterface($)
|
||||
{
|
||||
my($interface) = shift;
|
||||
|
||||
pidl "#ifndef _HEADER_$interface->{NAME}\n";
|
||||
pidl "#define _HEADER_$interface->{NAME}\n\n";
|
||||
|
||||
foreach my $d (@{$interface->{DATA}}) {
|
||||
next if ($d->{TYPE} ne "CONST");
|
||||
HeaderConst($d);
|
||||
}
|
||||
|
||||
foreach my $d (@{$interface->{DATA}}) {
|
||||
next if ($d->{TYPE} ne "TYPEDEF");
|
||||
HeaderTypedef($d);
|
||||
}
|
||||
|
||||
foreach my $d (@{$interface->{DATA}}) {
|
||||
next if ($d->{TYPE} ne "FUNCTION");
|
||||
|
||||
HeaderFunction($d);
|
||||
}
|
||||
|
||||
pidl "#endif /* _HEADER_$interface->{NAME} */\n";
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# parse a parsed IDL into a C header
|
||||
sub Parse($)
|
||||
{
|
||||
my($idl) = shift;
|
||||
$tab_depth = 0;
|
||||
|
||||
$res = "";
|
||||
%headerstructs = ();
|
||||
pidl "/* header auto-generated by pidl */\n\n";
|
||||
if (!is_intree()) {
|
||||
pidl "#include <core.h>\n\n";
|
||||
}
|
||||
|
||||
foreach (@{$idl}) {
|
||||
($_->{TYPE} eq "INTERFACE") && HeaderInterface($_);
|
||||
($_->{TYPE} eq "IMPORT") && HeaderImport(@{$_->{PATHS}});
|
||||
($_->{TYPE} eq "INCLUDE") && HeaderInclude(@{$_->{PATHS}});
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,128 @@
|
||||
###################################################
|
||||
# client calls generator
|
||||
# Copyright tridge@samba.org 2003
|
||||
# Copyright jelmer@samba.org 2005-2006
|
||||
# released under the GNU GPL
|
||||
|
||||
package Parse::Pidl::Samba4::NDR::Client;
|
||||
|
||||
use Parse::Pidl::Samba4 qw(choose_header is_intree);
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '0.01';
|
||||
|
||||
use strict;
|
||||
|
||||
my($res,$res_hdr);
|
||||
|
||||
#####################################################################
|
||||
# parse a function
|
||||
sub ParseFunction($$)
|
||||
{
|
||||
my ($interface, $fn) = @_;
|
||||
my $name = $fn->{NAME};
|
||||
my $uname = uc $name;
|
||||
|
||||
$res_hdr .= "\nstruct rpc_request *dcerpc_$name\_send(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *r);
|
||||
NTSTATUS dcerpc_$name(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *r);
|
||||
";
|
||||
|
||||
$res .= "
|
||||
struct rpc_request *dcerpc_$name\_send(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *r)
|
||||
{
|
||||
if (p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
|
||||
NDR_PRINT_IN_DEBUG($name, r);
|
||||
}
|
||||
|
||||
return dcerpc_ndr_request_send(p, NULL, &dcerpc_table_$interface->{NAME}, DCERPC_$uname, mem_ctx, r);
|
||||
}
|
||||
|
||||
NTSTATUS dcerpc_$name(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *r)
|
||||
{
|
||||
struct rpc_request *req;
|
||||
NTSTATUS status;
|
||||
|
||||
req = dcerpc_$name\_send(p, mem_ctx, r);
|
||||
if (req == NULL) return NT_STATUS_NO_MEMORY;
|
||||
|
||||
status = dcerpc_ndr_request_recv(req);
|
||||
|
||||
if (NT_STATUS_IS_OK(status) && (p->conn->flags & DCERPC_DEBUG_PRINT_OUT)) {
|
||||
NDR_PRINT_OUT_DEBUG($name, r);
|
||||
}
|
||||
";
|
||||
|
||||
if (defined($fn->{RETURN_TYPE}) and $fn->{RETURN_TYPE} eq "NTSTATUS") {
|
||||
$res .= "\tif (NT_STATUS_IS_OK(status)) status = r->out.result;\n";
|
||||
}
|
||||
$res .=
|
||||
"
|
||||
return status;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
my %done;
|
||||
|
||||
#####################################################################
|
||||
# parse the interface definitions
|
||||
sub ParseInterface($)
|
||||
{
|
||||
my($interface) = shift;
|
||||
|
||||
$res_hdr .= "#ifndef _HEADER_RPC_$interface->{NAME}\n";
|
||||
$res_hdr .= "#define _HEADER_RPC_$interface->{NAME}\n\n";
|
||||
|
||||
if (defined $interface->{PROPERTIES}->{uuid}) {
|
||||
$res_hdr .= "extern const struct dcerpc_interface_table dcerpc_table_$interface->{NAME};\n";
|
||||
}
|
||||
|
||||
$res .= "/* $interface->{NAME} - client functions generated by pidl */\n\n";
|
||||
|
||||
foreach my $fn (@{$interface->{FUNCTIONS}}) {
|
||||
next if not defined($fn->{OPNUM});
|
||||
next if defined($done{$fn->{NAME}});
|
||||
ParseFunction($interface, $fn);
|
||||
$done{$fn->{NAME}} = 1;
|
||||
}
|
||||
|
||||
$res_hdr .= "#endif /* _HEADER_RPC_$interface->{NAME} */\n";
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub Parse($$$$)
|
||||
{
|
||||
my($ndr,$header,$ndr_header,$client_header) = @_;
|
||||
|
||||
$res = "";
|
||||
$res_hdr = "";
|
||||
|
||||
$res .= "/* client functions auto-generated by pidl */\n";
|
||||
$res .= "\n";
|
||||
if (is_intree()) {
|
||||
$res .= "#include \"includes.h\"\n";
|
||||
} else {
|
||||
$res .= "#define _GNU_SOURCE\n";
|
||||
$res .= "#include <stdio.h>\n";
|
||||
$res .= "#include <stdbool.h>\n";
|
||||
$res .= "#include <stdlib.h>\n";
|
||||
$res .= "#include <stdint.h>\n";
|
||||
$res .= "#include <stdarg.h>\n";
|
||||
$res .= "#include <core/nterr.h>\n";
|
||||
}
|
||||
$res .= "#include \"$ndr_header\"\n";
|
||||
$res .= "#include \"$client_header\"\n";
|
||||
$res .= "\n";
|
||||
|
||||
$res_hdr .= choose_header("librpc/rpc/dcerpc.h", "dcerpc.h")."\n";
|
||||
$res_hdr .= "#include \"$header\"\n";
|
||||
|
||||
foreach my $x (@{$ndr}) {
|
||||
($x->{TYPE} eq "INTERFACE") && ParseInterface($x);
|
||||
}
|
||||
|
||||
return ($res,$res_hdr);
|
||||
}
|
||||
|
||||
1;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,325 @@
|
||||
###################################################
|
||||
# server boilerplate generator
|
||||
# Copyright tridge@samba.org 2003
|
||||
# Copyright metze@samba.org 2004
|
||||
# released under the GNU GPL
|
||||
|
||||
package Parse::Pidl::Samba4::NDR::Server;
|
||||
|
||||
use strict;
|
||||
use Parse::Pidl::Util;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '0.01';
|
||||
|
||||
my($res);
|
||||
|
||||
sub pidl($)
|
||||
{
|
||||
$res .= shift;
|
||||
}
|
||||
|
||||
|
||||
#####################################################
|
||||
# generate the switch statement for function dispatch
|
||||
sub gen_dispatch_switch($)
|
||||
{
|
||||
my $interface = shift;
|
||||
|
||||
foreach my $fn (@{$interface->{FUNCTIONS}}) {
|
||||
next if not defined($fn->{OPNUM});
|
||||
|
||||
pidl "\tcase $fn->{OPNUM}: {\n";
|
||||
pidl "\t\tstruct $fn->{NAME} *r2 = (struct $fn->{NAME} *)r;\n";
|
||||
pidl "\t\tif (DEBUGLEVEL >= 10) {\n";
|
||||
pidl "\t\t\tNDR_PRINT_FUNCTION_DEBUG($fn->{NAME}, NDR_IN, r2);\n";
|
||||
pidl "\t\t}\n";
|
||||
if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
|
||||
pidl "\t\tr2->out.result = $fn->{NAME}(dce_call, mem_ctx, r2);\n";
|
||||
} else {
|
||||
pidl "\t\t$fn->{NAME}(dce_call, mem_ctx, r2);\n";
|
||||
}
|
||||
pidl "\t\tif (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {\n";
|
||||
pidl "\t\t\tDEBUG(5,(\"function $fn->{NAME} will reply async\\n\"));\n";
|
||||
pidl "\t\t}\n";
|
||||
pidl "\t\tbreak;\n\t}\n";
|
||||
}
|
||||
}
|
||||
|
||||
#####################################################
|
||||
# generate the switch statement for function reply
|
||||
sub gen_reply_switch($)
|
||||
{
|
||||
my $interface = shift;
|
||||
|
||||
foreach my $fn (@{$interface->{FUNCTIONS}}) {
|
||||
next if not defined($fn->{OPNUM});
|
||||
|
||||
pidl "\tcase $fn->{OPNUM}: {\n";
|
||||
pidl "\t\tstruct $fn->{NAME} *r2 = (struct $fn->{NAME} *)r;\n";
|
||||
pidl "\t\tif (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {\n";
|
||||
pidl "\t\t\tDEBUG(5,(\"function $fn->{NAME} replied async\\n\"));\n";
|
||||
pidl "\t\t}\n";
|
||||
pidl "\t\tif (DEBUGLEVEL >= 10 && dce_call->fault_code == 0) {\n";
|
||||
pidl "\t\t\tNDR_PRINT_FUNCTION_DEBUG($fn->{NAME}, NDR_OUT | NDR_SET_VALUES, r2);\n";
|
||||
pidl "\t\t}\n";
|
||||
pidl "\t\tif (dce_call->fault_code != 0) {\n";
|
||||
pidl "\t\t\tDEBUG(2,(\"dcerpc_fault %s in $fn->{NAME}\\n\", dcerpc_errstr(mem_ctx, dce_call->fault_code)));\n";
|
||||
pidl "\t\t}\n";
|
||||
pidl "\t\tbreak;\n\t}\n";
|
||||
}
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# produce boilerplate code for a interface
|
||||
sub Boilerplate_Iface($)
|
||||
{
|
||||
my($interface) = shift;
|
||||
my $name = $interface->{NAME};
|
||||
my $uname = uc $name;
|
||||
my $uuid = lc($interface->{PROPERTIES}->{uuid});
|
||||
my $if_version = $interface->{PROPERTIES}->{version};
|
||||
|
||||
pidl "
|
||||
static NTSTATUS $name\__op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
|
||||
{
|
||||
#ifdef DCESRV_INTERFACE_$uname\_BIND
|
||||
return DCESRV_INTERFACE_$uname\_BIND(dce_call,iface);
|
||||
#else
|
||||
return NT_STATUS_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void $name\__op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)
|
||||
{
|
||||
#ifdef DCESRV_INTERFACE_$uname\_UNBIND
|
||||
DCESRV_INTERFACE_$uname\_UNBIND(context, iface);
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
static NTSTATUS $name\__op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
|
||||
{
|
||||
NTSTATUS status;
|
||||
uint16_t opnum = dce_call->pkt.u.request.opnum;
|
||||
|
||||
dce_call->fault_code = 0;
|
||||
|
||||
if (opnum >= dcerpc_table_$name.num_calls) {
|
||||
dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
|
||||
return NT_STATUS_NET_WRITE_FAULT;
|
||||
}
|
||||
|
||||
*r = talloc_size(mem_ctx, dcerpc_table_$name.calls[opnum].struct_size);
|
||||
NT_STATUS_HAVE_NO_MEMORY(*r);
|
||||
|
||||
/* unravel the NDR for the packet */
|
||||
status = dcerpc_table_$name.calls[opnum].ndr_pull(pull, NDR_IN, *r);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
dcerpc_log_packet(&dcerpc_table_$name, opnum, NDR_IN,
|
||||
&dce_call->pkt.u.request.stub_and_verifier);
|
||||
dce_call->fault_code = DCERPC_FAULT_NDR;
|
||||
return NT_STATUS_NET_WRITE_FAULT;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS $name\__op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
|
||||
{
|
||||
uint16_t opnum = dce_call->pkt.u.request.opnum;
|
||||
|
||||
switch (opnum) {
|
||||
";
|
||||
gen_dispatch_switch($interface);
|
||||
|
||||
pidl "
|
||||
default:
|
||||
dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dce_call->fault_code != 0) {
|
||||
dcerpc_log_packet(&dcerpc_table_$name, opnum, NDR_IN,
|
||||
&dce_call->pkt.u.request.stub_and_verifier);
|
||||
return NT_STATUS_NET_WRITE_FAULT;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS $name\__op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
|
||||
{
|
||||
uint16_t opnum = dce_call->pkt.u.request.opnum;
|
||||
|
||||
switch (opnum) {
|
||||
";
|
||||
gen_reply_switch($interface);
|
||||
|
||||
pidl "
|
||||
default:
|
||||
dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dce_call->fault_code != 0) {
|
||||
dcerpc_log_packet(&dcerpc_table_$name, opnum, NDR_IN,
|
||||
&dce_call->pkt.u.request.stub_and_verifier);
|
||||
return NT_STATUS_NET_WRITE_FAULT;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS $name\__op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)
|
||||
{
|
||||
NTSTATUS status;
|
||||
uint16_t opnum = dce_call->pkt.u.request.opnum;
|
||||
|
||||
status = dcerpc_table_$name.calls[opnum].ndr_push(push, NDR_OUT, r);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
dce_call->fault_code = DCERPC_FAULT_NDR;
|
||||
return NT_STATUS_NET_WRITE_FAULT;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static const struct dcesrv_interface $name\_interface = {
|
||||
.name = \"$name\",
|
||||
.syntax_id = {".print_uuid($uuid).",$if_version},
|
||||
.bind = $name\__op_bind,
|
||||
.unbind = $name\__op_unbind,
|
||||
.ndr_pull = $name\__op_ndr_pull,
|
||||
.dispatch = $name\__op_dispatch,
|
||||
.reply = $name\__op_reply,
|
||||
.ndr_push = $name\__op_ndr_push
|
||||
};
|
||||
|
||||
";
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# produce boilerplate code for an endpoint server
|
||||
sub Boilerplate_Ep_Server($)
|
||||
{
|
||||
my($interface) = shift;
|
||||
my $name = $interface->{NAME};
|
||||
my $uname = uc $name;
|
||||
|
||||
pidl "
|
||||
static NTSTATUS $name\__op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;i<dcerpc_table_$name.endpoints->count;i++) {
|
||||
NTSTATUS ret;
|
||||
const char *name = dcerpc_table_$name.endpoints->names[i];
|
||||
|
||||
ret = dcesrv_interface_register(dce_ctx, name, &$name\_interface, NULL);
|
||||
if (!NT_STATUS_IS_OK(ret)) {
|
||||
DEBUG(1,(\"$name\_op_init_server: failed to register endpoint \'%s\'\\n\",name));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static BOOL $name\__op_interface_by_uuid(struct dcesrv_interface *iface, const struct GUID *uuid, uint32_t if_version)
|
||||
{
|
||||
if ($name\_interface.syntax_id.if_version == if_version &&
|
||||
GUID_equal(\&$name\_interface.syntax_id.uuid, uuid)) {
|
||||
memcpy(iface,&$name\_interface, sizeof(*iface));
|
||||
return True;
|
||||
}
|
||||
|
||||
return False;
|
||||
}
|
||||
|
||||
static BOOL $name\__op_interface_by_name(struct dcesrv_interface *iface, const char *name)
|
||||
{
|
||||
if (strcmp($name\_interface.name, name)==0) {
|
||||
memcpy(iface,&$name\_interface, sizeof(*iface));
|
||||
return True;
|
||||
}
|
||||
|
||||
return False;
|
||||
}
|
||||
|
||||
NTSTATUS dcerpc_server_$name\_init(void)
|
||||
{
|
||||
NTSTATUS ret;
|
||||
struct dcesrv_endpoint_server ep_server;
|
||||
|
||||
/* fill in our name */
|
||||
ep_server.name = \"$name\";
|
||||
|
||||
/* fill in all the operations */
|
||||
ep_server.init_server = $name\__op_init_server;
|
||||
|
||||
ep_server.interface_by_uuid = $name\__op_interface_by_uuid;
|
||||
ep_server.interface_by_name = $name\__op_interface_by_name;
|
||||
|
||||
/* register ourselves with the DCERPC subsystem. */
|
||||
ret = dcerpc_register_ep_server(&ep_server);
|
||||
|
||||
if (!NT_STATUS_IS_OK(ret)) {
|
||||
DEBUG(0,(\"Failed to register \'$name\' endpoint server!\\n\"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
";
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# dcerpc server boilerplate from a parsed IDL structure
|
||||
sub ParseInterface($)
|
||||
{
|
||||
my($interface) = shift;
|
||||
my $count = 0;
|
||||
|
||||
if (!defined $interface->{PROPERTIES}->{uuid}) {
|
||||
return $res;
|
||||
}
|
||||
|
||||
if (!defined $interface->{PROPERTIES}->{version}) {
|
||||
$interface->{PROPERTIES}->{version} = "0.0";
|
||||
}
|
||||
|
||||
foreach my $fn (@{$interface->{FUNCTIONS}}) {
|
||||
if (defined($fn->{OPNUM})) { $count++; }
|
||||
}
|
||||
|
||||
if ($count == 0) {
|
||||
return $res;
|
||||
}
|
||||
|
||||
$res .= "/* $interface->{NAME} - dcerpc server boilerplate generated by pidl */\n\n";
|
||||
Boilerplate_Iface($interface);
|
||||
Boilerplate_Ep_Server($interface);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub Parse($$)
|
||||
{
|
||||
my($ndr,$header) = @_;
|
||||
|
||||
$res = "";
|
||||
$res .= "/* server functions auto-generated by pidl */\n";
|
||||
$res .= "#include \"$header\"\n";
|
||||
$res .= "\n";
|
||||
|
||||
foreach my $x (@{$ndr}) {
|
||||
ParseInterface($x) if ($x->{TYPE} eq "INTERFACE" and not defined($x->{PROPERTIES}{object}));
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,176 @@
|
||||
###################################################
|
||||
# Samba4 parser generator for swig wrappers
|
||||
# Copyright tpot@samba.org 2004,2005
|
||||
# Copyright jelmer@samba.org 2006
|
||||
# released under the GNU GPL
|
||||
|
||||
package Parse::Pidl::Samba4::SWIG;
|
||||
|
||||
use vars qw($VERSION);
|
||||
use Parse::Pidl::Samba4 qw(DeclLong);
|
||||
use Parse::Pidl::Typelist qw(mapType);
|
||||
use Parse::Pidl::Util qw(has_property);
|
||||
$VERSION = '0.01';
|
||||
|
||||
use strict;
|
||||
|
||||
my $ret = "";
|
||||
my $tabs = "";
|
||||
|
||||
sub pidl($)
|
||||
{
|
||||
my $p = shift;
|
||||
$ret .= $tabs. $p . "\n";
|
||||
}
|
||||
|
||||
sub indent() { $tabs.="\t"; }
|
||||
sub deindent() { $tabs = substr($tabs,0,-1); }
|
||||
|
||||
sub IgnoreInterface($$)
|
||||
{
|
||||
my ($basename,$if) = @_;
|
||||
|
||||
foreach (@{$if->{TYPES}}) {
|
||||
next unless (has_property($_, "public"));
|
||||
pidl "\%types($_->{NAME});";
|
||||
}
|
||||
}
|
||||
|
||||
sub ParseInterface($$)
|
||||
{
|
||||
my ($basename,$if) = @_;
|
||||
|
||||
pidl "\%inline {";
|
||||
pidl "struct $if->{NAME} { struct dcerpc_pipe *pipe; };";
|
||||
pidl "}";
|
||||
pidl "";
|
||||
pidl "\%extend $if->{NAME} {";
|
||||
indent();
|
||||
pidl "$if->{NAME} (const char *binding, struct cli_credentials *cred = NULL, TALLOC_CTX *mem_ctx = NULL, struct event_context *event = NULL)";
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "struct $if->{NAME} *ret = talloc(mem_ctx, struct $if->{NAME});";
|
||||
pidl "NTSTATUS status;";
|
||||
pidl "";
|
||||
pidl "status = dcerpc_pipe_connect(mem_ctx, &ret->pipe, binding, &dcerpc_table_$if->{NAME}, cred, event);";
|
||||
pidl "if (NT_STATUS_IS_ERR(status)) {";
|
||||
pidl "\tntstatus_exception(status);";
|
||||
pidl "\treturn NULL;";
|
||||
pidl "}";
|
||||
pidl "";
|
||||
pidl "return ret;";
|
||||
deindent;
|
||||
pidl "}";
|
||||
pidl "";
|
||||
pidl "~$if->{NAME}() {";
|
||||
pidl "\ttalloc_free(self);";
|
||||
pidl "}";
|
||||
pidl "";
|
||||
|
||||
foreach my $fn (@{$if->{FUNCTIONS}}) {
|
||||
pidl "/* $fn->{NAME} */";
|
||||
my $args = "";
|
||||
foreach (@{$fn->{ELEMENTS}}) {
|
||||
$args .= DeclLong($_) . ", ";
|
||||
}
|
||||
my $name = $fn->{NAME};
|
||||
$name =~ s/^$if->{NAME}_//g;
|
||||
$name =~ s/^$basename\_//g;
|
||||
$args .= "TALLOC_CTX *mem_ctx = NULL";
|
||||
pidl mapType($fn->{RETURN_TYPE}) . " $name($args)";
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "struct $fn->{NAME} r;";
|
||||
pidl "NTSTATUS status;";
|
||||
pidl "";
|
||||
pidl "/* Fill r structure */";
|
||||
|
||||
foreach (@{$fn->{ELEMENTS}}) {
|
||||
if (grep(/in/, @{$_->{DIRECTION}})) {
|
||||
pidl "r.in.$_->{NAME} = $_->{NAME};";
|
||||
}
|
||||
}
|
||||
|
||||
pidl "";
|
||||
pidl "status = dcerpc_$fn->{NAME}(self->pipe, mem_ctx, &r);";
|
||||
pidl "if (NT_STATUS_IS_ERR(status)) {";
|
||||
pidl "\tntstatus_exception(status);";
|
||||
if (defined($fn->{RETURN_TYPE})) {
|
||||
pidl "\treturn r.out.result;";
|
||||
} else {
|
||||
pidl "\treturn;";
|
||||
}
|
||||
pidl "}";
|
||||
pidl "";
|
||||
pidl "/* Set out arguments */";
|
||||
foreach (@{$fn->{ELEMENTS}}) {
|
||||
next unless (grep(/out/, @{$_->{DIRECTION}}));
|
||||
|
||||
pidl ("/* FIXME: $_->{NAME} [out] argument is not a pointer */") if ($_->{LEVELS}[0]->{TYPE} ne "POINTER");
|
||||
|
||||
pidl "*$_->{NAME} = *r.out.$_->{NAME};";
|
||||
}
|
||||
|
||||
if (defined($fn->{RETURN_TYPE})) {
|
||||
pidl "return r.out.result;";
|
||||
}
|
||||
deindent;
|
||||
pidl "}";
|
||||
pidl "";
|
||||
}
|
||||
|
||||
deindent();
|
||||
pidl "};";
|
||||
pidl "";
|
||||
|
||||
foreach (@{$if->{TYPES}}) {
|
||||
pidl "/* $_->{NAME} */";
|
||||
}
|
||||
|
||||
pidl "";
|
||||
}
|
||||
|
||||
sub Parse($$$$)
|
||||
{
|
||||
my($ndr,$basename,$header,$gen_header) = @_;
|
||||
|
||||
$ret = "";
|
||||
|
||||
pidl "/* This file is autogenerated by pidl. DO NOT EDIT */";
|
||||
|
||||
pidl "\%module $basename";
|
||||
|
||||
pidl "";
|
||||
|
||||
pidl "\%{";
|
||||
pidl "#include \"includes.h\"";
|
||||
pidl "#include \"auth/credentials/credentials.h\"";
|
||||
pidl "#include \"$header\"";
|
||||
pidl "#include \"$gen_header\"";
|
||||
pidl "%}";
|
||||
pidl "\%import \"samba.i\"";
|
||||
pidl "";
|
||||
pidl "\%inline {";
|
||||
pidl "void ntstatus_exception(NTSTATUS status)";
|
||||
pidl "{";
|
||||
pidl "\t/* FIXME */";
|
||||
pidl "}";
|
||||
pidl "}";
|
||||
pidl "";
|
||||
foreach (@$ndr) {
|
||||
IgnoreInterface($basename, $_) if ($_->{TYPE} eq "INTERFACE");
|
||||
}
|
||||
pidl "";
|
||||
|
||||
pidl "";
|
||||
|
||||
foreach (@$ndr) {
|
||||
ParseInterface($basename, $_) if ($_->{TYPE} eq "INTERFACE");
|
||||
}
|
||||
#FIXME: Foreach ref pointer, set NONNULL
|
||||
#FIXME: Foreach unique/full pointer, set MAYBENULL
|
||||
#FIXME: Foreach [out] parameter, set OUTPARAM
|
||||
return $ret;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,263 @@
|
||||
###################################################
|
||||
# Trivial Parser Generator
|
||||
# Copyright jelmer@samba.org 2005
|
||||
# released under the GNU GPL
|
||||
|
||||
package Parse::Pidl::Samba4::TDR;
|
||||
use Parse::Pidl::Util qw(has_property ParseExpr is_constant);
|
||||
use Parse::Pidl::Samba4 qw(is_intree choose_header);
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '0.01';
|
||||
|
||||
use strict;
|
||||
|
||||
my $ret;
|
||||
my $ret_hdr;
|
||||
my $tabs = "";
|
||||
|
||||
sub indent() { $tabs.="\t"; }
|
||||
sub deindent() { $tabs = substr($tabs, 1); }
|
||||
sub pidl($) { $ret .= $tabs.(shift)."\n"; }
|
||||
sub pidl_hdr($) { $ret_hdr .= (shift)."\n"; }
|
||||
sub fatal($$) { my ($e,$s) = @_; die("$e->{FILE}:$e->{LINE}: $s\n"); }
|
||||
sub typearg($) {
|
||||
my $t = shift;
|
||||
return(", const char *name") if ($t eq "print");
|
||||
return(", TALLOC_CTX *mem_ctx") if ($t eq "pull");
|
||||
return("");
|
||||
}
|
||||
|
||||
sub fn_declare($$)
|
||||
{
|
||||
my ($p, $d) = @_;
|
||||
if ($p) { pidl $d; pidl_hdr "$d;"; } else { pidl "static $d"; }
|
||||
}
|
||||
|
||||
sub ContainsArray($)
|
||||
{
|
||||
my $e = shift;
|
||||
foreach (@{$e->{ELEMENTS}}) {
|
||||
next if (has_property($_, "charset") and
|
||||
scalar(@{$_->{ARRAY_LEN}}) == 1);
|
||||
return 1 if (defined($_->{ARRAY_LEN}) and
|
||||
scalar(@{$_->{ARRAY_LEN}}) > 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub ParserElement($$$)
|
||||
{
|
||||
my ($e,$t,$env) = @_;
|
||||
my $switch = "";
|
||||
my $array = "";
|
||||
my $name = "";
|
||||
my $mem_ctx = "mem_ctx";
|
||||
|
||||
fatal($e,"Pointers not supported in TDR") if ($e->{POINTERS} > 0);
|
||||
fatal($e,"size_is() not supported in TDR") if (has_property($e, "size_is"));
|
||||
fatal($e,"length_is() not supported in TDR") if (has_property($e, "length_is"));
|
||||
|
||||
if ($t eq "print") {
|
||||
$name = ", \"$e->{NAME}\"$array";
|
||||
}
|
||||
|
||||
if (has_property($e, "flag")) {
|
||||
pidl "{";
|
||||
indent;
|
||||
pidl "uint32_t saved_flags = tdr->flags;";
|
||||
pidl "tdr->flags |= $e->{PROPERTIES}->{flag};";
|
||||
}
|
||||
|
||||
if (has_property($e, "charset")) {
|
||||
fatal($e,"charset() on non-array element") unless (defined($e->{ARRAY_LEN}) and scalar(@{$e->{ARRAY_LEN}}) > 0);
|
||||
|
||||
my $len = ParseExpr(@{$e->{ARRAY_LEN}}[0], $env);
|
||||
if ($len eq "*") { $len = "-1"; }
|
||||
$name = ", mem_ctx" if ($t eq "pull");
|
||||
pidl "TDR_CHECK(tdr_$t\_charset(tdr$name, &v->$e->{NAME}, $len, sizeof($e->{TYPE}_t), CH_$e->{PROPERTIES}->{charset}));";
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_property($e, "switch_is")) {
|
||||
$switch = ", " . ParseExpr($e->{PROPERTIES}->{switch_is}, $env);
|
||||
}
|
||||
|
||||
if (defined($e->{ARRAY_LEN}) and scalar(@{$e->{ARRAY_LEN}}) > 0) {
|
||||
my $len = ParseExpr($e->{ARRAY_LEN}[0], $env);
|
||||
|
||||
if ($t eq "pull" and not is_constant($len)) {
|
||||
pidl "TDR_ALLOC(mem_ctx, v->$e->{NAME}, $len);";
|
||||
$mem_ctx = "v->$e->{NAME}";
|
||||
}
|
||||
|
||||
pidl "for (i = 0; i < $len; i++) {";
|
||||
indent;
|
||||
$array = "[i]";
|
||||
}
|
||||
|
||||
if ($t eq "pull") {
|
||||
$name = ", $mem_ctx";
|
||||
}
|
||||
|
||||
if (has_property($e, "value") && $t eq "push") {
|
||||
pidl "v->$e->{NAME} = ".ParseExpr($e->{PROPERTIES}->{value}, $env).";";
|
||||
}
|
||||
|
||||
pidl "TDR_CHECK(tdr_$t\_$e->{TYPE}(tdr$name$switch, &v->$e->{NAME}$array));";
|
||||
|
||||
if ($array) { deindent; pidl "}"; }
|
||||
|
||||
if (has_property($e, "flag")) {
|
||||
pidl "tdr->flags = saved_flags;";
|
||||
deindent;
|
||||
pidl "}";
|
||||
}
|
||||
}
|
||||
|
||||
sub ParserStruct($$$$)
|
||||
{
|
||||
my ($e,$n,$t,$p) = @_;
|
||||
|
||||
fn_declare($p,,"NTSTATUS tdr_$t\_$n (struct tdr_$t *tdr".typearg($t).", struct $n *v)");
|
||||
pidl "{"; indent;
|
||||
pidl "int i;" if (ContainsArray($e));
|
||||
|
||||
if ($t eq "print") {
|
||||
pidl "tdr->print(tdr, \"\%-25s: struct $n\", name);";
|
||||
pidl "tdr->level++;";
|
||||
}
|
||||
|
||||
my %env = map { $_->{NAME} => "v->$_->{NAME}" } @{$e->{ELEMENTS}};
|
||||
$env{"this"} = "v";
|
||||
ParserElement($_, $t, \%env) foreach (@{$e->{ELEMENTS}});
|
||||
|
||||
if ($t eq "print") {
|
||||
pidl "tdr->level--;";
|
||||
}
|
||||
|
||||
pidl "return NT_STATUS_OK;";
|
||||
|
||||
deindent; pidl "}";
|
||||
}
|
||||
|
||||
sub ParserUnion($$$$)
|
||||
{
|
||||
my ($e,$n,$t,$p) = @_;
|
||||
|
||||
fn_declare($p,"NTSTATUS tdr_$t\_$n(struct tdr_$t *tdr".typearg($t).", int level, union $n *v)");
|
||||
pidl "{"; indent;
|
||||
pidl "int i;" if (ContainsArray($e));
|
||||
|
||||
if ($t eq "print") {
|
||||
pidl "tdr->print(tdr, \"\%-25s: union $n\", name);";
|
||||
pidl "tdr->level++;";
|
||||
}
|
||||
|
||||
pidl "switch (level) {"; indent;
|
||||
foreach (@{$e->{ELEMENTS}}) {
|
||||
if (has_property($_, "case")) {
|
||||
pidl "case " . $_->{PROPERTIES}->{case} . ":";
|
||||
} elsif (has_property($_, "default")) {
|
||||
pidl "default:";
|
||||
}
|
||||
indent; ParserElement($_, $t, {}); deindent;
|
||||
pidl "break;";
|
||||
}
|
||||
deindent; pidl "}";
|
||||
|
||||
if ($t eq "print") {
|
||||
pidl "tdr->level--;";
|
||||
}
|
||||
|
||||
pidl "return NT_STATUS_OK;\n";
|
||||
deindent; pidl "}";
|
||||
}
|
||||
|
||||
sub ParserBitmap($$$$)
|
||||
{
|
||||
my ($e,$n,$t,$p) = @_;
|
||||
return if ($p);
|
||||
pidl "#define tdr_$t\_$n tdr_$t\_" . Parse::Pidl::Typelist::bitmap_type_fn($e);
|
||||
}
|
||||
|
||||
sub ParserEnum($$$$)
|
||||
{
|
||||
my ($e,$n,$t,$p) = @_;
|
||||
my $bt = ($e->{PROPERTIES}->{base_type} or "uint8");
|
||||
|
||||
fn_declare($p, "NTSTATUS tdr_$t\_$n (struct tdr_$t *tdr".typearg($t).", enum $n *v)");
|
||||
pidl "{";
|
||||
if ($t eq "pull") {
|
||||
pidl "\t$bt\_t r;";
|
||||
pidl "\tTDR_CHECK(tdr_$t\_$bt(tdr, mem_ctx, \&r));";
|
||||
pidl "\t*v = r;";
|
||||
} elsif ($t eq "push") {
|
||||
pidl "\tTDR_CHECK(tdr_$t\_$bt(tdr, ($bt\_t *)v));";
|
||||
} elsif ($t eq "print") {
|
||||
pidl "\t/* FIXME */";
|
||||
}
|
||||
pidl "\treturn NT_STATUS_OK;";
|
||||
pidl "}";
|
||||
}
|
||||
|
||||
sub ParserTypedef($$)
|
||||
{
|
||||
my ($e,$t) = @_;
|
||||
|
||||
return if (has_property($e, "no$t"));
|
||||
|
||||
$e->{DATA}->{PROPERTIES} = $e->{PROPERTIES};
|
||||
|
||||
{ STRUCT => \&ParserStruct, UNION => \&ParserUnion,
|
||||
ENUM => \&ParserEnum, BITMAP => \&ParserBitmap
|
||||
}->{$e->{DATA}->{TYPE}}->($e->{DATA}, $e->{NAME}, $t, has_property($e, "public"));
|
||||
|
||||
pidl "";
|
||||
}
|
||||
|
||||
sub ParserInterface($)
|
||||
{
|
||||
my $x = shift;
|
||||
|
||||
pidl_hdr "#ifndef __TDR_$x->{NAME}_HEADER__";
|
||||
pidl_hdr "#define __TDR_$x->{NAME}_HEADER__";
|
||||
|
||||
foreach (@{$x->{DATA}}) {
|
||||
next if ($_->{TYPE} ne "TYPEDEF");
|
||||
ParserTypedef($_, "pull");
|
||||
ParserTypedef($_, "push");
|
||||
ParserTypedef($_, "print");
|
||||
}
|
||||
|
||||
pidl_hdr "#endif /* __TDR_$x->{NAME}_HEADER__ */";
|
||||
}
|
||||
|
||||
sub Parser($$$)
|
||||
{
|
||||
my ($idl,$hdrname,$baseheader) = @_;
|
||||
$ret = ""; $ret_hdr = "";
|
||||
pidl "/* autogenerated by pidl */";
|
||||
if (is_intree()) {
|
||||
pidl "#include \"includes.h\"";
|
||||
} else {
|
||||
pidl "#include <stdio.h>";
|
||||
pidl "#include <stdbool.h>";
|
||||
pidl "#include <stdlib.h>";
|
||||
pidl "#include <stdint.h>";
|
||||
pidl "#include <stdarg.h>";
|
||||
pidl "#include <string.h>";
|
||||
pidl "#include <core/nterr.h>";
|
||||
}
|
||||
pidl "#include \"$hdrname\"";
|
||||
pidl "";
|
||||
pidl_hdr "/* autogenerated by pidl */";
|
||||
pidl_hdr "#include \"$baseheader\"";
|
||||
pidl_hdr choose_header("tdr/tdr.h", "tdr.h");
|
||||
pidl_hdr "";
|
||||
|
||||
foreach (@$idl) { ParserInterface($_) if ($_->{TYPE} eq "INTERFACE"); }
|
||||
return ($ret_hdr, $ret);
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,99 @@
|
||||
###################################################
|
||||
# server template function generator
|
||||
# Copyright tridge@samba.org 2003
|
||||
# released under the GNU GPL
|
||||
|
||||
package Parse::Pidl::Samba4::Template;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '0.01';
|
||||
|
||||
use strict;
|
||||
|
||||
my($res);
|
||||
|
||||
#####################################################################
|
||||
# produce boilerplate code for a interface
|
||||
sub Template($)
|
||||
{
|
||||
my($interface) = shift;
|
||||
my($data) = $interface->{DATA};
|
||||
my $name = $interface->{NAME};
|
||||
|
||||
$res .=
|
||||
"/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
endpoint server for the $name pipe
|
||||
|
||||
Copyright (C) YOUR NAME HERE YEAR
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include \"includes.h\"
|
||||
#include \"rpc_server/dcerpc_server.h\"
|
||||
#include \"librpc/gen_ndr/ndr_$name.h\"
|
||||
#include \"rpc_server/common/common.h\"
|
||||
|
||||
";
|
||||
|
||||
foreach my $d (@{$data}) {
|
||||
if ($d->{TYPE} eq "FUNCTION") {
|
||||
my $fname = $d->{NAME};
|
||||
$res .=
|
||||
"
|
||||
/*
|
||||
$fname
|
||||
*/
|
||||
static $d->{RETURN_TYPE} $fname(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
|
||||
struct $fname *r)
|
||||
{
|
||||
";
|
||||
|
||||
if ($d->{RETURN_TYPE} eq "void") {
|
||||
$res .= "\tDCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);\n";
|
||||
} else {
|
||||
$res .= "\tDCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);\n";
|
||||
}
|
||||
|
||||
$res .= "}
|
||||
|
||||
";
|
||||
}
|
||||
}
|
||||
|
||||
$res .=
|
||||
"
|
||||
/* include the generated boilerplate */
|
||||
#include \"librpc/gen_ndr/ndr_$name\_s.c\"
|
||||
"
|
||||
}
|
||||
|
||||
|
||||
#####################################################################
|
||||
# parse a parsed IDL structure back into an IDL file
|
||||
sub Parse($)
|
||||
{
|
||||
my($idl) = shift;
|
||||
$res = "";
|
||||
foreach my $x (@{$idl}) {
|
||||
($x->{TYPE} eq "INTERFACE") &&
|
||||
Template($x);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,230 @@
|
||||
###################################################
|
||||
# Samba4 parser generator for IDL structures
|
||||
# Copyright jelmer@samba.org 2005
|
||||
# released under the GNU GPL
|
||||
|
||||
package Parse::Pidl::Typelist;
|
||||
|
||||
require Exporter;
|
||||
@ISA = qw(Exporter);
|
||||
@EXPORT_OK = qw(hasType getType mapType scalar_is_reference expandAlias);
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '0.01';
|
||||
|
||||
use Parse::Pidl::Util qw(has_property);
|
||||
use strict;
|
||||
|
||||
my %typedefs = ();
|
||||
|
||||
my @reference_scalars = (
|
||||
"string", "string_array", "nbt_string",
|
||||
"wrepl_nbt_name", "ipv4address"
|
||||
);
|
||||
|
||||
# a list of known scalar types
|
||||
my %scalars = (
|
||||
"void" => "void",
|
||||
"char" => "char",
|
||||
"int8" => "int8_t",
|
||||
"uint8" => "uint8_t",
|
||||
"int16" => "int16_t",
|
||||
"uint16" => "uint16_t",
|
||||
"int32" => "int32_t",
|
||||
"uint32" => "uint32_t",
|
||||
"hyper" => "uint64_t",
|
||||
"dlong" => "int64_t",
|
||||
"udlong" => "uint64_t",
|
||||
"udlongr" => "uint64_t",
|
||||
"pointer" => "void*",
|
||||
"DATA_BLOB" => "DATA_BLOB",
|
||||
"string" => "const char *",
|
||||
"string_array" => "const char **",
|
||||
"time_t" => "time_t",
|
||||
"NTTIME" => "NTTIME",
|
||||
"NTTIME_1sec" => "NTTIME",
|
||||
"NTTIME_hyper" => "NTTIME",
|
||||
"WERROR" => "WERROR",
|
||||
"NTSTATUS" => "NTSTATUS",
|
||||
"COMRESULT" => "COMRESULT",
|
||||
"nbt_string" => "const char *",
|
||||
"wrepl_nbt_name"=> "struct nbt_name *",
|
||||
"ipv4address" => "const char *",
|
||||
);
|
||||
|
||||
my %aliases = (
|
||||
"error_status_t" => "uint32",
|
||||
"boolean8" => "uint8",
|
||||
"boolean32" => "uint32",
|
||||
"DWORD" => "uint32",
|
||||
"int" => "int32",
|
||||
"WORD" => "uint16",
|
||||
"char" => "uint8",
|
||||
"long" => "int32",
|
||||
"short" => "int16",
|
||||
"HYPER_T" => "hyper",
|
||||
"HRESULT" => "COMRESULT",
|
||||
);
|
||||
|
||||
sub expandAlias($)
|
||||
{
|
||||
my $name = shift;
|
||||
|
||||
return $aliases{$name} if defined($aliases{$name});
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
# 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} if defined($scalars{$name});
|
||||
|
||||
die("Unknown scalar type $name");
|
||||
}
|
||||
|
||||
sub addType($)
|
||||
{
|
||||
my $t = shift;
|
||||
$typedefs{$t->{NAME}} = $t;
|
||||
}
|
||||
|
||||
sub getType($)
|
||||
{
|
||||
my $t = shift;
|
||||
return undef if not hasType($t);
|
||||
return $typedefs{$t};
|
||||
}
|
||||
|
||||
sub typeIs($$)
|
||||
{
|
||||
my ($t,$tt) = @_;
|
||||
|
||||
return 1 if (hasType($t) and getType($t)->{DATA}->{TYPE} eq $tt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub hasType($)
|
||||
{
|
||||
my $t = shift;
|
||||
return 1 if defined($typedefs{$t});
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub is_scalar($)
|
||||
{
|
||||
my $type = shift;
|
||||
|
||||
return 0 unless(hasType($type));
|
||||
|
||||
if (my $dt = getType($type)->{DATA}->{TYPE}) {
|
||||
return 1 if ($dt eq "SCALAR" or $dt eq "ENUM" or $dt eq "BITMAP");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub scalar_is_reference($)
|
||||
{
|
||||
my $name = shift;
|
||||
|
||||
return 1 if (grep(/^$name$/, @reference_scalars));
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub RegisterScalars()
|
||||
{
|
||||
foreach (keys %scalars) {
|
||||
addType({
|
||||
NAME => $_,
|
||||
TYPE => "TYPEDEF",
|
||||
DATA => {
|
||||
TYPE => "SCALAR",
|
||||
NAME => $_
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
sub enum_type_fn($)
|
||||
{
|
||||
my $enum = shift;
|
||||
$enum->{TYPE} eq "ENUM" or die("not an enum");
|
||||
if (has_property($enum->{PARENT}, "enum8bit")) {
|
||||
return "uint8";
|
||||
} elsif (has_property($enum->{PARENT}, "v1_enum")) {
|
||||
return "uint32";
|
||||
}
|
||||
return "uint16";
|
||||
}
|
||||
|
||||
sub bitmap_type_fn($)
|
||||
{
|
||||
my $bitmap = shift;
|
||||
|
||||
$bitmap->{TYPE} eq "BITMAP" or die("not a bitmap");
|
||||
|
||||
if (has_property($bitmap, "bitmap8bit")) {
|
||||
return "uint8";
|
||||
} elsif (has_property($bitmap, "bitmap16bit")) {
|
||||
return "uint16";
|
||||
} elsif (has_property($bitmap, "bitmap64bit")) {
|
||||
return "hyper";
|
||||
}
|
||||
return "uint32";
|
||||
}
|
||||
|
||||
sub mapType($)
|
||||
{
|
||||
my $t = shift;
|
||||
return "void" unless defined($t);
|
||||
my $dt;
|
||||
$t = expandAlias($t);
|
||||
|
||||
unless ($dt or ($dt = getType($t))) {
|
||||
# Best guess
|
||||
return "struct $t";
|
||||
}
|
||||
return mapScalarType($t) if ($dt->{DATA}->{TYPE} eq "SCALAR");
|
||||
return "$dt->{NAME}" if ($dt->{DATA}{TYPE} eq "DECORATED");
|
||||
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");
|
||||
|
||||
if ($dt->{DATA}->{TYPE} eq "BITMAP") {
|
||||
return mapScalarType(bitmap_type_fn($dt->{DATA}));
|
||||
}
|
||||
|
||||
die("Unknown type $dt->{DATA}->{TYPE}");
|
||||
}
|
||||
|
||||
sub LoadIdl($)
|
||||
{
|
||||
my $idl = shift;
|
||||
|
||||
foreach my $x (@{$idl}) {
|
||||
next if $x->{TYPE} ne "INTERFACE";
|
||||
|
||||
# DCOM interfaces can be types as well
|
||||
addType({
|
||||
NAME => $x->{NAME},
|
||||
TYPE => "TYPEDEF",
|
||||
DATA => $x
|
||||
}) if (has_property($x, "object"));
|
||||
|
||||
foreach my $y (@{$x->{DATA}}) {
|
||||
addType($y) if (
|
||||
$y->{TYPE} eq "TYPEDEF"
|
||||
or $y->{TYPE} eq "DECLARE");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RegisterScalars();
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,123 @@
|
||||
###################################################
|
||||
# utility functions to support pidl
|
||||
# Copyright tridge@samba.org 2000
|
||||
# released under the GNU GPL
|
||||
package Parse::Pidl::Util;
|
||||
|
||||
require Exporter;
|
||||
@ISA = qw(Exporter);
|
||||
@EXPORT = qw(has_property property_matches ParseExpr is_constant make_str print_uuid);
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '0.01';
|
||||
|
||||
use strict;
|
||||
|
||||
#####################################################################
|
||||
# a dumper wrapper to prevent dependence on the Data::Dumper module
|
||||
# unless we actually need it
|
||||
sub MyDumper($)
|
||||
{
|
||||
require Data::Dumper;
|
||||
my $s = shift;
|
||||
return Data::Dumper::Dumper($s);
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# see if a pidl property list contains a given property
|
||||
sub has_property($$)
|
||||
{
|
||||
my($e) = shift;
|
||||
my($p) = shift;
|
||||
|
||||
if (!defined $e->{PROPERTIES}) {
|
||||
return undef;
|
||||
}
|
||||
|
||||
return $e->{PROPERTIES}->{$p};
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# see if a pidl property matches a value
|
||||
sub property_matches($$$)
|
||||
{
|
||||
my($e) = shift;
|
||||
my($p) = shift;
|
||||
my($v) = shift;
|
||||
|
||||
if (!defined has_property($e, $p)) {
|
||||
return undef;
|
||||
}
|
||||
|
||||
if ($e->{PROPERTIES}->{$p} =~ /$v/) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
# return 1 if the string is a C constant
|
||||
sub is_constant($)
|
||||
{
|
||||
my $s = shift;
|
||||
if (defined $s && $s =~ /^\d/) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
# return a "" quoted string, unless already quoted
|
||||
sub make_str($)
|
||||
{
|
||||
my $str = shift;
|
||||
if (substr($str, 0, 1) eq "\"") {
|
||||
return $str;
|
||||
}
|
||||
return "\"" . $str . "\"";
|
||||
}
|
||||
|
||||
sub print_uuid($)
|
||||
{
|
||||
my ($uuid) = @_;
|
||||
$uuid =~ s/"//g;
|
||||
my ($time_low,$time_mid,$time_hi,$clock_seq,$node) = split /-/, $uuid;
|
||||
|
||||
my @clock_seq = $clock_seq =~ /(..)/g;
|
||||
my @node = $node =~ /(..)/g;
|
||||
|
||||
return "{0x$time_low,0x$time_mid,0x$time_hi," .
|
||||
"{".join(',', map {"0x$_"} @clock_seq)."}," .
|
||||
"{".join(',', map {"0x$_"} @node)."}}";
|
||||
}
|
||||
|
||||
# a hack to build on platforms that don't like negative enum values
|
||||
my $useUintEnums = 0;
|
||||
sub setUseUintEnums($)
|
||||
{
|
||||
$useUintEnums = shift;
|
||||
}
|
||||
sub useUintEnums()
|
||||
{
|
||||
return $useUintEnums;
|
||||
}
|
||||
|
||||
sub ParseExpr($$)
|
||||
{
|
||||
my($expr,$varlist) = @_;
|
||||
|
||||
die("Undefined value in ParseExpr " . (caller(1))[3] . (caller(0))[2]) if not defined($expr);
|
||||
|
||||
my @tokens = split /((?:[A-Za-z_])(?:(?:(?:[A-Za-z0-9_.])|(?:->))+))/, $expr;
|
||||
my $ret = "";
|
||||
|
||||
foreach my $t (@tokens) {
|
||||
if (defined($varlist->{$t})) {
|
||||
$ret .= $varlist->{$t};
|
||||
} else {
|
||||
$ret .= $t;
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,360 @@
|
||||
###################################################
|
||||
# parse an Wireshark conformance file
|
||||
# Copyright jelmer@samba.org 2005
|
||||
# released under the GNU GPL
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Parse::Pidl::Wireshark::Conformance - Conformance file parser for Wireshark
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module supports parsing Wireshark conformance files (*.cnf).
|
||||
|
||||
=head1 FILE FORMAT
|
||||
|
||||
Pidl needs additional data for Wireshark output. This data is read from
|
||||
so-called conformance files. This section describes the format of these
|
||||
files.
|
||||
|
||||
Conformance files are simple text files with a single command on each line.
|
||||
Empty lines and lines starting with a '#' character are ignored.
|
||||
Arguments to commands are seperated by spaces.
|
||||
|
||||
The following commands are currently supported:
|
||||
|
||||
=over 4
|
||||
|
||||
=item I<TYPE> name dissector ft_type base_type mask valsstring alignment
|
||||
|
||||
Register new data type with specified name, what dissector function to call
|
||||
and what properties to give header fields for elements of this type.
|
||||
|
||||
=item I<NOEMIT> type
|
||||
|
||||
Suppress emitting a dissect_type function for the specified type
|
||||
|
||||
=item I<PARAM_VALUE> type param
|
||||
|
||||
Set parameter to specify to dissector function for given type.
|
||||
|
||||
=item I<HF_FIELD> hf title filter ft_type base_type valsstring mask description
|
||||
|
||||
Generate a custom header field with specified properties.
|
||||
|
||||
=item I<HF_RENAME> old_hf_name new_hf_name
|
||||
|
||||
Force the use of new_hf_name when the parser generator was going to
|
||||
use old_hf_name.
|
||||
|
||||
This can be used in conjunction with HF_FIELD in order to make more than
|
||||
one element use the same filter name.
|
||||
|
||||
=item I<STRIP_PREFIX> prefix
|
||||
|
||||
Remove the specified prefix from all function names (if present).
|
||||
|
||||
=item I<PROTOCOL> longname shortname filtername
|
||||
|
||||
Change the short-, long- and filter-name for the current interface in
|
||||
Wireshark.
|
||||
|
||||
=item I<FIELD_DESCRIPTION> field desc
|
||||
|
||||
Change description for the specified header field. `field' is the hf name of the field.
|
||||
|
||||
=item I<IMPORT> dissector code...
|
||||
|
||||
Code to insert when generating the specified dissector. @HF@ and
|
||||
@PARAM@ will be substituted.
|
||||
|
||||
=item I<TFS> hf_name "true string" "false string"
|
||||
|
||||
Override the text shown when a bitmap boolean value is enabled or disabled.
|
||||
|
||||
=item I<MANUAL> fn_name
|
||||
|
||||
Force pidl to not generate a particular function but allow the user
|
||||
to write a function manually. This can be used to remove the function
|
||||
for only one level for a particular element rather than all the functions and
|
||||
ett/hf variables for a particular element as the NOEMIT command does.
|
||||
|
||||
=back
|
||||
|
||||
=head1 EXAMPLE
|
||||
|
||||
INFO_KEY OpenKey.Ke
|
||||
|
||||
=cut
|
||||
|
||||
package Parse::Pidl::Wireshark::Conformance;
|
||||
|
||||
require Exporter;
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '0.01';
|
||||
|
||||
@ISA = qw(Exporter);
|
||||
@EXPORT_OK = qw(ReadConformance);
|
||||
|
||||
use strict;
|
||||
|
||||
use Parse::Pidl::Util qw(has_property);
|
||||
|
||||
sub handle_type($$$$$$$$$$)
|
||||
{
|
||||
my ($pos,$data,$name,$dissectorname,$ft_type,$base_type,$mask,$valsstring,$alignment) = @_;
|
||||
|
||||
unless(defined($alignment)) {
|
||||
print "$pos: error incomplete TYPE command\n";
|
||||
return;
|
||||
}
|
||||
|
||||
unless ($dissectorname =~ /.*dissect_.*/) {
|
||||
print "$pos: warning: dissector name does not contain `dissect'\n";
|
||||
}
|
||||
|
||||
unless(valid_ft_type($ft_type)) {
|
||||
print "$pos: warning: invalid FT_TYPE `$ft_type'\n";
|
||||
}
|
||||
|
||||
unless (valid_base_type($base_type)) {
|
||||
print "$pos: warning: invalid BASE_TYPE `$base_type'\n";
|
||||
}
|
||||
|
||||
$data->{types}->{$name} = {
|
||||
NAME => $name,
|
||||
POS => $pos,
|
||||
USED => 0,
|
||||
DISSECTOR_NAME => $dissectorname,
|
||||
FT_TYPE => $ft_type,
|
||||
BASE_TYPE => $base_type,
|
||||
MASK => $mask,
|
||||
VALSSTRING => $valsstring,
|
||||
ALIGNMENT => $alignment
|
||||
};
|
||||
}
|
||||
|
||||
sub handle_tfs($$$$$)
|
||||
{
|
||||
my ($pos,$data,$hf,$trues,$falses) = @_;
|
||||
|
||||
unless(defined($falses)) {
|
||||
print "$pos: error: incomplete TFS command\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$data->{tfs}->{$hf} = {
|
||||
TRUE_STRING => $trues,
|
||||
FALSE_STRING => $falses
|
||||
};
|
||||
}
|
||||
|
||||
sub handle_hf_rename($$$$)
|
||||
{
|
||||
my ($pos,$data,$old,$new) = @_;
|
||||
|
||||
unless(defined($new)) {
|
||||
print "$pos: error: incomplete HF_RENAME command\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$data->{hf_renames}->{$old} = {
|
||||
OLDNAME => $old,
|
||||
NEWNAME => $new,
|
||||
POS => $pos,
|
||||
USED => 0
|
||||
};
|
||||
}
|
||||
|
||||
sub handle_param_value($$$$)
|
||||
{
|
||||
my ($pos,$data,$dissector_name,$value) = @_;
|
||||
|
||||
unless(defined($value)) {
|
||||
print "$pos: error: incomplete PARAM_VALUE command\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$data->{dissectorparams}->{$dissector_name} = {
|
||||
DISSECTOR => $dissector_name,
|
||||
PARAM => $value,
|
||||
POS => $pos,
|
||||
USED => 0
|
||||
};
|
||||
}
|
||||
|
||||
sub valid_base_type($)
|
||||
{
|
||||
my $t = shift;
|
||||
return 0 unless($t =~ /^BASE_.*/);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub valid_ft_type($)
|
||||
{
|
||||
my $t = shift;
|
||||
return 0 unless($t =~ /^FT_.*/);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub handle_hf_field($$$$$$$$$$)
|
||||
{
|
||||
my ($pos,$data,$index,$name,$filter,$ft_type,$base_type,$valsstring,$mask,$blurb) = @_;
|
||||
|
||||
unless(defined($blurb)) {
|
||||
print "$pos: error: incomplete HF_FIELD command\n";
|
||||
return;
|
||||
}
|
||||
|
||||
unless(valid_ft_type($ft_type)) {
|
||||
print "$pos: warning: invalid FT_TYPE `$ft_type'\n";
|
||||
}
|
||||
|
||||
unless(valid_base_type($base_type)) {
|
||||
print "$pos: warning: invalid BASE_TYPE `$base_type'\n";
|
||||
}
|
||||
|
||||
$data->{header_fields}->{$index} = {
|
||||
INDEX => $index,
|
||||
POS => $pos,
|
||||
USED => 0,
|
||||
NAME => $name,
|
||||
FILTER => $filter,
|
||||
FT_TYPE => $ft_type,
|
||||
BASE_TYPE => $base_type,
|
||||
VALSSTRING => $valsstring,
|
||||
MASK => $mask,
|
||||
BLURB => $blurb
|
||||
};
|
||||
}
|
||||
|
||||
sub handle_strip_prefix($$$)
|
||||
{
|
||||
my ($pos,$data,$x) = @_;
|
||||
|
||||
push (@{$data->{strip_prefixes}}, $x);
|
||||
}
|
||||
|
||||
sub handle_noemit($$$)
|
||||
{
|
||||
my ($pos,$data,$type) = @_;
|
||||
|
||||
if (defined($type)) {
|
||||
$data->{noemit}->{$type} = 1;
|
||||
} else {
|
||||
$data->{noemit_dissector} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
sub handle_manual($$$)
|
||||
{
|
||||
my ($pos,$data,$fn) = @_;
|
||||
|
||||
$data->{manual}->{$fn} = 1;
|
||||
}
|
||||
|
||||
sub handle_protocol($$$$$$)
|
||||
{
|
||||
my ($pos, $data, $name, $longname, $shortname, $filtername) = @_;
|
||||
|
||||
$data->{protocols}->{$name} = {
|
||||
LONGNAME => $longname,
|
||||
SHORTNAME => $shortname,
|
||||
FILTERNAME => $filtername
|
||||
};
|
||||
}
|
||||
|
||||
sub handle_fielddescription($$$$)
|
||||
{
|
||||
my ($pos,$data,$field,$desc) = @_;
|
||||
|
||||
$data->{fielddescription}->{$field} = {
|
||||
DESCRIPTION => $desc,
|
||||
POS => $pos,
|
||||
USED => 0
|
||||
};
|
||||
}
|
||||
|
||||
sub handle_import
|
||||
{
|
||||
my $pos = shift @_;
|
||||
my $data = shift @_;
|
||||
my $dissectorname = shift @_;
|
||||
|
||||
unless(defined($dissectorname)) {
|
||||
print "$pos: error: no dissectorname specified\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$data->{imports}->{$dissectorname} = {
|
||||
NAME => $dissectorname,
|
||||
DATA => join(' ', @_),
|
||||
USED => 0,
|
||||
POS => $pos
|
||||
};
|
||||
}
|
||||
|
||||
my %field_handlers = (
|
||||
TYPE => \&handle_type,
|
||||
NOEMIT => \&handle_noemit,
|
||||
MANUAL => \&handle_manual,
|
||||
PARAM_VALUE => \&handle_param_value,
|
||||
HF_FIELD => \&handle_hf_field,
|
||||
HF_RENAME => \&handle_hf_rename,
|
||||
TFS => \&handle_tfs,
|
||||
STRIP_PREFIX => \&handle_strip_prefix,
|
||||
PROTOCOL => \&handle_protocol,
|
||||
FIELD_DESCRIPTION => \&handle_fielddescription,
|
||||
IMPORT => \&handle_import
|
||||
);
|
||||
|
||||
sub ReadConformance($$)
|
||||
{
|
||||
my ($f,$data) = @_;
|
||||
|
||||
$data->{override} = "";
|
||||
|
||||
my $incodeblock = 0;
|
||||
|
||||
open(IN,"<$f") or return undef;
|
||||
|
||||
my $ln = 0;
|
||||
|
||||
foreach (<IN>) {
|
||||
$ln++;
|
||||
next if (/^#.*$/);
|
||||
next if (/^$/);
|
||||
|
||||
s/[\r\n]//g;
|
||||
|
||||
if ($_ eq "CODE START") {
|
||||
$incodeblock = 1;
|
||||
next;
|
||||
} elsif ($incodeblock and $_ eq "CODE END") {
|
||||
$incodeblock = 0;
|
||||
next;
|
||||
} elsif ($incodeblock) {
|
||||
$data->{override}.="$_\n";
|
||||
next;
|
||||
}
|
||||
|
||||
my @fields = /([^ "]+|"[^"]+")/g;
|
||||
|
||||
my $cmd = $fields[0];
|
||||
|
||||
shift @fields;
|
||||
|
||||
if (not defined($field_handlers{$cmd})) {
|
||||
print "$f:$ln: warning: Unknown command `$cmd'\n";
|
||||
next;
|
||||
}
|
||||
|
||||
$field_handlers{$cmd}("$f:$ln", $data, @fields);
|
||||
}
|
||||
|
||||
close(IN);
|
||||
}
|
||||
|
||||
1;
|
||||
File diff suppressed because it is too large
Load Diff
Executable
+777
@@ -0,0 +1,777 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
###################################################
|
||||
# package to parse IDL files and generate code for
|
||||
# rpc functions in Samba
|
||||
# Copyright tridge@samba.org 2000-2003
|
||||
# Copyright jelmer@samba.org 2005
|
||||
# released under the GNU GPL
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
pidl - An IDL compiler written in Perl
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
pidl --help
|
||||
|
||||
pidl [--outputdir[=OUTNAME]] [--includedir DIR...] [--parse-idl-tree] [--dump-idl-tree] [--dump-ndr-tree] [--header[=OUTPUT]] [--ejs[=OUTPUT]] [--swig[=OUTPUT]] [--uint-enums] [--ndr-parser[=OUTPUT]] [--client] [--server] [--dcom-proxy] [--com-header] [--warn-compat] [--quiet] [--verbose] [--template] [--ws-parser[=OUTPUT]] [--diff] [--dump-idl] [--tdr-parser[=OUTPUT]] [--samba3-ndr-client[=OUTPUT]] [--samba3-ndr-server[=OUTPUT]] [<idlfile>.idl]...
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
pidl is an IDL compiler written in Perl that aims to be somewhat
|
||||
compatible with the midl compiler. IDL is short for
|
||||
"Interface Definition Language".
|
||||
|
||||
pidl can generate stubs for DCE/RPC server code, DCE/RPC
|
||||
client code and Wireshark dissectors for DCE/RPC traffic.
|
||||
|
||||
IDL compilers like pidl take a description
|
||||
of an interface as their input and use it to generate C
|
||||
(though support for other languages may be added later) code that
|
||||
can use these interfaces, pretty print data sent
|
||||
using these interfaces, or even generate Wireshark
|
||||
dissectors that can parse data sent over the
|
||||
wire by these interfaces.
|
||||
|
||||
pidl takes IDL files in the same format as is used by midl,
|
||||
converts it to a .pidl file (which contains pidl's internal representation of the interface) and can then generate whatever output you need.
|
||||
.pidl files should be used for debugging purposes only. Write your
|
||||
interface definitions in .idl format.
|
||||
|
||||
The goal of pidl is to implement a IDL compiler that can be used
|
||||
while developing the RPC subsystem in Samba (for
|
||||
both marshalling/unmarshalling and debugging purposes).
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over 4
|
||||
|
||||
=item I<--help>
|
||||
|
||||
Show list of available options.
|
||||
|
||||
=item I<--outputdir OUTNAME>
|
||||
|
||||
Write output files to the specified directory. Defaults to the current
|
||||
directory.
|
||||
|
||||
=item I<--includedir DIR>
|
||||
|
||||
Add DIR to the search path used by the preprocessor. This option can be
|
||||
specified multiple times.
|
||||
|
||||
=item I<--parse-idl-tree>
|
||||
|
||||
Read internal tree structure from input files rather
|
||||
than assuming they contain IDL.
|
||||
|
||||
=item I<--dump-idl>
|
||||
|
||||
Generate a new IDL file. File will be named OUTNAME.idl.
|
||||
|
||||
=item I<--header>
|
||||
|
||||
Generate a C header file for the specified interface. Filename defaults to OUTNAME.h.
|
||||
|
||||
=item I<--ndr-parser>
|
||||
|
||||
Generate a C file and C header containing NDR parsers. The filename for
|
||||
the parser defaults to ndr_OUTNAME.c. The header filename will be the
|
||||
parser filename with the extension changed from .c to .h.
|
||||
|
||||
=item I<--tdr-parser>
|
||||
|
||||
Generate a C file and C header containing TDR parsers. The filename for
|
||||
the parser defaults to tdr_OUTNAME.c. The header filename will be the
|
||||
parser filename with the extension changed from .c to .h.
|
||||
|
||||
=item I<--server>
|
||||
|
||||
Generate boilerplate for the RPC server that implements
|
||||
the interface. Filename defaults to ndr_OUTNAME_s.c.
|
||||
|
||||
=item I<--template>
|
||||
|
||||
Generate stubs for a RPC server that implements the interface. Output will
|
||||
be written to stdout.
|
||||
|
||||
=item I<--ws-parser>
|
||||
|
||||
Generate an Wireshark dissector (in C) and header file. The dissector filename
|
||||
defaults to packet-dcerpc-OUTNAME.c while the header filename defaults to
|
||||
packet-dcerpc-OUTNAME.h.
|
||||
|
||||
Pidl will read additional data from an Wireshark conformance file if present.
|
||||
Such a file should have the same location as the IDL file but with the
|
||||
extension I<cnf> rather than I<idl>. See L<Parse::Pidl::Wireshark::Conformance>
|
||||
for details on the format of this file.
|
||||
|
||||
=item I<--diff>
|
||||
|
||||
Parse an IDL file, generate a new IDL file based on the internal data
|
||||
structures and see if there are any differences with the original IDL file.
|
||||
Useful for debugging pidl.
|
||||
|
||||
=item I<--dump-idl-tree>
|
||||
|
||||
Tell pidl to dump the internal tree representation of an IDL
|
||||
file the to disk. Useful for debugging pidl.
|
||||
|
||||
=item I<--dump-ndr-tree>
|
||||
|
||||
Tell pidl to dump the internal NDR information tree it generated
|
||||
from the IDL file to disk. Useful for debugging pidl.
|
||||
|
||||
=item I<--samba3-ndr-client>
|
||||
|
||||
Generate client calls for Samba3, to be placed in rpc_client/. Instead of
|
||||
calling out to the code in Samba3's rpc_parse/, this will call out to
|
||||
Samba4's NDR code instead.
|
||||
|
||||
=item I<--samba3-ndr-server>
|
||||
|
||||
Generate server calls for Samba3, to be placed in rpc_server/. Instead of
|
||||
calling out to the code in Samba3's rpc_parse/, this will call out to
|
||||
Samba4's NDR code instead.
|
||||
|
||||
=back
|
||||
|
||||
=head1 IDL SYNTAX
|
||||
|
||||
IDL files are always preprocessed using the C preprocessor.
|
||||
|
||||
Pretty much everything in an interface (the interface itself, functions,
|
||||
parameters) can have attributes (or properties whatever name you give them).
|
||||
Attributes always prepend the element they apply to and are surrounded
|
||||
by square brackets ([]). Multiple attributes are separated by comma's;
|
||||
arguments to attributes are specified between parentheses.
|
||||
|
||||
See the section COMPATIBILITY for the list of attributes that
|
||||
pidl supports.
|
||||
|
||||
C-style comments can be used.
|
||||
|
||||
=head2 CONFORMANT ARRAYS
|
||||
|
||||
A conformant array is one with that ends in [*] or []. The strange
|
||||
things about conformant arrays are that they can only appear as the last
|
||||
element of a structure (unless there is a pointer to the conformant array,
|
||||
of course) and the array size appears before the structure itself on the wire.
|
||||
|
||||
So, in this example:
|
||||
|
||||
typedef struct {
|
||||
long abc;
|
||||
long count;
|
||||
long foo;
|
||||
[size_is(count)] long s[*];
|
||||
} Struct1;
|
||||
|
||||
it appears like this:
|
||||
|
||||
[size_is] [abc] [count] [foo] [s...]
|
||||
|
||||
the first [size_is] field is the allocation size of the array, and
|
||||
occurs before the array elements and even before the structure
|
||||
alignment.
|
||||
|
||||
Note that size_is() can refer to a constant, but that doesn't change
|
||||
the wire representation. It does not make the array a fixed array.
|
||||
|
||||
midl.exe would write the above array as the following C header:
|
||||
|
||||
typedef struct {
|
||||
long abc;
|
||||
long count;
|
||||
long foo;
|
||||
long s[1];
|
||||
} Struct1;
|
||||
|
||||
pidl takes a different approach, and writes it like this:
|
||||
|
||||
typedef struct {
|
||||
long abc;
|
||||
long count;
|
||||
long foo;
|
||||
long *s;
|
||||
} Struct1;
|
||||
|
||||
=head2 VARYING ARRAYS
|
||||
|
||||
A varying array looks like this:
|
||||
|
||||
typedef struct {
|
||||
long abc;
|
||||
long count;
|
||||
long foo;
|
||||
[size_is(count)] long *s;
|
||||
} Struct1;
|
||||
|
||||
This will look like this on the wire:
|
||||
|
||||
[abc] [count] [foo] [PTR_s] [count] [s...]
|
||||
|
||||
=head2 FIXED ARRAYS
|
||||
|
||||
A fixed array looks like this:
|
||||
|
||||
typedef struct {
|
||||
long s[10];
|
||||
} Struct1;
|
||||
|
||||
The NDR representation looks just like 10 separate long
|
||||
declarations. The array size is not encoded on the wire.
|
||||
|
||||
pidl also supports "inline" arrays, which are not part of the IDL/NDR
|
||||
standard. These are declared like this:
|
||||
|
||||
typedef struct {
|
||||
uint32 foo;
|
||||
uint32 count;
|
||||
uint32 bar;
|
||||
long s[count];
|
||||
} Struct1;
|
||||
|
||||
This appears like this:
|
||||
|
||||
[foo] [count] [bar] [s...]
|
||||
|
||||
Fixed arrays are an extension added to support some of the strange
|
||||
embedded structures in security descriptors and spoolss.
|
||||
|
||||
This section is by no means complete. See the OpenGroup and MSDN
|
||||
documentation for additional information.
|
||||
|
||||
=head1 COMPATIBILITY WITH MIDL
|
||||
|
||||
=head2 Missing features in pidl
|
||||
|
||||
The following MIDL features are not (yet) implemented in pidl
|
||||
or are implemented with an incompatible interface:
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
|
||||
Asynchronous communication
|
||||
|
||||
=item *
|
||||
|
||||
Typelibs (.tlb files)
|
||||
|
||||
=item *
|
||||
|
||||
Datagram support (ncadg_*)
|
||||
|
||||
=back
|
||||
|
||||
=head2 Supported attributes and statements
|
||||
|
||||
in, out, ref, length_is, switch_is, size_is, uuid, case, default, string,
|
||||
unique, ptr, pointer_default, v1_enum, object, helpstring, range, local,
|
||||
call_as, endpoint, switch_type, progid, coclass, iid_is, represent_as,
|
||||
transmit_as, import, include.
|
||||
|
||||
=head2 PIDL Specific properties
|
||||
|
||||
=over 4
|
||||
|
||||
=item public
|
||||
|
||||
The [public] property on a structure or union is a pidl extension that
|
||||
forces the generated pull/push functions to be non-static. This allows
|
||||
you to declare types that can be used between modules. If you don't
|
||||
specify [public] then pull/push functions for other than top-level
|
||||
functions are declared static.
|
||||
|
||||
=item noprint
|
||||
|
||||
The [noprint] property is a pidl extension that allows you to specify
|
||||
that pidl should not generate a ndr_print_*() function for that
|
||||
structure or union. This is used when you wish to define your own
|
||||
print function that prints a structure in a nicer manner. A good
|
||||
example is the use of [noprint] on dom_sid, which allows the
|
||||
pretty-printing of SIDs.
|
||||
|
||||
=item value
|
||||
|
||||
The [value(expression)] property is a pidl extension that allows you
|
||||
to specify the value of a field when it is put on the wire. This
|
||||
allows fields that always have a well-known value to be automatically
|
||||
filled in, thus making the API more programmer friendly. The
|
||||
expression can be any C expression.
|
||||
|
||||
=item relative
|
||||
|
||||
The [relative] property can be supplied on a pointer. When it is used
|
||||
it declares the pointer as a spoolss style "relative" pointer, which
|
||||
means it appears on the wire as an offset within the current
|
||||
encapsulating structure. This is not part of normal IDL/NDR, but it is
|
||||
a very useful extension as it avoids the manual encoding of many
|
||||
complex structures.
|
||||
|
||||
=item subcontext(length)
|
||||
|
||||
Specifies that a size of I<length>
|
||||
bytes should be read, followed by a blob of that size,
|
||||
which will be parsed as NDR.
|
||||
|
||||
=item flag
|
||||
|
||||
Specify boolean options, mostly used for
|
||||
low-level NDR options. Several options
|
||||
can be specified using the | character.
|
||||
Note that flags are inherited by substructures!
|
||||
|
||||
=item nodiscriminant
|
||||
|
||||
The [nodiscriminant] property on a union means that the usual uint16
|
||||
discriminent field at the start of the union on the wire is
|
||||
omitted. This is not normally allowed in IDL/NDR, but is used for some
|
||||
spoolss structures.
|
||||
|
||||
=item charset(name)
|
||||
|
||||
Specify that the array or string uses the specified
|
||||
charset. If this attribute is specified, pidl will
|
||||
take care of converting the character data from this format
|
||||
to the host format. Commonly used values are UCS2, DOS and UTF8.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Unsupported MIDL properties or statements
|
||||
|
||||
aggregatable, appobject, async_uuid, bindable, control, cpp_quote,
|
||||
defaultbind, defaultcollelem, defaultvalue, defaultvtable, dispinterface,
|
||||
displaybind, dual, entry, first_is, helpcontext, helpfile, helpstringcontext,
|
||||
helpstringdll, hidden, idl_module, idl_quote, id, immediatebind, importlib,
|
||||
includelib, last_is, lcid, licensed, max_is, module,
|
||||
ms_union, no_injected_text, nonbrowsable, noncreatable, nonextensible, odl,
|
||||
oleautomation, optional, pragma, propget, propputref, propput, readonly,
|
||||
requestedit, restricted, retval, source, uidefault,
|
||||
usesgetlasterror, vararg, vi_progid, wire_marshal.
|
||||
|
||||
=head1 EXAMPLES
|
||||
|
||||
# Generating an Wireshark parser
|
||||
$ ./pidl --ws-parser -- atsvc.idl
|
||||
|
||||
# Generating a TDR parser and header
|
||||
$ ./pidl --tdr-parser --header -- regf.idl
|
||||
|
||||
# Generating a Samba3 client and server
|
||||
$ ./pidl --samba3-ndr-client --samba3-ndr-server -- dfs.idl
|
||||
|
||||
# Generating a Samba4 NDR parser, client and server
|
||||
$ ./pidl --ndr-parser --ndr-client --ndr-server -- samr.idl
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<http://msdn.microsoft.com/library/en-us/rpc/rpc/field_attributes.asp>,
|
||||
L<http://wiki.wireshark.org/DCE/RPC>,
|
||||
L<http://www.samba.org/>,
|
||||
L<yapp(1)>
|
||||
|
||||
=head1 LICENSE
|
||||
|
||||
pidl is licensed under the GNU General Public License L<http://www.gnu.org/licenses/gpl.html>.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
pidl was written by Andrew Tridgell, Stefan Metzmacher, Tim Potter and Jelmer
|
||||
Vernooij. The current maintainer is Jelmer Vernooij.
|
||||
|
||||
This manpage was written by Jelmer Vernooij, partially based on the original
|
||||
pidl README by Andrew Tridgell.
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
use strict;
|
||||
use FindBin qw($RealBin);
|
||||
use lib "$RealBin";
|
||||
use lib "$RealBin/lib";
|
||||
use Getopt::Long;
|
||||
use File::Basename;
|
||||
use Parse::Pidl;
|
||||
use Parse::Pidl::Util;
|
||||
use Parse::Pidl::ODL;
|
||||
|
||||
#####################################################################
|
||||
# save a data structure into a file
|
||||
sub SaveStructure($$)
|
||||
{
|
||||
my($filename,$v) = @_;
|
||||
FileSave($filename, Parse::Pidl::Util::MyDumper($v));
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# load a data structure from a file (as saved with SaveStructure)
|
||||
sub LoadStructure($)
|
||||
{
|
||||
my $f = shift;
|
||||
my $contents = FileLoad($f);
|
||||
defined $contents || return undef;
|
||||
return eval "$contents";
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# read a file into a string
|
||||
sub FileLoad($)
|
||||
{
|
||||
my($filename) = shift;
|
||||
local(*INPUTFILE);
|
||||
open(INPUTFILE, $filename) || return undef;
|
||||
my($saved_delim) = $/;
|
||||
undef $/;
|
||||
my($data) = <INPUTFILE>;
|
||||
close(INPUTFILE);
|
||||
$/ = $saved_delim;
|
||||
return $data;
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# write a string into a file
|
||||
sub FileSave($$)
|
||||
{
|
||||
my($filename) = shift;
|
||||
my($v) = shift;
|
||||
local(*FILE);
|
||||
open(FILE, ">$filename") || die "can't open $filename";
|
||||
print FILE $v;
|
||||
close(FILE);
|
||||
}
|
||||
|
||||
my(@opt_incdirs) = ();
|
||||
my($opt_help) = 0;
|
||||
my($opt_parse_idl_tree) = 0;
|
||||
my($opt_dump_idl_tree);
|
||||
my($opt_dump_ndr_tree);
|
||||
my($opt_dump_idl) = 0;
|
||||
my($opt_uint_enums) = 0;
|
||||
my($opt_diff) = 0;
|
||||
my($opt_header);
|
||||
my($opt_samba3_header);
|
||||
my($opt_samba3_parser);
|
||||
my($opt_samba3_server);
|
||||
my($opt_samba3_ndr_client);
|
||||
my($opt_samba3_ndr_server);
|
||||
my($opt_template) = 0;
|
||||
my($opt_client);
|
||||
my($opt_server);
|
||||
my($opt_ndr_parser);
|
||||
my($opt_tdr_parser);
|
||||
my($opt_ws_parser);
|
||||
my($opt_swig);
|
||||
my($opt_dcom_proxy);
|
||||
my($opt_com_header);
|
||||
my($opt_ejs);
|
||||
my($opt_quiet) = 0;
|
||||
my($opt_outputdir) = '.';
|
||||
my($opt_verbose) = 0;
|
||||
my($opt_warn_compat) = 0;
|
||||
|
||||
#########################################
|
||||
# display help text
|
||||
sub ShowHelp()
|
||||
{
|
||||
print "perl IDL parser and code generator
|
||||
Copyright (C) Andrew Tridgell <tridge\@samba.org>
|
||||
Copyright (C) Jelmer Vernooij <jelmer\@samba.org>
|
||||
|
||||
Usage: pidl [options] [--] <idlfile> [<idlfile>...]
|
||||
|
||||
Generic Options:
|
||||
--help this help page
|
||||
--outputdir=OUTDIR put output in OUTDIR/ [.]
|
||||
--warn-compat warn about incompatibility with other compilers
|
||||
--quiet be quiet
|
||||
--verbose be verbose
|
||||
--includedir DIR search DIR for included files
|
||||
|
||||
Debugging:
|
||||
--dump-idl-tree[=FILE] dump internal representation to file [BASENAME.pidl]
|
||||
--parse-idl-tree read internal representation instead of IDL
|
||||
--dump-ndr-tree[=FILE] dump internal NDR data tree to file [BASENAME.ndr]
|
||||
--dump-idl regenerate IDL file
|
||||
--diff run diff on original IDL and dumped output
|
||||
|
||||
Samba 4 output:
|
||||
--header[=OUTFILE] create generic header file [BASENAME.h]
|
||||
--uint-enums don't use C enums, instead use uint* types
|
||||
--ndr-parser[=OUTFILE] create a C NDR parser [ndr_BASENAME.c]
|
||||
--client[=OUTFILE] create a C NDR client [ndr_BASENAME_c.c]
|
||||
--tdr-parser[=OUTFILE] create a C TDR parser [tdr_BASENAME.c]
|
||||
--ejs[=OUTFILE] create ejs wrapper file [BASENAME_ejs.c]
|
||||
--swig[=OUTFILE] create swig wrapper file [BASENAME.i]
|
||||
--server[=OUTFILE] create server boilerplate [ndr_BASENAME_s.c]
|
||||
--template print a template for a pipe
|
||||
--dcom-proxy[=OUTFILE] create DCOM proxy [ndr_BASENAME_p.c]
|
||||
--com-header[=OUTFILE] create header for COM [com_BASENAME.h]
|
||||
|
||||
Samba 3 output:
|
||||
--samba3-ndr-client[=OUTF] create client calls for Samba3
|
||||
using Samba4's NDR code [cli_BASENAME.c]
|
||||
--samba3-ndr-server[=OUTF] create server call wrapper for Samba3
|
||||
using Samba4's NDR code [srv_BASENAME.c]
|
||||
|
||||
Wireshark parsers:
|
||||
--ws-parser[=OUTFILE] create Wireshark parser and header
|
||||
\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
# main program
|
||||
my $result = GetOptions (
|
||||
'help|h|?' => \$opt_help,
|
||||
'outputdir=s' => \$opt_outputdir,
|
||||
'dump-idl' => \$opt_dump_idl,
|
||||
'dump-idl-tree:s' => \$opt_dump_idl_tree,
|
||||
'parse-idl-tree' => \$opt_parse_idl_tree,
|
||||
'dump-ndr-tree:s' => \$opt_dump_ndr_tree,
|
||||
'uint-enums' => \$opt_uint_enums,
|
||||
'samba3-ndr-client:s' => \$opt_samba3_ndr_client,
|
||||
'samba3-ndr-server:s' => \$opt_samba3_ndr_server,
|
||||
'header:s' => \$opt_header,
|
||||
'server:s' => \$opt_server,
|
||||
'tdr-parser:s' => \$opt_tdr_parser,
|
||||
'template' => \$opt_template,
|
||||
'ndr-parser:s' => \$opt_ndr_parser,
|
||||
'client:s' => \$opt_client,
|
||||
'ws-parser:s' => \$opt_ws_parser,
|
||||
'ejs' => \$opt_ejs,
|
||||
'diff' => \$opt_diff,
|
||||
'swig:s' => \$opt_swig,
|
||||
'dcom-proxy:s' => \$opt_dcom_proxy,
|
||||
'com-header:s' => \$opt_com_header,
|
||||
'quiet' => \$opt_quiet,
|
||||
'verbose' => \$opt_verbose,
|
||||
'warn-compat' => \$opt_warn_compat,
|
||||
'includedir=s@' => \@opt_incdirs
|
||||
);
|
||||
|
||||
if (not $result) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ($opt_help) {
|
||||
ShowHelp();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
sub process_file($)
|
||||
{
|
||||
my $idl_file = shift;
|
||||
my $outputdir = $opt_outputdir;
|
||||
my $pidl;
|
||||
my $ndr;
|
||||
|
||||
my $basename = basename($idl_file, ".idl");
|
||||
|
||||
unless ($opt_quiet) { print "Compiling $idl_file\n"; }
|
||||
|
||||
if ($opt_parse_idl_tree) {
|
||||
$pidl = LoadStructure($idl_file);
|
||||
defined $pidl || die "Failed to load $idl_file";
|
||||
} else {
|
||||
require Parse::Pidl::IDL;
|
||||
|
||||
$pidl = Parse::Pidl::IDL::parse_file($idl_file, \@opt_incdirs);
|
||||
defined @$pidl || die "Failed to parse $idl_file";
|
||||
require Parse::Pidl::Typelist;
|
||||
Parse::Pidl::Typelist::LoadIdl($pidl);
|
||||
}
|
||||
|
||||
if (defined($opt_dump_idl_tree)) {
|
||||
my($pidl_file) = ($opt_dump_idl_tree or "$outputdir/$basename.pidl");
|
||||
SaveStructure($pidl_file, $pidl) or die "Failed to save $pidl_file\n";
|
||||
}
|
||||
|
||||
if ($opt_uint_enums) {
|
||||
Parse::Pidl::Util::setUseUintEnums(1);
|
||||
}
|
||||
|
||||
if ($opt_dump_idl) {
|
||||
require Parse::Pidl::Dump;
|
||||
print Parse::Pidl::Dump($pidl);
|
||||
}
|
||||
|
||||
if ($opt_diff) {
|
||||
my($tempfile) = "$outputdir/$basename.tmp";
|
||||
FileSave($tempfile, IdlDump::Dump($pidl));
|
||||
system("diff -wu $idl_file $tempfile");
|
||||
unlink($tempfile);
|
||||
}
|
||||
|
||||
|
||||
my $comh_filename = ($opt_com_header or "$outputdir/com_$basename.h");
|
||||
if (defined($opt_com_header)) {
|
||||
require Parse::Pidl::Samba4::COM::Header;
|
||||
my $res = Parse::Pidl::Samba4::COM::Header::Parse($pidl,"$outputdir/ndr_$basename.h");
|
||||
if ($res) {
|
||||
FileSave($comh_filename, $res);
|
||||
}
|
||||
}
|
||||
|
||||
if (defined($opt_dcom_proxy)) {
|
||||
require Parse::Pidl::Samba4::COM::Proxy;
|
||||
my $res = Parse::Pidl::Samba4::COM::Proxy::Parse($pidl,$comh_filename);
|
||||
if ($res) {
|
||||
my ($client) = ($opt_dcom_proxy or "$outputdir/$basename\_p.c");
|
||||
FileSave($client, $res);
|
||||
}
|
||||
}
|
||||
|
||||
if ($opt_warn_compat) {
|
||||
require Parse::Pidl::Compat;
|
||||
Parse::Pidl::Compat::Check($pidl);
|
||||
}
|
||||
|
||||
$pidl = Parse::Pidl::ODL::ODL2IDL($pidl);
|
||||
|
||||
if (defined($opt_ws_parser) or
|
||||
defined($opt_client) or defined($opt_server) or
|
||||
defined($opt_ndr_parser) or defined($opt_ejs) or
|
||||
defined($opt_dump_ndr_tree) or defined($opt_samba3_header) or
|
||||
defined($opt_samba3_parser) or defined($opt_samba3_server) or
|
||||
defined($opt_swig) or defined($opt_samba3_ndr_client) or
|
||||
defined($opt_samba3_ndr_server)) {
|
||||
require Parse::Pidl::NDR;
|
||||
$ndr = Parse::Pidl::NDR::Parse($pidl);
|
||||
}
|
||||
|
||||
if (defined($opt_dump_ndr_tree)) {
|
||||
my($ndr_file) = ($opt_dump_ndr_tree or "$outputdir/$basename.ndr");
|
||||
SaveStructure($ndr_file, $ndr) or die "Failed to save $ndr_file\n";
|
||||
}
|
||||
|
||||
my $gen_header = ($opt_header or "$outputdir/$basename.h");
|
||||
if (defined($opt_header)) {
|
||||
require Parse::Pidl::Samba4::Header;
|
||||
FileSave($gen_header, Parse::Pidl::Samba4::Header::Parse($pidl));
|
||||
}
|
||||
|
||||
my $h_filename = "$outputdir/ndr_$basename.h";
|
||||
if (defined($opt_client)) {
|
||||
require Parse::Pidl::Samba4::NDR::Client;
|
||||
my ($c_client) = ($opt_client or "$outputdir/ndr_$basename\_c.c");
|
||||
my ($c_header) = $c_client;
|
||||
$c_header =~ s/\.c$/.h/;
|
||||
|
||||
my ($srcd,$hdrd) = Parse::Pidl::Samba4::NDR::Client::Parse(
|
||||
$ndr,$gen_header,$h_filename,$c_header);
|
||||
|
||||
FileSave($c_client, $srcd);
|
||||
FileSave($c_header, $hdrd);
|
||||
}
|
||||
|
||||
if (defined($opt_swig)) {
|
||||
require Parse::Pidl::Samba4::SWIG;
|
||||
my($filename) = ($opt_swig or "$outputdir/$basename.i");
|
||||
my $code = Parse::Pidl::Samba4::SWIG::Parse($ndr, $basename, "$outputdir/ndr_$basename\_c.h", $gen_header);
|
||||
FileSave($filename, $code);
|
||||
}
|
||||
|
||||
if (defined($opt_ejs)) {
|
||||
require Parse::Pidl::Samba4::EJS;
|
||||
my ($hdr,$prsr) = Parse::Pidl::Samba4::EJS::Parse($ndr, $h_filename);
|
||||
FileSave("$outputdir/ndr_$basename\_ejs.c", $prsr);
|
||||
FileSave("$outputdir/ndr_$basename\_ejs.h", $hdr);
|
||||
}
|
||||
|
||||
if (defined($opt_server)) {
|
||||
require Parse::Pidl::Samba4::NDR::Server;
|
||||
my $dcom = "";
|
||||
|
||||
foreach (@{$pidl}) {
|
||||
next if ($_->{TYPE} ne "INTERFACE");
|
||||
|
||||
if (Parse::Pidl::Util::has_property($_, "object")) {
|
||||
require Parse::Pidl::Samba4::COM::Stub;
|
||||
$dcom .= Parse::Pidl::Samba4::COM::Stub::ParseInterface($_);
|
||||
}
|
||||
}
|
||||
|
||||
FileSave(($opt_server or "$outputdir/ndr_$basename\_s.c"), Parse::Pidl::Samba4::NDR::Server::Parse($ndr,$h_filename));
|
||||
|
||||
if ($dcom ne "") {
|
||||
$dcom = "
|
||||
#include \"includes.h\"
|
||||
#include \"$h_filename\"
|
||||
#include \"rpc_server/dcerpc_server.h\"
|
||||
#include \"rpc_server/common/common.h\"
|
||||
|
||||
$dcom
|
||||
";
|
||||
FileSave("$outputdir/$basename\_d.c", $dcom);
|
||||
}
|
||||
}
|
||||
|
||||
if (defined($opt_ndr_parser)) {
|
||||
my $parser_fname = ($opt_ndr_parser or "$outputdir/ndr_$basename.c");
|
||||
require Parse::Pidl::Samba4::NDR::Parser;
|
||||
my ($header,$parser) = Parse::Pidl::Samba4::NDR::Parser::Parse($ndr, $gen_header, $h_filename);
|
||||
|
||||
|
||||
FileSave($parser_fname, $parser);
|
||||
FileSave($h_filename, $header);
|
||||
|
||||
}
|
||||
|
||||
if (defined($opt_ws_parser)) {
|
||||
require Parse::Pidl::Wireshark::NDR;
|
||||
my($eparser) = ($opt_ws_parser or "$outputdir/packet-dcerpc-$basename.c");
|
||||
my $eheader = $eparser;
|
||||
$eheader =~ s/\.c$/\.h/;
|
||||
my $cnffile = $idl_file;
|
||||
$cnffile =~ s/\.idl$/\.cnf/;
|
||||
|
||||
my ($dp, $dh) = Parse::Pidl::Wireshark::NDR::Parse($ndr, $idl_file, $eheader, $cnffile);
|
||||
FileSave($eparser, $dp) if defined($dp);
|
||||
FileSave($eheader, $dh) if defined($dh);
|
||||
}
|
||||
|
||||
if (defined($opt_tdr_parser)) {
|
||||
my $tdr_parser = ($opt_tdr_parser or "$outputdir/tdr_$basename.c");
|
||||
my $tdr_header = $tdr_parser;
|
||||
$tdr_header =~ s/\.c$/\.h/;
|
||||
require Parse::Pidl::Samba4::TDR;
|
||||
my ($hdr,$prsr) = Parse::Pidl::Samba4::TDR::Parser($pidl, $tdr_header, $gen_header);
|
||||
FileSave($tdr_parser, $prsr);
|
||||
FileSave($tdr_header, $hdr);
|
||||
}
|
||||
|
||||
if ($opt_template) {
|
||||
require Parse::Pidl::Samba4::Template;
|
||||
print Parse::Pidl::Samba4::Template::Parse($pidl);
|
||||
}
|
||||
|
||||
if (defined($opt_samba3_ndr_client)) {
|
||||
my $client = ($opt_samba3_ndr_client or "$outputdir/cli_$basename.c");
|
||||
my $header = $client; $header =~ s/\.c$/\.h/;
|
||||
require Parse::Pidl::Samba3::ClientNDR;
|
||||
my ($c_code,$h_code) = Parse::Pidl::Samba3::ClientNDR::Parse($ndr, $header, $h_filename);
|
||||
FileSave($client, $c_code);
|
||||
FileSave($header, $h_code);
|
||||
}
|
||||
|
||||
if (defined($opt_samba3_ndr_server)) {
|
||||
my $server = ($opt_samba3_ndr_server or "$outputdir/srv_$basename.c");
|
||||
my $header = $server; $header =~ s/\.c$/\.h/;
|
||||
require Parse::Pidl::Samba3::ServerNDR;
|
||||
my ($c_code,$h_code) = Parse::Pidl::Samba3::ServerNDR::Parse($ndr, $header, $h_filename);
|
||||
FileSave($server, $c_code);
|
||||
FileSave($header, $h_code);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (scalar(@ARGV) == 0) {
|
||||
print "pidl: no input files\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
process_file($_) foreach (@ARGV);
|
||||
@@ -0,0 +1,220 @@
|
||||
some experiments with ref ptrs
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
short x;
|
||||
} xstruct;
|
||||
|
||||
uint16 echo_TestRef([in] xstruct foo);
|
||||
|
||||
short v = 13;
|
||||
xstruct r;
|
||||
r.x = v;
|
||||
echo_TestRef(r);
|
||||
|
||||
[0D 00]
|
||||
|
||||
----------------------------------------------------
|
||||
typedef struct {
|
||||
short *x;
|
||||
} xstruct;
|
||||
|
||||
uint16 echo_TestRef([in] xstruct foo);
|
||||
|
||||
short v = 13;
|
||||
xstruct r;
|
||||
r.x = &v;
|
||||
echo_TestRef(r);
|
||||
|
||||
[PP PP PP PP 0D 00]
|
||||
|
||||
|
||||
xstruct r;
|
||||
r.x = NULL;
|
||||
echo_TestRef(r);
|
||||
|
||||
[00 00 00 00]
|
||||
|
||||
----------------------------------------------------
|
||||
typedef struct {
|
||||
[ref] short *x;
|
||||
} xstruct;
|
||||
|
||||
uint16 echo_TestRef([in] xstruct foo);
|
||||
|
||||
short v = 13;
|
||||
xstruct r;
|
||||
r.x = &v;
|
||||
echo_TestRef(r);
|
||||
|
||||
[XX XX XX XX 0D 00]
|
||||
|
||||
|
||||
xstruct r;
|
||||
r.x = NULL;
|
||||
echo_TestRef(r);
|
||||
|
||||
[client runtime error 0x6f4]
|
||||
|
||||
|
||||
----------------------------------------------------
|
||||
typedef struct {
|
||||
short x;
|
||||
} xstruct;
|
||||
|
||||
uint16 echo_TestRef([in] xstruct *foo);
|
||||
|
||||
short v = 13;
|
||||
xstruct r;
|
||||
r.x = v;
|
||||
echo_TestRef(&r);
|
||||
|
||||
[0D 00]
|
||||
|
||||
|
||||
echo_TestRef(NULL);
|
||||
|
||||
[client runtime error 0x6f4]
|
||||
|
||||
----------------------------------------------------
|
||||
typedef struct {
|
||||
short x;
|
||||
} xstruct;
|
||||
|
||||
uint16 echo_TestRef([in,ref] xstruct *foo);
|
||||
|
||||
short v = 13;
|
||||
xstruct r;
|
||||
r.x = v;
|
||||
echo_TestRef(&r);
|
||||
|
||||
[0D 00]
|
||||
|
||||
|
||||
echo_TestRef(NULL);
|
||||
|
||||
[client runtime error 0x6f4]
|
||||
|
||||
|
||||
----------------------------------------------------
|
||||
typedef struct {
|
||||
short x;
|
||||
} xstruct;
|
||||
|
||||
uint16 echo_TestRef([in,unique] xstruct *foo);
|
||||
|
||||
short v = 13;
|
||||
xstruct r;
|
||||
r.x = v;
|
||||
echo_TestRef(&r);
|
||||
|
||||
[PP PP PP PP 0D 00]
|
||||
|
||||
|
||||
echo_TestRef(NULL);
|
||||
|
||||
[00 00 00 00]
|
||||
|
||||
|
||||
----------------------------------------------------
|
||||
typedef struct {
|
||||
short x;
|
||||
} xstruct;
|
||||
|
||||
uint16 echo_TestRef([out] xstruct foo);
|
||||
|
||||
[idl compiler error]
|
||||
|
||||
----------------------------------------------------
|
||||
typedef struct {
|
||||
short x;
|
||||
} xstruct;
|
||||
|
||||
void echo_TestRef([out] xstruct *foo);
|
||||
|
||||
xstruct r;
|
||||
echo_TestRef(&r);
|
||||
r.x -> 13;
|
||||
|
||||
[0D 00]
|
||||
|
||||
|
||||
echo_TestRef(NULL);
|
||||
|
||||
[client runtime error 0x6f4]
|
||||
|
||||
----------------------------------------------------
|
||||
typedef struct {
|
||||
short x;
|
||||
} xstruct;
|
||||
|
||||
void echo_TestRef([out,ref] xstruct *foo);
|
||||
|
||||
xstruct r;
|
||||
echo_TestRef(&r);
|
||||
r.x -> 13;
|
||||
|
||||
[0D 00]
|
||||
|
||||
|
||||
echo_TestRef(NULL);
|
||||
|
||||
[client runtime error 0x6f4]
|
||||
|
||||
----------------------------------------------------
|
||||
typedef struct {
|
||||
short x;
|
||||
} xstruct;
|
||||
|
||||
void echo_TestRef([out,unique] xstruct *foo);
|
||||
|
||||
[idl compiler error]
|
||||
|
||||
|
||||
----------------------------------------------------
|
||||
void echo_TestRef([in] short **foo);
|
||||
|
||||
short v = 13;
|
||||
short *pv = &v;
|
||||
|
||||
echo_TestRef(&pv);
|
||||
|
||||
[PP PP PP PP 0D 00]
|
||||
|
||||
|
||||
short *pv = NULL;
|
||||
|
||||
echo_TestRef(&pv);
|
||||
|
||||
[00 00 00 00]
|
||||
|
||||
|
||||
echo_TestRef(NULL);
|
||||
|
||||
[client runtime error 0x6f4]
|
||||
|
||||
|
||||
----------------------------------------------------
|
||||
void echo_TestRef([in,ref] short **foo);
|
||||
|
||||
short v = 13;
|
||||
short *pv = &v;
|
||||
|
||||
echo_TestRef(&pv);
|
||||
|
||||
[PP PP PP PP 0D 00]
|
||||
|
||||
|
||||
short *pv = NULL;
|
||||
|
||||
echo_TestRef(&pv);
|
||||
|
||||
[00 00 00 00]
|
||||
|
||||
|
||||
echo_TestRef(NULL);
|
||||
|
||||
[client runtime error 0x6f4]
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,233 @@
|
||||
########################
|
||||
# Parse::Yapp parser for a C header file that contains only structures
|
||||
# or unions.
|
||||
|
||||
# Copyright (C) 2005, Tim Potter <tpot@samba.org> released under the
|
||||
# GNU GPL version 2 or later
|
||||
|
||||
################
|
||||
# grammar
|
||||
|
||||
%%
|
||||
|
||||
definitions:
|
||||
definition { [$_[1]] }
|
||||
| definitions definition { push(@{$_[1]}, $_[2]); $_[1] }
|
||||
;
|
||||
|
||||
definition:
|
||||
struct
|
||||
| union
|
||||
| typedef
|
||||
| enum
|
||||
;
|
||||
|
||||
struct: STRUCT optional_identifier '{' elements '}' pointers optional_identifiers ';'
|
||||
{
|
||||
{
|
||||
"NAME" => $_[7],
|
||||
"STRUCT_NAME" => $_[2],
|
||||
"TYPE" => "struct",
|
||||
"DATA" => $_[4],
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
union:
|
||||
UNION optional_identifier '{' elements '}' pointers optional_identifier ';'
|
||||
{
|
||||
{
|
||||
"NAME" => $_[7],
|
||||
"UNION_NAME" => $_[2],
|
||||
"TYPE" => "union",
|
||||
"DATA" => $_[4],
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
typedef:
|
||||
TYPEDEF STRUCT '{' elements '}' optional_identifier ';'
|
||||
;
|
||||
|
||||
enum:
|
||||
ENUM IDENTIFIER '{' enum_identifiers '}' ';'
|
||||
;
|
||||
|
||||
enum_identifiers: enum_identifier
|
||||
| enum_identifiers ',' enum_identifier
|
||||
;
|
||||
|
||||
enum_identifier: IDENTIFIER
|
||||
| IDENTIFIER '=' IDENTIFIER
|
||||
;
|
||||
|
||||
elements: #empty
|
||||
| elements element { push(@{$_[1]}, $_[2]); $_[1] }
|
||||
;
|
||||
|
||||
element:
|
||||
| struct
|
||||
| union
|
||||
| STRUCT IDENTIFIER pointers IDENTIFIER ';'
|
||||
{{
|
||||
"NAME" => [$_[2]],
|
||||
"POINTERS" => $_[3],
|
||||
"TYPE" => "struct $_[2]",
|
||||
}}
|
||||
| UNION IDENTIFIER pointers IDENTIFIER ';'
|
||||
{{
|
||||
"NAME" => $_[2],
|
||||
"POINTERS" => $_[3],
|
||||
"TYPE" => "union $_[2]",
|
||||
}}
|
||||
| CONST type pointers IDENTIFIER array ';'
|
||||
{{
|
||||
"NAME" => [$_[4]],
|
||||
"TYPE" => $_[2],
|
||||
"POINTERS" => $_[3],
|
||||
}}
|
||||
| type pointers IDENTIFIER array ';'
|
||||
{{
|
||||
"NAME" => [$_[3]],
|
||||
"TYPE" => $_[1],
|
||||
"POINTERS" => $_[2],
|
||||
"ARRAY_LENGTH" => $_[4]
|
||||
}}
|
||||
;
|
||||
|
||||
array: #empty
|
||||
| '[' CONSTANT ']' { int($_[2]) }
|
||||
;
|
||||
|
||||
type: IDENTIFIER
|
||||
| ENUM IDENTIFIER
|
||||
{ "enum $_[2]" }
|
||||
;
|
||||
|
||||
pointers:
|
||||
#empty { 0 }
|
||||
| pointers '*' { $_[1]+1 }
|
||||
;
|
||||
|
||||
optional_identifiers: optional_identifier { [$_[1]] }
|
||||
| optional_identifiers ',' optional_identifier { push(@{$_[1]}, $_[3]); $_[1] }
|
||||
;
|
||||
|
||||
optional_identifier: IDENTIFIER | #empty { undef }
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
#####################################################################
|
||||
# traverse a perl data structure removing any empty arrays or
|
||||
# hashes and any hash elements that map to undef
|
||||
sub CleanData($)
|
||||
{
|
||||
sub CleanData($);
|
||||
my($v) = shift;
|
||||
if (ref($v) eq "ARRAY") {
|
||||
foreach my $i (0 .. $#{$v}) {
|
||||
CleanData($v->[$i]);
|
||||
if (ref($v->[$i]) eq "ARRAY" && $#{$v->[$i]}==-1) {
|
||||
$v->[$i] = undef;
|
||||
next;
|
||||
}
|
||||
}
|
||||
# this removes any undefined elements from the array
|
||||
@{$v} = grep { defined $_ } @{$v};
|
||||
} elsif (ref($v) eq "HASH") {
|
||||
foreach my $x (keys %{$v}) {
|
||||
CleanData($v->{$x});
|
||||
if (!defined $v->{$x}) { delete($v->{$x}); next; }
|
||||
if (ref($v->{$x}) eq "ARRAY" && $#{$v->{$x}}==-1) { delete($v->{$x}); next; }
|
||||
}
|
||||
}
|
||||
return $v;
|
||||
}
|
||||
|
||||
sub _Error {
|
||||
if (exists $_[0]->YYData->{ERRMSG}) {
|
||||
print $_[0]->YYData->{ERRMSG};
|
||||
delete $_[0]->YYData->{ERRMSG};
|
||||
return;
|
||||
};
|
||||
my $line = $_[0]->YYData->{LINE};
|
||||
my $last_token = $_[0]->YYData->{LAST_TOKEN};
|
||||
my $file = $_[0]->YYData->{INPUT_FILENAME};
|
||||
|
||||
print "$file:$line: Syntax error near '$last_token'\n";
|
||||
}
|
||||
|
||||
sub _Lexer($)
|
||||
{
|
||||
my($parser)=shift;
|
||||
|
||||
$parser->YYData->{INPUT} or return('',undef);
|
||||
|
||||
again:
|
||||
$parser->YYData->{INPUT} =~ s/^[ \t]*//;
|
||||
|
||||
for ($parser->YYData->{INPUT}) {
|
||||
if (/^\#/) {
|
||||
if (s/^\# (\d+) \"(.*?)\"( \d+|)//) {
|
||||
$parser->YYData->{LINE} = $1-1;
|
||||
$parser->YYData->{INPUT_FILENAME} = $2;
|
||||
goto again;
|
||||
}
|
||||
if (s/^\#line (\d+) \"(.*?)\"( \d+|)//) {
|
||||
$parser->YYData->{LINE} = $1-1;
|
||||
$parser->YYData->{INPUT_FILENAME} = $2;
|
||||
goto again;
|
||||
}
|
||||
if (s/^(\#.*)$//m) {
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
if (s/^(\n)//) {
|
||||
$parser->YYData->{LINE}++;
|
||||
goto again;
|
||||
}
|
||||
if (s/^\"(.*?)\"//) {
|
||||
$parser->YYData->{LAST_TOKEN} = $1;
|
||||
return('TEXT',$1);
|
||||
}
|
||||
if (s/^(\d+)(\W|$)/$2/) {
|
||||
$parser->YYData->{LAST_TOKEN} = $1;
|
||||
return('CONSTANT',$1);
|
||||
}
|
||||
if (s/^([\w_]+)//) {
|
||||
$parser->YYData->{LAST_TOKEN} = $1;
|
||||
if ($1 =~
|
||||
/^(const|typedef|union|struct|enum)$/x) {
|
||||
return uc($1);
|
||||
}
|
||||
return('IDENTIFIER',$1);
|
||||
}
|
||||
if (s/^(.)//s) {
|
||||
$parser->YYData->{LAST_TOKEN} = $1;
|
||||
return($1,$1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub parse($$)
|
||||
{
|
||||
my ($self,$filename) = @_;
|
||||
|
||||
my $saved_delim = $/;
|
||||
undef $/;
|
||||
my $cpp = $ENV{CPP};
|
||||
if (! defined $cpp) {
|
||||
$cpp = "cpp"
|
||||
}
|
||||
my $data = `$cpp -D__PIDL__ -xc $filename`;
|
||||
$/ = $saved_delim;
|
||||
|
||||
$self->YYData->{INPUT} = $data;
|
||||
$self->YYData->{LINE} = 0;
|
||||
$self->YYData->{LAST_TOKEN} = "NONE";
|
||||
|
||||
my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
|
||||
|
||||
return CleanData($idl);
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
# Some simple utility functions for pidl tests
|
||||
# Copyright (C) 2005-2006 Jelmer Vernooij
|
||||
# Published under the GNU General Public License
|
||||
|
||||
package Util;
|
||||
|
||||
require Exporter;
|
||||
@ISA = qw(Exporter);
|
||||
@EXPORT_OK = qw(test_samba4_ndr);
|
||||
|
||||
use strict;
|
||||
|
||||
use Test::More;
|
||||
use Parse::Pidl::IDL;
|
||||
use Parse::Pidl::NDR;
|
||||
use Parse::Pidl::Samba4::NDR::Parser;
|
||||
use Parse::Pidl::Samba4::Header;
|
||||
|
||||
# Generate a Samba4 parser for an IDL fragment and run it with a specified
|
||||
# piece of code to check whether the parser works as expected
|
||||
sub test_samba4_ndr
|
||||
{
|
||||
my ($name,$idl,$c,$extra) = @_;
|
||||
my $pidl = Parse::Pidl::IDL::parse_string("interface echo { $idl }; ", "<$name>");
|
||||
|
||||
ok(defined($pidl), "($name) parse idl");
|
||||
my $header = Parse::Pidl::Samba4::Header::Parse($pidl);
|
||||
ok(defined($header), "($name) generate generic header");
|
||||
my $pndr = Parse::Pidl::NDR::Parse($pidl);
|
||||
ok(defined($pndr), "($name) generate NDR tree");
|
||||
my ($ndrheader,$ndrparser) = Parse::Pidl::Samba4::NDR::Parser::Parse($pndr, undef, undef);
|
||||
ok(defined($ndrparser), "($name) generate NDR parser");
|
||||
ok(defined($ndrheader), "($name) generate NDR header");
|
||||
|
||||
SKIP: {
|
||||
|
||||
skip "no samba environment available, skipping compilation", 3
|
||||
if (system("pkg-config --exists ndr") != 0);
|
||||
|
||||
my $test_data_prefix = $ENV{TEST_DATA_PREFIX};
|
||||
|
||||
my $outfile;
|
||||
if (defined($test_data_prefix)) {
|
||||
$outfile = "$test_data_prefix/test-$name";
|
||||
} else {
|
||||
$outfile = "test-$name";
|
||||
}
|
||||
|
||||
my $cflags = `pkg-config --libs --cflags ndr`;
|
||||
|
||||
open CC, "|cc -x c - -o $outfile $cflags";
|
||||
print CC "#define uint_t unsigned int\n";
|
||||
print CC "#define _GNU_SOURCE\n";
|
||||
print CC "#include <stdint.h>\n";
|
||||
print CC "#include <stdlib.h>\n";
|
||||
print CC "#include <stdio.h>\n";
|
||||
print CC "#include <stdbool.h>\n";
|
||||
print CC "#include <stdarg.h>\n";
|
||||
print CC "#include <core.h>\n";
|
||||
print CC $header;
|
||||
print CC $ndrheader;
|
||||
print CC $extra if ($extra);
|
||||
print CC $ndrparser;
|
||||
print CC "int main(int argc, const char **argv)
|
||||
{
|
||||
TALLOC_CTX *mem_ctx = talloc_init(NULL);
|
||||
|
||||
$c
|
||||
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
return 0; }\n";
|
||||
close CC;
|
||||
|
||||
ok(-f $outfile, "($name) compile");
|
||||
|
||||
my $ret = system("./$outfile", ()) >> 8;
|
||||
print "# return code: $ret\n" if ($ret != 0);
|
||||
|
||||
ok($ret == 0, "($name) run");
|
||||
|
||||
ok(unlink($outfile), "($name) remove");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
Executable
+144
@@ -0,0 +1,144 @@
|
||||
#!/usr/bin/perl
|
||||
# NDR alignment tests
|
||||
# (C) 2005 Jelmer Vernooij. Published under the GNU GPL
|
||||
use strict;
|
||||
|
||||
use Test::More tests => 5 * 8;
|
||||
use FindBin qw($RealBin);
|
||||
use lib "$RealBin/../lib";
|
||||
use lib "$RealBin";
|
||||
use Util qw(test_samba4_ndr);
|
||||
|
||||
test_samba4_ndr('align-uint8-uint16',
|
||||
'
|
||||
typedef [public] struct {
|
||||
uint8 x;
|
||||
uint16 y;
|
||||
} bla;
|
||||
',
|
||||
'
|
||||
struct ndr_push *ndr = ndr_push_init();
|
||||
struct bla r;
|
||||
uint8_t expected[] = { 0x0D, 0x00, 0xef, 0xbe };
|
||||
DATA_BLOB expected_blob = { expected, 4 };
|
||||
DATA_BLOB result_blob;
|
||||
r.x = 13;
|
||||
r.y = 0xbeef;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_push_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r)))
|
||||
return 1;
|
||||
|
||||
result_blob = ndr_push_blob(ndr);
|
||||
|
||||
if (!data_blob_equal(&result_blob, &expected_blob))
|
||||
return 2;
|
||||
');
|
||||
|
||||
test_samba4_ndr('align-uint8-uint32',
|
||||
'
|
||||
typedef [public] struct {
|
||||
uint8 x;
|
||||
uint32 y;
|
||||
} bla;
|
||||
',
|
||||
'
|
||||
struct ndr_push *ndr = ndr_push_init();
|
||||
struct bla r;
|
||||
uint8_t expected[] = { 0x0D, 0x00, 0x00, 0x00, 0xef, 0xbe, 0xef, 0xbe };
|
||||
DATA_BLOB expected_blob = { expected, 8 };
|
||||
DATA_BLOB result_blob;
|
||||
r.x = 13;
|
||||
r.y = 0xbeefbeef;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_push_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r)))
|
||||
return 1;
|
||||
|
||||
result_blob = ndr_push_blob(ndr);
|
||||
|
||||
if (!data_blob_equal(&result_blob, &expected_blob))
|
||||
return 2;
|
||||
');
|
||||
|
||||
|
||||
test_samba4_ndr('align-uint8-hyper',
|
||||
'
|
||||
typedef [public] struct {
|
||||
uint8 x;
|
||||
hyper y;
|
||||
} bla;
|
||||
',
|
||||
'
|
||||
struct ndr_push *ndr = ndr_push_init();
|
||||
struct bla r;
|
||||
uint8_t expected[] = { 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe };
|
||||
DATA_BLOB expected_blob = { expected, 16 };
|
||||
DATA_BLOB result_blob;
|
||||
r.x = 13;
|
||||
r.y = 0xbeefbeefbeefbeef;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_push_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r)))
|
||||
return 1;
|
||||
|
||||
result_blob = ndr_push_blob(ndr);
|
||||
|
||||
if (!data_blob_equal(&result_blob, &expected_blob))
|
||||
return 2;
|
||||
');
|
||||
|
||||
test_samba4_ndr('noalignflag-uint8-uint16',
|
||||
'
|
||||
typedef [public] struct {
|
||||
uint8 x;
|
||||
uint16 y;
|
||||
} bla;
|
||||
',
|
||||
'
|
||||
struct ndr_push *ndr = ndr_push_init();
|
||||
struct bla r;
|
||||
uint8_t expected[] = { 0x0D, 0xef, 0xbe };
|
||||
DATA_BLOB expected_blob = { expected, 3 };
|
||||
DATA_BLOB result_blob;
|
||||
ndr->flags |= LIBNDR_FLAG_NOALIGN;
|
||||
|
||||
r.x = 13;
|
||||
r.y = 0xbeef;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_push_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r)))
|
||||
return 1;
|
||||
|
||||
result_blob = ndr_push_blob(ndr);
|
||||
|
||||
if (!data_blob_equal(&result_blob, &expected_blob))
|
||||
return 2;
|
||||
');
|
||||
|
||||
test_samba4_ndr('align-blob-align2',
|
||||
'
|
||||
typedef [public] struct {
|
||||
uint8 x;
|
||||
[flag(LIBNDR_FLAG_ALIGN2)] DATA_BLOB data;
|
||||
uint8 y;
|
||||
} blie;
|
||||
',
|
||||
'
|
||||
struct ndr_push *ndr = ndr_push_init();
|
||||
struct blie r;
|
||||
uint8_t data[] = { 0x01, 0x02 };
|
||||
uint8_t expected[] = { 0x0D, 0x00, 0x0E };
|
||||
DATA_BLOB expected_blob = { expected, 3 };
|
||||
DATA_BLOB result_blob;
|
||||
|
||||
r.x = 13;
|
||||
r.y = 14;
|
||||
r.data.data = data;
|
||||
r.data.length = 2;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_push_blie(ndr, NDR_SCALARS|NDR_BUFFERS, &r)))
|
||||
return 1;
|
||||
|
||||
result_blob = ndr_push_blob(ndr);
|
||||
|
||||
if (!data_blob_equal(&result_blob, &expected_blob))
|
||||
return 2;
|
||||
');
|
||||
Executable
+119
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/perl
|
||||
# NDR allocation tests
|
||||
# (C) 2005 Jelmer Vernooij. Published under the GNU GPL
|
||||
use strict;
|
||||
|
||||
use Test::More tests => 5 * 8;
|
||||
use FindBin qw($RealBin);
|
||||
use lib "$RealBin/../lib";
|
||||
use lib "$RealBin";
|
||||
use Util qw(test_samba4_ndr);
|
||||
|
||||
# Check that an outgoing scalar pointer is allocated correctly
|
||||
|
||||
test_samba4_ndr("alloc-scalar",
|
||||
'
|
||||
typedef struct {
|
||||
uint8 *x;
|
||||
} bla;
|
||||
|
||||
[public] void TestAlloc([in] bla foo);
|
||||
','
|
||||
uint8_t data[] = { 0xde, 0xad, 0xbe, 0xef, 0x03 };
|
||||
DATA_BLOB b = { data, 5 };
|
||||
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL);
|
||||
struct TestAlloc r;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_pull_TestAlloc(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (r.in.foo.x == NULL)
|
||||
return 2;
|
||||
|
||||
if (*r.in.foo.x != 0x03)
|
||||
return 3;
|
||||
'
|
||||
);
|
||||
|
||||
# Check that an outgoing buffer pointer is allocated correctly
|
||||
test_samba4_ndr("alloc-buffer",
|
||||
'
|
||||
typedef struct { uint8 data; } blie;
|
||||
typedef struct { blie *x; } bla;
|
||||
|
||||
[public] void TestAlloc([in] bla foo);
|
||||
','
|
||||
uint8_t data[] = { 0xde, 0xad, 0xbe, 0xef, 0x03 };
|
||||
DATA_BLOB b = { data, 5 };
|
||||
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL);
|
||||
struct TestAlloc r;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_pull_TestAlloc(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (r.in.foo.x == NULL)
|
||||
return 2;
|
||||
|
||||
if (r.in.foo.x->data != 0x03)
|
||||
return 3;
|
||||
'
|
||||
);
|
||||
|
||||
# Check that ref pointers aren't allocated by default
|
||||
test_samba4_ndr("ref-noalloc-null",
|
||||
'
|
||||
[public] void TestAlloc([in,ref] uint8 *t);
|
||||
','
|
||||
uint8_t data[] = { 0x03 };
|
||||
DATA_BLOB b = { data, 1 };
|
||||
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL);
|
||||
struct TestAlloc r;
|
||||
r.in.t = NULL;
|
||||
|
||||
if (NT_STATUS_IS_OK(ndr_pull_TestAlloc(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
'
|
||||
);
|
||||
|
||||
# Check that ref pointers aren't allocated by default
|
||||
test_samba4_ndr("ref-noalloc",
|
||||
'
|
||||
[public] void TestAlloc([in,ref] uint8 *t);
|
||||
','
|
||||
uint8_t data[] = { 0x03 };
|
||||
DATA_BLOB b = { data, 1 };
|
||||
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL);
|
||||
struct TestAlloc r;
|
||||
uint8_t x;
|
||||
r.in.t = &x;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_pull_TestAlloc(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (*r.in.t != 0x03)
|
||||
return 2;
|
||||
'
|
||||
);
|
||||
|
||||
# Check that an outgoing ref pointer is allocated correctly
|
||||
test_samba4_ndr("ref-alloc",
|
||||
'
|
||||
[public] void TestAlloc([in,ref] uint8 *t);
|
||||
','
|
||||
uint8_t data[] = { 0x03 };
|
||||
DATA_BLOB b = { data, 1 };
|
||||
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL);
|
||||
struct TestAlloc r;
|
||||
ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
|
||||
r.in.t = NULL;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_pull_TestAlloc(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (r.in.t == NULL)
|
||||
return 2;
|
||||
|
||||
if (*r.in.t != 0x03)
|
||||
return 3;
|
||||
'
|
||||
);
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/perl
|
||||
# Array testing
|
||||
# (C) 2005 Jelmer Vernooij <jelmer@samba.org>
|
||||
# Published under the GNU General Public License
|
||||
use strict;
|
||||
|
||||
use Test::More tests => 8;
|
||||
use FindBin qw($RealBin);
|
||||
use lib "$RealBin/../lib";
|
||||
use lib "$RealBin";
|
||||
use Util qw(test_samba4_ndr);
|
||||
|
||||
test_samba4_ndr(
|
||||
'Fixed-Array',
|
||||
|
||||
'[public] void Test([in] uint8 x[10]);',
|
||||
|
||||
'
|
||||
uint8_t data[] = {1,2,3,4,5,6,7,8,9,10};
|
||||
int i;
|
||||
DATA_BLOB b;
|
||||
struct ndr_pull *ndr;
|
||||
struct Test r;
|
||||
|
||||
b.data = data;
|
||||
b.length = 10;
|
||||
ndr = ndr_pull_init_blob(&b, mem_ctx);
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_pull_Test(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (ndr->offset != 10)
|
||||
return 2;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (r.in.x[i] != i+1) return 3;
|
||||
}
|
||||
');
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/perl
|
||||
# Simple tests for unique pointers
|
||||
# (C) 2006 Jelmer Vernooij <jelmer@samba.org>.
|
||||
# Published under the GNU General Public License.
|
||||
use strict;
|
||||
|
||||
use Test::More tests => 1 * 8;
|
||||
use FindBin qw($RealBin);
|
||||
use lib "$RealBin/../lib";
|
||||
use lib "$RealBin";
|
||||
use Util qw(test_samba4_ndr);
|
||||
|
||||
test_samba4_ndr("fullptr-push-dup",
|
||||
'
|
||||
[public] uint16 echo_TestFull([in,ptr] uint32 *x, [in,ptr] uint32 *y);
|
||||
',
|
||||
'
|
||||
struct ndr_push *ndr = ndr_push_init();
|
||||
uint32_t v = 13;
|
||||
struct echo_TestFull r;
|
||||
r.in.x = &v;
|
||||
r.in.y = &v;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_push_echo_TestFull(ndr, NDR_IN, &r))) {
|
||||
fprintf(stderr, "push failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ndr->offset != 12) {
|
||||
fprintf(stderr, "Offset(%d) != 12\n", ndr->offset);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (ndr->data[0] != ndr->data[8] ||
|
||||
ndr->data[1] != ndr->data[9] ||
|
||||
ndr->data[2] != ndr->data[10] ||
|
||||
ndr->data[3] != ndr->data[11]) {
|
||||
fprintf(stderr, "Data incorrect\n");
|
||||
return 3;
|
||||
}
|
||||
');
|
||||
Executable
+527
@@ -0,0 +1,527 @@
|
||||
#!/usr/bin/perl
|
||||
# Simple tests for pidl's handling of ref pointers, based
|
||||
# on tridge's ref_notes.txt
|
||||
# (C) 2005 Jelmer Vernooij <jelmer@samba.org>.
|
||||
# Published under the GNU General Public License.
|
||||
use strict;
|
||||
|
||||
use Test::More tests => 22 * 8;
|
||||
use FindBin qw($RealBin);
|
||||
use lib "$RealBin/../lib";
|
||||
use lib "$RealBin";
|
||||
use Util qw(test_samba4_ndr);
|
||||
|
||||
test_samba4_ndr("noptr-push",
|
||||
' typedef struct {
|
||||
uint16 x;
|
||||
} xstruct;
|
||||
|
||||
[public] uint16 echo_TestRef([in] xstruct foo);
|
||||
',
|
||||
'
|
||||
struct ndr_push *ndr = ndr_push_init();
|
||||
uint16_t v = 13;
|
||||
struct echo_TestRef r;
|
||||
r.in.foo.x = v;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) {
|
||||
fprintf(stderr, "push failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ndr->offset != 2) {
|
||||
fprintf(stderr, "Offset(%d) != 2\n", ndr->offset);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (ndr->data[0] != 13 || ndr->data[1] != 0) {
|
||||
fprintf(stderr, "Data incorrect\n");
|
||||
return 3;
|
||||
}
|
||||
');
|
||||
|
||||
test_samba4_ndr("ptr-embedded-push",
|
||||
' typedef struct {
|
||||
uint16 *x;
|
||||
} xstruct;
|
||||
|
||||
[public] uint16 echo_TestRef([in] xstruct foo);
|
||||
',
|
||||
'
|
||||
uint16_t v = 13;
|
||||
struct ndr_push *ndr = ndr_push_init();
|
||||
struct echo_TestRef r;
|
||||
r.in.foo.x = &v;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (ndr->offset != 6)
|
||||
return 2;
|
||||
|
||||
if (ndr->data[0] == 0 && ndr->data[1] == 0 &&
|
||||
ndr->data[2] == 0 && ndr->data[3] == 0)
|
||||
return 3;
|
||||
|
||||
if (ndr->data[4] != 13 || ndr->data[5] != 0)
|
||||
return 4;
|
||||
');
|
||||
|
||||
test_samba4_ndr("ptr-embedded-push-null",
|
||||
' typedef struct {
|
||||
uint16 *x;
|
||||
} xstruct;
|
||||
|
||||
[public] uint16 echo_TestRef([in] xstruct foo);
|
||||
',
|
||||
'
|
||||
struct ndr_push *ndr = ndr_push_init();
|
||||
struct echo_TestRef r;
|
||||
r.in.foo.x = NULL;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (ndr->offset != 4)
|
||||
return 2;
|
||||
|
||||
if (ndr->data[0] != 0 || ndr->data[1] != 0 ||
|
||||
ndr->data[2] != 0 || ndr->data[3] != 0)
|
||||
return 3;
|
||||
');
|
||||
|
||||
test_samba4_ndr("refptr-embedded-push",
|
||||
'
|
||||
typedef struct {
|
||||
[ref] uint16 *x;
|
||||
} xstruct;
|
||||
|
||||
[public] uint16 echo_TestRef([in] xstruct foo);
|
||||
',
|
||||
'
|
||||
uint16_t v = 13;
|
||||
struct ndr_push *ndr = ndr_push_init();
|
||||
struct echo_TestRef r;
|
||||
r.in.foo.x = &v;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (ndr->offset != 6)
|
||||
return 2;
|
||||
|
||||
if (ndr->data[0] == 0 && ndr->data[1] == 0 &&
|
||||
ndr->data[2] == 0 && ndr->data[3] == 0)
|
||||
return 3;
|
||||
|
||||
if (ndr->data[4] != 13 || ndr->data[5] != 0)
|
||||
return 4;
|
||||
');
|
||||
|
||||
test_samba4_ndr("refptr-embedded-push-null",
|
||||
'
|
||||
typedef struct {
|
||||
[ref] uint16 *x;
|
||||
} xstruct;
|
||||
|
||||
[public] uint16 echo_TestRef([in] xstruct foo);
|
||||
',
|
||||
'
|
||||
struct ndr_push *ndr = ndr_push_init();
|
||||
struct echo_TestRef r;
|
||||
r.in.foo.x = NULL;
|
||||
|
||||
if (NT_STATUS_IS_OK(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
/* Windows gives [client runtime error 0x6f4] */
|
||||
');
|
||||
|
||||
test_samba4_ndr("ptr-top-push",
|
||||
'
|
||||
typedef struct {
|
||||
uint16 x;
|
||||
} xstruct;
|
||||
|
||||
[public] uint16 echo_TestRef([in] xstruct *foo);
|
||||
',
|
||||
'
|
||||
struct ndr_push *ndr = ndr_push_init();
|
||||
struct echo_TestRef r;
|
||||
struct xstruct s;
|
||||
s.x = 13;
|
||||
r.in.foo = &s;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (ndr->offset != 2)
|
||||
return 2;
|
||||
|
||||
if (ndr->data[0] != 13 || ndr->data[1] != 0)
|
||||
return 3;
|
||||
');
|
||||
|
||||
test_samba4_ndr("ptr-top-push-null",
|
||||
'
|
||||
typedef struct {
|
||||
uint16 x;
|
||||
} xstruct;
|
||||
|
||||
[public] uint16 echo_TestRef([in] xstruct *foo);
|
||||
',
|
||||
'
|
||||
struct ndr_push *ndr = ndr_push_init();
|
||||
struct echo_TestRef r;
|
||||
r.in.foo = NULL;
|
||||
|
||||
if (NT_STATUS_IS_OK(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
/* Windows gives [client runtime error 0x6f4] */
|
||||
');
|
||||
|
||||
|
||||
test_samba4_ndr("refptr-top-push",
|
||||
'
|
||||
typedef struct {
|
||||
uint16 x;
|
||||
} xstruct;
|
||||
|
||||
[public] uint16 echo_TestRef([in,ref] xstruct *foo);
|
||||
',
|
||||
'
|
||||
struct ndr_push *ndr = ndr_push_init();
|
||||
struct echo_TestRef r;
|
||||
struct xstruct s;
|
||||
s.x = 13;
|
||||
r.in.foo = &s;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (ndr->offset != 2)
|
||||
return 2;
|
||||
|
||||
if (ndr->data[0] != 13 || ndr->data[1] != 0)
|
||||
return 3;
|
||||
');
|
||||
|
||||
test_samba4_ndr("refptr-top-push-null",
|
||||
'
|
||||
typedef struct {
|
||||
uint16 x;
|
||||
} xstruct;
|
||||
|
||||
[public] uint16 echo_TestRef([in,ref] xstruct *foo);
|
||||
',
|
||||
'
|
||||
struct ndr_push *ndr = ndr_push_init();
|
||||
struct echo_TestRef r;
|
||||
r.in.foo = NULL;
|
||||
|
||||
if (NT_STATUS_IS_OK(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
/* Windows gives [client runtime error 0x6f4] */
|
||||
');
|
||||
|
||||
|
||||
test_samba4_ndr("uniqueptr-top-push",
|
||||
' typedef struct {
|
||||
uint16 x;
|
||||
} xstruct;
|
||||
|
||||
[public] uint16 echo_TestRef([in,unique] xstruct *foo);
|
||||
',
|
||||
'
|
||||
struct ndr_push *ndr = ndr_push_init();
|
||||
struct echo_TestRef r;
|
||||
struct xstruct s;
|
||||
s.x = 13;
|
||||
r.in.foo = &s;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (ndr->offset != 6)
|
||||
return 2;
|
||||
|
||||
if (ndr->data[0] == 0 && ndr->data[1] == 0 &&
|
||||
ndr->data[2] == 0 && ndr->data[3] == 0)
|
||||
return 3;
|
||||
|
||||
if (ndr->data[4] != 13 || ndr->data[5] != 0)
|
||||
return 4;
|
||||
');
|
||||
|
||||
test_samba4_ndr("uniqueptr-top-push-null",
|
||||
' typedef struct {
|
||||
uint16 x;
|
||||
} xstruct;
|
||||
|
||||
[public] uint16 echo_TestRef([in,unique] xstruct *foo);
|
||||
',
|
||||
'
|
||||
struct ndr_push *ndr = ndr_push_init();
|
||||
struct echo_TestRef r;
|
||||
r.in.foo = NULL;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (ndr->offset != 4)
|
||||
return 2;
|
||||
|
||||
if (ndr->data[0] != 0 || ndr->data[1] != 0 ||
|
||||
ndr->data[2] != 0 || ndr->data[3] != 0)
|
||||
return 3;
|
||||
');
|
||||
|
||||
|
||||
test_samba4_ndr("ptr-top-out-pull",
|
||||
'
|
||||
typedef struct {
|
||||
uint16 x;
|
||||
} xstruct;
|
||||
|
||||
[public] void echo_TestRef([out] xstruct *foo);
|
||||
',
|
||||
'
|
||||
uint8_t data[] = { 0x0D, 0x00 };
|
||||
DATA_BLOB b = { data, 2 };
|
||||
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL);
|
||||
struct xstruct s;
|
||||
struct echo_TestRef r;
|
||||
|
||||
r.out.foo = &s;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_pull_echo_TestRef(ndr, NDR_OUT, &r)))
|
||||
return 1;
|
||||
|
||||
if (!r.out.foo)
|
||||
return 2;
|
||||
|
||||
if (r.out.foo->x != 13)
|
||||
return 3;
|
||||
');
|
||||
|
||||
test_samba4_ndr("ptr-top-out-pull-null",
|
||||
'
|
||||
typedef struct {
|
||||
uint16 x;
|
||||
} xstruct;
|
||||
|
||||
[public] void echo_TestRef([out] xstruct *foo);
|
||||
',
|
||||
'
|
||||
uint8_t data[] = { 0x0D, 0x00 };
|
||||
DATA_BLOB b = { data, 2 };
|
||||
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL);
|
||||
struct echo_TestRef r;
|
||||
|
||||
r.out.foo = NULL;
|
||||
|
||||
if (NT_STATUS_IS_OK(ndr_pull_echo_TestRef(ndr, NDR_OUT, &r)))
|
||||
return 1;
|
||||
|
||||
/* Windows gives [client runtime error 0x6f4] */
|
||||
');
|
||||
|
||||
|
||||
test_samba4_ndr("refptr-top-out-pull",
|
||||
'
|
||||
typedef struct {
|
||||
uint16 x;
|
||||
} xstruct;
|
||||
|
||||
[public] void echo_TestRef([out,ref] xstruct *foo);
|
||||
',
|
||||
'
|
||||
uint8_t data[] = { 0x0D, 0x00 };
|
||||
DATA_BLOB b = { data, 2 };
|
||||
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL);
|
||||
struct xstruct s;
|
||||
struct echo_TestRef r;
|
||||
|
||||
r.out.foo = &s;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_pull_echo_TestRef(ndr, NDR_OUT, &r)))
|
||||
return 1;
|
||||
|
||||
if (!r.out.foo)
|
||||
return 2;
|
||||
|
||||
if (r.out.foo->x != 13)
|
||||
return 3;
|
||||
');
|
||||
|
||||
test_samba4_ndr("refptr-top-out-pull-null",
|
||||
'
|
||||
typedef struct {
|
||||
uint16 x;
|
||||
} xstruct;
|
||||
|
||||
[public] void echo_TestRef([out,ref] xstruct *foo);
|
||||
',
|
||||
'
|
||||
uint8_t data[] = { 0x0D, 0x00 };
|
||||
DATA_BLOB b = { data, 2 };
|
||||
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL);
|
||||
struct echo_TestRef r;
|
||||
|
||||
r.out.foo = NULL;
|
||||
|
||||
if (NT_STATUS_IS_OK(ndr_pull_echo_TestRef(ndr, NDR_OUT, &r)))
|
||||
return 1;
|
||||
|
||||
/* Windows gives [client runtime error 0x6f4] */
|
||||
');
|
||||
|
||||
|
||||
test_samba4_ndr("ptr-top-push-double",
|
||||
'
|
||||
[public] void echo_TestRef([in] uint16 **foo);
|
||||
',
|
||||
' struct ndr_push *ndr = ndr_push_init();
|
||||
struct echo_TestRef r;
|
||||
uint16_t v = 13;
|
||||
uint16_t *pv = &v;
|
||||
r.in.foo = &pv;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (ndr->offset != 6)
|
||||
return 2;
|
||||
|
||||
if (ndr->data[0] == 0 && ndr->data[1] == 0 &&
|
||||
ndr->data[2] == 0 && ndr->data[3] == 0)
|
||||
return 3;
|
||||
|
||||
if (ndr->data[4] != 0x0D || ndr->data[5] != 0x00)
|
||||
return 4;
|
||||
');
|
||||
|
||||
SKIP: {
|
||||
skip "ptr-top-push-double-sndnull is known to fail", 8;
|
||||
|
||||
test_samba4_ndr("ptr-top-push-double-sndnull",
|
||||
'
|
||||
[public] void echo_TestRef([in] uint16 **foo);
|
||||
',
|
||||
' struct ndr_push *ndr = ndr_push_init();
|
||||
struct echo_TestRef r;
|
||||
uint16_t *pv = NULL;
|
||||
r.in.foo = &pv;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (ndr->offset != 4)
|
||||
return 2;
|
||||
|
||||
if (ndr->data[0] != 0 || ndr->data[1] != 0 ||
|
||||
ndr->data[2] != 0 || ndr->data[3] != 0)
|
||||
return 3;
|
||||
');
|
||||
}
|
||||
|
||||
test_samba4_ndr("ptr-top-push-double-fstnull",
|
||||
'
|
||||
[public] void echo_TestRef([in] uint16 **foo);
|
||||
',
|
||||
' struct ndr_push *ndr = ndr_push_init();
|
||||
struct echo_TestRef r;
|
||||
r.in.foo = NULL;
|
||||
|
||||
if (NT_STATUS_IS_OK(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
/* Windows gives [client runtime error 0x6f4] */
|
||||
|
||||
');
|
||||
|
||||
|
||||
test_samba4_ndr("refptr-top-push-double",
|
||||
'
|
||||
[public] void echo_TestRef([in,ref] uint16 **foo);
|
||||
',
|
||||
' struct ndr_push *ndr = ndr_push_init();
|
||||
struct echo_TestRef r;
|
||||
uint16_t v = 13;
|
||||
uint16_t *pv = &v;
|
||||
r.in.foo = &pv;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (ndr->offset != 6)
|
||||
return 2;
|
||||
|
||||
if (ndr->data[0] == 0 && ndr->data[1] == 0 &&
|
||||
ndr->data[2] == 0 && ndr->data[3] == 0)
|
||||
return 3;
|
||||
|
||||
if (ndr->data[4] != 0x0D || ndr->data[5] != 0x00)
|
||||
return 4;
|
||||
');
|
||||
|
||||
SKIP: {
|
||||
|
||||
skip "refptr-top-push-double-sndnull is known to fail", 8;
|
||||
|
||||
test_samba4_ndr("refptr-top-push-double-sndnull",
|
||||
'
|
||||
[public] void echo_TestRef([in,ref] uint16 **foo);
|
||||
',
|
||||
' struct ndr_push *ndr = ndr_push_init();
|
||||
struct echo_TestRef r;
|
||||
uint16_t *pv = NULL;
|
||||
r.in.foo = &pv;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (ndr->offset != 4)
|
||||
return 2;
|
||||
|
||||
if (ndr->data[0] != 0 || ndr->data[1] != 0 ||
|
||||
ndr->data[2] != 0 || ndr->data[3] != 0)
|
||||
return 3;
|
||||
');
|
||||
}
|
||||
|
||||
test_samba4_ndr("refptr-top-push-double-fstnull",
|
||||
'
|
||||
[public] void echo_TestRef([in,ref] uint16 **foo);
|
||||
',
|
||||
' struct ndr_push *ndr = ndr_push_init();
|
||||
struct echo_TestRef r;
|
||||
r.in.foo = NULL;
|
||||
|
||||
if (NT_STATUS_IS_OK(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
/* Windows gives [client runtime error 0x6f4] */
|
||||
|
||||
');
|
||||
|
||||
SKIP: {
|
||||
skip "ignore-ptrs are not supported yet", 8;
|
||||
test_samba4_ndr("ignore-ptr",
|
||||
'
|
||||
[public] void echo_TestRef([in,ignore] uint16 *foo, [in] uint16 *bar);
|
||||
',
|
||||
' struct ndr_push *ndr = ndr_push_init();
|
||||
struct echo_TestRef r;
|
||||
uint16_t v = 10;
|
||||
r.in.foo = &v;
|
||||
r.in.bar = &v;
|
||||
|
||||
if (NT_STATUS_IS_OK(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (ndr->offset != 4)
|
||||
return 2;
|
||||
');
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/perl
|
||||
# NDR represent_as() / transmit_as() tests
|
||||
# (C) 2006 Jelmer Vernooij. Published under the GNU GPL
|
||||
use strict;
|
||||
|
||||
use Test::More tests => 1 * 8;
|
||||
use FindBin qw($RealBin);
|
||||
use lib "$RealBin/../lib";
|
||||
use lib "$RealBin";
|
||||
use Util qw(test_samba4_ndr);
|
||||
|
||||
test_samba4_ndr('represent_as-simple',
|
||||
'
|
||||
void bla([in,represent_as(uint32)] uint8 x);
|
||||
',
|
||||
'
|
||||
uint8_t expected[] = { 0x0D };
|
||||
DATA_BLOB in_blob = { expected, 1 };
|
||||
struct ndr_pull *ndr = ndr_pull_init_blob(&in_blob, NULL);
|
||||
struct bla r;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_pull_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r)))
|
||||
return 1;
|
||||
|
||||
if (r.in.x != 13)
|
||||
return 2;
|
||||
',
|
||||
'
|
||||
#include <libcli/util/nterr.h>
|
||||
|
||||
NTSTATUS ndr_uint8_to_uint32(uint8_t from, uint32_t *to)
|
||||
{
|
||||
*to = from;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
NTSTATUS ndr_uint32_to_uint8(uint32_t from, uint8_t *to)
|
||||
{
|
||||
*to = from;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
'
|
||||
);
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/perl
|
||||
# Some simple tests for pidl
|
||||
# (C) 2005 Jelmer Vernooij <jelmer@samba.org>
|
||||
# Published under the GNU General Public License
|
||||
use strict;
|
||||
|
||||
use Test::More tests => 8;
|
||||
use FindBin qw($RealBin);
|
||||
use lib "$RealBin/../lib";
|
||||
use lib "$RealBin";
|
||||
use Util qw(test_samba4_ndr);
|
||||
|
||||
test_samba4_ndr("simple", "void Test(); ",
|
||||
"
|
||||
uint8_t data[] = { 0x02 };
|
||||
uint8_t result;
|
||||
DATA_BLOB b;
|
||||
struct ndr_pull *ndr;
|
||||
|
||||
b.data = data;
|
||||
b.length = 1;
|
||||
ndr = ndr_pull_init_blob(&b, mem_ctx);
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_pull_uint8(ndr, NDR_SCALARS, &result)))
|
||||
return 1;
|
||||
|
||||
if (result != 0x02)
|
||||
return 2;
|
||||
");
|
||||
Executable
+84
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/perl
|
||||
# String tests for pidl
|
||||
# (C) 2005 Jelmer Vernooij <jelmer@samba.org>
|
||||
# Published under the GNU General Public License
|
||||
use strict;
|
||||
|
||||
use Test::More tests => 3 * 8;
|
||||
use FindBin qw($RealBin);
|
||||
use lib "$RealBin/../lib";
|
||||
use lib "$RealBin";
|
||||
use Util qw(test_samba4_ndr);
|
||||
|
||||
test_samba4_ndr("string-pull-empty",
|
||||
' [public] void TestString([in,flag(STR_ASCII|LIBNDR_FLAG_STR_SIZE4)] string data);',
|
||||
'
|
||||
uint8_t data[] = { 0x00, 0x00, 0x00, 0x00 };
|
||||
DATA_BLOB b = { data, 4 };
|
||||
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL);
|
||||
struct TestString r;
|
||||
r.in.data = NULL;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_pull_TestString(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (r.in.data == NULL)
|
||||
return 2;
|
||||
|
||||
if (r.in.data[0] != 0)
|
||||
return 3;
|
||||
');
|
||||
|
||||
test_samba4_ndr("string-ascii-pull",
|
||||
'
|
||||
[public] void TestString([in,flag(STR_ASCII|LIBNDR_FLAG_STR_SIZE4)] string data);
|
||||
',
|
||||
'
|
||||
uint8_t data[] = { 0x03, 0x00, 0x00, 0x00,
|
||||
\'f\', \'o\', \'o\', 0 };
|
||||
DATA_BLOB b = { data, 8 };
|
||||
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL);
|
||||
struct TestString r;
|
||||
r.in.data = NULL;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_pull_TestString(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (r.in.data == NULL)
|
||||
return 2;
|
||||
|
||||
if (strncmp(r.in.data, "foo", 3) != 0)
|
||||
return 3;
|
||||
|
||||
if (r.in.data[4] != 0)
|
||||
return 4;
|
||||
');
|
||||
|
||||
test_samba4_ndr("string-out",
|
||||
'
|
||||
[public] void TestString([out,string] uint8 **data);
|
||||
',
|
||||
'
|
||||
uint8_t data[] = { 0x03, 0x00, 0x00, 0x00,
|
||||
\'f\', \'o\', \'o\', 0 };
|
||||
DATA_BLOB b = { data, 8 };
|
||||
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL);
|
||||
struct TestString r;
|
||||
char *str = NULL;
|
||||
r.out.data = &str;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_pull_TestString(ndr, NDR_IN, &r)))
|
||||
return 1;
|
||||
|
||||
if (r.out.data == NULL)
|
||||
return 2;
|
||||
|
||||
if (*r.out.data == NULL)
|
||||
return 3;
|
||||
|
||||
if (strncmp(r.out.data, "foo", 3) != 0)
|
||||
return 3;
|
||||
|
||||
if (r.out.data[4] != 0)
|
||||
return 4;
|
||||
');
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/perl
|
||||
# Support for tagged types
|
||||
# (C) 2005 Jelmer Vernooij. Published under the GNU GPL
|
||||
use strict;
|
||||
|
||||
use Test::More tests => 1 * 8;
|
||||
use FindBin qw($RealBin);
|
||||
use lib "$RealBin/../lib";
|
||||
use lib "$RealBin";
|
||||
use Util qw(test_samba4_ndr);
|
||||
|
||||
SKIP: {
|
||||
skip "Tagged types without typedef are not supported yet", 8;
|
||||
|
||||
test_samba4_ndr('struct-notypedef',
|
||||
'
|
||||
struct bla {
|
||||
uint8 x;
|
||||
};
|
||||
',
|
||||
'
|
||||
struct ndr_push *ndr = ndr_push_init();
|
||||
struct bla r;
|
||||
uint8_t expected[] = { 0x0D };
|
||||
DATA_BLOB expected_blob = { expected, 1 };
|
||||
DATA_BLOB result_blob;
|
||||
r.x = 13;
|
||||
|
||||
if (NT_STATUS_IS_ERR(ndr_push_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r)))
|
||||
return 1;
|
||||
|
||||
result_blob = ndr_push_blob(ndr);
|
||||
|
||||
if (!data_blob_equal(&result_blob, &expected_blob))
|
||||
return 2;
|
||||
');
|
||||
|
||||
}
|
||||
Executable
+90
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/perl
|
||||
# Some simple tests for pidls parsing routines
|
||||
# (C) 2005 Jelmer Vernooij <jelmer@samba.org>
|
||||
# Published under the GNU General Public License
|
||||
use strict;
|
||||
|
||||
use Test::More tests => 59;
|
||||
use FindBin qw($RealBin);
|
||||
use lib "$RealBin/../lib";
|
||||
use Parse::Pidl::IDL;
|
||||
use Parse::Pidl::NDR;
|
||||
|
||||
sub testok($$)
|
||||
{
|
||||
my ($name, $data) = @_;
|
||||
|
||||
my $pidl = Parse::Pidl::IDL::parse_string($data, "<$name>");
|
||||
|
||||
ok (defined($pidl), $name);
|
||||
return $pidl
|
||||
}
|
||||
|
||||
sub testfail($$)
|
||||
{
|
||||
my ($name, $data) = @_;
|
||||
|
||||
my $pidl = Parse::Pidl::IDL::parse_string($data, "<$name>");
|
||||
|
||||
ok ((not defined $pidl), $name);
|
||||
}
|
||||
|
||||
testfail "unknowntag", "bla test {};";
|
||||
testok "test1", "interface test { void Test(); }; ";
|
||||
testok "voidtest", "interface test { int Testx(void); }; ";
|
||||
testfail "voidtest", "interface test { Test(); }; ";
|
||||
testok "argtest", "interface test { int Test(int a, long b, uint32 c); }; ";
|
||||
testok "array1", "interface test { int Test(int a[]); };";
|
||||
testok "array2", "interface test { int Test(int a[2]); };";
|
||||
testok "array3", "interface test { int Test(int a[b]); };";
|
||||
testfail "array4", "interface test { int Test(int[] a); };";
|
||||
testok "ptr1", "interface test { int Test(int *a); };";
|
||||
testok "ptr2", "interface test { int Test(int **a); };";
|
||||
testok "ptr3", "interface test { int Test(int ***a); };";
|
||||
testfail "empty1", "interface test { };";
|
||||
testfail "empty2", "";
|
||||
testok "attr1", "[uuid(\"myuuid\"),attr] interface test { int Test(int ***a); };";
|
||||
testok "attr2", "interface test { [public] int Test(); };";
|
||||
testok "attr3", "[attr1] [attr2] interface test { [public] int Test(); };";
|
||||
testok "multfn", "interface test { int test1(); int test2(); };";
|
||||
testok "multif", "interface test { int test1(); }; interface test2 { int test2(); };";
|
||||
testok "tdstruct1", "interface test { typedef struct { } foo; };";
|
||||
testok "tdstruct2", "interface test { typedef struct { int a; } foo; };";
|
||||
testok "tdstruct3", "interface test { typedef struct { int a; int b; } foo; };";
|
||||
testfail "tdstruct4", "interface test { typedef struct { int a, int b; } foo; };";
|
||||
testok "struct1", "interface test { struct x { }; };";
|
||||
testok "struct2", "interface test { struct x { int a; }; };";
|
||||
testok "struct3", "interface test { struct x { int a; int b; }; };";
|
||||
testfail "struct4", "interface test { struct x { int a, int b; }; };";
|
||||
testfail "struct5", "interface test { struct { int a; } x; };";
|
||||
testok "tdunion1", "interface test { typedef union { } a; };";
|
||||
testok "tdunion2", "interface test { typedef union { int a; } a; };";
|
||||
testok "union1", "interface test { union a { }; };";
|
||||
testok "union2", "interface test { union x { int a; }; };";
|
||||
testfail "union3", "interface test { union { int a; } x; };";
|
||||
testok "typedef1", "interface test { typedef int a; };";
|
||||
testfail "typedef2", "interface test { typedef x; };";
|
||||
testok "tdenum1", "interface test { typedef enum { A=1, B=2, C} a; };";
|
||||
testok "enum1", "interface test { enum a { A=1, B=2, C}; };";
|
||||
testfail "enum2", "interface test { enum { A=1, B=2, C} a; };";
|
||||
testok "nested1", "interface test { struct x { struct { int a; } z; }; };";
|
||||
testok "nested2", "interface test { struct x { struct y { int a; } z; }; };";
|
||||
testok "bitmap1", "interface test { bitmap x { a=1 }; };";
|
||||
testok "unsigned", "interface test { struct x { unsigned short y; }; };";
|
||||
testok "signed", "interface test { struct x { signed short y; }; };";
|
||||
testok "declarg", "interface test { void test(struct { int x; } a); };";
|
||||
testok "structqual", "interface test { struct x { struct y z; }; };";
|
||||
testok "unionqual", "interface test { struct x { union y z; }; };";
|
||||
testok "enumqual", "interface test { struct x { enum y z; }; };";
|
||||
testok "bitmapqual", "interface test { struct x { bitmap y z; }; };";
|
||||
testok "emptystructdecl", "interface test { struct x; };";
|
||||
testok "emptyenumdecl", "interface test { enum x; };";
|
||||
testok "emptytdstructdecl", "interface test { typedef struct x y; };";
|
||||
testok "import", "import \"foo.idl\";";
|
||||
testok "include", "include \"foo.h\";";
|
||||
testfail "import-noquotes", "import foo.idl;";
|
||||
testfail "include-noquotes", "include foo.idl;";
|
||||
testok "importlib", "importlib \"foo.idl\";";
|
||||
testfail "import-nosemicolon", "import \"foo.idl\"";
|
||||
testok "import-multiple", "import \"foo.idl\", \"bar.idl\";";
|
||||
testok "include-multiple", "include \"foo.idl\", \"bar.idl\";";
|
||||
Reference in New Issue
Block a user