Add a local copy of pidl, add a README.ethereal to include

minimalistic building and usage instructions.


svn path=/trunk/; revision=15836
This commit is contained in:
Jörg Mayer 2005-09-16 09:31:05 +00:00
parent f6264ee8d2
commit fdc91d7e24
35 changed files with 14790 additions and 0 deletions

25
tools/pidl/Makefile.PL Executable file
View File

@ -0,0 +1,25 @@
use ExtUtils::MakeMaker;
WriteMakefile(
'NAME' => 'Parse::Pidl',
'VERSION_FROM' => 'lib/Parse/Pidl.pm',
'EXE_FILES' => [ 'pidl' ],
'PMLIBDIRS' => [ 'lib' ],
'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
doc: pidl.1 pidl.1.html
XSLTPROC=xsltproc
%.1: %.1.xml
test -z "$(XSLTPROC)" || $(XSLTPROC) -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
%.html: %.xml
test -z "$(XSLTPROC)" || $(XSLTPROC) -o $@ http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl $<
EOT
}

70
tools/pidl/README Normal file
View File

@ -0,0 +1,70 @@
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.
Documentation:
==============
Run 'make doc' to generate the manpage and a HTML version of the manpage.
This requires the xsltproc utility to be installed.
Internals overview:
===================
-- Generic --
Parse::Pidl::Dump - Converts the parse tree back to an IDL file
Parse::Pidl::Samba::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::Samba::NDR::Client - Generates client call functions in C using the NDR parser
Parse::Pidl::Samba::SWIG - Generates SWIG interface files (.i)
Parse::Pidl::Samba::NDR::Header - Generates a header file with NDR-parser specific data
Parse::Pidl::Samba::NDR::Parser - Generates pull/push functions for parsing NDR
Parse::Pidl::Samba::NDR::Server - Generates server side implementation in C
Parse::Pidl::Samba::TDR - Parser generator for the "Trivial Data Representation"
Parse::Pidl::Samba::Template - Generates stubs in C for server implementation
Parse::Pidl::Samba::EJS - Generates bindings for Embedded JavaScript (EJS)
Parse::Pidl::Samba::EJSHeader - Generates headers for the EJS bindings
-- Samba COM / DCOM --
Parse::Pidl::Samba::COM::Proxy - Generates proxy object for DCOM (client-side)
Parse::Pidl::Samba::COM::Stub - Generates stub call handler for DCOM (server-side)
Parse::Pidl::Samba::COM::Header - Generates header file for COM interface(s)
-- Ethereal --
Parse::Pidl::Ethereal::NDR - Generates a parser for the ethereal network sniffer
Parse::Pidl::Ethereal::Conformance - Reads conformance files containing additional data for generating Ethereal 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

View File

@ -0,0 +1,14 @@
This tree is a convenience copy of
svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/pidl
to allow building Ethereal pidl dissectors without having to
access a remove svn repository.
Don't do changes here, do them at the samba tree!
In order to build, install yapp (on Suse, the rpm is named perl-Parse-Yapp),
then do
make Makefile.PL && make
run
blib/pidl --eth-parser -- <idl-file>

12
tools/pidl/TODO Normal file
View File

@ -0,0 +1,12 @@
- True multiple dimension array / strings in arrays support
- compatibility mode for generating MIDL-readable data:
- strip out pidl-specific properties
- convert subcontext() to an array of uint8.
- perhaps replace subcontext() with something more generic? The argument
to subcontext() isn't really intuitive at the moment
- don't be so strict on array boundaries.. arrays can and will be empty when
a (regular) remote error occurs
- support nested elements

437
tools/pidl/idl.yp Normal file
View File

@ -0,0 +1,437 @@
########################
# 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] }
;
coclass: property_list 'coclass' identifier '{' interface_names '}' optional_semicolon
{$_[3] => {
"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
{$_[3] => {
"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 identifier '=' anytext ';'
{{
"TYPE" => "CONST",
"DTYPE" => $_[2],
"NAME" => $_[3],
"VALUE" => $_[5],
"FILE" => $_[0]->YYData->{INPUT_FILENAME},
"LINE" => $_[0]->YYData->{LINE},
}}
| 'const' identifier identifier array_len '=' anytext ';'
{{
"TYPE" => "CONST",
"DTYPE" => $_[2],
"NAME" => $_[3],
"ARRAY_LEN" => $_[4],
"VALUE" => $_[6],
"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_enum: 'enum'
{{
"TYPE" => "ENUM"
}}
;
decl_bitmap: 'bitmap'
{{
"TYPE" => "BITMAP"
}}
;
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},
}}
;
usertype: struct | union | enum | bitmap;
typedecl: usertype ';' { $_[1] };
type: usertype | identifier
| void { "void" }
;
enum: 'enum' optional_identifier '{' enum_elements '}'
{{
"TYPE" => "ENUM",
"NAME" => $_[2],
"ELEMENTS" => $_[4]
}}
;
enum_elements:
enum_element { [ $_[1] ] }
| enum_elements ',' enum_element { push(@{$_[1]}, $_[3]); $_[1] }
;
enum_element: identifier
| identifier '=' anytext { "$_[1]$_[2]$_[3]" }
;
bitmap: 'bitmap' optional_identifier '{' bitmap_elements '}'
{{
"TYPE" => "BITMAP",
"NAME" => $_[2],
"ELEMENTS" => $_[4]
}}
;
bitmap_elements:
bitmap_element { [ $_[1] ] }
| bitmap_elements ',' bitmap_element { push(@{$_[1]}, $_[3]); $_[1] }
;
bitmap_element: identifier '=' anytext { "$_[1] ( $_[3] )" }
;
struct: 'struct' optional_identifier '{' element_list1 '}'
{{
"TYPE" => "STRUCT",
"NAME" => $_[2],
"ELEMENTS" => $_[4]
}}
;
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} = Parse::Pidl::Util::FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] }
;
union_elements:
#empty
| union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
;
union: 'union' optional_identifier '{' union_elements '}'
{{
"TYPE" => "UNION",
"NAME" => $_[2],
"ELEMENTS" => $_[4]
}}
;
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 ']' { Parse::Pidl::Util::FlattenHash([$_[1],$_[3]]); }
;
properties: property { $_[1] }
| properties ',' property { Parse::Pidl::Util::FlattenHash([$_[1], $_[3]]); }
;
property: identifier {{ "$_[1]" => "1" }}
| identifier '(' listtext ')' {{ "$_[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
%%
use Parse::Pidl::Util;
#####################################################################
# 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 =~
/^(coclass|interface|const|typedef|declare|union
|struct|enum|bitmap|void)$/x) {
return $1;
}
return('IDENTIFIER',$1);
}
if (s/^(.)//s) {
$parser->YYData->{LAST_TOKEN} = $1;
return($1,$1);
}
}
}
sub parse_idl($$)
{
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);
}

View File

@ -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.01';
1;

View File

