r14550: Fix tests
[Samba.git] / source / pidl / lib / Parse / Pidl / Samba4 / NDR / Parser.pm
blobe7f8c85a90da3997f839f9e610ee0e337fdc19d1
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-2005
6 # released under the GNU GPL
8 package Parse::Pidl::Samba4::NDR::Parser;
10 use strict;
11 use Parse::Pidl::Typelist qw(hasType getType mapType);
12 use Parse::Pidl::Util qw(has_property ParseExpr print_uuid);
13 use Parse::Pidl::NDR qw(GetPrevLevel GetNextLevel ContainsDeferred);
14 use Parse::Pidl::Samba4 qw(is_intree choose_header);
16 use vars qw($VERSION);
17 $VERSION = '0.01';
19 # list of known types
20 my %typefamily;
22 sub get_typefamily($)
24 my $n = shift;
25 return $typefamily{$n};
28 sub append_prefix($$)
30 my ($e, $var_name) = @_;
31 my $pointers = 0;
33 foreach my $l (@{$e->{LEVELS}}) {
34 if ($l->{TYPE} eq "POINTER") {
35 $pointers++;
36 } elsif ($l->{TYPE} eq "ARRAY") {
37 if (($pointers == 0) and
38 (not $l->{IS_FIXED}) and
39 (not $l->{IS_INLINE})) {
40 return get_value_of($var_name);
42 } elsif ($l->{TYPE} eq "DATA") {
43 if (Parse::Pidl::Typelist::scalar_is_reference($l->{DATA_TYPE})) {
44 return get_value_of($var_name) unless ($pointers);
49 return $var_name;
52 sub has_fast_array($$)
54 my ($e,$l) = @_;
56 return 0 if ($l->{TYPE} ne "ARRAY");
58 my $nl = GetNextLevel($e,$l);
59 return 0 unless ($nl->{TYPE} eq "DATA");
60 return 0 unless (hasType($nl->{DATA_TYPE}));
62 my $t = getType($nl->{DATA_TYPE});
64 # Only uint8 and string have fast array functions at the moment
65 return ($t->{NAME} eq "uint8") or ($t->{NAME} eq "string");
68 sub is_charset_array($$)
70 my ($e,$l) = @_;
72 return 0 if ($l->{TYPE} ne "ARRAY");
74 my $nl = GetNextLevel($e,$l);
76 return 0 unless ($nl->{TYPE} eq "DATA");
78 return has_property($e, "charset");
81 sub get_pointer_to($)
83 my $var_name = shift;
85 if ($var_name =~ /^\*(.*)$/) {
86 return $1;
87 } elsif ($var_name =~ /^\&(.*)$/) {
88 return "&($var_name)";
89 } else {
90 return "&$var_name";
94 sub get_value_of($)
96 my $var_name = shift;
98 if ($var_name =~ /^\&(.*)$/) {
99 return $1;
100 } else {
101 return "*$var_name";
105 my $res;
106 my $deferred = "";
107 my $tabs = "";
109 ####################################
110 # pidl() is our basic output routine
111 sub pidl($)
113 my $d = shift;
114 if ($d) {
115 $res .= $tabs;
116 $res .= $d;
118 $res .="\n";
121 my $res_hdr;
123 sub pidl_hdr ($) { my $d = shift; $res_hdr .= "$d\n"; }
125 ####################################
126 # defer() is like pidl(), but adds to
127 # a deferred buffer which is then added to the
128 # output buffer at the end of the structure/union/function
129 # This is needed to cope with code that must be pushed back
130 # to the end of a block of elements
131 sub defer($)
133 my $d = shift;
134 if ($d) {
135 $deferred .= $tabs;
136 $deferred .= $d;
138 $deferred .="\n";
141 ########################################
142 # add the deferred content to the current
143 # output
144 sub add_deferred()
146 $res .= $deferred;
147 $deferred = "";
150 sub indent()
152 $tabs .= "\t";
155 sub deindent()
157 $tabs = substr($tabs, 0, -1);
160 #####################################################################
161 # check that a variable we get from ParseExpr isn't a null pointer
162 sub check_null_pointer($)
164 my $size = shift;
165 if ($size =~ /^\*/) {
166 my $size2 = substr($size, 1);
167 pidl "if ($size2 == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;";
171 #####################################################################
172 # check that a variable we get from ParseExpr isn't a null pointer,
173 # putting the check at the end of the structure/function
174 sub check_null_pointer_deferred($)
176 my $size = shift;
177 if ($size =~ /^\*/) {
178 my $size2 = substr($size, 1);
179 defer "if ($size2 == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;";
183 #####################################################################
184 # check that a variable we get from ParseExpr isn't a null pointer
185 # void return varient
186 sub check_null_pointer_void($)
188 my $size = shift;
189 if ($size =~ /^\*/) {
190 my $size2 = substr($size, 1);
191 pidl "if ($size2 == NULL) return;";
195 #####################################################################
196 # declare a function public or static, depending on its attributes
197 sub fn_declare($$)
199 my ($fn,$decl) = @_;
201 if (has_property($fn, "public")) {
202 pidl_hdr "$decl;";
203 pidl "_PUBLIC_ $decl";
204 } else {
205 pidl "static $decl";
209 ###################################################################
210 # setup any special flags for an element or structure
211 sub start_flags($)
213 my $e = shift;
214 my $flags = has_property($e, "flag");
215 if (defined $flags) {
216 pidl "{";
217 indent;
218 pidl "uint32_t _flags_save_$e->{TYPE} = ndr->flags;";
219 pidl "ndr_set_flags(&ndr->flags, $flags);";
223 ###################################################################
224 # end any special flags for an element or structure
225 sub end_flags($)
227 my $e = shift;
228 my $flags = has_property($e, "flag");
229 if (defined $flags) {
230 pidl "ndr->flags = _flags_save_$e->{TYPE};";
231 deindent;
232 pidl "}";
236 sub GenerateStructEnv($)
238 my $x = shift;
239 my %env;
241 foreach my $e (@{$x->{ELEMENTS}}) {
242 $env{$e->{NAME}} = "r->$e->{NAME}";
245 $env{"this"} = "r";
247 return \%env;
250 sub EnvSubstituteValue($$)
252 my ($env,$s) = @_;
254 # Substitute the value() values in the env
255 foreach my $e (@{$s->{ELEMENTS}}) {
256 next unless (my $v = has_property($e, "value"));
258 $env->{$e->{NAME}} = ParseExpr($v, $env);
261 return $env;
264 sub GenerateFunctionInEnv($)
266 my $fn = shift;
267 my %env;
269 foreach my $e (@{$fn->{ELEMENTS}}) {
270 if (grep (/in/, @{$e->{DIRECTION}})) {
271 $env{$e->{NAME}} = "r->in.$e->{NAME}";
275 return \%env;
278 sub GenerateFunctionOutEnv($)
280 my $fn = shift;
281 my %env;
283 foreach my $e (@{$fn->{ELEMENTS}}) {
284 if (grep (/out/, @{$e->{DIRECTION}})) {
285 $env{$e->{NAME}} = "r->out.$e->{NAME}";
286 } elsif (grep (/in/, @{$e->{DIRECTION}})) {
287 $env{$e->{NAME}} = "r->in.$e->{NAME}";
291 return \%env;
294 #####################################################################
295 # parse the data of an array - push side
296 sub ParseArrayPushHeader($$$$$)
298 my ($e,$l,$ndr,$var_name,$env) = @_;
300 my $size;
301 my $length;
303 if ($l->{IS_ZERO_TERMINATED}) {
304 if (has_property($e, "charset")) {
305 $size = $length = "ndr_charset_length($var_name, CH_$e->{PROPERTIES}->{charset})";
306 } else {
307 $size = $length = "ndr_string_length($var_name, sizeof(*$var_name))";
309 } else {
310 $size = ParseExpr($l->{SIZE_IS}, $env);
311 $length = ParseExpr($l->{LENGTH_IS}, $env);
314 if ((!$l->{IS_SURROUNDING}) and $l->{IS_CONFORMANT}) {
315 pidl "NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, $size));";
318 if ($l->{IS_VARYING}) {
319 pidl "NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, 0));"; # array offset
320 pidl "NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, $length));";
323 return $length;
326 #####################################################################
327 # parse an array - pull side
328 sub ParseArrayPullHeader($$$$$)
330 my ($e,$l,$ndr,$var_name,$env) = @_;
332 my $length;
333 my $size;
335 if ($l->{IS_CONFORMANT}) {
336 $length = $size = "ndr_get_array_size($ndr, " . get_pointer_to($var_name) . ")";
337 } elsif ($l->{IS_ZERO_TERMINATED}) { # Noheader arrays
338 $length = $size = "ndr_get_string_size($ndr, sizeof(*$var_name))";
339 } else {
340 $length = $size = ParseExpr($l->{SIZE_IS}, $env);
343 if ((!$l->{IS_SURROUNDING}) and $l->{IS_CONFORMANT}) {
344 pidl "NDR_CHECK(ndr_pull_array_size(ndr, " . get_pointer_to($var_name) . "));";
348 if ($l->{IS_VARYING}) {
349 pidl "NDR_CHECK(ndr_pull_array_length($ndr, " . get_pointer_to($var_name) . "));";
350 $length = "ndr_get_array_length($ndr, " . get_pointer_to($var_name) .")";
353 check_null_pointer($length);
355 if ($length ne $size) {
356 pidl "if ($length > $size) {";
357 indent;
358 pidl "return ndr_pull_error($ndr, NDR_ERR_ARRAY_SIZE, \"Bad array size %u should exceed array length %u\", $size, $length);";
359 deindent;
360 pidl "}";
363 if ($l->{IS_CONFORMANT} and not $l->{IS_ZERO_TERMINATED}) {
364 my $size = ParseExpr($l->{SIZE_IS}, $env);
365 defer "if ($var_name) {";
366 check_null_pointer_deferred($size);
367 defer "NDR_CHECK(ndr_check_array_size(ndr, (void*)" . get_pointer_to($var_name) . ", $size));";
368 defer "}";
371 if ($l->{IS_VARYING} and not $l->{IS_ZERO_TERMINATED}) {
372 my $length = ParseExpr($l->{LENGTH_IS}, $env);
373 defer "if ($var_name) {";
374 check_null_pointer_deferred($length);
375 defer "NDR_CHECK(ndr_check_array_length(ndr, (void*)" . get_pointer_to($var_name) . ", $length));";
376 defer "}"
379 if (not $l->{IS_FIXED} and not is_charset_array($e, $l)) {
380 AllocateArrayLevel($e,$l,$ndr,$env,$size);
383 return $length;
386 sub compression_alg($$)
388 my ($e,$l) = @_;
389 my $compression = $l->{COMPRESSION};
390 my ($alg, $clen, $dlen) = split(/ /, $compression);
392 return $alg;
395 sub compression_clen($$$)
397 my ($e,$l,$env) = @_;
398 my $compression = $l->{COMPRESSION};
399 my ($alg, $clen, $dlen) = split(/ /, $compression);
401 return ParseExpr($clen, $env);
404 sub compression_dlen($$$)
406 my ($e,$l,$env) = @_;
407 my $compression = $l->{COMPRESSION};
408 my ($alg, $clen, $dlen) = split(/ /, $compression);
410 return ParseExpr($dlen, $env);
413 sub ParseCompressionPushStart($$$$)
415 my ($e,$l,$ndr,$env) = @_;
416 my $comndr = "$ndr\_compressed";
417 my $alg = compression_alg($e, $l);
418 my $dlen = compression_dlen($e, $l, $env);
420 pidl "{";
421 indent;
422 pidl "struct ndr_push *$comndr;";
423 pidl "NDR_CHECK(ndr_push_compression_start($ndr, &$comndr, $alg, $dlen));";
425 return $comndr;
428 sub ParseCompressionPushEnd($$$$)
430 my ($e,$l,$ndr,$env) = @_;
431 my $comndr = "$ndr\_compressed";
432 my $alg = compression_alg($e, $l);
433 my $dlen = compression_dlen($e, $l, $env);
435 pidl "NDR_CHECK(ndr_push_compression_end($ndr, $comndr, $alg, $dlen));";
436 deindent;
437 pidl "}";
440 sub ParseCompressionPullStart($$$$)
442 my ($e,$l,$ndr,$env) = @_;
443 my $comndr = "$ndr\_compressed";
444 my $alg = compression_alg($e, $l);
445 my $dlen = compression_dlen($e, $l, $env);
447 pidl "{";
448 indent;
449 pidl "struct ndr_pull *$comndr;";
450 pidl "NDR_CHECK(ndr_pull_compression_start($ndr, &$comndr, $alg, $dlen));";
452 return $comndr;
455 sub ParseCompressionPullEnd($$$$)
457 my ($e,$l,$ndr,$env) = @_;
458 my $comndr = "$ndr\_compressed";
459 my $alg = compression_alg($e, $l);
460 my $dlen = compression_dlen($e, $l, $env);
462 pidl "NDR_CHECK(ndr_pull_compression_end($ndr, $comndr, $alg, $dlen));";
463 deindent;
464 pidl "}";
467 sub ParseObfuscationPushStart($$)
469 my ($e,$ndr) = @_;
470 my $obfuscation = has_property($e, "obfuscation");
472 pidl "NDR_CHECK(ndr_push_obfuscation_start($ndr, $obfuscation));";
474 return $ndr;
477 sub ParseObfuscationPushEnd($$)
479 my ($e,$ndr) = @_;
480 my $obfuscation = has_property($e, "obfuscation");
482 pidl "NDR_CHECK(ndr_push_obfuscation_end($ndr, $obfuscation));";
485 sub ParseObfuscationPullStart($$)
487 my ($e,$ndr) = @_;
488 my $obfuscation = has_property($e, "obfuscation");
490 pidl "NDR_CHECK(ndr_pull_obfuscation_start($ndr, $obfuscation));";
492 return $ndr;
495 sub ParseObfuscationPullEnd($$)
497 my ($e,$ndr) = @_;
498 my $obfuscation = has_property($e, "obfuscation");
500 pidl "NDR_CHECK(ndr_pull_obfuscation_end($ndr, $obfuscation));";
503 sub ParseSubcontextPushStart($$$$)
505 my ($e,$l,$ndr,$env) = @_;
506 my $subndr = "_ndr_$e->{NAME}";
507 my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE},$env);
509 pidl "{";
510 indent;
511 pidl "struct ndr_push *$subndr;";
512 pidl "NDR_CHECK(ndr_push_subcontext_start($ndr, &$subndr, $l->{HEADER_SIZE}, $subcontext_size));";
514 if (defined $l->{COMPRESSION}) {
515 $subndr = ParseCompressionPushStart($e, $l, $subndr, $env);
518 if (defined $l->{OBFUSCATION}) {
519 $subndr = ParseObfuscationPushStart($e, $subndr);
522 return $subndr;
525 sub ParseSubcontextPushEnd($$$$)
527 my ($e,$l,$ndr,$env) = @_;
528 my $subndr = "_ndr_$e->{NAME}";
529 my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE},$env);
531 if (defined $l->{COMPRESSION}) {
532 ParseCompressionPushEnd($e, $l, $subndr, $env);
535 if (defined $l->{OBFUSCATION}) {
536 ParseObfuscationPushEnd($e, $subndr);
539 pidl "NDR_CHECK(ndr_push_subcontext_end($ndr, $subndr, $l->{HEADER_SIZE}, $subcontext_size));";
540 deindent;
541 pidl "}";
544 sub ParseSubcontextPullStart($$$$)
546 my ($e,$l,$ndr,$env) = @_;
547 my $subndr = "_ndr_$e->{NAME}";
548 my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE},$env);
550 pidl "{";
551 indent;
552 pidl "struct ndr_pull *$subndr;";
553 pidl "NDR_CHECK(ndr_pull_subcontext_start($ndr, &$subndr, $l->{HEADER_SIZE}, $subcontext_size));";
555 if (defined $l->{COMPRESSION}) {
556 $subndr = ParseCompressionPullStart($e, $l, $subndr, $env);
559 if (defined $l->{OBFUSCATION}) {
560 $subndr = ParseObfuscationPullStart($e, $subndr);
563 return $subndr;
566 sub ParseSubcontextPullEnd($$$$)
568 my ($e,$l,$ndr,$env) = @_;
569 my $subndr = "_ndr_$e->{NAME}";
570 my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE},$env);
572 if (defined $l->{COMPRESSION}) {
573 ParseCompressionPullEnd($e, $l, $subndr, $env);
576 if (defined $l->{OBFUSCATION}) {
577 ParseObfuscationPullEnd($e, $subndr);
580 pidl "NDR_CHECK(ndr_pull_subcontext_end($ndr, $subndr, $l->{HEADER_SIZE}, $subcontext_size));";
581 deindent;
582 pidl "}";
585 sub ParseElementPushLevel
587 my ($e,$l,$ndr,$var_name,$env,$primitives,$deferred) = @_;
589 my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
591 if ($l->{TYPE} eq "ARRAY" and ($l->{IS_CONFORMANT} or $l->{IS_VARYING})) {
592 $var_name = get_pointer_to($var_name);
595 if (defined($ndr_flags)) {
596 if ($l->{TYPE} eq "SUBCONTEXT") {
597 my $subndr = ParseSubcontextPushStart($e, $l, $ndr, $env);
598 ParseElementPushLevel($e, GetNextLevel($e, $l), $subndr, $var_name, $env, 1, 1);
599 ParseSubcontextPushEnd($e, $l, $ndr, $env);
600 } elsif ($l->{TYPE} eq "POINTER") {
601 ParsePtrPush($e, $l, $var_name);
602 } elsif ($l->{TYPE} eq "ARRAY") {
603 my $length = ParseArrayPushHeader($e, $l, $ndr, $var_name, $env);
605 my $nl = GetNextLevel($e, $l);
607 # Allow speedups for arrays of scalar types
608 if (is_charset_array($e,$l)) {
609 pidl "NDR_CHECK(ndr_push_charset($ndr, $ndr_flags, $var_name, $length, sizeof(" . mapType($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));";
610 return;
611 } elsif (has_fast_array($e,$l)) {
612 pidl "NDR_CHECK(ndr_push_array_$nl->{DATA_TYPE}($ndr, $ndr_flags, $var_name, $length));";
613 return;
615 } elsif ($l->{TYPE} eq "SWITCH") {
616 ParseSwitchPush($e, $l, $ndr, $var_name, $ndr_flags, $env);
617 } elsif ($l->{TYPE} eq "DATA") {
618 ParseDataPush($e, $l, $ndr, $var_name, $ndr_flags);
622 if ($l->{TYPE} eq "POINTER" and $deferred) {
623 if ($l->{POINTER_TYPE} ne "ref") {
624 pidl "if ($var_name) {";
625 indent;
626 if ($l->{POINTER_TYPE} eq "relative") {
627 pidl "NDR_CHECK(ndr_push_relative_ptr2(ndr, $var_name));";
630 $var_name = get_value_of($var_name);
631 ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 1, 1);
633 if ($l->{POINTER_TYPE} ne "ref") {
634 deindent;
635 pidl "}";
637 } elsif ($l->{TYPE} eq "ARRAY" and not has_fast_array($e,$l) and
638 not is_charset_array($e, $l)) {
639 my $length = ParseExpr($l->{LENGTH_IS}, $env);
640 my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
642 $var_name = $var_name . "[$counter]";
644 if (($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) {
645 pidl "for ($counter = 0; $counter < $length; $counter++) {";
646 indent;
647 ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 1, 0);
648 deindent;
649 pidl "}";
652 if ($deferred and ContainsDeferred($e, $l)) {
653 pidl "for ($counter = 0; $counter < $length; $counter++) {";
654 indent;
655 ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 0, 1);
656 deindent;
657 pidl "}";
659 } elsif ($l->{TYPE} eq "SWITCH") {
660 ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, $primitives, $deferred);
664 #####################################################################
665 # parse scalars in a structure element
666 sub ParseElementPush($$$$$$)
668 my ($e,$ndr,$var_prefix,$env,$primitives,$deferred) = @_;
669 my $subndr = undef;
671 my $var_name = $var_prefix.$e->{NAME};
673 $var_name = append_prefix($e, $var_name);
675 return unless $primitives or ($deferred and ContainsDeferred($e, $e->{LEVELS}[0]));
677 start_flags($e);
679 if (my $value = has_property($e, "value")) {
680 $var_name = ParseExpr($value, $env);
683 ParseElementPushLevel($e, $e->{LEVELS}[0], $ndr, $var_name, $env, $primitives, $deferred);
685 end_flags($e);
688 #####################################################################
689 # parse a pointer in a struct element or function
690 sub ParsePtrPush($$$)
692 my ($e,$l,$var_name) = @_;
694 if ($l->{POINTER_TYPE} eq "ref") {
695 if ($l->{LEVEL} eq "EMBEDDED") {
696 pidl "NDR_CHECK(ndr_push_ref_ptr(ndr, $var_name));";
697 } else {
698 check_null_pointer(get_value_of($var_name));
700 } elsif ($l->{POINTER_TYPE} eq "relative") {
701 pidl "NDR_CHECK(ndr_push_relative_ptr1(ndr, $var_name));";
702 } elsif ($l->{POINTER_TYPE} eq "unique") {
703 pidl "NDR_CHECK(ndr_push_unique_ptr(ndr, $var_name));";
704 } elsif ($l->{POINTER_TYPE} eq "sptr") {
705 pidl "NDR_CHECK(ndr_push_sptr_ptr(ndr, $var_name));";
706 } else {
707 die("Unhandled pointer type $l->{POINTER_TYPE}");
711 #####################################################################
712 # print scalars in a structure element
713 sub ParseElementPrint($$$)
715 my($e,$var_name,$env) = @_;
717 $var_name = append_prefix($e, $var_name);
718 return if (has_property($e, "noprint"));
720 if (my $value = has_property($e, "value")) {
721 $var_name = "(ndr->flags & LIBNDR_PRINT_SET_VALUES)?" . ParseExpr($value,$env) . ":$var_name";
724 foreach my $l (@{$e->{LEVELS}}) {
725 if ($l->{TYPE} eq "POINTER") {
726 pidl "ndr_print_ptr(ndr, \"$e->{NAME}\", $var_name);";
727 pidl "ndr->depth++;";
728 if ($l->{POINTER_TYPE} ne "ref") {
729 pidl "if ($var_name) {";
730 indent;
732 $var_name = get_value_of($var_name);
733 } elsif ($l->{TYPE} eq "ARRAY") {
734 my $length;
736 if ($l->{IS_CONFORMANT} or $l->{IS_VARYING}) {
737 $var_name = get_pointer_to($var_name);
740 if ($l->{IS_ZERO_TERMINATED}) {
741 $length = "ndr_string_length($var_name, sizeof(*$var_name))";
742 } else {
743 $length = ParseExpr($l->{LENGTH_IS}, $env);
746 if (is_charset_array($e,$l)) {
747 pidl "ndr_print_string(ndr, \"$e->{NAME}\", $var_name);";
748 last;
749 } elsif (has_fast_array($e, $l)) {
750 my $nl = GetNextLevel($e, $l);
751 pidl "ndr_print_array_$nl->{DATA_TYPE}(ndr, \"$e->{NAME}\", $var_name, $length);";
752 last;
753 } else {
754 my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
756 pidl "ndr->print(ndr, \"\%s: ARRAY(\%d)\", \"$e->{NAME}\", $length);";
757 pidl 'ndr->depth++;';
758 pidl "for ($counter=0;$counter<$length;$counter++) {";
759 indent;
760 pidl "char *idx_$l->{LEVEL_INDEX}=NULL;";
761 pidl "asprintf(&idx_$l->{LEVEL_INDEX}, \"[\%d]\", $counter);";
762 pidl "if (idx_$l->{LEVEL_INDEX}) {";
763 indent;
765 $var_name = $var_name . "[$counter]";
767 } elsif ($l->{TYPE} eq "DATA") {
768 if (not Parse::Pidl::Typelist::is_scalar($l->{DATA_TYPE}) or Parse::Pidl::Typelist::scalar_is_reference($l->{DATA_TYPE})) {
769 $var_name = get_pointer_to($var_name);
771 pidl "ndr_print_$l->{DATA_TYPE}(ndr, \"$e->{NAME}\", $var_name);";
772 } elsif ($l->{TYPE} eq "SWITCH") {
773 my $switch_var = ParseExpr($l->{SWITCH_IS}, $env);
774 check_null_pointer_void($switch_var);
775 pidl "ndr_print_set_switch_value(ndr, " . get_pointer_to($var_name) . ", $switch_var);";
779 foreach my $l (reverse @{$e->{LEVELS}}) {
780 if ($l->{TYPE} eq "POINTER") {
781 if ($l->{POINTER_TYPE} ne "ref") {
782 deindent;
783 pidl "}";
785 pidl "ndr->depth--;";
786 } elsif (($l->{TYPE} eq "ARRAY")
787 and not is_charset_array($e,$l)
788 and not has_fast_array($e,$l)) {
789 pidl "free(idx_$l->{LEVEL_INDEX});";
790 deindent;
791 pidl "}";
792 deindent;
793 pidl "}";
794 pidl "ndr->depth--;";
799 #####################################################################
800 # parse scalars in a structure element - pull size
801 sub ParseSwitchPull($$$$$$)
803 my($e,$l,$ndr,$var_name,$ndr_flags,$env) = @_;
804 my $switch_var = ParseExpr($l->{SWITCH_IS}, $env);
806 check_null_pointer($switch_var);
808 $var_name = get_pointer_to($var_name);
809 pidl "NDR_CHECK(ndr_pull_set_switch_value($ndr, $var_name, $switch_var));";
812 #####################################################################
813 # push switch element
814 sub ParseSwitchPush($$$$$$)
816 my($e,$l,$ndr,$var_name,$ndr_flags,$env) = @_;
817 my $switch_var = ParseExpr($l->{SWITCH_IS}, $env);
819 check_null_pointer($switch_var);
820 $var_name = get_pointer_to($var_name);
821 pidl "NDR_CHECK(ndr_push_set_switch_value($ndr, $var_name, $switch_var));";
824 sub ParseDataPull($$$$$)
826 my ($e,$l,$ndr,$var_name,$ndr_flags) = @_;
828 if (Parse::Pidl::Typelist::scalar_is_reference($l->{DATA_TYPE})) {
829 $var_name = get_pointer_to($var_name);
832 $var_name = get_pointer_to($var_name);
834 pidl "NDR_CHECK(ndr_pull_$l->{DATA_TYPE}($ndr, $ndr_flags, $var_name));";
836 if (my $range = has_property($e, "range")) {
837 $var_name = get_value_of($var_name);
838 my ($low, $high) = split(/ /, $range, 2);
839 pidl "if ($var_name < $low || $var_name > $high) {";
840 pidl "\treturn ndr_pull_error($ndr, NDR_ERR_RANGE, \"value out of range\");";
841 pidl "}";
845 sub ParseDataPush($$$$$)
847 my ($e,$l,$ndr,$var_name,$ndr_flags) = @_;
849 # strings are passed by value rather then reference
850 if (not Parse::Pidl::Typelist::is_scalar($l->{DATA_TYPE}) or Parse::Pidl::Typelist::scalar_is_reference($l->{DATA_TYPE})) {
851 $var_name = get_pointer_to($var_name);
854 pidl "NDR_CHECK(ndr_push_$l->{DATA_TYPE}($ndr, $ndr_flags, $var_name));";
857 sub CalcNdrFlags($$$)
859 my ($l,$primitives,$deferred) = @_;
861 my $scalars = 0;
862 my $buffers = 0;
864 # Add NDR_SCALARS if this one is deferred
865 # and deferreds may be pushed
866 $scalars = 1 if ($l->{IS_DEFERRED} and $deferred);
868 # Add NDR_SCALARS if this one is not deferred and
869 # primitives may be pushed
870 $scalars = 1 if (!$l->{IS_DEFERRED} and $primitives);
872 # Add NDR_BUFFERS if this one contains deferred stuff
873 # and deferreds may be pushed
874 $buffers = 1 if ($l->{CONTAINS_DEFERRED} and $deferred);
876 return "NDR_SCALARS|NDR_BUFFERS" if ($scalars and $buffers);
877 return "NDR_SCALARS" if ($scalars);
878 return "NDR_BUFFERS" if ($buffers);
879 return undef;
882 sub ParseMemCtxPullStart($$$)
884 my $e = shift;
885 my $l = shift;
886 my $ptr_name = shift;
888 my $mem_r_ctx = "_mem_save_$e->{NAME}_$l->{LEVEL_INDEX}";
889 my $mem_c_ctx = $ptr_name;
890 my $mem_c_flags = "0";
892 return if ($l->{TYPE} eq "ARRAY" and $l->{IS_FIXED});
894 if (($l->{TYPE} eq "POINTER") and ($l->{POINTER_TYPE} eq "ref")) {
895 my $nl = GetNextLevel($e, $l);
896 my $next_is_array = ($nl->{TYPE} eq "ARRAY");
897 my $next_is_string = (($nl->{TYPE} eq "DATA") and
898 ($nl->{DATA_TYPE} eq "string"));
899 if ($next_is_array or $next_is_string) {
900 return;
901 } else {
902 $mem_c_flags = "LIBNDR_FLAG_REF_ALLOC";
906 pidl "$mem_r_ctx = NDR_PULL_GET_MEM_CTX(ndr);";
907 pidl "NDR_PULL_SET_MEM_CTX(ndr, $mem_c_ctx, $mem_c_flags);";
910 sub ParseMemCtxPullEnd($$)
912 my $e = shift;
913 my $l = shift;
915 my $mem_r_ctx = "_mem_save_$e->{NAME}_$l->{LEVEL_INDEX}";
916 my $mem_r_flags = "0";
918 return if ($l->{TYPE} eq "ARRAY" and $l->{IS_FIXED});
920 if (($l->{TYPE} eq "POINTER") and ($l->{POINTER_TYPE} eq "ref")) {
921 my $nl = GetNextLevel($e, $l);
922 my $next_is_array = ($nl->{TYPE} eq "ARRAY");
923 my $next_is_string = (($nl->{TYPE} eq "DATA") and
924 ($nl->{DATA_TYPE} eq "string"));
925 if ($next_is_array or $next_is_string) {
926 return;
927 } else {
928 $mem_r_flags = "LIBNDR_FLAG_REF_ALLOC";
932 pidl "NDR_PULL_SET_MEM_CTX(ndr, $mem_r_ctx, $mem_r_flags);";
935 sub CheckStringTerminator($$$$)
937 my ($ndr,$e,$l,$length) = @_;
938 my $nl = GetNextLevel($e, $l);
940 # Make sure last element is zero!
941 pidl "NDR_CHECK(ndr_check_string_terminator($ndr, $length, sizeof($nl->{DATA_TYPE}_t)));";
944 sub ParseElementPullLevel
946 my($e,$l,$ndr,$var_name,$env,$primitives,$deferred) = @_;
948 my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
950 if ($l->{TYPE} eq "ARRAY" and ($l->{IS_VARYING} or $l->{IS_CONFORMANT})) {
951 $var_name = get_pointer_to($var_name);
954 # Only pull something if there's actually something to be pulled
955 if (defined($ndr_flags)) {
956 if ($l->{TYPE} eq "SUBCONTEXT") {
957 my $subndr = ParseSubcontextPullStart($e, $l, $ndr, $env);
958 ParseElementPullLevel($e, GetNextLevel($e,$l), $subndr, $var_name, $env, 1, 1);
959 ParseSubcontextPullEnd($e, $l, $ndr, $env);
960 } elsif ($l->{TYPE} eq "ARRAY") {
961 my $length = ParseArrayPullHeader($e, $l, $ndr, $var_name, $env);
963 my $nl = GetNextLevel($e, $l);
965 if (is_charset_array($e,$l)) {
966 if ($l->{IS_ZERO_TERMINATED}) {
967 CheckStringTerminator($ndr, $e, $l, $length);
969 pidl "NDR_CHECK(ndr_pull_charset($ndr, $ndr_flags, ".get_pointer_to($var_name).", $length, sizeof(" . mapType($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));";
970 return;
971 } elsif (has_fast_array($e, $l)) {
972 if ($l->{IS_ZERO_TERMINATED}) {
973 CheckStringTerminator($ndr,$e,$l,$length);
975 pidl "NDR_CHECK(ndr_pull_array_$nl->{DATA_TYPE}($ndr, $ndr_flags, $var_name, $length));";
976 return;
978 } elsif ($l->{TYPE} eq "POINTER") {
979 ParsePtrPull($e, $l, $ndr, $var_name);
980 } elsif ($l->{TYPE} eq "SWITCH") {
981 ParseSwitchPull($e, $l, $ndr, $var_name, $ndr_flags, $env);
982 } elsif ($l->{TYPE} eq "DATA") {
983 ParseDataPull($e, $l, $ndr, $var_name, $ndr_flags);
987 # add additional constructions
988 if ($l->{TYPE} eq "POINTER" and $deferred) {
989 if ($l->{POINTER_TYPE} ne "ref") {
990 pidl "if ($var_name) {";
991 indent;
993 if ($l->{POINTER_TYPE} eq "relative") {
994 pidl "struct ndr_pull_save _relative_save;";
995 pidl "ndr_pull_save(ndr, &_relative_save);";
996 pidl "NDR_CHECK(ndr_pull_relative_ptr2(ndr, $var_name));";
1000 ParseMemCtxPullStart($e,$l, $var_name);
1002 $var_name = get_value_of($var_name);
1003 ParseElementPullLevel($e,GetNextLevel($e,$l), $ndr, $var_name, $env, 1, 1);
1005 ParseMemCtxPullEnd($e,$l);
1007 if ($l->{POINTER_TYPE} ne "ref") {
1008 if ($l->{POINTER_TYPE} eq "relative") {
1009 pidl "ndr_pull_restore(ndr, &_relative_save);";
1011 deindent;
1012 pidl "}";
1014 } elsif ($l->{TYPE} eq "ARRAY" and
1015 not has_fast_array($e,$l) and not is_charset_array($e, $l)) {
1016 my $length = ParseExpr($l->{LENGTH_IS}, $env);
1017 my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
1018 my $array_name = $var_name;
1020 $var_name = $var_name . "[$counter]";
1022 ParseMemCtxPullStart($e,$l, $array_name);
1024 if (($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) {
1025 my $nl = GetNextLevel($e,$l);
1027 if ($l->{IS_ZERO_TERMINATED}) {
1028 CheckStringTerminator($ndr,$e,$l,$length);
1031 pidl "for ($counter = 0; $counter < $length; $counter++) {";
1032 indent;
1033 ParseElementPullLevel($e, $nl, $ndr, $var_name, $env, 1, 0);
1034 deindent;
1035 pidl "}";
1038 if ($deferred and ContainsDeferred($e, $l)) {
1039 pidl "for ($counter = 0; $counter < $length; $counter++) {";
1040 indent;
1041 ParseElementPullLevel($e,GetNextLevel($e,$l), $ndr, $var_name, $env, 0, 1);
1042 deindent;
1043 pidl "}";
1046 ParseMemCtxPullEnd($e,$l);
1048 } elsif ($l->{TYPE} eq "SWITCH") {
1049 ParseElementPullLevel($e,GetNextLevel($e,$l), $ndr, $var_name, $env, $primitives, $deferred);
1053 #####################################################################
1054 # parse scalars in a structure element - pull size
1055 sub ParseElementPull($$$$$$)
1057 my($e,$ndr,$var_prefix,$env,$primitives,$deferred) = @_;
1059 my $var_name = $var_prefix.$e->{NAME};
1061 $var_name = append_prefix($e, $var_name);
1063 return unless $primitives or ($deferred and ContainsDeferred($e, $e->{LEVELS}[0]));
1065 start_flags($e);
1067 ParseElementPullLevel($e,$e->{LEVELS}[0],$ndr,$var_name,$env,$primitives,$deferred);
1069 end_flags($e);
1072 #####################################################################
1073 # parse a pointer in a struct element or function
1074 sub ParsePtrPull($$$$)
1076 my($e,$l,$ndr,$var_name) = @_;
1078 my $nl = GetNextLevel($e, $l);
1079 my $next_is_array = ($nl->{TYPE} eq "ARRAY");
1080 my $next_is_string = (($nl->{TYPE} eq "DATA") and
1081 ($nl->{DATA_TYPE} eq "string"));
1083 if ($l->{POINTER_TYPE} eq "ref") {
1084 unless ($l->{LEVEL} eq "TOP") {
1085 pidl "NDR_CHECK(ndr_pull_ref_ptr($ndr, &_ptr_$e->{NAME}));";
1088 unless ($next_is_array or $next_is_string) {
1089 pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {";
1090 pidl "\tNDR_PULL_ALLOC($ndr, $var_name);";
1091 pidl "}";
1094 return;
1095 } elsif (($l->{POINTER_TYPE} eq "unique") or
1096 ($l->{POINTER_TYPE} eq "relative") or
1097 ($l->{POINTER_TYPE} eq "sptr")) {
1098 pidl "NDR_CHECK(ndr_pull_generic_ptr($ndr, &_ptr_$e->{NAME}));";
1099 pidl "if (_ptr_$e->{NAME}) {";
1100 indent;
1101 } else {
1102 die("Unhandled pointer type $l->{POINTER_TYPE}");
1105 # Don't do this for arrays, they're allocated at the actual level
1106 # of the array
1107 unless ($next_is_array or $next_is_string) {
1108 pidl "NDR_PULL_ALLOC($ndr, $var_name);";
1109 } else {
1110 # FIXME: Yes, this is nasty.
1111 # We allocate an array twice
1112 # - once just to indicate that it's there,
1113 # - then the real allocation...
1114 pidl "NDR_PULL_ALLOC_SIZE($ndr, $var_name, 1);";
1117 #pidl "memset($var_name, 0, sizeof($var_name));";
1118 if ($l->{POINTER_TYPE} eq "relative") {
1119 pidl "NDR_CHECK(ndr_pull_relative_ptr1($ndr, $var_name, _ptr_$e->{NAME}));";
1121 deindent;
1122 pidl "} else {";
1123 pidl "\t$var_name = NULL;";
1124 pidl "}";
1127 #####################################################################
1128 # parse a struct
1129 sub ParseStructPush($$)
1131 my($struct,$name) = @_;
1133 return unless defined($struct->{ELEMENTS});
1135 my $env = GenerateStructEnv($struct);
1137 EnvSubstituteValue($env, $struct);
1139 # save the old relative_base_offset
1140 pidl "uint32_t _save_relative_base_offset = ndr_push_get_relative_base_offset(ndr);" if defined($struct->{PROPERTIES}{relative_base});
1142 foreach my $e (@{$struct->{ELEMENTS}}) {
1143 DeclareArrayVariables($e);
1146 start_flags($struct);
1148 # see if the structure contains a conformant array. If it
1149 # does, then it must be the last element of the structure, and
1150 # we need to push the conformant length early, as it fits on
1151 # the wire before the structure (and even before the structure
1152 # alignment)
1153 if (defined($struct->{SURROUNDING_ELEMENT})) {
1154 my $e = $struct->{SURROUNDING_ELEMENT};
1156 if (defined($e->{LEVELS}[0]) and
1157 $e->{LEVELS}[0]->{TYPE} eq "ARRAY") {
1158 my $size;
1160 if ($e->{LEVELS}[0]->{IS_ZERO_TERMINATED}) {
1161 if (has_property($e, "charset")) {
1162 $size = "ndr_charset_length(r->$e->{NAME}, CH_$e->{PROPERTIES}->{charset})";
1163 } else {
1164 $size = "ndr_string_length(r->$e->{NAME}, sizeof(*r->$e->{NAME}))";
1166 } else {
1167 $size = ParseExpr($e->{LEVELS}[0]->{SIZE_IS}, $env);
1170 pidl "NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, $size));";
1171 } else {
1172 pidl "NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_string_array_size(ndr, r->$e->{NAME})));";
1176 pidl "if (ndr_flags & NDR_SCALARS) {";
1177 indent;
1179 pidl "NDR_CHECK(ndr_push_align(ndr, $struct->{ALIGN}));";
1181 if (defined($struct->{PROPERTIES}{relative_base})) {
1182 # set the current offset as base for relative pointers
1183 # and store it based on the toplevel struct/union
1184 pidl "NDR_CHECK(ndr_push_setup_relative_base_offset1(ndr, r, ndr->offset));";
1187 foreach my $e (@{$struct->{ELEMENTS}}) {
1188 ParseElementPush($e, "ndr", "r->", $env, 1, 0);
1191 deindent;
1192 pidl "}";
1194 pidl "if (ndr_flags & NDR_BUFFERS) {";
1195 indent;
1196 if (defined($struct->{PROPERTIES}{relative_base})) {
1197 # retrieve the current offset as base for relative pointers
1198 # based on the toplevel struct/union
1199 pidl "NDR_CHECK(ndr_push_setup_relative_base_offset2(ndr, r));";
1201 foreach my $e (@{$struct->{ELEMENTS}}) {
1202 ParseElementPush($e, "ndr", "r->", $env, 0, 1);
1205 deindent;
1206 pidl "}";
1208 end_flags($struct);
1209 # restore the old relative_base_offset
1210 pidl "ndr_push_restore_relative_base_offset(ndr, _save_relative_base_offset);" if defined($struct->{PROPERTIES}{relative_base});
1213 #####################################################################
1214 # generate a push function for an enum
1215 sub ParseEnumPush($$)
1217 my($enum,$name) = @_;
1218 my($type_fn) = $enum->{BASE_TYPE};
1220 start_flags($enum);
1221 pidl "NDR_CHECK(ndr_push_$type_fn(ndr, NDR_SCALARS, r));";
1222 end_flags($enum);
1225 #####################################################################
1226 # generate a pull function for an enum
1227 sub ParseEnumPull($$)
1229 my($enum,$name) = @_;
1230 my($type_fn) = $enum->{BASE_TYPE};
1231 my($type_v_decl) = mapType($type_fn);
1233 pidl "$type_v_decl v;";
1234 start_flags($enum);
1235 pidl "NDR_CHECK(ndr_pull_$type_fn(ndr, NDR_SCALARS, &v));";
1236 pidl "*r = v;";
1238 end_flags($enum);
1241 #####################################################################
1242 # generate a print function for an enum
1243 sub ParseEnumPrint($$)
1245 my($enum,$name) = @_;
1247 pidl "const char *val = NULL;";
1248 pidl "";
1250 start_flags($enum);
1252 pidl "switch (r) {";
1253 indent;
1254 my $els = \@{$enum->{ELEMENTS}};
1255 foreach my $i (0 .. $#{$els}) {
1256 my $e = ${$els}[$i];
1257 chomp $e;
1258 if ($e =~ /^(.*)=/) {
1259 $e = $1;
1261 pidl "case $e: val = \"$e\"; break;";
1264 deindent;
1265 pidl "}";
1267 pidl "ndr_print_enum(ndr, name, \"$enum->{TYPE}\", val, r);";
1269 end_flags($enum);
1272 sub DeclEnum($)
1274 my ($e,$t) = @_;
1275 return "enum $e->{NAME} " .
1276 ($t eq "pull"?"*":"") . "r";
1279 $typefamily{ENUM} = {
1280 DECL => \&DeclEnum,
1281 PUSH_FN_BODY => \&ParseEnumPush,
1282 PULL_FN_BODY => \&ParseEnumPull,
1283 PRINT_FN_BODY => \&ParseEnumPrint,
1286 #####################################################################
1287 # generate a push function for a bitmap
1288 sub ParseBitmapPush($$)
1290 my($bitmap,$name) = @_;
1291 my($type_fn) = $bitmap->{BASE_TYPE};
1293 start_flags($bitmap);
1295 pidl "NDR_CHECK(ndr_push_$type_fn(ndr, NDR_SCALARS, r));";
1297 end_flags($bitmap);
1300 #####################################################################
1301 # generate a pull function for an bitmap
1302 sub ParseBitmapPull($$)
1304 my($bitmap,$name) = @_;
1305 my $type_fn = $bitmap->{BASE_TYPE};
1306 my($type_decl) = mapType($bitmap->{BASE_TYPE});
1308 pidl "$type_decl v;";
1309 start_flags($bitmap);
1310 pidl "NDR_CHECK(ndr_pull_$type_fn(ndr, NDR_SCALARS, &v));";
1311 pidl "*r = v;";
1313 end_flags($bitmap);
1316 #####################################################################
1317 # generate a print function for an bitmap
1318 sub ParseBitmapPrintElement($$$)
1320 my($e,$bitmap,$name) = @_;
1321 my($type_decl) = mapType($bitmap->{BASE_TYPE});
1322 my($type_fn) = $bitmap->{BASE_TYPE};
1323 my($flag);
1325 if ($e =~ /^(\w+) .*$/) {
1326 $flag = "$1";
1327 } else {
1328 die "Bitmap: \"$name\" invalid Flag: \"$e\"";
1331 pidl "ndr_print_bitmap_flag(ndr, sizeof($type_decl), \"$flag\", $flag, r);";
1334 #####################################################################
1335 # generate a print function for an bitmap
1336 sub ParseBitmapPrint($$)
1338 my($bitmap,$name) = @_;
1339 my($type_decl) = mapType($bitmap->{TYPE});
1340 my($type_fn) = $bitmap->{BASE_TYPE};
1342 start_flags($bitmap);
1344 pidl "ndr_print_$type_fn(ndr, name, r);";
1346 pidl "ndr->depth++;";
1347 foreach my $e (@{$bitmap->{ELEMENTS}}) {
1348 ParseBitmapPrintElement($e, $bitmap, $name);
1350 pidl "ndr->depth--;";
1352 end_flags($bitmap);
1355 sub DeclBitmap($$)
1357 my ($e,$t) = @_;
1358 return mapType(Parse::Pidl::Typelist::bitmap_type_fn($e->{DATA})) .
1359 ($t eq "pull"?" *":" ") . "r";
1362 $typefamily{BITMAP} = {
1363 DECL => \&DeclBitmap,
1364 PUSH_FN_BODY => \&ParseBitmapPush,
1365 PULL_FN_BODY => \&ParseBitmapPull,
1366 PRINT_FN_BODY => \&ParseBitmapPrint,
1369 #####################################################################
1370 # generate a struct print function
1371 sub ParseStructPrint($$)
1373 my($struct,$name) = @_;
1375 return unless defined $struct->{ELEMENTS};
1377 my $env = GenerateStructEnv($struct);
1379 EnvSubstituteValue($env, $struct);
1381 foreach my $e (@{$struct->{ELEMENTS}}) {
1382 DeclareArrayVariables($e);
1385 pidl "ndr_print_struct(ndr, name, \"$name\");";
1387 start_flags($struct);
1389 pidl "ndr->depth++;";
1390 foreach my $e (@{$struct->{ELEMENTS}}) {
1391 ParseElementPrint($e, "r->$e->{NAME}", $env);
1393 pidl "ndr->depth--;";
1395 end_flags($struct);
1398 sub DeclarePtrVariables($)
1400 my $e = shift;
1401 foreach my $l (@{$e->{LEVELS}}) {
1402 if ($l->{TYPE} eq "POINTER" and
1403 not ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "TOP")) {
1404 pidl "uint32_t _ptr_$e->{NAME};";
1405 last;
1410 sub DeclareArrayVariables($)
1412 my $e = shift;
1414 foreach my $l (@{$e->{LEVELS}}) {
1415 next if has_fast_array($e,$l);
1416 next if is_charset_array($e,$l);
1417 if ($l->{TYPE} eq "ARRAY") {
1418 pidl "uint32_t cntr_$e->{NAME}_$l->{LEVEL_INDEX};";
1423 sub need_decl_mem_ctx($$)
1425 my $e = shift;
1426 my $l = shift;
1428 return 0 if has_fast_array($e,$l);
1429 return 0 if is_charset_array($e,$l);
1430 return 1 if (($l->{TYPE} eq "ARRAY") and not $l->{IS_FIXED});
1432 if (($l->{TYPE} eq "POINTER") and ($l->{POINTER_TYPE} eq "ref")) {
1433 my $nl = GetNextLevel($e, $l);
1434 my $next_is_array = ($nl->{TYPE} eq "ARRAY");
1435 my $next_is_string = (($nl->{TYPE} eq "DATA") and
1436 ($nl->{DATA_TYPE} eq "string"));
1437 return 0 if ($next_is_array or $next_is_string);
1439 return 1 if ($l->{TYPE} eq "POINTER");
1441 return 0;
1444 sub DeclareMemCtxVariables($)
1446 my $e = shift;
1447 foreach my $l (@{$e->{LEVELS}}) {
1448 if (need_decl_mem_ctx($e, $l)) {
1449 pidl "TALLOC_CTX *_mem_save_$e->{NAME}_$l->{LEVEL_INDEX};";
1454 #####################################################################
1455 # parse a struct - pull side
1456 sub ParseStructPull($$)
1458 my($struct,$name) = @_;
1460 return unless defined $struct->{ELEMENTS};
1462 my $env = GenerateStructEnv($struct);
1464 # declare any internal pointers we need
1465 foreach my $e (@{$struct->{ELEMENTS}}) {
1466 DeclarePtrVariables($e);
1467 DeclareArrayVariables($e);
1468 DeclareMemCtxVariables($e);
1471 # save the old relative_base_offset
1472 pidl "uint32_t _save_relative_base_offset = ndr_pull_get_relative_base_offset(ndr);" if defined($struct->{PROPERTIES}{relative_base});
1474 start_flags($struct);
1476 pidl "if (ndr_flags & NDR_SCALARS) {";
1477 indent;
1479 if (defined $struct->{SURROUNDING_ELEMENT}) {
1480 pidl "NDR_CHECK(ndr_pull_array_size(ndr, &r->$struct->{SURROUNDING_ELEMENT}->{NAME}));";
1483 pidl "NDR_CHECK(ndr_pull_align(ndr, $struct->{ALIGN}));";
1485 if (defined($struct->{PROPERTIES}{relative_base})) {
1486 # set the current offset as base for relative pointers
1487 # and store it based on the toplevel struct/union
1488 pidl "NDR_CHECK(ndr_pull_setup_relative_base_offset1(ndr, r, ndr->offset));";
1491 foreach my $e (@{$struct->{ELEMENTS}}) {
1492 ParseElementPull($e, "ndr", "r->", $env, 1, 0);
1495 add_deferred();
1497 deindent;
1498 pidl "}";
1499 pidl "if (ndr_flags & NDR_BUFFERS) {";
1500 indent;
1501 if (defined($struct->{PROPERTIES}{relative_base})) {
1502 # retrieve the current offset as base for relative pointers
1503 # based on the toplevel struct/union
1504 pidl "NDR_CHECK(ndr_pull_setup_relative_base_offset2(ndr, r));";
1506 foreach my $e (@{$struct->{ELEMENTS}}) {
1507 ParseElementPull($e, "ndr", "r->", $env, 0, 1);
1510 add_deferred();
1512 deindent;
1513 pidl "}";
1515 end_flags($struct);
1516 # restore the old relative_base_offset
1517 pidl "ndr_pull_restore_relative_base_offset(ndr, _save_relative_base_offset);" if defined($struct->{PROPERTIES}{relative_base});
1520 #####################################################################
1521 # calculate size of ndr struct
1522 sub ParseStructNdrSize($)
1524 my $t = shift;
1525 my $sizevar;
1527 if (my $flags = has_property($t, "flag")) {
1528 pidl "flags |= $flags;";
1530 pidl "return ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_$t->{NAME});";
1533 sub DeclStruct($)
1535 my ($e,$t) = @_;
1536 return ($t ne "pull"?"const ":"") . "struct $e->{NAME} *r";
1539 sub ArgsStructNdrSize($)
1541 my $d = shift;
1542 return "const struct $d->{NAME} *r, int flags";
1545 $typefamily{STRUCT} = {
1546 PUSH_FN_BODY => \&ParseStructPush,
1547 DECL => \&DeclStruct,
1548 PULL_FN_BODY => \&ParseStructPull,
1549 PRINT_FN_BODY => \&ParseStructPrint,
1550 SIZE_FN_BODY => \&ParseStructNdrSize,
1551 SIZE_FN_ARGS => \&ArgsStructNdrSize,
1554 #####################################################################
1555 # calculate size of ndr struct
1556 sub ParseUnionNdrSize($)
1558 my $t = shift;
1559 my $sizevar;
1561 if (my $flags = has_property($t, "flag")) {
1562 pidl "flags |= $flags;";
1565 pidl "return ndr_size_union(r, flags, level, (ndr_push_flags_fn_t)ndr_push_$t->{NAME});";
1568 #####################################################################
1569 # parse a union - push side
1570 sub ParseUnionPush($$)
1572 my ($e,$name) = @_;
1573 my $have_default = 0;
1575 # save the old relative_base_offset
1576 pidl "uint32_t _save_relative_base_offset = ndr_push_get_relative_base_offset(ndr);" if defined($e->{PROPERTIES}{relative_base});
1577 pidl "int level;";
1579 start_flags($e);
1581 pidl "level = ndr_push_get_switch_value(ndr, r);";
1583 pidl "if (ndr_flags & NDR_SCALARS) {";
1584 indent;
1586 if (defined($e->{SWITCH_TYPE})) {
1587 pidl "NDR_CHECK(ndr_push_$e->{SWITCH_TYPE}(ndr, NDR_SCALARS, level));";
1590 pidl "switch (level) {";
1591 indent;
1592 foreach my $el (@{$e->{ELEMENTS}}) {
1593 if ($el->{CASE} eq "default") {
1594 $have_default = 1;
1596 pidl "$el->{CASE}:";
1598 if ($el->{TYPE} ne "EMPTY") {
1599 indent;
1600 if (defined($e->{PROPERTIES}{relative_base})) {
1601 pidl "NDR_CHECK(ndr_push_align(ndr, $el->{ALIGN}));";
1602 # set the current offset as base for relative pointers
1603 # and store it based on the toplevel struct/union
1604 pidl "NDR_CHECK(ndr_push_setup_relative_base_offset1(ndr, r, ndr->offset));";
1606 DeclareArrayVariables($el);
1607 ParseElementPush($el, "ndr", "r->", {}, 1, 0);
1608 deindent;
1610 pidl "break;";
1611 pidl "";
1613 if (! $have_default) {
1614 pidl "default:";
1615 pidl "\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1617 deindent;
1618 pidl "}";
1619 deindent;
1620 pidl "}";
1621 pidl "if (ndr_flags & NDR_BUFFERS) {";
1622 indent;
1623 if (defined($e->{PROPERTIES}{relative_base})) {
1624 # retrieve the current offset as base for relative pointers
1625 # based on the toplevel struct/union
1626 pidl "NDR_CHECK(ndr_push_setup_relative_base_offset2(ndr, r));";
1628 pidl "switch (level) {";
1629 indent;
1630 foreach my $el (@{$e->{ELEMENTS}}) {
1631 pidl "$el->{CASE}:";
1632 if ($el->{TYPE} ne "EMPTY") {
1633 indent;
1634 ParseElementPush($el, "ndr", "r->", {}, 0, 1);
1635 deindent;
1637 pidl "break;";
1638 pidl "";
1640 if (! $have_default) {
1641 pidl "default:";
1642 pidl "\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1644 deindent;
1645 pidl "}";
1647 deindent;
1648 pidl "}";
1649 end_flags($e);
1650 # restore the old relative_base_offset
1651 pidl "ndr_push_restore_relative_base_offset(ndr, _save_relative_base_offset);" if defined($e->{PROPERTIES}{relative_base});
1654 #####################################################################
1655 # print a union
1656 sub ParseUnionPrint($$)
1658 my ($e,$name) = @_;
1659 my $have_default = 0;
1661 pidl "int level;";
1662 foreach my $el (@{$e->{ELEMENTS}}) {
1663 DeclareArrayVariables($el);
1666 start_flags($e);
1668 pidl "level = ndr_print_get_switch_value(ndr, r);";
1670 pidl "ndr_print_union(ndr, name, level, \"$name\");";
1672 pidl "switch (level) {";
1673 indent;
1674 foreach my $el (@{$e->{ELEMENTS}}) {
1675 if ($el->{CASE} eq "default") {
1676 $have_default = 1;
1678 pidl "$el->{CASE}:";
1679 if ($el->{TYPE} ne "EMPTY") {
1680 indent;
1681 ParseElementPrint($el, "r->$el->{NAME}", {});
1682 deindent;
1684 pidl "break;";
1685 pidl "";
1687 if (! $have_default) {
1688 pidl "default:";
1689 pidl "\tndr_print_bad_level(ndr, name, level);";
1691 deindent;
1692 pidl "}";
1694 end_flags($e);
1697 #####################################################################
1698 # parse a union - pull side
1699 sub ParseUnionPull($$)
1701 my ($e,$name) = @_;
1702 my $have_default = 0;
1703 my $switch_type = $e->{SWITCH_TYPE};
1705 # save the old relative_base_offset
1706 pidl "uint32_t _save_relative_base_offset = ndr_pull_get_relative_base_offset(ndr);" if defined($e->{PROPERTIES}{relative_base});
1707 pidl "int level;";
1708 if (defined($switch_type)) {
1709 if (Parse::Pidl::Typelist::typeIs($switch_type, "ENUM")) {
1710 $switch_type = Parse::Pidl::Typelist::enum_type_fn(getType($switch_type));
1712 pidl mapType($switch_type) . " _level;";
1715 my %double_cases = ();
1716 foreach my $el (@{$e->{ELEMENTS}}) {
1717 next if ($el->{TYPE} eq "EMPTY");
1718 next if ($double_cases{"$el->{NAME}"});
1719 DeclareMemCtxVariables($el);
1720 $double_cases{"$el->{NAME}"} = 1;
1723 start_flags($e);
1725 pidl "level = ndr_pull_get_switch_value(ndr, r);";
1727 pidl "if (ndr_flags & NDR_SCALARS) {";
1728 indent;
1730 if (defined($switch_type)) {
1731 pidl "NDR_CHECK(ndr_pull_$switch_type(ndr, NDR_SCALARS, &_level));";
1732 pidl "if (_level != level) {";
1733 pidl "\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value %u for $name\", _level);";
1734 pidl "}";
1737 pidl "switch (level) {";
1738 indent;
1739 foreach my $el (@{$e->{ELEMENTS}}) {
1740 if ($el->{CASE} eq "default") {
1741 $have_default = 1;
1743 pidl "$el->{CASE}: {";
1745 if ($el->{TYPE} ne "EMPTY") {
1746 indent;
1747 DeclarePtrVariables($el);
1748 DeclareArrayVariables($el);
1749 if (defined($e->{PROPERTIES}{relative_base})) {
1750 pidl "NDR_CHECK(ndr_pull_align(ndr, $el->{ALIGN}));";
1751 # set the current offset as base for relative pointers
1752 # and store it based on the toplevel struct/union
1753 pidl "NDR_CHECK(ndr_pull_setup_relative_base_offset1(ndr, r, ndr->offset));";
1755 ParseElementPull($el, "ndr", "r->", {}, 1, 0);
1756 deindent;
1758 pidl "break; }";
1759 pidl "";
1761 if (! $have_default) {
1762 pidl "default:";
1763 pidl "\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1765 deindent;
1766 pidl "}";
1767 deindent;
1768 pidl "}";
1769 pidl "if (ndr_flags & NDR_BUFFERS) {";
1770 indent;
1771 if (defined($e->{PROPERTIES}{relative_base})) {
1772 # retrieve the current offset as base for relative pointers
1773 # based on the toplevel struct/union
1774 pidl "NDR_CHECK(ndr_pull_setup_relative_base_offset2(ndr, r));";
1776 pidl "switch (level) {";
1777 indent;
1778 foreach my $el (@{$e->{ELEMENTS}}) {
1779 pidl "$el->{CASE}:";
1780 if ($el->{TYPE} ne "EMPTY") {
1781 indent;
1782 ParseElementPull($el, "ndr", "r->", {}, 0, 1);
1783 deindent;
1785 pidl "break;";
1786 pidl "";
1788 if (! $have_default) {
1789 pidl "default:";
1790 pidl "\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1792 deindent;
1793 pidl "}";
1795 deindent;
1796 pidl "}";
1798 add_deferred();
1800 end_flags($e);
1801 # restore the old relative_base_offset
1802 pidl "ndr_pull_restore_relative_base_offset(ndr, _save_relative_base_offset);" if defined($e->{PROPERTIES}{relative_base});
1805 sub DeclUnion($$)
1807 my ($e,$t) = @_;
1808 return ($t ne "pull"?"const ":"") . "union $e->{NAME} *r";
1811 sub ArgsUnionNdrSize($)
1813 my $d = shift;
1814 return "const union $d->{NAME} *r, uint32_t level, int flags";
1817 $typefamily{UNION} = {
1818 PUSH_FN_BODY => \&ParseUnionPush,
1819 DECL => \&DeclUnion,
1820 PULL_FN_BODY => \&ParseUnionPull,
1821 PRINT_FN_BODY => \&ParseUnionPrint,
1822 SIZE_FN_ARGS => \&ArgsUnionNdrSize,
1823 SIZE_FN_BODY => \&ParseUnionNdrSize,
1826 #####################################################################
1827 # parse a typedef - push side
1828 sub ParseTypedefPush($)
1830 my($e) = shift;
1832 my $args = $typefamily{$e->{DATA}->{TYPE}}->{DECL}->($e,"push");
1833 fn_declare($e, "NTSTATUS ndr_push_$e->{NAME}(struct ndr_push *ndr, int ndr_flags, $args)");
1835 pidl "{";
1836 indent;
1837 $typefamily{$e->{DATA}->{TYPE}}->{PUSH_FN_BODY}->($e->{DATA}, $e->{NAME});
1838 pidl "return NT_STATUS_OK;";
1839 deindent;
1840 pidl "}";
1841 pidl "";;
1844 #####################################################################
1845 # parse a typedef - pull side
1846 sub ParseTypedefPull($)
1848 my($e) = shift;
1850 my $args = $typefamily{$e->{DATA}->{TYPE}}->{DECL}->($e,"pull");
1852 fn_declare($e, "NTSTATUS ndr_pull_$e->{NAME}(struct ndr_pull *ndr, int ndr_flags, $args)");
1854 pidl "{";
1855 indent;
1856 $typefamily{$e->{DATA}->{TYPE}}->{PULL_FN_BODY}->($e->{DATA}, $e->{NAME});
1857 pidl "return NT_STATUS_OK;";
1858 deindent;
1859 pidl "}";
1860 pidl "";
1863 #####################################################################
1864 # parse a typedef - print side
1865 sub ParseTypedefPrint($)
1867 my($e) = shift;
1869 my $args = $typefamily{$e->{DATA}->{TYPE}}->{DECL}->($e,"print");
1871 pidl "_PUBLIC_ void ndr_print_$e->{NAME}(struct ndr_print *ndr, const char *name, $args)";
1872 pidl_hdr "void ndr_print_$e->{NAME}(struct ndr_print *ndr, const char *name, $args);";
1873 pidl "{";
1874 indent;
1875 $typefamily{$e->{DATA}->{TYPE}}->{PRINT_FN_BODY}->($e->{DATA}, $e->{NAME});
1876 deindent;
1877 pidl "}";
1878 pidl "";
1881 #####################################################################
1882 ## calculate the size of a structure
1883 sub ParseTypedefNdrSize($)
1885 my($t) = shift;
1887 my $tf = $typefamily{$t->{DATA}->{TYPE}};
1888 my $args = $tf->{SIZE_FN_ARGS}->($t);
1890 fn_declare($t, "size_t ndr_size_$t->{NAME}($args)");
1892 pidl "{";
1893 indent;
1894 $typefamily{$t->{DATA}->{TYPE}}->{SIZE_FN_BODY}->($t);
1895 deindent;
1896 pidl "}";
1897 pidl "";
1900 #####################################################################
1901 # parse a function - print side
1902 sub ParseFunctionPrint($)
1904 my($fn) = shift;
1906 return if has_property($fn, "noprint");
1908 pidl "_PUBLIC_ void ndr_print_$fn->{NAME}(struct ndr_print *ndr, const char *name, int flags, const struct $fn->{NAME} *r)";
1909 pidl_hdr "void ndr_print_$fn->{NAME}(struct ndr_print *ndr, const char *name, int flags, const struct $fn->{NAME} *r);";
1910 pidl "{";
1911 indent;
1913 foreach my $e (@{$fn->{ELEMENTS}}) {
1914 DeclareArrayVariables($e);
1917 pidl "ndr_print_struct(ndr, name, \"$fn->{NAME}\");";
1918 pidl "ndr->depth++;";
1920 pidl "if (flags & NDR_SET_VALUES) {";
1921 pidl "\tndr->flags |= LIBNDR_PRINT_SET_VALUES;";
1922 pidl "}";
1924 pidl "if (flags & NDR_IN) {";
1925 indent;
1926 pidl "ndr_print_struct(ndr, \"in\", \"$fn->{NAME}\");";
1927 pidl "ndr->depth++;";
1929 my $env = GenerateFunctionInEnv($fn);
1930 EnvSubstituteValue($env, $fn);
1932 foreach my $e (@{$fn->{ELEMENTS}}) {
1933 if (grep(/in/,@{$e->{DIRECTION}})) {
1934 ParseElementPrint($e, "r->in.$e->{NAME}", $env);
1937 pidl "ndr->depth--;";
1938 deindent;
1939 pidl "}";
1941 pidl "if (flags & NDR_OUT) {";
1942 indent;
1943 pidl "ndr_print_struct(ndr, \"out\", \"$fn->{NAME}\");";
1944 pidl "ndr->depth++;";
1946 $env = GenerateFunctionOutEnv($fn);
1947 foreach my $e (@{$fn->{ELEMENTS}}) {
1948 if (grep(/out/,@{$e->{DIRECTION}})) {
1949 ParseElementPrint($e, "r->out.$e->{NAME}", $env);
1952 if ($fn->{RETURN_TYPE}) {
1953 pidl "ndr_print_$fn->{RETURN_TYPE}(ndr, \"result\", r->out.result);";
1955 pidl "ndr->depth--;";
1956 deindent;
1957 pidl "}";
1959 pidl "ndr->depth--;";
1960 deindent;
1961 pidl "}";
1962 pidl "";
1965 #####################################################################
1966 # parse a function
1967 sub ParseFunctionPush($)
1969 my($fn) = shift;
1971 return if has_property($fn, "nopush");
1973 fn_declare($fn, "NTSTATUS ndr_push_$fn->{NAME}(struct ndr_push *ndr, int flags, const struct $fn->{NAME} *r)");
1975 pidl "{";
1976 indent;
1978 foreach my $e (@{$fn->{ELEMENTS}}) {
1979 DeclareArrayVariables($e);
1982 pidl "if (flags & NDR_IN) {";
1983 indent;
1985 my $env = GenerateFunctionInEnv($fn);
1987 EnvSubstituteValue($env, $fn);
1989 foreach my $e (@{$fn->{ELEMENTS}}) {
1990 if (grep(/in/,@{$e->{DIRECTION}})) {
1991 ParseElementPush($e, "ndr", "r->in.", $env, 1, 1);
1995 deindent;
1996 pidl "}";
1998 pidl "if (flags & NDR_OUT) {";
1999 indent;
2001 $env = GenerateFunctionOutEnv($fn);
2002 foreach my $e (@{$fn->{ELEMENTS}}) {
2003 if (grep(/out/,@{$e->{DIRECTION}})) {
2004 ParseElementPush($e, "ndr", "r->out.", $env, 1, 1);
2008 if ($fn->{RETURN_TYPE}) {
2009 pidl "NDR_CHECK(ndr_push_$fn->{RETURN_TYPE}(ndr, NDR_SCALARS, r->out.result));";
2012 deindent;
2013 pidl "}";
2014 pidl "return NT_STATUS_OK;";
2015 deindent;
2016 pidl "}";
2017 pidl "";
2020 sub AllocateArrayLevel($$$$$)
2022 my ($e,$l,$ndr,$env,$size) = @_;
2024 my $var = ParseExpr($e->{NAME}, $env);
2026 check_null_pointer($size);
2027 my $pl = GetPrevLevel($e, $l);
2028 if (defined($pl) and
2029 $pl->{TYPE} eq "POINTER" and
2030 $pl->{POINTER_TYPE} eq "ref"
2031 and not $l->{IS_ZERO_TERMINATED}) {
2032 pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {";
2033 pidl "\tNDR_PULL_ALLOC_N($ndr, $var, $size);";
2034 pidl "}";
2035 if (grep(/in/,@{$e->{DIRECTION}}) and
2036 grep(/out/,@{$e->{DIRECTION}})) {
2037 pidl "memcpy(r->out.$e->{NAME},r->in.$e->{NAME},$size * sizeof(*r->in.$e->{NAME}));";
2039 return;
2042 pidl "NDR_PULL_ALLOC_N($ndr, $var, $size);";
2045 #####################################################################
2046 # parse a function
2047 sub ParseFunctionPull($)
2049 my($fn) = shift;
2051 return if has_property($fn, "nopull");
2053 # pull function args
2054 fn_declare($fn, "NTSTATUS ndr_pull_$fn->{NAME}(struct ndr_pull *ndr, int flags, struct $fn->{NAME} *r)");
2055 pidl "{";
2056 indent;
2058 # declare any internal pointers we need
2059 foreach my $e (@{$fn->{ELEMENTS}}) {
2060 DeclarePtrVariables($e);
2061 DeclareArrayVariables($e);
2064 my %double_cases = ();
2065 foreach my $e (@{$fn->{ELEMENTS}}) {
2066 next if ($e->{TYPE} eq "EMPTY");
2067 next if ($double_cases{"$e->{NAME}"});
2068 DeclareMemCtxVariables($e);
2069 $double_cases{"$e->{NAME}"} = 1;
2072 pidl "if (flags & NDR_IN) {";
2073 indent;
2075 # auto-init the out section of a structure. I originally argued that
2076 # this was a bad idea as it hides bugs, but coping correctly
2077 # with initialisation and not wiping ref vars is turning
2078 # out to be too tricky (tridge)
2079 foreach my $e (@{$fn->{ELEMENTS}}) {
2080 next unless grep(/out/, @{$e->{DIRECTION}});
2081 pidl "ZERO_STRUCT(r->out);";
2082 pidl "";
2083 last;
2086 my $env = GenerateFunctionInEnv($fn);
2088 foreach my $e (@{$fn->{ELEMENTS}}) {
2089 next unless (grep(/in/, @{$e->{DIRECTION}}));
2090 ParseElementPull($e, "ndr", "r->in.", $env, 1, 1);
2093 # allocate the "simple" out ref variables. FIXME: Shouldn't this have it's
2094 # own flag rather then be in NDR_IN ?
2096 foreach my $e (@{$fn->{ELEMENTS}}) {
2097 next unless (grep(/out/, @{$e->{DIRECTION}}));
2098 next unless ($e->{LEVELS}[0]->{TYPE} eq "POINTER" and
2099 $e->{LEVELS}[0]->{POINTER_TYPE} eq "ref");
2100 next if (($e->{LEVELS}[1]->{TYPE} eq "DATA") and
2101 ($e->{LEVELS}[1]->{DATA_TYPE} eq "string"));
2102 next if (($e->{LEVELS}[1]->{TYPE} eq "ARRAY")
2103 and $e->{LEVELS}[1]->{IS_ZERO_TERMINATED});
2105 if ($e->{LEVELS}[1]->{TYPE} eq "ARRAY") {
2106 my $size = ParseExpr($e->{LEVELS}[1]->{SIZE_IS}, $env);
2107 check_null_pointer($size);
2109 pidl "NDR_PULL_ALLOC_N(ndr, r->out.$e->{NAME}, $size);";
2111 if (grep(/in/, @{$e->{DIRECTION}})) {
2112 pidl "memcpy(r->out.$e->{NAME}, r->in.$e->{NAME}, $size * sizeof(*r->in.$e->{NAME}));";
2113 } else {
2114 pidl "memset(r->out.$e->{NAME}, 0, $size * sizeof(*r->out.$e->{NAME}));";
2116 } else {
2117 pidl "NDR_PULL_ALLOC(ndr, r->out.$e->{NAME});";
2119 if (grep(/in/, @{$e->{DIRECTION}})) {
2120 pidl "*r->out.$e->{NAME} = *r->in.$e->{NAME};";
2121 } else {
2122 pidl "ZERO_STRUCTP(r->out.$e->{NAME});";
2127 add_deferred();
2128 deindent;
2129 pidl "}";
2131 pidl "if (flags & NDR_OUT) {";
2132 indent;
2134 $env = GenerateFunctionOutEnv($fn);
2135 foreach my $e (@{$fn->{ELEMENTS}}) {
2136 next unless grep(/out/, @{$e->{DIRECTION}});
2137 ParseElementPull($e, "ndr", "r->out.", $env, 1, 1);
2140 if ($fn->{RETURN_TYPE}) {
2141 pidl "NDR_CHECK(ndr_pull_$fn->{RETURN_TYPE}(ndr, NDR_SCALARS, &r->out.result));";
2144 add_deferred();
2145 deindent;
2146 pidl "}";
2148 pidl "return NT_STATUS_OK;";
2149 deindent;
2150 pidl "}";
2151 pidl "";
2154 #####################################################################
2155 # produce a function call table
2156 sub FunctionTable($)
2158 my($interface) = shift;
2159 my $count = 0;
2160 my $uname = uc $interface->{NAME};
2162 return if ($#{$interface->{FUNCTIONS}}+1 == 0);
2163 return unless defined ($interface->{PROPERTIES}->{uuid});
2165 pidl "static const struct dcerpc_interface_call $interface->{NAME}\_calls[] = {";
2166 foreach my $d (@{$interface->{FUNCTIONS}}) {
2167 next if not defined($d->{OPNUM});
2168 pidl "\t{";
2169 pidl "\t\t\"$d->{NAME}\",";
2170 pidl "\t\tsizeof(struct $d->{NAME}),";
2171 pidl "\t\t(ndr_push_flags_fn_t) ndr_push_$d->{NAME},";
2172 pidl "\t\t(ndr_pull_flags_fn_t) ndr_pull_$d->{NAME},";
2173 pidl "\t\t(ndr_print_function_t) ndr_print_$d->{NAME},";
2174 pidl "\t\t".($d->{ASYNC}?"True":"False").",";
2175 pidl "\t},";
2176 $count++;
2178 pidl "\t{ NULL, 0, NULL, NULL, NULL, False }";
2179 pidl "};";
2180 pidl "";
2182 pidl "static const char * const $interface->{NAME}\_endpoint_strings[] = {";
2183 foreach my $ep (@{$interface->{ENDPOINTS}}) {
2184 pidl "\t$ep, ";
2186 my $endpoint_count = $#{$interface->{ENDPOINTS}}+1;
2188 pidl "};";
2189 pidl "";
2191 pidl "static const struct dcerpc_endpoint_list $interface->{NAME}\_endpoints = {";
2192 pidl "\t.count\t= $endpoint_count,";
2193 pidl "\t.names\t= $interface->{NAME}\_endpoint_strings";
2194 pidl "};";
2195 pidl "";
2197 if (! defined $interface->{PROPERTIES}->{authservice}) {
2198 $interface->{PROPERTIES}->{authservice} = "\"host\"";
2201 my @a = split / /, $interface->{PROPERTIES}->{authservice};
2202 my $authservice_count = $#a + 1;
2204 pidl "static const char * const $interface->{NAME}\_authservice_strings[] = {";
2205 foreach my $ap (@a) {
2206 pidl "\t$ap, ";
2208 pidl "};";
2209 pidl "";
2211 pidl "static const struct dcerpc_authservice_list $interface->{NAME}\_authservices = {";
2212 pidl "\t.count\t= $endpoint_count,";
2213 pidl "\t.names\t= $interface->{NAME}\_authservice_strings";
2214 pidl "};";
2215 pidl "";
2217 pidl "\nconst struct dcerpc_interface_table dcerpc_table_$interface->{NAME} = {";
2218 pidl "\t.name\t\t= \"$interface->{NAME}\",";
2219 pidl "\t.uuid\t\t= ". print_uuid($interface->{UUID}) .",";
2220 pidl "\t.if_version\t= DCERPC_$uname\_VERSION,";
2221 pidl "\t.helpstring\t= DCERPC_$uname\_HELPSTRING,";
2222 pidl "\t.num_calls\t= $count,";
2223 pidl "\t.calls\t\t= $interface->{NAME}\_calls,";
2224 pidl "\t.endpoints\t= &$interface->{NAME}\_endpoints,";
2225 pidl "\t.authservices\t= &$interface->{NAME}\_authservices";
2226 pidl "};";
2227 pidl "";
2231 #####################################################################
2232 # generate prototypes and defines for the interface definitions
2233 # FIXME: these prototypes are for the DCE/RPC client functions, not the
2234 # NDR parser and so do not belong here, technically speaking
2235 sub HeaderInterface($)
2237 my($interface) = shift;
2239 my $count = 0;
2241 pidl_hdr choose_header("librpc/ndr/libndr.h", "ndr.h");
2243 if (has_property($interface, "object")) {
2244 pidl choose_header("librpc/gen_ndr/ndr_orpc.h", "ndr/orpc.h");
2247 if (defined $interface->{PROPERTIES}->{depends}) {
2248 my @d = split / /, $interface->{PROPERTIES}->{depends};
2249 foreach my $i (@d) {
2250 pidl choose_header("librpc/gen_ndr/ndr_$i\.h", "gen_ndr/ndr_$i.h");
2254 if (defined $interface->{PROPERTIES}->{helper}) {
2255 foreach (split / /, $interface->{PROPERTIES}->{helper}) {
2256 pidl_hdr "#include $_";
2260 if (defined $interface->{PROPERTIES}->{uuid}) {
2261 my $name = uc $interface->{NAME};
2262 pidl_hdr "#define DCERPC_$name\_UUID " .
2263 Parse::Pidl::Util::make_str(lc($interface->{PROPERTIES}->{uuid}));
2265 if(!defined $interface->{PROPERTIES}->{version}) { $interface->{PROPERTIES}->{version} = "0.0"; }
2266 pidl_hdr "#define DCERPC_$name\_VERSION $interface->{PROPERTIES}->{version}";
2268 pidl_hdr "#define DCERPC_$name\_NAME \"$interface->{NAME}\"";
2270 if(!defined $interface->{PROPERTIES}->{helpstring}) { $interface->{PROPERTIES}->{helpstring} = "NULL"; }
2271 pidl_hdr "#define DCERPC_$name\_HELPSTRING $interface->{PROPERTIES}->{helpstring}";
2273 pidl_hdr "extern const struct dcerpc_interface_table dcerpc_table_$interface->{NAME};";
2274 pidl_hdr "NTSTATUS dcerpc_server_$interface->{NAME}_init(void);";
2277 foreach (@{$interface->{FUNCTIONS}}) {
2278 next if has_property($_, "noopnum");
2279 next if grep(/$_->{NAME}/,@{$interface->{INHERITED_FUNCTIONS}});
2280 my $u_name = uc $_->{NAME};
2282 my $val = sprintf("0x%02x", $count);
2283 if (defined($interface->{BASE})) {
2284 $val .= " + DCERPC_" . uc $interface->{BASE} . "_CALL_COUNT";
2287 pidl_hdr "#define DCERPC_$u_name ($val)";
2289 pidl_hdr "";
2290 $count++;
2293 my $val = $count;
2295 if (defined($interface->{BASE})) {
2296 $val .= " + DCERPC_" . uc $interface->{BASE} . "_CALL_COUNT";
2299 pidl_hdr "#define DCERPC_" . uc $interface->{NAME} . "_CALL_COUNT ($val)";
2303 #####################################################################
2304 # parse the interface definitions
2305 sub ParseInterface($$)
2307 my($interface,$needed) = @_;
2309 pidl_hdr "#ifndef _HEADER_NDR_$interface->{NAME}";
2310 pidl_hdr "#define _HEADER_NDR_$interface->{NAME}";
2312 pidl_hdr "";
2314 if ($needed->{"compression"}) {
2315 pidl choose_header("librpc/ndr/ndr_compression.h", "ndr/compression.h");
2318 HeaderInterface($interface);
2320 # Typedefs
2321 foreach my $d (@{$interface->{TYPES}}) {
2322 ($needed->{"push_$d->{NAME}"}) && ParseTypedefPush($d);
2323 ($needed->{"pull_$d->{NAME}"}) && ParseTypedefPull($d);
2324 ($needed->{"print_$d->{NAME}"}) && ParseTypedefPrint($d);
2326 # Make sure we don't generate a function twice...
2327 $needed->{"push_$d->{NAME}"} = $needed->{"pull_$d->{NAME}"} =
2328 $needed->{"print_$d->{NAME}"} = 0;
2330 ($needed->{"ndr_size_$d->{NAME}"}) && ParseTypedefNdrSize($d);
2333 # Functions
2334 foreach my $d (@{$interface->{FUNCTIONS}}) {
2335 ($needed->{"push_$d->{NAME}"}) && ParseFunctionPush($d);
2336 ($needed->{"pull_$d->{NAME}"}) && ParseFunctionPull($d);
2337 ($needed->{"print_$d->{NAME}"}) && ParseFunctionPrint($d);
2339 # Make sure we don't generate a function twice...
2340 $needed->{"push_$d->{NAME}"} = $needed->{"pull_$d->{NAME}"} =
2341 $needed->{"print_$d->{NAME}"} = 0;
2344 FunctionTable($interface);
2346 pidl_hdr "#endif /* _HEADER_NDR_$interface->{NAME} */";
2349 #####################################################################
2350 # parse a parsed IDL structure back into an IDL file
2351 sub Parse($$$)
2353 my($ndr,$gen_header,$ndr_header) = @_;
2355 $tabs = "";
2356 $res = "";
2358 $res_hdr = "";
2359 pidl_hdr "/* header auto-generated by pidl */";
2360 pidl_hdr "";
2361 pidl_hdr "#include \"$gen_header\"" if ($gen_header);
2362 pidl_hdr "";
2364 pidl "/* parser auto-generated by pidl */";
2365 pidl "";
2366 if (is_intree()) {
2367 pidl "#include \"includes.h\"";
2368 } else {
2369 pidl "#define _GNU_SOURCE";
2370 pidl "#include <stdint.h>";
2371 pidl "#include <stdlib.h>";
2372 pidl "#include <stdio.h>";
2373 pidl "#include <stdarg.h>";
2374 pidl "#include <string.h>";
2376 pidl choose_header("libcli/util/nterr.h", "core/nterr.h");
2377 pidl choose_header("librpc/gen_ndr/ndr_misc.h", "gen_ndr/ndr_misc.h");
2378 pidl choose_header("librpc/gen_ndr/ndr_dcerpc.h", "gen_ndr/ndr_dcerpc.h");
2379 pidl "#include \"$ndr_header\"" if ($ndr_header);
2380 pidl choose_header("librpc/rpc/dcerpc.h", "dcerpc.h"); #FIXME: This shouldn't be here!
2381 pidl "";
2383 my %needed = ();
2385 foreach (@{$ndr}) {
2386 ($_->{TYPE} eq "INTERFACE") && NeededInterface($_, \%needed);
2389 foreach (@{$ndr}) {
2390 ($_->{TYPE} eq "INTERFACE") && ParseInterface($_, \%needed);
2393 return ($res_hdr, $res);
2396 sub NeededFunction($$)
2398 my ($fn,$needed) = @_;
2399 $needed->{"pull_$fn->{NAME}"} = 1;
2400 $needed->{"push_$fn->{NAME}"} = 1;
2401 $needed->{"print_$fn->{NAME}"} = 1;
2402 foreach my $e (@{$fn->{ELEMENTS}}) {
2403 $e->{PARENT} = $fn;
2404 unless(defined($needed->{"pull_$e->{TYPE}"})) {
2405 $needed->{"pull_$e->{TYPE}"} = 1;
2407 unless(defined($needed->{"push_$e->{TYPE}"})) {
2408 $needed->{"push_$e->{TYPE}"} = 1;
2410 unless(defined($needed->{"print_$e->{TYPE}"})) {
2411 $needed->{"print_$e->{TYPE}"} = 1;
2416 sub NeededTypedef($$)
2418 my ($t,$needed) = @_;
2419 if (has_property($t, "public")) {
2420 $needed->{"pull_$t->{NAME}"} = not has_property($t, "nopull");
2421 $needed->{"push_$t->{NAME}"} = not has_property($t, "nopush");
2422 $needed->{"print_$t->{NAME}"} = not has_property($t, "noprint");
2425 if ($t->{DATA}->{TYPE} eq "STRUCT" or $t->{DATA}->{TYPE} eq "UNION") {
2426 if (has_property($t, "gensize")) {
2427 $needed->{"ndr_size_$t->{NAME}"} = 1;
2430 for my $e (@{$t->{DATA}->{ELEMENTS}}) {
2431 $e->{PARENT} = $t->{DATA};
2432 if (has_property($e, "compression")) {
2433 $needed->{"compression"} = 1;
2435 if ($needed->{"pull_$t->{NAME}"} and
2436 not defined($needed->{"pull_$e->{TYPE}"})) {
2437 $needed->{"pull_$e->{TYPE}"} = 1;
2439 if ($needed->{"push_$t->{NAME}"} and
2440 not defined($needed->{"push_$e->{TYPE}"})) {
2441 $needed->{"push_$e->{TYPE}"} = 1;
2443 if ($needed->{"print_$t->{NAME}"} and
2444 not defined($needed->{"print_$e->{TYPE}"})) {
2445 $needed->{"print_$e->{TYPE}"} = 1;
2451 #####################################################################
2452 # work out what parse functions are needed
2453 sub NeededInterface($$)
2455 my ($interface,$needed) = @_;
2456 NeededFunction($_, $needed) foreach (@{$interface->{FUNCTIONS}});
2457 NeededTypedef($_, $needed) foreach (reverse @{$interface->{TYPES}});