r5671: Bunch of fixes related to arrays and pointers to arrays.
[Samba/gebeck_regimport.git] / source4 / build / pidl / ndr.pm
blob333f20e78f19423153d308fe7d799cae56e9262a
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 NdrParser;
10 use strict;
11 use needed;
12 use typelist;
14 # list of known types
15 my %typefamily;
17 sub get_typefamily($)
19 my $n = shift;
20 return $typefamily{$n};
23 my %scalar_alignments =
25 "char" => 1,
26 "int8" => 1,
27 "uint8" => 1,
28 "short" => 2,
29 "wchar_t" => 2,
30 "int16" => 2,
31 "uint16" => 2,
32 "long" => 4,
33 "int32" => 4,
34 "uint32" => 4,
35 "dlong" => 4,
36 "udlong" => 4,
37 "udlongr" => 4,
38 "NTTIME" => 4,
39 "NTTIME_1sec" => 4,
40 "time_t" => 4,
41 "DATA_BLOB" => 4,
42 "error_status_t" => 4,
43 "WERROR" => 4,
44 "NTSTATUS" => 4,
45 "boolean32" => 4,
46 "unsigned32" => 4,
47 "ipv4address" => 4,
48 "hyper" => 8,
49 "NTTIME_hyper" => 8
52 $typefamily{SCALAR} = {
53 ALIGN => sub {
54 my $t = shift;
55 return $scalar_alignments{$t->{NAME}};
59 sub is_scalar_type($)
61 my $type = shift;
63 return 0 unless typelist::hasType($type);
65 if (my $dt = typelist::getType($type)->{DATA}->{TYPE}) {
66 return 1 if ($dt eq "SCALAR" or $dt eq "ENUM" or $dt eq "BITMAP");
69 return 0;
72 sub pointer_type($)
74 my $e = shift;
76 return undef unless $e->{POINTERS};
78 return "ref" if (util::has_property($e, "ref"));
79 return "ptr" if (util::has_property($e, "ptr"));
80 return "unique" if (util::has_property($e, "unique"));
81 return "relative" if (util::has_property($e, "relative"));
82 return "ignore" if (util::has_property($e, "ignore"));
84 return undef;
87 # return 1 if this is a fixed array
88 sub is_fixed_array($)
90 my $e = shift;
91 my $len = $e->{"ARRAY_LEN"};
92 return 1 if (defined $len && util::is_constant($len));
93 return 0;
96 # return 1 if this is a conformant array
97 sub is_conformant_array($)
99 my $e = shift;
100 return 1 if (util::has_property($e, "size_is"));
101 return 0;
104 # return 1 if this is a inline array
105 sub is_inline_array($)
107 my $e = shift;
108 my $len = $e->{"ARRAY_LEN"};
109 if (is_fixed_array($e) ||
110 defined $len && $len ne "*") {
111 return 1;
113 return 0;
116 # return 1 if this is a varying array
117 sub is_varying_array($)
119 my $e = shift;
120 return util::has_property($e, "length_is");
123 # return 1 if this is a surrounding array (sometimes
124 # referred to as an embedded array). Can only occur as
125 # the last element in a struct and can not contain any pointers.
126 sub is_surrounding_array($)
128 my $e = shift;
130 return ($e->{POINTERS} == 0
131 and defined $e->{ARRAY_LEN}
132 and $e->{ARRAY_LEN} eq "*"
133 and $e == $e->{PARENT}->{ELEMENTS}[-1]
134 and $e->{PARENT}->{TYPE} ne "FUNCTION");
137 sub array_type($)
139 my $e = shift;
141 return "conformant-varying" if (is_varying_array($e) and is_conformant_array($e));
142 return "conformant" if (is_varying_array($e));
143 return "varying" if (is_varying_array($e));
144 return "inline" if (is_inline_array($e));
145 return "fixed" if (is_fixed_array($e));
147 return undef;
150 # determine if an element needs a reference pointer on the wire
151 # in its NDR representation
152 sub need_wire_pointer($)
154 my $e = shift;
156 my $n = $e->{POINTERS};
157 my $pt = pointer_type($e);
159 # Top level "ref" pointers do not have a referrent identifier
160 if ( defined($pt)
161 and $pt eq "ref"
162 and $e->{PARENT}->{TYPE} eq "FUNCTION")
164 $n--;
167 return $n;
170 # determine if an element needs a "buffers" section in NDR
171 sub need_buffers_section($)
173 my $e = shift;
174 if ((is_scalar_type($e->{TYPE}) || util::has_property($e, "subcontext")) &&
175 $e->{POINTERS} == 0 &&
176 !util::array_size($e)) {
177 return 0;
179 return 1;
182 # see if a variable needs to be allocated by the NDR subsystem on pull
183 sub need_alloc($)
185 my $e = shift;
187 return 0 if (util::has_property($e, "ref"));
188 return 1 if ($e->{POINTERS} || util::array_size($e));
189 return 0;
192 # Prefix to get the actual value of a variable
193 sub c_ptr_prefix($)
195 my $e = shift;
196 my $pointers = "";
197 foreach my $i (need_wire_pointer($e)..$e->{POINTERS}-1) { $pointers.="*"; }
198 return $pointers;
201 # determine the C prefix used to refer to a variable when passing to a push
202 # function. This will be '*' for pointers to scalar types, '' for scalar
203 # types and normal pointers and '&' for pass-by-reference structures
204 sub c_push_prefix($)
206 my $e = shift;
208 my $ret = "";
210 if ($e->{TYPE} =~ "string") {
211 $ret = "";
212 } elsif (is_scalar_type($e->{TYPE}) and $e->{POINTERS} and
213 !util::array_size($e)) {
214 $ret .="*";
215 } elsif (!is_scalar_type($e->{TYPE}) &&
216 !$e->{POINTERS} &&
217 !util::array_size($e)) {
218 return "&";
221 foreach my $i (2..$e->{POINTERS}) { $ret.="*"; }
223 return $ret;
226 # determine the C prefix used to refer to a variable when passing to a pull
227 # return '&' or ''
228 sub c_pull_prefix($)
230 my $e = shift;
232 if (!$e->{POINTERS} && !util::array_size($e)) {
233 return "&";
236 if ($e->{TYPE} =~ "string") {
237 return "&";
240 my $ret = "";
241 foreach my $i (2..$e->{POINTERS}) { $ret.="*"; }
242 return $ret;
244 my $res = "";
245 my $tabs = "";
246 sub pidl($)
248 my $d = shift;
249 if ($d) {
250 $res .= $tabs;
251 $res .= $d;
253 $res .="\n";
256 sub indent()
258 $tabs .= "\t";
261 sub deindent()
263 $tabs = substr($tabs, 0, -1);
266 ####################################################################
267 # work out the name of a size_is() variable
268 sub ParseExpr($$$)
270 my($e) = shift;
271 my($size) = shift;
272 my($var_prefix) = shift;
274 my($fn) = $e->{PARENT};
276 return $size if (util::is_constant($size));
278 return $size if ($size =~ /ndr->|\(/);
280 my $prefix = "";
282 if ($size =~ /\*(.*)/) {
283 $size = $1;
284 $prefix = "*";
287 if ($fn->{TYPE} ne "FUNCTION") {
288 return $prefix . "r->$size";
291 my $e2 = util::find_sibling($e, $size);
293 die("Invalid sibling '$size'") unless defined($e2);
295 if (util::has_property($e2, "in") && util::has_property($e2, "out")) {
296 return $prefix . "$var_prefix$size";
299 if (util::has_property($e2, "in")) {
300 return $prefix . "r->in.$size";
303 if (util::has_property($e2, "out")) {
304 return $prefix . "r->out.$size";
307 die "invalid variable in $size for element $e->{NAME} in $fn->{NAME}\n";
310 #####################################################################
311 # check that a variable we get from ParseExpr isn't a null pointer
312 sub check_null_pointer($)
314 my $size = shift;
315 if ($size =~ /^\*/) {
316 my $size2 = substr($size, 1);
317 pidl "if ($size2 == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;";
321 #####################################################################
322 # check that a variable we get from ParseExpr isn't a null pointer
323 # void return varient
324 sub check_null_pointer_void($)
326 my $size = shift;
327 if ($size =~ /^\*/) {
328 my $size2 = substr($size, 1);
329 pidl "if ($size2 == NULL) return;";
333 #####################################################################
334 # work out is a parse function should be declared static or not
335 sub fn_prefix($)
337 my $fn = shift;
339 if ($fn->{TYPE} eq "TYPEDEF" or
340 $fn->{TYPE} eq "FUNCTION") {
341 return "" if (util::has_property($fn, "public"));
344 return "static ";
347 ###################################################################
348 # setup any special flags for an element or structure
349 sub start_flags($)
351 my $e = shift;
352 my $flags = util::has_property($e, "flag");
353 if (defined $flags) {
354 pidl "{ uint32_t _flags_save_$e->{TYPE} = ndr->flags;";
355 pidl "ndr_set_flags(&ndr->flags, $flags);";
359 ###################################################################
360 # end any special flags for an element or structure
361 sub end_flags($)
363 my $e = shift;
364 my $flags = util::has_property($e, "flag");
365 if (defined $flags) {
366 pidl "ndr->flags = _flags_save_$e->{TYPE};\n\t}";
370 #####################################################################
371 # work out the correct alignment for a structure or union
372 sub find_largest_alignment($)
374 my $s = shift;
376 my $align = 1;
377 for my $e (@{$s->{ELEMENTS}}) {
378 my $a = 1;
380 if (need_wire_pointer($e)) {
381 $a = 4;
382 } else {
383 $a = align_type($e->{TYPE});
386 $align = $a if ($align < $a);
389 return $align;
392 #####################################################################
393 # align a type
394 sub align_type
396 my $e = shift;
398 unless (typelist::hasType($e)) {
399 # it must be an external type - all we can do is guess
400 # print "Warning: assuming alignment of unknown type '$e' is 4\n";
401 return 4;
404 my $dt = typelist::getType($e)->{DATA};
406 my $tmp = $typefamily{$dt->{TYPE}}->{ALIGN}->($dt);
407 return $tmp;
410 #####################################################################
411 # parse array preceding data - push side
412 sub ParseArrayPushPreceding($$$)
414 my $e = shift;
415 my $var_prefix = shift;
416 my $ndr_flags = shift;
418 my $size = ParseExpr($e, util::array_size($e), $var_prefix);
420 if (!is_inline_array($e)) {
421 # we need to emit the array size
422 pidl "NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, $size));";
426 #####################################################################
427 # parse the data of an array - push side
428 sub ParseArrayPush($$$$)
430 my $e = shift;
431 my $ndr = shift;
432 my $var_prefix = shift;
433 my $ndr_flags = shift;
434 my $cprefix = c_push_prefix($e);
436 my $size = ParseExpr($e, util::array_size($e), $var_prefix);
438 # See whether the array size has been pushed yet
439 if (!is_surrounding_array($e)) {
440 ParseArrayPushPreceding($e, $var_prefix, $ndr_flags);
443 if (is_varying_array($e)) {
444 my $length = util::has_property($e, "length_is");
445 $length = ParseExpr($e, $length, $var_prefix);
446 pidl "NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, 0));";
447 pidl "NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, $length));";
448 $size = $length;
451 if (is_scalar_type($e->{TYPE})) {
452 pidl "NDR_CHECK(ndr_push_array_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}, $size));";
453 } else {
454 pidl "NDR_CHECK(ndr_push_array($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}, sizeof($cprefix$var_prefix$e->{NAME}\[0]), $size, (ndr_push_flags_fn_t)ndr_push_$e->{TYPE}));";
458 #####################################################################
459 # print an array
460 sub ParseArrayPrint($$)
462 my $e = shift;
463 my $var_prefix = shift;
464 my $size = ParseExpr($e, util::array_size($e), $var_prefix);
465 my $cprefix = c_push_prefix($e);
467 if (is_varying_array($e)) {
468 $size = ParseExpr($e, util::has_property($e, "length_is"), $var_prefix);
471 if (is_scalar_type($e->{TYPE})) {
472 pidl "ndr_print_array_$e->{TYPE}(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME}, $size);";
473 } else {
474 pidl "ndr_print_array(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME}, sizeof($cprefix$var_prefix$e->{NAME}\[0]), $size, (ndr_print_fn_t)ndr_print_$e->{TYPE});";
478 #####################################################################
479 # check the size_is and length_is constraints
480 sub CheckArraySizes($$)
482 my $e = shift;
483 my $var_prefix = shift;
485 if (is_conformant_array($e)) {
486 my $size = ParseExpr($e, util::array_size($e), $var_prefix);
487 pidl "if ($var_prefix$e->{NAME}) {";
488 indent;
489 check_null_pointer($size);
490 pidl "NDR_CHECK(ndr_check_array_size(ndr, (void*)&$var_prefix$e->{NAME}, $size));";
491 deindent;
492 pidl "}";
495 if (is_varying_array($e)) {
496 my $length = util::has_property($e, "length_is");
497 $length = ParseExpr($e, $length, $var_prefix);
498 pidl "if ($var_prefix$e->{NAME}) {";
499 indent;
500 check_null_pointer($length);
501 pidl "NDR_CHECK(ndr_check_array_length(ndr, (void*)&$var_prefix$e->{NAME}, $length));";
502 deindent;
503 pidl "}"
507 sub ParseArrayPullPreceding($$$)
509 my $e = shift;
510 my $var_prefix = shift;
511 my $ndr_flags = shift;
513 if (!is_inline_array($e)) {
514 # non fixed arrays encode the size just before the array
515 pidl "NDR_CHECK(ndr_pull_array_size(ndr, &$var_prefix$e->{NAME}));";
519 #####################################################################
520 # parse an array - pull side
521 sub ParseArrayPull($$$$)
523 my $e = shift;
524 my $ndr = shift;
525 my $var_prefix = shift;
526 my $ndr_flags = shift;
528 my $cprefix = c_pull_prefix($e);
529 my $length = ParseExpr($e, util::array_size($e), $var_prefix);
530 my $size = $length;
532 if (is_conformant_array($e)) {
533 $size = "ndr_get_array_size($ndr, &$var_prefix$e->{NAME})";
536 # if this is a conformant array then we use that size to allocate, and make sure
537 # we allocate enough to pull the elements
538 if (!is_inline_array($e) and not is_surrounding_array($e)) {
539 if ($var_prefix =~ /^r->out/ && $length =~ /^\*r->in/) {
540 my $length2 = substr($length, 1);
541 pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) { NDR_ALLOC($ndr, $length2); }";
544 ParseArrayPullPreceding($e, $var_prefix, $ndr_flags);
547 if (is_varying_array($e)) {
548 pidl "NDR_CHECK(ndr_pull_array_length($ndr, &$var_prefix$e->{NAME}));";
549 $length = "ndr_get_array_length($ndr, &$var_prefix$e->{NAME})";
552 check_null_pointer($length);
554 if ($length ne $size) {
555 pidl "if ($length > $size) {";
556 indent;
557 pidl "return ndr_pull_error($ndr, NDR_ERR_CONFORMANT_SIZE, \"Bad conformant size %u should be %u\", $size, $length);";
558 deindent;
559 pidl "}";
562 if ((need_alloc($e) && !is_fixed_array($e)) ||
563 ($var_prefix eq "r->in." && util::has_property($e, "ref"))) {
564 if (!is_inline_array($e) || $ndr_flags eq "NDR_SCALARS") {
565 pidl "NDR_ALLOC_N($ndr, $var_prefix$e->{NAME}, $size);";
569 if (($var_prefix eq "r->out." && util::has_property($e, "ref"))) {
570 if (!is_inline_array($e) || $ndr_flags eq "NDR_SCALARS") {
571 pidl "if ($ndr->flags & LIBNDR_FLAG_REF_ALLOC) {";
572 pidl "\tNDR_ALLOC_N($ndr, $var_prefix$e->{NAME}, $size);";
573 pidl "}";
577 if (is_scalar_type($e->{TYPE})) {
578 pidl "NDR_CHECK(ndr_pull_array_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}, $length));";
579 } else {
580 pidl "NDR_CHECK(ndr_pull_array($ndr, $ndr_flags, (void **)$cprefix$var_prefix$e->{NAME}, sizeof($cprefix$var_prefix$e->{NAME}\[0]), $length, (ndr_pull_flags_fn_t)ndr_pull_$e->{TYPE}));";
584 sub ParseSubcontextPushStart($)
586 my $e = shift;
587 my $sub_size = util::has_property($e, "subcontext");
589 pidl "{";
590 indent;
591 pidl "struct ndr_push *_ndr_$e->{NAME};";
592 pidl "";
593 pidl "_ndr_$e->{NAME} = ndr_push_init_ctx(ndr);";
594 pidl "if (!_ndr_$e->{NAME}) return NT_STATUS_NO_MEMORY;";
595 pidl "_ndr_$e->{NAME}->flags = ndr->flags;";
596 pidl "";
598 return "_ndr_$e->{NAME}";
601 sub ParseSubcontextPushEnd($)
603 my $e = shift;
604 my $sub_size = util::has_property($e, "subcontext");
605 pidl "NDR_CHECK(ndr_push_subcontext_header(ndr, $sub_size, _ndr_$e->{NAME}));";
606 pidl "NDR_CHECK(ndr_push_bytes(ndr, _ndr_$e->{NAME}->data, _ndr_$e->{NAME}->offset));";
607 deindent;
608 pidl "}";
611 sub ParseSubcontextPullStart($)
613 my $e = shift;
614 my $sub_size = util::has_property($e, "subcontext");
616 pidl "{";
617 indent;
618 pidl "struct ndr_pull *_ndr_$e->{NAME};";
619 pidl "NDR_ALLOC(ndr, _ndr_$e->{NAME});";
620 pidl "NDR_CHECK(ndr_pull_subcontext_header(ndr, $sub_size, _ndr_$e->{NAME}));";
622 return "_ndr_$e->{NAME}";
625 sub ParseSubcontextPullEnd($)
627 my $e = shift;
628 my $sub_size = util::has_property($e, "subcontext");
630 my $advance;
631 if ($sub_size) {
632 $advance = "_ndr_$e->{NAME}->data_size";
633 } else {
634 $advance = "_ndr_$e->{NAME}->offset";
636 pidl "NDR_CHECK(ndr_pull_advance(ndr, $advance));";
637 deindent;
638 pidl "}";
641 #####################################################################
642 # parse scalars in a structure element
643 sub ParseElementPushScalar($$$)
645 my($e) = shift;
646 my($var_prefix) = shift;
647 my($ndr_flags) = shift;
648 my $cprefix = c_push_prefix($e);
649 my $ptr_prefix = c_ptr_prefix($e);
650 my $sub_size = util::has_property($e, "subcontext");
651 my $ndr = "ndr";
653 start_flags($e);
655 if (my $value = util::has_property($e, "value")) {
656 pidl "$cprefix$var_prefix$e->{NAME} = $value;";
659 if (defined $sub_size and $e->{POINTERS} == 0) {
660 $ndr = ParseSubcontextPushStart($e);
663 if (need_wire_pointer($e)) {
664 ParsePtrPush($e, $ptr_prefix.$var_prefix);
665 } elsif (is_inline_array($e)) {
666 ParseArrayPush($e, $ndr, "r->", "NDR_SCALARS");
667 } elsif (need_alloc($e)) {
668 # no scalar component
669 } elsif (my $switch = util::has_property($e, "switch_is")) {
670 ParseSwitchPush($e, $ndr, $var_prefix, $ndr_flags, $switch);
671 } else {
672 pidl "NDR_CHECK(ndr_push_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));";
675 if (defined $sub_size and $e->{POINTERS} == 0) {
676 ParseSubcontextPushEnd($e);
679 end_flags($e);
682 #####################################################################
683 # parse a pointer in a struct element or function
684 sub ParsePtrPush($$)
686 my $e = shift;
687 my $var_prefix = shift;
689 if (util::has_property($e, "relative")) {
690 pidl "NDR_CHECK(ndr_push_relative_ptr1(ndr, $var_prefix$e->{NAME}));";
691 } else {
692 pidl "NDR_CHECK(ndr_push_unique_ptr(ndr, $var_prefix$e->{NAME}));";
696 #####################################################################
697 # print scalars in a structure element
698 sub ParseElementPrint($$)
700 my($e) = shift;
701 my($var_prefix) = shift;
702 my $cprefix = c_push_prefix($e);
703 my $ptr_prefix = c_ptr_prefix($e);
705 return if (util::has_property($e, "noprint"));
707 if (my $value = util::has_property($e, "value")) {
708 pidl "if (ndr->flags & LIBNDR_PRINT_SET_VALUES) {";
709 pidl "\t$cprefix$var_prefix$e->{NAME} = $value;";
710 pidl "}";
713 my $l = $e->{POINTERS};
714 $l++ if (util::array_size($e) and $l == 0 and !is_fixed_array($e));
716 foreach my $i (1..$l) {
717 pidl "ndr_print_ptr(ndr, \"$e->{NAME}\", $var_prefix$e->{NAME});";
718 pidl "ndr->depth++;";
719 if ($i > $l-need_wire_pointer($e)) {
720 pidl "if ($ptr_prefix$var_prefix$e->{NAME}) {";
721 indent;
725 if (util::array_size($e)) {
726 ParseArrayPrint($e, $var_prefix)
727 } elsif (my $switch = util::has_property($e, "switch_is")) {
728 my $switch_var = ParseExpr($e, $switch, $var_prefix);
729 check_null_pointer_void($switch_var);
731 pidl "ndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $switch_var, $cprefix$var_prefix$e->{NAME});";
732 } else {
733 pidl "ndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME});";
736 foreach my $i (1..$l) {
737 if ($i > $l-need_wire_pointer($e)) {
738 deindent;
739 pidl "}";
741 pidl "ndr->depth--;";
745 #####################################################################
746 # parse scalars in a structure element - pull size
747 sub ParseSwitchPull($$$$$)
749 my($e) = shift;
750 my $ndr = shift;
751 my($var_prefix) = shift;
752 my($ndr_flags) = shift;
753 my $switch = shift;
754 my $switch_var = ParseExpr($e, $switch, $var_prefix);
756 my $cprefix = c_pull_prefix($e);
758 my $utype = typelist::getType($e->{TYPE});
760 check_null_pointer($switch_var);
762 if (!defined $utype ||
763 !util::has_property($utype, "nodiscriminant")) {
764 my $e2 = util::find_sibling($e, $switch);
765 my $type_decl = typelist::mapType($e2);
766 pidl "if (($ndr_flags) & NDR_SCALARS) {";
767 indent;
768 pidl "$type_decl _level;";
769 pidl "NDR_CHECK(ndr_pull_$e2->{TYPE}($ndr, NDR_SCALARS, &_level));";
770 if ($switch_var =~ /r->in/) {
771 pidl "if (!($ndr->flags & LIBNDR_FLAG_REF_ALLOC) && _level != $switch_var) {";
772 indent;
773 } else {
774 pidl "if (_level != $switch_var) {";
775 indent;
777 pidl "return ndr_pull_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value %u in $e->{NAME}\", _level);";
778 deindent;
779 if ($switch_var =~ /r->/) {
780 pidl "} else { $switch_var = _level; }";
781 } else {
782 pidl "}";
784 deindent;
785 pidl "}";
788 pidl "NDR_CHECK(ndr_pull_$e->{TYPE}($ndr, $ndr_flags, $switch_var, $cprefix$var_prefix$e->{NAME}));";
791 #####################################################################
792 # push switch element
793 sub ParseSwitchPush($$$$$)
795 my($e) = shift;
796 my $ndr = shift;
797 my($var_prefix) = shift;
798 my($ndr_flags) = shift;
799 my $switch = shift;
800 my $switch_var = ParseExpr($e, $switch, $var_prefix);
801 my $cprefix = c_push_prefix($e);
803 check_null_pointer($switch_var);
805 my $utype = typelist::getType($e->{TYPE});
806 if (!defined $utype ||
807 !util::has_property($utype, "nodiscriminant")) {
808 my $e2 = util::find_sibling($e, $switch);
809 pidl "if (($ndr_flags) & NDR_SCALARS) {";
810 pidl "\tNDR_CHECK(ndr_push_$e2->{TYPE}($ndr, NDR_SCALARS, $switch_var));";
811 pidl "}";
814 pidl "NDR_CHECK(ndr_push_$e->{TYPE}($ndr, $ndr_flags, $switch_var, $cprefix$var_prefix$e->{NAME}));";
817 #####################################################################
818 # parse scalars in a structure element - pull size
819 sub ParseElementPullScalar($$$)
821 my($e) = shift;
822 my($var_prefix) = shift;
823 my($ndr_flags) = shift;
824 my $cprefix = c_pull_prefix($e);
825 my $ptr_prefix = c_ptr_prefix($e);
826 my $sub_size = util::has_property($e, "subcontext");
827 my $ndr = "ndr";
829 start_flags($e);
831 if (defined $sub_size && $e->{POINTERS} == 0) {
832 $ndr = ParseSubcontextPullStart($e);
833 $ndr_flags = "NDR_SCALARS|NDR_BUFFERS";
836 if (is_inline_array($e)) {
837 ParseArrayPull($e, $ndr, "r->", "NDR_SCALARS");
838 } elsif (need_wire_pointer($e)) {
839 ParsePtrPull($e, $ptr_prefix.$var_prefix);
840 } elsif (is_surrounding_array($e)) {
841 } elsif (my $switch = util::has_property($e, "switch_is")) {
842 ParseSwitchPull($e, $ndr, $var_prefix, $ndr_flags, $switch);
843 } else {
844 pidl "NDR_CHECK(ndr_pull_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));";
847 if (my $range = util::has_property($e, "range")) {
848 my ($low, $high) = split(/ /, $range, 2);
849 pidl "if ($var_prefix$e->{NAME} < $low || $var_prefix$e->{NAME} > $high) {";
850 pidl "\treturn ndr_pull_error($ndr, NDR_ERR_RANGE, \"value out of range\");";
851 pidl "}";
854 if (defined $sub_size && $e->{POINTERS} == 0) {
855 ParseSubcontextPullEnd($e);
858 end_flags($e);
861 #####################################################################
862 # parse a pointer in a struct element or function
863 sub ParsePtrPull($$)
865 my($e) = shift;
866 my($var_prefix) = shift;
868 pidl "NDR_CHECK(ndr_pull_unique_ptr(ndr, &_ptr_$e->{NAME}));";
869 pidl "if (_ptr_$e->{NAME}) {";
870 indent;
871 pidl "NDR_ALLOC(ndr, $var_prefix$e->{NAME});";
872 if (util::has_property($e, "relative")) {
873 pidl "NDR_CHECK(ndr_pull_relative_ptr1(ndr, $var_prefix$e->{NAME}, _ptr_$e->{NAME}));";
875 deindent;
876 pidl "} else {";
877 pidl "\t$var_prefix$e->{NAME} = NULL;";
878 pidl "}";
881 #####################################################################
882 # parse buffers in a structure element
883 sub ParseElementPushBuffer($$)
885 my($e) = shift;
886 my($var_prefix) = shift;
887 my $cprefix = c_push_prefix($e);
888 my $sub_size = util::has_property($e, "subcontext");
889 my $ndr = "ndr";
891 return unless (need_buffers_section($e));
893 start_flags($e);
895 my $pointers = c_ptr_prefix($e);
896 for my $i (1..need_wire_pointer($e)) {
897 if ($i > 1) {
898 ParsePtrPush($e,$pointers.$var_prefix);
900 pidl "if ($pointers$var_prefix$e->{NAME}) {";
901 indent;
902 $pointers.="*";
905 if (util::has_property($e, "relative")) {
906 pidl "NDR_CHECK(ndr_push_relative_ptr2(ndr, $var_prefix$e->{NAME}));";
909 my $ndr_flags = "NDR_BUFFERS";
910 if ($e->{POINTERS} || (util::array_size($e) && !is_inline_array($e)))
912 $ndr_flags="NDR_SCALARS|$ndr_flags"
915 if (defined $sub_size) {
916 $ndr = ParseSubcontextPushStart($e);
917 $ndr_flags = "NDR_SCALARS|NDR_BUFFERS";
920 if (util::array_size($e)) {
921 ParseArrayPush($e, $ndr, "r->", $ndr_flags);
922 } elsif (my $switch = util::has_property($e, "switch_is")) {
923 ParseSwitchPush($e, $ndr, $var_prefix, $ndr_flags, $switch);
924 } else {
925 pidl "NDR_CHECK(ndr_push_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));";
928 if (defined $sub_size) {
929 ParseSubcontextPushEnd($e);
932 for my $i (1..need_wire_pointer($e)) {
933 deindent;
934 pidl "}";
937 end_flags($e);
940 #####################################################################
941 # parse buffers in a structure element - pull side
942 sub ParseElementPullBuffer($$)
944 my($e) = shift;
945 my($var_prefix) = shift;
946 my $cprefix = c_pull_prefix($e);
947 my $sub_size = util::has_property($e, "subcontext");
948 my $ndr = "ndr";
950 return unless (need_buffers_section($e));
952 start_flags($e);
954 my $pointers = c_ptr_prefix($e);
955 for my $i (1..need_wire_pointer($e)) {
956 if ($i > 1) {
957 ParsePtrPull($e,$pointers.$var_prefix);
959 pidl "if ($pointers$var_prefix$e->{NAME}) {";
960 indent;
961 $pointers.="*";
964 if (util::has_property($e, "relative")) {
965 pidl "struct ndr_pull_save _relative_save;";
966 pidl "ndr_pull_save(ndr, &_relative_save);";
967 pidl "NDR_CHECK(ndr_pull_relative_ptr2(ndr, $var_prefix$e->{NAME}));";
970 my $ndr_flags = "NDR_BUFFERS";
971 if ($e->{POINTERS} || (util::array_size($e) && !is_inline_array($e)))
973 $ndr_flags="NDR_SCALARS|$ndr_flags"
976 if (defined $sub_size) {
977 $ndr = ParseSubcontextPullStart($e);
978 $ndr_flags = "NDR_SCALARS|NDR_BUFFERS";
981 if (util::array_size($e)) {
982 ParseArrayPull($e, $ndr, "r->", $ndr_flags);
983 } elsif (my $switch = util::has_property($e, "switch_is")) {
984 ParseSwitchPull($e, $ndr, $var_prefix, $ndr_flags, $switch);
985 } else {
986 pidl "NDR_CHECK(ndr_pull_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));";
989 if (defined $sub_size) {
990 ParseSubcontextPullEnd($e);
993 if (util::has_property($e, "relative")) {
994 pidl "ndr_pull_restore(ndr, &_relative_save);";
997 for my $i (1..need_wire_pointer($e)) {
998 deindent;
999 pidl "}";
1002 end_flags($e);
1005 #####################################################################
1006 # parse a struct
1007 sub ParseStructPush($)
1009 my($struct) = shift;
1011 return unless defined($struct->{ELEMENTS});
1013 start_flags($struct);
1015 # see if the structure contains a conformant array. If it
1016 # does, then it must be the last element of the structure, and
1017 # we need to push the conformant length early, as it fits on
1018 # the wire before the structure (and even before the structure
1019 # alignment)
1020 my $e = $struct->{ELEMENTS}[-1];
1021 if (is_conformant_array($e) and is_surrounding_array($e)) {
1022 ParseArrayPushPreceding($e, "r->", "NDR_SCALARS");
1025 if (defined $e->{TYPE} && $e->{TYPE} eq "string"
1026 && util::property_matches($e, "flag", ".*LIBNDR_FLAG_STR_CONFORMANT.*")) {
1027 pidl "NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_string_array_size(ndr, r->$e->{NAME})));";
1030 pidl "if (!(ndr_flags & NDR_SCALARS)) goto buffers;";
1032 pidl "NDR_CHECK(ndr_push_struct_start(ndr));";
1034 my $align = find_largest_alignment($struct);
1035 pidl "NDR_CHECK(ndr_push_align(ndr, $align));";
1037 foreach my $e (@{$struct->{ELEMENTS}}) {
1038 ParseElementPushScalar($e, "r->", "NDR_SCALARS");
1041 pidl "buffers:";
1042 pidl "if (!(ndr_flags & NDR_BUFFERS)) goto done;";
1043 foreach my $e (@{$struct->{ELEMENTS}}) {
1044 ParseElementPushBuffer($e, "r->");
1047 pidl "ndr_push_struct_end(ndr);";
1049 pidl "done:";
1051 end_flags($struct);
1054 #####################################################################
1055 # generate a push function for an enum
1056 sub ParseEnumPush($)
1058 my($enum) = shift;
1059 my($type_fn) = typelist::enum_type_fn($enum);
1061 start_flags($enum);
1063 pidl "NDR_CHECK(ndr_push_$type_fn(ndr, NDR_SCALARS, r));";
1065 end_flags($enum);
1068 #####################################################################
1069 # generate a pull function for an enum
1070 sub ParseEnumPull($)
1072 my($enum) = shift;
1073 my($type_fn) = typelist::enum_type_fn($enum);
1074 my($type_v_decl) = typelist::mapScalarType(typelist::enum_type_fn($enum));
1076 pidl "$type_v_decl v;";
1077 start_flags($enum);
1078 pidl "NDR_CHECK(ndr_pull_$type_fn(ndr, NDR_SCALARS, &v));";
1079 pidl "*r = v;";
1081 end_flags($enum);
1084 #####################################################################
1085 # generate a print function for an enum
1086 sub ParseEnumPrint($)
1088 my($enum) = shift;
1090 pidl "const char *val = NULL;";
1091 pidl "";
1093 start_flags($enum);
1095 pidl "switch (r) {";
1096 indent;
1097 my $els = \@{$enum->{ELEMENTS}};
1098 foreach my $i (0 .. $#{$els}) {
1099 my $e = ${$els}[$i];
1100 chomp $e;
1101 if ($e =~ /^(.*)=/) {
1102 $e = $1;
1104 pidl "case $e: val = \"$e\"; break;";
1107 deindent;
1108 pidl "}";
1110 pidl "ndr_print_enum(ndr, name, \"$enum->{TYPE}\", val, r);";
1112 end_flags($enum);
1115 sub ArgsEnumPush($)
1117 my $e = shift;
1118 return "struct ndr_push *ndr, int ndr_flags, enum $e->{NAME} r";
1121 sub ArgsEnumPrint($)
1123 my $e = shift;
1124 return "struct ndr_print *ndr, const char *name, enum $e->{NAME} r";
1127 sub ArgsEnumPull($)
1129 my $e = shift;
1130 return "struct ndr_pull *ndr, int ndr_flags, enum $e->{NAME} *r";
1133 $typefamily{ENUM} = {
1134 PUSH_FN_BODY => \&ParseEnumPush,
1135 PUSH_FN_ARGS => \&ArgsEnumPush,
1136 PULL_FN_BODY => \&ParseEnumPull,
1137 PULL_FN_ARGS => \&ArgsEnumPull,
1138 PRINT_FN_BODY => \&ParseEnumPrint,
1139 PRINT_FN_ARGS => \&ArgsEnumPrint,
1140 ALIGN => sub { return align_type(typelist::enum_type_fn(shift)); }
1143 #####################################################################
1144 # generate a push function for a bitmap
1145 sub ParseBitmapPush($)
1147 my($bitmap) = shift;
1148 my($type_fn) = typelist::bitmap_type_fn($bitmap);
1150 start_flags($bitmap);
1152 pidl "NDR_CHECK(ndr_push_$type_fn(ndr, NDR_SCALARS, r));";
1154 end_flags($bitmap);
1157 #####################################################################
1158 # generate a pull function for an bitmap
1159 sub ParseBitmapPull($)
1161 my($bitmap) = shift;
1162 my($type_fn) = typelist::bitmap_type_fn($bitmap);
1163 my($type_decl) = typelist::mapType($bitmap);
1165 pidl "$type_decl v;";
1166 start_flags($bitmap);
1167 pidl "NDR_CHECK(ndr_pull_$type_fn(ndr, NDR_SCALARS, &v));";
1168 pidl "*r = v;";
1170 end_flags($bitmap);
1173 #####################################################################
1174 # generate a print function for an bitmap
1175 sub ParseBitmapPrintElement($$)
1177 my($e) = shift;
1178 my($bitmap) = shift;
1179 my($type_decl) = typelist::mapType($bitmap);
1180 my($type_fn) = typelist::bitmap_type_fn($bitmap);
1181 my($name) = $bitmap->{PARENT}->{NAME};
1182 my($flag);
1184 if ($e =~ /^(\w+) .*$/) {
1185 $flag = "$1";
1186 } else {
1187 die "Bitmap: \"$name\" invalid Flag: \"$e\"";
1190 pidl "ndr_print_bitmap_flag(ndr, sizeof($type_decl), \"$flag\", $flag, r);";
1193 #####################################################################
1194 # generate a print function for an bitmap
1195 sub ParseBitmapPrint($)
1197 my($bitmap) = shift;
1198 my($type_decl) = typelist::mapType($bitmap);
1199 my($type_fn) = typelist::bitmap_type_fn($bitmap);
1201 start_flags($bitmap);
1203 pidl "ndr_print_$type_fn(ndr, name, r);";
1205 pidl "ndr->depth++;";
1206 foreach my $e (@{$bitmap->{ELEMENTS}}) {
1207 ParseBitmapPrintElement($e, $bitmap);
1209 pidl "ndr->depth--;";
1211 end_flags($bitmap);
1214 sub ArgsBitmapPush($)
1216 my $e = shift;
1217 my $type_decl = typelist::mapType($e->{DATA});
1218 return "struct ndr_push *ndr, int ndr_flags, $type_decl r";
1221 sub ArgsBitmapPrint($)
1223 my $e = shift;
1224 my $type_decl = typelist::mapType($e->{DATA});
1225 return "struct ndr_print *ndr, const char *name, $type_decl r";
1228 sub ArgsBitmapPull($)
1230 my $e = shift;
1231 my $type_decl = typelist::mapType($e->{DATA});
1232 return "struct ndr_pull *ndr, int ndr_flags, $type_decl *r";
1235 $typefamily{BITMAP} = {
1236 PUSH_FN_BODY => \&ParseBitmapPush,
1237 PUSH_FN_ARGS => \&ArgsBitmapPush,
1238 PULL_FN_BODY => \&ParseBitmapPull,
1239 PULL_FN_ARGS => \&ArgsBitmapPull,
1240 PRINT_FN_BODY => \&ParseBitmapPrint,
1241 PRINT_FN_ARGS => \&ArgsBitmapPrint,
1242 ALIGN => sub { return align_type(typelist::bitmap_type_fn(shift)); }
1245 #####################################################################
1246 # generate a struct print function
1247 sub ParseStructPrint($)
1249 my($struct) = shift;
1250 my($name) = $struct->{PARENT}->{NAME};
1252 return unless defined $struct->{ELEMENTS};
1254 pidl "ndr_print_struct(ndr, name, \"$name\");";
1256 start_flags($struct);
1258 pidl "ndr->depth++;";
1259 foreach my $e (@{$struct->{ELEMENTS}}) {
1260 ParseElementPrint($e, "r->");
1262 pidl "ndr->depth--;";
1264 end_flags($struct);
1267 #####################################################################
1268 # parse a struct - pull side
1269 sub ParseStructPull($)
1271 my($struct) = shift;
1272 my $conform_e;
1274 return unless defined $struct->{ELEMENTS};
1276 # see if the structure contains a conformant array. If it
1277 # does, then it must be the last element of the structure, and
1278 # we need to pull the conformant length early, as it fits on
1279 # the wire before the structure (and even before the structure
1280 # alignment)
1281 my $e = $struct->{ELEMENTS}[-1];
1282 if (is_conformant_array($e) and is_surrounding_array($e)) {
1283 $conform_e = $e;
1286 if (defined $e->{TYPE} && $e->{TYPE} eq "string"
1287 && util::property_matches($e, "flag", ".*LIBNDR_FLAG_STR_CONFORMANT.*")) {
1288 $conform_e = $e;
1291 # declare any internal pointers we need
1292 foreach my $e (@{$struct->{ELEMENTS}}) {
1293 if (need_wire_pointer($e)) {
1294 pidl "uint32_t _ptr_$e->{NAME};";
1298 start_flags($struct);
1300 pidl "if (!(ndr_flags & NDR_SCALARS)) goto buffers;";
1302 pidl "NDR_CHECK(ndr_pull_struct_start(ndr));";
1304 if (defined $conform_e) {
1305 ParseArrayPullPreceding($conform_e, "r->", "NDR_SCALARS");
1308 my $align = find_largest_alignment($struct);
1309 pidl "NDR_CHECK(ndr_pull_align(ndr, $align));";
1311 foreach my $e (@{$struct->{ELEMENTS}}) {
1312 ParseElementPullScalar($e, "r->", "NDR_SCALARS");
1315 pidl "buffers:\n";
1316 pidl "if (!(ndr_flags & NDR_BUFFERS)) goto done;";
1317 foreach my $e (@{$struct->{ELEMENTS}}) {
1318 ParseElementPullBuffer($e, "r->");
1321 foreach my $e (@{$struct->{ELEMENTS}}) {
1322 CheckArraySizes($e, "r->");
1325 pidl "ndr_pull_struct_end(ndr);";
1327 pidl "done:";
1329 end_flags($struct);
1332 #####################################################################
1333 # calculate size of ndr struct
1334 sub ParseStructNdrSize($)
1336 my $t = shift;
1337 my $static = fn_prefix($t);
1338 my $sizevar;
1340 if (my $flags = util::has_property($t, "flag")) {
1341 pidl "flags |= $flags;";
1343 pidl "return ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_$t->{NAME});";
1346 sub ArgsStructPush($)
1348 my $e = shift;
1349 return "struct ndr_push *ndr, int ndr_flags, struct $e->{NAME} *r";
1352 sub ArgsStructPrint($)
1354 my $e = shift;
1355 return "struct ndr_print *ndr, const char *name, struct $e->{NAME} *r";
1358 sub ArgsStructPull($)
1360 my $e = shift;
1361 return "struct ndr_pull *ndr, int ndr_flags, struct $e->{NAME} *r";
1364 sub ArgsStructNdrSize($)
1366 my $d = shift;
1367 return "const struct $d->{NAME} *r, int flags";
1370 $typefamily{STRUCT} = {
1371 PUSH_FN_BODY => \&ParseStructPush,
1372 PUSH_FN_ARGS => \&ArgsStructPush,
1373 PULL_FN_BODY => \&ParseStructPull,
1374 PULL_FN_ARGS => \&ArgsStructPull,
1375 PRINT_FN_BODY => \&ParseStructPrint,
1376 PRINT_FN_ARGS => \&ArgsStructPrint,
1377 SIZE_FN_BODY => \&ParseStructNdrSize,
1378 SIZE_FN_ARGS => \&ArgsStructNdrSize,
1379 ALIGN => \&find_largest_alignment
1382 #####################################################################
1383 # calculate size of ndr struct
1384 sub ParseUnionNdrSize($)
1386 my $t = shift;
1387 my $static = fn_prefix($t);
1388 my $sizevar;
1390 if (my $flags = util::has_property($t, "flag")) {
1391 pidl "flags |= $flags;";
1393 pidl "return ndr_size_union(r, flags, level, (ndr_push_union_fn_t)ndr_push_$t->{NAME});";
1396 #####################################################################
1397 # parse a union - push side
1398 sub ParseUnionPush($)
1400 my $e = shift;
1401 my $have_default = 0;
1403 start_flags($e);
1405 pidl "if (!(ndr_flags & NDR_SCALARS)) goto buffers;";
1407 pidl "NDR_CHECK(ndr_push_struct_start(ndr));";
1409 # my $align = union_alignment($e);
1410 # pidl "NDR_CHECK(ndr_push_align(ndr, $align));";
1412 pidl "switch (level) {";
1413 indent;
1414 foreach my $el (@{$e->{ELEMENTS}}) {
1415 if (util::has_property($el, "default")) {
1416 pidl "default:";
1417 $have_default = 1;
1418 } else {
1419 pidl "case $el->{PROPERTIES}->{case}:";
1422 if ($el->{TYPE} ne "EMPTY") {
1423 indent;
1424 ParseElementPushScalar($el, "r->", "NDR_SCALARS");
1425 deindent;
1427 pidl "break;";
1428 pidl "";
1430 if (! $have_default) {
1431 pidl "default:";
1432 pidl "\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1434 deindent;
1435 pidl "}";
1436 pidl "buffers:";
1437 pidl "if (!(ndr_flags & NDR_BUFFERS)) goto done;";
1438 pidl "switch (level) {";
1439 indent;
1440 foreach my $el (@{$e->{ELEMENTS}}) {
1441 if (util::has_property($el, "default")) {
1442 pidl "default:";
1443 } else {
1444 pidl "case $el->{PROPERTIES}->{case}:";
1446 if ($el->{TYPE} ne "EMPTY") {
1447 indent;
1448 ParseElementPushBuffer($el, "r->");
1449 deindent;
1451 pidl "break;";
1452 pidl "";
1454 if (! $have_default) {
1455 pidl "default:";
1456 pidl "\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1458 deindent;
1459 pidl "}";
1460 pidl "ndr_push_struct_end(ndr);";
1461 pidl "done:";
1462 end_flags($e);
1465 #####################################################################
1466 # print a union
1467 sub ParseUnionPrint($)
1469 my $e = shift;
1470 my $have_default = 0;
1471 my($name) = $e->{PARENT}->{NAME};
1473 pidl "ndr_print_union(ndr, name, level, \"$name\");";
1474 start_flags($e);
1476 pidl "switch (level) {";
1477 indent;
1478 foreach my $el (@{$e->{ELEMENTS}}) {
1479 if (util::has_property($el, "default")) {
1480 $have_default = 1;
1481 pidl "default:";
1482 } else {
1483 pidl "case $el->{PROPERTIES}->{case}:";
1485 if ($el->{TYPE} ne "EMPTY") {
1486 indent;
1487 ParseElementPrint($el, "r->");
1488 deindent;
1490 pidl "break;";
1491 pidl "";
1493 if (! $have_default) {
1494 pidl "default:";
1495 pidl "\tndr_print_bad_level(ndr, name, level);";
1497 deindent;
1498 pidl "}";
1500 end_flags($e);
1503 #####################################################################
1504 # parse a union - pull side
1505 sub ParseUnionPull($)
1507 my $e = shift;
1508 my $have_default = 0;
1510 start_flags($e);
1512 pidl "if (!(ndr_flags & NDR_SCALARS)) goto buffers;";
1514 pidl "NDR_CHECK(ndr_pull_struct_start(ndr));";
1516 # my $align = union_alignment($e);
1517 # pidl "\tNDR_CHECK(ndr_pull_align(ndr, $align));\n";
1519 pidl "switch (level) {";
1520 indent;
1521 foreach my $el (@{$e->{ELEMENTS}}) {
1522 if (util::has_property($el, "default")) {
1523 pidl "default: {";
1524 $have_default = 1;
1525 } else {
1526 pidl "case $el->{PROPERTIES}->{case}: {";
1528 if ($el->{TYPE} ne "EMPTY") {
1529 indent;
1530 if ($el->{POINTERS}) {
1531 pidl "uint32_t _ptr_$el->{NAME};";
1533 ParseElementPullScalar($el, "r->", "NDR_SCALARS");
1534 deindent;
1536 pidl "break; }";
1537 pidl "";
1539 if (! $have_default) {
1540 pidl "default:";
1541 pidl "\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1543 deindent;
1544 pidl "}";
1545 pidl "buffers:";
1546 pidl "if (!(ndr_flags & NDR_BUFFERS)) goto done;";
1547 pidl "switch (level) {";
1548 indent;
1549 foreach my $el (@{$e->{ELEMENTS}}) {
1550 if (util::has_property($el, "default")) {
1551 pidl "default:";
1552 } else {
1553 pidl "case $el->{PROPERTIES}->{case}:";
1555 if ($el->{TYPE} ne "EMPTY") {
1556 indent;
1557 ParseElementPullBuffer($el, "r->");
1558 deindent;
1560 pidl "break;";
1561 pidl "";
1563 if (! $have_default) {
1564 pidl "default:";
1565 pidl "\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1567 deindent;
1568 pidl "}";
1569 pidl "ndr_pull_struct_end(ndr);";
1570 pidl "done:";
1571 end_flags($e);
1574 sub ArgsUnionPush($)
1576 my $e = shift;
1577 return "struct ndr_push *ndr, int ndr_flags, int level, union $e->{NAME} *r";
1580 sub ArgsUnionPrint($)
1582 my $e = shift;
1583 return "struct ndr_print *ndr, const char *name, int level, union $e->{NAME} *r";
1586 sub ArgsUnionPull($)
1588 my $e = shift;
1589 return "struct ndr_pull *ndr, int ndr_flags, int level, union $e->{NAME} *r";
1592 sub ArgsUnionNdrSize($)
1594 my $d = shift;
1595 return "const union $d->{NAME} *r, uint32_t level, int flags";
1598 $typefamily{UNION} = {
1599 PUSH_FN_BODY => \&ParseUnionPush,
1600 PUSH_FN_ARGS => \&ArgsUnionPush,
1601 PULL_FN_BODY => \&ParseUnionPull,
1602 PULL_FN_ARGS => \&ArgsUnionPull,
1603 PRINT_FN_BODY => \&ParseUnionPrint,
1604 PRINT_FN_ARGS => \&ArgsUnionPrint,
1605 SIZE_FN_ARGS => \&ArgsUnionNdrSize,
1606 SIZE_FN_BODY => \&ParseUnionNdrSize,
1607 ALIGN => \&find_largest_alignment
1610 #####################################################################
1611 # parse a typedef - push side
1612 sub ParseTypedefPush($)
1614 my($e) = shift;
1615 my $static = fn_prefix($e);
1617 return unless needed::is_needed("push_$e->{NAME}");
1619 my $args = $typefamily{$e->{DATA}->{TYPE}}->{PUSH_FN_ARGS}->($e);
1620 pidl $static . "NTSTATUS ndr_push_$e->{NAME}($args)";
1622 pidl "{";
1623 indent;
1624 $typefamily{$e->{DATA}->{TYPE}}->{PUSH_FN_BODY}->($e->{DATA});
1625 pidl "return NT_STATUS_OK;";
1626 deindent;
1627 pidl "}";
1628 pidl "";;
1632 #####################################################################
1633 # parse a typedef - pull side
1634 sub ParseTypedefPull($)
1636 my($e) = shift;
1637 my $static = fn_prefix($e);
1639 return unless needed::is_needed("pull_$e->{NAME}");
1641 my $args = $typefamily{$e->{DATA}->{TYPE}}->{PULL_FN_ARGS}->($e);
1643 pidl $static . "NTSTATUS ndr_pull_$e->{NAME}($args)";
1645 pidl "{";
1646 indent;
1647 $typefamily{$e->{DATA}->{TYPE}}->{PULL_FN_BODY}->($e->{DATA});
1648 pidl "return NT_STATUS_OK;";
1649 deindent;
1650 pidl "}";
1651 pidl "";
1654 #####################################################################
1655 # parse a typedef - print side
1656 sub ParseTypedefPrint($)
1658 my($e) = shift;
1660 my $args = $typefamily{$e->{DATA}->{TYPE}}->{PRINT_FN_ARGS}->($e);
1662 return unless !util::has_property($e, "noprint");
1664 pidl "void ndr_print_$e->{NAME}($args)";
1665 pidl "{";
1666 indent;
1667 $typefamily{$e->{DATA}->{TYPE}}->{PRINT_FN_BODY}->($e->{DATA});
1668 deindent;
1669 pidl "}";
1672 #####################################################################
1673 ## calculate the size of a structure
1674 sub ParseTypedefNdrSize($)
1676 my($t) = shift;
1678 return unless needed::is_needed("ndr_size_$t->{NAME}");
1680 my $tf = $typefamily{$t->{DATA}->{TYPE}};
1681 my $args = $tf->{SIZE_FN_ARGS}->($t);
1683 pidl "size_t ndr_size_$t->{NAME}($args)";
1684 pidl "{";
1685 indent;
1686 $typefamily{$t->{DATA}->{TYPE}}->{SIZE_FN_BODY}->($t);
1687 deindent;
1688 pidl "}";
1689 pidl "";
1692 #####################################################################
1693 # parse a function - print side
1694 sub ParseFunctionPrint($)
1696 my($fn) = shift;
1698 return unless !util::has_property($fn, "noprint");
1700 pidl "void ndr_print_$fn->{NAME}(struct ndr_print *ndr, const char *name, int flags, struct $fn->{NAME} *r)";
1701 pidl "{";
1702 indent;
1703 pidl "ndr_print_struct(ndr, name, \"$fn->{NAME}\");";
1704 pidl "ndr->depth++;";
1706 pidl "if (flags & NDR_SET_VALUES) {";
1707 pidl "\tndr->flags |= LIBNDR_PRINT_SET_VALUES;";
1708 pidl "}";
1710 pidl "if (flags & NDR_IN) {";
1711 indent;
1712 pidl "ndr_print_struct(ndr, \"in\", \"$fn->{NAME}\");";
1713 pidl "ndr->depth++;";
1715 foreach my $e (@{$fn->{ELEMENTS}}) {
1716 if (util::has_property($e, "in")) {
1717 ParseElementPrint($e, "r->in.");
1720 pidl "ndr->depth--;";
1721 deindent;
1722 pidl "}";
1724 pidl "if (flags & NDR_OUT) {";
1725 indent;
1726 pidl "ndr_print_struct(ndr, \"out\", \"$fn->{NAME}\");";
1727 pidl "ndr->depth++;";
1728 foreach my $e (@{$fn->{ELEMENTS}}) {
1729 if (util::has_property($e, "out")) {
1730 ParseElementPrint($e, "r->out.");
1733 if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
1734 my $cprefix = "&";
1735 $cprefix = "" if (is_scalar_type($fn->{RETURN_TYPE})) ; # FIXME: Should really use util::c_push_prefix here
1736 pidl "ndr_print_$fn->{RETURN_TYPE}(ndr, \"result\", $cprefix"."r->out.result);";
1738 pidl "ndr->depth--;";
1739 deindent;
1740 pidl "}";
1742 pidl "ndr->depth--;";
1743 deindent;
1744 pidl "}";
1745 pidl "";
1748 #####################################################################
1749 # parse a function element
1750 sub ParseFunctionElementPush($$)
1752 my $e = shift;
1753 my $inout = shift;
1755 if (util::array_size($e)) {
1756 if (need_wire_pointer($e)) {
1757 pidl "NDR_CHECK(ndr_push_unique_ptr(ndr, r->$inout.$e->{NAME}));";
1758 pidl "if (r->$inout.$e->{NAME}) {";
1759 indent;
1760 ParseArrayPush($e, "ndr", "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1761 deindent;
1762 pidl "}";
1763 } else {
1764 ParseArrayPush($e, "ndr", "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1766 } else {
1767 ParseElementPushScalar($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1768 if (need_wire_pointer($e)) {
1769 ParseElementPushBuffer($e, "r->$inout.");
1774 #####################################################################
1775 # parse a function
1776 sub ParseFunctionPush($)
1778 my($fn) = shift;
1779 my $static = fn_prefix($fn);
1781 return unless !util::has_property($fn, "nopush");
1783 pidl $static . "NTSTATUS ndr_push_$fn->{NAME}(struct ndr_push *ndr, int flags, struct $fn->{NAME} *r)";
1784 pidl "{";
1785 indent;
1787 pidl "if (!(flags & NDR_IN)) goto ndr_out;";
1788 pidl "";
1790 foreach my $e (@{$fn->{ELEMENTS}}) {
1791 if (util::has_property($e, "in")) {
1792 ParseFunctionElementPush($e, "in");
1796 pidl "ndr_out:";
1797 pidl "if (!(flags & NDR_OUT)) goto done;";
1798 pidl "";
1800 foreach my $e (@{$fn->{ELEMENTS}}) {
1801 if (util::has_property($e, "out")) {
1802 ParseFunctionElementPush($e, "out");
1806 if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
1807 pidl "NDR_CHECK(ndr_push_$fn->{RETURN_TYPE}(ndr, NDR_SCALARS, r->out.result));";
1810 pidl "done:";
1811 pidl "return NT_STATUS_OK;";
1812 deindent;
1813 pidl "}";
1814 pidl "";
1817 #####################################################################
1818 # parse a function element
1819 sub ParseFunctionElementPull($$)
1821 my $e = shift;
1822 my $inout = shift;
1824 if (util::array_size($e)) {
1825 if (need_wire_pointer($e)) {
1826 pidl "NDR_CHECK(ndr_pull_unique_ptr(ndr, &_ptr_$e->{NAME}));";
1827 pidl "r->$inout.$e->{NAME} = NULL;";
1828 pidl "if (_ptr_$e->{NAME}) {";
1829 indent;
1830 } elsif ($inout eq "out" && util::has_property($e, "ref")) {
1831 pidl "if (r->$inout.$e->{NAME}) {";
1832 indent;
1835 ParseArrayPull($e, "ndr", "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1837 if (need_wire_pointer($e) or ($inout eq "out" and util::has_property($e, "ref"))) {
1838 deindent;
1839 pidl "}";
1841 } else {
1842 if ($inout eq "out" && util::has_property($e, "ref")) {
1843 pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {";
1844 pidl "\tNDR_ALLOC(ndr, r->out.$e->{NAME});";
1845 pidl "}";
1848 if ($inout eq "in" && util::has_property($e, "ref")) {
1849 pidl "NDR_ALLOC(ndr, r->in.$e->{NAME});";
1852 ParseElementPullScalar($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1853 if (need_wire_pointer($e)) {
1854 ParseElementPullBuffer($e, "r->$inout.");
1859 ############################################################
1860 # allocate ref variables
1861 sub AllocateRefVars($)
1863 my $e = shift;
1864 my $asize = util::array_size($e);
1866 # note that if the variable is also an "in"
1867 # variable then we copy the initial value from
1868 # the in side
1870 if (!defined $asize) {
1871 # its a simple variable
1872 pidl "NDR_ALLOC(ndr, r->out.$e->{NAME});";
1873 if (util::has_property($e, "in")) {
1874 pidl "*r->out.$e->{NAME} = *r->in.$e->{NAME};";
1875 } else {
1876 pidl "ZERO_STRUCTP(r->out.$e->{NAME});";
1878 return;
1881 # its an array
1882 my $size = ParseExpr($e, $asize, "r->out.");
1883 check_null_pointer($size);
1884 pidl "NDR_ALLOC_N(ndr, r->out.$e->{NAME}, $size);";
1885 if (util::has_property($e, "in")) {
1886 pidl "memcpy(r->out.$e->{NAME},r->in.$e->{NAME},$size * sizeof(*r->in.$e->{NAME}));";
1887 } else {
1888 pidl "memset(r->out.$e->{NAME}, 0, $size * sizeof(*r->out.$e->{NAME}));";
1892 #####################################################################
1893 # parse a function
1894 sub ParseFunctionPull($)
1896 my($fn) = shift;
1897 my $static = fn_prefix($fn);
1899 return unless !util::has_property($fn, "nopull");
1901 # pull function args
1902 pidl $static . "NTSTATUS ndr_pull_$fn->{NAME}(struct ndr_pull *ndr, int flags, struct $fn->{NAME} *r)";
1903 pidl "{";
1904 indent;
1906 # declare any internal pointers we need
1907 foreach my $e (@{$fn->{ELEMENTS}}) {
1908 if (need_wire_pointer($e)) {
1909 pidl "uint32_t _ptr_$e->{NAME};";
1913 pidl "if (!(flags & NDR_IN)) goto ndr_out;";
1914 pidl "";
1916 # auto-init the out section of a structure. I originally argued that
1917 # this was a bad idea as it hides bugs, but coping correctly
1918 # with initialisation and not wiping ref vars is turning
1919 # out to be too tricky (tridge)
1920 foreach my $e (@{$fn->{ELEMENTS}}) {
1921 if (util::has_property($e, "out")) {
1922 pidl "ZERO_STRUCT(r->out);";
1923 pidl "";
1924 last;
1928 foreach my $e (@{$fn->{ELEMENTS}}) {
1929 if (util::has_property($e, "in")) {
1930 ParseFunctionElementPull($e, "in");
1932 # we need to allocate any reference output variables, so that
1933 # a dcerpc backend can be sure they are non-null
1934 if (util::has_property($e, "out") && util::has_property($e, "ref")) {
1935 AllocateRefVars($e);
1939 foreach my $e (@{$fn->{ELEMENTS}}) {
1940 if (util::has_property($e, "in")) {
1941 CheckArraySizes($e, "r->in.");
1945 pidl "ndr_out:";
1946 pidl "if (!(flags & NDR_OUT)) goto done;";
1947 pidl "";
1949 foreach my $e (@{$fn->{ELEMENTS}}) {
1950 if (util::has_property($e, "out")) {
1951 ParseFunctionElementPull($e, "out");
1955 foreach my $e (@{$fn->{ELEMENTS}}) {
1956 if (util::has_property($e, "out")) {
1957 CheckArraySizes($e, "r->out.");
1961 if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
1962 pidl "NDR_CHECK(ndr_pull_$fn->{RETURN_TYPE}(ndr, NDR_SCALARS, &r->out.result));";
1965 pidl "done:";
1966 pidl "";
1967 pidl "return NT_STATUS_OK;";
1968 deindent;
1969 pidl "}";
1970 pidl "";
1973 #####################################################################
1974 # produce a function call table
1975 sub FunctionTable($)
1977 my($interface) = shift;
1978 my($data) = $interface->{INHERITED_DATA};
1979 my $count = 0;
1980 my $uname = uc $interface->{NAME};
1982 foreach my $d (@{$data}) {
1983 if ($d->{TYPE} eq "FUNCTION") { $count++; }
1986 return if ($count == 0);
1988 pidl "static const struct dcerpc_interface_call $interface->{NAME}\_calls[] = {";
1989 foreach my $d (@{$data}) {
1990 if ($d->{TYPE} eq "FUNCTION") {
1991 pidl "\t{";
1992 pidl "\t\t\"$d->{NAME}\",";
1993 pidl "\t\tsizeof(struct $d->{NAME}),";
1994 pidl "\t\t(ndr_push_flags_fn_t) ndr_push_$d->{NAME},";
1995 pidl "\t\t(ndr_pull_flags_fn_t) ndr_pull_$d->{NAME},";
1996 pidl "\t\t(ndr_print_function_t) ndr_print_$d->{NAME}";
1997 pidl "\t},";
2000 pidl "\t{ NULL, 0, NULL, NULL, NULL }";
2001 pidl "};";
2002 pidl "";
2004 # If no endpoint is set, default to the interface name as a named pipe
2005 if (! defined $interface->{PROPERTIES}->{endpoint}) {
2006 $interface->{PROPERTIES}->{endpoint} = "\"ncacn_np:[\\\\pipe\\\\" . $interface->{NAME} . "]\"";
2009 my @e = split / /, $interface->{PROPERTIES}->{endpoint};
2010 my $endpoint_count = $#e + 1;
2012 pidl "static const char * const $interface->{NAME}\_endpoint_strings[] = {";
2013 foreach my $ep (@e) {
2014 pidl "\t$ep, ";
2016 pidl "};";
2017 pidl "";
2019 pidl "static const struct dcerpc_endpoint_list $interface->{NAME}\_endpoints = {";
2020 pidl "\t.count\t= $endpoint_count,";
2021 pidl "\t.names\t= $interface->{NAME}\_endpoint_strings";
2022 pidl "};";
2023 pidl "";
2025 if (! defined $interface->{PROPERTIES}->{authservice}) {
2026 $interface->{PROPERTIES}->{authservice} = "\"host\"";
2029 my @a = split / /, $interface->{PROPERTIES}->{authservice};
2030 my $authservice_count = $#a + 1;
2032 pidl "static const char * const $interface->{NAME}\_authservice_strings[] = {";
2033 foreach my $ap (@a) {
2034 pidl "\t$ap, ";
2036 pidl "};";
2037 pidl "";
2039 pidl "static const struct dcerpc_authservice_list $interface->{NAME}\_authservices = {";
2040 pidl "\t.count\t= $endpoint_count,";
2041 pidl "\t.names\t= $interface->{NAME}\_authservice_strings";
2042 pidl "};";
2043 pidl "";
2045 pidl "\nconst struct dcerpc_interface_table dcerpc_table_$interface->{NAME} = {";
2046 pidl "\t.name\t\t= \"$interface->{NAME}\",";
2047 pidl "\t.uuid\t\t= DCERPC_$uname\_UUID,";
2048 pidl "\t.if_version\t= DCERPC_$uname\_VERSION,";
2049 pidl "\t.helpstring\t= DCERPC_$uname\_HELPSTRING,";
2050 pidl "\t.num_calls\t= $count,";
2051 pidl "\t.calls\t\t= $interface->{NAME}\_calls,";
2052 pidl "\t.endpoints\t= &$interface->{NAME}\_endpoints,";
2053 pidl "\t.authservices\t= &$interface->{NAME}\_authservices";
2054 pidl "};";
2055 pidl "";
2057 pidl "static NTSTATUS dcerpc_ndr_$interface->{NAME}_init(void)";
2058 pidl "{";
2059 pidl "\treturn librpc_register_interface(&dcerpc_table_$interface->{NAME});";
2060 pidl "}";
2061 pidl "";
2064 #####################################################################
2065 # parse the interface definitions
2066 sub ParseInterface($)
2068 my($interface) = shift;
2069 my($data) = $interface->{DATA};
2071 # Push functions
2072 foreach my $d (@{$data}) {
2073 ($d->{TYPE} eq "TYPEDEF") &&
2074 ParseTypedefPush($d);
2075 ($d->{TYPE} eq "FUNCTION") &&
2076 ParseFunctionPush($d);
2079 # Pull functions
2080 foreach my $d (@{$data}) {
2081 ($d->{TYPE} eq "TYPEDEF") &&
2082 ParseTypedefPull($d);
2083 ($d->{TYPE} eq "FUNCTION") &&
2084 ParseFunctionPull($d);
2087 # Print functions
2088 foreach my $d (@{$data}) {
2089 ($d->{TYPE} eq "TYPEDEF") &&
2090 ParseTypedefPrint($d);
2091 ($d->{TYPE} eq "FUNCTION") &&
2092 ParseFunctionPrint($d);
2095 # Size functions
2096 foreach my $d (@{$data}) {
2097 ($d->{TYPE} eq "TYPEDEF") &&
2098 ParseTypedefNdrSize($d);
2101 FunctionTable($interface);
2104 sub RegistrationFunction($$)
2106 my $idl = shift;
2107 my $filename = shift;
2109 $filename =~ /.*\/ndr_(.*).c/;
2110 my $basename = $1;
2111 pidl "NTSTATUS dcerpc_$basename\_init(void)";
2112 pidl "{";
2113 indent;
2114 pidl "NTSTATUS status = NT_STATUS_OK;";
2115 foreach my $interface (@{$idl}) {
2116 next if $interface->{TYPE} ne "INTERFACE";
2118 my $data = $interface->{INHERITED_DATA};
2119 my $count = 0;
2120 foreach my $d (@{$data}) {
2121 if ($d->{TYPE} eq "FUNCTION") { $count++; }
2124 next if ($count == 0);
2126 pidl "status = dcerpc_ndr_$interface->{NAME}_init();";
2127 pidl "if (NT_STATUS_IS_ERR(status)) {";
2128 pidl "\treturn status;";
2129 pidl "}";
2130 pidl "";
2132 pidl "return status;";
2133 deindent;
2134 pidl "}";
2135 pidl "";
2138 sub CheckPointerTypes($$)
2140 my $s = shift;
2141 my $default = shift;
2143 foreach my $e (@{$s->{ELEMENTS}}) {
2144 if ($e->{POINTERS}) {
2145 if (not defined(pointer_type($e))) {
2146 $e->{PROPERTIES}->{$default} = 1;
2149 if (pointer_type($e) eq "ptr") {
2150 print "Warning: ptr is not supported by pidl yet\n";
2156 sub LoadInterface($)
2158 my $x = shift;
2160 if (not util::has_property($x, "pointer_default")) {
2161 # MIDL defaults to "ptr" in DCE compatible mode (/osf)
2162 # and "unique" in Microsoft Extensions mode (default)
2163 $x->{PROPERTIES}->{pointer_default} = "unique";
2166 foreach my $d (@{$x->{DATA}}) {
2167 if (($d->{TYPE} eq "DECLARE") or ($d->{TYPE} eq "TYPEDEF")) {
2168 if ($d->{DATA}->{TYPE} eq "STRUCT" or $d->{DATA}->{TYPE} eq "UNION") {
2169 CheckPointerTypes($d->{DATA}, $x->{PROPERTIES}->{pointer_default});
2172 if (defined($d->{PROPERTIES}) && !defined($d->{DATA}->{PROPERTIES})) {
2173 $d->{DATA}->{PROPERTIES} = $d->{PROPERTIES};
2176 if ($d->{TYPE} eq "FUNCTION") {
2177 CheckPointerTypes($d,
2178 $x->{PROPERTIES}->{pointer_default} # MIDL defaults to "ref"
2184 sub Load($)
2186 my $idl = shift;
2188 foreach my $x (@{$idl}) {
2189 LoadInterface($x);
2193 #####################################################################
2194 # parse a parsed IDL structure back into an IDL file
2195 sub Parse($$)
2197 my($idl) = shift;
2198 my($filename) = shift;
2199 my $h_filename = $filename;
2200 $res = "";
2202 Load($idl);
2204 if ($h_filename =~ /(.*)\.c/) {
2205 $h_filename = "$1.h";
2208 pidl "/* parser auto-generated by pidl */";
2209 pidl "";
2210 pidl "#include \"includes.h\"";
2211 pidl "#include \"$h_filename\"";
2212 pidl "";
2214 foreach my $x (@{$idl}) {
2215 if ($x->{TYPE} eq "INTERFACE") {
2216 needed::BuildNeeded($x);
2217 ParseInterface($x);
2221 RegistrationFunction($idl, $filename);
2223 return $res;