@ -0,0 +1,203 @@
###################################################
# 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;
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"],
);
my($res);
sub warning($$)
{
my $l = shift;
my $m = shift;
print "$l->{FILE}:$l->{LINE}:Warning:$m\n";
}
sub error($$)
{
my ($l,$m) = @_;
print "$l->{FILE}:$l->{LINE}:$m\n";
}
sub CheckTypedef($)
{
my $td = shift;
if (has_property($td, "nodiscriminant")) {
error($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")) {
error($e, "noheader property not supported");
return;
}
if (has_property($e, "subcontext")) {
warning($e, "converting subcontext to byte array");
#FIXME
}
if (has_property($e, "compression")) {
error($e, "compression() property not supported");
}
if (has_property($e, "obfuscation")) {
error($e, "obfuscation() property not supported");
}
if (has_property($e, "sptr")) {
error($e, "sptr() pointer property not supported");
}
if (has_property($e, "relative")) {
error($e, "relative() pointer property not supported");
}
if (has_property($td, "flag")) {
warning($e, "ignoring flag() property");
}
if (has_property($td, "value")) {
warning($e, "ignoring value() property");
}
StripProperties($e);
}
sub CheckFunction($)
{
my $fn = shift;
if (has_property($fn, "noopnum")) {
error($fn, "noopnum not converted. Opcodes will be out of sync.");
}
StripProperties($fn);
}
sub CheckInterface($)
{
my $if = shift;
if (has_property($if, "pointer_default_top") and
$if->{PROPERTIES}->{pointer_default_top} ne "ref") {
error($if, "pointer_default_top() is pidl-specific");
}
StripProperties($if);
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 = [];
my $res = "";
foreach my $x (@{$pidl}) {
push (@$nidl, CheckInterface($x))
if ($x->{TYPE} eq "INTERFACE");
}
return $res;
}
1;

View File

@ -0,0 +1,277 @@
###################################################
# dump function for IDL structures
# Copyright tridge@samba.org 2000
# released under the GNU GPL
package Parse::Pidl::Dump;
use Exporter;
@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 my $e (@{$struct->{ELEMENTS}}) {
$res .= "\t" . DumpElement($e);
$res .= ";\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;

View File

@ -0,0 +1,251 @@
###################################################
# parse an ethereal conformance file
# Copyright jelmer@samba.org 2005
# released under the GNU GPL
package Parse::Pidl::Ethereal::Conformance;
require Exporter;
@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_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) = @_;
my $type;
$type = shift if ($#_ == 1);
if (defined($type)) {
$data->{noemit}->{$type} = 1;
} else {
$data->{noemit_dissector} = 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,
PARAM_VALUE => \&handle_param_value,
HF_FIELD => \&handle_hf_field,
HF_RENAME => \&handle_hf_rename,
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;

View File

@ -0,0 +1,956 @@
##################################################
# Samba4 NDR parser generator for IDL structures
# Copyright tridge@samba.org 2000-2003
# Copyright tpot@samba.org 2001,2005
# Copyright jelmer@samba.org 2004-2005
# Portions based on idl2eth.c by Ronnie Sahlberg
# released under the GNU GPL
package Parse::Pidl::Ethereal::NDR;
use strict;
use Parse::Pidl::Typelist;
use Parse::Pidl::Util qw(has_property ParseExpr property_matches make_str);
use Parse::Pidl::NDR;
use Parse::Pidl::Dump qw(DumpTypedef DumpFunction);
use Parse::Pidl::Ethereal::Conformance qw(ReadConformance);
my @ett;
my %hf_used = ();
my %dissector_used = ();
my $conformance = undef;
my %ptrtype_mappings = (
"unique" => "NDR_POINTER_UNIQUE",
"ref" => "NDR_POINTER_REF",
"ptr" => "NDR_POINTER_PTR"
);
sub type2ft($)
{
my($t) = shift;
return "FT_UINT$1" if $t =~ /uint(8|16|32|64)/;
return "FT_INT$1" if $t =~ /int(8|16|32|64)/;
return "FT_UINT64", if $t eq "HYPER_T" or $t eq "NTTIME_hyper"
or $t eq "hyper";
# TODO: should NTTIME_hyper be a FT_ABSOLUTE_TIME as well?
return "FT_ABSOLUTE_TIME" if $t eq "NTTIME" or $t eq "NTTIME_1sec";
return "FT_STRING" if ($t eq "string");
return "FT_NONE";
}
sub StripPrefixes($)
{
my ($s) = @_;
foreach (@{$conformance->{strip_prefixes}}) {
$s =~ s/^$_\_//g;
}
return $s;
}
# Convert a IDL structure field name (e.g access_mask) to a prettier
# string like 'Access Mask'.
sub field2name($)
{
my($field) = shift;
$field =~ s/_/ /g; # Replace underscores with spaces
$field =~ s/(\w+)/\u\L$1/g; # Capitalise each word
return $field;
}
my %res = ();
my $tabs = "";
sub pidl_code($)
{
my $d = shift;
if ($d) {
$res{code} .= $tabs;
$res{code} .= $d;
}
$res{code} .="\n";
}
sub pidl_hdr($) { my $x = shift; $res{hdr} .= "$x\n"; }
sub pidl_def($) { my $x = shift; $res{def} .= "$x\n"; }
sub indent()
{
$tabs .= "\t";
}
sub deindent()
{
$tabs = substr($tabs, 0, -1);
}
sub PrintIdl($)
{
my $idl = shift;
foreach (split /\n/, $idl) {
pidl_code "/* IDL: $_ */";
}
pidl_code "";
}
#####################################################################
# parse the interface definitions
sub Interface($)
{
my($interface) = @_;
Const($_,$interface->{NAME}) foreach (@{$interface->{CONSTS}});
Typedef($_,$interface->{NAME}) foreach (@{$interface->{TYPEDEFS}});
Function($_,$interface->{NAME}) foreach (@{$interface->{FUNCTIONS}});
}
sub Enum($$$)
{
my ($e,$name,$ifname) = @_;
my $valsstring = "$ifname\_$name\_vals";
my $dissectorname = "$ifname\_dissect\_enum\_".StripPrefixes($name);
return if (defined($conformance->{noemit}->{StripPrefixes($name)}));
foreach (@{$e->{ELEMENTS}}) {
if (/([^=]*)=(.*)/) {
pidl_hdr "#define $1 ($2)";
}
}
pidl_hdr "extern const value_string $valsstring\[];";
pidl_hdr "int $dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int hf_index, guint32 param);";
pidl_def "const value_string ".$valsstring."[] = {";
foreach (@{$e->{ELEMENTS}}) {
next unless (/([^=]*)=(.*)/);
pidl_def "\t{ $1, \"$1\" },";
}
pidl_def "{ 0, NULL }";
pidl_def "};";
pidl_code "int";
pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int hf_index, guint32 param _U_)";
pidl_code "{";
indent;
pidl_code "offset = dissect_ndr_$e->{BASE_TYPE}(tvb, offset, pinfo, tree, drep, hf_index, NULL);";
pidl_code "return offset;";
deindent;
pidl_code "}\n";
my $enum_size = $e->{BASE_TYPE};
$enum_size =~ s/uint//g;
register_type($name, "offset = $dissectorname(tvb, offset, pinfo, tree, drep, \@HF\@, \@PARAM\@);", type2ft($e->{BASE_TYPE}), "BASE_DEC", "0", "VALS($valsstring)", $enum_size / 8);
}
sub Bitmap($$$)
{
my ($e,$name,$ifname) = @_;
my $dissectorname = "$ifname\_dissect\_bitmap\_".StripPrefixes($name);
register_ett("ett_$ifname\_$name");
pidl_hdr "int $dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int hf_index, guint32 param);";
pidl_code "int";
pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_)";
pidl_code "{";
indent;
pidl_code "proto_item *item = NULL;";
pidl_code "proto_tree *tree = NULL;";
pidl_code "";
pidl_code "g$e->{BASE_TYPE} flags;";
if ($e->{ALIGN} > 1) {
pidl_code "ALIGN_TO_$e->{ALIGN}_BYTES;";
}
pidl_code "";
pidl_code "if(parent_tree) {";
indent;
pidl_code "item = proto_tree_add_item(parent_tree, hf_index, tvb, offset, $e->{ALIGN}, TRUE);";
pidl_code "tree = proto_item_add_subtree(item,ett_$ifname\_$name);";
deindent;
pidl_code "}\n";
pidl_code "offset = dissect_ndr_$e->{BASE_TYPE}(tvb, offset, pinfo, NULL, drep, -1, &flags);";
pidl_code "proto_item_append_text(item, \": \");\n";
pidl_code "if (!flags)";
pidl_code "\tproto_item_append_text(item, \"(No values set)\");\n";
foreach (@{$e->{ELEMENTS}}) {
next unless (/([^ ]*) (.*)/);
my ($en,$ev) = ($1,$2);
my $hf_bitname = "hf_$ifname\_$name\_$en";
my $filtername = "$ifname\.$name\.$en";
$hf_used{$hf_bitname} = 1;
register_hf_field($hf_bitname, field2name($en), $filtername, "FT_BOOLEAN", $e->{ALIGN} * 8, "TFS(&$name\_$en\_tfs)", $ev, "");
pidl_def "static const true_false_string $name\_$en\_tfs = {";
pidl_def " \"$en is SET\",";
pidl_def " \"$en is NOT SET\",";
pidl_def "};";
pidl_code "proto_tree_add_boolean(tree, $hf_bitname, tvb, offset-$e->{ALIGN}, $e->{ALIGN}, flags);";
pidl_code "if (flags&$ev){";
pidl_code "\tproto_item_append_text(item, \"$en\");";
pidl_code "\tif (flags & (~$ev))";
pidl_code "\t\tproto_item_append_text(item, \", \");";
pidl_code "}";
pidl_code "flags&=(~$ev);";
pidl_code "";
}
pidl_code "if(flags){";
pidl_code "\tproto_item_append_text(item, \"Unknown bitmap value 0x%x\", flags);";
pidl_code "}\n";
pidl_code "return offset;";
deindent;
pidl_code "}\n";
my $size = $e->{BASE_TYPE};
$size =~ s/uint//g;
register_type($name, "offset = $dissectorname(tvb, offset, pinfo, tree, drep, \@HF\@, \@PARAM\@);", type2ft($e->{BASE_TYPE}), "BASE_DEC", "0", "NULL", $size/8);
}
sub ElementLevel($$$$$)
{
my ($e,$l,$hf,$myname,$pn) = @_;
my $param = 0;
if (defined($conformance->{dissectorparams}->{$myname})) {
$conformance->{dissectorparams}->{$myname}->{PARAM} = 1;
$param = $conformance->{dissectorparams}->{$myname}->{PARAM};
}
if ($l->{TYPE} eq "POINTER") {
my $type;
if ($l->{LEVEL} eq "TOP") {
$type = "toplevel";
} elsif ($l->{LEVEL} eq "EMBEDDED") {
$type = "embedded";
}
pidl_code "offset = dissect_ndr_$type\_pointer(tvb, offset, pinfo, tree, drep, $myname\_, $ptrtype_mappings{$l->{POINTER_TYPE}}, \"Pointer to ".field2name(StripPrefixes($e->{NAME})) . " ($e->{TYPE})\",$hf);";
} elsif ($l->{TYPE} eq "ARRAY") {
if ($l->{IS_INLINE}) {
warn ("Inline arrays not supported");
pidl_code "/* FIXME: Handle inline array */";
} elsif ($l->{IS_FIXED}) {
pidl_code "int i;";
pidl_code "for (i = 0; i < $l->{SIZE_IS}; i++)";
pidl_code "\toffset = $myname\_(tvb, offset, pinfo, tree, drep);";
} else {
my $af = "";
($af = "ucarray") if ($l->{IS_CONFORMANT});
($af = "uvarray") if ($l->{IS_VARYING});
($af = "ucvarray") if ($l->{IS_CONFORMANT} and $l->{IS_VARYING});
pidl_code "offset = dissect_ndr_$af(tvb, offset, pinfo, tree, drep, $myname\_);";
}
} elsif ($l->{TYPE} eq "DATA") {
if ($l->{DATA_TYPE} eq "string") {
my $bs = 2; # Byte size defaults to that of UCS2
($bs = 1) if (property_matches($e, "flag", ".*LIBNDR_FLAG_STR_ASCII.*"));
if (property_matches($e, "flag", ".*LIBNDR_FLAG_STR_SIZE4.*") and property_matches($e, "flag", ".*LIBNDR_FLAG_STR_LEN4.*")) {
pidl_code "char *data;\n";
pidl_code "offset = dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep, $bs, $hf, FALSE, &data);";
pidl_code "proto_item_append_text(tree, \": %s\", data);";
} elsif (property_matches($e, "flag", ".*LIBNDR_FLAG_STR_SIZE4.*")) {
pidl_code "offset = dissect_ndr_vstring(tvb, offset, pinfo, tree, drep, $bs, $hf, FALSE, NULL);";
} else {
warn("Unable to handle string with flags $e->{PROPERTIES}->{flag}");
}
} else {
my $call;
if ($conformance->{imports}->{$l->{DATA_TYPE}}) {
$call = $conformance->{imports}->{$l->{DATA_TYPE}}->{DATA};
$conformance->{imports}->{$l->{DATA_TYPE}}->{USED} = 1;
} elsif (defined($conformance->{types}->{$l->{DATA_TYPE}})) {
$call= $conformance->{types}->{$l->{DATA_TYPE}}->{DISSECTOR_NAME};
$conformance->{types}->{$l->{DATA_TYPE}}->{USED} = 1;
} else {
if ($l->{DATA_TYPE} =~ /^([a-z]+)\_(.*)$/)
{
pidl_code "offset = $1_dissect_struct_$2(tvb,offset,pinfo,tree,drep,$hf,$param);";
}
return;
}
$call =~ s/\@HF\@/$hf/g;
$call =~ s/\@PARAM\@/$param/g;
pidl_code "$call";
}
} elsif ($_->{TYPE} eq "SUBCONTEXT") {
my $num_bits = ($l->{HEADER_SIZE}*8);
pidl_code "guint$num_bits size;";
pidl_code "int start_offset = offset;";
pidl_code "tvbuff_t *subtvb;";
pidl_code "offset = dissect_ndr_uint$num_bits(tvb, offset, pinfo, tree, drep, $hf, &size);";
pidl_code "proto_tree_add_text(tree, tvb, start_offset, offset - start_offset + size, \"Subcontext size\");";
pidl_code "subtvb = tvb_new_subset(tvb, offset, size, -1);";
pidl_code "$myname\_(subtvb, 0, pinfo, tree, drep);";
} else {
die("Unknown type `$_->{TYPE}'");
}
}
sub Element($$$)
{
my ($e,$pn,$ifname) = @_;
my $dissectorname = "$ifname\_dissect\_element\_".StripPrefixes($pn)."\_".StripPrefixes($e->{NAME});
my $call_code = "offset = $dissectorname(tvb, offset, pinfo, tree, drep);";
my $hf = register_hf_field("hf_$ifname\_$pn\_$e->{NAME}", field2name($e->{NAME}), "$ifname.$pn.$e->{NAME}", type2ft($e->{TYPE}), "BASE_HEX", "NULL", 0, "");
$hf_used{$hf} = 1;
my $eltname = StripPrefixes($pn) . ".$e->{NAME}";
if (defined($conformance->{noemit}->{$eltname})) {
return $call_code;
}
my $add = "";
foreach (@{$e->{LEVELS}}) {
next if ($_->{TYPE} eq "SWITCH");
pidl_def "static int $dissectorname$add(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep);";
pidl_code "static int";
pidl_code "$dissectorname$add(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)";
pidl_code "{";
indent;
ElementLevel($e,$_,$hf,$dissectorname.$add,$pn);
pidl_code "";
pidl_code "return offset;";
deindent;
pidl_code "}\n";
$add.="_";
}
return $call_code;
}
sub Function($$$)
{
my ($fn,$ifname) = @_;
my %dissectornames;
foreach (@{$fn->{ELEMENTS}}) {
$dissectornames{$_->{NAME}} = Element($_, $fn->{NAME}, $ifname) if not defined($dissectornames{$_->{NAME}});
}
my $fn_name = $_->{NAME};
$fn_name =~ s/^${ifname}_//;
PrintIdl DumpFunction($fn->{ORIGINAL});
pidl_code "static int";
pidl_code "$ifname\_dissect\_${fn_name}_response(tvbuff_t *tvb _U_, int offset _U_, packet_info *pinfo _U_, proto_tree *tree _U_, guint8 *drep _U_)";
pidl_code "{";
indent;
foreach (@{$fn->{ELEMENTS}}) {
if (grep(/out/,@{$_->{DIRECTION}})) {
pidl_code "$dissectornames{$_->{NAME}}";
pidl_code "offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);";
pidl_code "";
}
}
if (not defined($fn->{RETURN_TYPE})) {
} elsif ($fn->{RETURN_TYPE} eq "NTSTATUS") {
pidl_code "offset = dissect_ntstatus(tvb, offset, pinfo, tree, drep, hf\_$ifname\_status, NULL);";
$hf_used{"hf\_$ifname\_status"} = 1;
} elsif ($fn->{RETURN_TYPE} eq "WERROR") {
pidl_code "offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf\_$ifname\_werror, NULL);";
$hf_used{"hf\_$ifname\_werror"} = 1;
} else {
print "$fn->{FILE}:$fn->{LINE}: error: return type `$fn->{RETURN_TYPE}' not yet supported\n";
}
pidl_code "return offset;";
deindent;
pidl_code "}\n";
pidl_code "static int";
pidl_code "$ifname\_dissect\_${fn_name}_request(tvbuff_t *tvb _U_, int offset _U_, packet_info *pinfo _U_, proto_tree *tree _U_, guint8 *drep _U_)";
pidl_code "{";
indent;
foreach (@{$fn->{ELEMENTS}}) {
if (grep(/in/,@{$_->{DIRECTION}})) {
pidl_code "$dissectornames{$_->{NAME}}";
pidl_code "offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);";
}
}
pidl_code "return offset;";
deindent;
pidl_code "}\n";
}
sub Struct($$$)
{
my ($e,$name,$ifname) = @_;
my $dissectorname = "$ifname\_dissect\_struct\_".StripPrefixes($name);
return if (defined($conformance->{noemit}->{StripPrefixes($name)}));
register_ett("ett_$ifname\_$name");
my $res = "";
($res.="\t".Element($_, $name, $ifname)."\n\n") foreach (@{$e->{ELEMENTS}});
pidl_hdr "int $dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_);";
pidl_code "int";
pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_)";
pidl_code "{";
indent;
pidl_code "proto_item *item = NULL;";
pidl_code "proto_tree *tree = NULL;";
pidl_code "int old_offset;";
pidl_code "";
if ($e->{ALIGN} > 1) {
pidl_code "ALIGN_TO_$e->{ALIGN}_BYTES;";
}
pidl_code "";
pidl_code "old_offset = offset;";
pidl_code "";
pidl_code "if(parent_tree){";
indent;
pidl_code "item = proto_tree_add_item(parent_tree, hf_index, tvb, offset, -1, TRUE);";
pidl_code "tree = proto_item_add_subtree(item, ett_$ifname\_$name);";
deindent;
pidl_code "}";
pidl_code "\n$res";
pidl_code "proto_item_set_len(item, offset-old_offset);\n";
pidl_code "return offset;";
deindent;
pidl_code "}\n";
register_type($name, "offset = $dissectorname(tvb,offset,pinfo,tree,drep,\@HF\@,\@PARAM\@);", "FT_NONE", "BASE_NONE", 0, "NULL", 0);
}
sub Union($$$)
{
my ($e,$name,$ifname) = @_;
my $dissectorname = "$ifname\_dissect_".StripPrefixes($name);
return if (defined($conformance->{noemit}->{StripPrefixes($name)}));
register_ett("ett_$ifname\_$name");
my $res = "";
foreach (@{$e->{ELEMENTS}}) {
$res.="\n\t\t$_->{CASE}:\n";
if ($_->{TYPE} ne "EMPTY") {
$res.="\t\t\t".Element($_, $name, $ifname)."\n";
}
$res.="\t\tbreak;\n";
}
pidl_code "static int";
pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_)";
pidl_code "{";
indent;
pidl_code "proto_item *item = NULL;";
pidl_code "proto_tree *tree = NULL;";
pidl_code "int old_offset;";
pidl_code "g$e->{SWITCH_TYPE} level;";
pidl_code "";
if ($e->{ALIGN} > 1) {
pidl_code "ALIGN_TO_$e->{ALIGN}_BYTES;";
}
pidl_code "";
pidl_code "old_offset = offset;";
pidl_code "if(parent_tree){";
indent;
pidl_code "item = proto_tree_add_text(parent_tree, tvb, offset, -1, \"$name\");";
pidl_code "tree = proto_item_add_subtree(item, ett_$ifname\_$name);";
deindent;
pidl_code "}";
pidl_code "";
pidl_code "offset = dissect_ndr_$e->{SWITCH_TYPE}(tvb, offset, pinfo, tree, drep, hf_index, &level);";
pidl_code "switch(level) {$res\t}";
pidl_code "proto_item_set_len(item, offset-old_offset);\n";
pidl_code "return offset;";
deindent;
pidl_code "}";
register_type($name, "offset = $dissectorname(tvb, offset, pinfo, tree, drep, \@HF\@, \@PARAM\@);", "FT_NONE", "BASE_NONE", 0, "NULL", 0);
}
sub Const($$)
{
my ($const,$ifname) = @_;
if (!defined($const->{ARRAY_LEN}[0])) {
pidl_hdr "#define $const->{NAME}\t( $const->{VALUE} )\n";
} else {
pidl_hdr "#define $const->{NAME}\t $const->{VALUE}\n";
}
}
sub Typedef($$)
{
my ($e,$ifname) = @_;
PrintIdl DumpTypedef($e->{ORIGINAL});
{
ENUM => \&Enum,
STRUCT => \&Struct,
UNION => \&Union,
BITMAP => \&Bitmap
}->{$e->{DATA}->{TYPE}}->($e->{DATA}, $e->{NAME}, $ifname);
}
sub RegisterInterface($)
{
my ($x) = @_;
pidl_code "void proto_register_dcerpc_$x->{NAME}(void)";
pidl_code "{";
indent;
$res{code}.=DumpHfList()."\n";
$res{code}.="\n".DumpEttList()."\n";
if (defined($x->{UUID})) {
# These can be changed to non-pidl_code names if the old dissectors
# in epan/dissctors are deleted.
my $name = uc($x->{NAME}) . " (pidl)";
my $short_name = uc($x->{NAME});
my $filter_name = $x->{NAME};
if (has_property($x, "helpstring")) {
$name = $x->{PROPERTIES}->{helpstring};
}
if (defined($conformance->{protocols}->{$x->{NAME}})) {
$short_name = $conformance->{protocols}->{$x->{NAME}}->{SHORTNAME};
$name = $conformance->{protocols}->{$x->{NAME}}->{LONGNAME};
$filter_name = $conformance->{protocols}->{$x->{NAME}}->{FILTERNAME};
}
pidl_code "proto_dcerpc_$x->{NAME} = proto_register_protocol(".make_str($name).", ".make_str($short_name).", ".make_str($filter_name).");";
pidl_code "proto_register_field_array(proto_dcerpc_$x->{NAME}, hf, array_length (hf));";
pidl_code "proto_register_subtree_array(ett, array_length(ett));";
} else {
pidl_code "proto_dcerpc = proto_get_id_by_filter_name(\"dcerpc\");";
pidl_code "proto_register_field_array(proto_dcerpc, hf, array_length(hf));";
pidl_code "proto_register_subtree_array(ett, array_length(ett));";
}
deindent;
pidl_code "}\n";
}
sub RegisterInterfaceHandoff($)
{
my $x = shift;
if (defined($x->{UUID})) {
pidl_code "void proto_reg_handoff_dcerpc_$x->{NAME}(void)";
pidl_code "{";
indent;
pidl_code "dcerpc_init_uuid(proto_dcerpc_$x->{NAME}, ett_dcerpc_$x->{NAME},";
pidl_code "\t&uuid_dcerpc_$x->{NAME}, ver_dcerpc_$x->{NAME},";
pidl_code "\t$x->{NAME}_dissectors, hf_$x->{NAME}_opnum);";
deindent;
pidl_code "}";
$hf_used{"hf_$x->{NAME}_opnum"} = 1;
}
}
sub ProcessInterface($)
{
my ($x) = @_;
push(@{$conformance->{strip_prefixes}}, $x->{NAME});
my $define = "__PACKET_DCERPC_" . uc($_->{NAME}) . "_H";
pidl_hdr "#ifndef $define";
pidl_hdr "#define $define";
pidl_hdr "";
if (defined $x->{PROPERTIES}->{depends}) {
foreach (split / /, $x->{PROPERTIES}->{depends}) {
next if($_ eq "security");
pidl_hdr "#include \"packet-dcerpc-$_\.h\"\n";
}
}
pidl_def "static gint proto_dcerpc_$x->{NAME} = -1;";
register_ett("ett_dcerpc_$x->{NAME}");
register_hf_field("hf_$x->{NAME}_opnum", "Operation", "$x->{NAME}.opnum", "FT_UINT16", "BASE_DEC", "NULL", 0, "");
if (defined($x->{UUID})) {
my $if_uuid = $x->{UUID};
pidl_def "/* Version information */\n\n";
pidl_def "static e_uuid_t uuid_dcerpc_$x->{NAME} = {";
pidl_def "\t0x" . substr($if_uuid, 1, 8)
. ", 0x" . substr($if_uuid, 10, 4)
. ", 0x" . substr($if_uuid, 15, 4) . ",";
pidl_def "\t{ 0x" . substr($if_uuid, 20, 2)
. ", 0x" . substr($if_uuid, 22, 2)
. ", 0x" . substr($if_uuid, 25, 2)
. ", 0x" . substr($if_uuid, 27, 2)
. ", 0x" . substr($if_uuid, 29, 2)
. ", 0x" . substr($if_uuid, 31, 2)
. ", 0x" . substr($if_uuid, 33, 2)
. ", 0x" . substr($if_uuid, 35, 2) . " }";
pidl_def "};";
my $maj = $x->{VERSION};
$maj =~ s/\.(.*)$//g;
pidl_def "static guint16 ver_dcerpc_$x->{NAME} = $maj;";
pidl_def "";
}
Interface($x);
pidl_code "\n".DumpFunctionTable($x);
# Only register these two return types if they were actually used
if (defined($hf_used{"hf_$x->{NAME}_status"})) {
register_hf_field("hf_$x->{NAME}_status", "Status", "$x->{NAME}.status", "FT_UINT32", "BASE_HEX", "VALS(NT_errors)", 0, "");
}
if (defined($hf_used{"hf_$x->{NAME}_werror"})) {
register_hf_field("hf_$x->{NAME}_werror", "Windows Error", "$x->{NAME}.werror", "FT_UINT32", "BASE_HEX", "NULL", 0, "");
}
RegisterInterface($x);
RegisterInterfaceHandoff($x);
pidl_hdr "#endif /* $define */";
}
sub register_type($$$$$$$)
{
my ($type,$call,$ft,$base,$mask,$vals,$length) = @_;
$conformance->{types}->{$type} = {
NAME => $type,
DISSECTOR_NAME => $call,
FT_TYPE => $ft,
BASE_TYPE => $base,
MASK => $mask,
VALSSTRING => $vals,
ALIGNMENT => $length
};
}
# Loads the default types
sub Initialize($)
{
my $cnf_file = shift;
$conformance = {
imports => {},
header_fields=> {}
};
ReadConformance($cnf_file, $conformance) or print "Warning: No conformance file `$cnf_file'\n";
foreach my $bytes (qw(1 2 4 8)) {
my $bits = $bytes * 8;
register_type("uint$bits", "offset = dissect_ndr_uint$bits(tvb, offset, pinfo, tree, drep, \@HF\@,NULL);", "FT_UINT$bits", "BASE_DEC", 0, "NULL", $bytes);
register_type("int$bits", "offset = dissect_ndr_uint$bits(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);", "FT_INT$bits", "BASE_DEC", 0, "NULL", $bytes);
}
register_type("udlong", "offset = dissect_ndr_duint32(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);", "FT_UINT64", "BASE_DEC", 0, "NULL", 4);
register_type("bool8", "offset = dissect_ndr_uint8(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_INT8", "BASE_DEC", 0, "NULL", 1);
register_type("char", "offset = dissect_ndr_uint8(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_INT8", "BASE_DEC", 0, "NULL", 1);
register_type("long", "offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_INT32", "BASE_DEC", 0, "NULL", 4);
register_type("dlong", "offset = dissect_ndr_duint32(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_INT64", "BASE_DEC", 0, "NULL", 8);
register_type("GUID", "offset = dissect_ndr_uuid_t(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_GUID", "BASE_NONE", 0, "NULL", 4);
register_type("policy_handle", "offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep, \@HF\@, NULL, NULL, \@PARAM\@&0x01, \@PARAM\@&0x02);","FT_BYTES", "BASE_NONE", 0, "NULL", 4);
register_type("NTTIME", "offset = dissect_ndr_nt_NTTIME(tvb, offset, pinfo, tree, drep, \@HF\@);","FT_ABSOLUTE_TIME", "BASE_NONE", 0, "NULL", 4);
register_type("NTTIME_hyper", "offset = dissect_ndr_nt_NTTIME(tvb, offset, pinfo, tree, drep, \@HF\@);","FT_ABSOLUTE_TIME", "BASE_NONE", 0, "NULL", 4);
register_type("time_t", "offset = dissect_ndr_time_t(tvb, offset, pinfo,tree, drep, \@HF\@, NULL);","FT_ABSOLUTE_TIME", "BASE_DEC", 0, "NULL", 4);
register_type("NTTIME_1sec", "offset = dissect_ndr_nt_NTTIME(tvb, offset, pinfo, tree, drep, \@HF\@);", "FT_ABSOLUTE_TIME", "BASE_NONE", 0, "NULL", 4);
register_type("SID", "
dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
di->hf_index = \@HF\@;
offset = dissect_ndr_nt_SID_with_options(tvb, offset, pinfo, tree, drep, param);
","FT_STRING", "BASE_DEC", 0, "NULL", 4);
register_type("WERROR",
"offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_UINT32", "BASE_DEC", 0, "VALS(NT_errors)", 4);
}
#####################################################################
# Generate ethereal parser and header code
sub Parse($$$$)
{
my($ndr,$idl_file,$h_filename,$cnf_file) = @_;
Initialize($cnf_file);
return (undef, undef) if defined($conformance->{noemit_dissector});
$tabs = "";
%res = (code=>"",def=>"",hdr=>"");
@ett = ();
my $notice =
"/* DO NOT EDIT
This filter was automatically generated
from $idl_file and $cnf_file.
Pidl is a perl based IDL compiler for DCE/RPC idl files.
It is maintained by the Samba team, not the Ethereal team.
Instructions on how to download and install Pidl can be
found at http://wiki.ethereal.com/Pidl
*/
";
pidl_hdr $notice;
$res{headers} = "\n";
$res{headers} .= "#ifdef HAVE_CONFIG_H\n";
$res{headers} .= "#include \"config.h\"\n";
$res{headers} .= "#endif\n\n";
$res{headers} .= "#include <glib.h>\n";
$res{headers} .= "#include <string.h>\n";
$res{headers} .= "#include <epan/packet.h>\n\n";
$res{headers} .= "#include \"packet-dcerpc.h\"\n";
$res{headers} .= "#include \"packet-dcerpc-nt.h\"\n";
$res{headers} .= "#include \"packet-windows-common.h\"\n";
use File::Basename;
my $h_basename = basename($h_filename);
$res{headers} .= "#include \"$h_basename\"\n";
pidl_code "";
# Ethereal protocol registration
ProcessInterface($_) foreach (@$ndr);
$res{ett} = DumpEttDeclaration();
$res{hf} = DumpHfDeclaration();
my $parser = $notice;
$parser.= $res{headers};
$parser.=$res{ett};
$parser.=$res{hf};
$parser.=$res{def};
$parser.=$conformance->{override};
$parser.=$res{code};
my $header = "/* autogenerated by pidl */\n\n";
$header.=$res{hdr};
CheckUsed($conformance);
return ($parser,$header);
}
###############################################################################
# ETT
###############################################################################
sub register_ett($)
{
my $name = shift;
push (@ett, $name);
}
sub DumpEttList()
{
my $res = "\tstatic gint *ett[] = {\n";
foreach (@ett) {
$res .= "\t\t&$_,\n";
}
return "$res\t};\n";
}
sub DumpEttDeclaration()
{
my $res = "\n/* Ett declarations */\n";
foreach (@ett) {
$res .= "static gint $_ = -1;\n";
}
return "$res\n";
}
###############################################################################
# HF
###############################################################################
sub register_hf_field($$$$$$$$)
{
my ($index,$name,$filter_name,$ft_type,$base_type,$valsstring,$mask,$blurb) = @_;
if (defined ($conformance->{hf_renames}->{$index})) {
$conformance->{hf_renames}->{$index}->{USED} = 1;
return $conformance->{hf_renames}->{$index}->{NEWNAME};
}
$conformance->{header_fields}->{$index} = {
INDEX => $index,
NAME => $name,
FILTER => $filter_name,
FT_TYPE => $ft_type,
BASE_TYPE => $base_type,
VALSSTRING => $valsstring,
MASK => $mask,
BLURB => $blurb
};
if ((not defined($blurb) or $blurb eq "") and
defined($conformance->{fielddescription}->{$index})) {
$conformance->{header_fields}->{$index}->{BLURB} =
$conformance->{fielddescription}->{$index}->{DESCRIPTION};
$conformance->{fielddescription}->{$index}->{USED} = 1;
}
return $index;
}
sub DumpHfDeclaration()
{
my $res = "";
$res = "\n/* Header field declarations */\n";
foreach (keys %{$conformance->{header_fields}})
{
$res .= "static gint $_ = -1;\n";
}
return "$res\n";
}
sub DumpHfList()
{
my $res = "\tstatic hf_register_info hf[] = {\n";
foreach (values %{$conformance->{header_fields}})
{
$res .= "\t{ &$_->{INDEX},
{ ".make_str($_->{NAME}).", ".make_str($_->{FILTER}).", $_->{FT_TYPE}, $_->{BASE_TYPE}, $_->{VALSSTRING}, $_->{MASK}, ".make_str($_->{BLURB}).", HFILL }},
";
}
return $res."\t};\n";
}
###############################################################################
# Function table
###############################################################################
sub DumpFunctionTable($)
{
my $if = shift;
my $res = "static dcerpc_sub_dissector $if->{NAME}\_dissectors[] = {\n";
foreach (@{$if->{FUNCTIONS}}) {
my $fn_name = $_->{NAME};
$fn_name =~ s/^$if->{NAME}_//;
$res.= "\t{ $_->{OPNUM}, \"$fn_name\",\n";
$res.= "\t $if->{NAME}_dissect_${fn_name}_request, $if->{NAME}_dissect_${fn_name}_response},\n";
}
$res .= "\t{ 0, NULL, NULL, NULL }\n";
return "$res};\n";
}
sub CheckUsed($)
{
my $conformance = shift;
foreach (values %{$conformance->{header_fields}}) {
if (not defined($hf_used{$_->{INDEX}})) {
print "$_->{POS}: warning: hf field `$_->{INDEX}' not used\n";
}
}
foreach (values %{$conformance->{hf_renames}}) {
if (not $_->{USED}) {
print "$_->{POS}: warning: hf field `$_->{OLDNAME}' not used\n";
}
}
foreach (values %{$conformance->{dissectorparams}}) {
if (not $_->{USED}) {
print "$_->{POS}: warning: dissector param never used\n";
}
}
foreach (values %{$conformance->{imports}}) {
if (not $_->{USED}) {
print "$_->{POS}: warning: import never used\n";
}
}
foreach (values %{$conformance->{types}}) {
if (not $_->{USED} and defined($_->{POS})) {
print "$_->{POS}: warning: type never used\n";
}
}
foreach (values %{$conformance->{fielddescription}}) {
if (not $_->{USED}) {
print "$_->{POS}: warning: description never used\n";
}
}
}
1;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,967 @@
###################################################
# Samba4 NDR info tree generator
# Copyright tridge@samba.org 2000-2003
# Copyright tpot@samba.org 2001
# Copyright jelmer@samba.org 2004-2005
# released under the GNU GPL
package Parse::Pidl::NDR;
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(GetPrevLevel GetNextLevel ContainsDeferred);
use strict;
use Parse::Pidl::Typelist qw(hasType getType);
use Parse::Pidl::Util qw(has_property property_matches);
sub nonfatal($$)
{
my ($e,$s) = @_;
warn ("$e->{FILE}:$e->{LINE}: Warning: $s\n");
}
#####################################################################
# signal a fatal validation error
sub fatal($$)
{
my ($pos,$s) = @_;
die("$pos->{FILE}:$pos->{LINE}:$s\n");
}
#####################################################################
# return a table describing the order in which the parts of an element
# should be parsed
# Possible level types:
# - POINTER
# - ARRAY
# - SUBCONTEXT
# - SWITCH
# - DATA
sub GetElementLevelTable($)
{
my $e = shift;
my $order = [];
my $is_deferred = 0;
my @bracket_array = ();
my @length_is = ();
my @size_is = ();
if (has_property($e, "size_is")) {
@size_is = split /,/, has_property($e, "size_is");
}
if (has_property($e, "length_is")) {
@length_is = split /,/, has_property($e, "length_is");
}
if (defined($e->{ARRAY_LEN})) {
@bracket_array = @{$e->{ARRAY_LEN}};
}
# Parse the [][][][] style array stuff
foreach my $d (@bracket_array) {
my $size = $d;
my $length = $d;
my $is_surrounding = 0;
my $is_varying = 0;
my $is_conformant = 0;
my $is_string = 0;
if ($d eq "*") {
$is_conformant = 1;
if ($size = shift @size_is) {
} elsif ((scalar(@size_is) == 0) and has_property($e, "string")) {
$is_string = 1;
delete($e->{PROPERTIES}->{string});
} else {
print "$e->{FILE}:$e->{LINE}: Must specify size_is() for conformant array!\n";
exit 1;
}
if (($length = shift @length_is) or $is_string) {
$is_varying = 1;
} else {
$length = $size;
}
if ($e == $e->{PARENT}->{ELEMENTS}[-1]
and $e->{PARENT}->{TYPE} ne "FUNCTION") {
$is_surrounding = 1;
}
}
push (@$order, {
TYPE => "ARRAY",
SIZE_IS => $size,
LENGTH_IS => $length,
IS_DEFERRED => "$is_deferred",
IS_SURROUNDING => "$is_surrounding",
IS_ZERO_TERMINATED => "$is_string",
IS_VARYING => "$is_varying",
IS_CONFORMANT => "$is_conformant",
IS_FIXED => (not $is_conformant and Parse::Pidl::Util::is_constant($size)),
IS_INLINE => (not $is_conformant and not Parse::Pidl::Util::is_constant($size))
});
}
# Next, all the pointers
foreach my $i (1..$e->{POINTERS}) {
my $pt = pointer_type($e);
my $level = "EMBEDDED";
# Top level "ref" pointers do not have a referrent identifier
$level = "TOP" if ( defined($pt)
and $i == 1
and $e->{PARENT}->{TYPE} eq "FUNCTION");
push (@$order, {
TYPE => "POINTER",
# for now, there can only be one pointer type per element
POINTER_TYPE => pointer_type($e),
IS_DEFERRED => "$is_deferred",
LEVEL => $level
});
# everything that follows will be deferred
$is_deferred = 1 if ($e->{PARENT}->{TYPE} ne "FUNCTION");
my $array_size = shift @size_is;
my $array_length;
my $is_varying;
my $is_conformant;
my $is_string = 0;
if ($array_size) {
$is_conformant = 1;
if ($array_length = shift @length_is) {
$is_varying = 1;
} else {
$array_length = $array_size;
$is_varying =0;
}
}
if (scalar(@size_is) == 0 and has_property($e, "string")) {
$is_string = 1;
$is_varying = $is_conformant = has_property($e, "noheader")?0:1;
delete($e->{PROPERTIES}->{string});
}
if ($array_size or $is_string) {
push (@$order, {
TYPE => "ARRAY",
IS_ZERO_TERMINATED => "$is_string",
SIZE_IS => $array_size,
LENGTH_IS => $array_length,
IS_DEFERRED => "$is_deferred",
IS_SURROUNDING => 0,
IS_VARYING => "$is_varying",
IS_CONFORMANT => "$is_conformant",
IS_FIXED => 0,
IS_INLINE => 0,
});
$is_deferred = 0;
}
}
if (defined(has_property($e, "subcontext"))) {
my $hdr_size = has_property($e, "subcontext");
my $subsize = has_property($e, "subcontext_size");
if (not defined($subsize)) {
$subsize = -1;
}
push (@$order, {
TYPE => "SUBCONTEXT",
HEADER_SIZE => $hdr_size,
SUBCONTEXT_SIZE => $subsize,
IS_DEFERRED => $is_deferred,
COMPRESSION => has_property($e, "compression"),
OBFUSCATION => has_property($e, "obfuscation")
});
}
if (my $switch = has_property($e, "switch_is")) {
push (@$order, {
TYPE => "SWITCH",
SWITCH_IS => $switch,
IS_DEFERRED => $is_deferred
});
}
if (scalar(@size_is) > 0) {
nonfatal($e, "size_is() on non-array element");
}
if (scalar(@length_is) > 0) {
nonfatal($e, "length_is() on non-array element");
}
if (has_property($e, "string")) {
nonfatal($e, "string() attribute on non-array element");
}
push (@$order, {
TYPE => "DATA",
DATA_TYPE => $e->{TYPE},
IS_DEFERRED => $is_deferred,
CONTAINS_DEFERRED => can_contain_deferred($e),
IS_SURROUNDING => 0 #FIXME
});
my $i = 0;
foreach (@$order) { $_->{LEVEL_INDEX} = $i; $i+=1; }
return $order;
}
#####################################################################
# see if a type contains any deferred data
sub can_contain_deferred
{
my $e = shift;
return 0 if (Parse::Pidl::Typelist::is_scalar($e->{TYPE}));
return 1 unless (hasType($e->{TYPE})); # assume the worst
my $type = getType($e->{TYPE});
foreach my $x (@{$type->{DATA}->{ELEMENTS}}) {
return 1 if ($x->{POINTERS});
return 1 if (can_contain_deferred ($x));
}
return 0;
}
sub pointer_type($)
{
my $e = shift;
return undef unless $e->{POINTERS};
return "ref" if (has_property($e, "ref"));
return "ptr" if (has_property($e, "ptr"));
return "sptr" if (has_property($e, "sptr"));
return "unique" if (has_property($e, "unique"));
return "relative" if (has_property($e, "relative"));
return "ignore" if (has_property($e, "ignore"));
return undef;
}
#####################################################################
# work out the correct alignment for a structure or union
sub find_largest_alignment($)
{
my $s = shift;
my $align = 1;
for my $e (@{$s->{ELEMENTS}}) {
my $a = 1;
if ($e->{POINTERS}) {
$a = 4;
} elsif (has_property($e, "subcontext")){
$a = 1;
} else {
$a = align_type($e->{TYPE});
}
$align = $a if ($align < $a);
}
return $align;
}
#####################################################################
# align a type
sub align_type
{
my $e = shift;
unless (hasType($e)) {
# it must be an external type - all we can do is guess
# print "Warning: assuming alignment of unknown type '$e' is 4\n";
return 4;
}
my $dt = getType($e)->{DATA};
if ($dt->{TYPE} eq "ENUM") {
return align_type(Parse::Pidl::Typelist::enum_type_fn($dt));
} elsif ($dt->{TYPE} eq "BITMAP") {
return align_type(Parse::Pidl::Typelist::bitmap_type_fn($dt));
} elsif (($dt->{TYPE} eq "STRUCT") or ($dt->{TYPE} eq "UNION")) {
return find_largest_alignment($dt);
} elsif ($dt->{TYPE} eq "SCALAR") {
return Parse::Pidl::Typelist::getScalarAlignment($dt->{NAME});
}
die("Unknown data type type $dt->{TYPE}");
}
sub ParseElement($)
{
my $e = shift;
return {
NAME => $e->{NAME},
TYPE => $e->{TYPE},
PROPERTIES => $e->{PROPERTIES},
LEVELS => GetElementLevelTable($e),
ALIGN => align_type($e->{TYPE}),
ORIGINAL => $e
};
}
sub ParseStruct($)
{
my $struct = shift;
my @elements = ();
my $surrounding = undef;
foreach my $x (@{$struct->{ELEMENTS}})
{
push @elements, ParseElement($x);
}
my $e = $elements[-1];
if (defined($e) and defined($e->{LEVELS}[0]->{IS_SURROUNDING}) and
$e->{LEVELS}[0]->{IS_SURROUNDING}) {
$surrounding = $e;
}
if (defined $e->{TYPE} && $e->{TYPE} eq "string"
&& property_matches($e, "flag", ".*LIBNDR_FLAG_STR_CONFORMANT.*")) {
$surrounding = $struct->{ELEMENTS}[-1];
}
return {
TYPE => "STRUCT",
SURROUNDING_ELEMENT => $surrounding,
ELEMENTS => \@elements,
PROPERTIES => $struct->{PROPERTIES},
ORIGINAL => $struct
};
}
sub ParseUnion($)
{
my $e = shift;
my @elements = ();
my $switch_type = has_property($e, "switch_type");
unless (defined($switch_type)) { $switch_type = "uint32"; }
if (has_property($e, "nodiscriminant")) { $switch_type = undef; }
foreach my $x (@{$e->{ELEMENTS}})
{
my $t;
if ($x->{TYPE} eq "EMPTY") {
$t = { TYPE => "EMPTY" };
} else {
$t = ParseElement($x);
}
if (has_property($x, "default")) {
$t->{CASE} = "default";
} elsif (defined($x->{PROPERTIES}->{case})) {
$t->{CASE} = "case $x->{PROPERTIES}->{case}";
} else {
die("Union element $x->{NAME} has neither default nor case property");
}
push @elements, $t;
}
return {
TYPE => "UNION",
SWITCH_TYPE => $switch_type,
ELEMENTS => \@elements,
PROPERTIES => $e->{PROPERTIES},
ORIGINAL => $e
};
}
sub ParseEnum($)
{
my $e = shift;
return {
TYPE => "ENUM",
BASE_TYPE => Parse::Pidl::Typelist::enum_type_fn($e),
ELEMENTS => $e->{ELEMENTS},
PROPERTIES => $e->{PROPERTIES},
ORIGINAL => $e
};
}
sub ParseBitmap($)
{
my $e = shift;
return {
TYPE => "BITMAP",
BASE_TYPE => Parse::Pidl::Typelist::bitmap_type_fn($e),
ELEMENTS => $e->{ELEMENTS},
PROPERTIES => $e->{PROPERTIES},
ORIGINAL => $e
};
}
sub ParseTypedef($$)
{
my ($ndr,$d) = @_;
my $data;
if ($d->{DATA}->{TYPE} eq "STRUCT" or $d->{DATA}->{TYPE} eq "UNION") {
CheckPointerTypes($d->{DATA}, $ndr->{PROPERTIES}->{pointer_default});
}
if (defined($d->{PROPERTIES}) && !defined($d->{DATA}->{PROPERTIES})) {
$d->{DATA}->{PROPERTIES} = $d->{PROPERTIES};
}
$data = {
STRUCT => \&ParseStruct,
UNION => \&ParseUnion,
ENUM => \&ParseEnum,
BITMAP => \&ParseBitmap
}->{$d->{DATA}->{TYPE}}->($d->{DATA});
$data->{ALIGN} = align_type($d->{NAME});
return {
NAME => $d->{NAME},
TYPE => $d->{TYPE},
PROPERTIES => $d->{PROPERTIES},
DATA => $data,
ORIGINAL => $d
};
}
sub ParseConst($$)
{
my ($ndr,$d) = @_;
return $d;
}
sub ParseFunction($$$)
{
my ($ndr,$d,$opnum) = @_;
my @elements = ();
my $rettype = undef;
my $thisopnum = undef;
CheckPointerTypes($d, $ndr->{PROPERTIES}->{pointer_default_top});
if (not defined($d->{PROPERTIES}{noopnum})) {
$thisopnum = ${$opnum};
${$opnum}++;
}
foreach my $x (@{$d->{ELEMENTS}}) {
my $e = ParseElement($x);
push (@{$e->{DIRECTION}}, "in") if (has_property($x, "in"));
push (@{$e->{DIRECTION}}, "out") if (has_property($x, "out"));
push (@elements, $e);
}
if ($d->{RETURN_TYPE} ne "void") {
$rettype = $d->{RETURN_TYPE};
}
return {
NAME => $d->{NAME},
TYPE => "FUNCTION",
OPNUM => $thisopnum,
RETURN_TYPE => $rettype,
PROPERTIES => $d->{PROPERTIES},
ELEMENTS => \@elements,
ORIGINAL => $d
};
}
sub CheckPointerTypes($$)
{
my $s = shift;
my $default = shift;
foreach my $e (@{$s->{ELEMENTS}}) {
if ($e->{POINTERS} and not defined(pointer_type($e))) {
$e->{PROPERTIES}->{$default} = 1;
}
}
}
sub ParseInterface($)
{
my $idl = shift;
my @typedefs = ();
my @consts = ();
my @functions = ();
my @endpoints;
my @declares = ();
my $opnum = 0;
my $version;
if (not has_property($idl, "pointer_default")) {
# MIDL defaults to "ptr" in DCE compatible mode (/osf)
# and "unique" in Microsoft Extensions mode (default)
$idl->{PROPERTIES}->{pointer_default} = "unique";
}
if (not has_property($idl, "pointer_default_top")) {
$idl->{PROPERTIES}->{pointer_default_top} = "ref";
}
foreach my $d (@{$idl->{DATA}}) {
if ($d->{TYPE} eq "TYPEDEF") {
push (@typedefs, ParseTypedef($idl, $d));
}
if ($d->{TYPE} eq "DECLARE") {
push (@declares, $d);
}
if ($d->{TYPE} eq "FUNCTION") {
push (@functions, ParseFunction($idl, $d, \$opnum));
}
if ($d->{TYPE} eq "CONST") {
push (@consts, ParseConst($idl, $d));
}
}
$version = "0.0";
if(defined $idl->{PROPERTIES}->{version}) {
$version = $idl->{PROPERTIES}->{version};
}
# If no endpoint is set, default to the interface name as a named pipe
if (!defined $idl->{PROPERTIES}->{endpoint}) {
push @endpoints, "\"ncacn_np:[\\\\pipe\\\\" . $idl->{NAME} . "]\"";
} else {
@endpoints = split / /, $idl->{PROPERTIES}->{endpoint};
}
return {
NAME => $idl->{NAME},
UUID => has_property($idl, "uuid"),
VERSION => $version,
TYPE => "INTERFACE",
PROPERTIES => $idl->{PROPERTIES},
FUNCTIONS => \@functions,
CONSTS => \@consts,
TYPEDEFS => \@typedefs,
DECLARES => \@declares,
ENDPOINTS => \@endpoints
};
}
# Convert a IDL tree to a NDR tree
# Gives a result tree describing all that's necessary for easily generating
# NDR parsers / generators
sub Parse($)
{
my $idl = shift;
my @ndr = ();
push(@ndr, ParseInterface($_)) foreach (@{$idl});
return \@ndr;
}
sub GetNextLevel($$)
{
my $e = shift;
my $fl = shift;
my $seen = 0;
foreach my $l (@{$e->{LEVELS}}) {
return $l if ($seen);
($seen = 1) if ($l == $fl);
}
return undef;
}
sub GetPrevLevel($$)
{
my ($e,$fl) = @_;
my $prev = undef;
foreach my $l (@{$e->{LEVELS}}) {
(return $prev) if ($l == $fl);
$prev = $l;
}
return undef;
}
sub ContainsDeferred($$)
{
my ($e,$l) = @_;
return 1 if ($l->{CONTAINS_DEFERRED});
while ($l = GetNextLevel($e,$l))
{
return 1 if ($l->{IS_DEFERRED});
return 1 if ($l->{CONTAINS_DEFERRED});
}
return 0;
}
sub el_name($)
{
my $e = shift;
if ($e->{PARENT} && $e->{PARENT}->{NAME}) {
return "$e->{PARENT}->{NAME}.$e->{NAME}";
}
if ($e->{PARENT} && $e->{PARENT}->{PARENT}->{NAME}) {
return "$e->{PARENT}->{PARENT}->{NAME}.$e->{NAME}";
}
if ($e->{PARENT}) {
return "$e->{PARENT}->{NAME}.$e->{NAME}";
}
return $e->{NAME};
}
###################################
# find a sibling var in a structure
sub find_sibling($$)
{
my($e,$name) = @_;
my($fn) = $e->{PARENT};
if ($name =~ /\*(.*)/) {
$name = $1;
}
for my $e2 (@{$fn->{ELEMENTS}}) {
return $e2 if ($e2->{NAME} eq $name);
}
return undef;
}
my %property_list = (
# interface
"helpstring" => ["INTERFACE", "FUNCTION"],
"version" => ["INTERFACE"],
"uuid" => ["INTERFACE"],
"endpoint" => ["INTERFACE"],
"pointer_default" => ["INTERFACE"],
"pointer_default_top" => ["INTERFACE"],
"depends" => ["INTERFACE"],
"authservice" => ["INTERFACE"],
# dcom
"object" => ["INTERFACE"],
"local" => ["INTERFACE", "FUNCTION"],
"iid_is" => ["ELEMENT"],
"call_as" => ["FUNCTION"],
"idempotent" => ["FUNCTION"],
# function
"noopnum" => ["FUNCTION"],
"in" => ["ELEMENT"],
"out" => ["ELEMENT"],
# pointer
"ref" => ["ELEMENT"],
"ptr" => ["ELEMENT"],
"sptr" => ["ELEMENT"],
"unique" => ["ELEMENT"],
"ignore" => ["ELEMENT"],
"relative" => ["ELEMENT"],
"relative_base" => ["TYPEDEF"],
"gensize" => ["TYPEDEF"],
"value" => ["ELEMENT"],
"flag" => ["ELEMENT", "TYPEDEF"],
# generic
"public" => ["FUNCTION", "TYPEDEF"],
"nopush" => ["FUNCTION", "TYPEDEF"],
"nopull" => ["FUNCTION", "TYPEDEF"],
"noprint" => ["FUNCTION", "TYPEDEF"],
"noejs" => ["FUNCTION", "TYPEDEF"],
# union
"switch_is" => ["ELEMENT"],
"switch_type" => ["ELEMENT", "TYPEDEF"],
"nodiscriminant" => ["TYPEDEF"],
"case" => ["ELEMENT"],
"default" => ["ELEMENT"],
# subcontext
"subcontext" => ["ELEMENT"],
"subcontext_size" => ["ELEMENT"],
"compression" => ["ELEMENT"],
"obfuscation" => ["ELEMENT"],
# enum
"enum8bit" => ["TYPEDEF"],
"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"],
);
#####################################################################
# check for unknown properties
sub ValidProperties($$)
{
my ($e,$t) = @_;
return unless defined $e->{PROPERTIES};
foreach my $key (keys %{$e->{PROPERTIES}}) {
fatal($e, el_name($e) . ": unknown property '$key'\n")
unless defined($property_list{$key});
fatal($e, el_name($e) . ": property '$key' not allowed on '$t'\n")
unless grep($t, @{$property_list{$key}});
}
}
sub mapToScalar($)
{
my $t = shift;
my $ti = getType($t);
if (not defined ($ti)) {
return undef;
} elsif ($ti->{DATA}->{TYPE} eq "ENUM") {
return Parse::Pidl::Typelist::enum_type_fn($ti->{DATA});
} elsif ($ti->{DATA}->{TYPE} eq "BITMAP") {
return Parse::Pidl::Typelist::enum_type_fn($ti->{DATA});
} elsif ($ti->{DATA}->{TYPE} eq "SCALAR") {
return $t;
}
return undef;
}
#####################################################################
# parse a struct
sub ValidElement($)
{
my $e = shift;
ValidProperties($e,"ELEMENT");
if (has_property($e, "ptr")) {
fatal($e, el_name($e) . " : pidl does not support full NDR pointers yet\n");
}
# Check whether switches are used correctly.
if (my $switch = has_property($e, "switch_is")) {
my $e2 = find_sibling($e, $switch);
my $type = getType($e->{TYPE});
if (defined($type) and $type->{DATA}->{TYPE} ne "UNION") {
fatal($e, el_name($e) . ": switch_is() used on non-union type $e->{TYPE} which is a $type->{DATA}->{TYPE}");
}
if (!has_property($type, "nodiscriminant") and defined($e2)) {
my $discriminator_type = has_property($type, "switch_type");
$discriminator_type = "uint32" unless defined ($discriminator_type);
my $t1 = mapToScalar($discriminator_type);
if (not defined($t1)) {
fatal($e, el_name($e) . ": unable to map discriminator type '$discriminator_type' to scalar");
}
my $t2 = mapToScalar($e2->{TYPE});
if (not defined($t2)) {
fatal($e, el_name($e) . ": unable to map variable used for switch_is() to scalar");
}
if ($t1 ne $t2) {
nonfatal($e, el_name($e) . ": switch_is() is of type $e2->{TYPE} ($t2), while discriminator type for union $type->{NAME} is $discriminator_type ($t1)");
}
}
}
if (defined (has_property($e, "subcontext_size")) and not defined(has_property($e, "subcontext"))) {
fatal($e, el_name($e) . " : subcontext_size() on non-subcontext element");
}
if (defined (has_property($e, "compression")) and not defined(has_property($e, "subcontext"))) {
fatal($e, el_name($e) . " : compression() on non-subcontext element");
}
if (defined (has_property($e, "obfuscation")) and not defined(has_property($e, "subcontext"))) {
fatal($e, el_name($e) . " : obfuscation() on non-subcontext element");
}
if (!$e->{POINTERS} && (
has_property($e, "ptr") or
has_property($e, "sptr") or
has_property($e, "unique") or
has_property($e, "relative") or
has_property($e, "ref"))) {
fatal($e, el_name($e) . " : pointer properties on non-pointer element\n");
}
}
#####################################################################
# parse a struct
sub ValidStruct($)
{
my($struct) = shift;
ValidProperties($struct,"STRUCT");
foreach my $e (@{$struct->{ELEMENTS}}) {
$e->{PARENT} = $struct;
ValidElement($e);
}
}
#####################################################################
# parse a union
sub ValidUnion($)
{
my($union) = shift;
ValidProperties($union,"UNION");
if (has_property($union->{PARENT}, "nodiscriminant") and has_property($union->{PARENT}, "switch_type")) {
fatal($union->{PARENT}, $union->{PARENT}->{NAME} . ": switch_type() on union without discriminant");
}
foreach my $e (@{$union->{ELEMENTS}}) {
$e->{PARENT} = $union;
if (defined($e->{PROPERTIES}->{default}) and
defined($e->{PROPERTIES}->{case})) {
fatal $e, "Union member $e->{NAME} can not have both default and case properties!\n";
}
unless (defined ($e->{PROPERTIES}->{default}) or
defined ($e->{PROPERTIES}->{case})) {
fatal $e, "Union member $e->{NAME} must have default or case property\n";
}
if (has_property($e, "ref")) {
fatal($e, el_name($e) . " : embedded ref pointers are not supported yet\n");
}
ValidElement($e);
}
}
#####################################################################
# parse a typedef
sub ValidTypedef($)
{
my($typedef) = shift;
my $data = $typedef->{DATA};
ValidProperties($typedef,"TYPEDEF");
$data->{PARENT} = $typedef;
if (ref($data) eq "HASH") {
if ($data->{TYPE} eq "STRUCT") {
ValidStruct($data);
}
if ($data->{TYPE} eq "UNION") {
ValidUnion($data);
}
}
}
#####################################################################
# parse a function
sub ValidFunction($)
{
my($fn) = shift;
ValidProperties($fn,"FUNCTION");
foreach my $e (@{$fn->{ELEMENTS}}) {
$e->{PARENT} = $fn;
if (has_property($e, "ref") && !$e->{POINTERS}) {
fatal $e, "[ref] variables must be pointers ($fn->{NAME}/$e->{NAME})\n";
}
ValidElement($e);
}
}
#####################################################################
# parse the interface definitions
sub ValidInterface($)
{
my($interface) = shift;
my($data) = $interface->{DATA};
ValidProperties($interface,"INTERFACE");
if (has_property($interface, "pointer_default") &&
$interface->{PROPERTIES}->{pointer_default} eq "ptr") {
fatal $interface, "Full pointers are not supported yet\n";
}
if (has_property($interface, "object")) {
if (has_property($interface, "version") &&
$interface->{PROPERTIES}->{version} != 0) {
fatal $interface, "Object interfaces must have version 0.0 ($interface->{NAME})\n";
}
if (!defined($interface->{BASE}) &&
not ($interface->{NAME} eq "IUnknown")) {
fatal $interface, "Object interfaces must all derive from IUnknown ($interface->{NAME})\n";
}
}
foreach my $d (@{$data}) {
($d->{TYPE} eq "TYPEDEF") &&
ValidTypedef($d);
($d->{TYPE} eq "FUNCTION") &&
ValidFunction($d);
}
}
#####################################################################
# Validate an IDL structure
sub Validate($)
{
my($idl) = shift;
foreach my $x (@{$idl}) {
($x->{TYPE} eq "INTERFACE") &&
ValidInterface($x);
}
}
1;

