📄 ndr.pm
字号:
#################################################### Samba4 NDR info tree generator# Copyright tridge@samba.org 2000-2003# Copyright tpot@samba.org 2001# Copyright jelmer@samba.org 2004-2006# released under the GNU GPL=pod=head1 NAMEParse::Pidl::NDR - NDR parsing information generator=head1 DESCRIPTIONReturn a table describing the order in which the parts of an elementshould be parsedPossible level types: - POINTER - ARRAY - SUBCONTEXT - SWITCH - DATA=head1 AUTHORJelmer Vernooij <jelmer@samba.org>=cutpackage Parse::Pidl::NDR;require Exporter;use vars qw($VERSION);$VERSION = '0.01';@ISA = qw(Exporter);@EXPORT = qw(GetPrevLevel GetNextLevel ContainsDeferred ContainsString);@EXPORT_OK = qw(GetElementLevelTable ParseElement ValidElement align_type mapToScalar ParseType can_contain_deferred);use strict;use Parse::Pidl qw(warning fatal);use Parse::Pidl::Typelist qw(hasType getType expandAlias);use Parse::Pidl::Util qw(has_property property_matches);# Alignment of the built-in scalar typesmy $scalar_alignment = { 'void' => 0, 'char' => 1, 'int8' => 1, 'uint8' => 1, 'int16' => 2, 'uint16' => 2, 'int32' => 4, 'uint32' => 4, 'hyper' => 8, 'pointer' => 8, 'dlong' => 4, 'udlong' => 4, 'udlongr' => 4, 'DATA_BLOB' => 4, 'string' => 4, 'string_array' => 4, #??? 'time_t' => 4, 'NTTIME' => 4, 'NTTIME_1sec' => 4, 'NTTIME_hyper' => 8, 'WERROR' => 4, 'NTSTATUS' => 4, 'COMRESULT' => 4, 'nbt_string' => 4, 'wrepl_nbt_name' => 4, 'ipv4address' => 4};sub GetElementLevelTable($){ my $e = shift; my $order = []; my $is_deferred = 0; my @bracket_array = (); my @length_is = (); my @size_is = (); my $pointer_idx = 0; 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}}; } if (has_property($e, "out")) { my $needptrs = 1; if (has_property($e, "string")) { $needptrs++; } if ($#bracket_array >= 0) { $needptrs = 0; } warning($e, "[out] argument `$e->{NAME}' not a pointer") if ($needptrs > $e->{POINTERS}); } # Parse the [][][][] style array stuff for my $i (0 .. $#bracket_array) { my $d = $bracket_array[$#bracket_array - $i]; my $size = $d; my $length = $d; my $is_surrounding = 0; my $is_varying = 0; my $is_conformant = 0; my $is_string = 0; my $is_fixed = 0; my $is_inline = 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 { fatal($e, "Must specify size_is() for conformant array!") } 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; } } $is_fixed = 1 if (not $is_conformant and Parse::Pidl::Util::is_constant($size)); $is_inline = 1 if (not $is_conformant and not Parse::Pidl::Util::is_constant($size)); 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 => $is_fixed, IS_INLINE => $is_inline }); } # 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), POINTER_INDEX => $pointer_idx, IS_DEFERRED => "$is_deferred", LEVEL => $level }); warning($e, "top-level \[out\] pointer `$e->{NAME}' is not a \[ref\] pointer") if ($i == 1 and pointer_type($e) ne "ref" and $e->{PARENT}->{TYPE} eq "FUNCTION" and not has_property($e, "in")); $pointer_idx++; # 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") and $i == $e->{POINTERS}) { $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", SIZE_IS => $array_size, LENGTH_IS => $array_length, IS_DEFERRED => $is_deferred, IS_SURROUNDING => 0, IS_ZERO_TERMINATED => $is_string, 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"), }); } if (my $switch = has_property($e, "switch_is")) { push (@$order, { TYPE => "SWITCH", SWITCH_IS => $switch, IS_DEFERRED => $is_deferred }); } if (scalar(@size_is) > 0) { fatal($e, "size_is() on non-array element"); } if (scalar(@length_is) > 0) { fatal($e, "length_is() on non-array element"); } if (has_property($e, "string")) { fatal($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->{TYPE}), 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($){ sub can_contain_deferred($); my ($type) = @_; return 1 unless (hasType($type)); # assume the worst $type = getType($type); return 0 if (Parse::Pidl::Typelist::is_scalar($type)); return 1 if ($type->{TYPE} eq "DECLARE"); # assume the worst return can_contain_deferred($type->{DATA}) if ($type->{TYPE} eq "TYPEDEF"); return 0 unless defined($type->{ELEMENTS}); foreach (@{$type->{ELEMENTS}}) { return 1 if ($_->{POINTERS}); return 1 if (can_contain_deferred ($_->{TYPE})); } return 0;}sub pointer_type($){ my $e = shift; return undef unless $e->{POINTERS}; return "ref" if (has_property($e, "ref")); return "full" 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 unionsub 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; } elsif (has_property($e, "transmit_as")) { $a = align_type($e->{PROPERTIES}->{transmit_as}); } else { $a = align_type($e->{TYPE}); } $align = $a if ($align < $a); } return $align;}###################################################################### align a typesub align_type($){ sub align_type($); my ($e) = @_; if (ref($e) eq "HASH" and $e->{TYPE} eq "SCALAR") { return $scalar_alignment->{$e->{NAME}}; } 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); if ($dt->{TYPE} eq "TYPEDEF" or $dt->{TYPE} eq "DECLARE") { return align_type($dt->{DATA}); } elsif ($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); } die("Unknown data type type $dt->{TYPE}");}sub ParseElement($$){ my ($e, $pointer_default) = @_; $e->{TYPE} = expandAlias($e->{TYPE}); if (ref($e->{TYPE}) eq "HASH") { $e->{TYPE} = ParseType($e->{TYPE}, $pointer_default); } return { NAME => $e->{NAME}, TYPE => $e->{TYPE}, PROPERTIES => $e->{PROPERTIES}, LEVELS => GetElementLevelTable($e), REPRESENTATION_TYPE => ($e->{PROPERTIES}->{represent_as} or $e->{TYPE}), ALIGN => align_type($e->{TYPE}), ORIGINAL => $e };}sub ParseStruct($$){ my ($struct, $pointer_default) = @_; my @elements = (); my $surrounding = undef; return { TYPE => "STRUCT", NAME => $struct->{NAME}, SURROUNDING_ELEMENT => undef, ELEMENTS => undef, PROPERTIES => $struct->{PROPERTIES}, ORIGINAL => $struct, ALIGN => undef } unless defined($struct->{ELEMENTS}); CheckPointerTypes($struct, $pointer_default); foreach my $x (@{$struct->{ELEMENTS}}) { my $e = ParseElement($x, $pointer_default); if ($x != $struct->{ELEMENTS}[-1] and $e->{LEVELS}[0]->{IS_SURROUNDING}) { fatal($x, "conformant member not at end of struct"); } push @elements, $e; } 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]; } my $align = undef; if ($struct->{NAME}) { $align = align_type($struct->{NAME}); } return { TYPE => "STRUCT", NAME => $struct->{NAME}, SURROUNDING_ELEMENT => $surrounding, ELEMENTS => \@elements, PROPERTIES => $struct->{PROPERTIES}, ORIGINAL => $struct, ALIGN => $align };}sub ParseUnion($$){ my ($e, $pointer_default) = @_; my @elements = (); my $hasdefault = 0; my $switch_type = has_property($e, "switch_type"); unless (defined($switch_type)) { $switch_type = "uint32"; } if (has_property($e, "nodiscriminant")) { $switch_type = undef; } return { TYPE => "UNION", NAME => $e->{NAME}, SWITCH_TYPE => $switch_type, ELEMENTS => undef, PROPERTIES => $e->{PROPERTIES}, HAS_DEFAULT => $hasdefault, ORIGINAL => $e } unless defined($e->{ELEMENTS}); CheckPointerTypes($e, $pointer_default); foreach my $x (@{$e->{ELEMENTS}}) { my $t; if ($x->{TYPE} eq "EMPTY") { $t = { TYPE => "EMPTY" }; } else { $t = ParseElement($x, $pointer_default); } if (has_property($x, "default")) { $t->{CASE} = "default"; $hasdefault = 1; } 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", NAME => $e->{NAME}, SWITCH_TYPE => $switch_type, ELEMENTS => \@elements, PROPERTIES => $e->{PROPERTIES}, HAS_DEFAULT => $hasdefault, ORIGINAL => $e };}sub ParseEnum($$){ my ($e, $pointer_default) = @_; return { TYPE => "ENUM", NAME => $e->{NAME}, BASE_TYPE => Parse::Pidl::Typelist::enum_type_fn($e), ELEMENTS => $e->{ELEMENTS}, PROPERTIES => $e->{PROPERTIES}, ORIGINAL => $e };}sub ParseBitmap($$){ my ($e, $pointer_default) = @_; return { TYPE => "BITMAP", NAME => $e->{NAME}, BASE_TYPE => Parse::Pidl::Typelist::bitmap_type_fn($e), ELEMENTS => $e->{ELEMENTS}, PROPERTIES => $e->{PROPERTIES}, ORIGINAL => $e };}sub ParseType($$){ my ($d, $pointer_default) = @_; my $data = { STRUCT => \&ParseStruct, UNION => \&ParseUnion, ENUM => \&ParseEnum, BITMAP => \&ParseBitmap, TYPEDEF => \&ParseTypedef, }->{$d->{TYPE}}->($d, $pointer_default); return $data;}sub ParseTypedef($$){ my ($d, $pointer_default) = @_; if (defined($d->{DATA}->{PROPERTIES}) && !defined($d->{PROPERTIES})) { $d->{PROPERTIES} = $d->{DATA}->{PROPERTIES}; } my $data = ParseType($d->{DATA}, $pointer_default); $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, $ndr->{PROPERTIES}->{pointer_default}); push (@{$e->{DIRECTION}}, "in") if (has_property($x, "in")); push (@{$e->{DIRECTION}}, "out") if (has_property($x, "out")); push (@elements, $e);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -