1###################################################
2# Samba4 NDR parser generator for IDL structures
3# Copyright tridge@samba.org 2000-2003
4# Copyright tpot@samba.org 2001
5# Copyright jelmer@samba.org 2004-2006
6# released under the GNU GPL
7
8package Parse::Pidl::Samba4::NDR::Parser;
9use parent Parse::Pidl::Base;
10
11require Exporter;
12push @ISA, qw(Exporter);
13@EXPORT_OK = qw(check_null_pointer NeededFunction NeededElement NeededType $res NeededInterface TypeFunctionName ParseElementPrint);
14
15use strict;
16use warnings;
17use Parse::Pidl::Typelist qw(hasType getType mapTypeName typeHasBody);
18use Parse::Pidl::Util qw(has_property
19			 ParseExpr
20			 ParseExprExt
21			 print_uuid
22			 unmake_str
23			 parse_int
24			 parse_range);
25use Parse::Pidl::CUtil qw(get_pointer_to get_value_of get_array_element);
26use Parse::Pidl::NDR qw(GetPrevLevel GetNextLevel ContainsDeferred ContainsPipe is_charset_array);
27use Parse::Pidl::Samba4 qw(is_intree choose_header ArrayDynamicallyAllocated);
28use Parse::Pidl::Samba4::Header qw(GenerateFunctionInEnv GenerateFunctionOutEnv EnvSubstituteValue GenerateStructEnv);
29use Parse::Pidl qw(warning);
30
31use vars qw($VERSION);
32$VERSION = '0.01';
33
34# list of known types
35my %typefamily;
36
37sub new($$) {
38	my ($class) = @_;
39	my $self = { res => "", res_hdr => "", deferred => [], tabs => "", defer_tabs => "" };
40	bless($self, $class);
41}
42
43sub get_typefamily($)
44{
45	my $n = shift;
46	return $typefamily{$n};
47}
48
49sub append_prefix($$)
50{
51	my ($e, $var_name) = @_;
52	my $pointers = 0;
53	my $arrays = 0;
54
55	foreach my $l (@{$e->{LEVELS}}) {
56		if ($l->{TYPE} eq "POINTER") {
57			$pointers++;
58		} elsif ($l->{TYPE} eq "ARRAY") {
59			$arrays++;
60			if (($pointers == 0) and
61			    (not $l->{IS_FIXED}) and
62			    (not $l->{IS_INLINE})) {
63				return get_value_of($var_name);
64			}
65		} elsif ($l->{TYPE} eq "DATA") {
66			if (Parse::Pidl::Typelist::scalar_is_reference($l->{DATA_TYPE})) {
67				return get_value_of($var_name) unless ($pointers or $arrays);
68			}
69		}
70	}
71
72	return $var_name;
73}
74
75sub has_fast_array($$)
76{
77	my ($e,$l) = @_;
78
79	return 0 if ($l->{TYPE} ne "ARRAY");
80
81	my $nl = GetNextLevel($e,$l);
82	return 0 unless ($nl->{TYPE} eq "DATA");
83	return 0 unless (hasType($nl->{DATA_TYPE}));
84
85	my $t = getType($nl->{DATA_TYPE});
86
87	# Only uint8 has a fast array function at the moment
88	return ($t->{NAME} eq "uint8");
89}
90
91sub is_public_struct
92{
93	my ($d) = @_;
94	if (!has_property($d, "public")) {
95		return 0;
96	}
97	my $t = $d;
98	if ($d->{TYPE} eq "TYPEDEF") {
99		$t = $d->{DATA};
100	}
101	return $t->{TYPE} eq "STRUCT";
102}
103
104####################################
105# defer() is like pidl(), but adds to
106# a deferred buffer which is then added to the
107# output buffer at the end of the structure/union/function
108# This is needed to cope with code that must be pushed back
109# to the end of a block of elements
110sub defer_indent($) { my ($self) = @_; $self->{defer_tabs}.="\t"; }
111sub defer_deindent($) { my ($self) = @_; $self->{defer_tabs}=substr($self->{defer_tabs}, 0, -1); }
112
113sub defer($$)
114{
115	my ($self, $d) = @_;
116	if ($d) {
117		push(@{$self->{deferred}}, $self->{defer_tabs}.$d);
118	}
119}
120
121########################################
122# add the deferred content to the current
123# output
124sub add_deferred($)
125{
126	my ($self) = @_;
127	$self->pidl($_) foreach (@{$self->{deferred}});
128	$self->{deferred} = [];
129	$self->{defer_tabs} = "";
130}
131
132#####################################################################
133# declare a function public or static, depending on its attributes
134sub fn_declare($$$$)
135{
136	my ($self,$type,$fn,$decl) = @_;
137
138	if (has_property($fn, "no$type")) {
139		$self->pidl_hdr("$decl;");
140		return 0;
141	}
142
143	if (has_property($fn, "public")) {
144		$self->pidl_hdr("$decl;");
145		$self->pidl("_PUBLIC_ $decl");
146	} else {
147		$self->pidl("static $decl");
148	}
149
150	return 1;
151}
152
153###################################################################
154# setup any special flags for an element or structure
155sub start_flags($$$)
156{
157	my ($self, $e, $ndr) = @_;
158	my $flags = has_property($e, "flag");
159	if (defined $flags) {
160		$self->pidl("{");
161		$self->indent;
162		$self->pidl("uint32_t _flags_save_$e->{TYPE} = $ndr->flags;");
163		$self->pidl("ndr_set_flags(&$ndr->flags, $flags);");
164	}
165}
166
167###################################################################
168# end any special flags for an element or structure
169sub end_flags($$$)
170{
171	my ($self, $e, $ndr) = @_;
172	my $flags = has_property($e, "flag");
173	if (defined $flags) {
174		$self->pidl("$ndr->flags = _flags_save_$e->{TYPE};");
175		$self->deindent;
176		$self->pidl("}");
177	}
178}
179
180#####################################################################
181# parse the data of an array - push side
182sub ParseArrayPushHeader($$$$$$)
183{
184	my ($self,$e,$l,$ndr,$var_name,$env) = @_;
185
186	my $size;
187	my $length;
188
189	if ($l->{IS_ZERO_TERMINATED}) {
190		if (has_property($e, "charset")) {
191			$size = $length = "ndr_charset_length($var_name, CH_$e->{PROPERTIES}->{charset})";
192		} else {
193			$size = $length = "ndr_string_length($var_name, sizeof(*$var_name))";
194		}
195		if (defined($l->{SIZE_IS})) {
196			$size = ParseExpr($l->{SIZE_IS}, $env, $e);
197		}
198		if (defined($l->{LENGTH_IS})) {
199			$length = ParseExpr($l->{LENGTH_IS}, $env, $e);
200		}
201	} else {
202		$size = ParseExpr($l->{SIZE_IS}, $env, $e);
203		$length = ParseExpr($l->{LENGTH_IS}, $env, $e);
204	}
205
206	if ((!$l->{IS_SURROUNDING}) and $l->{IS_CONFORMANT}) {
207		$self->pidl("NDR_CHECK(ndr_push_uint3264($ndr, NDR_SCALARS, $size));");
208	}
209
210	if ($l->{IS_VARYING}) {
211		$self->pidl("NDR_CHECK(ndr_push_uint3264($ndr, NDR_SCALARS, 0));");  # array offset
212		$self->pidl("NDR_CHECK(ndr_push_uint3264($ndr, NDR_SCALARS, $length));");
213	}
214
215	return $length;
216}
217
218sub check_fully_dereferenced($$)
219{
220	my ($element, $env) = @_;
221
222	return sub ($) {
223		my $origvar = shift;
224		my $check = 0;
225
226		# Figure out the number of pointers in $ptr
227		my $expandedvar = $origvar;
228		$expandedvar =~ s/^(\**)//;
229		my $ptr = $1;
230
231		my $var = undef;
232		foreach (keys %$env) {
233			if ($env->{$_} eq $expandedvar) {
234				$var = $_;
235				last;
236			}
237		}
238
239		return($origvar) unless (defined($var));
240		my $e;
241		foreach (@{$element->{PARENT}->{ELEMENTS}}) {
242			if ($_->{NAME} eq $var) {
243				$e = $_;
244				last;
245			}
246		}
247
248		$e or die("Environment doesn't match siblings");
249
250		# See if pointer at pointer level $level
251		# needs to be checked.
252		my $nump = 0;
253		foreach (@{$e->{LEVELS}}) {
254			if ($_->{TYPE} eq "POINTER") {
255				$nump = $_->{POINTER_INDEX}+1;
256			}
257		}
258		warning($element->{ORIGINAL}, "Got pointer for `$e->{NAME}', expected fully dereferenced variable") if ($nump > length($ptr));
259		return ($origvar);
260	}
261}
262
263sub check_null_pointer($$$$)
264{
265	my ($element, $env, $print_fn, $return) = @_;
266
267	return sub ($) {
268		my $expandedvar = shift;
269		my $check = 0;
270
271		# Figure out the number of pointers in $ptr
272		$expandedvar =~ s/^(\**)//;
273		my $ptr = $1;
274
275		my $var = undef;
276		foreach (keys %$env) {
277			if ($env->{$_} eq $expandedvar) {
278				$var = $_;
279				last;
280			}
281		}
282
283		if (defined($var)) {
284			my $e;
285			# lookup ptr in $e
286			foreach (@{$element->{PARENT}->{ELEMENTS}}) {
287				if ($_->{NAME} eq $var) {
288					$e = $_;
289					last;
290				}
291			}
292
293			$e or die("Environment doesn't match siblings");
294
295			# See if pointer at pointer level $level
296			# needs to be checked.
297			foreach my $l (@{$e->{LEVELS}}) {
298				if ($l->{TYPE} eq "POINTER" and
299					$l->{POINTER_INDEX} == length($ptr)) {
300					# No need to check ref pointers
301					$check = ($l->{POINTER_TYPE} ne "ref");
302					last;
303				}
304
305				if ($l->{TYPE} eq "DATA") {
306					warning($element, "too much dereferences for `$var'");
307				}
308			}
309		} else {
310			warning($element, "unknown dereferenced expression `$expandedvar'");
311			$check = 1;
312		}
313
314		$print_fn->("if ($ptr$expandedvar == NULL) $return") if $check;
315	}
316}
317
318sub is_deferred_switch_non_empty($)
319{
320	# 1 if there needs to be a deferred branch in an ndr_pull/push,
321	# 0 otherwise.
322	my ($e) = @_;
323	my $have_default = 0;
324	foreach my $el (@{$e->{ELEMENTS}}) {
325		if ($el->{CASE} eq "default") {
326			$have_default = 1;
327		}
328		if ($el->{TYPE} ne "EMPTY") {
329			if (ContainsDeferred($el, $el->{LEVELS}[0])) {
330				return 1;
331			}
332		}
333	}
334	return ! $have_default;
335}
336
337sub ParseArrayPullGetSize($$$$$$)
338{
339	my ($self,$e,$l,$ndr,$var_name,$env) = @_;
340
341	my $size;
342
343	if ($l->{IS_CONFORMANT}) {
344		$size = "ndr_get_array_size($ndr, " . get_pointer_to($var_name) . ")";
345	} elsif ($l->{IS_ZERO_TERMINATED} and $l->{SIZE_IS} == 0 and $l->{LENGTH_IS} == 0) { # Noheader arrays
346		$size = "ndr_get_string_size($ndr, sizeof(*$var_name))";
347	} else {
348		$size = ParseExprExt($l->{SIZE_IS}, $env, $e->{ORIGINAL},
349			check_null_pointer($e, $env, sub { $self->pidl(shift); },
350					   "return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for size_is()\");"),
351			check_fully_dereferenced($e, $env));
352	}
353
354	$self->pidl("size_$e->{NAME}_$l->{LEVEL_INDEX} = $size;");
355	my $array_size = "size_$e->{NAME}_$l->{LEVEL_INDEX}";
356
357	if (my $range = has_property($e, "range")) {
358		my ($low, $high) = parse_range($range);
359		if ($low < 0) {
360			warning(0, "$low is invalid for the range of an array size");
361		}
362		if ($low == 0) {
363			$self->pidl("if ($array_size > $high) {");
364		} else {
365			$self->pidl("if ($array_size < $low || $array_size > $high) {");
366		}
367		$self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_RANGE, \"value out of range\");");
368		$self->pidl("}");
369	}
370
371	return $array_size;
372}
373
374#####################################################################
375# parse an array - pull side
376sub ParseArrayPullGetLength($$$$$$;$)
377{
378	my ($self,$e,$l,$ndr,$var_name,$env,$array_size) = @_;
379
380	if (not defined($array_size)) {
381		$array_size = $self->ParseArrayPullGetSize($e, $l, $ndr, $var_name, $env);
382	}
383
384	if (not $l->{IS_VARYING}) {
385		return $array_size;
386	}
387
388	my $length = "ndr_get_array_length($ndr, " . get_pointer_to($var_name) .")";
389	$self->pidl("length_$e->{NAME}_$l->{LEVEL_INDEX} = $length;");
390	my $array_length = "length_$e->{NAME}_$l->{LEVEL_INDEX}";
391
392	if (my $range = has_property($e, "range")) {
393		my ($low, $high) = parse_range($range);
394		if ($low < 0) {
395			warning(0, "$low is invalid for the range of an array size");
396		}
397		if ($low == 0) {
398			$self->pidl("if ($array_length > $high) {");
399		} else {
400			$self->pidl("if ($array_length < $low || $array_length > $high) {");
401		}
402		$self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_RANGE, \"value out of range\");");
403		$self->pidl("}");
404	}
405
406	return $array_length;
407}
408
409#####################################################################
410# parse an array - pull side
411sub ParseArrayPullHeader($$$$$$)
412{
413	my ($self,$e,$l,$ndr,$var_name,$env) = @_;
414
415	if ((!$l->{IS_SURROUNDING}) and $l->{IS_CONFORMANT}) {
416		$self->pidl("NDR_CHECK(ndr_pull_array_size($ndr, " . get_pointer_to($var_name) . "));");
417	}
418
419	if ($l->{IS_VARYING}) {
420		$self->pidl("NDR_CHECK(ndr_pull_array_length($ndr, " . get_pointer_to($var_name) . "));");
421	}
422
423	my $array_size = $self->ParseArrayPullGetSize($e, $l, $ndr, $var_name, $env);
424	my $array_length = $self->ParseArrayPullGetLength($e, $l, $ndr, $var_name, $env, $array_size);
425
426	if ($array_length ne $array_size) {
427		$self->pidl("if ($array_length > $array_size) {");
428		$self->indent;
429		$self->pidl("return ndr_pull_error($ndr, NDR_ERR_ARRAY_SIZE, \"Bad array size %u should exceed array length %u\", $array_size, $array_length);");
430		$self->deindent;
431		$self->pidl("}");
432	}
433
434	if ($l->{IS_CONFORMANT} and (defined($l->{SIZE_IS}) or not $l->{IS_ZERO_TERMINATED})) {
435		$self->defer("if ($var_name) {");
436		$self->defer_indent;
437		my $size = ParseExprExt($l->{SIZE_IS}, $env, $e->{ORIGINAL},
438			check_null_pointer($e, $env, sub { $self->defer(shift); },
439					   "return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for size_is()\");"),
440			check_fully_dereferenced($e, $env));
441		$self->defer("NDR_CHECK(ndr_check_array_size($ndr, (void*)" . get_pointer_to($var_name) . ", $size));");
442		$self->defer_deindent;
443		$self->defer("}");
444	}
445
446	if ($l->{IS_VARYING} and (defined($l->{LENGTH_IS}) or not $l->{IS_ZERO_TERMINATED})) {
447		$self->defer("if ($var_name) {");
448		$self->defer_indent;
449		my $length = ParseExprExt($l->{LENGTH_IS}, $env, $e->{ORIGINAL},
450			check_null_pointer($e, $env, sub { $self->defer(shift); },
451					   "return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for length_is()\");"),
452			check_fully_dereferenced($e, $env));
453		$self->defer("NDR_CHECK(ndr_check_array_length($ndr, (void*)" . get_pointer_to($var_name) . ", $length));");
454		$self->defer_deindent;
455		$self->defer("}");
456	}
457
458	if (ArrayDynamicallyAllocated($e,$l) and not is_charset_array($e,$l)) {
459		$self->AllocateArrayLevel($e,$l,$ndr,$var_name,$array_size);
460	}
461
462	return $array_length;
463}
464
465sub compression_alg($$)
466{
467	my ($e, $l) = @_;
468	my ($alg, $clen, $dlen) = split(/,/, $l->{COMPRESSION});
469
470	return $alg;
471}
472
473sub compression_clen($$$)
474{
475	my ($e, $l, $env) = @_;
476	my ($alg, $clen, $dlen) = split(/,/, $l->{COMPRESSION});
477
478	return ParseExpr($clen, $env, $e->{ORIGINAL});
479}
480
481sub compression_dlen($$$)
482{
483	my ($e,$l,$env) = @_;
484	my ($alg, $clen, $dlen) = split(/,/, $l->{COMPRESSION});
485
486	return ParseExpr($dlen, $env, $e->{ORIGINAL});
487}
488
489sub ParseCompressionPushStart($$$$$)
490{
491	my ($self,$e,$l,$ndr,$env) = @_;
492	my $comndr = "$ndr\_compressed";
493	my $alg = compression_alg($e, $l);
494	my $dlen = compression_dlen($e, $l, $env);
495
496	$self->pidl("{");
497	$self->indent;
498	$self->pidl("struct ndr_push *$comndr;");
499	$self->pidl("NDR_CHECK(ndr_push_compression_start($ndr, &$comndr, $alg, $dlen));");
500
501	return $comndr;
502}
503
504sub ParseCompressionPushEnd($$$$$)
505{
506	my ($self,$e,$l,$ndr,$env) = @_;
507	my $comndr = "$ndr\_compressed";
508	my $alg = compression_alg($e, $l);
509	my $dlen = compression_dlen($e, $l, $env);
510
511	$self->pidl("NDR_CHECK(ndr_push_compression_end($ndr, $comndr, $alg, $dlen));");
512	$self->deindent;
513	$self->pidl("}");
514}
515
516sub ParseCompressionPullStart($$$$$)
517{
518	my ($self,$e,$l,$ndr,$env) = @_;
519	my $comndr = "$ndr\_compressed";
520	my $alg = compression_alg($e, $l);
521	my $dlen = compression_dlen($e, $l, $env);
522	my $clen = compression_clen($e, $l, $env);
523
524	$self->pidl("{");
525	$self->indent;
526	$self->pidl("struct ndr_pull *$comndr;");
527	$self->pidl("NDR_CHECK(ndr_pull_compression_start($ndr, &$comndr, $alg, $dlen, $clen));");
528
529	return $comndr;
530}
531
532sub ParseCompressionPullEnd($$$$$)
533{
534	my ($self,$e,$l,$ndr,$env) = @_;
535	my $comndr = "$ndr\_compressed";
536	my $alg = compression_alg($e, $l);
537	my $dlen = compression_dlen($e, $l, $env);
538
539	$self->pidl("NDR_CHECK(ndr_pull_compression_end($ndr, $comndr, $alg, $dlen));");
540	$self->deindent;
541	$self->pidl("}");
542}
543
544sub ParseSubcontextPushStart($$$$$)
545{
546	my ($self,$e,$l,$ndr,$env) = @_;
547	my $subndr = "_ndr_$e->{NAME}";
548	my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
549
550	$self->pidl("{");
551	$self->indent;
552	$self->pidl("struct ndr_push *$subndr;");
553	$self->pidl("NDR_CHECK(ndr_push_subcontext_start($ndr, &$subndr, $l->{HEADER_SIZE}, $subcontext_size));");
554
555	if (defined $l->{COMPRESSION}) {
556		$subndr = $self->ParseCompressionPushStart($e, $l, $subndr, $env);
557	}
558
559	return $subndr;
560}
561
562sub ParseSubcontextPushEnd($$$$$)
563{
564	my ($self,$e,$l,$ndr,$env) = @_;
565	my $subndr = "_ndr_$e->{NAME}";
566	my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
567
568	if (defined $l->{COMPRESSION}) {
569		$self->ParseCompressionPushEnd($e, $l, $subndr, $env);
570	}
571
572	$self->pidl("NDR_CHECK(ndr_push_subcontext_end($ndr, $subndr, $l->{HEADER_SIZE}, $subcontext_size));");
573	$self->deindent;
574	$self->pidl("}");
575}
576
577sub ParseSubcontextPullStart($$$$$)
578{
579	my ($self,$e,$l,$ndr,$env) = @_;
580	my $subndr = "_ndr_$e->{NAME}";
581	my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
582
583	$self->pidl("{");
584	$self->indent;
585	$self->pidl("struct ndr_pull *$subndr;");
586	$self->pidl("NDR_CHECK(ndr_pull_subcontext_start($ndr, &$subndr, $l->{HEADER_SIZE}, $subcontext_size));");
587
588	if (defined $l->{COMPRESSION}) {
589		$subndr = $self->ParseCompressionPullStart($e, $l, $subndr, $env);
590	}
591
592	return $subndr;
593}
594
595sub ParseSubcontextPullEnd($$$$$)
596{
597	my ($self,$e,$l,$ndr,$env) = @_;
598	my $subndr = "_ndr_$e->{NAME}";
599	my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
600
601	if (defined $l->{COMPRESSION}) {
602		$self->ParseCompressionPullEnd($e, $l, $subndr, $env);
603	}
604
605	$self->pidl("NDR_CHECK(ndr_pull_subcontext_end($ndr, $subndr, $l->{HEADER_SIZE}, $subcontext_size));");
606	$self->deindent;
607	$self->pidl("}");
608}
609
610sub ParseElementPushLevel
611{
612	my ($self,$e,$l,$ndr,$var_name,$env,$primitives,$deferred) = @_;
613
614	my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
615
616	if ($l->{TYPE} eq "ARRAY" and ($l->{IS_CONFORMANT} or $l->{IS_VARYING})) {
617		$var_name = get_pointer_to($var_name);
618	}
619
620	if (defined($ndr_flags)) {
621		if ($l->{TYPE} eq "SUBCONTEXT") {
622			my $subndr = $self->ParseSubcontextPushStart($e, $l, $ndr, $env);
623			$self->ParseElementPushLevel($e, GetNextLevel($e, $l), $subndr, $var_name, $env, 1, 1);
624			$self->ParseSubcontextPushEnd($e, $l, $ndr, $env);
625		} elsif ($l->{TYPE} eq "POINTER") {
626			$self->ParsePtrPush($e, $l, $ndr, $var_name);
627		} elsif ($l->{TYPE} eq "ARRAY") {
628			my $length = $self->ParseArrayPushHeader($e, $l, $ndr, $var_name, $env);
629
630			my $nl = GetNextLevel($e, $l);
631
632			# Allow speedups for arrays of scalar types
633			if (is_charset_array($e,$l)) {
634				if ($l->{IS_TO_NULL}) {
635					$self->pidl("NDR_CHECK(ndr_push_charset_to_null($ndr, $ndr_flags, $var_name, $length, sizeof(" . mapTypeName($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));");
636				} else {
637					$self->pidl("NDR_CHECK(ndr_push_charset($ndr, $ndr_flags, $var_name, $length, sizeof(" . mapTypeName($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));");
638				}
639				return;
640			} elsif (has_fast_array($e,$l)) {
641				$self->pidl("NDR_CHECK(ndr_push_array_$nl->{DATA_TYPE}($ndr, $ndr_flags, $var_name, $length));");
642				return;
643			}
644		} elsif ($l->{TYPE} eq "DATA") {
645			$self->ParseDataPush($e, $l, $ndr, $var_name, $primitives, $deferred);
646		} elsif ($l->{TYPE} eq "TYPEDEF") {
647			$typefamily{$e->{DATA}->{TYPE}}->{PUSH_FN_BODY}->($self, $e->{DATA}, $ndr, $var_name);
648		}
649	}
650
651	if ($l->{TYPE} eq "POINTER" and $l->{POINTER_TYPE} eq "ignore") {
652		$self->pidl("/* [ignore] '$e->{NAME}' */");
653	} elsif ($l->{TYPE} eq "POINTER" and $deferred) {
654		my $rel_var_name = $var_name;
655		if ($l->{POINTER_TYPE} ne "ref") {
656			$self->pidl("if ($var_name) {");
657			$self->indent;
658			if ($l->{POINTER_TYPE} eq "relative") {
659				$self->pidl("NDR_CHECK(ndr_push_relative_ptr2_start($ndr, $rel_var_name));");
660			}
661			if ($l->{POINTER_TYPE} eq "relative_short") {
662				$self->pidl("NDR_CHECK(ndr_push_short_relative_ptr2($ndr, $var_name));");
663			}
664		}
665		$var_name = get_value_of($var_name);
666		$self->ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 1, 1);
667
668		if ($l->{POINTER_TYPE} ne "ref") {
669			if ($l->{POINTER_TYPE} eq "relative") {
670				$self->pidl("NDR_CHECK(ndr_push_relative_ptr2_end($ndr, $rel_var_name));");
671			}
672			$self->deindent;
673			$self->pidl("}");
674		}
675	} elsif ($l->{TYPE} eq "ARRAY" and not has_fast_array($e,$l) and
676		not is_charset_array($e, $l)) {
677		my $length = ParseExpr($l->{LENGTH_IS}, $env, $e->{ORIGINAL});
678		my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
679
680		my $array_pointless = ($length eq "0");
681
682		if ($array_pointless) {
683			warning($e->{ORIGINAL}, "pointless array `$e->{NAME}' will always have size 0");
684		}
685
686		$var_name = get_array_element($var_name, $counter);
687
688		if ((($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) and not $array_pointless) {
689			$self->pidl("for ($counter = 0; $counter < ($length); $counter++) {");
690			$self->indent;
691			$self->ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 1, 0);
692			$self->deindent;
693			$self->pidl("}");
694		}
695
696		if ($deferred and ContainsDeferred($e, $l) and not $array_pointless) {
697			$self->pidl("for ($counter = 0; $counter < ($length); $counter++) {");
698			$self->indent;
699			$self->ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 0, 1);
700			$self->deindent;
701			$self->pidl("}");
702		}
703	} elsif ($l->{TYPE} eq "SWITCH") {
704		my $nl = GetNextLevel($e,$l);
705		my $needs_deferred_switch = is_deferred_switch_non_empty($nl);
706
707		# Avoid setting a switch value if it will not be
708		# consumed again in the NDR_BUFFERS pull
709		if ($needs_deferred_switch or !$deferred) {
710			$self->ParseSwitchPush($e, $l, $ndr, $var_name, $env);
711		}
712		$self->ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, $primitives, $deferred);
713	}
714}
715
716#####################################################################
717# parse scalars in a structure element
718sub ParseElementPush($$$$$$)
719{
720	my ($self,$e,$ndr,$env,$primitives,$deferred) = @_;
721	my $subndr = undef;
722
723	my $var_name = $env->{$e->{NAME}};
724
725	if (has_property($e, "skip") or has_property($e, "skip_noinit")) {
726		$self->pidl("/* [skip] '$var_name' */");
727		return;
728	}
729
730	return if ContainsPipe($e, $e->{LEVELS}[0]);
731
732	return unless $primitives or ($deferred and ContainsDeferred($e, $e->{LEVELS}[0]));
733
734	# Representation type is different from transmit_as
735	if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
736		$self->pidl("{");
737		$self->indent;
738		my $transmit_name = "_transmit_$e->{NAME}";
739		$self->pidl(mapTypeName($e->{TYPE}) ." $transmit_name;");
740		$self->pidl("NDR_CHECK(ndr_$e->{REPRESENTATION_TYPE}_to_$e->{TYPE}($var_name, " . get_pointer_to($transmit_name) . "));");
741		$var_name = $transmit_name;
742	}
743
744	$var_name = append_prefix($e, $var_name);
745
746	$self->start_flags($e, $ndr);
747
748	if (defined(my $value = has_property($e, "value"))) {
749		$var_name = ParseExpr($value, $env, $e->{ORIGINAL});
750	}
751
752	$self->ParseElementPushLevel($e, $e->{LEVELS}[0], $ndr, $var_name, $env, $primitives, $deferred);
753
754	$self->end_flags($e, $ndr);
755
756	if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
757		$self->deindent;
758		$self->pidl("}");
759	}
760}
761
762#####################################################################
763# parse a pointer in a struct element or function
764sub ParsePtrPush($$$$$)
765{
766	my ($self,$e,$l,$ndr,$var_name) = @_;
767
768	if ($l->{POINTER_TYPE} eq "ref") {
769		if ($l->{LEVEL_INDEX} > 0) {
770			$self->pidl("if ($var_name == NULL) {");
771			$self->indent;
772			$self->pidl("return ndr_push_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL [ref] pointer\");");
773			$self->deindent;
774			$self->pidl("}");
775		}
776		if ($l->{LEVEL} eq "EMBEDDED") {
777			$self->pidl("NDR_CHECK(ndr_push_ref_ptr(ndr)); /* $var_name */");
778		}
779	} elsif ($l->{POINTER_TYPE} eq "relative") {
780		$self->pidl("NDR_CHECK(ndr_push_relative_ptr1($ndr, $var_name));");
781	} elsif ($l->{POINTER_TYPE} eq "relative_short") {
782		$self->pidl("NDR_CHECK(ndr_push_short_relative_ptr1($ndr, $var_name));");
783	} elsif ($l->{POINTER_TYPE} eq "unique") {
784		$self->pidl("NDR_CHECK(ndr_push_unique_ptr($ndr, $var_name));");
785	} elsif ($l->{POINTER_TYPE} eq "full") {
786		$self->pidl("NDR_CHECK(ndr_push_full_ptr($ndr, $var_name));");
787	} elsif ($l->{POINTER_TYPE} eq "ignore") {
788	        # We don't want this pointer to appear on the wire at all
789		$self->pidl("NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, 0));");
790	} else {
791		die("Unhandled pointer type $l->{POINTER_TYPE}");
792	}
793}
794
795sub need_pointer_to($$$)
796{
797	my ($e, $l, $scalar_only) = @_;
798
799	my $t;
800	if (ref($l->{DATA_TYPE})) {
801		$t = "$l->{DATA_TYPE}->{TYPE}_$l->{DATA_TYPE}->{NAME}";
802	} else {
803		$t = $l->{DATA_TYPE};
804	}
805
806	if (not Parse::Pidl::Typelist::is_scalar($t)) {
807		return 1 if $scalar_only;
808	}
809
810	my $arrays = 0;
811
812	foreach my $tl (@{$e->{LEVELS}}) {
813		last if $l == $tl;
814		if ($tl->{TYPE} eq "ARRAY") {
815			$arrays++;
816		}
817	}
818
819	if (Parse::Pidl::Typelist::scalar_is_reference($t)) {
820		return 1 unless $arrays;
821	}
822
823	return 0;
824}
825
826sub ParseDataPrint($$$$$)
827{
828	my ($self, $e, $l, $ndr, $var_name) = @_;
829
830	if (not ref($l->{DATA_TYPE}) or defined($l->{DATA_TYPE}->{NAME})) {
831
832		if (need_pointer_to($e, $l, 1)) {
833			$var_name = get_pointer_to($var_name);
834		}
835
836		$self->pidl(TypeFunctionName("ndr_print", $l->{DATA_TYPE})."($ndr, \"$e->{NAME}\", $var_name);");
837	} else {
838		$self->ParseTypePrint($l->{DATA_TYPE}, $ndr, $var_name);
839	}
840}
841
842#####################################################################
843# print scalars in a structure element
844sub ParseElementPrint($$$$$)
845{
846	my($self, $e, $ndr, $var_name, $env) = @_;
847
848	return if (has_property($e, "noprint"));
849	my $cur_depth = 0;
850	my $ignore_depth = 0xFFFF;
851
852	$self->start_flags($e, $ndr);
853	if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
854		$self->pidl("ndr_print_$e->{REPRESENTATION_TYPE}($ndr, \"$e->{NAME}\", $var_name);");
855		$self->end_flags($e, $ndr);
856		return;
857	}
858
859	$var_name = append_prefix($e, $var_name);
860
861	if (defined(my $value = has_property($e, "value"))) {
862		$var_name = "($ndr->flags & LIBNDR_PRINT_SET_VALUES)?" . ParseExpr($value,$env, $e->{ORIGINAL}) . ":$var_name";
863	}
864
865	foreach my $l (@{$e->{LEVELS}}) {
866		$cur_depth += 1;
867
868		if ($cur_depth > $ignore_depth) {
869			next;
870		}
871
872		if ($l->{TYPE} eq "POINTER") {
873			$self->pidl("ndr_print_ptr($ndr, \"$e->{NAME}\", $var_name);");
874			if ($l->{POINTER_TYPE} eq "ignore") {
875				$self->pidl("/* [ignore] '$e->{NAME}' */");
876				$ignore_depth = $cur_depth;
877				last;
878			}
879			$self->pidl("$ndr->depth++;");
880			if ($l->{POINTER_TYPE} ne "ref") {
881				$self->pidl("if ($var_name) {");
882				$self->indent;
883			}
884			$var_name = get_value_of($var_name);
885		} elsif ($l->{TYPE} eq "ARRAY") {
886			my $length;
887
888			if ($l->{IS_CONFORMANT} or $l->{IS_VARYING}) {
889				$var_name = get_pointer_to($var_name);
890			}
891
892			if ($l->{IS_ZERO_TERMINATED} and not defined($l->{LENGTH_IS})) {
893				$length = "ndr_string_length($var_name, sizeof(*$var_name))";
894			} else {
895				$length = ParseExprExt($l->{LENGTH_IS}, $env, $e->{ORIGINAL},
896							check_null_pointer($e, $env, sub { $self->pidl(shift); }, "return;"), check_fully_dereferenced($e, $env));
897			}
898
899			if (is_charset_array($e,$l)) {
900				$self->pidl("ndr_print_string($ndr, \"$e->{NAME}\", $var_name);");
901				last;
902			} elsif (has_fast_array($e, $l)) {
903				my $nl = GetNextLevel($e, $l);
904				$self->pidl("ndr_print_array_$nl->{DATA_TYPE}($ndr, \"$e->{NAME}\", $var_name, $length);");
905				last;
906			} else {
907				my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
908
909				$self->pidl("$ndr->print($ndr, \"\%s: ARRAY(\%d)\", \"$e->{NAME}\", (int)$length);");
910				$self->pidl("$ndr->depth++;");
911				$self->pidl("for ($counter = 0; $counter < ($length); $counter++) {");
912				$self->indent;
913
914				$var_name = get_array_element($var_name, $counter);
915			}
916		} elsif ($l->{TYPE} eq "DATA") {
917			$self->ParseDataPrint($e, $l, $ndr, $var_name);
918		} elsif ($l->{TYPE} eq "SWITCH") {
919			my $switch_var = ParseExprExt($l->{SWITCH_IS}, $env, $e->{ORIGINAL},
920						check_null_pointer($e, $env, sub { $self->pidl(shift); }, "return;"), check_fully_dereferenced($e, $env));
921			$self->pidl("ndr_print_set_switch_value($ndr, " . get_pointer_to($var_name) . ", $switch_var);");
922		}
923	}
924
925	foreach my $l (reverse @{$e->{LEVELS}}) {
926		$cur_depth -= 1;
927
928		if ($cur_depth > $ignore_depth) {
929			next;
930		}
931
932		if ($l->{TYPE} eq "POINTER") {
933			if ($l->{POINTER_TYPE} eq "ignore") {
934				next;
935			}
936
937			if ($l->{POINTER_TYPE} ne "ref") {
938				$self->deindent;
939				$self->pidl("}");
940			}
941			$self->pidl("$ndr->depth--;");
942		} elsif (($l->{TYPE} eq "ARRAY")
943			and not is_charset_array($e,$l)
944			and not has_fast_array($e,$l)) {
945			$self->deindent;
946			$self->pidl("}");
947			$self->pidl("$ndr->depth--;");
948		}
949	}
950
951	$self->end_flags($e, $ndr);
952}
953
954#####################################################################
955# parse scalars in a structure element - pull size
956sub ParseSwitchPull($$$$$$)
957{
958	my($self,$e,$l,$ndr,$var_name,$env) = @_;
959	my $switch_var = ParseExprExt($l->{SWITCH_IS}, $env, $e->{ORIGINAL},
960		check_null_pointer($e, $env, sub { $self->pidl(shift); },
961				   "return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for switch_is()\");"),
962		check_fully_dereferenced($e, $env));
963
964	$var_name = get_pointer_to($var_name);
965	$self->pidl("NDR_CHECK(ndr_pull_set_switch_value($ndr, $var_name, $switch_var));");
966}
967
968#####################################################################
969# push switch element
970sub ParseSwitchPush($$$$$$)
971{
972	my($self,$e,$l,$ndr,$var_name,$env) = @_;
973	my $switch_var = ParseExprExt($l->{SWITCH_IS}, $env, $e->{ORIGINAL},
974		check_null_pointer($e, $env, sub { $self->pidl(shift); },
975				   "return ndr_push_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for switch_is()\");"),
976		check_fully_dereferenced($e, $env));
977
978	$var_name = get_pointer_to($var_name);
979	$self->pidl("NDR_CHECK(ndr_push_set_switch_value($ndr, $var_name, $switch_var));");
980}
981
982sub ParseDataPull($$$$$$$)
983{
984	my ($self,$e,$l,$ndr,$var_name,$primitives,$deferred) = @_;
985
986	if (not ref($l->{DATA_TYPE}) or defined($l->{DATA_TYPE}->{NAME})) {
987
988		my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
989
990		if (need_pointer_to($e, $l, 0)) {
991			$var_name = get_pointer_to($var_name);
992		}
993
994		$var_name = get_pointer_to($var_name);
995
996		$self->pidl("NDR_CHECK(".TypeFunctionName("ndr_pull", $l->{DATA_TYPE})."($ndr, $ndr_flags, $var_name));");
997
998		my $pl = GetPrevLevel($e, $l);
999
1000		my $range = has_property($e, "range");
1001		if ($range and (not $pl or $pl->{TYPE} ne "ARRAY")) {
1002			$var_name = get_value_of($var_name);
1003			my $signed = Parse::Pidl::Typelist::is_signed($l->{DATA_TYPE});
1004			my ($low, $high) = parse_range($range);
1005			if ($low < 0 and not $signed) {
1006				warning(0, "$low is invalid for the range of an unsigned type");
1007			}
1008			if ($low == 0 and not $signed) {
1009				$self->pidl("if ($var_name > $high) {");
1010			} else {
1011				$self->pidl("if ($var_name < $low || $var_name > $high) {");
1012			}
1013			$self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_RANGE, \"value out of range\");");
1014			$self->pidl("}");
1015		}
1016	} else {
1017		$self->ParseTypePull($l->{DATA_TYPE}, $ndr, $var_name, $primitives, $deferred);
1018	}
1019}
1020
1021sub ParseDataPush($$$$$$$)
1022{
1023	my ($self,$e,$l,$ndr,$var_name,$primitives,$deferred) = @_;
1024
1025	if (not ref($l->{DATA_TYPE}) or defined($l->{DATA_TYPE}->{NAME})) {
1026
1027		my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
1028
1029		# strings are passed by value rather than reference
1030		if (need_pointer_to($e, $l, 1)) {
1031			$var_name = get_pointer_to($var_name);
1032		}
1033
1034		$self->pidl("NDR_CHECK(".TypeFunctionName("ndr_push", $l->{DATA_TYPE})."($ndr, $ndr_flags, $var_name));");
1035	} else {
1036		$self->ParseTypePush($l->{DATA_TYPE}, $ndr, $var_name, $primitives, $deferred);
1037	}
1038}
1039
1040sub CalcNdrFlags($$$)
1041{
1042	my ($l,$primitives,$deferred) = @_;
1043
1044	my $scalars = 0;
1045	my $buffers = 0;
1046
1047	# Add NDR_SCALARS if this one is deferred
1048	# and deferreds may be pushed
1049	$scalars = 1 if ($l->{IS_DEFERRED} and $deferred);
1050
1051	# Add NDR_SCALARS if this one is not deferred and
1052	# primitives may be pushed
1053	$scalars = 1 if (!$l->{IS_DEFERRED} and $primitives);
1054
1055	# Add NDR_BUFFERS if this one contains deferred stuff
1056	# and deferreds may be pushed
1057	$buffers = 1 if ($l->{CONTAINS_DEFERRED} and $deferred);
1058
1059	return "NDR_SCALARS|NDR_BUFFERS" if ($scalars and $buffers);
1060	return "NDR_SCALARS" if ($scalars);
1061	return "NDR_BUFFERS" if ($buffers);
1062	return undef;
1063}
1064
1065sub ParseMemCtxPullFlags($$$$)
1066{
1067	my ($self, $e, $l) = @_;
1068
1069	return undef unless ($l->{TYPE} eq "POINTER" or $l->{TYPE} eq "ARRAY");
1070	return undef if (($l->{TYPE} eq "POINTER") and ($l->{POINTER_TYPE} eq "ignore"));
1071
1072	return undef unless ($l->{TYPE} ne "ARRAY" or ArrayDynamicallyAllocated($e,$l));
1073	return undef if has_fast_array($e, $l);
1074	return undef if is_charset_array($e, $l);
1075
1076	my $mem_flags = "0";
1077
1078	if (($l->{TYPE} eq "POINTER") and ($l->{POINTER_TYPE} eq "ref")) {
1079		my $nl = GetNextLevel($e, $l);
1080		return undef if ($nl->{TYPE} eq "PIPE");
1081		return undef if ($nl->{TYPE} eq "ARRAY");
1082		return undef if (($nl->{TYPE} eq "DATA") and ($nl->{DATA_TYPE} eq "string"));
1083
1084		if ($l->{LEVEL} eq "TOP") {
1085			$mem_flags = "LIBNDR_FLAG_REF_ALLOC";
1086		}
1087	}
1088
1089	return $mem_flags;
1090}
1091
1092sub ParseMemCtxPullStart($$$$$)
1093{
1094	my ($self, $e, $l, $ndr, $ptr_name) = @_;
1095
1096	my $mem_r_ctx = "_mem_save_$e->{NAME}_$l->{LEVEL_INDEX}";
1097	my $mem_c_ctx = $ptr_name;
1098	my $mem_c_flags = $self->ParseMemCtxPullFlags($e, $l);
1099
1100	return unless defined($mem_c_flags);
1101
1102	$self->pidl("$mem_r_ctx = NDR_PULL_GET_MEM_CTX($ndr);");
1103	$self->pidl("NDR_PULL_SET_MEM_CTX($ndr, $mem_c_ctx, $mem_c_flags);");
1104}
1105
1106sub ParseMemCtxPullEnd($$$$)
1107{
1108	my ($self, $e, $l, $ndr) = @_;
1109
1110	my $mem_r_ctx = "_mem_save_$e->{NAME}_$l->{LEVEL_INDEX}";
1111	my $mem_r_flags = $self->ParseMemCtxPullFlags($e, $l);
1112
1113	return unless defined($mem_r_flags);
1114
1115	$self->pidl("NDR_PULL_SET_MEM_CTX($ndr, $mem_r_ctx, $mem_r_flags);");
1116}
1117
1118sub CheckStringTerminator($$$$$)
1119{
1120	my ($self,$ndr,$e,$l,$length) = @_;
1121	my $nl = GetNextLevel($e, $l);
1122
1123	# Make sure last element is zero!
1124	$self->pidl("NDR_CHECK(ndr_check_string_terminator($ndr, $length, sizeof($nl->{DATA_TYPE}_t)));");
1125}
1126
1127sub ParseElementPullLevel
1128{
1129	my($self,$e,$l,$ndr,$var_name,$env,$primitives,$deferred) = @_;
1130
1131	my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
1132	my $array_length = undef;
1133
1134	if (has_property($e, "skip") or has_property($e, "skip_noinit")) {
1135		$self->pidl("/* [skip] '$var_name' */");
1136		if (not has_property($e, "skip_noinit")) {
1137			$self->pidl("NDR_ZERO_STRUCT($var_name);");
1138		}
1139		return;
1140	}
1141
1142	if ($l->{TYPE} eq "ARRAY" and ($l->{IS_VARYING} or $l->{IS_CONFORMANT})) {
1143		$var_name = get_pointer_to($var_name);
1144	}
1145
1146	# Only pull something if there's actually something to be pulled
1147	if (defined($ndr_flags)) {
1148		if ($l->{TYPE} eq "SUBCONTEXT") {
1149			my $subndr = $self->ParseSubcontextPullStart($e, $l, $ndr, $env);
1150			$self->ParseElementPullLevel($e, GetNextLevel($e,$l), $subndr, $var_name, $env, 1, 1);
1151			$self->ParseSubcontextPullEnd($e, $l, $ndr, $env);
1152		} elsif ($l->{TYPE} eq "ARRAY") {
1153			my $length = $self->ParseArrayPullHeader($e, $l, $ndr, $var_name, $env);
1154			$array_length = $length;
1155
1156			my $nl = GetNextLevel($e, $l);
1157
1158			if (is_charset_array($e,$l)) {
1159				if ($l->{IS_ZERO_TERMINATED}) {
1160					$self->CheckStringTerminator($ndr, $e, $l, $length);
1161				}
1162				if ($l->{IS_TO_NULL}) {
1163					$self->pidl("NDR_CHECK(ndr_pull_charset_to_null($ndr, $ndr_flags, ".get_pointer_to($var_name).", $length, sizeof(" . mapTypeName($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));");
1164				} else {
1165					$self->pidl("NDR_CHECK(ndr_pull_charset($ndr, $ndr_flags, ".get_pointer_to($var_name).", $length, sizeof(" . mapTypeName($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));");
1166				}
1167				return;
1168			} elsif (has_fast_array($e, $l)) {
1169				if ($l->{IS_ZERO_TERMINATED}) {
1170					$self->CheckStringTerminator($ndr,$e,$l,$length);
1171				}
1172				$self->pidl("NDR_CHECK(ndr_pull_array_$nl->{DATA_TYPE}($ndr, $ndr_flags, $var_name, $length));");
1173				return;
1174			}
1175		} elsif ($l->{TYPE} eq "POINTER") {
1176			$self->ParsePtrPull($e, $l, $ndr, $var_name);
1177		} elsif ($l->{TYPE} eq "DATA") {
1178			$self->ParseDataPull($e, $l, $ndr, $var_name, $primitives, $deferred);
1179		} elsif ($l->{TYPE} eq "TYPEDEF") {
1180			$typefamily{$e->{DATA}->{TYPE}}->{PULL_FN_BODY}->($self, $e->{DATA}, $ndr, $var_name);
1181		}
1182	}
1183
1184	# add additional constructions
1185	if ($l->{TYPE} eq "POINTER" and $l->{POINTER_TYPE} eq "ignore") {
1186		$self->pidl("/* [ignore] '$e->{NAME}' */");
1187	} elsif ($l->{TYPE} eq "POINTER" and $deferred) {
1188		if ($l->{POINTER_TYPE} ne "ref") {
1189			$self->pidl("if ($var_name) {");
1190			$self->indent;
1191
1192			if ($l->{POINTER_TYPE} eq "relative" or $l->{POINTER_TYPE} eq "relative_short") {
1193				$self->pidl("uint32_t _relative_save_offset;");
1194				$self->pidl("_relative_save_offset = $ndr->offset;");
1195				$self->pidl("NDR_CHECK(ndr_pull_relative_ptr2($ndr, $var_name));");
1196			}
1197		}
1198
1199		$self->ParseMemCtxPullStart($e, $l, $ndr, $var_name);
1200
1201		$var_name = get_value_of($var_name);
1202		$self->ParseElementPullLevel($e, GetNextLevel($e,$l), $ndr, $var_name, $env, 1, 1);
1203
1204		$self->ParseMemCtxPullEnd($e, $l, $ndr);
1205
1206		if ($l->{POINTER_TYPE} ne "ref") {
1207			if ($l->{POINTER_TYPE} eq "relative" or $l->{POINTER_TYPE} eq "relative_short") {
1208				$self->pidl("if ($ndr->offset > $ndr->relative_highest_offset) {");
1209				$self->indent;
1210				$self->pidl("$ndr->relative_highest_offset = $ndr->offset;");
1211				$self->deindent;
1212				$self->pidl("}");
1213				$self->pidl("$ndr->offset = _relative_save_offset;");
1214			}
1215			$self->deindent;
1216			$self->pidl("}");
1217		}
1218	} elsif ($l->{TYPE} eq "ARRAY" and
1219			not has_fast_array($e,$l) and not is_charset_array($e, $l)) {
1220		my $length = $array_length;
1221		my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
1222		my $array_name = $var_name;
1223
1224		if (not defined($length)) {
1225			$length = $self->ParseArrayPullGetLength($e, $l, $ndr, $var_name, $env);
1226		}
1227
1228		$var_name = get_array_element($var_name, $counter);
1229
1230		$self->ParseMemCtxPullStart($e, $l, $ndr, $array_name);
1231
1232		if (($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) {
1233			my $nl = GetNextLevel($e,$l);
1234
1235			if ($l->{IS_ZERO_TERMINATED}) {
1236				$self->CheckStringTerminator($ndr,$e,$l,$length);
1237			}
1238
1239			$self->pidl("for ($counter = 0; $counter < ($length); $counter++) {");
1240			$self->indent;
1241			$self->ParseElementPullLevel($e, $nl, $ndr, $var_name, $env, 1, 0);
1242			$self->deindent;
1243			$self->pidl("}");
1244		}
1245
1246		if ($deferred and ContainsDeferred($e, $l)) {
1247			$self->pidl("for ($counter = 0; $counter < ($length); $counter++) {");
1248			$self->defer("for ($counter = 0; $counter < ($length); $counter++) {");
1249			$self->defer_indent;
1250			$self->indent;
1251			$self->ParseElementPullLevel($e,GetNextLevel($e,$l), $ndr, $var_name, $env, 0, 1);
1252			$self->deindent;
1253			$self->defer_deindent;
1254			$self->pidl("}");
1255			$self->defer("}");
1256		}
1257
1258		$self->ParseMemCtxPullEnd($e, $l, $ndr);
1259
1260	} elsif ($l->{TYPE} eq "SWITCH") {
1261		my $nl = GetNextLevel($e,$l);
1262		my $needs_deferred_switch = is_deferred_switch_non_empty($nl);
1263
1264		# Avoid setting a switch value if it will not be
1265		# consumed again in the NDR_BUFFERS pull
1266		if ($needs_deferred_switch or !$deferred) {
1267			$self->ParseSwitchPull($e, $l, $ndr, $var_name, $env);
1268		}
1269		$self->ParseElementPullLevel($e, $nl, $ndr, $var_name, $env, $primitives, $deferred);
1270	}
1271}
1272
1273#####################################################################
1274# parse scalars in a structure element - pull size
1275sub ParseElementPull($$$$$$)
1276{
1277	my($self,$e,$ndr,$env,$primitives,$deferred) = @_;
1278
1279	my $var_name = $env->{$e->{NAME}};
1280	my $represent_name;
1281	my $transmit_name;
1282
1283	return if ContainsPipe($e, $e->{LEVELS}[0]);
1284
1285	return unless $primitives or ($deferred and ContainsDeferred($e, $e->{LEVELS}[0]));
1286
1287	if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
1288		$self->pidl("{");
1289		$self->indent;
1290		$represent_name = $var_name;
1291		$transmit_name = "_transmit_$e->{NAME}";
1292		$var_name = $transmit_name;
1293		$self->pidl(mapTypeName($e->{TYPE})." $var_name;");
1294	}
1295
1296	$var_name = append_prefix($e, $var_name);
1297
1298	$self->start_flags($e, $ndr);
1299
1300	$self->ParseElementPullLevel($e,$e->{LEVELS}[0],$ndr,$var_name,$env,$primitives,$deferred);
1301
1302	$self->end_flags($e, $ndr);
1303
1304	# Representation type is different from transmit_as
1305	if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
1306		$self->pidl("NDR_CHECK(ndr_$e->{TYPE}_to_$e->{REPRESENTATION_TYPE}($transmit_name, ".get_pointer_to($represent_name)."));");
1307		$self->deindent;
1308		$self->pidl("}");
1309	}
1310}
1311
1312#####################################################################
1313# parse a pointer in a struct element or function
1314sub ParsePtrPull($$$$$)
1315{
1316	my($self, $e,$l,$ndr,$var_name) = @_;
1317
1318	my $nl = GetNextLevel($e, $l);
1319	my $next_is_array = ($nl->{TYPE} eq "ARRAY");
1320	my $next_is_string = (($nl->{TYPE} eq "DATA") and
1321						 ($nl->{DATA_TYPE} eq "string"));
1322
1323	if ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "TOP") {
1324
1325		if (!$next_is_array and !$next_is_string) {
1326			$self->pidl("if ($ndr->flags & LIBNDR_FLAG_REF_ALLOC) {");
1327			$self->pidl("\tNDR_PULL_ALLOC($ndr, $var_name);");
1328			$self->pidl("}");
1329		}
1330
1331		return;
1332	} elsif ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "EMBEDDED") {
1333		$self->pidl("NDR_CHECK(ndr_pull_ref_ptr($ndr, &_ptr_$e->{NAME}));");
1334	} elsif (($l->{POINTER_TYPE} eq "unique") or
1335		 ($l->{POINTER_TYPE} eq "relative") or
1336		 ($l->{POINTER_TYPE} eq "full")) {
1337		$self->pidl("NDR_CHECK(ndr_pull_generic_ptr($ndr, &_ptr_$e->{NAME}));");
1338	} elsif ($l->{POINTER_TYPE} eq "relative_short") {
1339		$self->pidl("NDR_CHECK(ndr_pull_relative_ptr_short($ndr, &_ptr_$e->{NAME}));");
1340	} elsif ($l->{POINTER_TYPE} eq "ignore") {
1341                #We want to consume the pointer bytes, but ignore the pointer value
1342	        $self->pidl("NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &_ptr_$e->{NAME}));");
1343		$self->pidl("_ptr_$e->{NAME} = 0;");
1344	} else {
1345		die("Unhandled pointer type $l->{POINTER_TYPE}");
1346	}
1347
1348	$self->pidl("if (_ptr_$e->{NAME}) {");
1349	$self->indent;
1350
1351	if ($l->{POINTER_TYPE} eq "ignore") {
1352	        # Don't do anything, we don't want to do the
1353	        # allocation, as we forced it to NULL just above, and
1354	        # we may not know the declared type anyway.
1355	} else {
1356	        # Don't do this for arrays, they're allocated at the actual level
1357	        # of the array
1358	        unless ($next_is_array or $next_is_string) {
1359		       $self->pidl("NDR_PULL_ALLOC($ndr, $var_name);");
1360		} else {
1361		       # FIXME: Yes, this is nasty.
1362		       # We allocate an array twice
1363		       # - once just to indicate that it's there,
1364		       # - then the real allocation...
1365		       $self->pidl("NDR_PULL_ALLOC($ndr, $var_name);");
1366		}
1367	}
1368
1369	#$self->pidl("memset($var_name, 0, sizeof($var_name));");
1370	if ($l->{POINTER_TYPE} eq "relative" or $l->{POINTER_TYPE} eq "relative_short") {
1371		$self->pidl("NDR_CHECK(ndr_pull_relative_ptr1($ndr, $var_name, _ptr_$e->{NAME}));");
1372	}
1373	$self->deindent;
1374	$self->pidl("} else {");
1375	$self->pidl("\t$var_name = NULL;");
1376	$self->pidl("}");
1377}
1378
1379sub CheckRefPtrs($$$$)
1380{
1381	my ($self,$e,$ndr,$env) = @_;
1382
1383	return if ContainsPipe($e, $e->{LEVELS}[0]);
1384	return if ($e->{LEVELS}[0]->{TYPE} ne "POINTER");
1385	return if ($e->{LEVELS}[0]->{POINTER_TYPE} ne "ref");
1386
1387	my $var_name = $env->{$e->{NAME}};
1388	$var_name = append_prefix($e, $var_name);
1389
1390	$self->pidl("if ($var_name == NULL) {");
1391	$self->indent;
1392	$self->pidl("return ndr_push_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL [ref] pointer\");");
1393	$self->deindent;
1394	$self->pidl("}");
1395}
1396
1397sub ParseStructPushPrimitives($$$$$)
1398{
1399	my ($self, $struct, $ndr, $varname, $env) = @_;
1400
1401	$self->CheckRefPtrs($_, $ndr, $env) foreach (@{$struct->{ELEMENTS}});
1402
1403	# see if the structure contains a conformant array. If it
1404	# does, then it must be the last element of the structure, and
1405	# we need to push the conformant length early, as it fits on
1406	# the wire before the structure (and even before the structure
1407	# alignment)
1408	if (defined($struct->{SURROUNDING_ELEMENT})) {
1409		my $e = $struct->{SURROUNDING_ELEMENT};
1410
1411		if (defined($e->{LEVELS}[0]) and
1412			$e->{LEVELS}[0]->{TYPE} eq "ARRAY") {
1413			my $size;
1414
1415			if ($e->{LEVELS}[0]->{IS_ZERO_TERMINATED}) {
1416				if (has_property($e, "charset")) {
1417					$size = "ndr_charset_length($varname->$e->{NAME}, CH_$e->{PROPERTIES}->{charset})";
1418				} else {
1419					$size = "ndr_string_length($varname->$e->{NAME}, sizeof(*$varname->$e->{NAME}))";
1420				}
1421				if (defined($e->{LEVELS}[0]->{SIZE_IS})) {
1422					$size = ParseExpr($e->{LEVELS}[0]->{SIZE_IS}, $env, $e->{ORIGINAL});
1423				}
1424			} else {
1425				$size = ParseExpr($e->{LEVELS}[0]->{SIZE_IS}, $env, $e->{ORIGINAL});
1426			}
1427
1428			$self->pidl("NDR_CHECK(ndr_push_uint3264($ndr, NDR_SCALARS, $size));");
1429		} else {
1430			$self->pidl("NDR_CHECK(ndr_push_uint3264($ndr, NDR_SCALARS, ndr_string_array_size($ndr, $varname->$e->{NAME})));");
1431		}
1432	}
1433
1434	$self->pidl("NDR_CHECK(ndr_push_align($ndr, $struct->{ALIGN}));");
1435
1436	if (defined($struct->{PROPERTIES}{relative_base})) {
1437		# set the current offset as base for relative pointers
1438		# and store it based on the toplevel struct/union
1439		$self->pidl("NDR_CHECK(ndr_push_setup_relative_base_offset1($ndr, $varname, $ndr->offset));");
1440	}
1441
1442	$self->ParseElementPush($_, $ndr, $env, 1, 0) foreach (@{$struct->{ELEMENTS}});
1443
1444	$self->pidl("NDR_CHECK(ndr_push_trailer_align($ndr, $struct->{ALIGN}));");
1445}
1446
1447sub ParseStructPushDeferred($$$$)
1448{
1449	my ($self, $struct, $ndr, $varname, $env) = @_;
1450	if (defined($struct->{PROPERTIES}{relative_base})) {
1451		# retrieve the current offset as base for relative pointers
1452		# based on the toplevel struct/union
1453		$self->pidl("NDR_CHECK(ndr_push_setup_relative_base_offset2($ndr, $varname));");
1454	}
1455	$self->ParseElementPush($_, $ndr, $env, 0, 1) foreach (@{$struct->{ELEMENTS}});
1456}
1457
1458#####################################################################
1459# parse a struct
1460sub ParseStructPush($$$$)
1461{
1462	my ($self, $struct, $ndr, $varname) = @_;
1463
1464	return unless defined($struct->{ELEMENTS});
1465
1466	my $env = GenerateStructEnv($struct, $varname);
1467
1468	EnvSubstituteValue($env, $struct);
1469
1470	$self->DeclareArrayVariablesNoZero($_, $env) foreach (@{$struct->{ELEMENTS}});
1471
1472	$self->start_flags($struct, $ndr);
1473
1474	$self->pidl("NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);");
1475	$self->pidl("if (ndr_flags & NDR_SCALARS) {");
1476	$self->indent;
1477	$self->ParseStructPushPrimitives($struct, $ndr, $varname, $env);
1478	$self->deindent;
1479	$self->pidl("}");
1480
1481	$self->pidl("if (ndr_flags & NDR_BUFFERS) {");
1482	$self->indent;
1483	$self->ParseStructPushDeferred($struct, $ndr, $varname, $env);
1484	$self->deindent;
1485	$self->pidl("}");
1486
1487	$self->end_flags($struct, $ndr);
1488}
1489
1490#####################################################################
1491# generate a push function for an enum
1492sub ParseEnumPush($$$$)
1493{
1494	my($self,$enum,$ndr,$varname) = @_;
1495	my($type_fn) = $enum->{BASE_TYPE};
1496
1497	$self->start_flags($enum, $ndr);
1498	$self->pidl("NDR_CHECK(ndr_push_enum_$type_fn($ndr, NDR_SCALARS, $varname));");
1499	$self->end_flags($enum, $ndr);
1500}
1501
1502#####################################################################
1503# generate a pull function for an enum
1504sub ParseEnumPull($$$$)
1505{
1506	my($self,$enum,$ndr,$varname) = @_;
1507	my($type_fn) = $enum->{BASE_TYPE};
1508	my($type_v_decl) = mapTypeName($type_fn);
1509
1510	$self->pidl("$type_v_decl v;");
1511	$self->start_flags($enum, $ndr);
1512	$self->pidl("NDR_CHECK(ndr_pull_enum_$type_fn($ndr, NDR_SCALARS, &v));");
1513	$self->pidl("*$varname = v;");
1514
1515	$self->end_flags($enum, $ndr);
1516}
1517
1518#####################################################################
1519# generate a print function for an enum
1520sub ParseEnumPrint($$$$$)
1521{
1522	my($self,$enum,$ndr,$name,$varname) = @_;
1523
1524	$self->pidl("const char *val = NULL;");
1525	$self->pidl("");
1526
1527	$self->start_flags($enum, $ndr);
1528
1529	$self->pidl("switch ($varname) {");
1530	$self->indent;
1531	my $els = \@{$enum->{ELEMENTS}};
1532	foreach my $i (0 .. $#{$els}) {
1533		my $e = ${$els}[$i];
1534		chomp $e;
1535		if ($e =~ /^(.*)=/) {
1536			$e = $1;
1537		}
1538		$self->pidl("case $e: val = \"$e\"; break;");
1539	}
1540
1541	$self->deindent;
1542	$self->pidl("}");
1543
1544	$self->pidl("ndr_print_enum($ndr, name, \"$enum->{TYPE}\", val, $varname);");
1545
1546	$self->end_flags($enum, $ndr);
1547}
1548
1549sub DeclEnum($$$$)
1550{
1551	my ($e,$t,$name,$varname) = @_;
1552	return "enum $name " .
1553		($t eq "pull"?"*":"") . $varname;
1554}
1555
1556$typefamily{ENUM} = {
1557	DECL => \&DeclEnum,
1558	PUSH_FN_BODY => \&ParseEnumPush,
1559	PULL_FN_BODY => \&ParseEnumPull,
1560	PRINT_FN_BODY => \&ParseEnumPrint,
1561};
1562
1563#####################################################################
1564# generate a push function for a bitmap
1565sub ParseBitmapPush($$$$)
1566{
1567	my($self,$bitmap,$ndr,$varname) = @_;
1568	my($type_fn) = $bitmap->{BASE_TYPE};
1569
1570	$self->start_flags($bitmap, $ndr);
1571
1572	$self->pidl("NDR_CHECK(ndr_push_$type_fn($ndr, NDR_SCALARS, $varname));");
1573
1574	$self->end_flags($bitmap, $ndr);
1575}
1576
1577#####################################################################
1578# generate a pull function for an bitmap
1579sub ParseBitmapPull($$$$)
1580{
1581	my($self,$bitmap,$ndr,$varname) = @_;
1582	my $type_fn = $bitmap->{BASE_TYPE};
1583	my($type_decl) = mapTypeName($bitmap->{BASE_TYPE});
1584
1585	$self->pidl("$type_decl v;");
1586	$self->start_flags($bitmap, $ndr);
1587	$self->pidl("NDR_CHECK(ndr_pull_$type_fn($ndr, NDR_SCALARS, &v));");
1588	$self->pidl("*$varname = v;");
1589
1590	$self->end_flags($bitmap, $ndr);
1591}
1592
1593#####################################################################
1594# generate a print function for an bitmap
1595sub ParseBitmapPrintElement($$$$$$)
1596{
1597	my($self,$e,$bitmap,$ndr,$name,$varname) = @_;
1598	my($type_decl) = mapTypeName($bitmap->{BASE_TYPE});
1599	my($type_fn) = $bitmap->{BASE_TYPE};
1600	my($flag);
1601
1602	if ($e =~ /^(\w+) .*$/) {
1603		$flag = "$1";
1604	} else {
1605		die "Bitmap: \"$name\" invalid Flag: \"$e\"";
1606	}
1607
1608	$self->pidl("ndr_print_bitmap_flag($ndr, sizeof($type_decl), \"$flag\", $flag, $varname);");
1609}
1610
1611#####################################################################
1612# generate a print function for an bitmap
1613sub ParseBitmapPrint($$$$$)
1614{
1615	my($self,$bitmap,$ndr,$name,$varname) = @_;
1616	my($type_decl) = mapTypeName($bitmap->{TYPE});
1617	my($type_fn) = $bitmap->{BASE_TYPE};
1618
1619	$self->start_flags($bitmap, $ndr);
1620
1621	$self->pidl("ndr_print_$type_fn($ndr, name, $varname);");
1622
1623	$self->pidl("$ndr->depth++;");
1624	foreach my $e (@{$bitmap->{ELEMENTS}}) {
1625		$self->ParseBitmapPrintElement($e, $bitmap, $ndr, $name, $varname);
1626	}
1627	$self->pidl("$ndr->depth--;");
1628
1629	$self->end_flags($bitmap, $ndr);
1630}
1631
1632sub DeclBitmap($$$$)
1633{
1634	my ($e,$t,$name,$varname) = @_;
1635	return mapTypeName(Parse::Pidl::Typelist::bitmap_type_fn($e)) .
1636		($t eq "pull"?" *":" ") . $varname;
1637}
1638
1639$typefamily{BITMAP} = {
1640	DECL => \&DeclBitmap,
1641	PUSH_FN_BODY => \&ParseBitmapPush,
1642	PULL_FN_BODY => \&ParseBitmapPull,
1643	PRINT_FN_BODY => \&ParseBitmapPrint,
1644};
1645
1646#####################################################################
1647# generate a struct print function
1648sub ParseStructPrint($$$$$)
1649{
1650	my($self,$struct,$ndr,$name,$varname) = @_;
1651
1652	return unless defined $struct->{ELEMENTS};
1653
1654	my $env = GenerateStructEnv($struct, $varname);
1655
1656	$self->DeclareArrayVariables($_) foreach (@{$struct->{ELEMENTS}});
1657
1658	$self->pidl("ndr_print_struct($ndr, name, \"$name\");");
1659	$self->pidl("if (r == NULL) { ndr_print_null($ndr); return; }");
1660
1661	$self->start_flags($struct, $ndr);
1662
1663	$self->pidl("$ndr->depth++;");
1664
1665	$self->ParseElementPrint($_, $ndr, $env->{$_->{NAME}}, $env)
1666		foreach (@{$struct->{ELEMENTS}});
1667	$self->pidl("$ndr->depth--;");
1668
1669	$self->end_flags($struct, $ndr);
1670}
1671
1672sub DeclarePtrVariables($$)
1673{
1674	my ($self,$e) = @_;
1675
1676	if (has_property($e, "skip") or has_property($e, "skip_noinit")) {
1677		return;
1678	}
1679
1680	foreach my $l (@{$e->{LEVELS}}) {
1681		my $size = 32;
1682		if ($l->{TYPE} eq "POINTER" and
1683			not ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "TOP")) {
1684			if ($l->{POINTER_TYPE} eq "relative_short") {
1685				$size = 16;
1686			}
1687			$self->pidl("uint${size}_t _ptr_$e->{NAME};");
1688			last;
1689		}
1690	}
1691}
1692
1693sub DeclareArrayVariables($$;$)
1694{
1695	my ($self,$e,$pull) = @_;
1696
1697	if (has_property($e, "skip") or has_property($e, "skip_noinit")) {
1698		return;
1699	}
1700
1701	foreach my $l (@{$e->{LEVELS}}) {
1702		next if ($l->{TYPE} ne "ARRAY");
1703		if (defined($pull)) {
1704			$self->pidl("uint32_t size_$e->{NAME}_$l->{LEVEL_INDEX} = 0;");
1705			if ($l->{IS_VARYING}) {
1706				$self->pidl("uint32_t length_$e->{NAME}_$l->{LEVEL_INDEX} = 0;");
1707			}
1708		}
1709		next if has_fast_array($e,$l);
1710		next if is_charset_array($e,$l);
1711		$self->pidl("uint32_t cntr_$e->{NAME}_$l->{LEVEL_INDEX};");
1712	}
1713}
1714
1715sub DeclareArrayVariablesNoZero($$$)
1716{
1717	my ($self,$e,$env) = @_;
1718
1719	if (has_property($e, "skip") or has_property($e, "skip_noinit")) {
1720		return;
1721	}
1722
1723	foreach my $l (@{$e->{LEVELS}}) {
1724		next if ($l->{TYPE} ne "ARRAY");
1725		next if has_fast_array($e,$l);
1726		next if is_charset_array($e,$l);
1727		my $length = ParseExpr($l->{LENGTH_IS}, $env, $e->{ORIGINAL});
1728		if ($length eq "0") {
1729			warning($e->{ORIGINAL}, "pointless array cntr: 'cntr_$e->{NAME}_$l->{LEVEL_INDEX}': length=$length");
1730		} else {
1731			$self->pidl("uint32_t cntr_$e->{NAME}_$l->{LEVEL_INDEX};");
1732		}
1733	}
1734}
1735
1736sub DeclareMemCtxVariables($$)
1737{
1738	my ($self,$e) = @_;
1739
1740	if (has_property($e, "skip") or has_property($e, "skip_noinit")) {
1741		return;
1742	}
1743
1744	foreach my $l (@{$e->{LEVELS}}) {
1745		my $mem_flags = $self->ParseMemCtxPullFlags($e, $l);
1746
1747		if (($l->{TYPE} eq "POINTER") and ($l->{POINTER_TYPE} eq "ignore")) {
1748			last;
1749		}
1750
1751		if (defined($mem_flags)) {
1752			$self->pidl("TALLOC_CTX *_mem_save_$e->{NAME}_$l->{LEVEL_INDEX} = NULL;");
1753		}
1754	}
1755}
1756
1757sub ParseStructPullPrimitives($$$$$)
1758{
1759	my($self,$struct,$ndr,$varname,$env) = @_;
1760
1761	if (defined $struct->{SURROUNDING_ELEMENT}) {
1762		$self->pidl("NDR_CHECK(ndr_pull_array_size($ndr, &$varname->$struct->{SURROUNDING_ELEMENT}->{NAME}));");
1763	}
1764
1765	$self->pidl("NDR_CHECK(ndr_pull_align($ndr, $struct->{ALIGN}));");
1766
1767	if (defined($struct->{PROPERTIES}{relative_base})) {
1768		# set the current offset as base for relative pointers
1769		# and store it based on the toplevel struct/union
1770		$self->pidl("NDR_CHECK(ndr_pull_setup_relative_base_offset1($ndr, $varname, $ndr->offset));");
1771	}
1772
1773	$self->ParseElementPull($_, $ndr, $env, 1, 0) foreach (@{$struct->{ELEMENTS}});
1774
1775	$self->add_deferred();
1776
1777	$self->pidl("NDR_CHECK(ndr_pull_trailer_align($ndr, $struct->{ALIGN}));");
1778}
1779
1780sub ParseStructPullDeferred($$$$$)
1781{
1782	my ($self,$struct,$ndr,$varname,$env) = @_;
1783
1784	if (defined($struct->{PROPERTIES}{relative_base})) {
1785		# retrieve the current offset as base for relative pointers
1786		# based on the toplevel struct/union
1787		$self->pidl("NDR_CHECK(ndr_pull_setup_relative_base_offset2($ndr, $varname));");
1788	}
1789	foreach my $e (@{$struct->{ELEMENTS}}) {
1790		$self->ParseElementPull($e, $ndr, $env, 0, 1);
1791	}
1792
1793	$self->add_deferred();
1794}
1795
1796#####################################################################
1797# parse a struct - pull side
1798sub ParseStructPull($$$$)
1799{
1800	my($self,$struct,$ndr,$varname) = @_;
1801
1802	return unless defined $struct->{ELEMENTS};
1803
1804	# declare any internal pointers we need
1805	foreach my $e (@{$struct->{ELEMENTS}}) {
1806		$self->DeclarePtrVariables($e);
1807		$self->DeclareArrayVariables($e, "pull");
1808		$self->DeclareMemCtxVariables($e);
1809	}
1810
1811	$self->start_flags($struct, $ndr);
1812
1813	my $env = GenerateStructEnv($struct, $varname);
1814
1815	$self->pidl("NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);");
1816	$self->pidl("if (ndr_flags & NDR_SCALARS) {");
1817	$self->indent;
1818	$self->ParseStructPullPrimitives($struct,$ndr,$varname,$env);
1819	$self->deindent;
1820	$self->pidl("}");
1821	$self->pidl("if (ndr_flags & NDR_BUFFERS) {");
1822	$self->indent;
1823	$self->ParseStructPullDeferred($struct,$ndr,$varname,$env);
1824	$self->deindent;
1825	$self->pidl("}");
1826
1827	$self->end_flags($struct, $ndr);
1828}
1829
1830#####################################################################
1831# calculate size of ndr struct
1832sub ParseStructNdrSize($$$$)
1833{
1834	my ($self,$t, $name, $varname) = @_;
1835	my $sizevar;
1836
1837	if (my $flags = has_property($t, "flag")) {
1838		$self->pidl("flags |= $flags;");
1839	}
1840	$self->pidl("return ndr_size_struct($varname, flags, (ndr_push_flags_fn_t)ndr_push_$name);");
1841}
1842
1843sub DeclStruct($$$$)
1844{
1845	my ($e,$t,$name,$varname) = @_;
1846	if ($t eq "base") {
1847	        return "struct $name $varname";
1848	}
1849	return ($t ne "pull"?"const ":"") . "struct $name *$varname";
1850}
1851
1852sub ArgsStructNdrSize($$$)
1853{
1854	my ($d, $name, $varname) = @_;
1855	return "const struct $name *$varname, int flags";
1856}
1857
1858$typefamily{STRUCT} = {
1859	PUSH_FN_BODY => \&ParseStructPush,
1860	DECL => \&DeclStruct,
1861	PULL_FN_BODY => \&ParseStructPull,
1862	PRINT_FN_BODY => \&ParseStructPrint,
1863	SIZE_FN_BODY => \&ParseStructNdrSize,
1864	SIZE_FN_ARGS => \&ArgsStructNdrSize,
1865};
1866
1867#####################################################################
1868# calculate size of ndr struct
1869sub ParseUnionNdrSize($$$)
1870{
1871	my ($self, $t, $name, $varname) = @_;
1872	my $sizevar;
1873
1874	if (my $flags = has_property($t, "flag")) {
1875		$self->pidl("flags |= $flags;");
1876	}
1877
1878	$self->pidl("return ndr_size_union($varname, flags, level, (ndr_push_flags_fn_t)ndr_push_$name);");
1879}
1880
1881sub ParseUnionPushPrimitives($$$$)
1882{
1883	my ($self, $e, $ndr ,$varname) = @_;
1884
1885	my $have_default = 0;
1886
1887	if (defined($e->{SWITCH_TYPE})) {
1888		if (defined($e->{ALIGN})) {
1889			$self->pidl("NDR_CHECK(ndr_push_union_align($ndr, $e->{ALIGN}));");
1890		}
1891
1892		$self->pidl("NDR_CHECK(ndr_push_$e->{SWITCH_TYPE}($ndr, NDR_SCALARS, level));");
1893	}
1894
1895	if (defined($e->{ALIGN})) {
1896		if ($e->{IS_MS_UNION}) {
1897			$self->pidl("/* ms_union is always aligned to the largest union arm*/");
1898			$self->pidl("NDR_CHECK(ndr_push_align($ndr, $e->{ALIGN}));");
1899		} else {
1900			$self->pidl("NDR_CHECK(ndr_push_union_align($ndr, $e->{ALIGN}));");
1901		}
1902	}
1903
1904	$self->pidl("switch (level) {");
1905	$self->indent;
1906	foreach my $el (@{$e->{ELEMENTS}}) {
1907		if ($el->{CASE} eq "default") {
1908			$have_default = 1;
1909		}
1910		$self->pidl("$el->{CASE}: {");
1911
1912		if ($el->{TYPE} ne "EMPTY") {
1913			$self->indent;
1914			if (defined($e->{PROPERTIES}{relative_base})) {
1915				$self->pidl("NDR_CHECK(ndr_push_align($ndr, $el->{ALIGN}));");
1916				# set the current offset as base for relative pointers
1917				# and store it based on the toplevel struct/union
1918				$self->pidl("NDR_CHECK(ndr_push_setup_relative_base_offset1($ndr, $varname, $ndr->offset));");
1919			}
1920			$self->DeclareArrayVariables($el);
1921			my $el_env = {$el->{NAME} => "$varname->$el->{NAME}"};
1922			$self->CheckRefPtrs($el, $ndr, $el_env);
1923			$self->ParseElementPush($el, $ndr, $el_env, 1, 0);
1924			$self->deindent;
1925		}
1926		$self->pidl("break; }");
1927		$self->pidl("");
1928	}
1929	if (! $have_default) {
1930		$self->pidl("default:");
1931		$self->pidl("\treturn ndr_push_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);");
1932	}
1933	$self->deindent;
1934	$self->pidl("}");
1935}
1936
1937sub ParseUnionPushDeferred($$$$)
1938{
1939	my ($self,$e,$ndr,$varname) = @_;
1940
1941	my $have_default = 0;
1942
1943	if (defined($e->{PROPERTIES}{relative_base})) {
1944		# retrieve the current offset as base for relative pointers
1945		# based on the toplevel struct/union
1946		$self->pidl("NDR_CHECK(ndr_push_setup_relative_base_offset2($ndr, $varname));");
1947	}
1948	$self->pidl("switch (level) {");
1949	$self->indent;
1950	foreach my $el (@{$e->{ELEMENTS}}) {
1951		if ($el->{CASE} eq "default") {
1952			$have_default = 1;
1953		}
1954
1955		$self->pidl("$el->{CASE}:");
1956		if ($el->{TYPE} ne "EMPTY") {
1957			$self->indent;
1958			$self->ParseElementPush($el, $ndr, {$el->{NAME} => "$varname->$el->{NAME}"}, 0, 1);
1959			$self->deindent;
1960		}
1961		$self->pidl("break;");
1962		$self->pidl("");
1963	}
1964	if (! $have_default) {
1965		$self->pidl("default:");
1966		$self->pidl("\treturn ndr_push_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);");
1967	}
1968	$self->deindent;
1969	$self->pidl("}");
1970}
1971
1972#####################################################################
1973# parse a union - push side
1974sub ParseUnionPush($$$$)
1975{
1976	my ($self,$e,$ndr,$varname) = @_;
1977	my $have_default = 0;
1978
1979	$self->pidl("uint32_t level;");
1980	$self->start_flags($e, $ndr);
1981
1982	$self->pidl("NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);");
1983	$self->pidl("if (ndr_flags & NDR_SCALARS) {");
1984	$self->indent;
1985	$self->pidl("/* This token is not used again (except perhaps below in the NDR_BUFFERS case) */");
1986	$self->pidl("NDR_CHECK(ndr_push_steal_switch_value($ndr, $varname, &level));");
1987
1988	$self->ParseUnionPushPrimitives($e, $ndr, $varname);
1989	$self->deindent;
1990	$self->pidl("}");
1991        if (is_deferred_switch_non_empty($e)) {
1992                $self->pidl("if (ndr_flags & NDR_BUFFERS) {");
1993                $self->indent;
1994                # In case we had ndr_flags of NDR_SCALERS|NDR_BUFFERS
1995                $self->pidl("if (!(ndr_flags & NDR_SCALARS)) {");
1996                $self->indent;
1997                $self->pidl("/* We didn't get it above, and the token is not needed after this. */");
1998                $self->pidl("NDR_CHECK(ndr_push_steal_switch_value($ndr, $varname, &level));");
1999                $self->deindent;
2000                $self->pidl("}");
2001                $self->ParseUnionPushDeferred($e, $ndr, $varname);
2002                $self->deindent;
2003                $self->pidl("}");
2004        }
2005	$self->end_flags($e, $ndr);
2006}
2007
2008#####################################################################
2009# print a union
2010sub ParseUnionPrint($$$$$)
2011{
2012	my ($self,$e,$ndr,$name,$varname) = @_;
2013	my $have_default = 0;
2014
2015	$self->pidl("uint32_t level;");
2016	foreach my $el (@{$e->{ELEMENTS}}) {
2017		$self->DeclareArrayVariables($el);
2018	}
2019
2020	$self->start_flags($e, $ndr);
2021
2022	$self->pidl("level = ndr_print_steal_switch_value($ndr, $varname);");
2023
2024	$self->pidl("ndr_print_union($ndr, name, level, \"$name\");");
2025
2026	$self->pidl("switch (level) {");
2027	$self->indent;
2028	foreach my $el (@{$e->{ELEMENTS}}) {
2029		if ($el->{CASE} eq "default") {
2030			$have_default = 1;
2031		}
2032		$self->pidl("$el->{CASE}:");
2033		if ($el->{TYPE} ne "EMPTY") {
2034			$self->indent;
2035			$self->ParseElementPrint($el, $ndr, "$varname->$el->{NAME}", {});
2036			$self->deindent;
2037		}
2038		$self->pidl("break;");
2039		$self->pidl("");
2040	}
2041	if (! $have_default) {
2042		$self->pidl("default:");
2043		$self->pidl("\tndr_print_bad_level($ndr, name, level);");
2044	}
2045	$self->deindent;
2046	$self->pidl("}");
2047
2048	$self->end_flags($e, $ndr);
2049}
2050
2051sub ParseUnionPullPrimitives($$$$$)
2052{
2053	my ($self,$e,$ndr,$varname,$switch_type) = @_;
2054	my $have_default = 0;
2055
2056
2057	if (defined($switch_type)) {
2058		if (defined($e->{ALIGN})) {
2059			$self->pidl("NDR_CHECK(ndr_pull_union_align($ndr, $e->{ALIGN}));");
2060		}
2061
2062		$self->pidl("NDR_CHECK(ndr_pull_$switch_type($ndr, NDR_SCALARS, &_level));");
2063		$self->pidl("if (_level != level) {");
2064		$self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value %u for $varname at \%s\", _level, __location__);");
2065		$self->pidl("}");
2066	}
2067
2068	if (defined($e->{ALIGN})) {
2069		if ($e->{IS_MS_UNION}) {
2070			$self->pidl("/* ms_union is always aligned to the largest union arm*/");
2071			$self->pidl("NDR_CHECK(ndr_pull_align($ndr, $e->{ALIGN}));");
2072		} else {
2073			$self->pidl("NDR_CHECK(ndr_pull_union_align($ndr, $e->{ALIGN}));");
2074		}
2075	}
2076
2077	$self->pidl("switch (level) {");
2078	$self->indent;
2079	foreach my $el (@{$e->{ELEMENTS}}) {
2080		if ($el->{CASE} eq "default") {
2081			$have_default = 1;
2082		}
2083		$self->pidl("$el->{CASE}: {");
2084
2085		if ($el->{TYPE} ne "EMPTY") {
2086			$self->indent;
2087			if (defined($e->{PROPERTIES}{relative_base})) {
2088				$self->pidl("NDR_CHECK(ndr_pull_align($ndr, $el->{ALIGN}));");
2089				# set the current offset as base for relative pointers
2090				# and store it based on the toplevel struct/union
2091				$self->pidl("NDR_CHECK(ndr_pull_setup_relative_base_offset1($ndr, $varname, $ndr->offset));");
2092			}
2093			$self->ParseElementPull($el, $ndr, {$el->{NAME} => "$varname->$el->{NAME}"}, 1, 0);
2094			$self->deindent;
2095		}
2096		$self->pidl("break; }");
2097		$self->pidl("");
2098	}
2099	if (! $have_default) {
2100		$self->pidl("default:");
2101		$self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u at \%s\", level, __location__);");
2102	}
2103	$self->deindent;
2104	$self->pidl("}");
2105}
2106
2107sub ParseUnionPullDeferred($$$$)
2108{
2109	my ($self,$e,$ndr,$varname) = @_;
2110	my $have_default = 0;
2111
2112	$self->pidl("switch (level) {");
2113	$self->indent;
2114	foreach my $el (@{$e->{ELEMENTS}}) {
2115		if ($el->{CASE} eq "default") {
2116			$have_default = 1;
2117		}
2118
2119		$self->pidl("$el->{CASE}:");
2120		if ($el->{TYPE} ne "EMPTY") {
2121			$self->indent;
2122			if (defined($e->{PROPERTIES}{relative_base})) {
2123				# retrieve the current offset as base for relative pointers
2124				# based on the toplevel struct/union
2125				$self->pidl("NDR_CHECK(ndr_pull_setup_relative_base_offset2($ndr, $varname));");
2126			}
2127			$self->ParseElementPull($el, $ndr, {$el->{NAME} => "$varname->$el->{NAME}"}, 0, 1);
2128			$self->deindent;
2129		}
2130		$self->pidl("break;");
2131		$self->pidl("");
2132	}
2133	if (! $have_default) {
2134		$self->pidl("default:");
2135		$self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u at \%s\", level, __location__);");
2136	}
2137	$self->deindent;
2138	$self->pidl("}");
2139
2140
2141}
2142
2143#####################################################################
2144# parse a union - pull side
2145sub ParseUnionPull($$$$)
2146{
2147	my ($self,$e,$ndr,$varname) = @_;
2148	my $switch_type = $e->{SWITCH_TYPE};
2149        my $needs_deferred_switch = is_deferred_switch_non_empty($e);
2150	$self->pidl("uint32_t level;");
2151	if (defined($switch_type)) {
2152		if (Parse::Pidl::Typelist::typeIs($switch_type, "ENUM")) {
2153			$switch_type = Parse::Pidl::Typelist::enum_type_fn(getType($switch_type)->{DATA});
2154		}
2155		$self->pidl(mapTypeName($switch_type) . " _level;");
2156	}
2157
2158	my %double_cases = ();
2159	foreach my $el (@{$e->{ELEMENTS}}) {
2160		next if ($el->{TYPE} eq "EMPTY");
2161		next if ($double_cases{"$el->{NAME}"});
2162		$self->DeclareMemCtxVariables($el);
2163		$self->DeclarePtrVariables($el);
2164		$self->DeclareArrayVariables($el, "pull");
2165		$double_cases{"$el->{NAME}"} = 1;
2166	}
2167
2168	$self->start_flags($e, $ndr);
2169
2170	$self->pidl("NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);");
2171	$self->pidl("if (ndr_flags & NDR_SCALARS) {");
2172	$self->indent;
2173	$self->pidl("/* This token is not used again (except perhaps below in the NDR_BUFFERS case) */");
2174	$self->pidl("NDR_CHECK(ndr_pull_steal_switch_value($ndr, $varname, &level));");
2175	$self->ParseUnionPullPrimitives($e,$ndr,$varname,$switch_type);
2176	$self->deindent;
2177	$self->pidl("}");
2178	if ($needs_deferred_switch) {
2179		$self->pidl("if (ndr_flags & NDR_BUFFERS) {");
2180		$self->indent;
2181		# In case we had ndr_flags of NDR_SCALERS|NDR_BUFFERS
2182		$self->pidl("if (!(ndr_flags & NDR_SCALARS)) {");
2183		$self->indent;
2184		$self->pidl("/* We didn't get it above, and the token is not needed after this. */");
2185		$self->pidl("NDR_CHECK(ndr_pull_steal_switch_value($ndr, $varname, &level));");
2186		$self->deindent;
2187		$self->pidl("}");
2188		$self->ParseUnionPullDeferred($e,$ndr,$varname);
2189		$self->deindent;
2190		$self->pidl("}");
2191	}
2192	$self->add_deferred();
2193
2194	$self->end_flags($e, $ndr);
2195}
2196
2197sub DeclUnion($$$$)
2198{
2199	my ($e,$t,$name,$varname) = @_;
2200	if ($t eq "base") {
2201	        return "union $name $varname";
2202	}
2203	return ($t ne "pull"?"const ":"") . "union $name *$varname";
2204}
2205
2206sub ArgsUnionNdrSize($$)
2207{
2208	my ($d,$name) = @_;
2209	return "const union $name *r, uint32_t level, int flags";
2210}
2211
2212$typefamily{UNION} = {
2213	PUSH_FN_BODY => \&ParseUnionPush,
2214	DECL => \&DeclUnion,
2215	PULL_FN_BODY => \&ParseUnionPull,
2216	PRINT_FN_BODY => \&ParseUnionPrint,
2217	SIZE_FN_ARGS => \&ArgsUnionNdrSize,
2218	SIZE_FN_BODY => \&ParseUnionNdrSize,
2219};
2220
2221#####################################################################
2222# parse a typedef - push side
2223sub ParseTypedefPush($$$$)
2224{
2225	my($self,$e,$ndr,$varname) = @_;
2226
2227	my $env;
2228
2229	$env->{$e->{NAME}} = $varname;
2230
2231	$self->ParseElementPushLevel($e, $e->{LEVELS}[0], $ndr, $varname, $env, 1, 1);
2232}
2233
2234#####################################################################
2235# parse a typedef - pull side
2236sub ParseTypedefPull($$$$)
2237{
2238	my($self,$e,$ndr,$varname) = @_;
2239
2240	my $env;
2241
2242	$env->{$e->{NAME}} = $varname;
2243
2244	$self->ParseElementPullLevel($e, $e->{LEVELS}[0], $ndr, $varname, $env, 1, 1);
2245}
2246
2247#####################################################################
2248# parse a typedef - print side
2249sub ParseTypedefPrint($$$$$)
2250{
2251	my($self,$e,$ndr,$name,$varname) = @_;
2252
2253	$typefamily{$e->{DATA}->{TYPE}}->{PRINT_FN_BODY}->($self, $e->{DATA}, $ndr, $name, $varname);
2254}
2255
2256#####################################################################
2257## calculate the size of a structure
2258sub ParseTypedefNdrSize($$$$)
2259{
2260	my($self,$t,$name,$varname) = @_;
2261
2262	$typefamily{$t->{DATA}->{TYPE}}->{SIZE_FN_BODY}->($self, $t->{DATA}, $name, $varname);
2263}
2264
2265sub DeclTypedef($$$$)
2266{
2267	my ($e, $t, $name, $varname) = @_;
2268
2269	return $typefamily{$e->{DATA}->{TYPE}}->{DECL}->($e->{DATA}, $t, $name, $varname);
2270}
2271
2272sub ArgsTypedefNdrSize($$$)
2273{
2274	my ($d, $name, $varname) = @_;
2275	return $typefamily{$d->{DATA}->{TYPE}}->{SIZE_FN_ARGS}->($d->{DATA}, $name, $varname);
2276}
2277
2278$typefamily{TYPEDEF} = {
2279	PUSH_FN_BODY => \&ParseTypedefPush,
2280	DECL => \&DeclTypedef,
2281	PULL_FN_BODY => \&ParseTypedefPull,
2282	PRINT_FN_BODY => \&ParseTypedefPrint,
2283	SIZE_FN_ARGS => \&ArgsTypedefNdrSize,
2284	SIZE_FN_BODY => \&ParseTypedefNdrSize,
2285};
2286
2287sub ParsePipePushChunk($$)
2288{
2289	my ($self, $t) = @_;
2290
2291	my $pipe = $t;
2292	$pipe = $t->{DATA} if ($t->{TYPE} eq "TYPEDEF");
2293	my $struct = $pipe->{DATA};
2294
2295	my $name = "$struct->{NAME}";
2296	my $ndr = "ndr";
2297	my $varname = "r";
2298
2299	my $args = $typefamily{$struct->{TYPE}}->{DECL}->($struct, "push", $name, $varname);
2300
2301	$self->fn_declare("push", $struct, "enum ndr_err_code ndr_push_$name(struct ndr_push *$ndr, int ndr_flags, $args)") or return;
2302
2303	return if has_property($t, "nopush");
2304
2305	$self->pidl("{");
2306	$self->indent;
2307
2308	$self->ParseStructPush($struct, $ndr, $varname);
2309	$self->pidl("");
2310
2311	$self->pidl("NDR_CHECK(ndr_push_pipe_chunk_trailer(ndr, ndr_flags, $varname->count));");
2312	$self->pidl("");
2313
2314	$self->pidl("return NDR_ERR_SUCCESS;");
2315	$self->deindent;
2316	$self->pidl("}");
2317	$self->pidl("");
2318}
2319
2320sub ParsePipePullChunk($$)
2321{
2322	my ($self, $t) = @_;
2323
2324	my $pipe = $t;
2325	$pipe = $t->{DATA} if ($t->{TYPE} eq "TYPEDEF");
2326	my $struct = $pipe->{DATA};
2327
2328	my $name = "$struct->{NAME}";
2329	my $ndr = "ndr";
2330	my $varname = "r";
2331
2332	my $args = $typefamily{$struct->{TYPE}}->{DECL}->($struct, "pull", $name, $varname);
2333
2334	$self->fn_declare("pull", $struct, "enum ndr_err_code ndr_pull_$name(struct ndr_pull *$ndr, int ndr_flags, $args)") or return;
2335
2336	return if has_property($struct, "nopull");
2337
2338	$self->pidl("{");
2339	$self->indent;
2340
2341	$self->ParseStructPull($struct, $ndr, $varname);
2342	$self->pidl("");
2343
2344	$self->pidl("NDR_CHECK(ndr_check_pipe_chunk_trailer($ndr, ndr_flags, $varname->count));");
2345	$self->pidl("");
2346
2347	$self->pidl("return NDR_ERR_SUCCESS;");
2348	$self->deindent;
2349	$self->pidl("}");
2350	$self->pidl("");
2351}
2352
2353sub ParsePipePrintChunk($$)
2354{
2355	my ($self, $t) = @_;
2356
2357	my $pipe = $t;
2358	$pipe = $t->{DATA} if ($t->{TYPE} eq "TYPEDEF");
2359	my $struct = $pipe->{DATA};
2360
2361	my $name = "$struct->{NAME}";
2362	my $ndr = "ndr";
2363	my $varname = "r";
2364
2365	my $args = $typefamily{$struct->{TYPE}}->{DECL}->($struct, "print", $name, $varname);
2366
2367	$self->pidl_hdr("void ndr_print_$name(struct ndr_print *ndr, const char *name, $args);");
2368
2369	return if (has_property($t, "noprint"));
2370
2371	$self->pidl("_PUBLIC_ void ndr_print_$name(struct ndr_print *$ndr, const char *name, $args)");
2372	$self->pidl("{");
2373	$self->indent;
2374	$self->ParseTypePrint($struct, $ndr, $varname);
2375	$self->deindent;
2376	$self->pidl("}");
2377	$self->pidl("");
2378}
2379
2380#####################################################################
2381# parse a function - print side
2382sub ParseFunctionPrint($$)
2383{
2384	my($self, $fn) = @_;
2385	my $ndr = "ndr";
2386
2387	$self->pidl_hdr("void ndr_print_$fn->{NAME}(struct ndr_print *$ndr, const char *name, int flags, const struct $fn->{NAME} *r);");
2388
2389	return if has_property($fn, "noprint");
2390
2391	$self->pidl("_PUBLIC_ void ndr_print_$fn->{NAME}(struct ndr_print *$ndr, const char *name, int flags, const struct $fn->{NAME} *r)");
2392	$self->pidl("{");
2393	$self->indent;
2394
2395	foreach my $e (@{$fn->{ELEMENTS}}) {
2396		$self->DeclareArrayVariables($e);
2397	}
2398
2399	$self->pidl("ndr_print_struct($ndr, name, \"$fn->{NAME}\");");
2400	$self->pidl("if (r == NULL) { ndr_print_null($ndr); return; }");
2401	$self->pidl("$ndr->depth++;");
2402
2403	$self->pidl("if (flags & NDR_SET_VALUES) {");
2404	$self->pidl("\t$ndr->flags |= LIBNDR_PRINT_SET_VALUES;");
2405	$self->pidl("}");
2406
2407	$self->pidl("if (flags & NDR_IN) {");
2408	$self->indent;
2409	$self->pidl("ndr_print_struct($ndr, \"in\", \"$fn->{NAME}\");");
2410	$self->pidl("$ndr->depth++;");
2411
2412	my $env = GenerateFunctionInEnv($fn);
2413
2414	foreach my $e (@{$fn->{ELEMENTS}}) {
2415		if (grep(/in/,@{$e->{DIRECTION}})) {
2416			$self->ParseElementPrint($e, $ndr, $env->{$e->{NAME}}, $env);
2417		}
2418	}
2419	$self->pidl("$ndr->depth--;");
2420	$self->deindent;
2421	$self->pidl("}");
2422
2423	$self->pidl("if (flags & NDR_OUT) {");
2424	$self->indent;
2425	$self->pidl("ndr_print_struct($ndr, \"out\", \"$fn->{NAME}\");");
2426	$self->pidl("$ndr->depth++;");
2427
2428	$env = GenerateFunctionOutEnv($fn);
2429	foreach my $e (@{$fn->{ELEMENTS}}) {
2430		if (grep(/out/,@{$e->{DIRECTION}})) {
2431			$self->ParseElementPrint($e, $ndr, $env->{$e->{NAME}}, $env);
2432		}
2433	}
2434	if ($fn->{RETURN_TYPE}) {
2435		$self->pidl("ndr_print_$fn->{RETURN_TYPE}($ndr, \"result\", r->out.result);");
2436	}
2437	$self->pidl("$ndr->depth--;");
2438	$self->deindent;
2439	$self->pidl("}");
2440
2441	$self->pidl("$ndr->depth--;");
2442	$self->deindent;
2443	$self->pidl("}");
2444	$self->pidl("");
2445}
2446
2447#####################################################################
2448# parse a function
2449sub ParseFunctionPush($$)
2450{
2451	my($self, $fn) = @_;
2452	my $ndr = "ndr";
2453
2454	$self->fn_declare("push", $fn, "enum ndr_err_code ndr_push_$fn->{NAME}(struct ndr_push *$ndr, int flags, const struct $fn->{NAME} *r)") or return;
2455
2456	return if has_property($fn, "nopush");
2457
2458	$self->pidl("{");
2459	$self->indent;
2460
2461	foreach my $e (@{$fn->{ELEMENTS}}) {
2462		$self->DeclareArrayVariables($e);
2463	}
2464
2465	$self->pidl("NDR_PUSH_CHECK_FN_FLAGS(ndr, flags);");
2466
2467	$self->pidl("if (flags & NDR_IN) {");
2468	$self->indent;
2469
2470	my $env = GenerateFunctionInEnv($fn);
2471
2472	EnvSubstituteValue($env, $fn);
2473
2474	foreach my $e (@{$fn->{ELEMENTS}}) {
2475		if (grep(/in/,@{$e->{DIRECTION}})) {
2476			$self->CheckRefPtrs($e, $ndr, $env);
2477		}
2478	}
2479
2480	foreach my $e (@{$fn->{ELEMENTS}}) {
2481		if (grep(/in/,@{$e->{DIRECTION}})) {
2482			$self->ParseElementPush($e, $ndr, $env, 1, 1);
2483		}
2484	}
2485
2486	$self->deindent;
2487	$self->pidl("}");
2488
2489	$self->pidl("if (flags & NDR_OUT) {");
2490	$self->indent;
2491
2492	$env = GenerateFunctionOutEnv($fn);
2493	EnvSubstituteValue($env, $fn);
2494
2495	foreach my $e (@{$fn->{ELEMENTS}}) {
2496		if (grep(/out/,@{$e->{DIRECTION}})) {
2497			$self->CheckRefPtrs($e, $ndr, $env);
2498		}
2499	}
2500
2501	foreach my $e (@{$fn->{ELEMENTS}}) {
2502		if (grep(/out/,@{$e->{DIRECTION}})) {
2503			$self->ParseElementPush($e, $ndr, $env, 1, 1);
2504		}
2505	}
2506
2507	if ($fn->{RETURN_TYPE}) {
2508		$self->pidl("NDR_CHECK(ndr_push_$fn->{RETURN_TYPE}($ndr, NDR_SCALARS, r->out.result));");
2509	}
2510
2511	$self->deindent;
2512	$self->pidl("}");
2513	$self->pidl("return NDR_ERR_SUCCESS;");
2514	$self->deindent;
2515	$self->pidl("}");
2516	$self->pidl("");
2517}
2518
2519sub AllocateArrayLevel($$$$$$)
2520{
2521	my ($self,$e,$l,$ndr,$var,$size) = @_;
2522
2523	my $pl = GetPrevLevel($e, $l);
2524	if (defined($pl) and
2525	    $pl->{TYPE} eq "POINTER" and
2526	    $pl->{POINTER_TYPE} eq "ref"
2527	    and not $l->{IS_ZERO_TERMINATED}) {
2528		$self->pidl("if ($ndr->flags & LIBNDR_FLAG_REF_ALLOC) {");
2529		$self->pidl("\tNDR_PULL_ALLOC_N($ndr, $var, $size);");
2530		$self->pidl("}");
2531		if (grep(/in/,@{$e->{DIRECTION}}) and
2532		    grep(/out/,@{$e->{DIRECTION}})) {
2533			$self->pidl("memcpy(r->out.$e->{NAME}, r->in.$e->{NAME}, ($size) * sizeof(*r->in.$e->{NAME}));");
2534		}
2535		return;
2536	}
2537
2538	$self->pidl("NDR_PULL_ALLOC_N($ndr, $var, $size);");
2539}
2540
2541#####################################################################
2542# parse a function
2543sub ParseFunctionPull($$)
2544{
2545	my($self,$fn) = @_;
2546	my $ndr = "ndr";
2547
2548	# pull function args
2549	$self->fn_declare("pull", $fn, "enum ndr_err_code ndr_pull_$fn->{NAME}(struct ndr_pull *$ndr, int flags, struct $fn->{NAME} *r)") or return;
2550
2551	$self->pidl("{");
2552	$self->indent;
2553
2554	# declare any internal pointers we need
2555	foreach my $e (@{$fn->{ELEMENTS}}) {
2556		$self->DeclarePtrVariables($e);
2557		$self->DeclareArrayVariables($e, "pull");
2558	}
2559
2560	my %double_cases = ();
2561	foreach my $e (@{$fn->{ELEMENTS}}) {
2562		next if ($e->{TYPE} eq "EMPTY");
2563		next if ($double_cases{"$e->{NAME}"});
2564		$self->DeclareMemCtxVariables($e);
2565		$double_cases{"$e->{NAME}"} = 1;
2566	}
2567
2568	$self->pidl("NDR_PULL_CHECK_FN_FLAGS(ndr, flags);");
2569
2570	$self->pidl("if (flags & NDR_IN) {");
2571	$self->indent;
2572
2573	# auto-init the out section of a structure. I originally argued that
2574	# this was a bad idea as it hides bugs, but coping correctly
2575	# with initialisation and not wiping ref vars is turning
2576	# out to be too tricky (tridge)
2577	foreach my $e (@{$fn->{ELEMENTS}}) {
2578		next unless grep(/out/, @{$e->{DIRECTION}});
2579		$self->pidl("NDR_ZERO_STRUCT(r->out);");
2580		$self->pidl("");
2581		last;
2582	}
2583
2584	my $env = GenerateFunctionInEnv($fn);
2585
2586	foreach my $e (@{$fn->{ELEMENTS}}) {
2587		next unless (grep(/in/, @{$e->{DIRECTION}}));
2588		$self->ParseElementPull($e, $ndr, $env, 1, 1);
2589	}
2590
2591	# allocate the "simple" out ref variables. FIXME: Shouldn't this have it's
2592	# own flag rather than be in NDR_IN ?
2593
2594	foreach my $e (@{$fn->{ELEMENTS}}) {
2595		next unless (grep(/out/, @{$e->{DIRECTION}}));
2596		next unless ($e->{LEVELS}[0]->{TYPE} eq "POINTER" and
2597		             $e->{LEVELS}[0]->{POINTER_TYPE} eq "ref");
2598		next if (($e->{LEVELS}[1]->{TYPE} eq "DATA") and
2599				 ($e->{LEVELS}[1]->{DATA_TYPE} eq "string"));
2600		next if ($e->{LEVELS}[1]->{TYPE} eq "PIPE");
2601		next if (($e->{LEVELS}[1]->{TYPE} eq "ARRAY")
2602			and   $e->{LEVELS}[1]->{IS_ZERO_TERMINATED});
2603
2604		if ($e->{LEVELS}[1]->{TYPE} eq "ARRAY") {
2605			my $size = ParseExprExt($e->{LEVELS}[1]->{SIZE_IS}, $env, $e->{ORIGINAL},
2606				check_null_pointer($e, $env, sub { $self->pidl(shift); },
2607						   "return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for size_is()\");"),
2608				check_fully_dereferenced($e, $env));
2609			$self->pidl("NDR_PULL_ALLOC_N($ndr, r->out.$e->{NAME}, $size);");
2610
2611			if (grep(/in/, @{$e->{DIRECTION}})) {
2612				$self->pidl("memcpy(r->out.$e->{NAME}, r->in.$e->{NAME}, ($size) * sizeof(*r->in.$e->{NAME}));");
2613			} else {
2614				$self->pidl("memset(r->out.$e->{NAME}, 0, ($size) * sizeof(*r->out.$e->{NAME}));");
2615			}
2616		} elsif ($e->{LEVELS}[1]->{TYPE} eq "ARRAY") {
2617			if (grep(/in/, @{$e->{DIRECTION}})) {
2618				$self->pidl("r->out.$e->{NAME} = r->in.$e->{NAME};");
2619			} else {
2620				$self->pidl("r->out.$e->{NAME} = NULL;");
2621			}
2622		} else {
2623			$self->pidl("NDR_PULL_ALLOC($ndr, r->out.$e->{NAME});");
2624
2625			if (grep(/in/, @{$e->{DIRECTION}})) {
2626				$self->pidl("*r->out.$e->{NAME} = *r->in.$e->{NAME};");
2627			} else {
2628				$self->pidl("NDR_ZERO_STRUCTP(r->out.$e->{NAME});");
2629			}
2630		}
2631	}
2632
2633	$self->add_deferred();
2634	$self->deindent;
2635	$self->pidl("}");
2636
2637	$self->pidl("if (flags & NDR_OUT) {");
2638	$self->indent;
2639
2640	$self->pidl("#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION");
2641
2642	# This for fuzzers of ndr_pull where the out elements refer to
2643	# in elements in size_is or length_is.
2644	#
2645	# Not actually very harmful but also not useful outsie a fuzzer
2646	foreach my $e (@{$fn->{ELEMENTS}}) {
2647		next unless (grep(/in/, @{$e->{DIRECTION}}));
2648		next unless ($e->{LEVELS}[0]->{TYPE} eq "POINTER" and
2649		             $e->{LEVELS}[0]->{POINTER_TYPE} eq "ref");
2650		next if (($e->{LEVELS}[1]->{TYPE} eq "DATA") and
2651				 ($e->{LEVELS}[1]->{DATA_TYPE} eq "string"));
2652		next if ($e->{LEVELS}[1]->{TYPE} eq "PIPE");
2653		next if ($e->{LEVELS}[1]->{TYPE} eq "ARRAY");
2654
2655		$self->pidl("if (r->in.$e->{NAME} == NULL) {");
2656		$self->indent;
2657		$self->pidl("NDR_PULL_ALLOC($ndr, r->in.$e->{NAME});");
2658		$self->pidl("NDR_ZERO_STRUCTP(r->in.$e->{NAME});");
2659		$self->deindent;
2660		$self->pidl("}");
2661	}
2662
2663	$self->pidl("#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */");
2664
2665	$env = GenerateFunctionOutEnv($fn);
2666	foreach my $e (@{$fn->{ELEMENTS}}) {
2667		next unless grep(/out/, @{$e->{DIRECTION}});
2668		$self->ParseElementPull($e, $ndr, $env, 1, 1);
2669	}
2670
2671	if ($fn->{RETURN_TYPE}) {
2672		$self->pidl("NDR_CHECK(ndr_pull_$fn->{RETURN_TYPE}($ndr, NDR_SCALARS, &r->out.result));");
2673	}
2674
2675	$self->add_deferred();
2676	$self->deindent;
2677	$self->pidl("}");
2678
2679	$self->pidl("return NDR_ERR_SUCCESS;");
2680	$self->deindent;
2681	$self->pidl("}");
2682	$self->pidl("");
2683}
2684
2685sub AuthServiceStruct($$$)
2686{
2687	my ($self, $ifacename, $authservice) = @_;
2688	my @a = split /,/, $authservice;
2689	my $authservice_count = $#a + 1;
2690
2691	$self->pidl("static const char * const $ifacename\_authservice_strings[] = {");
2692	foreach my $ap (@a) {
2693		$self->pidl("\t$ap, ");
2694	}
2695	$self->pidl("};");
2696	$self->pidl("");
2697
2698	$self->pidl("static const struct ndr_interface_string_array $ifacename\_authservices = {");
2699	$self->pidl("\t.count\t= $authservice_count,");
2700	$self->pidl("\t.names\t= $ifacename\_authservice_strings");
2701	$self->pidl("};");
2702	$self->pidl("");
2703}
2704
2705sub ParseGeneratePipeArray($$$)
2706{
2707	my ($self, $fn, $direction) = @_;
2708
2709	$self->pidl("static const struct ndr_interface_call_pipe $fn->{NAME}\_$direction\_pipes[] = {");
2710	$self->indent;
2711
2712	foreach my $e (@{$fn->{ELEMENTS}}) {
2713		next unless ContainsPipe($e, $e->{LEVELS}[0]);
2714		next unless (grep(/$direction/, @{$e->{DIRECTION}}));
2715
2716		my $cname = "$e->{TYPE}_chunk";
2717
2718		$self->pidl("{");
2719		$self->indent;
2720		$self->pidl("\"$direction.$e->{NAME}\",");
2721		$self->pidl("\"$cname\",");
2722		$self->pidl("sizeof(struct $cname),");
2723		$self->pidl("(ndr_push_flags_fn_t) ndr_push_$cname,");
2724		$self->pidl("(ndr_pull_flags_fn_t) ndr_pull_$cname,");
2725		$self->pidl("(ndr_print_fn_t) ndr_print_$cname,");
2726		$self->deindent;
2727		$self->pidl("},");
2728	}
2729	$self->pidl("{ .name = NULL }");
2730	$self->deindent;
2731	$self->pidl("};");
2732	$self->pidl("");
2733}
2734
2735sub FunctionCallPipes($$)
2736{
2737	my ($self, $d) = @_;
2738	return if not defined($d->{OPNUM});
2739
2740	my $in_pipes = 0;
2741	my $out_pipes = 0;
2742
2743	foreach my $e (@{$d->{ELEMENTS}}) {
2744		next unless ContainsPipe($e, $e->{LEVELS}[0]);
2745
2746		if (grep(/in/, @{$e->{DIRECTION}})) {
2747			$in_pipes++;
2748		}
2749		if (grep(/out/, @{$e->{DIRECTION}})) {
2750			$out_pipes++;
2751		}
2752	}
2753
2754	if ($in_pipes) {
2755		$self->ParseGeneratePipeArray($d, "in");
2756	}
2757
2758	if ($out_pipes) {
2759		$self->ParseGeneratePipeArray($d, "out");
2760	}
2761}
2762
2763sub FunctionCallEntry($$)
2764{
2765	my ($self, $d) = @_;
2766	return 0 if not defined($d->{OPNUM});
2767
2768	my $in_pipes = 0;
2769	my $out_pipes = 0;
2770
2771	foreach my $e (@{$d->{ELEMENTS}}) {
2772		next unless ContainsPipe($e, $e->{LEVELS}[0]);
2773
2774		if (grep(/in/, @{$e->{DIRECTION}})) {
2775			$in_pipes++;
2776		}
2777		if (grep(/out/, @{$e->{DIRECTION}})) {
2778			$out_pipes++;
2779		}
2780	}
2781
2782	my $in_pipes_ptr = "NULL";
2783	my $out_pipes_ptr = "NULL";
2784
2785	if ($in_pipes) {
2786		$in_pipes_ptr = "$d->{NAME}_in_pipes";
2787	}
2788
2789	if ($out_pipes) {
2790		$out_pipes_ptr = "$d->{NAME}_out_pipes";
2791	}
2792
2793	$self->pidl("\t{");
2794	$self->pidl("\t\t\"$d->{NAME}\",");
2795	$self->pidl("\t\tsizeof(struct $d->{NAME}),");
2796	$self->pidl("\t\t(ndr_push_flags_fn_t) ndr_push_$d->{NAME},");
2797	$self->pidl("\t\t(ndr_pull_flags_fn_t) ndr_pull_$d->{NAME},");
2798	$self->pidl("\t\t(ndr_print_function_t) ndr_print_$d->{NAME},");
2799	$self->pidl("\t\t{ $in_pipes, $in_pipes_ptr },");
2800	$self->pidl("\t\t{ $out_pipes, $out_pipes_ptr },");
2801	$self->pidl("\t},");
2802	return 1;
2803}
2804
2805sub StructEntry($$)
2806{
2807	my ($self, $d) = @_;
2808	my $type_decl = $typefamily{$d->{TYPE}}->{DECL}->($d, "base", $d->{NAME}, "");
2809
2810	$self->pidl("\t{");
2811	$self->pidl("\t\t.name = \"$d->{NAME}\",");
2812	$self->pidl("\t\t.struct_size = sizeof($type_decl),");
2813	$self->pidl("\t\t.ndr_push = (ndr_push_flags_fn_t) ndr_push_$d->{NAME},");
2814	$self->pidl("\t\t.ndr_pull = (ndr_pull_flags_fn_t) ndr_pull_$d->{NAME},");
2815	$self->pidl("\t\t.ndr_print = (ndr_print_function_t) ndr_print_flags_$d->{NAME},");
2816	$self->pidl("\t},");
2817	return 1;
2818}
2819
2820#####################################################################
2821# produce a function call table
2822sub FunctionTable($$)
2823{
2824	my($self,$interface) = @_;
2825	my $count = 0;
2826	my $count_public_structs = 0;
2827	my $uname = uc $interface->{NAME};
2828
2829	foreach my $d (@{$interface->{TYPES}}) {
2830	        next unless (is_public_struct($d));
2831		$count_public_structs += 1;
2832	}
2833	return if ($#{$interface->{FUNCTIONS}}+1 == 0 and
2834		   $count_public_structs == 0);
2835
2836	foreach my $d (@{$interface->{INHERITED_FUNCTIONS}},@{$interface->{FUNCTIONS}}) {
2837		$self->FunctionCallPipes($d);
2838	}
2839
2840	$self->pidl("static const struct ndr_interface_public_struct $interface->{NAME}\_public_structs[] = {");
2841
2842	foreach my $d (@{$interface->{TYPES}}) {
2843	        next unless (is_public_struct($d));
2844		$self->StructEntry($d);
2845	}
2846	$self->pidl("\t{ .name = NULL }");
2847	$self->pidl("};");
2848	$self->pidl("");
2849
2850	$self->pidl("static const struct ndr_interface_call $interface->{NAME}\_calls[] = {");
2851
2852	foreach my $d (@{$interface->{INHERITED_FUNCTIONS}},@{$interface->{FUNCTIONS}}) {
2853		$count += $self->FunctionCallEntry($d);
2854	}
2855	$self->pidl("\t{ .name = NULL }");
2856	$self->pidl("};");
2857	$self->pidl("");
2858
2859	$self->pidl("static const char * const $interface->{NAME}\_endpoint_strings[] = {");
2860	foreach my $ep (@{$interface->{ENDPOINTS}}) {
2861		$self->pidl("\t$ep, ");
2862	}
2863	my $endpoint_count = $#{$interface->{ENDPOINTS}}+1;
2864
2865	$self->pidl("};");
2866	$self->pidl("");
2867
2868	$self->pidl("static const struct ndr_interface_string_array $interface->{NAME}\_endpoints = {");
2869	$self->pidl("\t.count\t= $endpoint_count,");
2870	$self->pidl("\t.names\t= $interface->{NAME}\_endpoint_strings");
2871	$self->pidl("};");
2872	$self->pidl("");
2873
2874	if (! defined $interface->{PROPERTIES}->{authservice}) {
2875		$interface->{PROPERTIES}->{authservice} = "\"host\"";
2876	}
2877
2878	$self->AuthServiceStruct($interface->{NAME},
2879		                     $interface->{PROPERTIES}->{authservice});
2880
2881	$self->pidl("\nconst struct ndr_interface_table ndr_table_$interface->{NAME} = {");
2882	$self->pidl("\t.name\t\t= \"$interface->{NAME}\",");
2883	if (defined $interface->{PROPERTIES}->{uuid}) {
2884		$self->pidl("\t.syntax_id\t= {");
2885		$self->pidl("\t\t" . print_uuid($interface->{UUID}) .",");
2886		$self->pidl("\t\tNDR_$uname\_VERSION");
2887		$self->pidl("\t},");
2888		$self->pidl("\t.helpstring\t= NDR_$uname\_HELPSTRING,");
2889	}
2890	$self->pidl("\t.num_calls\t= $count,");
2891	$self->pidl("\t.calls\t\t= $interface->{NAME}\_calls,");
2892	$self->pidl("\t.num_public_structs\t= $count_public_structs,");
2893	$self->pidl("\t.public_structs\t\t= $interface->{NAME}\_public_structs,");
2894	$self->pidl("\t.endpoints\t= &$interface->{NAME}\_endpoints,");
2895	$self->pidl("\t.authservices\t= &$interface->{NAME}\_authservices");
2896	$self->pidl("};");
2897	$self->pidl("");
2898
2899}
2900
2901#####################################################################
2902# generate include statements for imported idl files
2903sub HeaderImport
2904{
2905	my $self = shift;
2906	my @imports = @_;
2907	foreach (@imports) {
2908		$_ = unmake_str($_);
2909		s/\.idl$//;
2910		$self->pidl(choose_header("librpc/gen_ndr/ndr_$_\.h", "gen_ndr/ndr_$_.h"));
2911	}
2912}
2913
2914#####################################################################
2915# generate include statements for included header files
2916sub HeaderInclude
2917{
2918	my $self = shift;
2919	my @includes = @_;
2920	foreach (@includes) {
2921		$self->pidl_hdr("#include $_");
2922	}
2923}
2924
2925#####################################################################
2926# generate prototypes and defines for the interface definitions
2927# FIXME: these prototypes are for the DCE/RPC client functions, not the
2928# NDR parser and so do not belong here, technically speaking
2929sub HeaderInterface($$$)
2930{
2931	my($self,$interface,$needed) = @_;
2932
2933	my $count = 0;
2934
2935	if ($needed->{"compression"}) {
2936		$self->pidl(choose_header("librpc/ndr/ndr_compression.h", "ndr/compression.h"));
2937	}
2938
2939	if (has_property($interface, "object")) {
2940		$self->pidl(choose_header("librpc/gen_ndr/ndr_orpc.h", "ndr/orpc.h"));
2941	}
2942
2943	if (defined $interface->{PROPERTIES}->{helper}) {
2944		$self->HeaderInclude(split /,/, $interface->{PROPERTIES}->{helper});
2945	}
2946
2947	if (defined $interface->{PROPERTIES}->{uuid}) {
2948		my $name = uc $interface->{NAME};
2949		$self->pidl_hdr("#define NDR_$name\_UUID " .
2950		Parse::Pidl::Util::make_str(lc($interface->{UUID})));
2951
2952		$self->pidl_hdr("#define NDR_$name\_VERSION $interface->{VERSION}");
2953
2954		$self->pidl_hdr("#define NDR_$name\_NAME \"$interface->{NAME}\"");
2955
2956		if(!defined $interface->{PROPERTIES}->{helpstring}) { $interface->{PROPERTIES}->{helpstring} = "NULL"; }
2957		$self->pidl_hdr("#define NDR_$name\_HELPSTRING $interface->{PROPERTIES}->{helpstring}");
2958	}
2959
2960	my $count_public_structs = 0;
2961	foreach my $d (@{$interface->{TYPES}}) {
2962	        next unless (has_property($d, "public"));
2963		$count_public_structs += 1;
2964	}
2965	if ($#{$interface->{FUNCTIONS}}+1 > 0 or
2966		   $count_public_structs > 0) {
2967		$self->pidl_hdr("extern const struct ndr_interface_table ndr_table_$interface->{NAME};");
2968	}
2969
2970	foreach (@{$interface->{FUNCTIONS}}) {
2971		next if has_property($_, "noopnum");
2972		next if grep(/^$_->{NAME}$/,@{$interface->{INHERITED_FUNCTIONS}});
2973		my $u_name = uc $_->{NAME};
2974
2975		my $val = sprintf("0x%02x", $count);
2976		if (defined($interface->{BASE})) {
2977			$val .= " + NDR_" . uc $interface->{BASE} . "_CALL_COUNT";
2978		}
2979
2980		$self->pidl_hdr("#define NDR_$u_name ($val)");
2981
2982		$self->pidl_hdr("");
2983		$count++;
2984	}
2985
2986	my $val = $count;
2987
2988	if (defined($interface->{BASE})) {
2989		$val .= " + NDR_" . uc $interface->{BASE} . "_CALL_COUNT";
2990	}
2991
2992	$self->pidl_hdr("#define NDR_" . uc $interface->{NAME} . "_CALL_COUNT ($val)");
2993
2994}
2995
2996sub ParseTypePush($$$$$$)
2997{
2998	my ($self,$e, $ndr, $varname, $primitives, $deferred) = @_;
2999
3000	# save the old relative_base_offset
3001	$self->pidl("uint32_t _save_relative_base_offset = ndr_push_get_relative_base_offset($ndr);") if defined(has_property($e, "relative_base"));
3002	$typefamily{$e->{TYPE}}->{PUSH_FN_BODY}->($self, $e, $ndr, $varname);
3003	# restore the old relative_base_offset
3004	$self->pidl("ndr_push_restore_relative_base_offset($ndr, _save_relative_base_offset);") if defined(has_property($e, "relative_base"));
3005}
3006
3007sub ParseTypePushFunction($$$)
3008{
3009	my ($self, $e, $varname) = @_;
3010	my $ndr = "ndr";
3011
3012	my $args = $typefamily{$e->{TYPE}}->{DECL}->($e, "push", $e->{NAME}, $varname);
3013
3014	$self->fn_declare("push", $e, "enum ndr_err_code ".TypeFunctionName("ndr_push", $e)."(struct ndr_push *$ndr, int ndr_flags, $args)") or return;
3015
3016	$self->pidl("{");
3017	$self->indent;
3018	$self->ParseTypePush($e, $ndr, $varname, 1, 1);
3019	$self->pidl("return NDR_ERR_SUCCESS;");
3020	$self->deindent;
3021	$self->pidl("}");
3022	$self->pidl("");;
3023}
3024
3025sub ParseTypePull($$$$$$)
3026{
3027	my ($self, $e, $ndr, $varname, $primitives, $deferred) = @_;
3028
3029	# save the old relative_base_offset
3030	$self->pidl("uint32_t _save_relative_base_offset = ndr_pull_get_relative_base_offset($ndr);") if defined(has_property($e, "relative_base"));
3031	$typefamily{$e->{TYPE}}->{PULL_FN_BODY}->($self, $e, $ndr, $varname);
3032	# restore the old relative_base_offset
3033	$self->pidl("ndr_pull_restore_relative_base_offset($ndr, _save_relative_base_offset);") if defined(has_property($e, "relative_base"));
3034}
3035
3036sub ParseTypePullFunction($$)
3037{
3038	my ($self, $e, $varname) = @_;
3039	my $ndr = "ndr";
3040
3041	my $args = $typefamily{$e->{TYPE}}->{DECL}->($e, "pull", $e->{NAME}, $varname);
3042
3043	$self->fn_declare("pull", $e, "enum ndr_err_code ".TypeFunctionName("ndr_pull", $e)."(struct ndr_pull *$ndr, int ndr_flags, $args)") or return;
3044
3045	$self->pidl("{");
3046	$self->indent;
3047	$self->ParseTypePull($e, $ndr, $varname, 1, 1);
3048	$self->pidl("return NDR_ERR_SUCCESS;");
3049	$self->deindent;
3050	$self->pidl("}");
3051	$self->pidl("");
3052}
3053
3054sub ParseTypePrint($$$$)
3055{
3056	my ($self, $e, $ndr, $varname) = @_;
3057
3058	$typefamily{$e->{TYPE}}->{PRINT_FN_BODY}->($self, $e, $ndr, $e->{NAME}, $varname);
3059}
3060
3061sub ParseTypePrintFunction($$$)
3062{
3063	my ($self, $e, $varname) = @_;
3064	my $ndr = "ndr";
3065
3066	my $args = $typefamily{$e->{TYPE}}->{DECL}->($e, "print", $e->{NAME}, $varname);
3067
3068	$self->pidl_hdr("void ".TypeFunctionName("ndr_print", $e)."(struct ndr_print *ndr, const char *name, $args);");
3069
3070	if (is_public_struct($e)) {
3071                $self->pidl("static void ".TypeFunctionName("ndr_print_flags", $e).
3072                             "(struct ndr_print *$ndr, const char *name, int unused, $args)"
3073                             );
3074		$self->pidl("{");
3075		$self->indent;
3076		$self->pidl(TypeFunctionName("ndr_print", $e)."($ndr, name, $varname);");
3077		$self->deindent;
3078		$self->pidl("}");
3079		$self->pidl("");
3080	}
3081
3082	return if (has_property($e, "noprint"));
3083
3084	$self->pidl("_PUBLIC_ void ".TypeFunctionName("ndr_print", $e)."(struct ndr_print *$ndr, const char *name, $args)");
3085	$self->pidl("{");
3086	$self->indent;
3087	$self->ParseTypePrint($e, $ndr, $varname);
3088	$self->deindent;
3089	$self->pidl("}");
3090	$self->pidl("");
3091}
3092
3093sub ParseTypeNdrSize($$)
3094{
3095	my ($self,$t) = @_;
3096
3097	my $varname = "r";
3098	my $tf = $typefamily{$t->{TYPE}};
3099	my $args = $tf->{SIZE_FN_ARGS}->($t, $t->{NAME}, $varname);
3100
3101	$self->fn_declare("size", $t, "size_t ndr_size_$t->{NAME}($args)") or return;
3102
3103	$self->pidl("{");
3104	$self->indent;
3105	$typefamily{$t->{TYPE}}->{SIZE_FN_BODY}->($self,$t, $t->{NAME}, $varname);
3106	$self->deindent;
3107	$self->pidl("}");
3108	$self->pidl("");
3109}
3110
3111#####################################################################
3112# parse the interface definitions
3113sub ParseInterface($$$)
3114{
3115	my($self,$interface,$needed) = @_;
3116
3117	$self->pidl_hdr("#ifndef _HEADER_NDR_$interface->{NAME}");
3118	$self->pidl_hdr("#define _HEADER_NDR_$interface->{NAME}");
3119
3120	$self->pidl_hdr("");
3121
3122	$self->HeaderInterface($interface, $needed);
3123
3124	# Typedefs
3125	foreach my $d (@{$interface->{TYPES}}) {
3126		if (Parse::Pidl::Typelist::typeIs($d, "PIPE")) {
3127			($needed->{TypeFunctionName("ndr_push", $d)}) &&
3128				$self->ParsePipePushChunk($d);
3129			($needed->{TypeFunctionName("ndr_pull", $d)}) &&
3130				$self->ParsePipePullChunk($d);
3131			($needed->{TypeFunctionName("ndr_print", $d)}) &&
3132				$self->ParsePipePrintChunk($d);
3133
3134			$needed->{TypeFunctionName("ndr_pull", $d)} = 0;
3135			$needed->{TypeFunctionName("ndr_push", $d)} = 0;
3136			$needed->{TypeFunctionName("ndr_print", $d)} = 0;
3137			next;
3138		}
3139
3140		next unless(typeHasBody($d));
3141
3142		($needed->{TypeFunctionName("ndr_push", $d)}) && $self->ParseTypePushFunction($d, "r");
3143		($needed->{TypeFunctionName("ndr_pull", $d)}) && $self->ParseTypePullFunction($d, "r");
3144		($needed->{TypeFunctionName("ndr_print", $d)}) && $self->ParseTypePrintFunction($d, "r");
3145
3146		# Make sure we don't generate a function twice...
3147		$needed->{TypeFunctionName("ndr_push", $d)} =
3148		    $needed->{TypeFunctionName("ndr_pull", $d)} =
3149			$needed->{TypeFunctionName("ndr_print", $d)} = 0;
3150
3151		($needed->{"ndr_size_$d->{NAME}"}) && $self->ParseTypeNdrSize($d);
3152	}
3153
3154	# Functions
3155	foreach my $d (@{$interface->{FUNCTIONS}}) {
3156		($needed->{"ndr_push_$d->{NAME}"}) && $self->ParseFunctionPush($d);
3157		($needed->{"ndr_pull_$d->{NAME}"}) && $self->ParseFunctionPull($d);
3158		($needed->{"ndr_print_$d->{NAME}"}) && $self->ParseFunctionPrint($d);
3159	}
3160
3161        # Allow compilation of generated files where replacement functions
3162        # for structures declared nopull/nopush have not been provided.
3163        #
3164        # This makes sense when only the print functions are used
3165        #
3166        # Otherwise the ndr_table XXX will reference these
3167
3168        $self->pidl("#ifndef SKIP_NDR_TABLE_$interface->{NAME}");
3169	$self->FunctionTable($interface);
3170        $self->pidl("#endif /* SKIP_NDR_TABLE_$interface->{NAME} */");
3171
3172	$self->pidl_hdr("#endif /* _HEADER_NDR_$interface->{NAME} */");
3173}
3174
3175sub GenerateIncludes($)
3176{
3177	my ($self) = @_;
3178	if (is_intree()) {
3179		$self->pidl("#include \"includes.h\"");
3180	} else {
3181		$self->pidl("#ifndef _GNU_SOURCE");
3182		$self->pidl("#define _GNU_SOURCE");
3183		$self->pidl("#endif");
3184		$self->pidl("#include <stdint.h>");
3185		$self->pidl("#include <stdlib.h>");
3186		$self->pidl("#include <stdio.h>");
3187		$self->pidl("#include <stdbool.h>");
3188		$self->pidl("#include <stdarg.h>");
3189		$self->pidl("#include <string.h>");
3190	}
3191}
3192
3193#####################################################################
3194# parse a parsed IDL structure back into an IDL file
3195sub Parse($$$$)
3196{
3197	my($self, $ndr,$gen_header,$ndr_header) = @_;
3198
3199	$self->pidl_hdr("/* header auto-generated by pidl */");
3200	$self->pidl_hdr("");
3201	$self->pidl_hdr(choose_header("librpc/ndr/libndr.h", "ndr.h"));
3202	$self->pidl_hdr("#include \"$gen_header\"") if ($gen_header);
3203	$self->pidl_hdr("");
3204
3205	$self->pidl("/* parser auto-generated by pidl */");
3206	$self->pidl("");
3207	$self->GenerateIncludes();
3208	$self->pidl("#include \"$ndr_header\"") if ($ndr_header);
3209	$self->pidl("");
3210
3211	my %needed = ();
3212
3213	foreach (@{$ndr}) {
3214		($_->{TYPE} eq "INTERFACE") && NeededInterface($_, \%needed);
3215	}
3216
3217	foreach (@{$ndr}) {
3218		($_->{TYPE} eq "INTERFACE") && $self->ParseInterface($_, \%needed);
3219		($_->{TYPE} eq "IMPORT") && $self->HeaderImport(@{$_->{PATHS}});
3220		($_->{TYPE} eq "INCLUDE") && $self->HeaderInclude(@{$_->{PATHS}});
3221	}
3222
3223	return ($self->{res_hdr}, $self->{res});
3224}
3225
3226sub NeededElement($$$)
3227{
3228	my ($e, $dir, $needed) = @_;
3229
3230	return if ($e->{TYPE} eq "EMPTY");
3231
3232	return if (ref($e->{TYPE}) eq "HASH" and
3233		       not defined($e->{TYPE}->{NAME}));
3234
3235	my ($t, $rt);
3236	if (ref($e->{TYPE}) eq "HASH") {
3237		$t = $e->{TYPE}->{TYPE}."_".$e->{TYPE}->{NAME};
3238	} else {
3239		$t = $e->{TYPE};
3240	}
3241
3242	if (ref($e->{REPRESENTATION_TYPE}) eq "HASH") {
3243		$rt = $e->{REPRESENTATION_TYPE}->{TYPE}."_".$e->{REPRESENTATION_TYPE}->{NAME};
3244	} else {
3245		$rt = $e->{REPRESENTATION_TYPE};
3246	}
3247
3248	die ("$e->{NAME} $t, $rt FOO") unless ($rt ne "");
3249
3250	my @fn = ();
3251	if ($dir eq "print") {
3252		push(@fn, TypeFunctionName("ndr_print", $e->{REPRESENTATION_TYPE}));
3253	} elsif ($dir eq "pull") {
3254		push (@fn, TypeFunctionName("ndr_pull", $e->{TYPE}));
3255		push (@fn, "ndr_$t\_to_$rt")
3256			if ($rt ne $t);
3257	} elsif ($dir eq "push") {
3258		push (@fn, TypeFunctionName("ndr_push", $e->{TYPE}));
3259		push (@fn, "ndr_$rt\_to_$t")
3260			if ($rt ne $t);
3261	} else {
3262		die("invalid direction `$dir'");
3263	}
3264
3265	foreach (@fn) {
3266		unless (defined($needed->{$_})) {
3267			$needed->{$_} = 1;
3268		}
3269	}
3270}
3271
3272sub NeededFunction($$)
3273{
3274	my ($fn,$needed) = @_;
3275	$needed->{"ndr_pull_$fn->{NAME}"} = 1;
3276	$needed->{"ndr_push_$fn->{NAME}"} = 1;
3277	$needed->{"ndr_print_$fn->{NAME}"} = 1;
3278	foreach my $e (@{$fn->{ELEMENTS}}) {
3279		$e->{PARENT} = $fn;
3280		NeededElement($e, $_, $needed) foreach ("pull", "push", "print");
3281	}
3282}
3283
3284sub NeededType($$$)
3285{
3286	sub NeededType($$$);
3287	my ($t,$needed,$req) = @_;
3288
3289	NeededType($t->{DATA}, $needed, $req) if ($t->{TYPE} eq "TYPEDEF");
3290	NeededType($t->{DATA}, $needed, $req) if ($t->{TYPE} eq "PIPE");
3291
3292	if ($t->{TYPE} eq "STRUCT" or $t->{TYPE} eq "UNION") {
3293		return unless defined($t->{ELEMENTS});
3294		for my $e (@{$t->{ELEMENTS}}) {
3295			$e->{PARENT} = $t;
3296			if (has_property($e, "compression")) {
3297				$needed->{"compression"} = 1;
3298			}
3299			NeededElement($e, $req, $needed);
3300			NeededType($e->{TYPE}, $needed, $req) if (ref($e->{TYPE}) eq "HASH");
3301		}
3302	}
3303}
3304
3305#####################################################################
3306# work out what parse functions are needed
3307sub NeededInterface($$)
3308{
3309	my ($interface,$needed) = @_;
3310	NeededFunction($_, $needed) foreach (@{$interface->{FUNCTIONS}});
3311	foreach (reverse @{$interface->{TYPES}}) {
3312
3313		if (has_property($_, "public")) {
3314			$needed->{TypeFunctionName("ndr_pull", $_)} = $needed->{TypeFunctionName("ndr_push", $_)} =
3315				$needed->{TypeFunctionName("ndr_print", $_)} = 1;
3316		}
3317
3318		NeededType($_, $needed, "pull") if ($needed->{TypeFunctionName("ndr_pull", $_)});
3319		NeededType($_, $needed, "push") if ($needed->{TypeFunctionName("ndr_push", $_)});
3320		NeededType($_, $needed, "print") if ($needed->{TypeFunctionName("ndr_print", $_)});
3321		if (has_property($_, "gensize")) {
3322			$needed->{"ndr_size_$_->{NAME}"} = 1;
3323		}
3324	}
3325}
3326
3327sub TypeFunctionName($$)
3328{
3329	my ($prefix, $t) = @_;
3330
3331	return "$prefix\_$t->{NAME}" if (ref($t) eq "HASH" and
3332			$t->{TYPE} eq "TYPEDEF");
3333	return "$prefix\_$t->{TYPE}_$t->{NAME}" if (ref($t) eq "HASH");
3334	return "$prefix\_$t";
3335}
3336
33371;
3338