View File

@ -0,0 +1,92 @@
##########################################
# 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;
#####################################################################
# find an interface in an array of interfaces
sub get_interface($$)
{
my($if) = shift;
my($n) = shift;
foreach(@{$if}) {
if($_->{NAME} eq $n) { return $_; }
}
return 0;
}
sub FunctionAddObjArgs($)
{
my $e = shift;
unshift(@{$e->{ELEMENTS}}, {
'NAME' => 'ORPCthis',
'POINTERS' => 0,
'PROPERTIES' => { 'in' => '1' },
'TYPE' => 'ORPCTHIS'
});
unshift(@{$e->{ELEMENTS}}, {
'NAME' => 'ORPCthat',
'POINTERS' => 0,
'PROPERTIES' => { 'out' => '1' },
'TYPE' => 'ORPCTHAT'
});
}
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;
foreach my $x (@{$odl}) {
# 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);
}
# Object interfaces use ORPC
my @depends = ();
if(has_property($x, "depends")) {
@depends = split /,/, $x->{PROPERTIES}->{depends};
}
push @depends, "orpc";
$x->{PROPERTIES}->{depends} = join(',',@depends);
}
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});
}
}
}
return $odl;
}
1;

View File

@ -0,0 +1,139 @@
# COM Header generation
# (C) 2005 Jelmer Vernooij <jelmer@samba.org>
package Parse::Pidl::Samba::COM::Header;
use Parse::Pidl::Typelist;
use Parse::Pidl::Util qw(has_property);
use strict;
sub GetArgumentProtoList($)
{
my $f = shift;
my $res = "";
foreach my $a (@{$f->{ELEMENTS}}) {
$res .= ", " . Parse::Pidl::Typelist::mapType($a->{TYPE}) . " ";
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] &&
!Parse::Pidl::Util::is_constant($a->{ARRAY_LEN}[0]) &&
!$a->{POINTERS}) {
$res .= "*";
}
$res .= $a->{NAME};
if (defined $a->{ARRAY_LEN}[0] && Parse::Pidl::Util::is_constant($a->{ARRAY_LEN}[0])) {
$res .= "[$a->{ARRAY_LEN}[0]]";
}
}
return $res;
}
sub GetArgumentList($)
{
my $f = shift;
my $res = "";
foreach my $a (@{$f->{ELEMENTS}}) {
$res .= ", $a->{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}) {
$res .= "\t" . Parse::Pidl::Typelist::mapType($d->{RETURN_TYPE}) . " (*$d->{NAME}) (struct $interface->{NAME} *d, TALLOC_CTX *mem_ctx" . GetArgumentProtoList($d) . ");\\\n" if ($d->{TYPE} eq "FUNCTION");
}
$res .= "\n";
$res .= "struct $interface->{NAME}_vtable {\n";
$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 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");
$res .= "#define $if->{NAME}_$d->{NAME}(interface, mem_ctx" . GetArgumentList($d) . ") ";
$res .= "((interface)->vtable->$d->{NAME}(interface, mem_ctx" . GetArgumentList($d) . "))";
$res .="\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 = shift;
my $res = "";
foreach my $x (@{$idl})
{
if ($x->{TYPE} eq "INTERFACE" && has_property($x, "object")) {
$res.=ParseInterface($x);
}
if ($x->{TYPE} eq "COCLASS") {
$res.=ParseCoClass($x);
}
}
return $res;
}
1;

View File

@ -0,0 +1,212 @@
###################################################
# 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::Samba::COM::Proxy;
use Parse::Pidl::Samba::COM::Header;
use Parse::Pidl::Util qw(has_property);
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 .= "static NTSTATUS dcom_proxy_$interface->{NAME}_init(void)
{
struct GUID base_iid;
struct $interface->{NAME}_vtable *proxy_vtable = talloc(talloc_autofree_context(), struct $interface->{NAME}_vtable);
";
if (defined($interface->{BASE})) {
$res.= "
const void *base_vtable;
GUID_from_string(DCERPC_" . (uc $interface->{BASE}) . "_UUID, &base_iid);
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.= "
GUID_from_string(DCERPC_" . (uc $interface->{NAME}) . "_UUID, &proxy_vtable.iid);
return dcom_register_proxy(&proxy_vtable);
}\n\n";
}
#####################################################################
# parse a function
sub ParseFunction($$)
{
my $interface = shift;
my $fn = shift;
my $name = $fn->{NAME};
my $uname = uc $name;
$res.="
static $fn->{RETURN_TYPE} dcom_proxy_$interface->{NAME}_$name(struct $interface->{NAME} *d, TALLOC_CTX *mem_ctx" . Parse::Pidl::Samba::COM::Header::GetArgumentProtoList($fn) . ")
{
struct dcerpc_pipe *p;
NTSTATUS status = dcom_get_pipe(d, &p);
struct $name r;
struct rpc_request *req;
if (NT_STATUS_IS_ERR(status)) {
return status;
}
ZERO_STRUCT(r.in.ORPCthis);
r.in.ORPCthis.version.MajorVersion = COM_MAJOR_VERSION;
r.in.ORPCthis.version.MinorVersion = COM_MINOR_VERSION;
";
# Put arguments into r
foreach my $a (@{$fn->{ELEMENTS}}) {
next unless (has_property($a, "in"));
if (Parse::Pidl::Typelist::typeIs($a->{TYPE}, "INTERFACE")) {
$res .="\tNDR_CHECK(dcom_OBJREF_from_IUnknown(&r.in.$a->{NAME}.obj, $a->{NAME}));\n";
} else {
$res .= "\tr.in.$a->{NAME} = $a->{NAME};\n";
}
}
$res .="
if (p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
NDR_PRINT_IN_DEBUG($name, &r);
}
status = dcerpc_ndr_request(p, &d->ipid, &dcerpc_table_$interface->{NAME}, DCERPC_$uname, mem_ctx, &r);
if (NT_STATUS_IS_OK(status) && (p->conn->flags & DCERPC_DEBUG_PRINT_OUT)) {
NDR_PRINT_OUT_DEBUG($name, r);
}
";
# Put r info back into arguments
foreach my $a (@{$fn->{ELEMENTS}}) {
next unless (has_property($a, "out"));
if (Parse::Pidl::Typelist::typeIs($a->{TYPE}, "INTERFACE")) {
$res .="\tNDR_CHECK(dcom_IUnknown_from_OBJREF(d->ctx, &$a->{NAME}, r.out.$a->{NAME}.obj));\n";
} else {
$res .= "\t*$a->{NAME} = r.out.$a->{NAME};\n";
}
}
if ($fn->{RETURN_TYPE} eq "NTSTATUS") {
$res .= "\tif (NT_STATUS_IS_OK(status)) status = r.out.result;\n";
}
$res .=
"
return r.out.result;
}\n\n";
}
#####################################################################
# 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 = shift;
my $res = "";
foreach my $x (@{$pidl}) {
next if ($x->{TYPE} ne "INTERFACE");
next if has_property($x, "local");
next unless has_property($x, "object");
$res .= ParseInterface($x);
}
return $res;
}
1;

