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