1
###################################################
2
# Samba4 NDR parser generator for IDL structures
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
8
package Parse::Pidl::Samba4::NDR::Parser;
12
@EXPORT_OK = qw(check_null_pointer NeededFunction NeededElement NeededType $res NeededInterface TypeFunctionName ParseElementPrint);
15
use Parse::Pidl::Typelist qw(hasType getType mapTypeName typeHasBody);
16
use Parse::Pidl::Util qw(has_property ParseExpr ParseExprExt print_uuid unmake_str);
17
use Parse::Pidl::CUtil qw(get_pointer_to get_value_of get_array_element);
18
use Parse::Pidl::NDR qw(GetPrevLevel GetNextLevel ContainsDeferred is_charset_array);
19
use Parse::Pidl::Samba4 qw(is_intree choose_header);
20
use Parse::Pidl::Samba4::Header qw(GenerateFunctionInEnv GenerateFunctionOutEnv EnvSubstituteValue GenerateStructEnv);
21
use Parse::Pidl qw(warning);
23
use vars qw($VERSION);
31
my $self = { res => "", res_hdr => "", deferred => [], tabs => "", defer_tabs => "" };
38
return $typefamily{$n};
43
my ($e, $var_name) = @_;
47
foreach my $l (@{$e->{LEVELS}}) {
48
if ($l->{TYPE} eq "POINTER") {
50
} elsif ($l->{TYPE} eq "ARRAY") {
52
if (($pointers == 0) and
53
(not $l->{IS_FIXED}) and
54
(not $l->{IS_INLINE})) {
55
return get_value_of($var_name);
57
} elsif ($l->{TYPE} eq "DATA") {
58
if (Parse::Pidl::Typelist::scalar_is_reference($l->{DATA_TYPE})) {
59
return get_value_of($var_name) unless ($pointers or $arrays);
67
sub has_fast_array($$)
71
return 0 if ($l->{TYPE} ne "ARRAY");
73
my $nl = GetNextLevel($e,$l);
74
return 0 unless ($nl->{TYPE} eq "DATA");
75
return 0 unless (hasType($nl->{DATA_TYPE}));
77
my $t = getType($nl->{DATA_TYPE});
79
# Only uint8 and string have fast array functions at the moment
80
return ($t->{NAME} eq "uint8") or ($t->{NAME} eq "string");
84
####################################
85
# pidl() is our basic output routine
90
$self->{res} .= $self->{tabs};
96
sub pidl_hdr($$) { my ($self, $d) = @_; $self->{res_hdr} .= "$d\n"; }
98
####################################
99
# defer() is like pidl(), but adds to
100
# a deferred buffer which is then added to the
101
# output buffer at the end of the structure/union/function
102
# This is needed to cope with code that must be pushed back
103
# to the end of a block of elements
104
sub defer_indent($) { my ($self) = @_; $self->{defer_tabs}.="\t"; }
105
sub defer_deindent($) { my ($self) = @_; $self->{defer_tabs}=substr($self->{defer_tabs}, 0, -1); }
111
push(@{$self->{deferred}}, $self->{defer_tabs}.$d);
115
########################################
116
# add the deferred content to the current
121
$self->pidl($_) foreach (@{$self->{deferred}});
122
$self->{deferred} = [];
123
$self->{defer_tabs} = "";
129
$self->{tabs} .= "\t";
135
$self->{tabs} = substr($self->{tabs}, 0, -1);
138
#####################################################################
139
# declare a function public or static, depending on its attributes
142
my ($self,$type,$fn,$decl) = @_;
144
if (has_property($fn, "no$type")) {
145
$self->pidl_hdr("$decl;");
149
if (has_property($fn, "public")) {
150
$self->pidl_hdr("$decl;");
151
$self->pidl("_PUBLIC_ $decl");
153
$self->pidl("static $decl");
159
###################################################################
160
# setup any special flags for an element or structure
163
my ($self, $e, $ndr) = @_;
164
my $flags = has_property($e, "flag");
165
if (defined $flags) {
168
$self->pidl("uint32_t _flags_save_$e->{TYPE} = $ndr->flags;");
169
$self->pidl("ndr_set_flags(&$ndr->flags, $flags);");
173
###################################################################
174
# end any special flags for an element or structure
177
my ($self, $e, $ndr) = @_;
178
my $flags = has_property($e, "flag");
179
if (defined $flags) {
180
$self->pidl("$ndr->flags = _flags_save_$e->{TYPE};");
186
#####################################################################
187
# parse the data of an array - push side
188
sub ParseArrayPushHeader($$$$$$)
190
my ($self,$e,$l,$ndr,$var_name,$env) = @_;
195
if ($l->{IS_ZERO_TERMINATED}) {
196
if (has_property($e, "charset")) {
197
$size = $length = "ndr_charset_length($var_name, CH_$e->{PROPERTIES}->{charset})";
199
$size = $length = "ndr_string_length($var_name, sizeof(*$var_name))";
202
$size = ParseExpr($l->{SIZE_IS}, $env, $e);
203
$length = ParseExpr($l->{LENGTH_IS}, $env, $e);
206
if ((!$l->{IS_SURROUNDING}) and $l->{IS_CONFORMANT}) {
207
$self->pidl("NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, $size));");
210
if ($l->{IS_VARYING}) {
211
$self->pidl("NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, 0));"); # array offset
212
$self->pidl("NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, $length));");
218
sub check_fully_dereferenced($$)
220
my ($element, $env) = @_;
226
# Figure out the number of pointers in $ptr
227
my $expandedvar = $origvar;
228
$expandedvar =~ s/^(\**)//;
232
foreach (keys %$env) {
233
if ($env->{$_} eq $expandedvar) {
239
return($origvar) unless (defined($var));
241
foreach (@{$element->{PARENT}->{ELEMENTS}}) {
242
if ($_->{NAME} eq $var) {
248
$e or die("Environment doesn't match siblings");
250
# See if pointer at pointer level $level
251
# needs to be checked.
253
foreach (@{$e->{LEVELS}}) {
254
if ($_->{TYPE} eq "POINTER") {
255
$nump = $_->{POINTER_INDEX}+1;
258
warning($element->{ORIGINAL}, "Got pointer for `$e->{NAME}', expected fully derefenced variable") if ($nump > length($ptr));
263
sub check_null_pointer($$$$)
265
my ($element, $env, $print_fn, $return) = @_;
268
my $expandedvar = shift;
271
# Figure out the number of pointers in $ptr
272
$expandedvar =~ s/^(\**)//;
276
foreach (keys %$env) {
277
if ($env->{$_} eq $expandedvar) {
286
foreach (@{$element->{PARENT}->{ELEMENTS}}) {
287
if ($_->{NAME} eq $var) {
293
$e or die("Environment doesn't match siblings");
295
# See if pointer at pointer level $level
296
# needs to be checked.
297
foreach my $l (@{$e->{LEVELS}}) {
298
if ($l->{TYPE} eq "POINTER" and
299
$l->{POINTER_INDEX} == length($ptr)) {
300
# No need to check ref pointers
301
$check = ($l->{POINTER_TYPE} ne "ref");
305
if ($l->{TYPE} eq "DATA") {
306
warning($element, "too much dereferences for `$var'");
310
warning($element, "unknown dereferenced expression `$expandedvar'");
314
$print_fn->("if ($ptr$expandedvar == NULL) $return") if $check;
318
#####################################################################
319
# parse an array - pull side
320
sub ParseArrayPullHeader($$$$$$)
322
my ($self,$e,$l,$ndr,$var_name,$env) = @_;
327
if ($l->{IS_CONFORMANT}) {
328
$length = $size = "ndr_get_array_size($ndr, " . get_pointer_to($var_name) . ")";
329
} elsif ($l->{IS_ZERO_TERMINATED}) { # Noheader arrays
330
$length = $size = "ndr_get_string_size($ndr, sizeof(*$var_name))";
332
$length = $size = ParseExprExt($l->{SIZE_IS}, $env, $e->{ORIGINAL},
333
check_null_pointer($e, $env, sub { $self->pidl(shift); },
334
"return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for size_is()\");"),
335
check_fully_dereferenced($e, $env));
338
if ((!$l->{IS_SURROUNDING}) and $l->{IS_CONFORMANT}) {
339
$self->pidl("NDR_CHECK(ndr_pull_array_size($ndr, " . get_pointer_to($var_name) . "));");
342
if ($l->{IS_VARYING}) {
343
$self->pidl("NDR_CHECK(ndr_pull_array_length($ndr, " . get_pointer_to($var_name) . "));");
344
$length = "ndr_get_array_length($ndr, " . get_pointer_to($var_name) .")";
347
if ($length ne $size) {
348
$self->pidl("if ($length > $size) {");
350
$self->pidl("return ndr_pull_error($ndr, NDR_ERR_ARRAY_SIZE, \"Bad array size %u should exceed array length %u\", $size, $length);");
355
if ($l->{IS_CONFORMANT} and not $l->{IS_ZERO_TERMINATED}) {
356
$self->defer("if ($var_name) {");
358
my $size = ParseExprExt($l->{SIZE_IS}, $env, $e->{ORIGINAL},
359
check_null_pointer($e, $env, sub { $self->defer(shift); },
360
"return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for size_is()\");"),
361
check_fully_dereferenced($e, $env));
362
$self->defer("NDR_CHECK(ndr_check_array_size($ndr, (void*)" . get_pointer_to($var_name) . ", $size));");
363
$self->defer_deindent;
367
if ($l->{IS_VARYING} and not $l->{IS_ZERO_TERMINATED}) {
368
$self->defer("if ($var_name) {");
370
my $length = ParseExprExt($l->{LENGTH_IS}, $env, $e->{ORIGINAL},
371
check_null_pointer($e, $env, sub { $self->defer(shift); },
372
"return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for length_is()\");"),
373
check_fully_dereferenced($e, $env));
374
$self->defer("NDR_CHECK(ndr_check_array_length($ndr, (void*)" . get_pointer_to($var_name) . ", $length));");
375
$self->defer_deindent;
379
if (not $l->{IS_FIXED} and not is_charset_array($e, $l)) {
380
$self->AllocateArrayLevel($e,$l,$ndr,$var_name,$size);
386
sub compression_alg($$)
389
my ($alg, $clen, $dlen) = split(/,/, $l->{COMPRESSION});
394
sub compression_clen($$$)
396
my ($e, $l, $env) = @_;
397
my ($alg, $clen, $dlen) = split(/,/, $l->{COMPRESSION});
399
return ParseExpr($clen, $env, $e->{ORIGINAL});
402
sub compression_dlen($$$)
404
my ($e,$l,$env) = @_;
405
my ($alg, $clen, $dlen) = split(/,/, $l->{COMPRESSION});
407
return ParseExpr($dlen, $env, $e->{ORIGINAL});
410
sub ParseCompressionPushStart($$$$$)
412
my ($self,$e,$l,$ndr,$env) = @_;
413
my $comndr = "$ndr\_compressed";
414
my $alg = compression_alg($e, $l);
415
my $dlen = compression_dlen($e, $l, $env);
419
$self->pidl("struct ndr_push *$comndr;");
420
$self->pidl("NDR_CHECK(ndr_push_compression_start($ndr, &$comndr, $alg, $dlen));");
425
sub ParseCompressionPushEnd($$$$$)
427
my ($self,$e,$l,$ndr,$env) = @_;
428
my $comndr = "$ndr\_compressed";
429
my $alg = compression_alg($e, $l);
430
my $dlen = compression_dlen($e, $l, $env);
432
$self->pidl("NDR_CHECK(ndr_push_compression_end($ndr, $comndr, $alg, $dlen));");
437
sub ParseCompressionPullStart($$$$$)
439
my ($self,$e,$l,$ndr,$env) = @_;
440
my $comndr = "$ndr\_compressed";
441
my $alg = compression_alg($e, $l);
442
my $dlen = compression_dlen($e, $l, $env);
446
$self->pidl("struct ndr_pull *$comndr;");
447
$self->pidl("NDR_CHECK(ndr_pull_compression_start($ndr, &$comndr, $alg, $dlen));");
452
sub ParseCompressionPullEnd($$$$$)
454
my ($self,$e,$l,$ndr,$env) = @_;
455
my $comndr = "$ndr\_compressed";
456
my $alg = compression_alg($e, $l);
457
my $dlen = compression_dlen($e, $l, $env);
459
$self->pidl("NDR_CHECK(ndr_pull_compression_end($ndr, $comndr, $alg, $dlen));");
464
sub ParseSubcontextPushStart($$$$$)
466
my ($self,$e,$l,$ndr,$env) = @_;
467
my $subndr = "_ndr_$e->{NAME}";
468
my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
472
$self->pidl("struct ndr_push *$subndr;");
473
$self->pidl("NDR_CHECK(ndr_push_subcontext_start($ndr, &$subndr, $l->{HEADER_SIZE}, $subcontext_size));");
475
if (defined $l->{COMPRESSION}) {
476
$subndr = $self->ParseCompressionPushStart($e, $l, $subndr, $env);
482
sub ParseSubcontextPushEnd($$$$$)
484
my ($self,$e,$l,$ndr,$env) = @_;
485
my $subndr = "_ndr_$e->{NAME}";
486
my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
488
if (defined $l->{COMPRESSION}) {
489
$self->ParseCompressionPushEnd($e, $l, $subndr, $env);
492
$self->pidl("NDR_CHECK(ndr_push_subcontext_end($ndr, $subndr, $l->{HEADER_SIZE}, $subcontext_size));");
497
sub ParseSubcontextPullStart($$$$$)
499
my ($self,$e,$l,$ndr,$env) = @_;
500
my $subndr = "_ndr_$e->{NAME}";
501
my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
505
$self->pidl("struct ndr_pull *$subndr;");
506
$self->pidl("NDR_CHECK(ndr_pull_subcontext_start($ndr, &$subndr, $l->{HEADER_SIZE}, $subcontext_size));");
508
if (defined $l->{COMPRESSION}) {
509
$subndr = $self->ParseCompressionPullStart($e, $l, $subndr, $env);
515
sub ParseSubcontextPullEnd($$$$$)
517
my ($self,$e,$l,$ndr,$env) = @_;
518
my $subndr = "_ndr_$e->{NAME}";
519
my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
521
if (defined $l->{COMPRESSION}) {
522
$self->ParseCompressionPullEnd($e, $l, $subndr, $env);
525
$self->pidl("NDR_CHECK(ndr_pull_subcontext_end($ndr, $subndr, $l->{HEADER_SIZE}, $subcontext_size));");
530
sub ParseElementPushLevel
532
my ($self,$e,$l,$ndr,$var_name,$env,$primitives,$deferred) = @_;
534
my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
536
if ($l->{TYPE} eq "ARRAY" and ($l->{IS_CONFORMANT} or $l->{IS_VARYING})) {
537
$var_name = get_pointer_to($var_name);
540
if (defined($ndr_flags)) {
541
if ($l->{TYPE} eq "SUBCONTEXT") {
542
my $subndr = $self->ParseSubcontextPushStart($e, $l, $ndr, $env);
543
$self->ParseElementPushLevel($e, GetNextLevel($e, $l), $subndr, $var_name, $env, 1, 1);
544
$self->ParseSubcontextPushEnd($e, $l, $ndr, $env);
545
} elsif ($l->{TYPE} eq "POINTER") {
546
$self->ParsePtrPush($e, $l, $ndr, $var_name);
547
} elsif ($l->{TYPE} eq "ARRAY") {
548
my $length = $self->ParseArrayPushHeader($e, $l, $ndr, $var_name, $env);
550
my $nl = GetNextLevel($e, $l);
552
# Allow speedups for arrays of scalar types
553
if (is_charset_array($e,$l)) {
554
$self->pidl("NDR_CHECK(ndr_push_charset($ndr, $ndr_flags, $var_name, $length, sizeof(" . mapTypeName($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));");
556
} elsif (has_fast_array($e,$l)) {
557
$self->pidl("NDR_CHECK(ndr_push_array_$nl->{DATA_TYPE}($ndr, $ndr_flags, $var_name, $length));");
560
} elsif ($l->{TYPE} eq "SWITCH") {
561
$self->ParseSwitchPush($e, $l, $ndr, $var_name, $env);
562
} elsif ($l->{TYPE} eq "DATA") {
563
$self->ParseDataPush($e, $l, $ndr, $var_name, $primitives, $deferred);
564
} elsif ($l->{TYPE} eq "TYPEDEF") {
565
$typefamily{$e->{DATA}->{TYPE}}->{PUSH_FN_BODY}->($self, $e->{DATA}, $ndr, $var_name);
569
if ($l->{TYPE} eq "POINTER" and $deferred) {
570
if ($l->{POINTER_TYPE} ne "ref") {
571
$self->pidl("if ($var_name) {");
573
if ($l->{POINTER_TYPE} eq "relative") {
574
$self->pidl("NDR_CHECK(ndr_push_relative_ptr2($ndr, $var_name));");
577
$var_name = get_value_of($var_name);
578
$self->ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 1, 1);
580
if ($l->{POINTER_TYPE} ne "ref") {
584
} elsif ($l->{TYPE} eq "ARRAY" and not has_fast_array($e,$l) and
585
not is_charset_array($e, $l)) {
586
my $length = ParseExpr($l->{LENGTH_IS}, $env, $e->{ORIGINAL});
587
my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
589
$var_name = get_array_element($var_name, $counter);
591
if (($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) {
592
$self->pidl("for ($counter = 0; $counter < $length; $counter++) {");
594
$self->ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 1, 0);
599
if ($deferred and ContainsDeferred($e, $l)) {
600
$self->pidl("for ($counter = 0; $counter < $length; $counter++) {");
602
$self->ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 0, 1);
606
} elsif ($l->{TYPE} eq "SWITCH") {
607
$self->ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, $primitives, $deferred);
611
#####################################################################
612
# parse scalars in a structure element
613
sub ParseElementPush($$$$$$)
615
my ($self,$e,$ndr,$env,$primitives,$deferred) = @_;
618
my $var_name = $env->{$e->{NAME}};
620
return unless $primitives or ($deferred and ContainsDeferred($e, $e->{LEVELS}[0]));
622
# Representation type is different from transmit_as
623
if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
626
my $transmit_name = "_transmit_$e->{NAME}";
627
$self->pidl(mapTypeName($e->{TYPE}) ." $transmit_name;");
628
$self->pidl("NDR_CHECK(ndr_$e->{REPRESENTATION_TYPE}_to_$e->{TYPE}($var_name, " . get_pointer_to($transmit_name) . "));");
629
$var_name = $transmit_name;
632
$var_name = append_prefix($e, $var_name);
634
$self->start_flags($e, $ndr);
636
if (defined(my $value = has_property($e, "value"))) {
637
$var_name = ParseExpr($value, $env, $e->{ORIGINAL});
640
$self->ParseElementPushLevel($e, $e->{LEVELS}[0], $ndr, $var_name, $env, $primitives, $deferred);
642
$self->end_flags($e, $ndr);
644
if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
650
#####################################################################
651
# parse a pointer in a struct element or function
652
sub ParsePtrPush($$$$$)
654
my ($self,$e,$l,$ndr,$var_name) = @_;
656
if ($l->{POINTER_TYPE} eq "ref") {
657
$self->pidl("if ($var_name == NULL) {");
659
$self->pidl("return ndr_push_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL [ref] pointer\");");
662
if ($l->{LEVEL} eq "EMBEDDED") {
663
$self->pidl("NDR_CHECK(ndr_push_ref_ptr(ndr));");
665
} elsif ($l->{POINTER_TYPE} eq "relative") {
666
$self->pidl("NDR_CHECK(ndr_push_relative_ptr1($ndr, $var_name));");
667
} elsif ($l->{POINTER_TYPE} eq "unique") {
668
$self->pidl("NDR_CHECK(ndr_push_unique_ptr($ndr, $var_name));");
669
} elsif ($l->{POINTER_TYPE} eq "full") {
670
$self->pidl("NDR_CHECK(ndr_push_full_ptr($ndr, $var_name));");
672
die("Unhandled pointer type $l->{POINTER_TYPE}");
676
sub need_pointer_to($$$)
678
my ($e, $l, $scalar_only) = @_;
681
if (ref($l->{DATA_TYPE})) {
682
$t = "$l->{DATA_TYPE}->{TYPE}_$l->{DATA_TYPE}->{NAME}";
684
$t = $l->{DATA_TYPE};
687
if (not Parse::Pidl::Typelist::is_scalar($t)) {
688
return 1 if $scalar_only;
693
foreach my $tl (@{$e->{LEVELS}}) {
695
if ($tl->{TYPE} eq "ARRAY") {
700
if (Parse::Pidl::Typelist::scalar_is_reference($t)) {
701
return 1 unless $arrays;
707
sub ParseDataPrint($$$$$)
709
my ($self, $e, $l, $ndr, $var_name) = @_;
711
if (not ref($l->{DATA_TYPE}) or defined($l->{DATA_TYPE}->{NAME})) {
713
if (need_pointer_to($e, $l, 1)) {
714
$var_name = get_pointer_to($var_name);
717
$self->pidl(TypeFunctionName("ndr_print", $l->{DATA_TYPE})."($ndr, \"$e->{NAME}\", $var_name);");
719
$self->ParseTypePrint($l->{DATA_TYPE}, $ndr, $var_name);
723
#####################################################################
724
# print scalars in a structure element
725
sub ParseElementPrint($$$$$)
727
my($self, $e, $ndr, $var_name, $env) = @_;
729
return if (has_property($e, "noprint"));
731
if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
732
$self->pidl("ndr_print_$e->{REPRESENTATION_TYPE}($ndr, \"$e->{NAME}\", $var_name);");
736
$var_name = append_prefix($e, $var_name);
738
if (defined(my $value = has_property($e, "value"))) {
739
$var_name = "($ndr->flags & LIBNDR_PRINT_SET_VALUES)?" . ParseExpr($value,$env, $e->{ORIGINAL}) . ":$var_name";
742
foreach my $l (@{$e->{LEVELS}}) {
743
if ($l->{TYPE} eq "POINTER") {
744
$self->pidl("ndr_print_ptr($ndr, \"$e->{NAME}\", $var_name);");
745
$self->pidl("$ndr->depth++;");
746
if ($l->{POINTER_TYPE} ne "ref") {
747
$self->pidl("if ($var_name) {");
750
$var_name = get_value_of($var_name);
751
} elsif ($l->{TYPE} eq "ARRAY") {
754
if ($l->{IS_CONFORMANT} or $l->{IS_VARYING}) {
755
$var_name = get_pointer_to($var_name);
758
if ($l->{IS_ZERO_TERMINATED}) {
759
$length = "ndr_string_length($var_name, sizeof(*$var_name))";
761
$length = ParseExprExt($l->{LENGTH_IS}, $env, $e->{ORIGINAL},
762
check_null_pointer($e, $env, sub { $self->pidl(shift); }, "return;"), check_fully_dereferenced($e, $env));
765
if (is_charset_array($e,$l)) {
766
$self->pidl("ndr_print_string($ndr, \"$e->{NAME}\", $var_name);");
768
} elsif (has_fast_array($e, $l)) {
769
my $nl = GetNextLevel($e, $l);
770
$self->pidl("ndr_print_array_$nl->{DATA_TYPE}($ndr, \"$e->{NAME}\", $var_name, $length);");
773
my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
775
$self->pidl("$ndr->print($ndr, \"\%s: ARRAY(\%d)\", \"$e->{NAME}\", (int)$length);");
776
$self->pidl("$ndr->depth++;");
777
$self->pidl("for ($counter=0;$counter<$length;$counter++) {");
779
$self->pidl("char *idx_$l->{LEVEL_INDEX}=NULL;");
780
$self->pidl("if (asprintf(&idx_$l->{LEVEL_INDEX}, \"[\%d]\", $counter) != -1) {");
783
$var_name = get_array_element($var_name, $counter);
785
} elsif ($l->{TYPE} eq "DATA") {
786
$self->ParseDataPrint($e, $l, $ndr, $var_name);
787
} elsif ($l->{TYPE} eq "SWITCH") {
788
my $switch_var = ParseExprExt($l->{SWITCH_IS}, $env, $e->{ORIGINAL},
789
check_null_pointer($e, $env, sub { $self->pidl(shift); }, "return;"), check_fully_dereferenced($e, $env));
790
$self->pidl("ndr_print_set_switch_value($ndr, " . get_pointer_to($var_name) . ", $switch_var);");
794
foreach my $l (reverse @{$e->{LEVELS}}) {
795
if ($l->{TYPE} eq "POINTER") {
796
if ($l->{POINTER_TYPE} ne "ref") {
800
$self->pidl("$ndr->depth--;");
801
} elsif (($l->{TYPE} eq "ARRAY")
802
and not is_charset_array($e,$l)
803
and not has_fast_array($e,$l)) {
804
$self->pidl("free(idx_$l->{LEVEL_INDEX});");
809
$self->pidl("$ndr->depth--;");
814
#####################################################################
815
# parse scalars in a structure element - pull size
816
sub ParseSwitchPull($$$$$$)
818
my($self,$e,$l,$ndr,$var_name,$env) = @_;
819
my $switch_var = ParseExprExt($l->{SWITCH_IS}, $env, $e->{ORIGINAL},
820
check_null_pointer($e, $env, sub { $self->pidl(shift); },
821
"return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for switch_is()\");"),
822
check_fully_dereferenced($e, $env));
824
$var_name = get_pointer_to($var_name);
825
$self->pidl("NDR_CHECK(ndr_pull_set_switch_value($ndr, $var_name, $switch_var));");
828
#####################################################################
829
# push switch element
830
sub ParseSwitchPush($$$$$$)
832
my($self,$e,$l,$ndr,$var_name,$env) = @_;
833
my $switch_var = ParseExprExt($l->{SWITCH_IS}, $env, $e->{ORIGINAL},
834
check_null_pointer($e, $env, sub { $self->pidl(shift); },
835
"return ndr_push_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for switch_is()\");"),
836
check_fully_dereferenced($e, $env));
838
$var_name = get_pointer_to($var_name);
839
$self->pidl("NDR_CHECK(ndr_push_set_switch_value($ndr, $var_name, $switch_var));");
842
sub ParseDataPull($$$$$$$)
844
my ($self,$e,$l,$ndr,$var_name,$primitives,$deferred) = @_;
846
if (not ref($l->{DATA_TYPE}) or defined($l->{DATA_TYPE}->{NAME})) {
848
my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
850
if (need_pointer_to($e, $l, 0)) {
851
$var_name = get_pointer_to($var_name);
854
$var_name = get_pointer_to($var_name);
856
$self->pidl("NDR_CHECK(".TypeFunctionName("ndr_pull", $l->{DATA_TYPE})."($ndr, $ndr_flags, $var_name));");
858
if (my $range = has_property($e, "range")) {
859
$var_name = get_value_of($var_name);
860
my ($low, $high) = split(/,/, $range, 2);
861
$self->pidl("if ($var_name < $low || $var_name > $high) {");
862
$self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_RANGE, \"value out of range\");");
866
$self->ParseTypePull($l->{DATA_TYPE}, $ndr, $var_name, $primitives, $deferred);
870
sub ParseDataPush($$$$$$$)
872
my ($self,$e,$l,$ndr,$var_name,$primitives,$deferred) = @_;
874
if (not ref($l->{DATA_TYPE}) or defined($l->{DATA_TYPE}->{NAME})) {
876
my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
878
# strings are passed by value rather than reference
879
if (need_pointer_to($e, $l, 1)) {
880
$var_name = get_pointer_to($var_name);
883
$self->pidl("NDR_CHECK(".TypeFunctionName("ndr_push", $l->{DATA_TYPE})."($ndr, $ndr_flags, $var_name));");
885
$self->ParseTypePush($l->{DATA_TYPE}, $ndr, $var_name, $primitives, $deferred);
889
sub CalcNdrFlags($$$)
891
my ($l,$primitives,$deferred) = @_;
896
# Add NDR_SCALARS if this one is deferred
897
# and deferreds may be pushed
898
$scalars = 1 if ($l->{IS_DEFERRED} and $deferred);
900
# Add NDR_SCALARS if this one is not deferred and
901
# primitives may be pushed
902
$scalars = 1 if (!$l->{IS_DEFERRED} and $primitives);
904
# Add NDR_BUFFERS if this one contains deferred stuff
905
# and deferreds may be pushed
906
$buffers = 1 if ($l->{CONTAINS_DEFERRED} and $deferred);
908
return "NDR_SCALARS|NDR_BUFFERS" if ($scalars and $buffers);
909
return "NDR_SCALARS" if ($scalars);
910
return "NDR_BUFFERS" if ($buffers);
914
sub ParseMemCtxPullFlags($$$$)
916
my ($self, $e, $l) = @_;
918
return undef unless ($l->{TYPE} eq "POINTER" or $l->{TYPE} eq "ARRAY");
920
return undef if ($l->{TYPE} eq "ARRAY" and $l->{IS_FIXED});
921
return undef if has_fast_array($e, $l);
922
return undef if is_charset_array($e, $l);
926
if (($l->{TYPE} eq "POINTER") and ($l->{POINTER_TYPE} eq "ref")) {
927
my $nl = GetNextLevel($e, $l);
928
my $next_is_array = ($nl->{TYPE} eq "ARRAY");
929
my $next_is_string = (($nl->{TYPE} eq "DATA") and
930
($nl->{DATA_TYPE} eq "string"));
931
if ($next_is_array or $next_is_string) {
933
} elsif ($l->{LEVEL} eq "TOP") {
934
$mem_flags = "LIBNDR_FLAG_REF_ALLOC";
941
sub ParseMemCtxPullStart($$$$$)
943
my ($self, $e, $l, $ndr, $ptr_name) = @_;
945
my $mem_r_ctx = "_mem_save_$e->{NAME}_$l->{LEVEL_INDEX}";
946
my $mem_c_ctx = $ptr_name;
947
my $mem_c_flags = $self->ParseMemCtxPullFlags($e, $l);
949
return unless defined($mem_c_flags);
951
$self->pidl("$mem_r_ctx = NDR_PULL_GET_MEM_CTX($ndr);");
952
$self->pidl("NDR_PULL_SET_MEM_CTX($ndr, $mem_c_ctx, $mem_c_flags);");
955
sub ParseMemCtxPullEnd($$$$)
957
my ($self, $e, $l, $ndr) = @_;
959
my $mem_r_ctx = "_mem_save_$e->{NAME}_$l->{LEVEL_INDEX}";
960
my $mem_r_flags = $self->ParseMemCtxPullFlags($e, $l);
962
return unless defined($mem_r_flags);
964
$self->pidl("NDR_PULL_SET_MEM_CTX($ndr, $mem_r_ctx, $mem_r_flags);");
967
sub CheckStringTerminator($$$$$)
969
my ($self,$ndr,$e,$l,$length) = @_;
970
my $nl = GetNextLevel($e, $l);
972
# Make sure last element is zero!
973
$self->pidl("NDR_CHECK(ndr_check_string_terminator($ndr, $length, sizeof($nl->{DATA_TYPE}_t)));");
976
sub ParseElementPullLevel
978
my($self,$e,$l,$ndr,$var_name,$env,$primitives,$deferred) = @_;
980
my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
982
if ($l->{TYPE} eq "ARRAY" and ($l->{IS_VARYING} or $l->{IS_CONFORMANT})) {
983
$var_name = get_pointer_to($var_name);
986
# Only pull something if there's actually something to be pulled
987
if (defined($ndr_flags)) {
988
if ($l->{TYPE} eq "SUBCONTEXT") {
989
my $subndr = $self->ParseSubcontextPullStart($e, $l, $ndr, $env);
990
$self->ParseElementPullLevel($e, GetNextLevel($e,$l), $subndr, $var_name, $env, 1, 1);
991
$self->ParseSubcontextPullEnd($e, $l, $ndr, $env);
992
} elsif ($l->{TYPE} eq "ARRAY") {
993
my $length = $self->ParseArrayPullHeader($e, $l, $ndr, $var_name, $env);
995
my $nl = GetNextLevel($e, $l);
997
if (is_charset_array($e,$l)) {
998
if ($l->{IS_ZERO_TERMINATED}) {
999
$self->CheckStringTerminator($ndr, $e, $l, $length);
1001
$self->pidl("NDR_CHECK(ndr_pull_charset($ndr, $ndr_flags, ".get_pointer_to($var_name).", $length, sizeof(" . mapTypeName($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));");
1003
} elsif (has_fast_array($e, $l)) {
1004
if ($l->{IS_ZERO_TERMINATED}) {
1005
$self->CheckStringTerminator($ndr,$e,$l,$length);
1007
$self->pidl("NDR_CHECK(ndr_pull_array_$nl->{DATA_TYPE}($ndr, $ndr_flags, $var_name, $length));");
1010
} elsif ($l->{TYPE} eq "POINTER") {
1011
$self->ParsePtrPull($e, $l, $ndr, $var_name);
1012
} elsif ($l->{TYPE} eq "SWITCH") {
1013
$self->ParseSwitchPull($e, $l, $ndr, $var_name, $env);
1014
} elsif ($l->{TYPE} eq "DATA") {
1015
$self->ParseDataPull($e, $l, $ndr, $var_name, $primitives, $deferred);
1016
} elsif ($l->{TYPE} eq "TYPEDEF") {
1017
$typefamily{$e->{DATA}->{TYPE}}->{PULL_FN_BODY}->($self, $e->{DATA}, $ndr, $var_name);
1021
# add additional constructions
1022
if ($l->{TYPE} eq "POINTER" and $deferred) {
1023
if ($l->{POINTER_TYPE} ne "ref") {
1024
$self->pidl("if ($var_name) {");
1027
if ($l->{POINTER_TYPE} eq "relative") {
1028
$self->pidl("uint32_t _relative_save_offset;");
1029
$self->pidl("_relative_save_offset = $ndr->offset;");
1030
$self->pidl("NDR_CHECK(ndr_pull_relative_ptr2($ndr, $var_name));");
1034
$self->ParseMemCtxPullStart($e, $l, $ndr, $var_name);
1036
$var_name = get_value_of($var_name);
1037
$self->ParseElementPullLevel($e, GetNextLevel($e,$l), $ndr, $var_name, $env, 1, 1);
1039
$self->ParseMemCtxPullEnd($e, $l, $ndr);
1041
if ($l->{POINTER_TYPE} ne "ref") {
1042
if ($l->{POINTER_TYPE} eq "relative") {
1043
$self->pidl("$ndr->offset = _relative_save_offset;");
1048
} elsif ($l->{TYPE} eq "ARRAY" and
1049
not has_fast_array($e,$l) and not is_charset_array($e, $l)) {
1050
my $length = ParseExpr($l->{LENGTH_IS}, $env, $e->{ORIGINAL});
1051
my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
1052
my $array_name = $var_name;
1054
$var_name = get_array_element($var_name, $counter);
1056
$self->ParseMemCtxPullStart($e, $l, $ndr, $array_name);
1058
if (($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) {
1059
my $nl = GetNextLevel($e,$l);
1061
if ($l->{IS_ZERO_TERMINATED}) {
1062
$self->CheckStringTerminator($ndr,$e,$l,$length);
1065
$self->pidl("for ($counter = 0; $counter < $length; $counter++) {");
1067
$self->ParseElementPullLevel($e, $nl, $ndr, $var_name, $env, 1, 0);
1072
if ($deferred and ContainsDeferred($e, $l)) {
1073
$self->pidl("for ($counter = 0; $counter < $length; $counter++) {");
1075
$self->ParseElementPullLevel($e,GetNextLevel($e,$l), $ndr, $var_name, $env, 0, 1);
1080
$self->ParseMemCtxPullEnd($e, $l, $ndr);
1082
} elsif ($l->{TYPE} eq "SWITCH") {
1083
$self->ParseElementPullLevel($e, GetNextLevel($e,$l), $ndr, $var_name, $env, $primitives, $deferred);
1087
#####################################################################
1088
# parse scalars in a structure element - pull size
1089
sub ParseElementPull($$$$$$)
1091
my($self,$e,$ndr,$env,$primitives,$deferred) = @_;
1093
my $var_name = $env->{$e->{NAME}};
1097
return unless $primitives or ($deferred and ContainsDeferred($e, $e->{LEVELS}[0]));
1099
if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
1102
$represent_name = $var_name;
1103
$transmit_name = "_transmit_$e->{NAME}";
1104
$var_name = $transmit_name;
1105
$self->pidl(mapTypeName($e->{TYPE})." $var_name;");
1108
$var_name = append_prefix($e, $var_name);
1110
$self->start_flags($e, $ndr);
1112
$self->ParseElementPullLevel($e,$e->{LEVELS}[0],$ndr,$var_name,$env,$primitives,$deferred);
1114
$self->end_flags($e, $ndr);
1116
# Representation type is different from transmit_as
1117
if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
1118
$self->pidl("NDR_CHECK(ndr_$e->{TYPE}_to_$e->{REPRESENTATION_TYPE}($transmit_name, ".get_pointer_to($represent_name)."));");
1124
#####################################################################
1125
# parse a pointer in a struct element or function
1126
sub ParsePtrPull($$$$$)
1128
my($self, $e,$l,$ndr,$var_name) = @_;
1130
my $nl = GetNextLevel($e, $l);
1131
my $next_is_array = ($nl->{TYPE} eq "ARRAY");
1132
my $next_is_string = (($nl->{TYPE} eq "DATA") and
1133
($nl->{DATA_TYPE} eq "string"));
1135
if ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "TOP") {
1137
if (!$next_is_array and !$next_is_string) {
1138
$self->pidl("if ($ndr->flags & LIBNDR_FLAG_REF_ALLOC) {");
1139
$self->pidl("\tNDR_PULL_ALLOC($ndr, $var_name);");
1144
} elsif ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "EMBEDDED") {
1145
$self->pidl("NDR_CHECK(ndr_pull_ref_ptr($ndr, &_ptr_$e->{NAME}));");
1146
} elsif (($l->{POINTER_TYPE} eq "unique") or
1147
($l->{POINTER_TYPE} eq "relative") or
1148
($l->{POINTER_TYPE} eq "full")) {
1149
$self->pidl("NDR_CHECK(ndr_pull_generic_ptr($ndr, &_ptr_$e->{NAME}));");
1151
die("Unhandled pointer type $l->{POINTER_TYPE}");
1154
$self->pidl("if (_ptr_$e->{NAME}) {");
1157
# Don't do this for arrays, they're allocated at the actual level
1159
unless ($next_is_array or $next_is_string) {
1160
$self->pidl("NDR_PULL_ALLOC($ndr, $var_name);");
1162
# FIXME: Yes, this is nasty.
1163
# We allocate an array twice
1164
# - once just to indicate that it's there,
1165
# - then the real allocation...
1166
$self->pidl("NDR_PULL_ALLOC($ndr, $var_name);");
1169
#$self->pidl("memset($var_name, 0, sizeof($var_name));");
1170
if ($l->{POINTER_TYPE} eq "relative") {
1171
$self->pidl("NDR_CHECK(ndr_pull_relative_ptr1($ndr, $var_name, _ptr_$e->{NAME}));");
1174
$self->pidl("} else {");
1175
$self->pidl("\t$var_name = NULL;");
1179
sub ParseStructPushPrimitives($$$$$)
1181
my ($self, $struct, $ndr, $varname, $env) = @_;
1183
# see if the structure contains a conformant array. If it
1184
# does, then it must be the last element of the structure, and
1185
# we need to push the conformant length early, as it fits on
1186
# the wire before the structure (and even before the structure
1188
if (defined($struct->{SURROUNDING_ELEMENT})) {
1189
my $e = $struct->{SURROUNDING_ELEMENT};
1191
if (defined($e->{LEVELS}[0]) and
1192
$e->{LEVELS}[0]->{TYPE} eq "ARRAY") {
1195
if ($e->{LEVELS}[0]->{IS_ZERO_TERMINATED}) {
1196
if (has_property($e, "charset")) {
1197
$size = "ndr_charset_length($varname->$e->{NAME}, CH_$e->{PROPERTIES}->{charset})";
1199
$size = "ndr_string_length($varname->$e->{NAME}, sizeof(*$varname->$e->{NAME}))";
1202
$size = ParseExpr($e->{LEVELS}[0]->{SIZE_IS}, $env, $e->{ORIGINAL});
1205
$self->pidl("NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, $size));");
1207
$self->pidl("NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, ndr_string_array_size($ndr, $varname->$e->{NAME})));");
1211
$self->pidl("NDR_CHECK(ndr_push_align($ndr, $struct->{ALIGN}));");
1213
if (defined($struct->{PROPERTIES}{relative_base})) {
1214
# set the current offset as base for relative pointers
1215
# and store it based on the toplevel struct/union
1216
$self->pidl("NDR_CHECK(ndr_push_setup_relative_base_offset1($ndr, $varname, $ndr->offset));");
1219
$self->ParseElementPush($_, $ndr, $env, 1, 0) foreach (@{$struct->{ELEMENTS}});
1222
sub ParseStructPushDeferred($$$$)
1224
my ($self, $struct, $ndr, $varname, $env) = @_;
1225
if (defined($struct->{PROPERTIES}{relative_base})) {
1226
# retrieve the current offset as base for relative pointers
1227
# based on the toplevel struct/union
1228
$self->pidl("NDR_CHECK(ndr_push_setup_relative_base_offset2($ndr, $varname));");
1230
$self->ParseElementPush($_, $ndr, $env, 0, 1) foreach (@{$struct->{ELEMENTS}});
1233
#####################################################################
1235
sub ParseStructPush($$$$)
1237
my ($self, $struct, $ndr, $varname) = @_;
1239
return unless defined($struct->{ELEMENTS});
1241
my $env = GenerateStructEnv($struct, $varname);
1243
EnvSubstituteValue($env, $struct);
1245
$self->DeclareArrayVariables($_) foreach (@{$struct->{ELEMENTS}});
1247
$self->start_flags($struct, $ndr);
1249
$self->pidl("if (ndr_flags & NDR_SCALARS) {");
1251
$self->ParseStructPushPrimitives($struct, $ndr, $varname, $env);
1255
$self->pidl("if (ndr_flags & NDR_BUFFERS) {");
1257
$self->ParseStructPushDeferred($struct, $ndr, $varname, $env);
1261
$self->end_flags($struct, $ndr);
1264
#####################################################################
1265
# generate a push function for an enum
1266
sub ParseEnumPush($$$$)
1268
my($self,$enum,$ndr,$varname) = @_;
1269
my($type_fn) = $enum->{BASE_TYPE};
1271
$self->start_flags($enum, $ndr);
1272
$self->pidl("NDR_CHECK(ndr_push_$type_fn($ndr, NDR_SCALARS, $varname));");
1273
$self->end_flags($enum, $ndr);
1276
#####################################################################
1277
# generate a pull function for an enum
1278
sub ParseEnumPull($$$$)
1280
my($self,$enum,$ndr,$varname) = @_;
1281
my($type_fn) = $enum->{BASE_TYPE};
1282
my($type_v_decl) = mapTypeName($type_fn);
1284
$self->pidl("$type_v_decl v;");
1285
$self->start_flags($enum, $ndr);
1286
$self->pidl("NDR_CHECK(ndr_pull_$type_fn($ndr, NDR_SCALARS, &v));");
1287
$self->pidl("*$varname = v;");
1289
$self->end_flags($enum, $ndr);
1292
#####################################################################
1293
# generate a print function for an enum
1294
sub ParseEnumPrint($$$$$)
1296
my($self,$enum,$ndr,$name,$varname) = @_;
1298
$self->pidl("const char *val = NULL;");
1301
$self->start_flags($enum, $ndr);
1303
$self->pidl("switch ($varname) {");
1305
my $els = \@{$enum->{ELEMENTS}};
1306
foreach my $i (0 .. $#{$els}) {
1307
my $e = ${$els}[$i];
1309
if ($e =~ /^(.*)=/) {
1312
$self->pidl("case $e: val = \"$e\"; break;");
1318
$self->pidl("ndr_print_enum($ndr, name, \"$enum->{TYPE}\", val, $varname);");
1320
$self->end_flags($enum, $ndr);
1325
my ($e,$t,$name,$varname) = @_;
1326
return "enum $name " .
1327
($t eq "pull"?"*":"") . $varname;
1330
$typefamily{ENUM} = {
1332
PUSH_FN_BODY => \&ParseEnumPush,
1333
PULL_FN_BODY => \&ParseEnumPull,
1334
PRINT_FN_BODY => \&ParseEnumPrint,
1337
#####################################################################
1338
# generate a push function for a bitmap
1339
sub ParseBitmapPush($$$$)
1341
my($self,$bitmap,$ndr,$varname) = @_;
1342
my($type_fn) = $bitmap->{BASE_TYPE};
1344
$self->start_flags($bitmap, $ndr);
1346
$self->pidl("NDR_CHECK(ndr_push_$type_fn($ndr, NDR_SCALARS, $varname));");
1348
$self->end_flags($bitmap, $ndr);
1351
#####################################################################
1352
# generate a pull function for an bitmap
1353
sub ParseBitmapPull($$$$)
1355
my($self,$bitmap,$ndr,$varname) = @_;
1356
my $type_fn = $bitmap->{BASE_TYPE};
1357
my($type_decl) = mapTypeName($bitmap->{BASE_TYPE});
1359
$self->pidl("$type_decl v;");
1360
$self->start_flags($bitmap, $ndr);
1361
$self->pidl("NDR_CHECK(ndr_pull_$type_fn($ndr, NDR_SCALARS, &v));");
1362
$self->pidl("*$varname = v;");
1364
$self->end_flags($bitmap, $ndr);
1367
#####################################################################
1368
# generate a print function for an bitmap
1369
sub ParseBitmapPrintElement($$$$$$)
1371
my($self,$e,$bitmap,$ndr,$name,$varname) = @_;
1372
my($type_decl) = mapTypeName($bitmap->{BASE_TYPE});
1373
my($type_fn) = $bitmap->{BASE_TYPE};
1376
if ($e =~ /^(\w+) .*$/) {
1379
die "Bitmap: \"$name\" invalid Flag: \"$e\"";
1382
$self->pidl("ndr_print_bitmap_flag($ndr, sizeof($type_decl), \"$flag\", $flag, $varname);");
1385
#####################################################################
1386
# generate a print function for an bitmap
1387
sub ParseBitmapPrint($$$$$)
1389
my($self,$bitmap,$ndr,$name,$varname) = @_;
1390
my($type_decl) = mapTypeName($bitmap->{TYPE});
1391
my($type_fn) = $bitmap->{BASE_TYPE};
1393
$self->start_flags($bitmap, $ndr);
1395
$self->pidl("ndr_print_$type_fn($ndr, name, $varname);");
1397
$self->pidl("$ndr->depth++;");
1398
foreach my $e (@{$bitmap->{ELEMENTS}}) {
1399
$self->ParseBitmapPrintElement($e, $bitmap, $ndr, $name, $varname);
1401
$self->pidl("$ndr->depth--;");
1403
$self->end_flags($bitmap, $ndr);
1406
sub DeclBitmap($$$$)
1408
my ($e,$t,$name,$varname) = @_;
1409
return mapTypeName(Parse::Pidl::Typelist::bitmap_type_fn($e)) .
1410
($t eq "pull"?" *":" ") . $varname;
1413
$typefamily{BITMAP} = {
1414
DECL => \&DeclBitmap,
1415
PUSH_FN_BODY => \&ParseBitmapPush,
1416
PULL_FN_BODY => \&ParseBitmapPull,
1417
PRINT_FN_BODY => \&ParseBitmapPrint,
1420
#####################################################################
1421
# generate a struct print function
1422
sub ParseStructPrint($$$$$)
1424
my($self,$struct,$ndr,$name,$varname) = @_;
1426
return unless defined $struct->{ELEMENTS};
1428
my $env = GenerateStructEnv($struct, $varname);
1430
$self->DeclareArrayVariables($_) foreach (@{$struct->{ELEMENTS}});
1432
$self->pidl("ndr_print_struct($ndr, name, \"$name\");");
1434
$self->start_flags($struct, $ndr);
1436
$self->pidl("$ndr->depth++;");
1438
$self->ParseElementPrint($_, $ndr, $env->{$_->{NAME}}, $env)
1439
foreach (@{$struct->{ELEMENTS}});
1440
$self->pidl("$ndr->depth--;");
1442
$self->end_flags($struct, $ndr);
1445
sub DeclarePtrVariables($$)
1448
foreach my $l (@{$e->{LEVELS}}) {
1449
if ($l->{TYPE} eq "POINTER" and
1450
not ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "TOP")) {
1451
$self->pidl("uint32_t _ptr_$e->{NAME};");
1457
sub DeclareArrayVariables($$)
1461
foreach my $l (@{$e->{LEVELS}}) {
1462
next if has_fast_array($e,$l);
1463
next if is_charset_array($e,$l);
1464
if ($l->{TYPE} eq "ARRAY") {
1465
$self->pidl("uint32_t cntr_$e->{NAME}_$l->{LEVEL_INDEX};");
1470
sub DeclareMemCtxVariables($$)
1473
foreach my $l (@{$e->{LEVELS}}) {
1474
my $mem_flags = $self->ParseMemCtxPullFlags($e, $l);
1475
if (defined($mem_flags)) {
1476
$self->pidl("TALLOC_CTX *_mem_save_$e->{NAME}_$l->{LEVEL_INDEX};");
1481
sub ParseStructPullPrimitives($$$$$)
1483
my($self,$struct,$ndr,$varname,$env) = @_;
1485
if (defined $struct->{SURROUNDING_ELEMENT}) {
1486
$self->pidl("NDR_CHECK(ndr_pull_array_size($ndr, &$varname->$struct->{SURROUNDING_ELEMENT}->{NAME}));");
1489
$self->pidl("NDR_CHECK(ndr_pull_align($ndr, $struct->{ALIGN}));");
1491
if (defined($struct->{PROPERTIES}{relative_base})) {
1492
# set the current offset as base for relative pointers
1493
# and store it based on the toplevel struct/union
1494
$self->pidl("NDR_CHECK(ndr_pull_setup_relative_base_offset1($ndr, $varname, $ndr->offset));");
1497
$self->ParseElementPull($_, $ndr, $env, 1, 0) foreach (@{$struct->{ELEMENTS}});
1499
$self->add_deferred();
1502
sub ParseStructPullDeferred($$$$$)
1504
my ($self,$struct,$ndr,$varname,$env) = @_;
1506
if (defined($struct->{PROPERTIES}{relative_base})) {
1507
# retrieve the current offset as base for relative pointers
1508
# based on the toplevel struct/union
1509
$self->pidl("NDR_CHECK(ndr_pull_setup_relative_base_offset2($ndr, $varname));");
1511
foreach my $e (@{$struct->{ELEMENTS}}) {
1512
$self->ParseElementPull($e, $ndr, $env, 0, 1);
1515
$self->add_deferred();
1518
#####################################################################
1519
# parse a struct - pull side
1520
sub ParseStructPull($$$$)
1522
my($self,$struct,$ndr,$varname) = @_;
1524
return unless defined $struct->{ELEMENTS};
1526
# declare any internal pointers we need
1527
foreach my $e (@{$struct->{ELEMENTS}}) {
1528
$self->DeclarePtrVariables($e);
1529
$self->DeclareArrayVariables($e);
1530
$self->DeclareMemCtxVariables($e);
1533
$self->start_flags($struct, $ndr);
1535
my $env = GenerateStructEnv($struct, $varname);
1537
$self->pidl("if (ndr_flags & NDR_SCALARS) {");
1539
$self->ParseStructPullPrimitives($struct,$ndr,$varname,$env);
1542
$self->pidl("if (ndr_flags & NDR_BUFFERS) {");
1544
$self->ParseStructPullDeferred($struct,$ndr,$varname,$env);
1548
$self->end_flags($struct, $ndr);
1551
#####################################################################
1552
# calculate size of ndr struct
1553
sub ParseStructNdrSize($$$$)
1555
my ($self,$t, $name, $varname) = @_;
1558
if (my $flags = has_property($t, "flag")) {
1559
$self->pidl("flags |= $flags;");
1561
$self->pidl("return ndr_size_struct($varname, flags, (ndr_push_flags_fn_t)ndr_push_$name);");
1564
sub DeclStruct($$$$)
1566
my ($e,$t,$name,$varname) = @_;
1567
return ($t ne "pull"?"const ":"") . "struct $name *$varname";
1570
sub ArgsStructNdrSize($$$)
1572
my ($d, $name, $varname) = @_;
1573
return "const struct $name *$varname, int flags";
1576
$typefamily{STRUCT} = {
1577
PUSH_FN_BODY => \&ParseStructPush,
1578
DECL => \&DeclStruct,
1579
PULL_FN_BODY => \&ParseStructPull,
1580
PRINT_FN_BODY => \&ParseStructPrint,
1581
SIZE_FN_BODY => \&ParseStructNdrSize,
1582
SIZE_FN_ARGS => \&ArgsStructNdrSize,
1585
#####################################################################
1586
# calculate size of ndr struct
1587
sub ParseUnionNdrSize($$$)
1589
my ($self, $t, $name, $varname) = @_;
1592
if (my $flags = has_property($t, "flag")) {
1593
$self->pidl("flags |= $flags;");
1596
$self->pidl("return ndr_size_union($varname, flags, level, (ndr_push_flags_fn_t)ndr_push_$name);");
1599
sub ParseUnionPushPrimitives($$$$)
1601
my ($self, $e, $ndr ,$varname) = @_;
1603
my $have_default = 0;
1605
$self->pidl("int level = ndr_push_get_switch_value($ndr, $varname);");
1607
if (defined($e->{SWITCH_TYPE})) {
1608
$self->pidl("NDR_CHECK(ndr_push_$e->{SWITCH_TYPE}($ndr, NDR_SCALARS, level));");
1611
$self->pidl("switch (level) {");
1613
foreach my $el (@{$e->{ELEMENTS}}) {
1614
if ($el->{CASE} eq "default") {
1617
$self->pidl("$el->{CASE}: {");
1619
if ($el->{TYPE} ne "EMPTY") {
1621
if (defined($e->{PROPERTIES}{relative_base})) {
1622
$self->pidl("NDR_CHECK(ndr_push_align($ndr, $el->{ALIGN}));");
1623
# set the current offset as base for relative pointers
1624
# and store it based on the toplevel struct/union
1625
$self->pidl("NDR_CHECK(ndr_push_setup_relative_base_offset1($ndr, $varname, $ndr->offset));");
1627
$self->DeclareArrayVariables($el);
1628
$self->ParseElementPush($el, $ndr, {$el->{NAME} => "$varname->$el->{NAME}"}, 1, 0);
1631
$self->pidl("break; }");
1634
if (! $have_default) {
1635
$self->pidl("default:");
1636
$self->pidl("\treturn ndr_push_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);");
1642
sub ParseUnionPushDeferred($$$$)
1644
my ($self,$e,$ndr,$varname) = @_;
1646
my $have_default = 0;
1648
$self->pidl("int level = ndr_push_get_switch_value($ndr, $varname);");
1649
if (defined($e->{PROPERTIES}{relative_base})) {
1650
# retrieve the current offset as base for relative pointers
1651
# based on the toplevel struct/union
1652
$self->pidl("NDR_CHECK(ndr_push_setup_relative_base_offset2($ndr, $varname));");
1654
$self->pidl("switch (level) {");
1656
foreach my $el (@{$e->{ELEMENTS}}) {
1657
if ($el->{CASE} eq "default") {
1661
$self->pidl("$el->{CASE}:");
1662
if ($el->{TYPE} ne "EMPTY") {
1664
$self->ParseElementPush($el, $ndr, {$el->{NAME} => "$varname->$el->{NAME}"}, 0, 1);
1667
$self->pidl("break;");
1670
if (! $have_default) {
1671
$self->pidl("default:");
1672
$self->pidl("\treturn ndr_push_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);");
1678
#####################################################################
1679
# parse a union - push side
1680
sub ParseUnionPush($$$$)
1682
my ($self,$e,$ndr,$varname) = @_;
1683
my $have_default = 0;
1685
$self->start_flags($e, $ndr);
1687
$self->pidl("if (ndr_flags & NDR_SCALARS) {");
1689
$self->ParseUnionPushPrimitives($e, $ndr, $varname);
1692
$self->pidl("if (ndr_flags & NDR_BUFFERS) {");
1694
$self->ParseUnionPushDeferred($e, $ndr, $varname);
1697
$self->end_flags($e, $ndr);
1700
#####################################################################
1702
sub ParseUnionPrint($$$$$)
1704
my ($self,$e,$ndr,$name,$varname) = @_;
1705
my $have_default = 0;
1707
$self->pidl("int level;");
1708
foreach my $el (@{$e->{ELEMENTS}}) {
1709
$self->DeclareArrayVariables($el);
1712
$self->start_flags($e, $ndr);
1714
$self->pidl("level = ndr_print_get_switch_value($ndr, $varname);");
1716
$self->pidl("ndr_print_union($ndr, name, level, \"$name\");");
1718
$self->pidl("switch (level) {");
1720
foreach my $el (@{$e->{ELEMENTS}}) {
1721
if ($el->{CASE} eq "default") {
1724
$self->pidl("$el->{CASE}:");
1725
if ($el->{TYPE} ne "EMPTY") {
1727
$self->ParseElementPrint($el, $ndr, "$varname->$el->{NAME}", {});
1730
$self->pidl("break;");
1733
if (! $have_default) {
1734
$self->pidl("default:");
1735
$self->pidl("\tndr_print_bad_level($ndr, name, level);");
1740
$self->end_flags($e, $ndr);
1743
sub ParseUnionPullPrimitives($$$$$)
1745
my ($self,$e,$ndr,$varname,$switch_type) = @_;
1746
my $have_default = 0;
1748
if (defined($switch_type)) {
1749
$self->pidl("NDR_CHECK(ndr_pull_$switch_type($ndr, NDR_SCALARS, &_level));");
1750
$self->pidl("if (_level != level) {");
1751
$self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value %u for $varname\", _level);");
1755
$self->pidl("switch (level) {");
1757
foreach my $el (@{$e->{ELEMENTS}}) {
1758
if ($el->{CASE} eq "default") {
1761
$self->pidl("$el->{CASE}: {");
1763
if ($el->{TYPE} ne "EMPTY") {
1765
$self->DeclarePtrVariables($el);
1766
$self->DeclareArrayVariables($el);
1767
if (defined($e->{PROPERTIES}{relative_base})) {
1768
$self->pidl("NDR_CHECK(ndr_pull_align($ndr, $el->{ALIGN}));");
1769
# set the current offset as base for relative pointers
1770
# and store it based on the toplevel struct/union
1771
$self->pidl("NDR_CHECK(ndr_pull_setup_relative_base_offset1($ndr, $varname, $ndr->offset));");
1773
$self->ParseElementPull($el, $ndr, {$el->{NAME} => "$varname->$el->{NAME}"}, 1, 0);
1776
$self->pidl("break; }");
1779
if (! $have_default) {
1780
$self->pidl("default:");
1781
$self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);");
1787
sub ParseUnionPullDeferred($$$$)
1789
my ($self,$e,$ndr,$varname) = @_;
1790
my $have_default = 0;
1792
if (defined($e->{PROPERTIES}{relative_base})) {
1793
# retrieve the current offset as base for relative pointers
1794
# based on the toplevel struct/union
1795
$self->pidl("NDR_CHECK(ndr_pull_setup_relative_base_offset2($ndr, $varname));");
1797
$self->pidl("switch (level) {");
1799
foreach my $el (@{$e->{ELEMENTS}}) {
1800
if ($el->{CASE} eq "default") {
1804
$self->pidl("$el->{CASE}:");
1805
if ($el->{TYPE} ne "EMPTY") {
1807
$self->ParseElementPull($el, $ndr, {$el->{NAME} => "$varname->$el->{NAME}"}, 0, 1);
1810
$self->pidl("break;");
1813
if (! $have_default) {
1814
$self->pidl("default:");
1815
$self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);");
1823
#####################################################################
1824
# parse a union - pull side
1825
sub ParseUnionPull($$$$)
1827
my ($self,$e,$ndr,$varname) = @_;
1828
my $switch_type = $e->{SWITCH_TYPE};
1830
$self->pidl("int level;");
1831
if (defined($switch_type)) {
1832
if (Parse::Pidl::Typelist::typeIs($switch_type, "ENUM")) {
1833
$switch_type = Parse::Pidl::Typelist::enum_type_fn(getType($switch_type)->{DATA});
1835
$self->pidl(mapTypeName($switch_type) . " _level;");
1838
my %double_cases = ();
1839
foreach my $el (@{$e->{ELEMENTS}}) {
1840
next if ($el->{TYPE} eq "EMPTY");
1841
next if ($double_cases{"$el->{NAME}"});
1842
$self->DeclareMemCtxVariables($el);
1843
$double_cases{"$el->{NAME}"} = 1;
1846
$self->start_flags($e, $ndr);
1848
$self->pidl("level = ndr_pull_get_switch_value($ndr, $varname);");
1850
$self->pidl("if (ndr_flags & NDR_SCALARS) {");
1852
$self->ParseUnionPullPrimitives($e,$ndr,$varname,$switch_type);
1856
$self->pidl("if (ndr_flags & NDR_BUFFERS) {");
1858
$self->ParseUnionPullDeferred($e,$ndr,$varname);
1862
$self->add_deferred();
1864
$self->end_flags($e, $ndr);
1869
my ($e,$t,$name,$varname) = @_;
1870
return ($t ne "pull"?"const ":"") . "union $name *$varname";
1873
sub ArgsUnionNdrSize($$)
1876
return "const union $name *r, uint32_t level, int flags";
1879
$typefamily{UNION} = {
1880
PUSH_FN_BODY => \&ParseUnionPush,
1881
DECL => \&DeclUnion,
1882
PULL_FN_BODY => \&ParseUnionPull,
1883
PRINT_FN_BODY => \&ParseUnionPrint,
1884
SIZE_FN_ARGS => \&ArgsUnionNdrSize,
1885
SIZE_FN_BODY => \&ParseUnionNdrSize,
1888
#####################################################################
1889
# parse a typedef - push side
1890
sub ParseTypedefPush($$$$)
1892
my($self,$e,$ndr,$varname) = @_;
1896
$env->{$e->{NAME}} = $varname;
1898
$self->ParseElementPushLevel($e, $e->{LEVELS}[0], $ndr, $varname, $env, 1, 1);
1901
#####################################################################
1902
# parse a typedef - pull side
1903
sub ParseTypedefPull($$$$)
1905
my($self,$e,$ndr,$varname) = @_;
1909
$env->{$e->{NAME}} = $varname;
1911
$self->ParseElementPullLevel($e, $e->{LEVELS}[0], $ndr, $varname, $env, 1, 1);
1914
#####################################################################
1915
# parse a typedef - print side
1916
sub ParseTypedefPrint($$$$$)
1918
my($self,$e,$ndr,$name,$varname) = @_;
1920
$typefamily{$e->{DATA}->{TYPE}}->{PRINT_FN_BODY}->($self, $e->{DATA}, $ndr, $name, $varname);
1923
#####################################################################
1924
## calculate the size of a structure
1925
sub ParseTypedefNdrSize($$$$)
1927
my($self,$t,$name,$varname) = @_;
1929
$typefamily{$t->{DATA}->{TYPE}}->{SIZE_FN_BODY}->($self, $t->{DATA}, $name, $varname);
1932
sub DeclTypedef($$$$)
1934
my ($e, $t, $name, $varname) = @_;
1936
return $typefamily{$e->{DATA}->{TYPE}}->{DECL}->($e->{DATA}, $t, $name, $varname);
1939
sub ArgsTypedefNdrSize($$$)
1941
my ($d, $name, $varname) = @_;
1942
return $typefamily{$d->{DATA}->{TYPE}}->{SIZE_FN_ARGS}->($d->{DATA}, $name, $varname);
1945
$typefamily{TYPEDEF} = {
1946
PUSH_FN_BODY => \&ParseTypedefPush,
1947
DECL => \&DeclTypedef,
1948
PULL_FN_BODY => \&ParseTypedefPull,
1949
PRINT_FN_BODY => \&ParseTypedefPrint,
1950
SIZE_FN_ARGS => \&ArgsTypedefNdrSize,
1951
SIZE_FN_BODY => \&ParseTypedefNdrSize,
1954
#####################################################################
1955
# parse a function - print side
1956
sub ParseFunctionPrint($$)
1958
my($self, $fn) = @_;
1961
$self->pidl_hdr("void ndr_print_$fn->{NAME}(struct ndr_print *$ndr, const char *name, int flags, const struct $fn->{NAME} *r);");
1963
return if has_property($fn, "noprint");
1965
$self->pidl("_PUBLIC_ void ndr_print_$fn->{NAME}(struct ndr_print *$ndr, const char *name, int flags, const struct $fn->{NAME} *r)");
1969
foreach my $e (@{$fn->{ELEMENTS}}) {
1970
$self->DeclareArrayVariables($e);
1973
$self->pidl("ndr_print_struct($ndr, name, \"$fn->{NAME}\");");
1974
$self->pidl("$ndr->depth++;");
1976
$self->pidl("if (flags & NDR_SET_VALUES) {");
1977
$self->pidl("\t$ndr->flags |= LIBNDR_PRINT_SET_VALUES;");
1980
$self->pidl("if (flags & NDR_IN) {");
1982
$self->pidl("ndr_print_struct($ndr, \"in\", \"$fn->{NAME}\");");
1983
$self->pidl("$ndr->depth++;");
1985
my $env = GenerateFunctionInEnv($fn);
1987
foreach my $e (@{$fn->{ELEMENTS}}) {
1988
if (grep(/in/,@{$e->{DIRECTION}})) {
1989
$self->ParseElementPrint($e, $ndr, $env->{$e->{NAME}}, $env);
1992
$self->pidl("$ndr->depth--;");
1996
$self->pidl("if (flags & NDR_OUT) {");
1998
$self->pidl("ndr_print_struct($ndr, \"out\", \"$fn->{NAME}\");");
1999
$self->pidl("$ndr->depth++;");
2001
$env = GenerateFunctionOutEnv($fn);
2002
foreach my $e (@{$fn->{ELEMENTS}}) {
2003
if (grep(/out/,@{$e->{DIRECTION}})) {
2004
$self->ParseElementPrint($e, $ndr, $env->{$e->{NAME}}, $env);
2007
if ($fn->{RETURN_TYPE}) {
2008
$self->pidl("ndr_print_$fn->{RETURN_TYPE}($ndr, \"result\", r->out.result);");
2010
$self->pidl("$ndr->depth--;");
2014
$self->pidl("$ndr->depth--;");
2020
#####################################################################
2022
sub ParseFunctionPush($$)
2024
my($self, $fn) = @_;
2027
$self->fn_declare("push", $fn, "enum ndr_err_code ndr_push_$fn->{NAME}(struct ndr_push *$ndr, int flags, const struct $fn->{NAME} *r)") or return;
2029
return if has_property($fn, "nopush");
2034
foreach my $e (@{$fn->{ELEMENTS}}) {
2035
$self->DeclareArrayVariables($e);
2038
$self->pidl("if (flags & NDR_IN) {");
2041
my $env = GenerateFunctionInEnv($fn);
2043
EnvSubstituteValue($env, $fn);
2045
foreach my $e (@{$fn->{ELEMENTS}}) {
2046
if (grep(/in/,@{$e->{DIRECTION}})) {
2047
$self->ParseElementPush($e, $ndr, $env, 1, 1);
2054
$self->pidl("if (flags & NDR_OUT) {");
2057
$env = GenerateFunctionOutEnv($fn);
2058
foreach my $e (@{$fn->{ELEMENTS}}) {
2059
if (grep(/out/,@{$e->{DIRECTION}})) {
2060
$self->ParseElementPush($e, $ndr, $env, 1, 1);
2064
if ($fn->{RETURN_TYPE}) {
2065
$self->pidl("NDR_CHECK(ndr_push_$fn->{RETURN_TYPE}($ndr, NDR_SCALARS, r->out.result));");
2070
$self->pidl("return NDR_ERR_SUCCESS;");
2076
sub AllocateArrayLevel($$$$$$)
2078
my ($self,$e,$l,$ndr,$var,$size) = @_;
2080
my $pl = GetPrevLevel($e, $l);
2081
if (defined($pl) and
2082
$pl->{TYPE} eq "POINTER" and
2083
$pl->{POINTER_TYPE} eq "ref"
2084
and not $l->{IS_ZERO_TERMINATED}) {
2085
$self->pidl("if ($ndr->flags & LIBNDR_FLAG_REF_ALLOC) {");
2086
$self->pidl("\tNDR_PULL_ALLOC_N($ndr, $var, $size);");
2088
if (grep(/in/,@{$e->{DIRECTION}}) and
2089
grep(/out/,@{$e->{DIRECTION}})) {
2090
$self->pidl("memcpy(r->out.$e->{NAME}, r->in.$e->{NAME}, $size * sizeof(*r->in.$e->{NAME}));");
2095
$self->pidl("NDR_PULL_ALLOC_N($ndr, $var, $size);");
2098
#####################################################################
2100
sub ParseFunctionPull($$)
2105
# pull function args
2106
$self->fn_declare("pull", $fn, "enum ndr_err_code ndr_pull_$fn->{NAME}(struct ndr_pull *$ndr, int flags, struct $fn->{NAME} *r)") or return;
2111
# declare any internal pointers we need
2112
foreach my $e (@{$fn->{ELEMENTS}}) {
2113
$self->DeclarePtrVariables($e);
2114
$self->DeclareArrayVariables($e);
2117
my %double_cases = ();
2118
foreach my $e (@{$fn->{ELEMENTS}}) {
2119
next if ($e->{TYPE} eq "EMPTY");
2120
next if ($double_cases{"$e->{NAME}"});
2121
$self->DeclareMemCtxVariables($e);
2122
$double_cases{"$e->{NAME}"} = 1;
2125
$self->pidl("if (flags & NDR_IN) {");
2128
# auto-init the out section of a structure. I originally argued that
2129
# this was a bad idea as it hides bugs, but coping correctly
2130
# with initialisation and not wiping ref vars is turning
2131
# out to be too tricky (tridge)
2132
foreach my $e (@{$fn->{ELEMENTS}}) {
2133
next unless grep(/out/, @{$e->{DIRECTION}});
2134
$self->pidl("ZERO_STRUCT(r->out);");
2139
my $env = GenerateFunctionInEnv($fn);
2141
foreach my $e (@{$fn->{ELEMENTS}}) {
2142
next unless (grep(/in/, @{$e->{DIRECTION}}));
2143
$self->ParseElementPull($e, $ndr, $env, 1, 1);
2146
# allocate the "simple" out ref variables. FIXME: Shouldn't this have it's
2147
# own flag rather than be in NDR_IN ?
2149
foreach my $e (@{$fn->{ELEMENTS}}) {
2150
next unless (grep(/out/, @{$e->{DIRECTION}}));
2151
next unless ($e->{LEVELS}[0]->{TYPE} eq "POINTER" and
2152
$e->{LEVELS}[0]->{POINTER_TYPE} eq "ref");
2153
next if (($e->{LEVELS}[1]->{TYPE} eq "DATA") and
2154
($e->{LEVELS}[1]->{DATA_TYPE} eq "string"));
2155
next if (($e->{LEVELS}[1]->{TYPE} eq "ARRAY")
2156
and $e->{LEVELS}[1]->{IS_ZERO_TERMINATED});
2158
if ($e->{LEVELS}[1]->{TYPE} eq "ARRAY") {
2159
my $size = ParseExprExt($e->{LEVELS}[1]->{SIZE_IS}, $env, $e->{ORIGINAL},
2160
check_null_pointer($e, $env, sub { $self->pidl(shift); },
2161
"return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for size_is()\");"),
2162
check_fully_dereferenced($e, $env));
2163
$self->pidl("NDR_PULL_ALLOC_N($ndr, r->out.$e->{NAME}, $size);");
2165
if (grep(/in/, @{$e->{DIRECTION}})) {
2166
$self->pidl("memcpy(r->out.$e->{NAME}, r->in.$e->{NAME}, ($size) * sizeof(*r->in.$e->{NAME}));");
2168
$self->pidl("memset(r->out.$e->{NAME}, 0, ($size) * sizeof(*r->out.$e->{NAME}));");
2171
$self->pidl("NDR_PULL_ALLOC($ndr, r->out.$e->{NAME});");
2173
if (grep(/in/, @{$e->{DIRECTION}})) {
2174
$self->pidl("*r->out.$e->{NAME} = *r->in.$e->{NAME};");
2176
$self->pidl("ZERO_STRUCTP(r->out.$e->{NAME});");
2181
$self->add_deferred();
2185
$self->pidl("if (flags & NDR_OUT) {");
2188
$env = GenerateFunctionOutEnv($fn);
2189
foreach my $e (@{$fn->{ELEMENTS}}) {
2190
next unless grep(/out/, @{$e->{DIRECTION}});
2191
$self->ParseElementPull($e, $ndr, $env, 1, 1);
2194
if ($fn->{RETURN_TYPE}) {
2195
$self->pidl("NDR_CHECK(ndr_pull_$fn->{RETURN_TYPE}($ndr, NDR_SCALARS, &r->out.result));");
2198
$self->add_deferred();
2202
$self->pidl("return NDR_ERR_SUCCESS;");
2208
sub AuthServiceStruct($$$)
2210
my ($self, $ifacename, $authservice) = @_;
2211
my @a = split /,/, $authservice;
2212
my $authservice_count = $#a + 1;
2214
$self->pidl("static const char * const $ifacename\_authservice_strings[] = {");
2215
foreach my $ap (@a) {
2216
$self->pidl("\t$ap, ");
2221
$self->pidl("static const struct ndr_interface_string_array $ifacename\_authservices = {");
2222
$self->pidl("\t.count\t= $authservice_count,");
2223
$self->pidl("\t.names\t= $ifacename\_authservice_strings");
2228
sub FunctionCallEntry($$)
2230
my ($self, $d) = @_;
2231
return if not defined($d->{OPNUM});
2233
$self->pidl("\t\t\"$d->{NAME}\",");
2234
$self->pidl("\t\tsizeof(struct $d->{NAME}),");
2235
$self->pidl("\t\t(ndr_push_flags_fn_t) ndr_push_$d->{NAME},");
2236
$self->pidl("\t\t(ndr_pull_flags_fn_t) ndr_pull_$d->{NAME},");
2237
$self->pidl("\t\t(ndr_print_function_t) ndr_print_$d->{NAME},");
2238
$self->pidl("\t\t".($d->{ASYNC}?"true":"false").",");
2239
$self->pidl("\t},");
2242
#####################################################################
2243
# produce a function call table
2244
sub FunctionTable($$)
2246
my($self,$interface) = @_;
2248
my $uname = uc $interface->{NAME};
2250
return if ($#{$interface->{FUNCTIONS}}+1 == 0);
2251
return unless defined ($interface->{PROPERTIES}->{uuid});
2253
$self->pidl("static const struct ndr_interface_call $interface->{NAME}\_calls[] = {");
2255
foreach my $d (@{$interface->{INHERITED_FUNCTIONS}},@{$interface->{FUNCTIONS}}) {
2256
$self->FunctionCallEntry($d);
2259
$self->pidl("\t{ NULL, 0, NULL, NULL, NULL, false }");
2263
$self->pidl("static const char * const $interface->{NAME}\_endpoint_strings[] = {");
2264
foreach my $ep (@{$interface->{ENDPOINTS}}) {
2265
$self->pidl("\t$ep, ");
2267
my $endpoint_count = $#{$interface->{ENDPOINTS}}+1;
2272
$self->pidl("static const struct ndr_interface_string_array $interface->{NAME}\_endpoints = {");
2273
$self->pidl("\t.count\t= $endpoint_count,");
2274
$self->pidl("\t.names\t= $interface->{NAME}\_endpoint_strings");
2278
if (! defined $interface->{PROPERTIES}->{authservice}) {
2279
$interface->{PROPERTIES}->{authservice} = "\"host\"";
2282
$self->AuthServiceStruct($interface->{NAME},
2283
$interface->{PROPERTIES}->{authservice});
2285
$self->pidl("\nconst struct ndr_interface_table ndr_table_$interface->{NAME} = {");
2286
$self->pidl("\t.name\t\t= \"$interface->{NAME}\",");
2287
$self->pidl("\t.syntax_id\t= {");
2288
$self->pidl("\t\t" . print_uuid($interface->{UUID}) .",");
2289
$self->pidl("\t\tNDR_$uname\_VERSION");
2290
$self->pidl("\t},");
2291
$self->pidl("\t.helpstring\t= NDR_$uname\_HELPSTRING,");
2292
$self->pidl("\t.num_calls\t= $count,");
2293
$self->pidl("\t.calls\t\t= $interface->{NAME}\_calls,");
2294
$self->pidl("\t.endpoints\t= &$interface->{NAME}\_endpoints,");
2295
$self->pidl("\t.authservices\t= &$interface->{NAME}\_authservices");
2301
#####################################################################
2302
# generate include statements for imported idl files
2307
foreach (@imports) {
2308
$_ = unmake_str($_);
2310
$self->pidl(choose_header("librpc/gen_ndr/ndr_$_\.h", "gen_ndr/ndr_$_.h"));
2314
#####################################################################
2315
# generate include statements for included header files
2320
foreach (@includes) {
2321
$self->pidl_hdr("#include $_");
2325
#####################################################################
2326
# generate prototypes and defines for the interface definitions
2327
# FIXME: these prototypes are for the DCE/RPC client functions, not the
2328
# NDR parser and so do not belong here, technically speaking
2329
sub HeaderInterface($$$)
2331
my($self,$interface,$needed) = @_;
2335
if ($needed->{"compression"}) {
2336
$self->pidl(choose_header("librpc/ndr/ndr_compression.h", "ndr/compression.h"));
2339
if (has_property($interface, "object")) {
2340
$self->pidl(choose_header("librpc/gen_ndr/ndr_orpc.h", "ndr/orpc.h"));
2343
if (defined $interface->{PROPERTIES}->{helper}) {
2344
$self->HeaderInclude(split /,/, $interface->{PROPERTIES}->{helper});
2347
if (defined $interface->{PROPERTIES}->{uuid}) {
2348
my $name = uc $interface->{NAME};
2349
$self->pidl_hdr("#define NDR_$name\_UUID " .
2350
Parse::Pidl::Util::make_str(lc($interface->{PROPERTIES}->{uuid})));
2352
if(!defined $interface->{PROPERTIES}->{version}) { $interface->{PROPERTIES}->{version} = "0.0"; }
2353
$self->pidl_hdr("#define NDR_$name\_VERSION $interface->{PROPERTIES}->{version}");
2355
$self->pidl_hdr("#define NDR_$name\_NAME \"$interface->{NAME}\"");
2357
if(!defined $interface->{PROPERTIES}->{helpstring}) { $interface->{PROPERTIES}->{helpstring} = "NULL"; }
2358
$self->pidl_hdr("#define NDR_$name\_HELPSTRING $interface->{PROPERTIES}->{helpstring}");
2360
$self->pidl_hdr("extern const struct ndr_interface_table ndr_table_$interface->{NAME};");
2363
foreach (@{$interface->{FUNCTIONS}}) {
2364
next if has_property($_, "noopnum");
2365
next if grep(/^$_->{NAME}$/,@{$interface->{INHERITED_FUNCTIONS}});
2366
my $u_name = uc $_->{NAME};
2368
my $val = sprintf("0x%02x", $count);
2369
if (defined($interface->{BASE})) {
2370
$val .= " + NDR_" . uc $interface->{BASE} . "_CALL_COUNT";
2373
$self->pidl_hdr("#define NDR_$u_name ($val)");
2375
$self->pidl_hdr("");
2381
if (defined($interface->{BASE})) {
2382
$val .= " + NDR_" . uc $interface->{BASE} . "_CALL_COUNT";
2385
$self->pidl_hdr("#define NDR_" . uc $interface->{NAME} . "_CALL_COUNT ($val)");
2389
sub ParseTypePush($$$$$$)
2391
my ($self,$e, $ndr, $varname, $primitives, $deferred) = @_;
2393
# save the old relative_base_offset
2394
$self->pidl("uint32_t _save_relative_base_offset = ndr_push_get_relative_base_offset($ndr);") if defined(has_property($e, "relative_base"));
2395
$typefamily{$e->{TYPE}}->{PUSH_FN_BODY}->($self, $e, $ndr, $varname);
2396
# restore the old relative_base_offset
2397
$self->pidl("ndr_push_restore_relative_base_offset($ndr, _save_relative_base_offset);") if defined(has_property($e, "relative_base"));
2400
sub ParseTypePushFunction($$$)
2402
my ($self, $e, $varname) = @_;
2405
my $args = $typefamily{$e->{TYPE}}->{DECL}->($e, "push", $e->{NAME}, $varname);
2407
$self->fn_declare("push", $e, "enum ndr_err_code ".TypeFunctionName("ndr_push", $e)."(struct ndr_push *$ndr, int ndr_flags, $args)") or return;
2411
$self->ParseTypePush($e, $ndr, $varname, 1, 1);
2412
$self->pidl("return NDR_ERR_SUCCESS;");
2418
sub ParseTypePull($$$$$$)
2420
my ($self, $e, $ndr, $varname, $primitives, $deferred) = @_;
2422
# save the old relative_base_offset
2423
$self->pidl("uint32_t _save_relative_base_offset = ndr_pull_get_relative_base_offset($ndr);") if defined(has_property($e, "relative_base"));
2424
$typefamily{$e->{TYPE}}->{PULL_FN_BODY}->($self, $e, $ndr, $varname);
2425
# restore the old relative_base_offset
2426
$self->pidl("ndr_pull_restore_relative_base_offset($ndr, _save_relative_base_offset);") if defined(has_property($e, "relative_base"));
2429
sub ParseTypePullFunction($$)
2431
my ($self, $e, $varname) = @_;
2434
my $args = $typefamily{$e->{TYPE}}->{DECL}->($e, "pull", $e->{NAME}, $varname);
2436
$self->fn_declare("pull", $e, "enum ndr_err_code ".TypeFunctionName("ndr_pull", $e)."(struct ndr_pull *$ndr, int ndr_flags, $args)") or return;
2440
$self->ParseTypePull($e, $ndr, $varname, 1, 1);
2441
$self->pidl("return NDR_ERR_SUCCESS;");
2447
sub ParseTypePrint($$$$)
2449
my ($self, $e, $ndr, $varname) = @_;
2451
$typefamily{$e->{TYPE}}->{PRINT_FN_BODY}->($self, $e, $ndr, $e->{NAME}, $varname);
2454
sub ParseTypePrintFunction($$$)
2456
my ($self, $e, $varname) = @_;
2459
my $args = $typefamily{$e->{TYPE}}->{DECL}->($e, "print", $e->{NAME}, $varname);
2461
$self->pidl_hdr("void ".TypeFunctionName("ndr_print", $e)."(struct ndr_print *ndr, const char *name, $args);");
2463
return if (has_property($e, "noprint"));
2465
$self->pidl("_PUBLIC_ void ".TypeFunctionName("ndr_print", $e)."(struct ndr_print *$ndr, const char *name, $args)");
2468
$self->ParseTypePrint($e, $ndr, $varname);
2474
sub ParseTypeNdrSize($$)
2479
my $tf = $typefamily{$t->{TYPE}};
2480
my $args = $tf->{SIZE_FN_ARGS}->($t, $t->{NAME}, $varname);
2482
$self->fn_declare("size", $t, "size_t ndr_size_$t->{NAME}($args)") or return;
2486
$typefamily{$t->{TYPE}}->{SIZE_FN_BODY}->($self,$t, $t->{NAME}, $varname);
2492
#####################################################################
2493
# parse the interface definitions
2494
sub ParseInterface($$$)
2496
my($self,$interface,$needed) = @_;
2498
$self->pidl_hdr("#ifndef _HEADER_NDR_$interface->{NAME}");
2499
$self->pidl_hdr("#define _HEADER_NDR_$interface->{NAME}");
2501
$self->pidl_hdr("");
2503
$self->HeaderInterface($interface, $needed);
2506
foreach my $d (@{$interface->{TYPES}}) {
2507
next unless(typeHasBody($d));
2509
($needed->{TypeFunctionName("ndr_push", $d)}) && $self->ParseTypePushFunction($d, "r");
2510
($needed->{TypeFunctionName("ndr_pull", $d)}) && $self->ParseTypePullFunction($d, "r");
2511
($needed->{TypeFunctionName("ndr_print", $d)}) && $self->ParseTypePrintFunction($d, "r");
2513
# Make sure we don't generate a function twice...
2514
$needed->{TypeFunctionName("ndr_push", $d)} =
2515
$needed->{TypeFunctionName("ndr_pull", $d)} =
2516
$needed->{TypeFunctionName("ndr_print", $d)} = 0;
2518
($needed->{"ndr_size_$d->{NAME}"}) && $self->ParseTypeNdrSize($d);
2522
foreach my $d (@{$interface->{FUNCTIONS}}) {
2523
($needed->{"ndr_push_$d->{NAME}"}) && $self->ParseFunctionPush($d);
2524
($needed->{"ndr_pull_$d->{NAME}"}) && $self->ParseFunctionPull($d);
2525
($needed->{"ndr_print_$d->{NAME}"}) && $self->ParseFunctionPrint($d);
2527
# Make sure we don't generate a function twice...
2528
$needed->{"ndr_push_$d->{NAME}"} = $needed->{"ndr_pull_$d->{NAME}"} =
2529
$needed->{"ndr_print_$d->{NAME}"} = 0;
2532
$self->FunctionTable($interface);
2534
$self->pidl_hdr("#endif /* _HEADER_NDR_$interface->{NAME} */");
2537
sub GenerateIncludes($)
2541
$self->pidl("#include \"includes.h\"");
2543
$self->pidl("#define _GNU_SOURCE");
2544
$self->pidl("#include <stdint.h>");
2545
$self->pidl("#include <stdlib.h>");
2546
$self->pidl("#include <stdio.h>");
2547
$self->pidl("#include <stdbool.h>");
2548
$self->pidl("#include <stdarg.h>");
2549
$self->pidl("#include <string.h>");
2553
#####################################################################
2554
# parse a parsed IDL structure back into an IDL file
2557
my($self, $ndr,$gen_header,$ndr_header) = @_;
2559
$self->pidl_hdr("/* header auto-generated by pidl */");
2560
$self->pidl_hdr("");
2561
$self->pidl_hdr(choose_header("librpc/ndr/libndr.h", "ndr.h"));
2562
$self->pidl_hdr("#include \"$gen_header\"") if ($gen_header);
2563
$self->pidl_hdr("");
2565
$self->pidl("/* parser auto-generated by pidl */");
2567
$self->GenerateIncludes();
2568
$self->pidl("#include \"$ndr_header\"") if ($ndr_header);
2574
($_->{TYPE} eq "INTERFACE") && NeededInterface($_, \%needed);
2578
($_->{TYPE} eq "INTERFACE") && $self->ParseInterface($_, \%needed);
2579
($_->{TYPE} eq "IMPORT") && $self->HeaderImport(@{$_->{PATHS}});
2580
($_->{TYPE} eq "INCLUDE") && $self->HeaderInclude(@{$_->{PATHS}});
2583
return ($self->{res_hdr}, $self->{res});
2586
sub NeededElement($$$)
2588
my ($e, $dir, $needed) = @_;
2590
return if ($e->{TYPE} eq "EMPTY");
2592
return if (ref($e->{TYPE}) eq "HASH" and
2593
not defined($e->{TYPE}->{NAME}));
2596
if (ref($e->{TYPE}) eq "HASH") {
2597
$t = $e->{TYPE}->{TYPE}."_".$e->{TYPE}->{NAME};
2602
if (ref($e->{REPRESENTATION_TYPE}) eq "HASH") {
2603
$rt = $e->{REPRESENTATION_TYPE}->{TYPE}."_".$e->{REPRESENTATION_TYPE}->{NAME};
2605
$rt = $e->{REPRESENTATION_TYPE};
2608
die ("$e->{NAME} $t, $rt FOO") unless ($rt ne "");
2611
if ($dir eq "print") {
2612
push(@fn, TypeFunctionName("ndr_print", $e->{REPRESENTATION_TYPE}));
2613
} elsif ($dir eq "pull") {
2614
push (@fn, TypeFunctionName("ndr_pull", $e->{TYPE}));
2615
push (@fn, "ndr_$t\_to_$rt")
2617
} elsif ($dir eq "push") {
2618
push (@fn, TypeFunctionName("ndr_push", $e->{TYPE}));
2619
push (@fn, "ndr_$rt\_to_$t")
2622
die("invalid direction `$dir'");
2626
unless (defined($needed->{$_})) {
2632
sub NeededFunction($$)
2634
my ($fn,$needed) = @_;
2635
$needed->{"ndr_pull_$fn->{NAME}"} = 1;
2636
$needed->{"ndr_push_$fn->{NAME}"} = 1;
2637
$needed->{"ndr_print_$fn->{NAME}"} = 1;
2638
foreach my $e (@{$fn->{ELEMENTS}}) {
2640
NeededElement($e, $_, $needed) foreach ("pull", "push", "print");
2646
sub NeededType($$$);
2647
my ($t,$needed,$req) = @_;
2649
NeededType($t->{DATA}, $needed, $req) if ($t->{TYPE} eq "TYPEDEF");
2651
if ($t->{TYPE} eq "STRUCT" or $t->{TYPE} eq "UNION") {
2652
return unless defined($t->{ELEMENTS});
2653
for my $e (@{$t->{ELEMENTS}}) {
2655
if (has_property($e, "compression")) {
2656
$needed->{"compression"} = 1;
2658
NeededElement($e, $req, $needed);
2659
NeededType($e->{TYPE}, $needed, $req) if (ref($e->{TYPE}) eq "HASH");
2664
#####################################################################
2665
# work out what parse functions are needed
2666
sub NeededInterface($$)
2668
my ($interface,$needed) = @_;
2669
NeededFunction($_, $needed) foreach (@{$interface->{FUNCTIONS}});
2670
foreach (reverse @{$interface->{TYPES}}) {
2671
if (has_property($_, "public")) {
2672
$needed->{TypeFunctionName("ndr_pull", $_)} = $needed->{TypeFunctionName("ndr_push", $_)} =
2673
$needed->{TypeFunctionName("ndr_print", $_)} = 1;
2676
NeededType($_, $needed, "pull") if ($needed->{TypeFunctionName("ndr_pull", $_)});
2677
NeededType($_, $needed, "push") if ($needed->{TypeFunctionName("ndr_push", $_)});
2678
NeededType($_, $needed, "print") if ($needed->{TypeFunctionName("ndr_print", $_)});
2679
if (has_property($_, "gensize")) {
2680
$needed->{"ndr_size_$_->{NAME}"} = 1;
2685
sub TypeFunctionName($$)
2687
my ($prefix, $t) = @_;
2689
return "$prefix\_$t->{NAME}" if (ref($t) eq "HASH" and
2690
$t->{TYPE} eq "TYPEDEF");
2691
return "$prefix\_$t->{TYPE}_$t->{NAME}" if (ref($t) eq "HASH");
2692
return "$prefix\_$t";