View File

@ -0,0 +1,324 @@
###################################################
# 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::Samba::COM::Stub;
use Parse::Pidl::Util qw(has_property);
use strict;
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;

View File

@ -0,0 +1,835 @@
###################################################
# EJS function wrapper generator
# Copyright jelmer@samba.org 2005
# Copyright Andrew Tridgell 2005
# released under the GNU GPL
package Parse::Pidl::Samba::EJS;
use strict;
use Parse::Pidl::Typelist;
use Parse::Pidl::Util qw(has_property);
my($res);
my %constants;
my $tabs = "";
sub pidl($)
{
my $d = shift;
if ($d) {
$res .= $tabs;
$res .= $d;
}
$res .= "\n";
}
sub indent()
{
$tabs .= "\t";
}
sub deindent()
{
$tabs = substr($tabs, 0, -1);
}
# 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";
}
}
#####################################################################
# work out is a parse function should be declared static or not
sub fn_prefix($)
{
my $fn = shift;
return "" if (has_property($fn, "public"));
return "static ";
}
###########################
# 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;
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}) {
pidl "EJS_ALLOC_N(ejs, $var, $size);";
}
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);
pidl fn_prefix($d);
pidl "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, struct $name *r)\n{";
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);
pidl fn_prefix($d);
pidl "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, union $name *r)\n{";
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);
pidl fn_prefix($d);
pidl "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, enum $name *r)\n{";
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});
pidl fn_prefix($d);
pidl "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, $type_decl *r)\n{";
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});
} 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;
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') {
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);
pidl fn_prefix($d);
pidl "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const struct $name *r)\n{";
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);
pidl fn_prefix($d);
pidl "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const union $name *r)\n{";
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);
pidl fn_prefix($d);
pidl "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const enum $name *r)\n{";
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;
}
}
pidl fn_prefix($d);
pidl "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const $type_decl *r)\n{";
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});
} 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};
}
#####################################################################
# parse the interface definitions
sub EjsInterface($$)
{
my($interface,$needed) = @_;
my @fns = ();
my $name = $interface->{NAME};
%constants = ();
foreach my $d (@{$interface->{TYPEDEFS}}) {
($needed->{"push_$d->{NAME}"}) && EjsTypedefPush($d);
($needed->{"pull_$d->{NAME}"}) && EjsTypedefPull($d);
}
foreach my $d (@{$interface->{FUNCTIONS}}) {
next if not defined($d->{OPNUM});
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 "return smbcalls_register_ejs(\"$name\_init\", ejs_$name\_init);";
deindent;
pidl "}";
}
#####################################################################
# parse a parsed IDL into a C header
sub Parse($$)
{
my($ndr,$hdr) = @_;
my $ejs_hdr = $hdr;
$ejs_hdr =~ s/.h$/_ejs.h/;
$res = "";
pidl "
/* EJS wrapper functions auto-generated by pidl */
#include \"includes.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);
}
return $res;
}
sub NeededFunction($$)
{
my ($fn,$needed) = @_;
$needed->{"pull_$fn->{NAME}"} = 1;
$needed->{"push_$fn->{NAME}"} = 1;
foreach my $e (@{$fn->{ELEMENTS}}) {
if (grep (/in/, @{$e->{DIRECTION}})) {
$needed->{"pull_$e->{TYPE}"} = 1;
}
if (grep (/out/, @{$e->{DIRECTION}})) {
$needed->{"push_$e->{TYPE}"} = 1;
}
}
}
sub NeededTypedef($$)
{
my ($t,$needed) = @_;
if (Parse::Pidl::Util::has_property($t, "public")) {
$needed->{"pull_$t->{NAME}"} = not Parse::Pidl::Util::has_property($t, "noejs");
$needed->{"push_$t->{NAME}"} = not Parse::Pidl::Util::has_property($t, "noejs");
}
if ($t->{DATA}->{TYPE} ne "STRUCT" &&
$t->{DATA}->{TYPE} ne "UNION") {
return;
}
for my $e (@{$t->{DATA}->{ELEMENTS}}) {
if ($needed->{"pull_$t->{NAME}"}) {
$needed->{"pull_$e->{TYPE}"} = 1;
}
if ($needed->{"push_$t->{NAME}"}) {
$needed->{"push_$e->{TYPE}"} = 1;
}
}
}
#####################################################################
# work out what parse functions are needed
sub NeededInterface($$)
{
my ($interface,$needed) = @_;
foreach my $d (@{$interface->{FUNCTIONS}}) {
NeededFunction($d, $needed);
}
foreach my $d (reverse @{$interface->{TYPEDEFS}}) {
NeededTypedef($d, $needed);
}
}
1;

