1
###################################################
2
# Samba4 NDR info tree generator
3
# Copyright tridge@samba.org 2000-2003
4
# Copyright tpot@samba.org 2001
5
# Copyright jelmer@samba.org 2004-2006
6
# released under the GNU GPL
12
Parse::Pidl::NDR - NDR parsing information generator
16
Return a table describing the order in which the parts of an element
27
Jelmer Vernooij <jelmer@samba.org>
31
package Parse::Pidl::NDR;
34
use vars qw($VERSION);
37
@EXPORT = qw(GetPrevLevel GetNextLevel ContainsDeferred ContainsString);
38
@EXPORT_OK = qw(GetElementLevelTable ParseElement ValidElement align_type mapToScalar ParseType can_contain_deferred is_charset_array);
41
use Parse::Pidl qw(warning fatal);
42
use Parse::Pidl::Typelist qw(hasType getType expandAlias);
43
use Parse::Pidl::Util qw(has_property property_matches);
45
# Alignment of the built-in scalar types
46
my $scalar_alignment = {
62
'string_array' => 4, #???
71
'wrepl_nbt_name' => 4,
75
sub GetElementLevelTable($$)
77
my ($e, $pointer_default) = @_;
81
my @bracket_array = ();
86
if (has_property($e, "size_is")) {
87
@size_is = split /,/, has_property($e, "size_is");
90
if (has_property($e, "length_is")) {
91
@length_is = split /,/, has_property($e, "length_is");
94
if (defined($e->{ARRAY_LEN})) {
95
@bracket_array = @{$e->{ARRAY_LEN}};
98
if (has_property($e, "out")) {
101
if (has_property($e, "string")) { $needptrs++; }
102
if ($#bracket_array >= 0) { $needptrs = 0; }
104
warning($e, "[out] argument `$e->{NAME}' not a pointer") if ($needptrs > $e->{POINTERS});
107
# Parse the [][][][] style array stuff
108
for my $i (0 .. $#bracket_array) {
109
my $d = $bracket_array[$#bracket_array - $i];
112
my $is_surrounding = 0;
114
my $is_conformant = 0;
121
if ($size = shift @size_is) {
122
} elsif ((scalar(@size_is) == 0) and has_property($e, "string")) {
124
delete($e->{PROPERTIES}->{string});
126
fatal($e, "Must specify size_is() for conformant array!")
129
if (($length = shift @length_is) or $is_string) {
135
if ($e == $e->{PARENT}->{ELEMENTS}[-1]
136
and $e->{PARENT}->{TYPE} ne "FUNCTION") {
141
$is_fixed = 1 if (not $is_conformant and Parse::Pidl::Util::is_constant($size));
142
$is_inline = 1 if (not $is_conformant and not Parse::Pidl::Util::is_constant($size));
147
LENGTH_IS => $length,
148
IS_DEFERRED => $is_deferred,
149
IS_SURROUNDING => $is_surrounding,
150
IS_ZERO_TERMINATED => $is_string,
151
IS_VARYING => $is_varying,
152
IS_CONFORMANT => $is_conformant,
153
IS_FIXED => $is_fixed,
154
IS_INLINE => $is_inline
158
# Next, all the pointers
159
foreach my $i (1..$e->{POINTERS}) {
160
my $level = "EMBEDDED";
161
# Top level "ref" pointers do not have a referrent identifier
162
$level = "TOP" if ($i == 1 and $e->{PARENT}->{TYPE} eq "FUNCTION");
166
# Only the first level gets the pointer type from the
167
# pointer property, the others get them from
168
# the pointer_default() interface property
170
# see http://msdn2.microsoft.com/en-us/library/aa378984(VS.85).aspx
171
# (Here they talk about the rightmost pointer, but testing shows
172
# they mean the leftmost pointer.)
176
$pt = pointer_type($e);
178
$is_deferred = 1 if ($pt ne "ref" and $e->{PARENT}->{TYPE} eq "FUNCTION");
179
$pt = $pointer_default;
185
POINTER_INDEX => $pointer_idx,
186
IS_DEFERRED => "$is_deferred",
190
warning($e, "top-level \[out\] pointer `$e->{NAME}' is not a \[ref\] pointer")
191
if ($i == 1 and $pt ne "ref" and
192
$e->{PARENT}->{TYPE} eq "FUNCTION" and
193
not has_property($e, "in"));
197
# everything that follows will be deferred
198
$is_deferred = 1 if ($level ne "TOP");
200
my $array_size = shift @size_is;
207
if ($array_length = shift @length_is) {
210
$array_length = $array_size;
215
if (scalar(@size_is) == 0 and has_property($e, "string") and
216
$i == $e->{POINTERS}) {
218
$is_varying = $is_conformant = has_property($e, "noheader")?0:1;
219
delete($e->{PROPERTIES}->{string});
222
if ($array_size or $is_string) {
225
SIZE_IS => $array_size,
226
LENGTH_IS => $array_length,
227
IS_DEFERRED => $is_deferred,
229
IS_ZERO_TERMINATED => $is_string,
230
IS_VARYING => $is_varying,
231
IS_CONFORMANT => $is_conformant,
240
if (defined(has_property($e, "subcontext"))) {
241
my $hdr_size = has_property($e, "subcontext");
242
my $subsize = has_property($e, "subcontext_size");
243
if (not defined($subsize)) {
248
TYPE => "SUBCONTEXT",
249
HEADER_SIZE => $hdr_size,
250
SUBCONTEXT_SIZE => $subsize,
251
IS_DEFERRED => $is_deferred,
252
COMPRESSION => has_property($e, "compression"),
256
if (my $switch = has_property($e, "switch_is")) {
259
SWITCH_IS => $switch,
260
IS_DEFERRED => $is_deferred
264
if (scalar(@size_is) > 0) {
265
fatal($e, "size_is() on non-array element");
268
if (scalar(@length_is) > 0) {
269
fatal($e, "length_is() on non-array element");
272
if (has_property($e, "string")) {
273
fatal($e, "string() attribute on non-array element");
278
DATA_TYPE => $e->{TYPE},
279
IS_DEFERRED => $is_deferred,
280
CONTAINS_DEFERRED => can_contain_deferred($e->{TYPE}),
281
IS_SURROUNDING => 0 #FIXME
285
foreach (@$order) { $_->{LEVEL_INDEX} = $i; $i+=1; }
290
sub GetTypedefLevelTable($$$)
292
my ($e, $data, $pointer_default) = @_;
301
foreach (@$order) { $_->{LEVEL_INDEX} = $i; $i+=1; }
306
#####################################################################
307
# see if a type contains any deferred data
308
sub can_contain_deferred($)
310
sub can_contain_deferred($);
313
return 1 unless (hasType($type)); # assume the worst
315
$type = getType($type);
317
return 0 if (Parse::Pidl::Typelist::is_scalar($type));
319
return can_contain_deferred($type->{DATA}) if ($type->{TYPE} eq "TYPEDEF");
321
return 0 unless defined($type->{ELEMENTS});
323
foreach (@{$type->{ELEMENTS}}) {
324
return 1 if ($_->{POINTERS});
325
return 1 if (can_contain_deferred ($_->{TYPE}));
335
return undef unless $e->{POINTERS};
337
return "ref" if (has_property($e, "ref"));
338
return "full" if (has_property($e, "ptr"));
339
return "sptr" if (has_property($e, "sptr"));
340
return "unique" if (has_property($e, "unique"));
341
return "relative" if (has_property($e, "relative"));
342
return "ignore" if (has_property($e, "ignore"));
347
#####################################################################
348
# work out the correct alignment for a structure or union
349
sub find_largest_alignment($)
354
for my $e (@{$s->{ELEMENTS}}) {
357
if ($e->{POINTERS}) {
359
} elsif (has_property($e, "subcontext")) {
361
} elsif (has_property($e, "transmit_as")) {
362
$a = align_type($e->{PROPERTIES}->{transmit_as});
364
$a = align_type($e->{TYPE});
367
$align = $a if ($align < $a);
373
#####################################################################
380
if (ref($e) eq "HASH" and $e->{TYPE} eq "SCALAR") {
381
return $scalar_alignment->{$e->{NAME}};
384
return 0 if ($e eq "EMPTY");
386
unless (hasType($e)) {
387
# it must be an external type - all we can do is guess
388
# warning($e, "assuming alignment of unknown type '$e' is 4");
392
my $dt = getType($e);
394
if ($dt->{TYPE} eq "TYPEDEF") {
395
return align_type($dt->{DATA});
396
} elsif ($dt->{TYPE} eq "ENUM") {
397
return align_type(Parse::Pidl::Typelist::enum_type_fn($dt));
398
} elsif ($dt->{TYPE} eq "BITMAP") {
399
return align_type(Parse::Pidl::Typelist::bitmap_type_fn($dt));
400
} elsif (($dt->{TYPE} eq "STRUCT") or ($dt->{TYPE} eq "UNION")) {
401
# Struct/union without body: assume 4
402
return 4 unless (defined($dt->{ELEMENTS}));
403
return find_largest_alignment($dt);
406
die("Unknown data type type $dt->{TYPE}");
411
my ($e, $pointer_default) = @_;
413
$e->{TYPE} = expandAlias($e->{TYPE});
415
if (ref($e->{TYPE}) eq "HASH") {
416
$e->{TYPE} = ParseType($e->{TYPE}, $pointer_default);
422
PROPERTIES => $e->{PROPERTIES},
423
LEVELS => GetElementLevelTable($e, $pointer_default),
424
REPRESENTATION_TYPE => ($e->{PROPERTIES}->{represent_as} or $e->{TYPE}),
425
ALIGN => align_type($e->{TYPE}),
432
my ($struct, $pointer_default) = @_;
434
my $surrounding = undef;
438
NAME => $struct->{NAME},
439
SURROUNDING_ELEMENT => undef,
441
PROPERTIES => $struct->{PROPERTIES},
444
} unless defined($struct->{ELEMENTS});
446
CheckPointerTypes($struct, $pointer_default);
448
foreach my $x (@{$struct->{ELEMENTS}})
450
my $e = ParseElement($x, $pointer_default);
451
if ($x != $struct->{ELEMENTS}[-1] and
452
$e->{LEVELS}[0]->{IS_SURROUNDING}) {
453
fatal($x, "conformant member not at end of struct");
458
my $e = $elements[-1];
459
if (defined($e) and defined($e->{LEVELS}[0]->{IS_SURROUNDING}) and
460
$e->{LEVELS}[0]->{IS_SURROUNDING}) {
464
if (defined $e->{TYPE} && $e->{TYPE} eq "string"
465
&& property_matches($e, "flag", ".*LIBNDR_FLAG_STR_CONFORMANT.*")) {
466
$surrounding = $struct->{ELEMENTS}[-1];
470
if ($struct->{NAME}) {
471
$align = align_type($struct->{NAME});
476
NAME => $struct->{NAME},
477
SURROUNDING_ELEMENT => $surrounding,
478
ELEMENTS => \@elements,
479
PROPERTIES => $struct->{PROPERTIES},
487
my ($e, $pointer_default) = @_;
490
my $switch_type = has_property($e, "switch_type");
491
unless (defined($switch_type)) { $switch_type = "uint32"; }
492
if (has_property($e, "nodiscriminant")) { $switch_type = undef; }
497
SWITCH_TYPE => $switch_type,
499
PROPERTIES => $e->{PROPERTIES},
500
HAS_DEFAULT => $hasdefault,
502
} unless defined($e->{ELEMENTS});
504
CheckPointerTypes($e, $pointer_default);
506
foreach my $x (@{$e->{ELEMENTS}})
509
if ($x->{TYPE} eq "EMPTY") {
510
$t = { TYPE => "EMPTY" };
512
$t = ParseElement($x, $pointer_default);
514
if (has_property($x, "default")) {
515
$t->{CASE} = "default";
517
} elsif (defined($x->{PROPERTIES}->{case})) {
518
$t->{CASE} = "case $x->{PROPERTIES}->{case}";
520
die("Union element $x->{NAME} has neither default nor case property");
528
SWITCH_TYPE => $switch_type,
529
ELEMENTS => \@elements,
530
PROPERTIES => $e->{PROPERTIES},
531
HAS_DEFAULT => $hasdefault,
538
my ($e, $pointer_default) = @_;
543
BASE_TYPE => Parse::Pidl::Typelist::enum_type_fn($e),
544
ELEMENTS => $e->{ELEMENTS},
545
PROPERTIES => $e->{PROPERTIES},
552
my ($e, $pointer_default) = @_;
557
BASE_TYPE => Parse::Pidl::Typelist::bitmap_type_fn($e),
558
ELEMENTS => $e->{ELEMENTS},
559
PROPERTIES => $e->{PROPERTIES},
566
my ($d, $pointer_default) = @_;
569
STRUCT => \&ParseStruct,
570
UNION => \&ParseUnion,
572
BITMAP => \&ParseBitmap,
573
TYPEDEF => \&ParseTypedef,
574
}->{$d->{TYPE}}->($d, $pointer_default);
581
my ($d, $pointer_default) = @_;
583
if (defined($d->{DATA}->{PROPERTIES}) && !defined($d->{PROPERTIES})) {
584
$d->{PROPERTIES} = $d->{DATA}->{PROPERTIES};
587
my $data = ParseType($d->{DATA}, $pointer_default);
588
$data->{ALIGN} = align_type($d->{NAME});
593
PROPERTIES => $d->{PROPERTIES},
594
LEVELS => GetTypedefLevelTable($d, $data, $pointer_default),
607
sub ParseFunction($$$)
609
my ($ndr,$d,$opnum) = @_;
612
my $thisopnum = undef;
614
CheckPointerTypes($d, "ref");
616
if (not defined($d->{PROPERTIES}{noopnum})) {
617
$thisopnum = ${$opnum};
621
foreach my $x (@{$d->{ELEMENTS}}) {
622
my $e = ParseElement($x, $ndr->{PROPERTIES}->{pointer_default});
623
push (@{$e->{DIRECTION}}, "in") if (has_property($x, "in"));
624
push (@{$e->{DIRECTION}}, "out") if (has_property($x, "out"));
626
push (@elements, $e);
629
if ($d->{RETURN_TYPE} ne "void") {
630
$rettype = expandAlias($d->{RETURN_TYPE});
634
if (has_property($d, "async")) { $async = 1; }
641
RETURN_TYPE => $rettype,
642
PROPERTIES => $d->{PROPERTIES},
643
ELEMENTS => \@elements,
648
sub CheckPointerTypes($$)
650
my ($s,$default) = @_;
652
return unless defined($s->{ELEMENTS});
654
foreach my $e (@{$s->{ELEMENTS}}) {
655
if ($e->{POINTERS} and not defined(pointer_type($e))) {
656
$e->{PROPERTIES}->{$default} = '1';
661
sub FindNestedTypes($$)
663
sub FindNestedTypes($$);
666
return unless defined($t->{ELEMENTS});
667
return if ($t->{TYPE} eq "ENUM");
668
return if ($t->{TYPE} eq "BITMAP");
670
foreach (@{$t->{ELEMENTS}}) {
671
if (ref($_->{TYPE}) eq "HASH") {
672
push (@$l, $_->{TYPE}) if (defined($_->{TYPE}->{NAME}));
673
FindNestedTypes($l, $_->{TYPE});
678
sub ParseInterface($)
688
if (not has_property($idl, "pointer_default")) {
689
# MIDL defaults to "ptr" in DCE compatible mode (/osf)
690
# and "unique" in Microsoft Extensions mode (default)
691
$idl->{PROPERTIES}->{pointer_default} = "unique";
694
foreach my $d (@{$idl->{DATA}}) {
695
if ($d->{TYPE} eq "FUNCTION") {
696
push (@functions, ParseFunction($idl, $d, \$opnum));
697
} elsif ($d->{TYPE} eq "CONST") {
698
push (@consts, ParseConst($idl, $d));
700
push (@types, ParseType($d, $idl->{PROPERTIES}->{pointer_default}));
701
FindNestedTypes(\@types, $d);
707
if(defined $idl->{PROPERTIES}->{version}) {
708
my @if_version = split(/\./, $idl->{PROPERTIES}->{version});
709
if ($if_version[0] == $idl->{PROPERTIES}->{version}) {
710
$version = $idl->{PROPERTIES}->{version};
712
$version = $if_version[1] << 16 | $if_version[0];
716
# If no endpoint is set, default to the interface name as a named pipe
717
if (!defined $idl->{PROPERTIES}->{endpoint}) {
718
push @endpoints, "\"ncacn_np:[\\\\pipe\\\\" . $idl->{NAME} . "]\"";
720
@endpoints = split /,/, $idl->{PROPERTIES}->{endpoint};
724
NAME => $idl->{NAME},
725
UUID => lc(has_property($idl, "uuid")),
728
PROPERTIES => $idl->{PROPERTIES},
729
FUNCTIONS => \@functions,
732
ENDPOINTS => \@endpoints
736
# Convert a IDL tree to a NDR tree
737
# Gives a result tree describing all that's necessary for easily generating
738
# NDR parsers / generators
743
return undef unless (defined($idl));
745
Parse::Pidl::NDR::Validate($idl);
750
($_->{TYPE} eq "CPP_QUOTE") && push(@ndr, $_);
751
($_->{TYPE} eq "INTERFACE") && push(@ndr, ParseInterface($_));
752
($_->{TYPE} eq "IMPORT") && push(@ndr, $_);
765
foreach my $l (@{$e->{LEVELS}}) {
766
return $l if ($seen);
767
($seen = 1) if ($l == $fl);
778
foreach my $l (@{$e->{LEVELS}}) {
779
(return $prev) if ($l == $fl);
786
sub ContainsString($)
790
foreach my $l (@{$e->{LEVELS}}) {
791
return 1 if ($l->{TYPE} eq "ARRAY" and $l->{IS_ZERO_TERMINATED});
797
sub ContainsDeferred($$)
801
return 1 if ($l->{CONTAINS_DEFERRED});
803
while ($l = GetNextLevel($e,$l))
805
return 1 if ($l->{IS_DEFERRED});
806
return 1 if ($l->{CONTAINS_DEFERRED});
815
my $name = "<ANONYMOUS>";
817
$name = $e->{NAME} if defined($e->{NAME});
819
if (defined($e->{PARENT}) and defined($e->{PARENT}->{NAME})) {
820
return "$e->{PARENT}->{NAME}.$name";
823
if (defined($e->{PARENT}) and
824
defined($e->{PARENT}->{PARENT}) and
825
defined($e->{PARENT}->{PARENT}->{NAME})) {
826
return "$e->{PARENT}->{PARENT}->{NAME}.$name";
832
###################################
833
# find a sibling var in a structure
837
my($fn) = $e->{PARENT};
839
if ($name =~ /\*(.*)/) {
843
for my $e2 (@{$fn->{ELEMENTS}}) {
844
return $e2 if ($e2->{NAME} eq $name);
850
my %property_list = (
852
"helpstring" => ["INTERFACE", "FUNCTION"],
853
"version" => ["INTERFACE"],
854
"uuid" => ["INTERFACE"],
855
"endpoint" => ["INTERFACE"],
856
"pointer_default" => ["INTERFACE"],
857
"helper" => ["INTERFACE"],
858
"pyhelper" => ["INTERFACE"],
859
"authservice" => ["INTERFACE"],
860
"restricted" => ["INTERFACE"],
863
"object" => ["INTERFACE"],
864
"local" => ["INTERFACE", "FUNCTION"],
865
"iid_is" => ["ELEMENT"],
866
"call_as" => ["FUNCTION"],
867
"idempotent" => ["FUNCTION"],
870
"noopnum" => ["FUNCTION"],
872
"out" => ["ELEMENT"],
873
"async" => ["FUNCTION"],
876
"ref" => ["ELEMENT"],
877
"ptr" => ["ELEMENT"],
878
"unique" => ["ELEMENT"],
879
"ignore" => ["ELEMENT"],
880
"relative" => ["ELEMENT"],
881
"null_is_ffffffff" => ["ELEMENT"],
882
"relative_base" => ["TYPEDEF", "STRUCT", "UNION"],
884
"gensize" => ["TYPEDEF", "STRUCT", "UNION"],
885
"value" => ["ELEMENT"],
886
"flag" => ["ELEMENT", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP"],
889
"public" => ["FUNCTION", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP"],
890
"nopush" => ["FUNCTION", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP"],
891
"nopull" => ["FUNCTION", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP"],
892
"nosize" => ["FUNCTION", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP"],
893
"noprint" => ["FUNCTION", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP", "ELEMENT"],
894
"todo" => ["FUNCTION"],
897
"switch_is" => ["ELEMENT"],
898
"switch_type" => ["ELEMENT", "UNION"],
899
"nodiscriminant" => ["UNION"],
900
"case" => ["ELEMENT"],
901
"default" => ["ELEMENT"],
903
"represent_as" => ["ELEMENT"],
904
"transmit_as" => ["ELEMENT"],
907
"subcontext" => ["ELEMENT"],
908
"subcontext_size" => ["ELEMENT"],
909
"compression" => ["ELEMENT"],
912
"enum8bit" => ["ENUM"],
913
"enum16bit" => ["ENUM"],
914
"v1_enum" => ["ENUM"],
917
"bitmap8bit" => ["BITMAP"],
918
"bitmap16bit" => ["BITMAP"],
919
"bitmap32bit" => ["BITMAP"],
920
"bitmap64bit" => ["BITMAP"],
923
"range" => ["ELEMENT"],
924
"size_is" => ["ELEMENT"],
925
"string" => ["ELEMENT"],
926
"noheader" => ["ELEMENT"],
927
"charset" => ["ELEMENT"],
928
"length_is" => ["ELEMENT"],
931
#####################################################################
932
# check for unknown properties
933
sub ValidProperties($$)
937
return unless defined $e->{PROPERTIES};
939
foreach my $key (keys %{$e->{PROPERTIES}}) {
940
warning($e, el_name($e) . ": unknown property '$key'")
941
unless defined($property_list{$key});
943
fatal($e, el_name($e) . ": property '$key' not allowed on '$t'")
944
unless grep(/^$t$/, @{$property_list{$key}});
952
return $t->{NAME} if (ref($t) eq "HASH" and $t->{TYPE} eq "SCALAR");
953
my $ti = getType($t);
955
if (not defined ($ti)) {
957
} elsif ($ti->{TYPE} eq "TYPEDEF") {
958
return mapToScalar($ti->{DATA});
959
} elsif ($ti->{TYPE} eq "ENUM") {
960
return Parse::Pidl::Typelist::enum_type_fn($ti);
961
} elsif ($ti->{TYPE} eq "BITMAP") {
962
return Parse::Pidl::Typelist::bitmap_type_fn($ti);
968
#####################################################################
969
# validate an element
974
ValidProperties($e,"ELEMENT");
976
# Check whether switches are used correctly.
977
if (my $switch = has_property($e, "switch_is")) {
978
my $e2 = find_sibling($e, $switch);
979
my $type = getType($e->{TYPE});
981
if (defined($type) and $type->{DATA}->{TYPE} ne "UNION") {
982
fatal($e, el_name($e) . ": switch_is() used on non-union type $e->{TYPE} which is a $type->{DATA}->{TYPE}");
985
if (not has_property($type->{DATA}, "nodiscriminant") and defined($e2)) {
986
my $discriminator_type = has_property($type->{DATA}, "switch_type");
987
$discriminator_type = "uint32" unless defined ($discriminator_type);
989
my $t1 = mapToScalar($discriminator_type);
991
if (not defined($t1)) {
992
fatal($e, el_name($e) . ": unable to map discriminator type '$discriminator_type' to scalar");
995
my $t2 = mapToScalar($e2->{TYPE});
996
if (not defined($t2)) {
997
fatal($e, el_name($e) . ": unable to map variable used for switch_is() to scalar");
1001
warning($e, el_name($e) . ": switch_is() is of type $e2->{TYPE} ($t2), while discriminator type for union $type->{NAME} is $discriminator_type ($t1)");
1006
if (has_property($e, "subcontext") and has_property($e, "represent_as")) {
1007
fatal($e, el_name($e) . " : subcontext() and represent_as() can not be used on the same element");
1010
if (has_property($e, "subcontext") and has_property($e, "transmit_as")) {
1011
fatal($e, el_name($e) . " : subcontext() and transmit_as() can not be used on the same element");
1014
if (has_property($e, "represent_as") and has_property($e, "transmit_as")) {
1015
fatal($e, el_name($e) . " : represent_as() and transmit_as() can not be used on the same element");
1018
if (has_property($e, "represent_as") and has_property($e, "value")) {
1019
fatal($e, el_name($e) . " : represent_as() and value() can not be used on the same element");
1022
if (has_property($e, "subcontext")) {
1023
warning($e, "subcontext() is deprecated. Use represent_as() or transmit_as() instead");
1026
if (defined (has_property($e, "subcontext_size")) and not defined(has_property($e, "subcontext"))) {
1027
fatal($e, el_name($e) . " : subcontext_size() on non-subcontext element");
1030
if (defined (has_property($e, "compression")) and not defined(has_property($e, "subcontext"))) {
1031
fatal($e, el_name($e) . " : compression() on non-subcontext element");
1034
if (!$e->{POINTERS} && (
1035
has_property($e, "ptr") or
1036
has_property($e, "unique") or
1037
has_property($e, "relative") or
1038
has_property($e, "ref"))) {
1039
fatal($e, el_name($e) . " : pointer properties on non-pointer element\n");
1043
#####################################################################
1049
ValidProperties($enum, "ENUM");
1052
#####################################################################
1058
ValidProperties($bitmap, "BITMAP");
1061
#####################################################################
1065
my($struct) = shift;
1067
ValidProperties($struct, "STRUCT");
1069
return unless defined($struct->{ELEMENTS});
1071
foreach my $e (@{$struct->{ELEMENTS}}) {
1072
$e->{PARENT} = $struct;
1077
#####################################################################
1083
ValidProperties($union,"UNION");
1085
if (has_property($union->{PARENT}, "nodiscriminant") and
1086
has_property($union->{PARENT}, "switch_type")) {
1087
fatal($union->{PARENT}, $union->{PARENT}->{NAME} . ": switch_type(" . $union->{PARENT}->{PROPERTIES}->{switch_type} . ") on union without discriminant");
1090
return unless defined($union->{ELEMENTS});
1092
foreach my $e (@{$union->{ELEMENTS}}) {
1093
$e->{PARENT} = $union;
1095
if (defined($e->{PROPERTIES}->{default}) and
1096
defined($e->{PROPERTIES}->{case})) {
1097
fatal($e, "Union member $e->{NAME} can not have both default and case properties!");
1100
unless (defined ($e->{PROPERTIES}->{default}) or
1101
defined ($e->{PROPERTIES}->{case})) {
1102
fatal($e, "Union member $e->{NAME} must have default or case property");
1105
if (has_property($e, "ref")) {
1106
fatal($e, el_name($e) . ": embedded ref pointers are not supported yet\n");
1114
#####################################################################
1118
my($typedef) = shift;
1119
my $data = $typedef->{DATA};
1121
ValidProperties($typedef, "TYPEDEF");
1123
$data->{PARENT} = $typedef;
1125
$data->{FILE} = $typedef->{FILE} unless defined($data->{FILE});
1126
$data->{LINE} = $typedef->{LINE} unless defined($data->{LINE});
1128
ValidType($data) if (ref($data) eq "HASH");
1131
#####################################################################
1132
# validate a function
1133
sub ValidFunction($)
1137
ValidProperties($fn,"FUNCTION");
1139
foreach my $e (@{$fn->{ELEMENTS}}) {
1141
if (has_property($e, "ref") && !$e->{POINTERS}) {
1142
fatal($e, "[ref] variables must be pointers ($fn->{NAME}/$e->{NAME})");
1148
#####################################################################
1155
TYPEDEF => \&ValidTypedef,
1156
STRUCT => \&ValidStruct,
1157
UNION => \&ValidUnion,
1158
ENUM => \&ValidEnum,
1159
BITMAP => \&ValidBitmap
1160
}->{$t->{TYPE}}->($t);
1163
#####################################################################
1164
# parse the interface definitions
1165
sub ValidInterface($)
1167
my($interface) = shift;
1168
my($data) = $interface->{DATA};
1170
if (has_property($interface, "helper")) {
1171
warning($interface, "helper() is pidl-specific and deprecated. Use `include' instead");
1174
ValidProperties($interface,"INTERFACE");
1176
if (has_property($interface, "pointer_default")) {
1177
if (not grep (/$interface->{PROPERTIES}->{pointer_default}/,
1178
("ref", "unique", "ptr"))) {
1179
fatal($interface, "Unknown default pointer type `$interface->{PROPERTIES}->{pointer_default}'");
1183
if (has_property($interface, "object")) {
1184
if (has_property($interface, "version") &&
1185
$interface->{PROPERTIES}->{version} != 0) {
1186
fatal($interface, "Object interfaces must have version 0.0 ($interface->{NAME})");
1189
if (!defined($interface->{BASE}) &&
1190
not ($interface->{NAME} eq "IUnknown")) {
1191
fatal($interface, "Object interfaces must all derive from IUnknown ($interface->{NAME})");
1195
foreach my $d (@{$data}) {
1196
($d->{TYPE} eq "FUNCTION") && ValidFunction($d);
1197
($d->{TYPE} eq "TYPEDEF" or
1198
$d->{TYPE} eq "STRUCT" or
1199
$d->{TYPE} eq "UNION" or
1200
$d->{TYPE} eq "ENUM" or
1201
$d->{TYPE} eq "BITMAP") && ValidType($d);
1206
#####################################################################
1207
# Validate an IDL structure
1212
foreach my $x (@{$idl}) {
1213
($x->{TYPE} eq "INTERFACE") &&
1215
($x->{TYPE} eq "IMPORTLIB") &&
1216
fatal($x, "importlib() not supported");
1220
sub is_charset_array($$)
1224
return 0 if ($l->{TYPE} ne "ARRAY");
1226
my $nl = GetNextLevel($e,$l);
1228
return 0 unless ($nl->{TYPE} eq "DATA");
1230
return has_property($e, "charset");