r8264: - Use standard perl package structure for pidl.
[sfrench/samba-autobuild/.git] / source4 / build / pidl / Parse / Pidl / Samba / NDR / Parser.pm
1 ###################################################
2 # Samba4 NDR parser generator for IDL structures
3 # Copyright tridge@samba.org 2000-2003
4 # Copyright tpot@samba.org 2001
5 # Copyright jelmer@samba.org 2004-2005
6 # released under the GNU GPL
7
8 package Parse::Pidl::Samba::NDR::Parser;
9
10 use strict;
11 use Parse::Pidl::Typelist;
12 use Parse::Pidl::NDR;
13
14 # list of known types
15 my %typefamily;
16
17 sub get_typefamily($)
18 {
19         my $n = shift;
20         return $typefamily{$n};
21 }
22
23 sub append_prefix($$)
24 {
25         my ($e, $var_name) = @_;
26         my $pointers = 0;
27
28         foreach my $l (@{$e->{LEVELS}}) {
29                 if ($l->{TYPE} eq "POINTER") {
30                         $pointers++;
31                 } elsif ($l->{TYPE} eq "ARRAY") {
32                         if (($pointers == 0) and 
33                             (not $l->{IS_FIXED}) and
34                             (not $l->{IS_INLINE})) {
35                                 return get_value_of($var_name); 
36                         }
37                 } elsif ($l->{TYPE} eq "DATA") {
38                         if (Parse::Pidl::Typelist::scalar_is_reference($l->{DATA_TYPE})) {
39                                 return get_value_of($var_name) unless ($pointers);
40                         }
41                 }
42         }
43         
44         return $var_name;
45 }
46
47 sub is_scalar_array($$)
48 {
49         my ($e,$l) = @_;
50
51         return 0 if ($l->{TYPE} ne "ARRAY");
52
53         my $nl = Parse::Pidl::NDR::GetNextLevel($e,$l);
54         return (($nl->{TYPE} eq "DATA") and 
55                 (Parse::Pidl::Typelist::is_scalar($nl->{DATA_TYPE})));
56 }
57
58 sub get_pointer_to($)
59 {
60         my $var_name = shift;
61         
62         if ($var_name =~ /^\*(.*)$/) {
63                 return $1;
64         } elsif ($var_name =~ /^\&(.*)$/) {
65                 return "&($var_name)";
66         } else {
67                 return "&$var_name";
68         }
69 }
70
71 sub get_value_of($)
72 {
73         my $var_name = shift;
74
75         if ($var_name =~ /^\&(.*)$/) {
76                 return $1;
77         } else {
78                 return "*$var_name";
79         }
80 }
81
82 my $res = "";
83 my $tabs = "";
84 sub pidl($)
85 {
86         my $d = shift;
87         if ($d) {
88                 $res .= $tabs;
89                 $res .= $d;
90         }
91         $res .="\n";
92 }
93
94 sub indent()
95 {
96         $tabs .= "\t";
97 }
98
99 sub deindent()
100 {
101         $tabs = substr($tabs, 0, -1);
102 }
103
104 #####################################################################
105 # check that a variable we get from ParseExpr isn't a null pointer
106 sub check_null_pointer($)
107 {
108         my $size = shift;
109         if ($size =~ /^\*/) {
110                 my $size2 = substr($size, 1);
111                 pidl "if ($size2 == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;";
112         }
113 }
114
115 #####################################################################
116 # check that a variable we get from ParseExpr isn't a null pointer
117 # void return varient
118 sub check_null_pointer_void($)
119 {
120         my $size = shift;
121         if ($size =~ /^\*/) {
122                 my $size2 = substr($size, 1);
123                 pidl "if ($size2 == NULL) return;";
124         }
125 }
126
127 #####################################################################
128 # work out is a parse function should be declared static or not
129 sub fn_prefix($)
130 {
131         my $fn = shift;
132
133         return "" if (Parse::Pidl::Util::has_property($fn, "public"));
134         return "static ";
135 }
136
137 ###################################################################
138 # setup any special flags for an element or structure
139 sub start_flags($)
140 {
141         my $e = shift;
142         my $flags = Parse::Pidl::Util::has_property($e, "flag");
143         if (defined $flags) {
144                 pidl "{";
145                 indent;
146                 pidl "uint32_t _flags_save_$e->{TYPE} = ndr->flags;";
147                 pidl "ndr_set_flags(&ndr->flags, $flags);";
148         }
149 }
150
151 ###################################################################
152 # end any special flags for an element or structure
153 sub end_flags($)
154 {
155         my $e = shift;
156         my $flags = Parse::Pidl::Util::has_property($e, "flag");
157         if (defined $flags) {
158                 pidl "ndr->flags = _flags_save_$e->{TYPE};";
159                 deindent;
160                 pidl "}";
161         }
162 }
163
164 sub GenerateStructEnv($)
165 {
166         my $x = shift;
167         my %env;
168
169         foreach my $e (@{$x->{ELEMENTS}}) {
170                 $env{$e->{NAME}} = "r->$e->{NAME}";
171         }
172
173         $env{"this"} = "r";
174
175         return \%env;
176 }
177
178 sub GenerateFunctionInEnv($)
179 {
180         my $fn = shift;
181         my %env;
182
183         foreach my $e (@{$fn->{ELEMENTS}}) {
184                 if (grep (/in/, @{$e->{DIRECTION}})) {
185                         $env{$e->{NAME}} = "r->in.$e->{NAME}";
186                 }
187         }
188
189         return \%env;
190 }
191
192 sub GenerateFunctionOutEnv($)
193 {
194         my $fn = shift;
195         my %env;
196
197         foreach my $e (@{$fn->{ELEMENTS}}) {
198                 if (grep (/out/, @{$e->{DIRECTION}})) {
199                         $env{$e->{NAME}} = "r->out.$e->{NAME}";
200                 } elsif (grep (/in/, @{$e->{DIRECTION}})) {
201                         $env{$e->{NAME}} = "r->in.$e->{NAME}";
202                 }
203         }
204
205         return \%env;
206 }
207
208 #####################################################################
209 # parse the data of an array - push side
210 sub ParseArrayPushHeader($$$$$)
211 {
212         my ($e,$l,$ndr,$var_name,$env) = @_;
213
214         if ($l->{IS_CONFORMANT} or $l->{IS_VARYING}) {
215                 $var_name = get_pointer_to($var_name);
216         }
217
218         my $size;
219         my $length;
220
221         if ($l->{IS_ZERO_TERMINATED}) {
222                 $size = $length = "ndr_string_length($var_name, sizeof(*$var_name))";
223         } else {
224                 $size = Parse::Pidl::Util::ParseExpr($l->{SIZE_IS}, $env);
225                 $length = Parse::Pidl::Util::ParseExpr($l->{LENGTH_IS}, $env);
226         }
227
228         if ((!$l->{IS_SURROUNDING}) and $l->{IS_CONFORMANT}) {
229                 pidl "NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, $size));";
230         }
231         
232         if ($l->{IS_VARYING}) {
233                 pidl "NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, 0));";
234                 pidl "NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, $length));";
235         } 
236
237         return $length;
238 }
239
240 #####################################################################
241 # parse an array - pull side
242 sub ParseArrayPullHeader($$$$$)
243 {
244         my ($e,$l,$ndr,$var_name,$env) = @_;
245
246         if ($l->{IS_CONFORMANT} or $l->{IS_VARYING}) {
247                 $var_name = get_pointer_to($var_name);
248         }
249
250         my $length;
251         my $size;
252
253         if ($l->{IS_CONFORMANT}) {
254                 $length = $size = "ndr_get_array_size($ndr, " . get_pointer_to($var_name) . ")";
255         } elsif ($l->{IS_ZERO_TERMINATED}) { # Noheader arrays
256                 $length = $size = "ndr_get_string_size($ndr, sizeof(*$var_name))";
257         } else {
258                 $length = $size = Parse::Pidl::Util::ParseExpr($l->{SIZE_IS}, $env);
259         }
260
261         if ((!$l->{IS_SURROUNDING}) and $l->{IS_CONFORMANT}) {
262                 pidl "NDR_CHECK(ndr_pull_array_size(ndr, " . get_pointer_to($var_name) . "));";
263         }
264
265
266         if ($l->{IS_VARYING}) {
267                 pidl "NDR_CHECK(ndr_pull_array_length($ndr, " . get_pointer_to($var_name) . "));";
268                 $length = "ndr_get_array_length($ndr, " . get_pointer_to($var_name) .")";
269         }
270
271         check_null_pointer($length);
272
273         if ($length ne $size) {
274                 pidl "if ($length > $size) {";
275                 indent;
276                 pidl "return ndr_pull_error($ndr, NDR_ERR_ARRAY_SIZE, \"Bad array size %u should exceed array length %u\", $size, $length);";
277                 deindent;
278                 pidl "}";
279         }
280
281         if ($l->{IS_CONFORMANT} and not $l->{IS_ZERO_TERMINATED}) {
282                 my $size = Parse::Pidl::Util::ParseExpr($l->{SIZE_IS}, $env);
283                 check_null_pointer($size);
284                 pidl "NDR_CHECK(ndr_check_array_size(ndr, (void*)" . get_pointer_to($var_name) . ", $size));";
285         }
286
287         if ($l->{IS_VARYING} and not $l->{IS_ZERO_TERMINATED}) {
288                 my $length = Parse::Pidl::Util::ParseExpr($l->{LENGTH_IS}, $env);
289                 check_null_pointer($length);
290                 pidl "NDR_CHECK(ndr_check_array_length(ndr, (void*)" . get_pointer_to($var_name) . ", $length));";
291         }
292
293         if (!$l->{IS_FIXED}) {
294                 AllocateArrayLevel($e,$l,$ndr,$env,$size);
295         }
296
297         return $length;
298 }
299
300 sub compression_alg($$)
301 {
302         my ($e,$l) = @_;
303         my $compression = $l->{COMPRESSION};
304         my ($alg, $clen, $dlen) = split(/ /, $compression);
305
306         return $alg;
307 }
308
309 sub compression_clen($$$)
310 {
311         my ($e,$l,$env) = @_;
312         my $compression = $l->{COMPRESSION};
313         my ($alg, $clen, $dlen) = split(/ /, $compression);
314
315         return Parse::Pidl::Util::ParseExpr($clen, $env);
316 }
317
318 sub compression_dlen($$$)
319 {
320         my ($e,$l,$env) = @_;
321         my $compression = $l->{COMPRESSION};
322         my ($alg, $clen, $dlen) = split(/ /, $compression);
323
324         return Parse::Pidl::Util::ParseExpr($dlen, $env);
325 }
326
327 sub ParseCompressionPushStart($$$)
328 {
329         my ($e,$l,$ndr) = @_;
330         my $comndr = "$ndr\_compressed";
331
332         pidl "{";
333         indent;
334         pidl "struct ndr_push *$comndr;";
335         pidl "";
336         pidl "$comndr = ndr_push_init_ctx($ndr);";
337         pidl "if (!$comndr) return NT_STATUS_NO_MEMORY;";
338         pidl "$comndr->flags = $ndr->flags;";
339         pidl "";
340         
341         return $comndr;
342 }
343
344 sub ParseCompressionPushEnd($$$)
345 {
346         my ($e,$l,$ndr) = @_;
347         my $comndr = "$ndr\_compressed";
348         my $alg = compression_alg($e, $l);
349
350         pidl "NDR_CHECK(ndr_push_compression($ndr, $comndr, $alg));";
351         deindent;
352         pidl "}";
353 }
354
355 sub ParseCompressionPullStart($$$$)
356 {
357         my ($e,$l,$ndr,$env) = @_;
358         my $comndr = "$ndr\_compressed";
359         my $alg = compression_alg($e, $l);
360         my $dlen = compression_dlen($e, $l, $env);
361
362         pidl "{";
363         indent;
364         pidl "struct ndr_pull *$comndr;";
365         pidl "NDR_ALLOC($ndr, $comndr);";
366         pidl "NDR_CHECK(ndr_pull_compression($ndr, $comndr, $alg, $dlen));";
367
368         return $comndr;
369 }
370
371 sub ParseCompressionPullEnd($$$)
372 {
373         my ($e,$l,$ndr) = @_;
374         my $comndr = "$ndr\_compressed";
375
376         deindent;
377         pidl "}";
378 }
379
380 sub ParseObfuscationPushStart($$)
381 {
382         my ($e,$ndr) = @_;
383
384         # nothing to do here
385
386         return $ndr;
387 }
388
389 sub ParseObfuscationPushEnd($$)
390 {
391         my ($e,$ndr) = @_;
392         my $obfuscation = Parse::Pidl::Util::has_property($e, "obfuscation");
393
394         pidl "NDR_CHECK(ndr_push_obfuscation($ndr, $obfuscation));";
395 }
396
397 sub ParseObfuscationPullStart($$)
398 {
399         my ($e,$ndr) = @_;
400         my $obfuscation = Parse::Pidl::Util::has_property($e, "obfuscation");
401
402         pidl "NDR_CHECK(ndr_pull_obfuscation($ndr, $obfuscation));";
403
404         return $ndr;
405 }
406
407 sub ParseObfuscationPullEnd($$)
408 {
409         my ($e,$ndr) = @_;
410
411         # nothing to do here
412 }
413
414 sub ParseSubcontextPushStart($$$$$)
415 {
416         my ($e,$l,$ndr,$var_name,$ndr_flags) = @_;
417         my $retndr = "_ndr_$e->{NAME}";
418
419         pidl "{";
420         indent;
421         pidl "struct ndr_push *$retndr;";
422         pidl "";
423         pidl "$retndr = ndr_push_init_ctx($ndr);";
424         pidl "if (!$retndr) return NT_STATUS_NO_MEMORY;";
425         pidl "$retndr->flags = $ndr->flags;";
426         pidl "";
427
428         if (defined $l->{COMPRESSION}) {
429                 $retndr = ParseCompressionPushStart($e, $l, $retndr);
430         }
431
432         if (defined $l->{OBFUSCATION}) {
433                 $retndr = ParseObfuscationPushStart($e, $retndr);
434         }
435
436         return $retndr;
437 }
438
439 sub ParseSubcontextPushEnd($$$$)
440 {
441         my ($e,$l,$ndr_flags,$env) = @_;
442         my $ndr = "_ndr_$e->{NAME}";
443         my $subcontext_size = Parse::Pidl::Util::ParseExpr($l->{SUBCONTEXT_SIZE},$env);
444
445         if (defined $l->{COMPRESSION}) {
446                 ParseCompressionPushEnd($e, $l, $ndr);
447         }
448
449         if (defined $l->{OBFUSCATION}) {
450                 ParseObfuscationPushEnd($e, $ndr);
451         }
452
453         pidl "NDR_CHECK(ndr_push_subcontext_header(ndr, $l->{HEADER_SIZE}, $subcontext_size, $ndr));";
454         pidl "NDR_CHECK(ndr_push_bytes(ndr, $ndr->data, $ndr->offset));";
455         deindent;
456         pidl "}";
457 }
458
459 sub ParseSubcontextPullStart($$$$$$)
460 {
461         my ($e,$l,$ndr,$var_name,$ndr_flags,$env) = @_;
462         my $retndr = "_ndr_$e->{NAME}";
463         my $subcontext_size = Parse::Pidl::Util::ParseExpr($l->{SUBCONTEXT_SIZE},$env);
464
465         pidl "{";
466         indent;
467         pidl "struct ndr_pull *$retndr;";
468         pidl "NDR_ALLOC(ndr, $retndr);";
469         pidl "NDR_CHECK(ndr_pull_subcontext_header($ndr, $l->{HEADER_SIZE}, $subcontext_size, $retndr));"; 
470
471         if (defined $l->{COMPRESSION}) {
472                 $retndr = ParseCompressionPullStart($e, $l, $retndr, $env);
473         }
474
475         if (defined $l->{OBFUSCATION}) {
476                 $retndr = ParseObfuscationPullStart($e, $retndr);
477         }
478         
479         return ($retndr,$var_name);
480 }
481
482 sub ParseSubcontextPullEnd($$$)
483 {
484         my ($e,$l,$env) = @_;
485         my $ndr = "_ndr_$e->{NAME}";
486
487         if (defined $l->{COMPRESSION}) {
488                 ParseCompressionPullEnd($e, $l, $ndr);
489         }
490
491         if (defined $l->{OBFUSCATION}) {
492                 ParseObfuscationPullEnd($e, $ndr);
493         }
494
495         my $advance;
496         if (defined($l->{SUBCONTEXT_SIZE}) and ($l->{SUBCONTEXT_SIZE} ne "-1")) {
497                 $advance = Parse::Pidl::Util::ParseExpr($l->{SUBCONTEXT_SIZE},$env);
498         } elsif ($l->{HEADER_SIZE}) {
499                 $advance = "$ndr->data_size";
500         } else {
501                 $advance = "$ndr->offset";
502         }
503         pidl "NDR_CHECK(ndr_pull_advance(ndr, $advance));";
504         deindent;
505         pidl "}";
506 }
507
508 sub ParseElementPushLevel
509 {
510         my ($e,$l,$ndr,$var_name,$env,$primitives,$deferred) = @_;
511
512         my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
513
514         if (defined($ndr_flags)) {
515                 if ($l->{TYPE} eq "SUBCONTEXT") {
516                         $ndr = ParseSubcontextPushStart($e, $l, $ndr, $var_name, $ndr_flags);
517                         ParseElementPushLevel($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $ndr, $var_name, $env, 1, 1);
518                         ParseSubcontextPushEnd($e, $l, $ndr_flags, $env);
519                 } elsif ($l->{TYPE} eq "POINTER") {
520                         ParsePtrPush($e, $l, $var_name);
521                 } elsif ($l->{TYPE} eq "ARRAY") {
522                         my $length = ParseArrayPushHeader($e, $l, $ndr, $var_name, $env); 
523                         # Allow speedups for arrays of scalar types
524                         if (is_scalar_array($e,$l)) {
525                                 if ($l->{IS_CONFORMANT} or $l->{IS_VARYING}) {
526                                         $var_name = get_pointer_to($var_name);
527                                 }
528
529                                 my $nl = Parse::Pidl::NDR::GetNextLevel($e, $l);
530
531                                 if (Parse::Pidl::Util::has_property($e, "charset")) {
532                                         pidl "NDR_CHECK(ndr_push_charset($ndr, $ndr_flags, $var_name, $length, sizeof(" . Parse::Pidl::Typelist::mapType($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));";
533                                 } else {
534                                         pidl "NDR_CHECK(ndr_push_array_$nl->{DATA_TYPE}($ndr, $ndr_flags, $var_name, $length));";
535                                 } 
536                                 return;
537                         } 
538                 } elsif ($l->{TYPE} eq "SWITCH") {
539                         ParseSwitchPush($e, $l, $ndr, $var_name, $ndr_flags, $env);
540                 } elsif ($l->{TYPE} eq "DATA") {
541                         ParseDataPush($e, $l, $ndr, $var_name, $ndr_flags);
542                 }
543         }
544
545         if ($l->{TYPE} eq "POINTER" and $deferred) {
546                 if ($l->{POINTER_TYPE} ne "ref") {
547                         pidl "if ($var_name) {";
548                         indent;
549                         if ($l->{POINTER_TYPE} eq "relative") {
550                                 pidl "NDR_CHECK(ndr_push_relative_ptr2(ndr, $var_name));";
551                         }
552                 }
553                 $var_name = get_value_of($var_name);
554                 ParseElementPushLevel($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $ndr, $var_name, $env, $primitives, $deferred);
555
556                 if ($l->{POINTER_TYPE} ne "ref") {
557                         deindent;
558                         pidl "}";
559                 }
560         } elsif ($l->{TYPE} eq "ARRAY" and not is_scalar_array($e,$l)) {
561                 my $length = Parse::Pidl::Util::ParseExpr($l->{LENGTH_IS}, $env);
562                 my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
563
564                 $var_name = $var_name . "[$counter]";
565
566                 if ($l->{IS_VARYING} or $l->{IS_CONFORMANT}) {
567                         $var_name = get_pointer_to($var_name);
568                 }
569
570                 if (($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) {
571                         pidl "for ($counter = 0; $counter < $length; $counter++) {";
572                         indent;
573                         ParseElementPushLevel($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $ndr, $var_name, $env, 1, 0);
574                         deindent;
575                         pidl "}";
576                 }
577
578                 if ($deferred and Parse::Pidl::NDR::ContainsDeferred($e, $l)) {
579                         pidl "for ($counter = 0; $counter < $length; $counter++) {";
580                         indent;
581                         ParseElementPushLevel($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $ndr, $var_name, $env, 0, 1);
582                         deindent;
583                         pidl "}";
584                 }       
585         } elsif ($l->{TYPE} eq "SWITCH") {
586                 ParseElementPushLevel($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $ndr, $var_name, $env, $primitives, $deferred);
587         }
588 }
589
590 #####################################################################
591 # parse scalars in a structure element
592 sub ParseElementPush($$$$$$)
593 {
594         my ($e,$ndr,$var_prefix,$env,$primitives,$deferred) = @_;
595         my $subndr = undef;
596
597         my $var_name = $var_prefix.$e->{NAME};
598
599         $var_name = append_prefix($e, $var_name);
600
601         return unless $primitives or ($deferred and Parse::Pidl::NDR::ContainsDeferred($e, $e->{LEVELS}[0]));
602
603         start_flags($e);
604
605         if (my $value = Parse::Pidl::Util::has_property($e, "value")) {
606                 $var_name = Parse::Pidl::Util::ParseExpr($value, $env);
607         }
608
609         ParseElementPushLevel($e, $e->{LEVELS}[0], $ndr, $var_name, $env, $primitives, $deferred);
610
611         end_flags($e);
612 }
613
614 #####################################################################
615 # parse a pointer in a struct element or function
616 sub ParsePtrPush($$$)
617 {
618         my ($e,$l,$var_name) = @_;
619
620         if ($l->{POINTER_TYPE} eq "ref") {
621                 if ($l->{LEVEL} eq "EMBEDDED") {
622                         pidl "NDR_CHECK(ndr_push_ref_ptr(ndr, $var_name));";
623                 } else {
624                         check_null_pointer(get_value_of($var_name));
625                 }
626         } elsif ($l->{POINTER_TYPE} eq "relative") {
627                 pidl "NDR_CHECK(ndr_push_relative_ptr1(ndr, $var_name));";
628         } elsif ($l->{POINTER_TYPE} eq "unique") {
629                 pidl "NDR_CHECK(ndr_push_unique_ptr(ndr, $var_name));";
630         } elsif ($l->{POINTER_TYPE} eq "sptr") {
631                 pidl "NDR_CHECK(ndr_push_sptr_ptr(ndr, $var_name));";
632         } else {
633                 die("Unhandled pointer type $l->{POINTER_TYPE}");
634         }
635 }
636
637 #####################################################################
638 # print scalars in a structure element
639 sub ParseElementPrint($$$)
640 {
641         my($e,$var_name,$env) = @_;
642
643         $var_name = append_prefix($e, $var_name);
644         return if (Parse::Pidl::Util::has_property($e, "noprint"));
645
646         if (my $value = Parse::Pidl::Util::has_property($e, "value")) {
647                 $var_name = "(ndr->flags & LIBNDR_PRINT_SET_VALUES)?" . Parse::Pidl::Util::ParseExpr($value,$env) . ":$var_name";
648         }
649
650         foreach my $l (@{$e->{LEVELS}}) {
651                 if ($l->{TYPE} eq "POINTER") {
652                         pidl "ndr_print_ptr(ndr, \"$e->{NAME}\", $var_name);";
653                         pidl "ndr->depth++;";
654                         if ($l->{POINTER_TYPE} ne "ref") {
655                                 pidl "if ($var_name) {";
656                                 indent;
657                         }
658                         $var_name = get_value_of($var_name);
659                 } elsif ($l->{TYPE} eq "ARRAY") {
660                         my $length;
661
662                         if (is_scalar_array($e, $l) and ($l->{IS_CONFORMANT} or $l->{IS_VARYING})){ 
663                                 $var_name = get_pointer_to($var_name); 
664                         }
665                         
666                         if ($l->{IS_ZERO_TERMINATED}) {
667                                 $length = "ndr_string_length($var_name, sizeof(*$var_name))";
668                         } else {
669                                 $length = Parse::Pidl::Util::ParseExpr($l->{LENGTH_IS}, $env);
670                         }
671
672                         if (is_scalar_array($e, $l)) {
673                                 if (Parse::Pidl::Util::has_property($e, "charset")) {
674                                         pidl "ndr_print_string(ndr, \"$e->{NAME}\", $var_name);";
675                                 } else {
676                                         my $nl = Parse::Pidl::NDR::GetNextLevel($e, $l);
677                                         pidl "ndr_print_array_$nl->{DATA_TYPE}(ndr, \"$e->{NAME}\", $var_name, $length);";
678                                 } 
679                                 last;
680                         }
681
682                         my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
683
684                         pidl "ndr->print(ndr, \"\%s: ARRAY(\%d)\", \"$e->{NAME}\", $length);";
685                         pidl 'ndr->depth++;';
686                         pidl "for ($counter=0;$counter<$length;$counter++) {";
687                         indent;
688                         pidl "char *idx_$l->{LEVEL_INDEX}=NULL;";
689                         pidl "asprintf(&idx_$l->{LEVEL_INDEX}, \"[\%d]\", $counter);";
690                         pidl "if (idx_$l->{LEVEL_INDEX}) {";
691                         indent;
692
693                         $var_name = $var_name . "[$counter]";
694
695                         if ($l->{IS_VARYING} or $l->{IS_CONFORMANT}){ $var_name = get_pointer_to($var_name); }
696
697                 } elsif ($l->{TYPE} eq "DATA") {
698                         if (not Parse::Pidl::Typelist::is_scalar($l->{DATA_TYPE}) or Parse::Pidl::Typelist::scalar_is_reference($l->{DATA_TYPE})) {
699                                 $var_name = get_pointer_to($var_name);
700                         }
701                         pidl "ndr_print_$l->{DATA_TYPE}(ndr, \"$e->{NAME}\", $var_name);";
702                 } elsif ($l->{TYPE} eq "SWITCH") {
703                         my $switch_var = Parse::Pidl::Util::ParseExpr($l->{SWITCH_IS}, $env);
704                         check_null_pointer_void($switch_var);
705                         pidl "ndr_print_set_switch_value(ndr, " . get_pointer_to($var_name) . ", $switch_var);";
706                 } 
707         }
708
709         foreach my $l (reverse @{$e->{LEVELS}}) {
710                 if ($l->{TYPE} eq "POINTER") {
711                         if ($l->{POINTER_TYPE} ne "ref") {
712                                 deindent;
713                                 pidl "}";
714                         }
715                         pidl "ndr->depth--;";
716                 } elsif ($l->{TYPE} eq "ARRAY" and not is_scalar_array($e, $l)) {
717                         pidl "free(idx_$l->{LEVEL_INDEX});";
718                         deindent;
719                         pidl "}";
720                         deindent;
721                         pidl "}";
722                         pidl "ndr->depth--;";
723                 }
724         }
725 }
726
727 #####################################################################
728 # parse scalars in a structure element - pull size
729 sub ParseSwitchPull($$$$$$)
730 {
731         my($e,$l,$ndr,$var_name,$ndr_flags,$env) = @_;
732         my $switch_var = Parse::Pidl::Util::ParseExpr($l->{SWITCH_IS}, $env);
733
734         check_null_pointer($switch_var);
735
736         $var_name = get_pointer_to($var_name);
737         pidl "NDR_CHECK(ndr_pull_set_switch_value($ndr, $var_name, $switch_var));";
738 }
739
740 #####################################################################
741 # push switch element
742 sub ParseSwitchPush($$$$$$)
743 {
744         my($e,$l,$ndr,$var_name,$ndr_flags,$env) = @_;
745         my $switch_var = Parse::Pidl::Util::ParseExpr($l->{SWITCH_IS}, $env);
746
747         check_null_pointer($switch_var);
748         $var_name = get_pointer_to($var_name);
749         pidl "NDR_CHECK(ndr_push_set_switch_value($ndr, $var_name, $switch_var));";
750 }
751
752 sub ParseDataPull($$$$$)
753 {
754         my ($e,$l,$ndr,$var_name,$ndr_flags) = @_;
755
756         if (Parse::Pidl::Typelist::scalar_is_reference($l->{DATA_TYPE})) {
757                 $var_name = get_pointer_to($var_name);
758         }
759
760         $var_name = get_pointer_to($var_name);
761
762         pidl "NDR_CHECK(ndr_pull_$l->{DATA_TYPE}($ndr, $ndr_flags, $var_name));";
763
764         if (my $range = Parse::Pidl::Util::has_property($e, "range")) {
765                 $var_name = get_value_of($var_name);
766                 my ($low, $high) = split(/ /, $range, 2);
767                 pidl "if ($var_name < $low || $var_name > $high) {";
768                 pidl "\treturn ndr_pull_error($ndr, NDR_ERR_RANGE, \"value out of range\");";
769                 pidl "}";
770         }
771 }
772
773 sub ParseDataPush($$$$$)
774 {
775         my ($e,$l,$ndr,$var_name,$ndr_flags) = @_;
776
777         # strings are passed by value rather then reference
778         if (not Parse::Pidl::Typelist::is_scalar($l->{DATA_TYPE}) or Parse::Pidl::Typelist::scalar_is_reference($l->{DATA_TYPE})) {
779                 $var_name = get_pointer_to($var_name);
780         }
781
782         pidl "NDR_CHECK(ndr_push_$l->{DATA_TYPE}($ndr, $ndr_flags, $var_name));";
783 }
784
785 sub CalcNdrFlags($$$)
786 {
787         my ($l,$primitives,$deferred) = @_;
788
789         my $scalars = 0;
790         my $buffers = 0;
791
792         # Add NDR_SCALARS if this one is deferred 
793         # and deferreds may be pushed
794         $scalars = 1 if ($l->{IS_DEFERRED} and $deferred);
795
796         # Add NDR_SCALARS if this one is not deferred and 
797         # primitives may be pushed
798         $scalars = 1 if (!$l->{IS_DEFERRED} and $primitives);
799         
800         # Add NDR_BUFFERS if this one contains deferred stuff
801         # and deferreds may be pushed
802         $buffers = 1 if ($l->{CONTAINS_DEFERRED} and $deferred);
803
804         return "NDR_SCALARS|NDR_BUFFERS" if ($scalars and $buffers);
805         return "NDR_SCALARS" if ($scalars);
806         return "NDR_BUFFERS" if ($buffers);
807         return undef;
808 }
809
810 sub ParseElementPullLevel
811 {
812         my($e,$l,$ndr,$var_name,$env,$primitives,$deferred) = @_;
813
814         my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
815
816         # Only pull something if there's actually something to be pulled
817         if (defined($ndr_flags)) {
818                 if ($l->{TYPE} eq "SUBCONTEXT") {
819                         ($ndr,$var_name) = ParseSubcontextPullStart($e, $l, $ndr, $var_name, $ndr_flags, $env);
820                         ParseElementPullLevel($e,Parse::Pidl::NDR::GetNextLevel($e,$l), $ndr, $var_name, $env, 1, 1);
821                         ParseSubcontextPullEnd($e, $l, $env);
822                 } elsif ($l->{TYPE} eq "ARRAY") {
823                         my $length = ParseArrayPullHeader($e, $l, $ndr, $var_name, $env); 
824
825                         # Speed things up a little - special array pull functions
826                         # for scalars
827                         if (is_scalar_array($e, $l)) {
828                                 if ($l->{IS_VARYING} or $l->{IS_CONFORMANT}) {
829                                         $var_name = get_pointer_to($var_name);
830                                 }
831                                 my $nl = Parse::Pidl::NDR::GetNextLevel($e, $l);
832
833                                 if (Parse::Pidl::Util::has_property($e, "charset")) {
834                                         pidl "NDR_CHECK(ndr_pull_charset($ndr, $ndr_flags, ".get_pointer_to($var_name).", $length, sizeof(" . Parse::Pidl::Typelist::mapType($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));";
835                                 } else {
836                                         pidl "NDR_CHECK(ndr_pull_array_$nl->{DATA_TYPE}($ndr, $ndr_flags, $var_name, $length));";
837                                         if ($l->{IS_ZERO_TERMINATED}) {
838                                                 # Make sure last element is zero!
839                                                 pidl "NDR_CHECK(ndr_check_string_terminator($ndr, $var_name, $length, sizeof(*$var_name)));";
840                                         }
841                                 }
842                                 return;
843                         }
844                 } elsif ($l->{TYPE} eq "POINTER") {
845                         ParsePtrPull($e, $l, $ndr, $var_name);
846                 } elsif ($l->{TYPE} eq "SWITCH") {
847                         ParseSwitchPull($e, $l, $ndr, $var_name, $ndr_flags, $env);
848                 } elsif ($l->{TYPE} eq "DATA") {
849                         ParseDataPull($e, $l, $ndr, $var_name, $ndr_flags);
850                 }
851         }
852
853         # add additional constructions
854         if ($l->{TYPE} eq "POINTER" and $deferred) {
855                 if ($l->{POINTER_TYPE} ne "ref") {
856                         pidl "if ($var_name) {";
857                         indent;
858
859                         if ($l->{POINTER_TYPE} eq "relative") {
860                                 pidl "struct ndr_pull_save _relative_save;";
861                                 pidl "ndr_pull_save(ndr, &_relative_save);";
862                                 pidl "NDR_CHECK(ndr_pull_relative_ptr2(ndr, $var_name));";
863                         }
864                 }
865
866                 $var_name = get_value_of($var_name);
867                 ParseElementPullLevel($e,Parse::Pidl::NDR::GetNextLevel($e,$l), $ndr, $var_name, $env, $primitives, $deferred);
868
869                 if ($l->{POINTER_TYPE} ne "ref") {
870                         if ($l->{POINTER_TYPE} eq "relative") {
871                                 pidl "ndr_pull_restore(ndr, &_relative_save);";
872                         }
873                         deindent;
874                         pidl "}";
875                 }
876         } elsif ($l->{TYPE} eq "ARRAY" and not is_scalar_array($e,$l)) {
877                 my $length = Parse::Pidl::Util::ParseExpr($l->{LENGTH_IS}, $env);
878                 my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
879
880                 $var_name = $var_name . "[$counter]";
881                 if ($l->{IS_VARYING} or $l->{IS_CONFORMANT}) {
882                         $var_name = get_pointer_to($var_name);
883                 }
884
885                 if (($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) {
886                         pidl "for ($counter = 0; $counter < $length; $counter++) {";
887                         indent;
888                         ParseElementPullLevel($e,Parse::Pidl::NDR::GetNextLevel($e,$l), $ndr, $var_name, $env, 1, 0);
889                         deindent;
890                         pidl "}";
891
892                         if ($l->{IS_ZERO_TERMINATED}) {
893                                 # Make sure last element is zero!
894                                 pidl "NDR_CHECK(ndr_check_string_terminator($ndr, $var_name, $length, sizeof(*$var_name)));";
895                         }
896                 }
897
898                 if ($deferred and Parse::Pidl::NDR::ContainsDeferred($e, $l)) {
899                         pidl "for ($counter = 0; $counter < $length; $counter++) {";
900                         indent;
901                         ParseElementPullLevel($e,Parse::Pidl::NDR::GetNextLevel($e,$l), $ndr, $var_name, $env, 0, 1);
902                         deindent;
903                         pidl "}";
904                 }
905         } elsif ($l->{TYPE} eq "SWITCH") {
906                 ParseElementPullLevel($e,Parse::Pidl::NDR::GetNextLevel($e,$l), $ndr, $var_name, $env, $primitives, $deferred);
907         }
908 }
909
910 #####################################################################
911 # parse scalars in a structure element - pull size
912 sub ParseElementPull($$$$$$)
913 {
914         my($e,$ndr,$var_prefix,$env,$primitives,$deferred) = @_;
915
916         my $var_name = $var_prefix.$e->{NAME};
917
918         $var_name = append_prefix($e, $var_name);
919
920         return unless $primitives or ($deferred and Parse::Pidl::NDR::ContainsDeferred($e, $e->{LEVELS}[0]));
921
922         start_flags($e);
923
924         ParseElementPullLevel($e,$e->{LEVELS}[0],$ndr,$var_name,$env,$primitives,$deferred);
925
926         end_flags($e);
927 }
928
929 #####################################################################
930 # parse a pointer in a struct element or function
931 sub ParsePtrPull($$$$)
932 {
933         my($e,$l,$ndr,$var_name) = @_;
934
935         my $nl = Parse::Pidl::NDR::GetNextLevel($e, $l);
936         my $next_is_array = ($nl->{TYPE} eq "ARRAY");
937         my $next_is_string = (($nl->{TYPE} eq "DATA") and 
938                                                  ($nl->{DATA_TYPE} eq "string"));
939
940         if ($l->{POINTER_TYPE} eq "ref") {
941                 unless ($l->{LEVEL} eq "TOP") {
942                         pidl "NDR_CHECK(ndr_pull_ref_ptr($ndr, &_ptr_$e->{NAME}));";
943                 }
944
945                 unless ($next_is_array or $next_is_string) {
946                         pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {";
947                         pidl "\tNDR_ALLOC($ndr, $var_name);"; 
948                         pidl "}";
949                 }
950                 
951                 return;
952         } elsif (($l->{POINTER_TYPE} eq "unique") or 
953                  ($l->{POINTER_TYPE} eq "relative") or
954                  ($l->{POINTER_TYPE} eq "sptr")) {
955                 pidl "NDR_CHECK(ndr_pull_generic_ptr($ndr, &_ptr_$e->{NAME}));";
956                 pidl "if (_ptr_$e->{NAME}) {";
957                 indent;
958         } else {
959                 die("Unhandled pointer type $l->{POINTER_TYPE}");
960         }
961
962         # Don't do this for arrays, they're allocated at the actual level 
963         # of the array
964         unless ($next_is_array or $next_is_string) { 
965                 pidl "NDR_ALLOC($ndr, $var_name);"; 
966         } else {
967                 pidl "NDR_ALLOC_SIZE($ndr, $var_name, 1);"; # FIXME: Yes, this is nasty. We allocate an array twice - once just to indicate that  it's there, then the real allocation...
968         }
969
970         #pidl "memset($var_name, 0, sizeof($var_name));";
971         if ($l->{POINTER_TYPE} eq "relative") {
972                 pidl "NDR_CHECK(ndr_pull_relative_ptr1($ndr, $var_name, _ptr_$e->{NAME}));";
973         }
974         deindent;
975         pidl "} else {";
976         pidl "\t$var_name = NULL;";
977         pidl "}";
978 }
979
980 #####################################################################
981 # parse a struct
982 sub ParseStructPush($$)
983 {
984         my($struct,$name) = @_;
985         
986         return unless defined($struct->{ELEMENTS});
987
988         my $env = GenerateStructEnv($struct);
989
990         # save the old relative_base_offset
991         pidl "uint32_t _save_relative_base_offset = ndr_push_get_relative_base_offset(ndr);" if defined($struct->{PROPERTIES}{relative_base});
992
993         foreach my $e (@{$struct->{ELEMENTS}}) { 
994                 DeclareArrayVariables($e);
995         }
996
997         start_flags($struct);
998
999         # see if the structure contains a conformant array. If it
1000         # does, then it must be the last element of the structure, and
1001         # we need to push the conformant length early, as it fits on
1002         # the wire before the structure (and even before the structure
1003         # alignment)
1004         my $e = $struct->{ELEMENTS}[-1];
1005         if (defined($struct->{SURROUNDING_ELEMENT})) {
1006                 my $e = $struct->{SURROUNDING_ELEMENT};
1007
1008                 if (defined($e->{LEVELS}[0]) and 
1009                         $e->{LEVELS}[0]->{TYPE} eq "ARRAY") {
1010                         my $size = Parse::Pidl::Util::ParseExpr($e->{LEVELS}[0]->{SIZE_IS}, $env);
1011
1012                         pidl "NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, $size));";
1013                 } else {
1014                         pidl "NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_string_array_size(ndr, r->$e->{NAME})));";
1015                 }
1016         }
1017
1018         pidl "if (ndr_flags & NDR_SCALARS) {";
1019         indent;
1020
1021         pidl "NDR_CHECK(ndr_push_align(ndr, $struct->{ALIGN}));";
1022
1023         if (defined($struct->{PROPERTIES}{relative_base})) {
1024                 # set the current offset as base for relative pointers
1025                 # and store it based on the toplevel struct/union
1026                 pidl "NDR_CHECK(ndr_push_setup_relative_base_offset1(ndr, r, ndr->offset));";
1027         }
1028
1029         foreach my $e (@{$struct->{ELEMENTS}}) {
1030                 ParseElementPush($e, "ndr", "r->", $env, 1, 0);
1031         }       
1032
1033         deindent;
1034         pidl "}";
1035
1036         pidl "if (ndr_flags & NDR_BUFFERS) {";
1037         indent;
1038         if (defined($struct->{PROPERTIES}{relative_base})) {
1039                 # retrieve the current offset as base for relative pointers
1040                 # based on the toplevel struct/union
1041                 pidl "NDR_CHECK(ndr_push_setup_relative_base_offset2(ndr, r));";
1042         }
1043         foreach my $e (@{$struct->{ELEMENTS}}) {
1044                 ParseElementPush($e, "ndr", "r->", $env, 0, 1);
1045         }
1046
1047         deindent;
1048         pidl "}";
1049
1050         end_flags($struct);
1051         # restore the old relative_base_offset
1052         pidl "ndr_push_restore_relative_base_offset(ndr, _save_relative_base_offset);" if defined($struct->{PROPERTIES}{relative_base});
1053 }
1054
1055 #####################################################################
1056 # generate a push function for an enum
1057 sub ParseEnumPush($$)
1058 {
1059         my($enum,$name) = @_;
1060         my($type_fn) = $enum->{BASE_TYPE};
1061
1062         start_flags($enum);
1063         pidl "NDR_CHECK(ndr_push_$type_fn(ndr, NDR_SCALARS, r));";
1064         end_flags($enum);
1065 }
1066
1067 #####################################################################
1068 # generate a pull function for an enum
1069 sub ParseEnumPull($$)
1070 {
1071         my($enum,$name) = @_;
1072         my($type_fn) = $enum->{BASE_TYPE};
1073         my($type_v_decl) = Parse::Pidl::Typelist::mapType($type_fn);
1074
1075         pidl "$type_v_decl v;";
1076         start_flags($enum);
1077         pidl "NDR_CHECK(ndr_pull_$type_fn(ndr, NDR_SCALARS, &v));";
1078         pidl "*r = v;";
1079
1080         end_flags($enum);
1081 }
1082
1083 #####################################################################
1084 # generate a print function for an enum
1085 sub ParseEnumPrint($$)
1086 {
1087         my($enum,$name) = @_;
1088
1089         pidl "const char *val = NULL;";
1090         pidl "";
1091
1092         start_flags($enum);
1093
1094         pidl "switch (r) {";
1095         indent;
1096         my $els = \@{$enum->{ELEMENTS}};
1097         foreach my $i (0 .. $#{$els}) {
1098                 my $e = ${$els}[$i];
1099                 chomp $e;
1100                 if ($e =~ /^(.*)=/) {
1101                         $e = $1;
1102                 }
1103                 pidl "case $e: val = \"$e\"; break;";
1104         }
1105
1106         deindent;
1107         pidl "}";
1108         
1109         pidl "ndr_print_enum(ndr, name, \"$enum->{TYPE}\", val, r);";
1110
1111         end_flags($enum);
1112 }
1113
1114 sub ArgsEnumPush($)
1115 {
1116         my $e = shift;
1117         return "struct ndr_push *ndr, int ndr_flags, enum $e->{NAME} r";
1118 }
1119
1120 sub ArgsEnumPrint($)
1121 {
1122         my $e = shift;
1123         return "struct ndr_print *ndr, const char *name, enum $e->{NAME} r";
1124 }
1125
1126 sub ArgsEnumPull($)
1127 {
1128         my $e = shift;
1129         return "struct ndr_pull *ndr, int ndr_flags, enum $e->{NAME} *r";
1130 }
1131
1132 $typefamily{ENUM} = {
1133         PUSH_FN_BODY => \&ParseEnumPush,
1134         PUSH_FN_ARGS => \&ArgsEnumPush,
1135         PULL_FN_BODY => \&ParseEnumPull,
1136         PULL_FN_ARGS => \&ArgsEnumPull,
1137         PRINT_FN_BODY => \&ParseEnumPrint,
1138         PRINT_FN_ARGS => \&ArgsEnumPrint,
1139 };
1140
1141 #####################################################################
1142 # generate a push function for a bitmap
1143 sub ParseBitmapPush($$)
1144 {
1145         my($bitmap,$name) = @_;
1146         my($type_fn) = $bitmap->{BASE_TYPE};
1147
1148         start_flags($bitmap);
1149
1150         pidl "NDR_CHECK(ndr_push_$type_fn(ndr, NDR_SCALARS, r));";
1151
1152         end_flags($bitmap);
1153 }
1154
1155 #####################################################################
1156 # generate a pull function for an bitmap
1157 sub ParseBitmapPull($$)
1158 {
1159         my($bitmap,$name) = @_;
1160         my $type_fn = $bitmap->{BASE_TYPE};
1161         my($type_decl) = Parse::Pidl::Typelist::mapType($bitmap->{BASE_TYPE});
1162
1163         pidl "$type_decl v;";
1164         start_flags($bitmap);
1165         pidl "NDR_CHECK(ndr_pull_$type_fn(ndr, NDR_SCALARS, &v));";
1166         pidl "*r = v;";
1167
1168         end_flags($bitmap);
1169 }
1170
1171 #####################################################################
1172 # generate a print function for an bitmap
1173 sub ParseBitmapPrintElement($$$)
1174 {
1175         my($e,$bitmap,$name) = @_;
1176         my($type_decl) = Parse::Pidl::Typelist::mapType($bitmap->{BASE_TYPE});
1177         my($type_fn) = $bitmap->{BASE_TYPE};
1178         my($flag);
1179
1180         if ($e =~ /^(\w+) .*$/) {
1181                 $flag = "$1";
1182         } else {
1183                 die "Bitmap: \"$name\" invalid Flag: \"$e\"";
1184         }
1185
1186         pidl "ndr_print_bitmap_flag(ndr, sizeof($type_decl), \"$flag\", $flag, r);";
1187 }
1188
1189 #####################################################################
1190 # generate a print function for an bitmap
1191 sub ParseBitmapPrint($$)
1192 {
1193         my($bitmap,$name) = @_;
1194         my($type_decl) = Parse::Pidl::Typelist::mapType($bitmap->{TYPE});
1195         my($type_fn) = $bitmap->{BASE_TYPE};
1196
1197         start_flags($bitmap);
1198
1199         pidl "ndr_print_$type_fn(ndr, name, r);";
1200
1201         pidl "ndr->depth++;";
1202         foreach my $e (@{$bitmap->{ELEMENTS}}) {
1203                 ParseBitmapPrintElement($e, $bitmap, $name);
1204         }
1205         pidl "ndr->depth--;";
1206
1207         end_flags($bitmap);
1208 }
1209
1210 sub ArgsBitmapPush($)
1211 {
1212         my $e = shift;
1213         my $type_decl = Parse::Pidl::Typelist::mapType($e->{DATA}->{BASE_TYPE});
1214         return "struct ndr_push *ndr, int ndr_flags, $type_decl r";
1215 }
1216
1217 sub ArgsBitmapPrint($)
1218 {
1219         my $e = shift;
1220         my $type_decl = Parse::Pidl::Typelist::mapType($e->{DATA}->{BASE_TYPE});
1221         return "struct ndr_print *ndr, const char *name, $type_decl r";
1222 }
1223
1224 sub ArgsBitmapPull($)
1225 {
1226         my $e = shift;
1227         my $type_decl = Parse::Pidl::Typelist::mapType($e->{DATA}->{BASE_TYPE});
1228         return "struct ndr_pull *ndr, int ndr_flags, $type_decl *r";
1229 }
1230
1231 $typefamily{BITMAP} = {
1232         PUSH_FN_BODY => \&ParseBitmapPush,
1233         PUSH_FN_ARGS => \&ArgsBitmapPush,
1234         PULL_FN_BODY => \&ParseBitmapPull,
1235         PULL_FN_ARGS => \&ArgsBitmapPull,
1236         PRINT_FN_BODY => \&ParseBitmapPrint,
1237         PRINT_FN_ARGS => \&ArgsBitmapPrint,
1238 };
1239
1240 #####################################################################
1241 # generate a struct print function
1242 sub ParseStructPrint($$)
1243 {
1244         my($struct,$name) = @_;
1245
1246         return unless defined $struct->{ELEMENTS};
1247
1248         my $env = GenerateStructEnv($struct);
1249
1250         foreach my $e (@{$struct->{ELEMENTS}}) {
1251                 DeclareArrayVariables($e);
1252         }
1253
1254         pidl "ndr_print_struct(ndr, name, \"$name\");";
1255
1256         start_flags($struct);
1257
1258         pidl "ndr->depth++;";
1259         foreach my $e (@{$struct->{ELEMENTS}}) {
1260                 ParseElementPrint($e, "r->$e->{NAME}", $env);
1261         }
1262         pidl "ndr->depth--;";
1263
1264         end_flags($struct);
1265 }
1266
1267 sub DeclarePtrVariables($)
1268 {
1269         my $e = shift;
1270         foreach my $l (@{$e->{LEVELS}}) {
1271                 if ($l->{TYPE} eq "POINTER" and 
1272                         not ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "TOP")) {
1273                         pidl "uint32_t _ptr_$e->{NAME};";
1274                         last;
1275                 }
1276         }
1277 }
1278
1279 sub DeclareArrayVariables($)
1280 {
1281         my $e = shift;
1282
1283         foreach my $l (@{$e->{LEVELS}}) {
1284                 next if (is_scalar_array($e,$l));
1285                 if ($l->{TYPE} eq "ARRAY") {
1286                         pidl "uint32_t cntr_$e->{NAME}_$l->{LEVEL_INDEX};";
1287                 }
1288         }
1289 }
1290
1291 #####################################################################
1292 # parse a struct - pull side
1293 sub ParseStructPull($$)
1294 {
1295         my($struct,$name) = @_;
1296
1297         return unless defined $struct->{ELEMENTS};
1298
1299         my $env = GenerateStructEnv($struct);
1300
1301         # declare any internal pointers we need
1302         foreach my $e (@{$struct->{ELEMENTS}}) {
1303                 DeclarePtrVariables($e);
1304                 DeclareArrayVariables($e);
1305         }
1306
1307         # save the old relative_base_offset
1308         pidl "uint32_t _save_relative_base_offset = ndr_pull_get_relative_base_offset(ndr);" if defined($struct->{PROPERTIES}{relative_base});
1309
1310         start_flags($struct);
1311
1312         pidl "if (ndr_flags & NDR_SCALARS) {";
1313         indent;
1314
1315         if (defined $struct->{SURROUNDING_ELEMENT}) {
1316                 pidl "NDR_CHECK(ndr_pull_array_size(ndr, &r->$struct->{SURROUNDING_ELEMENT}->{NAME}));";
1317         }
1318
1319         pidl "NDR_CHECK(ndr_pull_align(ndr, $struct->{ALIGN}));";
1320
1321         if (defined($struct->{PROPERTIES}{relative_base})) {
1322                 # set the current offset as base for relative pointers
1323                 # and store it based on the toplevel struct/union
1324                 pidl "NDR_CHECK(ndr_pull_setup_relative_base_offset1(ndr, r, ndr->offset));";
1325         }
1326
1327         foreach my $e (@{$struct->{ELEMENTS}}) {
1328                 ParseElementPull($e, "ndr", "r->", $env, 1, 0);
1329         }       
1330
1331         deindent;
1332         pidl "}";
1333         pidl "if (ndr_flags & NDR_BUFFERS) {";
1334         indent;
1335         if (defined($struct->{PROPERTIES}{relative_base})) {
1336                 # retrieve the current offset as base for relative pointers
1337                 # based on the toplevel struct/union
1338                 pidl "NDR_CHECK(ndr_pull_setup_relative_base_offset2(ndr, r));";
1339         }
1340         foreach my $e (@{$struct->{ELEMENTS}}) {
1341                 ParseElementPull($e, "ndr", "r->", $env, 0, 1);
1342         }
1343
1344         deindent;
1345         pidl "}";
1346
1347         end_flags($struct);
1348         # restore the old relative_base_offset
1349         pidl "ndr_pull_restore_relative_base_offset(ndr, _save_relative_base_offset);" if defined($struct->{PROPERTIES}{relative_base});
1350 }
1351
1352 #####################################################################
1353 # calculate size of ndr struct
1354 sub ParseStructNdrSize($)
1355 {
1356         my $t = shift;
1357         my $sizevar;
1358
1359         if (my $flags = Parse::Pidl::Util::has_property($t, "flag")) {
1360                 pidl "flags |= $flags;";
1361         }
1362         pidl "return ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_$t->{NAME});";
1363 }
1364
1365 sub ArgsStructPush($)
1366 {
1367         my $e = shift;
1368         return "struct ndr_push *ndr, int ndr_flags, const struct $e->{NAME} *r";
1369 }
1370
1371 sub ArgsStructPrint($)
1372 {
1373         my $e = shift;
1374         return "struct ndr_print *ndr, const char *name, const struct $e->{NAME} *r";
1375 }
1376
1377 sub ArgsStructPull($)
1378 {
1379         my $e = shift;
1380         return "struct ndr_pull *ndr, int ndr_flags, struct $e->{NAME} *r";
1381 }
1382
1383 sub ArgsStructNdrSize($)
1384 {
1385         my $d = shift;
1386         return "const struct $d->{NAME} *r, int flags";
1387 }
1388
1389 $typefamily{STRUCT} = {
1390         PUSH_FN_BODY => \&ParseStructPush,
1391         PUSH_FN_ARGS => \&ArgsStructPush,
1392         PULL_FN_BODY => \&ParseStructPull,
1393         PULL_FN_ARGS => \&ArgsStructPull,
1394         PRINT_FN_BODY => \&ParseStructPrint,
1395         PRINT_FN_ARGS => \&ArgsStructPrint,
1396         SIZE_FN_BODY => \&ParseStructNdrSize,
1397         SIZE_FN_ARGS => \&ArgsStructNdrSize,
1398 };
1399
1400 #####################################################################
1401 # calculate size of ndr struct
1402 sub ParseUnionNdrSize($)
1403 {
1404         my $t = shift;
1405         my $sizevar;
1406
1407         if (my $flags = Parse::Pidl::Util::has_property($t, "flag")) {
1408                 pidl "flags |= $flags;";
1409         }
1410
1411         pidl "return ndr_size_union(r, flags, level, (ndr_push_flags_fn_t)ndr_push_$t->{NAME});";
1412 }
1413
1414 #####################################################################
1415 # parse a union - push side
1416 sub ParseUnionPush($$)
1417 {
1418         my ($e,$name) = @_;
1419         my $have_default = 0;
1420
1421         # save the old relative_base_offset
1422         pidl "uint32_t _save_relative_base_offset = ndr_push_get_relative_base_offset(ndr);" if defined($e->{PROPERTIES}{relative_base});
1423         pidl "int level;";
1424
1425         start_flags($e);
1426
1427         pidl "level = ndr_push_get_switch_value(ndr, r);";
1428
1429         pidl "if (ndr_flags & NDR_SCALARS) {";
1430         indent;
1431
1432         if (defined($e->{SWITCH_TYPE})) {
1433                 pidl "NDR_CHECK(ndr_push_$e->{SWITCH_TYPE}(ndr, NDR_SCALARS, level));";
1434         }
1435
1436         pidl "switch (level) {";
1437         indent;
1438         foreach my $el (@{$e->{ELEMENTS}}) {
1439                 if ($el->{CASE} eq "default") {
1440                         $have_default = 1;
1441                 }
1442                 pidl "$el->{CASE}:";
1443
1444                 if ($el->{TYPE} ne "EMPTY") {
1445                         indent;
1446                         if (defined($e->{PROPERTIES}{relative_base})) {
1447                                 pidl "NDR_CHECK(ndr_push_align(ndr, $el->{ALIGN}));";
1448                                 # set the current offset as base for relative pointers
1449                                 # and store it based on the toplevel struct/union
1450                                 pidl "NDR_CHECK(ndr_push_setup_relative_base_offset1(ndr, r, ndr->offset));";
1451                         }
1452                         DeclareArrayVariables($el);
1453                         ParseElementPush($el, "ndr", "r->", {}, 1, 0);
1454                         deindent;
1455                 }
1456                 pidl "break;";
1457                 pidl "";
1458         }
1459         if (! $have_default) {
1460                 pidl "default:";
1461                 pidl "\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1462         }
1463         deindent;
1464         pidl "}";
1465         deindent;
1466         pidl "}";
1467         pidl "if (ndr_flags & NDR_BUFFERS) {";
1468         indent;
1469         if (defined($e->{PROPERTIES}{relative_base})) {
1470                 # retrieve the current offset as base for relative pointers
1471                 # based on the toplevel struct/union
1472                 pidl "NDR_CHECK(ndr_push_setup_relative_base_offset2(ndr, r));";
1473         }
1474         pidl "switch (level) {";
1475         indent;
1476         foreach my $el (@{$e->{ELEMENTS}}) {
1477                 pidl "$el->{CASE}:";
1478                 if ($el->{TYPE} ne "EMPTY") {
1479                         indent;
1480                         ParseElementPush($el, "ndr", "r->", {}, 0, 1);
1481                         deindent;
1482                 }
1483                 pidl "break;";
1484                 pidl "";
1485         }
1486         if (! $have_default) {
1487                 pidl "default:";
1488                 pidl "\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1489         }
1490         deindent;
1491         pidl "}";
1492
1493         deindent;
1494         pidl "}";
1495         end_flags($e);
1496         # restore the old relative_base_offset
1497         pidl "ndr_push_restore_relative_base_offset(ndr, _save_relative_base_offset);" if defined($e->{PROPERTIES}{relative_base});
1498 }
1499
1500 #####################################################################
1501 # print a union
1502 sub ParseUnionPrint($$)
1503 {
1504         my ($e,$name) = @_;
1505         my $have_default = 0;
1506
1507         pidl "int level = ndr_print_get_switch_value(ndr, r);";
1508
1509         foreach my $el (@{$e->{ELEMENTS}}) {
1510                 DeclareArrayVariables($el);
1511         }
1512
1513         pidl "ndr_print_union(ndr, name, level, \"$name\");";
1514         start_flags($e);
1515
1516         pidl "switch (level) {";
1517         indent;
1518         foreach my $el (@{$e->{ELEMENTS}}) {
1519                 if ($el->{CASE} eq "default") {
1520                         $have_default = 1;
1521                 }
1522                 pidl "$el->{CASE}:";
1523                 if ($el->{TYPE} ne "EMPTY") {
1524                         indent;
1525                         ParseElementPrint($el, "r->$el->{NAME}", {});
1526                         deindent;
1527                 }
1528                 pidl "break;";
1529                 pidl "";
1530         }
1531         if (! $have_default) {
1532                 pidl "default:";
1533                 pidl "\tndr_print_bad_level(ndr, name, level);";
1534         }
1535         deindent;
1536         pidl "}";
1537
1538         end_flags($e);
1539 }
1540
1541 #####################################################################
1542 # parse a union - pull side
1543 sub ParseUnionPull($$)
1544 {
1545         my ($e,$name) = @_;
1546         my $have_default = 0;
1547         my $switch_type = $e->{SWITCH_TYPE};
1548
1549         # save the old relative_base_offset
1550         pidl "uint32_t _save_relative_base_offset = ndr_pull_get_relative_base_offset(ndr);" if defined($e->{PROPERTIES}{relative_base});
1551         pidl "int level;";
1552         if (defined($switch_type)) {
1553                 if (Parse::Pidl::Typelist::typeIs($switch_type, "ENUM")) {
1554                         $switch_type = Parse::Pidl::Typelist::enum_type_fn(Parse::Pidl::Typelist::getType($switch_type));
1555                 }
1556                 pidl Parse::Pidl::Typelist::mapType($switch_type) . " _level;";
1557         }
1558
1559         start_flags($e);
1560
1561         pidl "level = ndr_pull_get_switch_value(ndr, r);";
1562
1563         pidl "if (ndr_flags & NDR_SCALARS) {";
1564         indent;
1565
1566         if (defined($switch_type)) {
1567                 pidl "NDR_CHECK(ndr_pull_$switch_type(ndr, NDR_SCALARS, &_level));";
1568                 pidl "if (_level != level) {"; 
1569                 pidl "\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value %u for $name\", _level);";
1570                 pidl "}";
1571         }
1572
1573         pidl "switch (level) {";
1574         indent;
1575         foreach my $el (@{$e->{ELEMENTS}}) {
1576                 if ($el->{CASE} eq "default") {
1577                         $have_default = 1;
1578                 } 
1579                 pidl "$el->{CASE}: {";
1580
1581                 if ($el->{TYPE} ne "EMPTY") {
1582                         indent;
1583                         DeclarePtrVariables($el);
1584                         DeclareArrayVariables($el);
1585                         if (defined($e->{PROPERTIES}{relative_base})) {
1586                                 pidl "NDR_CHECK(ndr_pull_align(ndr, $el->{ALIGN}));";
1587                                 # set the current offset as base for relative pointers
1588                                 # and store it based on the toplevel struct/union
1589                                 pidl "NDR_CHECK(ndr_pull_setup_relative_base_offset1(ndr, r, ndr->offset));";
1590                         }
1591                         ParseElementPull($el, "ndr", "r->", {}, 1, 0);
1592                         deindent;
1593                 }
1594                 pidl "break; }";
1595                 pidl "";
1596         }
1597         if (! $have_default) {
1598                 pidl "default:";
1599                 pidl "\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1600         }
1601         deindent;
1602         pidl "}";
1603         deindent;
1604         pidl "}";
1605         pidl "if (ndr_flags & NDR_BUFFERS) {";
1606         indent;
1607         if (defined($e->{PROPERTIES}{relative_base})) {
1608                 # retrieve the current offset as base for relative pointers
1609                 # based on the toplevel struct/union
1610                 pidl "NDR_CHECK(ndr_pull_setup_relative_base_offset2(ndr, r));";
1611         }
1612         pidl "switch (level) {";
1613         indent;
1614         foreach my $el (@{$e->{ELEMENTS}}) {
1615                 pidl "$el->{CASE}:";
1616                 if ($el->{TYPE} ne "EMPTY") {
1617                         indent;
1618                         ParseElementPull($el, "ndr", "r->", {}, 0, 1);
1619                         deindent;
1620                 }
1621                 pidl "break;";
1622                 pidl "";
1623         }
1624         if (! $have_default) {
1625                 pidl "default:";
1626                 pidl "\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1627         }
1628         deindent;
1629         pidl "}";
1630
1631         deindent;
1632         pidl "}";
1633         end_flags($e);
1634         # restore the old relative_base_offset
1635         pidl "ndr_pull_restore_relative_base_offset(ndr, _save_relative_base_offset);" if defined($e->{PROPERTIES}{relative_base});
1636 }
1637
1638 sub ArgsUnionPush($)
1639 {
1640         my $e = shift;
1641         return "struct ndr_push *ndr, int ndr_flags, const union $e->{NAME} *r";
1642 }
1643
1644 sub ArgsUnionPrint($)
1645 {
1646         my $e = shift;
1647         return "struct ndr_print *ndr, const char *name, const union $e->{NAME} *r";
1648 }
1649
1650 sub ArgsUnionPull($)
1651 {
1652         my $e = shift;
1653         return "struct ndr_pull *ndr, int ndr_flags, union $e->{NAME} *r";
1654 }
1655
1656 sub ArgsUnionNdrSize($)
1657 {
1658         my $d = shift;
1659         return "const union $d->{NAME} *r, uint32_t level, int flags";
1660 }
1661
1662 $typefamily{UNION} = {
1663         PUSH_FN_BODY => \&ParseUnionPush,
1664         PUSH_FN_ARGS => \&ArgsUnionPush,
1665         PULL_FN_BODY => \&ParseUnionPull,
1666         PULL_FN_ARGS => \&ArgsUnionPull,
1667         PRINT_FN_BODY => \&ParseUnionPrint,
1668         PRINT_FN_ARGS => \&ArgsUnionPrint,
1669         SIZE_FN_ARGS => \&ArgsUnionNdrSize,
1670         SIZE_FN_BODY => \&ParseUnionNdrSize,
1671 };
1672         
1673 #####################################################################
1674 # parse a typedef - push side
1675 sub ParseTypedefPush($)
1676 {
1677         my($e) = shift;
1678
1679         my $args = $typefamily{$e->{DATA}->{TYPE}}->{PUSH_FN_ARGS}->($e);
1680         pidl fn_prefix($e) . "NTSTATUS ndr_push_$e->{NAME}($args)";
1681
1682         pidl "{";
1683         indent;
1684         $typefamily{$e->{DATA}->{TYPE}}->{PUSH_FN_BODY}->($e->{DATA}, $e->{NAME});
1685         pidl "return NT_STATUS_OK;";
1686         deindent;
1687         pidl "}";
1688         pidl "";;
1689 }
1690
1691 #####################################################################
1692 # parse a typedef - pull side
1693 sub ParseTypedefPull($)
1694 {
1695         my($e) = shift;
1696
1697         my $args = $typefamily{$e->{DATA}->{TYPE}}->{PULL_FN_ARGS}->($e);
1698
1699         pidl fn_prefix($e) . "NTSTATUS ndr_pull_$e->{NAME}($args)";
1700
1701         pidl "{";
1702         indent;
1703         $typefamily{$e->{DATA}->{TYPE}}->{PULL_FN_BODY}->($e->{DATA}, $e->{NAME});
1704         pidl "return NT_STATUS_OK;";
1705         deindent;
1706         pidl "}";
1707         pidl "";
1708 }
1709
1710 #####################################################################
1711 # parse a typedef - print side
1712 sub ParseTypedefPrint($)
1713 {
1714         my($e) = shift;
1715
1716         my $args = $typefamily{$e->{DATA}->{TYPE}}->{PRINT_FN_ARGS}->($e);
1717
1718         pidl "void ndr_print_$e->{NAME}($args)";
1719         pidl "{";
1720         indent;
1721         $typefamily{$e->{DATA}->{TYPE}}->{PRINT_FN_BODY}->($e->{DATA}, $e->{NAME});
1722         deindent;
1723         pidl "}";
1724         pidl "";
1725 }
1726
1727 #####################################################################
1728 ## calculate the size of a structure
1729 sub ParseTypedefNdrSize($)
1730 {
1731         my($t) = shift;
1732
1733         my $tf = $typefamily{$t->{DATA}->{TYPE}};
1734         my $args = $tf->{SIZE_FN_ARGS}->($t);
1735
1736         pidl "size_t ndr_size_$t->{NAME}($args)";
1737         pidl "{";
1738         indent;
1739         $typefamily{$t->{DATA}->{TYPE}}->{SIZE_FN_BODY}->($t);
1740         deindent;
1741         pidl "}";
1742         pidl "";
1743 }
1744
1745 #####################################################################
1746 # parse a function - print side
1747 sub ParseFunctionPrint($)
1748 {
1749         my($fn) = shift;
1750
1751         return if Parse::Pidl::Util::has_property($fn, "noprint");
1752
1753         pidl "void ndr_print_$fn->{NAME}(struct ndr_print *ndr, const char *name, int flags, const struct $fn->{NAME} *r)";
1754         pidl "{";
1755         indent;
1756
1757         foreach my $e (@{$fn->{ELEMENTS}}) {
1758                 DeclareArrayVariables($e);
1759         }
1760
1761         pidl "ndr_print_struct(ndr, name, \"$fn->{NAME}\");";
1762         pidl "ndr->depth++;";
1763
1764         pidl "if (flags & NDR_SET_VALUES) {";
1765         pidl "\tndr->flags |= LIBNDR_PRINT_SET_VALUES;";
1766         pidl "}";
1767
1768         pidl "if (flags & NDR_IN) {";
1769         indent;
1770         pidl "ndr_print_struct(ndr, \"in\", \"$fn->{NAME}\");";
1771         pidl "ndr->depth++;";
1772
1773         my $env = GenerateFunctionInEnv($fn);
1774
1775         foreach my $e (@{$fn->{ELEMENTS}}) {
1776                 if (grep(/in/,@{$e->{DIRECTION}})) {
1777                         ParseElementPrint($e, "r->in.$e->{NAME}", $env);
1778                 }
1779         }
1780         pidl "ndr->depth--;";
1781         deindent;
1782         pidl "}";
1783         
1784         pidl "if (flags & NDR_OUT) {";
1785         indent;
1786         pidl "ndr_print_struct(ndr, \"out\", \"$fn->{NAME}\");";
1787         pidl "ndr->depth++;";
1788
1789         $env = GenerateFunctionOutEnv($fn);
1790         foreach my $e (@{$fn->{ELEMENTS}}) {
1791                 if (grep(/out/,@{$e->{DIRECTION}})) {
1792                         ParseElementPrint($e, "r->out.$e->{NAME}", $env);
1793                 }
1794         }
1795         if ($fn->{RETURN_TYPE}) {
1796                 pidl "ndr_print_$fn->{RETURN_TYPE}(ndr, \"result\", r->out.result);";
1797         }
1798         pidl "ndr->depth--;";
1799         deindent;
1800         pidl "}";
1801         
1802         pidl "ndr->depth--;";
1803         deindent;
1804         pidl "}";
1805         pidl "";
1806 }
1807
1808 #####################################################################
1809 # parse a function
1810 sub ParseFunctionPush($)
1811
1812         my($fn) = shift;
1813
1814         return if Parse::Pidl::Util::has_property($fn, "nopush");
1815
1816         pidl fn_prefix($fn) . "NTSTATUS ndr_push_$fn->{NAME}(struct ndr_push *ndr, int flags, const struct $fn->{NAME} *r)";
1817         pidl "{";
1818         indent;
1819
1820         foreach my $e (@{$fn->{ELEMENTS}}) { 
1821                 DeclareArrayVariables($e);
1822         }
1823
1824         pidl "if (flags & NDR_IN) {";
1825         indent;
1826
1827         my $env = GenerateFunctionInEnv($fn);
1828
1829         foreach my $e (@{$fn->{ELEMENTS}}) {
1830                 if (grep(/in/,@{$e->{DIRECTION}})) {
1831                         ParseElementPush($e, "ndr", "r->in.", $env, 1, 1);
1832                 }
1833         }
1834
1835         deindent;
1836         pidl "}";
1837
1838         pidl "if (flags & NDR_OUT) {";
1839         indent;
1840
1841         $env = GenerateFunctionOutEnv($fn);
1842         foreach my $e (@{$fn->{ELEMENTS}}) {
1843                 if (grep(/out/,@{$e->{DIRECTION}})) {
1844                         ParseElementPush($e, "ndr", "r->out.", $env, 1, 1);
1845                 }
1846         }
1847
1848         if ($fn->{RETURN_TYPE}) {
1849                 pidl "NDR_CHECK(ndr_push_$fn->{RETURN_TYPE}(ndr, NDR_SCALARS, r->out.result));";
1850         }
1851     
1852         deindent;
1853         pidl "}";
1854         pidl "return NT_STATUS_OK;";
1855         deindent;
1856         pidl "}";
1857         pidl "";
1858 }
1859
1860 sub AllocateArrayLevel($$$$$)
1861 {
1862         my ($e,$l,$ndr,$env,$size) = @_;
1863
1864         return if (Parse::Pidl::Util::has_property($e, "charset"));
1865
1866         my $var = Parse::Pidl::Util::ParseExpr($e->{NAME}, $env);
1867
1868         check_null_pointer($size);
1869         my $pl = Parse::Pidl::NDR::GetPrevLevel($e, $l);
1870         if (defined($pl) and 
1871             $pl->{TYPE} eq "POINTER" and 
1872             $pl->{POINTER_TYPE} eq "ref"
1873                 and not $l->{IS_ZERO_TERMINATED}) {
1874             pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {";
1875             pidl "\tNDR_ALLOC_N($ndr, $var, $size);";
1876             pidl "}";
1877         } else {
1878                 pidl "NDR_ALLOC_N($ndr, $var, $size);";
1879         }
1880
1881         if (grep(/in/,@{$e->{DIRECTION}}) and
1882             grep(/out/,@{$e->{DIRECTION}})) {
1883                 pidl "memcpy(r->out.$e->{NAME},r->in.$e->{NAME},$size * sizeof(*r->in.$e->{NAME}));";
1884         }
1885 }
1886
1887 #####################################################################
1888 # parse a function
1889 sub ParseFunctionPull($)
1890
1891         my($fn) = shift;
1892
1893         return if Parse::Pidl::Util::has_property($fn, "nopull");
1894
1895         # pull function args
1896         pidl fn_prefix($fn) . "NTSTATUS ndr_pull_$fn->{NAME}(struct ndr_pull *ndr, int flags, struct $fn->{NAME} *r)";
1897         pidl "{";
1898         indent;
1899
1900         # declare any internal pointers we need
1901         foreach my $e (@{$fn->{ELEMENTS}}) { 
1902                 DeclarePtrVariables($e); 
1903                 DeclareArrayVariables($e);
1904         }
1905
1906         pidl "if (flags & NDR_IN) {";
1907         indent;
1908
1909         # auto-init the out section of a structure. I originally argued that
1910         # this was a bad idea as it hides bugs, but coping correctly
1911         # with initialisation and not wiping ref vars is turning
1912         # out to be too tricky (tridge)
1913         foreach my $e (@{$fn->{ELEMENTS}}) {
1914                 next unless grep(/out/, @{$e->{DIRECTION}});
1915                 pidl "ZERO_STRUCT(r->out);";
1916                 pidl "";
1917                 last;
1918         }
1919
1920         my $env = GenerateFunctionInEnv($fn);
1921
1922         foreach my $e (@{$fn->{ELEMENTS}}) {
1923                 next unless (grep(/in/, @{$e->{DIRECTION}}));
1924                 ParseElementPull($e, "ndr", "r->in.", $env, 1, 1);
1925         }
1926
1927         # allocate the "simple" out ref variables. FIXME: Shouldn't this have it's
1928         # own flag rather then be in NDR_IN ?
1929
1930         foreach my $e (@{$fn->{ELEMENTS}}) {
1931                 next unless (grep(/out/, @{$e->{DIRECTION}}));
1932                 next unless ($e->{LEVELS}[0]->{TYPE} eq "POINTER" and 
1933                              $e->{LEVELS}[0]->{POINTER_TYPE} eq "ref");
1934                 next if (($e->{LEVELS}[1]->{TYPE} eq "DATA") and 
1935                                  ($e->{LEVELS}[1]->{DATA_TYPE} eq "string"));
1936                 next if (($e->{LEVELS}[1]->{TYPE} eq "ARRAY") 
1937                         and   $e->{LEVELS}[1]->{IS_ZERO_TERMINATED});
1938
1939                 if ($e->{LEVELS}[1]->{TYPE} eq "ARRAY") {
1940                         my $size = Parse::Pidl::Util::ParseExpr($e->{LEVELS}[1]->{SIZE_IS}, $env);
1941                         check_null_pointer($size);
1942                         
1943                         pidl "NDR_ALLOC_N(ndr, r->out.$e->{NAME}, $size);";
1944
1945                         if (grep(/in/, @{$e->{DIRECTION}})) {
1946                                 pidl "memcpy(r->out.$e->{NAME}, r->in.$e->{NAME}, $size * sizeof(*r->in.$e->{NAME}));";
1947                         } else {
1948                                 pidl "memset(r->out.$e->{NAME}, 0, $size * sizeof(*r->out.$e->{NAME}));";
1949                         }
1950                 } else {
1951                         pidl "NDR_ALLOC(ndr, r->out.$e->{NAME});";
1952                 
1953                         if (grep(/in/, @{$e->{DIRECTION}})) {
1954                                 pidl "*r->out.$e->{NAME} = *r->in.$e->{NAME};";
1955                         } else {
1956                                 pidl "ZERO_STRUCTP(r->out.$e->{NAME});";
1957                         }
1958                 }
1959         }
1960
1961         deindent;
1962         pidl "}";
1963         
1964         pidl "if (flags & NDR_OUT) {";
1965         indent;
1966
1967         $env = GenerateFunctionOutEnv($fn);
1968         foreach my $e (@{$fn->{ELEMENTS}}) {
1969                 next unless grep(/out/, @{$e->{DIRECTION}});
1970                 ParseElementPull($e, "ndr", "r->out.", $env, 1, 1);
1971         }
1972
1973         if ($fn->{RETURN_TYPE}) {
1974                 pidl "NDR_CHECK(ndr_pull_$fn->{RETURN_TYPE}(ndr, NDR_SCALARS, &r->out.result));";
1975         }
1976
1977         deindent;
1978         pidl "}";
1979         pidl "return NT_STATUS_OK;";
1980         deindent;
1981         pidl "}";
1982         pidl "";
1983 }
1984
1985 #####################################################################
1986 # produce a function call table
1987 sub FunctionTable($)
1988 {
1989         my($interface) = shift;
1990         my $count = 0;
1991         my $uname = uc $interface->{NAME};
1992
1993         $count = $#{$interface->{FUNCTIONS}}+1;
1994
1995         return if ($count == 0);
1996
1997         pidl "static const struct dcerpc_interface_call $interface->{NAME}\_calls[] = {";
1998         $count = 0;
1999         foreach my $d (@{$interface->{FUNCTIONS}}) {
2000                 next if not defined($d->{OPNUM});
2001                 pidl "\t{";
2002                 pidl "\t\t\"$d->{NAME}\",";
2003                 pidl "\t\tsizeof(struct $d->{NAME}),";
2004                 pidl "\t\t(ndr_push_flags_fn_t) ndr_push_$d->{NAME},";
2005                 pidl "\t\t(ndr_pull_flags_fn_t) ndr_pull_$d->{NAME},";
2006                 pidl "\t\t(ndr_print_function_t) ndr_print_$d->{NAME}";
2007                 pidl "\t},";
2008                 $count++;
2009         }
2010         pidl "\t{ NULL, 0, NULL, NULL, NULL }";
2011         pidl "};";
2012         pidl "";
2013
2014         pidl "static const char * const $interface->{NAME}\_endpoint_strings[] = {";
2015         foreach my $ep (@{$interface->{ENDPOINTS}}) {
2016                 pidl "\t$ep, ";
2017         }
2018         my $endpoint_count = $#{$interface->{ENDPOINTS}}+1;
2019         
2020         pidl "};";
2021         pidl "";
2022
2023         pidl "static const struct dcerpc_endpoint_list $interface->{NAME}\_endpoints = {";
2024         pidl "\t.count\t= $endpoint_count,";
2025         pidl "\t.names\t= $interface->{NAME}\_endpoint_strings";
2026         pidl "};";
2027         pidl "";
2028
2029         if (! defined $interface->{PROPERTIES}->{authservice}) {
2030                 $interface->{PROPERTIES}->{authservice} = "\"host\"";
2031         }
2032
2033         my @a = split / /, $interface->{PROPERTIES}->{authservice};
2034         my $authservice_count = $#a + 1;
2035
2036         pidl "static const char * const $interface->{NAME}\_authservice_strings[] = {";
2037         foreach my $ap (@a) {
2038                 pidl "\t$ap, ";
2039         }
2040         pidl "};";
2041         pidl "";
2042
2043         pidl "static const struct dcerpc_authservice_list $interface->{NAME}\_authservices = {";
2044         pidl "\t.count\t= $endpoint_count,";
2045         pidl "\t.names\t= $interface->{NAME}\_authservice_strings";
2046         pidl "};";
2047         pidl "";
2048
2049         pidl "\nconst struct dcerpc_interface_table dcerpc_table_$interface->{NAME} = {";
2050         pidl "\t.name\t\t= \"$interface->{NAME}\",";
2051         pidl "\t.uuid\t\t= DCERPC_$uname\_UUID,";
2052         pidl "\t.if_version\t= DCERPC_$uname\_VERSION,";
2053         pidl "\t.helpstring\t= DCERPC_$uname\_HELPSTRING,";
2054         pidl "\t.num_calls\t= $count,";
2055         pidl "\t.calls\t\t= $interface->{NAME}\_calls,";
2056         pidl "\t.endpoints\t= &$interface->{NAME}\_endpoints,";
2057         pidl "\t.authservices\t= &$interface->{NAME}\_authservices";
2058         pidl "};";
2059         pidl "";
2060
2061         pidl "static NTSTATUS dcerpc_ndr_$interface->{NAME}_init(void)";
2062         pidl "{";
2063         pidl "\treturn librpc_register_interface(&dcerpc_table_$interface->{NAME});";
2064         pidl "}";
2065         pidl "";
2066 }
2067
2068 #####################################################################
2069 # parse the interface definitions
2070 sub ParseInterface($$)
2071 {
2072         my($interface,$needed) = @_;
2073
2074         # Typedefs
2075         foreach my $d (@{$interface->{TYPEDEFS}}) {
2076                 ($needed->{"push_$d->{NAME}"}) && ParseTypedefPush($d);
2077                 ($needed->{"pull_$d->{NAME}"}) && ParseTypedefPull($d);
2078                 ($needed->{"print_$d->{NAME}"}) && ParseTypedefPrint($d);
2079
2080                 # Make sure we don't generate a function twice...
2081                 $needed->{"push_$d->{NAME}"} = $needed->{"pull_$d->{NAME}"} = 
2082                         $needed->{"print_$d->{NAME}"} = 0;
2083
2084                 ($needed->{"ndr_size_$d->{NAME}"}) && ParseTypedefNdrSize($d);
2085         }
2086
2087         # Functions
2088         foreach my $d (@{$interface->{FUNCTIONS}}) {
2089                 ($needed->{"push_$d->{NAME}"}) && ParseFunctionPush($d);
2090                 ($needed->{"pull_$d->{NAME}"}) && ParseFunctionPull($d);
2091                 ($needed->{"print_$d->{NAME}"}) && ParseFunctionPrint($d);
2092
2093                 # Make sure we don't generate a function twice...
2094                 $needed->{"push_$d->{NAME}"} = $needed->{"pull_$d->{NAME}"} = 
2095                         $needed->{"print_$d->{NAME}"} = 0;
2096         }
2097
2098         FunctionTable($interface);
2099 }
2100
2101 sub RegistrationFunction($$)
2102 {
2103         my ($idl,$filename) = @_;
2104
2105         $filename =~ /.*\/ndr_(.*).c/;
2106         my $basename = $1;
2107         pidl "NTSTATUS dcerpc_$basename\_init(void)";
2108         pidl "{";
2109         indent;
2110         pidl "NTSTATUS status = NT_STATUS_OK;";
2111         foreach my $interface (@{$idl}) {
2112                 next if $interface->{TYPE} ne "INTERFACE";
2113
2114                 my $count = ($#{$interface->{FUNCTIONS}}+1);
2115
2116                 next if ($count == 0);
2117
2118                 pidl "status = dcerpc_ndr_$interface->{NAME}_init();";
2119                 pidl "if (NT_STATUS_IS_ERR(status)) {";
2120                 pidl "\treturn status;";
2121                 pidl "}";
2122                 pidl "";
2123         }
2124         pidl "return status;";
2125         deindent;
2126         pidl "}";
2127         pidl "";
2128 }
2129
2130 #####################################################################
2131 # parse a parsed IDL structure back into an IDL file
2132 sub Parse($$)
2133 {
2134         my($ndr,$filename) = @_;
2135
2136         $tabs = "";
2137         my $h_filename = $filename;
2138         $res = "";
2139
2140         if ($h_filename =~ /(.*)\.c/) {
2141                 $h_filename = "$1.h";
2142         }
2143
2144         pidl "/* parser auto-generated by pidl */";
2145         pidl "";
2146         pidl "#include \"includes.h\"";
2147         pidl "#include \"$h_filename\"";
2148         pidl "";
2149
2150         my %needed = ();
2151
2152         foreach my $x (@{$ndr}) {
2153                 ($x->{TYPE} eq "INTERFACE") && NeededInterface($x, \%needed);
2154         }
2155
2156         foreach my $x (@{$ndr}) {
2157                 ($x->{TYPE} eq "INTERFACE") && ParseInterface($x, \%needed);
2158         }
2159
2160         RegistrationFunction($ndr, $filename);
2161
2162         return $res;
2163 }
2164
2165 sub NeededFunction($$)
2166 {
2167         my ($fn,$needed) = @_;
2168         $needed->{"pull_$fn->{NAME}"} = 1;
2169         $needed->{"push_$fn->{NAME}"} = 1;
2170         $needed->{"print_$fn->{NAME}"} = 1;
2171         foreach my $e (@{$fn->{ELEMENTS}}) {
2172                 $e->{PARENT} = $fn;
2173                 unless(defined($needed->{"pull_$e->{TYPE}"})) {
2174                         $needed->{"pull_$e->{TYPE}"} = 1;
2175                 }
2176                 unless(defined($needed->{"push_$e->{TYPE}"})) {
2177                         $needed->{"push_$e->{TYPE}"} = 1;
2178                 }
2179                 unless(defined($needed->{"print_$e->{TYPE}"})) {
2180                         $needed->{"print_$e->{TYPE}"} = 1;
2181                 }
2182         }
2183 }
2184
2185 sub NeededTypedef($$)
2186 {
2187         my ($t,$needed) = @_;
2188         if (Parse::Pidl::Util::has_property($t, "public")) {
2189                 $needed->{"pull_$t->{NAME}"} = not Parse::Pidl::Util::has_property($t, "nopull");
2190                 $needed->{"push_$t->{NAME}"} = not Parse::Pidl::Util::has_property($t, "nopush");
2191                 $needed->{"print_$t->{NAME}"} = not Parse::Pidl::Util::has_property($t, "noprint");
2192         }
2193
2194         if ($t->{DATA}->{TYPE} eq "STRUCT" or $t->{DATA}->{TYPE} eq "UNION") {
2195                 if (Parse::Pidl::Util::has_property($t, "gensize")) {
2196                         $needed->{"ndr_size_$t->{NAME}"} = 1;
2197                 }
2198
2199                 for my $e (@{$t->{DATA}->{ELEMENTS}}) {
2200                         $e->{PARENT} = $t->{DATA};
2201                         if ($needed->{"pull_$t->{NAME}"} and
2202                                 not defined($needed->{"pull_$e->{TYPE}"})) {
2203                                 $needed->{"pull_$e->{TYPE}"} = 1;
2204                         }
2205                         if ($needed->{"push_$t->{NAME}"} and
2206                                 not defined($needed->{"push_$e->{TYPE}"})) {
2207                                 $needed->{"push_$e->{TYPE}"} = 1;
2208                         }
2209                         if ($needed->{"print_$t->{NAME}"} and 
2210                                 not defined($needed->{"print_$e->{TYPE}"})) {
2211                                 $needed->{"print_$e->{TYPE}"} = 1;
2212                         }
2213                 }
2214         }
2215 }
2216
2217 #####################################################################
2218 # work out what parse functions are needed
2219 sub NeededInterface($$)
2220 {
2221         my ($interface,$needed) = @_;
2222         foreach my $d (@{$interface->{FUNCTIONS}}) {
2223             NeededFunction($d, $needed);
2224         }
2225         foreach my $d (reverse @{$interface->{TYPEDEFS}}) {
2226             NeededTypedef($d, $needed);
2227         }
2228 }
2229
2230 1;