View File

@ -0,0 +1,76 @@
###################################################
# create C header files for an EJS mapping functions
# Copyright tridge@samba.org 2005
# released under the GNU GPL
package Parse::Pidl::Samba::EJSHeader;
use strict;
use Parse::Pidl::Typelist;
use Parse::Pidl::Util qw(has_property);
my($res);
sub pidl ($)
{
$res .= shift;
}
#####################################################################
# prototype a typedef
sub HeaderTypedefProto($)
{
my $d = shift;
my $name = $d->{NAME};
return unless has_property($d, "public");
my $type_decl = Parse::Pidl::Typelist::mapType($name);
pidl "NTSTATUS ejs_push_$d->{NAME}(struct ejs_rpc *, struct MprVar *, const char *, const $type_decl *);\n";
pidl "NTSTATUS ejs_pull_$d->{NAME}(struct ejs_rpc *, struct MprVar *, const char *, $type_decl *);\n";
}
#####################################################################
# parse the interface definitions
sub HeaderInterface($)
{
my($interface) = shift;
my $count = 0;
pidl "#ifndef _HEADER_EJS_$interface->{NAME}\n";
pidl "#define _HEADER_EJS_$interface->{NAME}\n\n";
if (defined $interface->{PROPERTIES}->{depends}) {
my @d = split / /, $interface->{PROPERTIES}->{depends};
foreach my $i (@d) {
pidl "#include \"librpc/gen_ndr/ndr_$i\_ejs\.h\"\n";
}
}
pidl "\n";
foreach my $d (@{$interface->{TYPEDEFS}}) {
HeaderTypedefProto($d);
}
pidl "\n";
pidl "#endif /* _HEADER_EJS_$interface->{NAME} */\n";
}
#####################################################################
# parse a parsed IDL into a C header
sub Parse($)
{
my($idl) = shift;
$res = "";
pidl "/* header auto-generated by pidl */\n\n";
foreach my $x (@{$idl}) {
($x->{TYPE} eq "INTERFACE") && HeaderInterface($x);
}
return $res;
}
1;

View File

@ -0,0 +1,356 @@
###################################################
# 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::Samba::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);
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();
HeaderType($element, $element->{TYPE}, "");
pidl " ";
my $numstar = $element->{POINTERS};
foreach (@{$element->{ARRAY_LEN}})
{
next if is_constant($_) and
not has_property($element, "charset");
$numstar++;
}
$numstar-- if Parse::Pidl::Typelist::scalar_is_reference($element->{TYPE});
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 my $e (@{$struct->{ELEMENTS}}) {
HeaderElement($e);
$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}, []);
}
}
#####################################################################
# 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);
return;
}
if (has_property($e, "charset")) {
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 my $e (@{$fn->{ELEMENTS}}) {
if (has_property($e, $prop)) {
HeaderElement($e);
}
}
}
#####################################################################
# 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";
}
#####################################################################
# parse the interface definitions
sub HeaderInterface($)
{
my($interface) = shift;
my $count = 0;
pidl "#ifndef _HEADER_$interface->{NAME}\n";
pidl "#define _HEADER_$interface->{NAME}\n\n";
if (defined $interface->{PROPERTIES}->{depends}) {
my @d = split / /, $interface->{PROPERTIES}->{depends};
foreach my $i (@d) {
pidl "#include \"librpc/gen_ndr/$i\.h\"\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 = "";
pidl "/* header auto-generated by pidl */\n\n";
foreach my $x (@{$idl}) {
($x->{TYPE} eq "INTERFACE") && HeaderInterface($x);
}
return $res;
}
1;

View File

@ -0,0 +1,99 @@
###################################################
# client calls generator
# Copyright tridge@samba.org 2003
# released under the GNU GPL
package Parse::Pidl::Samba::NDR::Client;
use strict;
my($res);
#####################################################################
# parse a function
sub ParseFunction($$)
{
my ($interface, $fn) = @_;
my $name = $fn->{NAME};
my $uname = uc $name;
$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 .= "/* $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;
}
return $res;
}
sub Parse($$)
{
my($ndr) = shift;
my($filename) = shift;
my $h_filename = $filename;
$res = "";
if ($h_filename =~ /(.*)\.c/) {
$h_filename = "$1.h";
}
$res .= "/* client functions auto-generated by pidl */\n";
$res .= "\n";
$res .= "#include \"includes.h\"\n";
$res .= "#include \"$h_filename\"\n";
$res .= "\n";
foreach my $x (@{$ndr}) {
($x->{TYPE} eq "INTERFACE") && ParseInterface($x);
}
return $res;
}
1;

View File

@ -0,0 +1,166 @@
###################################################
# 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::Samba::NDR::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::Samba::NDR::Parser;
my($res);
my($tab_depth);
sub pidl ($)
{
$res .= shift;
}
sub tabs()
{
my $res = "";
$res .="\t" foreach (1..$tab_depth);
return $res;
}
#####################################################################
# prototype a typedef
sub HeaderTypedefProto($)
{
my($d) = shift;
my $tf = Parse::Pidl::Samba::NDR::Parser::get_typefamily($d->{DATA}{TYPE});
if (has_property($d, "gensize")) {
my $size_args = $tf->{SIZE_FN_ARGS}->($d);
pidl "size_t ndr_size_$d->{NAME}($size_args);\n";
}
return unless has_property($d, "public");
unless (has_property($d, "nopush")) {
pidl "NTSTATUS ndr_push_$d->{NAME}(struct ndr_push *ndr, int ndr_flags, " . $tf->{DECL}->($d, "push") . ");\n";
}
unless (has_property($d, "nopull")) {
pidl "NTSTATUS ndr_pull_$d->{NAME}(struct ndr_pull *ndr, int ndr_flags, " . $tf->{DECL}->($d, "pull") . ");\n";
}
unless (has_property($d, "noprint")) {
pidl "void ndr_print_$d->{NAME}(struct ndr_print *ndr, const char *name, " . $tf->{DECL}->($d, "print") . ");\n";
}
}
#####################################################################
# output prototypes for a IDL function
sub HeaderFnProto($$)
{
my ($interface,$fn) = @_;
my $name = $fn->{NAME};
pidl "void ndr_print_$name(struct ndr_print *ndr, const char *name, int flags, const struct $name *r);\n";
unless (has_property($fn, "noopnum")) {
pidl "NTSTATUS dcerpc_$name(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *r);\n";
pidl "struct rpc_request *dcerpc_$name\_send(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *r);\n";
}
return unless has_property($fn, "public");
pidl "NTSTATUS ndr_push_$name(struct ndr_push *ndr, int flags, const struct $name *r);\n";
pidl "NTSTATUS ndr_pull_$name(struct ndr_pull *ndr, int flags, struct $name *r);\n";
pidl "\n";
}
#####################################################################
# parse the interface definitions
sub HeaderInterface($)
{
my($interface) = shift;
if (defined $interface->{PROPERTIES}->{depends}) {
my @d = split / /, $interface->{PROPERTIES}->{depends};
foreach my $i (@d) {
pidl "#include \"librpc/gen_ndr/ndr_$i\.h\"\n";
}
}
my $count = 0;
pidl "#ifndef _HEADER_NDR_$interface->{NAME}\n";
pidl "#define _HEADER_NDR_$interface->{NAME}\n\n";
if (defined $interface->{PROPERTIES}->{uuid}) {
my $name = uc $interface->{NAME};
pidl "#define DCERPC_$name\_UUID " .
Parse::Pidl::Util::make_str($interface->{PROPERTIES}->{uuid}) . "\n";
if(!defined $interface->{PROPERTIES}->{version}) { $interface->{PROPERTIES}->{version} = "0.0"; }
pidl "#define DCERPC_$name\_VERSION $interface->{PROPERTIES}->{version}\n";
pidl "#define DCERPC_$name\_NAME \"$interface->{NAME}\"\n";
if(!defined $interface->{PROPERTIES}->{helpstring}) { $interface->{PROPERTIES}->{helpstring} = "NULL"; }
pidl "#define DCERPC_$name\_HELPSTRING $interface->{PROPERTIES}->{helpstring}\n";
pidl "\nextern const struct dcerpc_interface_table dcerpc_table_$interface->{NAME};\n";
pidl "NTSTATUS dcerpc_server_$interface->{NAME}_init(void);\n\n";
}
foreach my $d (@{$interface->{DATA}}) {
next if $d->{TYPE} ne "FUNCTION";
next if has_property($d, "noopnum");
next if grep(/$d->{NAME}/,@{$interface->{INHERITED_FUNCTIONS}});
my $u_name = uc $d->{NAME};
pidl "#define DCERPC_$u_name (";
if (defined($interface->{BASE})) {
pidl "DCERPC_" . uc $interface->{BASE} . "_CALL_COUNT + ";
}
pidl sprintf("0x%02x", $count) . ")\n";
$count++;
}
pidl "\n#define DCERPC_" . uc $interface->{NAME} . "_CALL_COUNT (";
if (defined($interface->{BASE})) {
pidl "DCERPC_" . uc $interface->{BASE} . "_CALL_COUNT + ";
}
pidl "$count)\n\n";
foreach my $d (@{$interface->{DATA}}) {
next if ($d->{TYPE} ne "TYPEDEF");
HeaderTypedefProto($d);
}
foreach my $d (@{$interface->{DATA}}) {
next if ($d->{TYPE} ne "FUNCTION");
HeaderFnProto($interface, $d);
}
pidl "#endif /* _HEADER_NDR_$interface->{NAME} */\n";
}
#####################################################################
# parse a parsed IDL into a C header
sub Parse($$)
{
my($idl,$basename) = @_;
$tab_depth = 0;
$res = "";
pidl "/* header auto-generated by pidl */\n";
pidl "#include \"librpc/gen_ndr/$basename\.h\"\n\n";
foreach my $x (@{$idl}) {
($x->{TYPE} eq "INTERFACE") && HeaderInterface($x);
}
return $res;
}
1;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,322 @@
###################################################
# server boilerplate generator
# Copyright tridge@samba.org 2003
# Copyright metze@samba.org 2004
# released under the GNU GPL
package Parse::Pidl::Samba::NDR::Server;
use strict;
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 = 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 = 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 = 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;
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\",
.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 ($name\_interface.if_version == if_version &&
strcmp($name\_interface.uuid, uuid)==0) {
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) = shift;
my($filename) = shift;
$res = "";
$res .= "/* server functions auto-generated by pidl */\n";
$res .= "\n";
foreach my $x (@{$ndr}) {
ParseInterface($x) if ($x->{TYPE} eq "INTERFACE" and not defined($x->{PROPERTIES}{object}));
}
return $res;
}
1;

View File

@ -0,0 +1,76 @@
###################################################
# Samba4 parser generator for swig wrappers
# Copyright tpot@samba.org 2004,2005
# released under the GNU GPL
package Parse::Pidl::Samba::SWIG;
use strict;
sub pidl($)
{
print OUT shift;
}
#####################################################################
# rewrite autogenerated header file
sub RewriteHeader($$$)
{
my($idl) = shift;
my($input) = shift;
my($output) = shift;
open(IN, "<$input") || die "can't open $input for reading";
open(OUT, ">$output") || die "can't open $output for writing";
pidl "%{\n";
pidl "#define data_in in\n";
pidl "#define data_out out\n";
pidl "%}\n\n";
while(<IN>) {
# Rename dom_sid2 to dom_sid as we don't care about the difference
# for the swig wrappers.
s/dom_sid2/dom_sid/g;
# Copy structure and union definitions
if (/^(struct|union) .*? {$/ .. /^\};$/) {
s/\} (in|out);/\} data_$1;/; # "in" is a Python keyword
pidl $_;
next;
}
# Copy dcerpc functions
pidl $_ if /^NTSTATUS dcerpc_.*?\(struct dcerpc_pipe/;
# Copy interface definitions
pidl $_
if /^\#define DCERPC_.*?_UUID/ or /^\#define DCERPC_.*?_VERSION/;
}
close(OUT);
}
#####################################################################
# rewrite autogenerated header file
sub RewriteC($$$)
{
my($idl) = shift;
my($input) = shift;
my($output) = shift;
open(IN, "<$input") || die "can't open $input for reading";
open(OUT, ">>$output") || die "can't open $output for writing";
while(<IN>) {
}
close(OUT);
}
1;

View File

