use vars qw($VERSION);
$VERSION = '0.01';
@ISA = qw(Exporter);
-@EXPORT = qw(GetPrevLevel GetNextLevel ContainsDeferred ContainsString);
+@EXPORT = qw(GetPrevLevel GetNextLevel ContainsDeferred ContainsPipe ContainsString);
@EXPORT_OK = qw(GetElementLevelTable ParseElement ValidElement align_type mapToScalar ParseType can_contain_deferred is_charset_array);
use strict;
use Parse::Pidl qw(warning fatal);
-use Parse::Pidl::Typelist qw(hasType getType expandAlias);
+use Parse::Pidl::Typelist qw(hasType getType typeIs expandAlias mapScalarType is_fixed_size_scalar);
use Parse::Pidl::Util qw(has_property property_matches);
# Alignment of the built-in scalar types
'uint8' => 1,
'int16' => 2,
'uint16' => 2,
+ 'int1632' => 3,
+ 'uint1632' => 3,
'int32' => 4,
'uint32' => 4,
+ 'int3264' => 5,
+ 'uint3264' => 5,
'hyper' => 8,
'double' => 8,
'pointer' => 8,
'string' => 4,
'string_array' => 4, #???
'time_t' => 4,
+ 'uid_t' => 8,
+ 'gid_t' => 8,
'NTTIME' => 4,
'NTTIME_1sec' => 4,
'NTTIME_hyper' => 8,
'WERROR' => 4,
'NTSTATUS' => 4,
'COMRESULT' => 4,
+ 'dns_string' => 4,
'nbt_string' => 4,
'wrepl_nbt_name' => 4,
- 'ipv4address' => 4
+ 'ipv4address' => 4,
+ 'ipv6address' => 4, #16?
+ 'dnsp_name' => 1,
+ 'dnsp_string' => 1
};
-sub GetElementLevelTable($$)
+sub GetElementLevelTable($$$)
{
- my ($e, $pointer_default) = @_;
+ my ($e, $pointer_default, $ms_union) = @_;
my $order = [];
my $is_deferred = 0;
if (has_property($e, "out")) {
my $needptrs = 1;
- if (has_property($e, "string")) { $needptrs++; }
+ if (has_property($e, "string") and not has_property($e, "in")) { $needptrs++; }
if ($#bracket_array >= 0) { $needptrs = 0; }
warning($e, "[out] argument `$e->{NAME}' not a pointer") if ($needptrs > $e->{POINTERS});
}
+ my $allow_pipe = ($e->{PARENT}->{TYPE} eq "FUNCTION");
+ my $is_pipe = typeIs($e->{TYPE}, "PIPE");
+
+ if ($is_pipe) {
+ if (not $allow_pipe) {
+ fatal($e, "argument `$e->{NAME}' is a pipe and not allowed on $e->{PARENT}->{TYPE}");
+ }
+
+ if ($e->{POINTERS} > 1) {
+ fatal($e, "$e->{POINTERS} are not allowed on pipe element $e->{NAME}");
+ }
+
+ if ($e->{POINTERS} < 0) {
+ fatal($e, "pipe element $e->{NAME} needs pointer");
+ }
+
+ if ($e->{POINTERS} == 1 and pointer_type($e) ne "ref") {
+ fatal($e, "pointer should be 'ref' on pipe element $e->{NAME}");
+ }
+
+ if (scalar(@size_is) > 0) {
+ fatal($e, "size_is() on pipe element");
+ }
+
+ if (scalar(@length_is) > 0) {
+ fatal($e, "length_is() on pipe element");
+ }
+
+ if (scalar(@bracket_array) > 0) {
+ fatal($e, "brackets on pipe element");
+ }
+
+ if (defined(has_property($e, "subcontext"))) {
+ fatal($e, "subcontext on pipe element");
+ }
+
+ if (has_property($e, "switch_is")) {
+ fatal($e, "switch_is on pipe element");
+ }
+
+ if (can_contain_deferred($e->{TYPE})) {
+ fatal($e, "$e->{TYPE} can_contain_deferred - not allowed on pipe element");
+ }
+ }
+
# Parse the [][][][] style array stuff
for my $i (0 .. $#bracket_array) {
my $d = $bracket_array[$#bracket_array - $i];
if ($d eq "*") {
$is_conformant = 1;
if ($size = shift @size_is) {
+ if ($e->{POINTERS} < 1 and has_property($e, "string")) {
+ $is_string = 1;
+ delete($e->{PROPERTIES}->{string});
+ }
} elsif ((scalar(@size_is) == 0) and has_property($e, "string")) {
$is_string = 1;
delete($e->{PROPERTIES}->{string});
}
}
+ if ($is_pipe) {
+ push (@$order, {
+ TYPE => "PIPE",
+ IS_DEFERRED => 0,
+ CONTAINS_DEFERRED => 0,
+ });
+
+ my $i = 0;
+ foreach (@$order) { $_->{LEVEL_INDEX} = $i; $i+=1; }
+
+ return $order;
+ }
+
if (defined(has_property($e, "subcontext"))) {
my $hdr_size = has_property($e, "subcontext");
my $subsize = has_property($e, "subcontext_size");
return $order;
}
-sub GetTypedefLevelTable($$$)
+sub GetTypedefLevelTable($$$$)
{
- my ($e, $data, $pointer_default) = @_;
+ my ($e, $data, $pointer_default, $ms_union) = @_;
my $order = [];
return "sptr" if (has_property($e, "sptr"));
return "unique" if (has_property($e, "unique"));
return "relative" if (has_property($e, "relative"));
+ return "relative_short" if (has_property($e, "relative_short"));
return "ignore" if (has_property($e, "ignore"));
return undef;
my $a = 1;
if ($e->{POINTERS}) {
- $a = 4;
+ # this is a hack for NDR64
+ # the NDR layer translates this into
+ # an alignment of 4 for NDR and 8 for NDR64
+ $a = 5;
} elsif (has_property($e, "subcontext")) {
$a = 1;
} elsif (has_property($e, "transmit_as")) {
if ($dt->{TYPE} eq "TYPEDEF") {
return align_type($dt->{DATA});
+ } elsif ($dt->{TYPE} eq "CONFORMANCE") {
+ return $dt->{DATA}->{ALIGN};
} elsif ($dt->{TYPE} eq "ENUM") {
return align_type(Parse::Pidl::Typelist::enum_type_fn($dt));
} elsif ($dt->{TYPE} eq "BITMAP") {
# Struct/union without body: assume 4
return 4 unless (defined($dt->{ELEMENTS}));
return find_largest_alignment($dt);
+ } elsif (($dt->{TYPE} eq "PIPE")) {
+ return 5;
}
die("Unknown data type type $dt->{TYPE}");
}
-sub ParseElement($$)
+sub ParseElement($$$)
{
- my ($e, $pointer_default) = @_;
+ my ($e, $pointer_default, $ms_union) = @_;
$e->{TYPE} = expandAlias($e->{TYPE});
if (ref($e->{TYPE}) eq "HASH") {
- $e->{TYPE} = ParseType($e->{TYPE}, $pointer_default);
+ $e->{TYPE} = ParseType($e->{TYPE}, $pointer_default, $ms_union);
}
return {
NAME => $e->{NAME},
TYPE => $e->{TYPE},
PROPERTIES => $e->{PROPERTIES},
- LEVELS => GetElementLevelTable($e, $pointer_default),
+ LEVELS => GetElementLevelTable($e, $pointer_default, $ms_union),
REPRESENTATION_TYPE => ($e->{PROPERTIES}->{represent_as} or $e->{TYPE}),
ALIGN => align_type($e->{TYPE}),
ORIGINAL => $e
};
}
-sub ParseStruct($$)
+sub ParseStruct($$$)
{
- my ($struct, $pointer_default) = @_;
+ my ($struct, $pointer_default, $ms_union) = @_;
my @elements = ();
my $surrounding = undef;
foreach my $x (@{$struct->{ELEMENTS}})
{
- my $e = ParseElement($x, $pointer_default);
+ my $e = ParseElement($x, $pointer_default, $ms_union);
if ($x != $struct->{ELEMENTS}[-1] and
$e->{LEVELS}[0]->{IS_SURROUNDING}) {
fatal($x, "conformant member not at end of struct");
sub ParseUnion($$)
{
- my ($e, $pointer_default) = @_;
+ my ($e, $pointer_default, $ms_union) = @_;
my @elements = ();
+ my $is_ms_union = $ms_union;
+ $is_ms_union = 1 if has_property($e, "ms_union");
my $hasdefault = 0;
my $switch_type = has_property($e, "switch_type");
unless (defined($switch_type)) { $switch_type = "uint32"; }
ELEMENTS => undef,
PROPERTIES => $e->{PROPERTIES},
HAS_DEFAULT => $hasdefault,
- ORIGINAL => $e
+ IS_MS_UNION => $is_ms_union,
+ ORIGINAL => $e,
+ ALIGN => undef
} unless defined($e->{ELEMENTS});
CheckPointerTypes($e, $pointer_default);
if ($x->{TYPE} eq "EMPTY") {
$t = { TYPE => "EMPTY" };
} else {
- $t = ParseElement($x, $pointer_default);
+ $t = ParseElement($x, $pointer_default, $ms_union);
}
if (has_property($x, "default")) {
$t->{CASE} = "default";
push @elements, $t;
}
+ my $align = undef;
+ if ($e->{NAME}) {
+ $align = align_type($e->{NAME});
+ }
+
return {
TYPE => "UNION",
NAME => $e->{NAME},
ELEMENTS => \@elements,
PROPERTIES => $e->{PROPERTIES},
HAS_DEFAULT => $hasdefault,
- ORIGINAL => $e
+ IS_MS_UNION => $is_ms_union,
+ ORIGINAL => $e,
+ ALIGN => $align
};
}
sub ParseEnum($$)
{
- my ($e, $pointer_default) = @_;
+ my ($e, $pointer_default, $ms_union) = @_;
return {
TYPE => "ENUM",
};
}
-sub ParseBitmap($$)
+sub ParseBitmap($$$)
{
- my ($e, $pointer_default) = @_;
+ my ($e, $pointer_default, $ms_union) = @_;
return {
TYPE => "BITMAP",
};
}
-sub ParseType($$)
+sub ParsePipe($$$)
+{
+ my ($pipe, $pointer_default, $ms_union) = @_;
+
+ my $pname = $pipe->{NAME};
+ $pname = $pipe->{PARENT}->{NAME} unless defined $pname;
+
+ if (not defined($pipe->{PROPERTIES})
+ and defined($pipe->{PARENT}->{PROPERTIES})) {
+ $pipe->{PROPERTIES} = $pipe->{PARENT}->{PROPERTIES};
+ }
+
+ if (ref($pipe->{DATA}) eq "HASH") {
+ if (not defined($pipe->{DATA}->{PROPERTIES})
+ and defined($pipe->{PROPERTIES})) {
+ $pipe->{DATA}->{PROPERTIES} = $pipe->{PROPERTIES};
+ }
+ }
+
+ my $struct = ParseStruct($pipe->{DATA}, $pointer_default, $ms_union);
+ $struct->{ALIGN} = 5;
+ $struct->{NAME} = "$pname\_chunk";
+
+ # 'count' is element [0] and 'array' [1]
+ my $e = $struct->{ELEMENTS}[1];
+ # level [0] is of type "ARRAY"
+ my $l = $e->{LEVELS}[1];
+
+ # here we check that pipe elements have a fixed size type
+ while (defined($l)) {
+ my $cl = $l;
+ $l = GetNextLevel($e, $cl);
+ if ($cl->{TYPE} ne "DATA") {
+ fatal($pipe, el_name($pipe) . ": pipe contains non DATA level");
+ }
+
+ # for now we only support scalars
+ next if is_fixed_size_scalar($cl->{DATA_TYPE});
+
+ fatal($pipe, el_name($pipe) . ": pipe contains non fixed size type[$cl->{DATA_TYPE}]");
+ }
+
+ return {
+ TYPE => "PIPE",
+ NAME => $pipe->{NAME},
+ DATA => $struct,
+ PROPERTIES => $pipe->{PROPERTIES},
+ ORIGINAL => $pipe,
+ };
+}
+
+sub ParseType($$$)
{
- my ($d, $pointer_default) = @_;
+ my ($d, $pointer_default, $ms_union) = @_;
my $data = {
STRUCT => \&ParseStruct,
ENUM => \&ParseEnum,
BITMAP => \&ParseBitmap,
TYPEDEF => \&ParseTypedef,
- }->{$d->{TYPE}}->($d, $pointer_default);
+ PIPE => \&ParsePipe,
+ }->{$d->{TYPE}}->($d, $pointer_default, $ms_union);
return $data;
}
sub ParseTypedef($$)
{
- my ($d, $pointer_default) = @_;
+ my ($d, $pointer_default, $ms_union) = @_;
- if (defined($d->{DATA}->{PROPERTIES}) && !defined($d->{PROPERTIES})) {
- $d->{PROPERTIES} = $d->{DATA}->{PROPERTIES};
- }
+ my $data;
+
+ if (ref($d->{DATA}) eq "HASH") {
+ if (defined($d->{DATA}->{PROPERTIES})
+ and not defined($d->{PROPERTIES})) {
+ $d->{PROPERTIES} = $d->{DATA}->{PROPERTIES};
+ }
- my $data = ParseType($d->{DATA}, $pointer_default);
- $data->{ALIGN} = align_type($d->{NAME});
+ $data = ParseType($d->{DATA}, $pointer_default, $ms_union);
+ $data->{ALIGN} = align_type($d->{NAME});
+ } else {
+ $data = getType($d->{DATA});
+ }
return {
NAME => $d->{NAME},
TYPE => $d->{TYPE},
PROPERTIES => $d->{PROPERTIES},
- LEVELS => GetTypedefLevelTable($d, $data, $pointer_default),
+ LEVELS => GetTypedefLevelTable($d, $data, $pointer_default, $ms_union),
DATA => $data,
ORIGINAL => $d
};
return $d;
}
-sub ParseFunction($$$)
+sub ParseFunction($$$$)
{
- my ($ndr,$d,$opnum) = @_;
+ my ($ndr,$d,$opnum,$ms_union) = @_;
my @elements = ();
my $rettype = undef;
my $thisopnum = undef;
}
foreach my $x (@{$d->{ELEMENTS}}) {
- my $e = ParseElement($x, $ndr->{PROPERTIES}->{pointer_default});
+ my $e = ParseElement($x, $ndr->{PROPERTIES}->{pointer_default}, $ms_union);
push (@{$e->{DIRECTION}}, "in") if (has_property($x, "in"));
push (@{$e->{DIRECTION}}, "out") if (has_property($x, "out"));
$rettype = expandAlias($d->{RETURN_TYPE});
}
- my $async = 0;
- if (has_property($d, "async")) { $async = 1; }
-
return {
NAME => $d->{NAME},
TYPE => "FUNCTION",
OPNUM => $thisopnum,
- ASYNC => $async,
RETURN_TYPE => $rettype,
PROPERTIES => $d->{PROPERTIES},
ELEMENTS => \@elements,
my @endpoints;
my $opnum = 0;
my $version;
+ my $ms_union = 0;
+ $ms_union = 1 if has_property($idl, "ms_union");
if (not has_property($idl, "pointer_default")) {
# MIDL defaults to "ptr" in DCE compatible mode (/osf)
foreach my $d (@{$idl->{DATA}}) {
if ($d->{TYPE} eq "FUNCTION") {
- push (@functions, ParseFunction($idl, $d, \$opnum));
+ push (@functions, ParseFunction($idl, $d, \$opnum, $ms_union));
} elsif ($d->{TYPE} eq "CONST") {
push (@consts, ParseConst($idl, $d));
} else {
- push (@types, ParseType($d, $idl->{PROPERTIES}->{pointer_default}));
+ push (@types, ParseType($d, $idl->{PROPERTIES}->{pointer_default}, $ms_union));
FindNestedTypes(\@types, $d);
}
}
return 0;
}
+sub ContainsPipe($$)
+{
+ my ($e,$l) = @_;
+
+ return 1 if ($l->{TYPE} eq "PIPE");
+
+ while ($l = GetNextLevel($e,$l))
+ {
+ return 1 if ($l->{TYPE} eq "PIPE");
+ }
+
+ return 0;
+}
+
sub el_name($)
{
my $e = shift;
"helper" => ["INTERFACE"],
"pyhelper" => ["INTERFACE"],
"authservice" => ["INTERFACE"],
- "restricted" => ["INTERFACE"],
+ "restricted" => ["INTERFACE"],
+ "no_srv_register" => ["INTERFACE"],
# dcom
"object" => ["INTERFACE"],
"noopnum" => ["FUNCTION"],
"in" => ["ELEMENT"],
"out" => ["ELEMENT"],
- "async" => ["FUNCTION"],
# pointer
- "ref" => ["ELEMENT"],
- "ptr" => ["ELEMENT"],
- "unique" => ["ELEMENT"],
+ "ref" => ["ELEMENT", "TYPEDEF"],
+ "ptr" => ["ELEMENT", "TYPEDEF"],
+ "unique" => ["ELEMENT", "TYPEDEF"],
"ignore" => ["ELEMENT"],
- "relative" => ["ELEMENT"],
- "null_is_ffffffff" => ["ELEMENT"],
+ "relative" => ["ELEMENT", "TYPEDEF"],
+ "relative_short" => ["ELEMENT", "TYPEDEF"],
+ "null_is_ffffffff" => ["ELEMENT"],
"relative_base" => ["TYPEDEF", "STRUCT", "UNION"],
"gensize" => ["TYPEDEF", "STRUCT", "UNION"],
"value" => ["ELEMENT"],
- "flag" => ["ELEMENT", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP"],
+ "flag" => ["ELEMENT", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP", "PIPE"],
# generic
- "public" => ["FUNCTION", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP"],
- "nopush" => ["FUNCTION", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP"],
- "nopull" => ["FUNCTION", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP"],
+ "public" => ["FUNCTION", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP", "PIPE"],
+ "nopush" => ["FUNCTION", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP", "PIPE"],
+ "nopull" => ["FUNCTION", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP", "PIPE"],
"nosize" => ["FUNCTION", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP"],
- "noprint" => ["FUNCTION", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP", "ELEMENT"],
+ "noprint" => ["FUNCTION", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP", "ELEMENT", "PIPE"],
+ "nopython" => ["FUNCTION", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP"],
"todo" => ["FUNCTION"],
# union
"switch_is" => ["ELEMENT"],
"switch_type" => ["ELEMENT", "UNION"],
"nodiscriminant" => ["UNION"],
+ "ms_union" => ["INTERFACE", "UNION"],
"case" => ["ELEMENT"],
"default" => ["ELEMENT"],
my $discriminator_type = has_property($type->{DATA}, "switch_type");
$discriminator_type = "uint32" unless defined ($discriminator_type);
- my $t1 = mapToScalar($discriminator_type);
+ my $t1 = mapScalarType(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});
+ my $t2 = mapScalarType(mapToScalar($e2->{TYPE}));
if (not defined($t2)) {
fatal($e, el_name($e) . ": unable to map variable used for switch_is() to scalar");
}
has_property($e, "ptr") or
has_property($e, "unique") or
has_property($e, "relative") or
+ has_property($e, "relative_short") or
has_property($e, "ref"))) {
fatal($e, el_name($e) . " : pointer properties on non-pointer element\n");
}
sub ValidPipe($)
{
my ($pipe) = @_;
- my $data = $pipe->{DATA};
+ my $struct = $pipe->{DATA};
ValidProperties($pipe, "PIPE");
- fatal($pipe, $pipe->{NAME} . ": 'pipe' is not yet supported by pidl");
+ $struct->{PARENT} = $pipe;
+
+ $struct->{FILE} = $pipe->{FILE} unless defined($struct->{FILE});
+ $struct->{LINE} = $pipe->{LINE} unless defined($struct->{LINE});
+
+ ValidType($struct);
}
#####################################################################
ValidProperties($typedef, "TYPEDEF");
+ return unless (ref($data) eq "HASH");
+
$data->{PARENT} = $typedef;
$data->{FILE} = $typedef->{FILE} unless defined($data->{FILE});
$data->{LINE} = $typedef->{LINE} unless defined($data->{LINE});
- ValidType($data) if (ref($data) eq "HASH");
+ ValidType($data);
}
#####################################################################