@ -0,0 +1,278 @@
###################################################
# Trivial Parser Generator
# Copyright jelmer@samba.org 2005
# released under the GNU GPL
package Parse::Pidl::Samba::TDR;
use Parse::Pidl::Util qw(has_property ParseExpr is_constant);
use Data::Dumper;
use strict;
my $ret = "";
my $tabs = "";
sub indent() { $tabs.="\t"; }
sub deindent() { $tabs = substr($tabs, 1); }
sub pidl($) { $ret .= $tabs.(shift)."\n"; }
sub fatal($$) { my ($e,$s) = @_; die("$e->{FILE}:$e->{LINE}: $s\n"); }
sub static($) { my $p = shift; return("static ") unless ($p); return ""; }
sub typearg($) {
my $t = shift;
return(", const char *name") if ($t eq "print");
return(", TALLOC_CTX *mem_ctx") if ($t eq "pull");
return("");
}
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) = @_;
pidl static($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) = @_;
pidl static($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");
pidl static($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;
foreach (@{$x->{DATA}}) {
next if ($_->{TYPE} ne "TYPEDEF");
ParserTypedef($_, "pull");
ParserTypedef($_, "push");
ParserTypedef($_, "print");
}
}
sub Parser($$)
{
my ($idl,$hdrname) = @_;
$ret = "";
pidl "/* autogenerated by pidl */";
pidl "#include \"includes.h\"";
pidl "#include \"$hdrname\"";
pidl "";
foreach (@$idl) { ParserInterface($_) if ($_->{TYPE} eq "INTERFACE"); }
return $ret;
}
sub HeaderInterface($$)
{
my ($x,$outputdir) = @_;
pidl "#ifndef __TDR_$x->{NAME}_HEADER__";
pidl "#define __TDR_$x->{NAME}_HEADER__";
foreach my $e (@{$x->{DATA}}) {
next unless ($e->{TYPE} eq "TYPEDEF");
next unless has_property($e, "public");
my $switch = "";
$switch = ", int level" if ($e->{DATA}->{TYPE} eq "UNION");
if ($e->{DATA}->{TYPE} eq "BITMAP") {
# FIXME
} else {
my ($n, $d) = ($e->{NAME}, lc($e->{DATA}->{TYPE}));
pidl "NTSTATUS tdr_pull\_$n(struct tdr_pull *tdr, TALLOC_CTX *ctx$switch, $d $n *v);";
pidl "NTSTATUS tdr_print\_$n(struct tdr_print *tdr, const char *name$switch, $d $n *v);";
pidl "NTSTATUS tdr_push\_$n(struct tdr_push *tdr$switch, $d $n *v);";
}
pidl "";
}
pidl "#endif /* __TDR_$x->{NAME}_HEADER__ */";
}
sub Header($$$)
{
my ($idl,$outputdir,$basename) = @_;
$ret = "";
pidl "/* Generated by pidl */";
pidl "#include \"$outputdir/$basename.h\"";
pidl "";
foreach (@$idl) {
HeaderInterface($_, $outputdir) if ($_->{TYPE} eq "INTERFACE");
}
return $ret;
}
1;

View File

@ -0,0 +1,88 @@
###################################################
# server template function generator
# Copyright tridge@samba.org 2003
# released under the GNU GPL
package Parse::Pidl::Samba::Template;
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\"
";
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)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
";
}
}
$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;

View File

@ -0,0 +1,169 @@
# Simple system for running tests against pidl
# (C) 2005 Jelmer Vernooij <jelmer@samba.org>
# Published under the GNU General Public License
package Parse::Pidl::Test;
use strict;
use Parse::Pidl::Util;
use Getopt::Long;
my $cc = $ENV{CC};
my @cflags = split / /, $ENV{CFLAGS};
my @ldflags = split / /, $ENV{LDFLAGS};
$cc = "cc" if ($cc eq "");
sub generate_cfile($$$)
{
my ($filename, $fragment, $incfiles) = @_;
unless (open (OUT, ">$filename")) {
print STDERR "Unable to open $filename\n";
return -1;
}
print OUT '
/* This file was autogenerated. All changes made will be lost! */
#include "include/includes.h"
';
foreach (@$incfiles) {
print OUT "#include \"$_\"\n";
}
print OUT '
int main(int argc, char **argv)
{
TALLOC_CTX *mem_ctx = talloc_init(NULL);
';
print OUT $fragment;
print OUT "\treturn 0;\n}\n";
close OUT;
return 0;
}
sub generate_idlfile($$)
{
my ($filename,$fragment) = @_;
unless (open(OUT, ">$filename")) {
print STDERR "Unable to open $filename\n";
return -1;
}
print OUT '
[uuid("1-2-3-4-5")] interface test_if
{
';
print OUT $fragment;
print OUT "\n}\n";
close OUT;
return 0;
}
sub compile_idl($$$)
{
my ($filename,$idl_path, $idlargs) = @_;
my @args = @$idlargs;
push (@args, $filename);
unless (system($idl_path, @args) == 0) {
print STDERR "Error compiling IDL file $filename: $!\n";
return -1;
}
}
sub compile_cfile($)
{
my ($filename) = @_;
return system($cc, @cflags, '-I.', '-Iinclude', '-c', $filename);
}
sub link_files($$)
{
my ($exe_name,$objs) = @_;
return system($cc, @ldflags, '-Lbin', '-lrpc', '-o', $exe_name, @$objs);
}
sub test_idl($$$$)
{
my ($name,$settings,$idl,$c) = @_;
$| = 1;
print "Running $name... ";
my $outputdir = $settings->{OutputDir};
my $c_filename = $outputdir."/".$name."_test.c";
my $idl_filename = $outputdir."/".$name."_idl.idl";
my $exe_filename = $outputdir."/".$name."_exe";
return -1 if (generate_cfile($c_filename, $c, $settings->{IncludeFiles}) == -1);
return -1 if (generate_idlfile($idl_filename, $idl) == -1);
return -1 if (compile_idl($idl_filename, $settings->{'IDL-Compiler'}, $settings->{'IDL-Arguments'}) == -1);
my @srcs = ($c_filename);
push (@srcs, @{$settings->{'ExtraFiles'}});
foreach (@srcs) {
next unless /\.c$/;
return -1 if (compile_cfile($_) == -1);
}
my @objs;
foreach (@srcs) {
if (/\.c$/) { s/\.c$/\.o/g; }
push(@objs, $_);
}
return -1 if (link_files($exe_filename, \@objs) == -1);
my $ret = system("./$exe_filename");
if ($ret != 0) {
$ret = $? >> 8;
print "failed with return value $ret\n";
return $ret;
}
unless ($settings->{Keep}) {
unlink(@srcs, @objs, $exe_filename, $idl_filename);
}
print "Ok\n";
return $ret;
}
sub GetSettings($)
{
my $settings = {
OutputDir => ".",
'IDL-Compiler' => "./pidl"
};
my %opts = ();
GetOptions('idl-compiler=s' => \$settings->{'IDL-Compiler'},
'outputdir=s' => \$settings->{OutputDir},
'keep' => \$settings->{Keep},
'help' => sub { ShowHelp(); exit 1; } );
return %$settings;
}
sub ShowHelp()
{
print " --idl-compiler=PATH-TO-PIDL Override path to IDL compiler\n";
print " --outputdir=OUTPUTDIR Write temporary files to OUTPUTDIR rather then .\n";
print " --keep Keep intermediate files after running test";
print " --help Show this help message\n";
}
1;

View File

@ -0,0 +1,336 @@
###################################################
# 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 = qw(hasType getType mapType);
use Parse::Pidl::Util qw(has_property);
use strict;
my %typedefs = ();
# a list of known scalar types
my $scalars = {
# 0 byte types
"void" => {
C_TYPE => "void",
IS_REFERENCE => 0,
NDR_ALIGN => 0
},
# 1 byte types
"char" => {
C_TYPE => "char",
IS_REFERENCE => 0,
NDR_ALIGN => 1
},
"int8" => {
C_TYPE => "int8_t",
IS_REFERENCE => 0,
NDR_ALIGN => 1
},
"uint8" => {
C_TYPE => "uint8_t",
IS_REFERENCE => 0,
NDR_ALIGN => 1
},
# 2 byte types
"int16" => {
C_TYPE => "int16_t",
IS_REFERENCE => 0,
NDR_ALIGN => 2
},
"uint16" => { C_TYPE => "uint16_t",
IS_REFERENCE => 0,
NDR_ALIGN => 2
},
# 4 byte types
"int32" => {
C_TYPE => "int32_t",
IS_REFERENCE => 0,
NDR_ALIGN => 4
},
"uint32" => { C_TYPE => "uint32_t",
IS_REFERENCE => 0,
NDR_ALIGN => 4
},
# 8 byte types
"hyper" => {
C_TYPE => "uint64_t",
IS_REFERENCE => 0,
NDR_ALIGN => 8
},
"dlong" => {
C_TYPE => "int64_t",
IS_REFERENCE => 0,
NDR_ALIGN => 4
},
"udlong" => {
C_TYPE => "uint64_t",
IS_REFERENCE => 0,
NDR_ALIGN => 4
},
"udlongr" => {
C_TYPE => "uint64_t",
IS_REFERENCE => 0,
NDR_ALIGN => 4
},
# DATA_BLOB types
"DATA_BLOB" => {
C_TYPE => "DATA_BLOB",
IS_REFERENCE => 0,
NDR_ALIGN => 4
},
# string types
"string" => {
C_TYPE => "const char *",
IS_REFERENCE => 1,
NDR_ALIGN => 4 #???
},
"string_array" => {
C_TYPE => "const char **",
IS_REFERENCE => 1,
NDR_ALIGN => 4 #???
},
# time types
"time_t" => {
C_TYPE => "time_t",
IS_REFERENCE => 0,
NDR_ALIGN => 4
},
"NTTIME" => {
C_TYPE => "NTTIME",
IS_REFERENCE => 0,
NDR_ALIGN => 4
},
"NTTIME_1sec" => {
C_TYPE => "NTTIME",
IS_REFERENCE => 0,
NDR_ALIGN => 4
},
"NTTIME_hyper" => {
C_TYPE => "NTTIME",
IS_REFERENCE => 0,
NDR_ALIGN => 8
},
# error code types
"WERROR" => {
C_TYPE => "WERROR",
IS_REFERENCE => 0,
NDR_ALIGN => 4
},
"NTSTATUS" => {
C_TYPE => "NTSTATUS",
IS_REFERENCE => 0,
NDR_ALIGN => 4
},
"COMRESULT" => {
"C_TYPE" => "COMRESULT",
IS_REFERENCE => 0,
NDR_ALIGN => 4
},
# special types
"nbt_string" => {
C_TYPE => "const char *",
IS_REFERENCE => 1,
NDR_ALIGN => 4 #???
},
"ipv4address" => {
C_TYPE => "const char *",
IS_REFERENCE => 1,
NDR_ALIGN => 4
}
};
# map from a IDL type to a C header type
sub mapScalarType($)
{
my $name = shift;
# it's a bug when a type is not in the list
# of known scalars or has no mapping
return $typedefs{$name}->{DATA}->{C_TYPE} if defined($typedefs{$name}) and defined($typedefs{$name}->{DATA}->{C_TYPE});
die("Unknown scalar type $name");
}
sub getScalarAlignment($)
{
my $name = shift;
# it's a bug when a type is not in the list
# of known scalars or has no mapping
return $scalars->{$name}{NDR_ALIGN} if defined($scalars->{$name}) and defined($scalars->{$name}{NDR_ALIGN});
die("Unknown scalar type $name");
}
sub addType($)
{
my $t = shift;
$typedefs{$t->{NAME}} = $t;
}
sub getType($)
{
my $t = shift;
return undef if not hasType($t);
return $typedefs{$t};
}
sub typeIs($$)
{
my $t = shift;
my $tt = shift;
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 $scalars->{$name}{IS_REFERENCE} if defined($scalars->{$name}) and defined($scalars->{$name}{IS_REFERENCE});
return 0;
}
sub RegisterScalars()
{
foreach my $k (keys %{$scalars}) {
$typedefs{$k} = {
NAME => $k,
TYPE => "TYPEDEF",
DATA => $scalars->{$k}
};
$typedefs{$k}->{DATA}->{TYPE} = "SCALAR";
$typedefs{$k}->{DATA}->{NAME} = $k;
}
}
my $aliases = {
"DWORD" => "uint32",
"int" => "int32",
"WORD" => "uint16",
"char" => "uint8",
"long" => "int32",
"short" => "int16",
"HYPER_T" => "hyper",
"HRESULT" => "COMRESULT",
};
sub RegisterAliases()
{
foreach my $k (keys %{$aliases}) {
$typedefs{$k} = $typedefs{$aliases->{$k}};
}
}
sub enum_type_fn($)
{
my $enum = shift;
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;
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;
die("Undef passed to mapType") unless defined($t);
my $dt;
unless ($dt or ($dt = getType($t))) {
# Best guess
return "struct $t";
}
return mapScalarType($t) if ($dt->{DATA}->{TYPE} eq "SCALAR");
return "enum $dt->{NAME}" if ($dt->{DATA}->{TYPE} eq "ENUM");
return "struct $dt->{NAME}" if ($dt->{DATA}->{TYPE} eq "STRUCT");
return "struct $dt->{NAME}" if ($dt->{DATA}->{TYPE} eq "INTERFACE");
return "union $dt->{NAME}" if ($dt->{DATA}->{TYPE} eq "UNION");
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();
RegisterAliases();
1;

View File

@ -0,0 +1,149 @@
###################################################
# 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);
use strict;
#####################################################################
# flatten an array of arrays into a single array
sub FlattenArray2($)
{
my $a = shift;
my @b;
for my $d (@{$a}) {
for my $d1 (@{$d}) {
push(@b, $d1);
}
}
return \@b;
}
#####################################################################
# flatten an array of arrays into a single array
sub FlattenArray($)
{
my $a = shift;
my @b;
for my $d (@{$a}) {
for my $d1 (@{$d}) {
push(@b, $d1);
}
}
return \@b;
}
#####################################################################
# 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;
}
#####################################################################
# 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 . "\"";
}
# 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") 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;

360
tools/pidl/pidl Executable file
View File

@ -0,0 +1,360 @@
#!/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
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_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_ndr_header);
my($opt_template) = 0;
my($opt_client);
my($opt_server);
my($opt_ndr_parser);
my($opt_tdr_header);
my($opt_tdr_parser);
my($opt_eth_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) tridge\@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
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-header[=OUTFILE] create a C NDR-specific header file [ndr_BASENAME.h]
--ndr-parser[=OUTFILE] create a C NDR parser [ndr_BASENAME.c]
--client[=OUTFILE] create a C NDR client [ndr_BASENAME_c.c]
--tdr-header[=OUTFILE] create a C TDR header file [tdr_BASENAME.h]
--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]
Ethereal parsers:
--eth-parser[=OUTFILE] create ethereal parser and header
\n";
exit(0);
}
# main program
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,
'ndr-header:s' => \$opt_ndr_header,
'header:s' => \$opt_header,
'server:s' => \$opt_server,
'tdr-header:s' => \$opt_tdr_header,
'tdr-parser:s' => \$opt_tdr_parser,
'template' => \$opt_template,
'ndr-parser:s' => \$opt_ndr_parser,
'client:s' => \$opt_client,
'eth-parser:s' => \$opt_eth_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
);
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;
my $idl_parser = new Parse::Pidl::IDL;
$pidl = $idl_parser->parse_idl($idl_file);
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);
}
if (defined($opt_com_header)) {
require Parse::Pidl::Samba::COM::Header;
my $res = Parse::Pidl::Samba::COM::Header::Parse($pidl);
if ($res) {
my $comh_filename = ($opt_com_header or "$outputdir/com_$basename.h");
FileSave($comh_filename,
"#include \"librpc/gen_ndr/ndr_orpc.h\"\n" .
"#include \"$outputdir/ndr_$basename.h\"\n" .
$res);
}
}
if (defined($opt_dcom_proxy)) {
require Parse::Pidl::Samba::COM::Proxy;
my $res = Parse::Pidl::Samba::COM::Proxy::Parse($pidl);
if ($res) {
my ($client) = ($opt_dcom_proxy or "$outputdir/$basename\_p.c");
FileSave($client,
"#include \"includes.h\"\n" .
"#include \"$outputdir/com_$basename.h\"\n" .
"#include \"lib/com/dcom/dcom.h\"\n" .$res);
}
}
if ($opt_warn_compat) {
require Parse::Pidl::Compat;
Parse::Pidl::Compat::Check($pidl);
}
$pidl = Parse::Pidl::ODL::ODL2IDL($pidl);
if (defined($opt_ndr_header) or defined($opt_eth_parser) or
defined($opt_client) or defined($opt_server) or
defined($opt_ndr_parser) or defined($opt_ejs) or
defined($opt_dump_ndr_tree)) {
require Parse::Pidl::NDR;
Parse::Pidl::NDR::Validate($pidl);
$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";
}
if (defined($opt_header)) {
my $header = ($opt_header or "$outputdir/$basename.h");
require Parse::Pidl::Samba::Header;
FileSave($header, Parse::Pidl::Samba::Header::Parse($pidl));
}
if (defined($opt_ndr_header)) {
my $header = ($opt_ndr_header or "$outputdir/ndr_$basename.h");
require Parse::Pidl::Samba::NDR::Header;
FileSave($header, Parse::Pidl::Samba::NDR::Header::Parse($pidl, $basename));
if (defined($opt_swig)) {
require Parse::Pidl::Samba::SWIG;
my($filename) = ($opt_swig or "$outputdir/$basename.i");
Parse::Pidl::Samba::SWIG::RewriteHeader($pidl, $header, $filename);
}
}
my $h_filename = "$outputdir/ndr_$basename.h";
if (defined($opt_client)) {
require Parse::Pidl::Samba::NDR::Client;
my ($client) = ($opt_client or "$outputdir/ndr_$basename\_c.c");
FileSave($client, Parse::Pidl::Samba::NDR::Client::Parse($ndr,$h_filename));
}
if (defined($opt_ejs)) {
require Parse::Pidl::Samba::EJS;
require Parse::Pidl::Samba::EJSHeader;
FileSave("$outputdir/ndr_$basename\_ejs.c", Parse::Pidl::Samba::EJS::Parse($ndr, $h_filename));
FileSave("$outputdir/ndr_$basename\_ejs.h", Parse::Pidl::Samba::EJSHeader::Parse($ndr));
}
if (defined($opt_server)) {
require Parse::Pidl::Samba::NDR::Server;
my $dcom = "";
foreach my $x (@{$pidl}) {
next if ($x->{TYPE} ne "INTERFACE");
if (Parse::Pidl::Util::has_property($x, "object")) {
require Parse::Pidl::Samba::COM::Stub;
$dcom .= Parse::Pidl::Samba::COM::Stub::ParseInterface($x);
}
}
FileSave(($opt_server or "$outputdir/ndr_$basename\_s.c"), Parse::Pidl::Samba::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 = ($opt_ndr_parser or "$outputdir/ndr_$basename.c");
require Parse::Pidl::Samba::NDR::Parser;
FileSave($parser, Parse::Pidl::Samba::NDR::Parser::Parse($ndr, $parser));
}
if (defined($opt_eth_parser)) {
require Parse::Pidl::Ethereal::NDR;
my($eparser) = ($opt_eth_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::Ethereal::NDR::Parse($ndr, $idl_file, $eheader, $cnffile);
FileSave($eparser, $dp) if defined($dp);
FileSave($eheader, $dh) if defined($dh);
}
my $tdr_parser = ($opt_tdr_parser or "$outputdir/tdr_$basename.c");
my $tdr_header = ($opt_tdr_header or "$outputdir/tdr_$basename.h");
if (defined($opt_tdr_parser)) {
require Parse::Pidl::Samba::TDR;
FileSave($tdr_parser, Parse::Pidl::Samba::TDR::Parser($pidl, $tdr_header));
}
if (defined($opt_tdr_header)) {
require Parse::Pidl::Samba::TDR;
FileSave($tdr_header, Parse::Pidl::Samba::TDR::Header($pidl, $outputdir,$basename));
}
if ($opt_template) {
require Parse::Pidl::Samba::Template;
print Parse::Pidl::Samba::Template::Parse($pidl);
}
}
if (scalar(@ARGV) == 0) {
print "pidl: no input files\n";
exit(0);
}
process_file($_) foreach (@ARGV);

606
tools/pidl/pidl.1.xml Normal file
View File

@ -0,0 +1,606 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
<refentry id="pidl.1">
<refmeta>
<refentrytitle>pidl</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>pidl</refname>
<refpurpose>IDL Compiler written in Perl</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>pidl</command>
<arg choice="opt">--help</arg>
<arg choice="opt">--outputdir OUTNAME</arg>
<arg choice="opt">--parse-idl-tree</arg>
<arg choice="opt">--dump-idl-tree</arg>
<arg choice="opt">--dump-ndr-tree</arg>
<arg choice="opt">--ndr-header[=OUTPUT]</arg>
<arg choice="opt">--header[=OUTPUT]</arg>
<arg choice="opt">--ejs[=OUTPUT]</arg>
<arg choice="opt">--swig[=OUTPUT]</arg>
<arg choice="opt">--uint-enums</arg>
<arg choice="opt">--ndr-parser[=OUTPUT]</arg>
<arg choice="opt">--client</arg>
<arg choice="opt">--server</arg>
<arg choice="opt">--dcom-proxy</arg>
<arg choice="opt">--com-header</arg>
<arg choice="opt">--warn-compat</arg>
<arg choice="opt">--quiet</arg>
<arg choice="opt">--verbose</arg>
<arg choice="opt">--template</arg>
<arg choice="opt">--eth-parser[=OUTPUT]</arg>
<arg choice="opt">--diff</arg>
<arg choice="opt">--dump-idl</arg>
<arg choice="req">idlfile</arg>
<arg choice="opt">idlfile2</arg>
<arg choice="opt">...</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>DESCRIPTION</title>
<para>pidl is an IDL compiler written in Perl that aims to be somewhat
compatible with the midl compiler. IDL stands for
"Interface Definition Language".</para>
<para>pidl can generate stubs for DCE/RPC server code, DCE/RPC
client code and ethereal dissectors for DCE/RPC traffic.</para>
<para>IDL compilers like <emphasis>pidl</emphasis> 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 ethereal
dissectors that can parse data sent over the
wire by these interfaces. </para>
<para>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.
</para>
<para>
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).
</para>
</refsect1>
<refsect1>
<title>OPTIONS</title>
<variablelist>
<varlistentry>
<term>--help</term>
<listitem><para>
Show list of available options.</para></listitem>
</varlistentry>
<varlistentry>
<term>--outputdir OUTNAME</term>
<listitem><para>Write output files to the specified directory.
Defaults to the current directory.
</para></listitem>
</varlistentry>
<varlistentry>
<term>--parse-idl-tree</term>
<listitem><para>
Read internal tree structure from input files rather
then assuming they contain IDL.</para></listitem>
</varlistentry>
<varlistentry>
<term>--dump-idl</term>
<listitem><para>
Generate a new IDL file. File will be named OUTNAME.idl.</para></listitem>
</varlistentry>
<varlistentry>
<term>--header</term>
<listitem><para>
Generate a C header file for the specified interface. Filename defaults to OUTNAME.h.</para></listitem>
</varlistentry>
<varlistentry>
<term>--ndr-header</term>
<listitem><para>
Generate a C header file with the prototypes for the NDR parsers. Filename defaults to ndr_OUTNAME.h.</para></listitem>
</varlistentry>
<varlistentry>
<term>--ndr-parser</term>
<listitem><para>
Generate a C file containing NDR parsers.
Filename defaults to ndr_OUTNAME.c.
</para></listitem>
</varlistentry>
<varlistentry>
<term>--server</term>
<listitem><para>
Generate boilerplate for the RPC server that implements
the interface. Filename defaults to ndr_OUTNAME_s.c</para></listitem>
</varlistentry>
<varlistentry>
<term>--template</term>
<listitem><para>
Generate stubs for a RPC server that implements
the interface. Output will be written to stdout.
</para></listitem>
</varlistentry>
<varlistentry>
<term>--eth-parser</term>
<listitem><para>
Generate an Ethereal dissector (in C) for the interface. Filename
defaults to packet-dcerpc-OUTNAME.c.
</para>
<para>Pidl will read additional data
from an ethereal conformance file if present. Such a file should
have the same location as the IDL file but with the extension
<quote>cnf</quote> rather then <quote>idl</quote>. See
below for details on the format of this file.
</para></listitem>
</varlistentry>
<varlistentry>
<term>--diff</term>
<listitem><para>
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.</para></listitem>
</varlistentry>
<varlistentry>
<term>--dump-idl-tree</term>
<listitem><para>
Tell pidl to dump the internal tree representation of an IDL
file the to disk. Useful
for debugging pidl.</para></listitem>
</varlistentry>
<varlistentry>
<term>--dump-ndr-tree</term>
<listitem><para>
Tell pidl to dump the internal NDR information tree it generated
from the IDL file to disk. Useful for debugging pidl.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>IDL SYNTAX</title>
<para>IDL files are always preprocessed using the C preprocessor.</para>
<para>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. </para>
<para>See the section COMPATIBILITY for the list of attributes that
pidl supports.</para>
<para>C-style comments can be used.</para>
<refsect2>
<title>CONFORMANT ARRAYS</title>
<para>
A conformant array is one with that ends in [*] or []. The strange
things about conformant arrays are:
</para>
<simplelist>
<member>they can only appear as the last element of a structure</member>
<member>the array size appears before the structure itself on the wire. </member>
</simplelist>
<para>
So, in this example:
</para>
<programlisting>
typedef struct {
long abc;
long count;
long foo;
[size_is(count)] long s[*];
} Struct1;
</programlisting>
<para>
it appears like this:
</para>
<programlisting>
[size_is] [abc] [count] [foo] [s...]
</programlisting>
<para>
the first [size_is] field is the allocation size of the array, and
occurs before the array elements and even before the structure
alignment.
</para>
<para>
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.
</para>
<para>
midl.exe would write the above array as the following C header:
</para>
<programlisting>
typedef struct {
long abc;
long count;
long foo;
long s[1];
} Struct1;
</programlisting>
<para>
pidl takes a different approach, and writes it like this:
</para>
<programlisting>
typedef struct {
long abc;
long count;
long foo;
long *s;
} Struct1;
</programlisting>
</refsect2>
<refsect2>
<title>VARYING ARRAYS</title>
<para>
A varying array looks like this:
</para>
<programlisting>
typedef struct {
long abc;
long count;
long foo;
[size_is(count)] long *s;
} Struct1;
</programlisting>
<para>
This will look like this on the wire:
</para>
<programlisting>
[abc] [count] [foo] [PTR_s] [count] [s...]
</programlisting>
</refsect2>
<refsect2>
<title>FIXED ARRAYS</title>
<para>
A fixed array looks like this:
</para>
<programlisting>
typedef struct {
long s[10];
} Struct1;
</programlisting>
<para>
The NDR representation looks just like 10 separate long
declarations. The array size is not encoded on the wire.
</para>
<para>
pidl also supports "inline" arrays, which are not part of the IDL/NDR
standard. These are declared like this:
</para>
<programlisting>
typedef struct {
uint32 foo;
uint32 count;
uint32 bar;
long s[count];
} Struct1;
</programlisting>
<para>
This appears like this:
</para>
<programlisting>
[foo] [count] [bar] [s...]
</programlisting>
<para>
Fixed arrays are an extension added to support some of the strange
embedded structures in security descriptors and spoolss.
</para>
</refsect2>
<para>This section is by no means complete. See the OpenGroup and MSDN
documentation for additional information.</para>
</refsect1>
<refsect1>
<title>COMPATIBILITY WITH MIDL</title>
<refsect2>
<title>Missing features in pidl</title>
<para>
The following MIDL features are not (yet) implemented in pidl
or are implemented with an incompatible interface:
</para>
<simplelist>
<member>Asynchronous communication</member>
<member>Typelibs (.tlb files)</member>
<member>Datagram support (ncadg_*)</member>
</simplelist>
</refsect2>
<refsect2>
<title>Supported properties (attributes is the MIDL term)</title>
<para>
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.
</para>
</refsect2>
<refsect2>
<title>PIDL Specific properties</title>
<variablelist>
<varlistentry><term>public</term>
<listitem><para>
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.
</para></listitem>
</varlistentry>
<varlistentry><term>noprint</term>
<listitem><para>
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.
</para></listitem>
</varlistentry>
<varlistentry><term>value</term>
<listitem><para>
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.
</para></listitem>
</varlistentry>
<varlistentry><term>relative</term>
<listitem><para>
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.
</para></listitem>
</varlistentry>
<varlistentry><term>subcontext(length)</term>
<listitem><para>
Specifies that a size of <replaceable>length</replaceable>
bytes should be read, followed by a blob of that size,
which will be parsed as NDR.
</para></listitem>
</varlistentry>
<varlistentry><term>flag</term>
<listitem><para>
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!
</para></listitem>
</varlistentry>
<varlistentry><term>nodiscriminant</term>
<listitem><para>
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.
</para></listitem>
</varlistentry>
<varlistentry><term>charset(name)</term>
<listitem><para>
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.
</para></listitem>
</varlistentry>
</variablelist>
</refsect2>
<refsect2>
<title>Unsupported MIDL properties</title>
<para>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, import, include, 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, transmit_as, uidefault, usesgetlasterror, vararg, vi_progid, wire_marshal. </para>
</refsect2>
</refsect1>
<refsect1>
<title>ETHEREAL CONFORMANCE FILES</title>
<para>
Pidl needs additional data for ethereal output. This data is read from
so-called conformance files. This section describes the format of these
files.</para>
<para>
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.
</para>
<para>
The following commands are currently supported:
</para>
<variablelist>
<varlistentry>
<term>TYPE name dissector ft_type base_type mask valsstring alignment</term>
<listitem><para>Register new data type with specified name, what dissector function to call and what properties to give header fields for elements of this type.</para></listitem>
</varlistentry>
<varlistentry>
<term>NOEMIT type</term>
<listitem><para>
Suppress emitting a dissect_type function for the specified type
</para></listitem>
</varlistentry>
<varlistentry>
<term>PARAM_VALUE type param</term>
<listitem><para>
Set parameter to specify to dissector function for given type.
</para></listitem>
</varlistentry>
<varlistentry>
<term>HF_FIELD hf title filter ft_type base_type valsstring mask description</term>
<listitem><para>
Generate a custom header field with specified properties.
</para></listitem>
</varlistentry>
<varlistentry>
<term>HF_RENAME old_hf_name new_hf_name</term>
<listitem><para>
Force the use of new_hf_name when the parser generator was going to
use old_hf_name.
</para>
<para>
This can be used in conjunction with HF_FIELD in order to make more then
one element use the same filter name.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>STRIP_PREFIX prefix</term>
<listitem><para>
Remove the specified prefix from all function names (if present).
</para></listitem>
</varlistentry>
<varlistentry>
<term>PROTOCOL longname shortname filtername</term>
<listitem><para>
Change the short-, long- and filter-name for the current interface in
Ethereal.
</para></listitem>
</varlistentry>
<varlistentry>
<term>FIELD_DESCRIPTION field desc</term>
<listitem><para>Change description for the specified header field. `field' is the hf name of the field.
</para></listitem>
</varlistentry>
<varlistentry>
<term>IMPORT dissector code...</term>
<listitem><para>
Code to insert when generating the specified dissector. @HF@ and
@PARAM@ will be substituted.
</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>EXAMPLES</title>
<programlisting>
# Generating an ethereal parser
$ ./pidl --eth-parser -- atsvc.idl
# Generating a TDR parser
$ ./pidl --tdr-parser --tdr-header --header -- regf.idl
</programlisting>
</refsect1>
<refsect1>
<title>VERSION</title>
<para>This man page is correct for version 4.0 of the Samba suite.</para>
</refsect1>
<refsect1>
<title>SEE ALSO</title>
<para><ulink url="http://msdn.microsoft.com/library/en-us/rpc/rpc/field_attributes.asp">Field Attributes [Remote Procedure Call]</ulink>, <ulink url="http://wiki.ethereal.com/DCE/RPC">Ethereal Wiki on DCE/RPC</ulink>.</para>
</refsect1>
<refsect1>
<title>AUTHOR</title>
<para>pidl was written by Andrew Tridgell, Stefan Metzmacher, Tim
Potter and Jelmer Vernooij. </para>
<para>This manpage was written by Jelmer Vernooij, partially based on the original pidl README by Andrew Tridgell. </para>
</refsect1>
</refentry>

0
tools/pidl/pm_to_blib Normal file
View File

220
tools/pidl/ref_notes.txt Normal file
View File

@ -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]

1272
tools/pidl/smb_interfaces.pm Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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);
}