r948: Tridge suggested that the best way to write the ethereal parser is to
[samba.git] / source4 / build / pidl / eparser.pm
1 ###################################################
2 # Samba4 parser generator for IDL structures
3 # Copyright tridge@samba.org 2000-2003
4 # Copyright tpot@samba.org 2001
5 # released under the GNU GPL
6
7 package IdlEParser;
8
9 use strict;
10 use client;
11 use Data::Dumper;
12
13 # the list of needed functions
14 my %needed;
15 my %structs;
16
17 my $module = "samr";
18 my $if_uuid;
19 my $if_version;
20 my $if_endpoints;
21
22 sub pidl($)
23 {
24         print OUT shift;
25 }
26
27 #####################################################################
28 # parse a properties list
29 sub ParseProperties($)
30 {
31     my($props) = shift;
32     foreach my $d (@{$props}) {
33         if (ref($d) ne "HASH") {
34             pidl "[$d] ";
35         } else {
36             foreach my $k (keys %{$d}) {
37                 pidl "[$k($d->{$k})] ";
38             }
39         }
40     }
41 }
42
43 ###################################
44 # find a sibling var in a structure
45 sub find_sibling($$)
46 {
47         my($e) = shift;
48         my($name) = shift;
49         my($fn) = $e->{PARENT};
50
51         if ($name =~ /\*(.*)/) {
52                 $name = $1;
53         }
54
55         if ($fn->{TYPE} eq "FUNCTION") {
56                 for my $e2 (@{$fn->{DATA}}) {
57                         if ($e2->{NAME} eq $name) {
58                                 return $e2;
59                         }
60                 }
61         }
62
63         for my $e2 (@{$fn->{ELEMENTS}}) {
64                 if ($e2->{NAME} eq $name) {
65                         return $e2;
66                 }
67         }
68         die "invalid sibling '$name'";
69 }
70
71 ####################################################################
72 # work out the name of a size_is() variable
73 sub find_size_var($$$)
74 {
75         my($e) = shift;
76         my($size) = shift;
77         my($var_prefix) = shift;
78
79         my($fn) = $e->{PARENT};
80
81         if (util::is_constant($size)) {
82                 return $size;
83         }
84
85         if ($size =~ /ndr->|\(/) {
86                 return $size;
87         }
88
89         my $prefix = "";
90
91         if ($size =~ /\*(.*)/) {
92                 $size = $1;
93                 $prefix = "*";
94         }
95
96         if ($fn->{TYPE} ne "FUNCTION") {
97                 return $prefix . "r->$size";
98         }
99
100         my $e2 = find_sibling($e, $size);
101
102         if (util::has_property($e2, "in") && util::has_property($e2, "out")) {
103                 return $prefix . "$var_prefix$size";
104         }
105         if (util::has_property($e2, "in")) {
106                 return $prefix . "r->in.$size";
107         }
108         if (util::has_property($e2, "out")) {
109                 return $prefix . "r->out.$size";
110         }
111
112         die "invalid variable in $size for element $e->{NAME} in $fn->{NAME}\n";
113 }
114
115
116 #####################################################################
117 # work out is a parse function should be declared static or not
118 sub fn_prefix($)
119 {
120         my $fn = shift;
121         if ($fn->{TYPE} eq "TYPEDEF") {
122                 if (util::has_property($fn->{DATA}, "public")) {
123                         return "";
124                 }
125         }
126
127         if ($fn->{TYPE} eq "FUNCTION") {
128                 if (util::has_property($fn, "public")) {
129                         return "";
130                 }
131         }
132         return "static ";
133 }
134
135
136 ###################################################################
137 # setup any special flags for an element or structure
138 sub start_flags($)
139 {
140         my $e = shift;
141         my $flags = util::has_property($e, "flag");
142         if (defined $flags) {
143                 pidl "\t{ guint32 _flags_save_$e->{TYPE} = flags;\n";
144                 pidl "\tflags |= $flags;\n";
145         }
146 }
147
148 ###################################################################
149 # end any special flags for an element or structure
150 sub end_flags($)
151 {
152         my $e = shift;
153         my $flags = util::has_property($e, "flag");
154         if (defined $flags) {
155                 pidl "\tflags = _flags_save_$e->{TYPE};\n\t}\n";
156         }
157 }
158
159
160 #####################################################################
161 # work out the correct alignment for a structure
162 sub struct_alignment
163 {
164         my $s = shift;
165
166         my $align = 1;
167         for my $e (@{$s->{ELEMENTS}}) {
168                 my $a = 1;
169
170                 if (!util::need_wire_pointer($e)
171                     && defined $structs{$e->{TYPE}}) {
172                         if ($structs{$e->{TYPE}}->{DATA}->{TYPE} eq "STRUCT") {
173                                 $a = struct_alignment($structs{$e->{TYPE}}->{DATA});
174                         } elsif ($structs{$e->{TYPE}}->{DATA}->{TYPE} eq "UNION") {
175                                 if (defined $structs{$e->{TYPE}}->{DATA}) {
176                                         $a = union_alignment($structs{$e->{TYPE}}->{DATA});
177                                 }
178                         }
179                 } else {
180                         $a = util::type_align($e);
181                 }
182
183                 if ($align < $a) {
184                         $align = $a;
185                 }
186         }
187
188         return $align;
189 }
190
191 #####################################################################
192 # work out the correct alignment for a union
193 sub union_alignment
194 {
195         my $u = shift;
196
197         my $align = 1;
198
199         foreach my $e (@{$u->{DATA}}) {
200                 my $a = 1;
201
202                 if ($e->{TYPE} eq "EMPTY") {
203                         next;
204                 }
205
206                 if (!util::need_wire_pointer($e)
207                     && defined $structs{$e->{DATA}->{TYPE}}) {
208                         my $s = $structs{$e->{DATA}->{TYPE}};
209                         if ($s->{DATA}->{TYPE} eq "STRUCT") {
210                                 $a = struct_alignment($s->{DATA});
211                         } elsif ($s->{DATA}->{TYPE} eq "UNION") {
212                                 $a = union_alignment($s->{DATA});
213                         }
214                 } else {
215                         $a = util::type_align($e->{DATA});
216                 }
217
218                 if ($align < $a) {
219                         $align = $a;
220                 }
221         }
222
223         return $align;
224 }
225
226 #####################################################################
227 # parse an array - push side
228 sub ParseArrayPush($$$)
229 {
230         my $e = shift;
231         my $var_prefix = shift;
232         my $ndr_flags = shift;
233
234         my $size = find_size_var($e, util::array_size($e), $var_prefix);
235
236         if (defined $e->{CONFORMANT_SIZE}) {
237                 # the conformant size has already been pushed
238         } elsif (!util::is_inline_array($e)) {
239                 # we need to emit the array size
240                 pidl "\t\toffset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_array_size, NULL);\n";
241         }
242
243         if (my $length = util::has_property($e, "length_is")) {
244                 $length = find_size_var($e, $length, $var_prefix);
245                 pidl "\t\toffset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_length_is, NULL);\n";
246                 pidl "\t\toffset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_length_is, NULL);\n";
247                 $size = $length;
248         }
249
250         if (util::is_scalar_type($e->{TYPE})) {
251                 pidl "\t\t// ndr_push_array_$e->{TYPE}(ndr, $ndr_flags, $var_prefix$e->{NAME}, $size);\n";
252         } else {
253                 pidl "\t\t// ndr_push_array(ndr, $ndr_flags, $var_prefix$e->{NAME}, sizeof($var_prefix$e->{NAME}\[0]), $size, (ndr_push_flags_fn_t)ndr_push_$e->{TYPE});\n";
254         }
255 }
256
257 #####################################################################
258 # parse an array - pull side
259 sub ParseArrayPull($$$)
260 {
261         my $e = shift;
262         my $var_prefix = shift;
263         my $ndr_flags = shift;
264
265         my $size = find_size_var($e, util::array_size($e), $var_prefix);
266         my $alloc_size = $size;
267
268         # if this is a conformant array then we use that size to allocate, and make sure
269         # we allocate enough to pull the elements
270         if (defined $e->{CONFORMANT_SIZE}) {
271                 $alloc_size = $e->{CONFORMANT_SIZE};
272
273                 pidl "\tif ($size > $alloc_size) {\n";
274                 pidl "\t\treturn ndr_pull_error(ndr, NDR_ERR_CONFORMANT_SIZE, \"Bad conformant size %u should be %u\", $alloc_size, $size);\n";
275                 pidl "\t}\n";
276         } elsif (!util::is_inline_array($e)) {
277                 if ($var_prefix =~ /^r->out/ && $size =~ /^\*r->in/) {
278                         my $size2 = substr($size, 1);
279                         pidl "if (flags & LIBNDR_FLAG_REF_ALLOC) {      NDR_ALLOC(ndr, $size2); }\n";
280                 }
281
282                 # non fixed arrays encode the size just before the array
283                 pidl "\t{\n";
284                 pidl "\t\tuint32_t _array_size;\n";
285                 pidl "\t\t(ndr_pull_uint32(ndr, &_array_size);\n";
286                 if ($size =~ /r->in/) {
287                         pidl "\t\tif (!(flags & LIBNDR_FLAG_REF_ALLOC) && _array_size != $size) {\n";
288                 } else {
289                         pidl "\t\tif ($size != _array_size) {\n";
290                 }
291                 pidl "\t\t\treturn ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, \"Bad array size %u should be %u\", _array_size, $size);\n";
292                 pidl "\t\t}\n";
293                 if ($size =~ /r->in/) {
294                         pidl "else { $size = _array_size; }\n";
295                 }
296                 pidl "\t}\n";
297         }
298
299         if ((util::need_alloc($e) && !util::is_fixed_array($e)) ||
300             ($var_prefix eq "r->in." && util::has_property($e, "ref"))) {
301                 if (!util::is_inline_array($e) || $ndr_flags eq "NDR_SCALARS") {
302                         pidl "\t\tNDR_ALLOC_N(ndr, $var_prefix$e->{NAME}, MAX(1, $alloc_size));\n";
303                 }
304         }
305
306         if (($var_prefix eq "r->out." && util::has_property($e, "ref"))) {
307                 if (!util::is_inline_array($e) || $ndr_flags eq "NDR_SCALARS") {
308                         pidl "\tif (flags & LIBNDR_FLAG_REF_ALLOC) {";
309                         pidl "\t\tNDR_ALLOC_N(ndr, $var_prefix$e->{NAME}, MAX(1, $alloc_size));\n";
310                         pidl "\t}\n";
311                 }
312         }
313
314         pidl "\t{\n";
315
316         if (my $length = util::has_property($e, "length_is")) {
317                 $length = find_size_var($e, $length, $var_prefix);
318                 pidl "\t\tuint32_t _offset, _length;\n";
319                 pidl "\t\tndr_pull_uint32(ndr, &_offset);\n";
320                 pidl "\t\tndr_pull_uint32(ndr, &_length);\n";
321                 pidl "\t\tif (_offset != 0) return ndr_pull_error(ndr, NDR_ERR_OFFSET, \"Bad array offset 0x%08x\", _offset);\n";
322                 pidl "\t\tif (_length > $size || _length != $length) return ndr_pull_error(ndr, NDR_ERR_LENGTH, \"Bad array length 0x%08x > size 0x%08x\", _offset, $size);\n\n";
323                 $size = "_length";
324         }
325
326         if (util::is_scalar_type($e->{TYPE})) {
327                 pidl "\t\tndr_pull_array_$e->{TYPE}(ndr, $ndr_flags, $var_prefix$e->{NAME}, $size);\n";
328         } else {
329                 pidl "\t\tndr_pull_array(ndr, $ndr_flags, (void **)$var_prefix$e->{NAME}, sizeof($var_prefix$e->{NAME}\[0]), $size, (ndr_pull_flags_fn_t)ndr_pull_$e->{TYPE});\n";
330         }
331
332         pidl "\t}\n";
333 }
334 sub ParamPolicyHandle($)
335 {
336     my($p) = shift;
337     my($res);
338
339     $res .= "\toffset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep, hf_policy_handle, NULL, NULL, FALSE, FALSE);\n";
340
341     return $res;
342 }
343
344
345 sub ParamString($)
346 {
347     my($p) = shift;
348     my($res);
349
350     $res .= "\toffset = dissect_ndr_pointer_cb(tvb, offset, pinfo, tree, drep, dissect_ndr_wchar_cvstring, NDR_POINTER_UNIQUE, \"$p->{NAME}\", hf_$p->{NAME}_string, cb_wstr_postprocess, GINT_TO_POINTER(1));\n";
351
352     return $res;
353 }
354
355 sub ParamDomSID($)
356 {
357     my($p) = shift;
358     my($res);
359
360     $res .= "\toffset = dissect_ndr_nt_SID(tvb, offset, pinfo, tree, drep);\n";
361
362     return $res;
363 }
364
365 my %param_handlers = (
366                       'policy_handle' => \&ParamPolicyHandle,
367                       'string' => \&ParamString,
368                       'dom_sid2'      => \&ParamDomSID,
369                       );
370
371 ####################################################################
372 # parse scalars in a structure element
373 sub ParseElementPushScalar($$$)
374 {
375         my($e) = shift;
376         my($var_prefix) = shift;
377         my($ndr_flags) = shift;
378         my $cprefix = util::c_push_prefix($e);
379         my $sub_size = util::has_property($e, "subcontext");
380
381         start_flags($e);
382
383         if (my $value = util::has_property($e, "value")) {
384                 pidl "\t$cprefix$var_prefix$e->{NAME} = $value;\n";
385         }
386
387         if (util::has_property($e, "relative")) {
388                 pidl "\tndr_push_relative(ndr, NDR_SCALARS, $var_prefix$e->{NAME}, (ndr_push_const_fn_t) ndr_push_$e->{TYPE});\n";
389         } elsif (util::is_inline_array($e)) {
390                 ParseArrayPush($e, "r->", "NDR_SCALARS");
391         } elsif (util::need_wire_pointer($e)) {
392             pidl "\toffset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_ptr, &ptr);\n";
393         } elsif (util::need_alloc($e)) {
394                 # no scalar component
395         } elsif (my $switch = util::has_property($e, "switch_is")) {
396                 ParseElementPushSwitch($e, $var_prefix, $ndr_flags, $switch);
397         } elsif (defined $sub_size) {
398                 if (util::is_builtin_type($e->{TYPE})) {
399                         pidl "\tndr_push_subcontext_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_push_fn_t) ndr_push_$e->{TYPE});\n";
400                 } else {
401                         pidl "\tndr_push_subcontext_flags_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_push_flags_fn_t) ndr_push_$e->{TYPE});\n";
402                 }
403         } elsif (util::is_builtin_type($e->{TYPE})) {
404                 pidl "\toffset = dissect_ndr_$e->{TYPE}(tvb, offset, pinfo, tree, drep, hf_$e->{NAME}_$e->{TYPE}, NULL);\n";
405         } else {
406             if (defined($param_handlers{$e->{TYPE}})) {
407                 pidl &{$param_handlers{$e->{TYPE}}}($e);
408             } else {
409                 pidl "\tproto_tree_add_text(tree, tvb, offset, -1, \"Unhandled IDL type '$e->{TYPE}'\");\n";
410             }
411         }
412
413         end_flags($e);
414 }
415
416 #####################################################################
417 # print scalars in a structure element
418 sub ParseElementPrintScalar($$)
419 {
420         my($e) = shift;
421         my($var_prefix) = shift;
422         my $cprefix = util::c_push_prefix($e);
423
424         if (util::has_property($e, "noprint")) {
425                 return;
426         }
427
428         if (my $value = util::has_property($e, "value")) {
429                 pidl "\tif (flags & LIBNDR_PRINT_SET_VALUES) {\n";
430                 pidl "\t\t$cprefix$var_prefix$e->{NAME} = $value;\n";
431                 pidl "\t}\n";
432         }
433
434         if (util::is_fixed_array($e)) {
435                 ParseElementPrintBuffer($e, $var_prefix);
436         } elsif (util::has_direct_buffers($e)) {
437                 pidl "\tndr_print_ptr(ndr, \"$e->{NAME}\", $var_prefix$e->{NAME});\n";
438                 pidl "\tndr->depth++;\n";
439                 ParseElementPrintBuffer($e, $var_prefix);
440                 pidl "\tndr->depth--;\n";
441         } elsif (my $switch = util::has_property($e, "switch_is")) {
442                 ParseElementPrintSwitch($e, $var_prefix, $switch);
443         } else {
444                 pidl "\tndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME});\n";
445         }
446 }
447
448 #####################################################################
449 # parse scalars in a structure element - pull size
450 sub ParseElementPullSwitch($$$$)
451 {
452         my($e) = shift;
453         my($var_prefix) = shift;
454         my($ndr_flags) = shift;
455         my $switch = shift;
456         my $switch_var = find_size_var($e, $switch, $var_prefix);
457
458         my $cprefix = util::c_pull_prefix($e);
459
460         my $utype = $structs{$e->{TYPE}};
461         if (!defined $utype ||
462             !util::has_property($utype->{DATA}, "nodiscriminant")) {
463                 my $e2 = find_sibling($e, $switch);
464                 pidl "\tif (($ndr_flags) & NDR_SCALARS) {\n";
465                 pidl "\t\t $e2->{TYPE} _level;\n";
466                 pidl "\t\tndr_pull_$e2->{TYPE}(ndr, &_level);\n";
467                 if ($switch_var =~ /r->in/) {
468                         pidl "\t\tif (!(flags & LIBNDR_FLAG_REF_ALLOC) && _level != $switch_var) {\n";
469                 } else {
470                         pidl "\t\tif (_level != $switch_var) {\n";
471                 }
472                 pidl "\t\t\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value %u in $e->{NAME}\");\t\t}\n";
473                 if ($switch_var =~ /r->/) {
474                         pidl "else { $switch_var = _level; }\n";
475                 }
476                 pidl "\t}\n";
477         }
478
479         my $sub_size = util::has_property($e, "subcontext");
480         if (defined $sub_size) {
481                 pidl "\tndr_pull_subcontext_union_fn(ndr, $sub_size, $switch_var, $cprefix$var_prefix$e->{NAME}, (ndr_pull_union_fn_t) ndr_pull_$e->{TYPE});\n";
482         } else {
483                 pidl "\tndr_pull_$e->{TYPE}(ndr, $ndr_flags, $switch_var, $cprefix$var_prefix$e->{NAME});\n";
484         }
485
486
487 }
488
489 #####################################################################
490 # push switch element
491 sub ParseElementPushSwitch($$$$)
492 {
493         my($e) = shift;
494         my($var_prefix) = shift;
495         my($ndr_flags) = shift;
496         my $switch = shift;
497         my $switch_var = find_size_var($e, $switch, $var_prefix);
498         my $cprefix = util::c_push_prefix($e);
499
500         my $utype = $structs{$e->{TYPE}};
501         if (!defined $utype ||
502             !util::has_property($utype->{DATA}, "nodiscriminant")) {
503                 my $e2 = find_sibling($e, $switch);
504                 pidl "\tif (($ndr_flags) & NDR_SCALARS) {\n";
505                 pidl "\t\toffset = dissect_ndr_$e2->{TYPE}(tvb, offset, pinfo, tree, drep, hf_switch, NULL);\n";
506                 pidl "\t}\n";
507         }
508
509         my $sub_size = util::has_property($e, "subcontext");
510         if (defined $sub_size) {
511                 pidl "\tndr_push_subcontext_union_fn(ndr, $sub_size, $switch_var, $cprefix$var_prefix$e->{NAME}, (ndr_push_union_fn_t) ndr_push_$e->{TYPE});\n";
512         } else {
513             if (defined($param_handlers{$e->{TYPE}})) {
514                 pidl &{$param_handlers{$e->{TYPE}}}($e);
515             } else {
516                 pidl "\tproto_tree_add_text(tree, tvb, offset, -1, \"Unhandled IDL type '$e->{TYPE}'\");\n";
517             }
518 #               pidl "\tndr_push_$e->{TYPE}(ndr, $ndr_flags, $switch_var, $cprefix$var_prefix$e->{NAME});\n";
519         }
520 }
521
522 #####################################################################
523 # print scalars in a structure element 
524 sub ParseElementPrintSwitch($$$)
525 {
526         my($e) = shift;
527         my($var_prefix) = shift;
528         my $switch = shift;
529         my $switch_var = find_size_var($e, $switch, $var_prefix);
530         my $cprefix = util::c_push_prefix($e);
531
532         pidl "\tndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $switch_var, $cprefix$var_prefix$e->{NAME});\n";
533 }
534
535
536 #####################################################################
537 # parse scalars in a structure element - pull size
538 sub ParseElementPullScalar($$$)
539 {
540         my($e) = shift;
541         my($var_prefix) = shift;
542         my($ndr_flags) = shift;
543         my $cprefix = util::c_pull_prefix($e);
544         my $sub_size = util::has_property($e, "subcontext");
545
546         start_flags($e);
547
548         if (util::has_property($e, "relative")) {
549                 pidl "\tndr_pull_relative(ndr, (const void **)&$var_prefix$e->{NAME}, sizeof(*$var_prefix$e->{NAME}), (ndr_pull_flags_fn_t)ndr_pull_$e->{TYPE});\n";
550         } elsif (util::is_inline_array($e)) {
551                 ParseArrayPull($e, "r->", "NDR_SCALARS");
552         } elsif (util::need_wire_pointer($e)) {
553                 pidl "\tndr_pull_uint32(ndr, &_ptr_$e->{NAME});\n";
554                 pidl "\tif (_ptr_$e->{NAME}) {\n";
555                 pidl "\t\tNDR_ALLOC(ndr, $var_prefix$e->{NAME});\n";
556                 pidl "\t} else {\n";
557                 pidl "\t\t$var_prefix$e->{NAME} = NULL;\n";
558                 pidl "\t}\n";
559         } elsif (util::need_alloc($e)) {
560                 # no scalar component
561         } elsif (my $switch = util::has_property($e, "switch_is")) {
562                 ParseElementPullSwitch($e, $var_prefix, $ndr_flags, $switch);
563         } elsif (defined $sub_size) {
564                 if (util::is_builtin_type($e->{TYPE})) {
565                         pidl "\tndr_pull_subcontext_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_pull_fn_t) ndr_pull_$e->{TYPE});\n";
566                 } else {
567                         pidl "\tndr_pull_subcontext_flags_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_pull_flags_fn_t) ndr_pull_$e->{TYPE});\n";
568                 }
569         } elsif (util::is_builtin_type($e->{TYPE})) {
570                 pidl "\tndr_pull_$e->{TYPE}(ndr, $cprefix$var_prefix$e->{NAME});\n";
571         } else {
572                 pidl "\tndr_pull_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME});\n";
573         }
574
575         end_flags($e);
576 }
577
578 #####################################################################
579 # parse buffers in a structure element
580 sub ParseElementPushBuffer($$$)
581 {
582         my($e) = shift;
583         my($var_prefix) = shift;
584         my($ndr_flags) = shift;
585         my $cprefix = util::c_push_prefix($e);
586         my $sub_size = util::has_property($e, "subcontext");
587
588         if (util::is_pure_scalar($e)) {
589                 return;
590         }
591
592         start_flags($e);
593
594         if (util::need_wire_pointer($e)) {
595                 pidl "\tif (ptr) {\n";
596         }
597             
598         if (util::has_property($e, "relative")) {
599                 pidl "\tndr_push_relative(ndr, NDR_BUFFERS, $cprefix$var_prefix$e->{NAME}, (ndr_push_const_fn_t) ndr_push_$e->{TYPE});\n";
600         } elsif (util::is_inline_array($e)) {
601                 ParseArrayPush($e, "r->", "NDR_BUFFERS");
602         } elsif (util::array_size($e)) {
603                 ParseArrayPush($e, "r->", "NDR_SCALARS|NDR_BUFFERS");
604         } elsif (my $switch = util::has_property($e, "switch_is")) {
605                 if ($e->{POINTERS}) {
606                         ParseElementPushSwitch($e, $var_prefix, "NDR_BUFFERS|NDR_SCALARS", $switch);
607                 } else {
608                         ParseElementPushSwitch($e, $var_prefix, "NDR_BUFFERS", $switch);
609                 }
610         } elsif (defined $sub_size) {
611                 if ($e->{POINTERS}) {
612                         if (util::is_builtin_type($e->{TYPE})) {
613                                 pidl "\tndr_push_subcontext_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_push_fn_t) ndr_push_$e->{TYPE});\n";
614                         } else {
615                                 pidl "\tndr_push_subcontext_flags_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_push_flags_fn_t) ndr_push_$e->{TYPE});\n";
616                         }
617                 }
618         } elsif (util::is_builtin_type($e->{TYPE})) {
619                 pidl "\toffset = dissect_ndr_$e->{TYPE}(tvb, offset, pinfo, tree, drep, hf_$e->{NAME}_$e->{TYPE}, NULL);\n";
620         } elsif ($e->{POINTERS}) {
621             if (defined($param_handlers{$e->{TYPE}})) {
622                 pidl &{$param_handlers{$e->{TYPE}}}($e);
623             } else {
624                 pidl "\t\toffset = dissect_$e->{TYPE}(tvb, offset, pinfo, tree, drep, NDR_SCALARS|NDR_BUFFERS);\n";
625             }
626         } else {
627             if (defined($param_handlers{$e->{TYPE}})) {
628                 pidl &{$param_handlers{$e->{TYPE}}}($e);
629             } else {
630                 pidl "\t\toffset = dissect__$e->{TYPE}(tvb, offset, pinfo, tree, drep, $ndr_flags);\n";
631             }
632         }
633
634         if (util::need_wire_pointer($e)) {
635                 pidl "\t}\n";
636         }       
637
638         end_flags($e);
639 }
640
641 #####################################################################
642 # print buffers in a structure element
643 sub ParseElementPrintBuffer($$)
644 {
645         my($e) = shift;
646         my($var_prefix) = shift;
647         my $cprefix = util::c_push_prefix($e);
648
649         if (util::need_wire_pointer($e)) {
650                 pidl "\tif ($var_prefix$e->{NAME}) {\n";
651         }
652             
653         if (util::array_size($e)) {
654                 ParseArrayPrint($e, $var_prefix);
655         } elsif (my $switch = util::has_property($e, "switch_is")) {
656                 ParseElementPrintSwitch($e, $var_prefix, $switch);
657         } else {
658                 pidl "\t\tndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME});\n";
659         }
660
661         if (util::need_wire_pointer($e)) {
662                 pidl "\t}\n";
663         }       
664 }
665
666
667 #####################################################################
668 # parse buffers in a structure element - pull side
669 sub ParseElementPullBuffer($$$)
670 {
671         my($e) = shift;
672         my($var_prefix) = shift;
673         my($ndr_flags) = shift;
674         my $cprefix = util::c_pull_prefix($e);
675         my $sub_size = util::has_property($e, "subcontext");
676
677         if (util::is_pure_scalar($e)) {
678                 return;
679         }
680
681         if (util::has_property($e, "relative")) {
682                 return;
683         }
684
685         start_flags($e);
686
687         if (util::need_wire_pointer($e)) {
688                 pidl "\tif ($var_prefix$e->{NAME}) {\n";
689         }
690             
691         if (util::is_inline_array($e)) {
692                 ParseArrayPull($e, "r->", "NDR_BUFFERS");
693         } elsif (util::array_size($e)) {
694                 ParseArrayPull($e, "r->", "NDR_SCALARS|NDR_BUFFERS");
695         } elsif (my $switch = util::has_property($e, "switch_is")) {
696                 if ($e->{POINTERS}) {
697                         ParseElementPullSwitch($e, $var_prefix, "NDR_SCALARS|NDR_BUFFERS", $switch);
698                 } else {
699                         ParseElementPullSwitch($e, $var_prefix, "NDR_BUFFERS", $switch);
700                 }
701         } elsif (defined $sub_size) {
702                 if ($e->{POINTERS}) {
703                         if (util::is_builtin_type($e->{TYPE})) {
704                                 pidl "\tndr_pull_subcontext_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_pull_fn_t) ndr_pull_$e->{TYPE});\n";
705                         } else {
706                                 pidl "\tndr_pull_subcontext_flags_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_pull_flags_fn_t) ndr_pull_$e->{TYPE});\n";
707                         }
708                 }
709         } elsif (util::is_builtin_type($e->{TYPE})) {
710                 pidl "\t\tndr_pull_$e->{TYPE}(ndr, $cprefix$var_prefix$e->{NAME});\n";
711         } elsif ($e->{POINTERS}) {
712                 pidl "\t\tndr_pull_$e->{TYPE}(ndr, NDR_SCALARS|NDR_BUFFERS, $cprefix$var_prefix$e->{NAME});\n";
713         } else {
714                 pidl "\t\tndr_pull_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME});\n";
715         }
716
717         if (util::need_wire_pointer($e)) {
718                 pidl "\t}\n";
719         }       
720
721         end_flags($e);
722 }
723
724 #####################################################################
725 # parse a struct
726 sub ParseStructPush($)
727 {
728         my($struct) = shift;
729         my $conform_e;
730         
731         if (! defined $struct->{ELEMENTS}) {
732                 return;
733         }
734
735         start_flags($struct);
736
737         # see if the structure contains a conformant array. If it
738         # does, then it must be the last element of the structure, and
739         # we need to push the conformant length early, as it fits on
740         # the wire before the structure (and even before the structure
741         # alignment)
742         my $e = $struct->{ELEMENTS}[-1];
743         if (defined $e->{ARRAY_LEN} && $e->{ARRAY_LEN} eq "*") {
744                 my $size = find_size_var($e, util::array_size($e), "r->");
745                 $e->{CONFORMANT_SIZE} = $size;
746                 $conform_e = $e;
747                 pidl "\tndr_push_uint32(ndr, $size);\n";
748         }
749
750         pidl "\tif (!(ndr_flags & NDR_SCALARS)) goto buffers;\n";
751
752         pidl "\tndr_push_struct_start(ndr);\n";
753
754         my $align = struct_alignment($struct);
755         pidl "\tndr_push_align(ndr, $align);\n";
756
757         foreach my $e (@{$struct->{ELEMENTS}}) {
758                 ParseElementPushScalar($e, "r->", "NDR_SCALARS");
759         }       
760
761         pidl "buffers:\n";
762         pidl "\tif (!(ndr_flags & NDR_BUFFERS)) goto done;\n";
763         foreach my $e (@{$struct->{ELEMENTS}}) {
764                 ParseElementPushBuffer($e, "r->", "NDR_BUFFERS");
765         }
766
767         pidl "\tndr_push_struct_end(ndr);\n";
768
769         pidl "done:\n";
770
771         end_flags($struct);
772 }
773
774 #####################################################################
775 # parse a struct - pull side
776 sub ParseStructPull($)
777 {
778         my($struct) = shift;
779         my $conform_e;
780
781         if (! defined $struct->{ELEMENTS}) {
782                 return;
783         }
784
785         # see if the structure contains a conformant array. If it
786         # does, then it must be the last element of the structure, and
787         # we need to pull the conformant length early, as it fits on
788         # the wire before the structure (and even before the structure
789         # alignment)
790         my $e = $struct->{ELEMENTS}[-1];
791         if (defined $e->{ARRAY_LEN} && $e->{ARRAY_LEN} eq "*") {
792                 $conform_e = $e;
793                 pidl "\tuint32_t _conformant_size;\n";
794                 $conform_e->{CONFORMANT_SIZE} = "_conformant_size";
795         }
796
797         # declare any internal pointers we need
798         foreach my $e (@{$struct->{ELEMENTS}}) {
799                 if (util::need_wire_pointer($e) &&
800                     !util::has_property($e, "relative")) {
801                         pidl "\tuint32_t _ptr_$e->{NAME};\n";
802                 }
803         }
804
805         start_flags($struct);
806
807         pidl "\tif (!(ndr_flags & NDR_SCALARS)) goto buffers;\n";
808
809         pidl "\tndr_pull_struct_start(ndr);\n";
810
811         if (defined $conform_e) {
812                 pidl "\tndr_pull_uint32(ndr, &$conform_e->{CONFORMANT_SIZE});\n";
813         }
814
815         my $align = struct_alignment($struct);
816         pidl "\tndr_pull_align(ndr, $align);\n";
817
818         foreach my $e (@{$struct->{ELEMENTS}}) {
819                 ParseElementPullScalar($e, "r->", "NDR_SCALARS");
820         }       
821
822         pidl "buffers:\n";
823         pidl "\tif (!(ndr_flags & NDR_BUFFERS)) goto done;\n";
824         foreach my $e (@{$struct->{ELEMENTS}}) {
825                 ParseElementPullBuffer($e, "r->", "NDR_BUFFERS");
826         }
827
828         pidl "\tndr_pull_struct_end(ndr);\n";
829
830         pidl "done:\n";
831
832         end_flags($struct);
833 }
834
835
836 #####################################################################
837 # parse a union - push side
838 sub ParseUnionPush($)
839 {
840         my $e = shift;
841         my $have_default = 0;
842
843         start_flags($e);
844
845         pidl "\tif (!(ndr_flags & NDR_SCALARS)) goto buffers;\n";
846
847         pidl "\tndr_push_struct_start(ndr);\n";
848
849 #       my $align = union_alignment($e);
850 #       pidl "\tndr_push_align(ndr, $align);\n";
851
852         pidl "\tswitch (level) {\n";
853         foreach my $el (@{$e->{DATA}}) {
854                 if ($el->{CASE} eq "default") {
855                         pidl "\tdefault:\n";
856                         $have_default = 1;
857                 } else {
858                         pidl "\tcase $el->{CASE}:\n";
859                 }
860                 if ($el->{TYPE} eq "UNION_ELEMENT") {
861                         ParseElementPushScalar($el->{DATA}, "r->", "NDR_SCALARS");
862                 }
863                 pidl "\tbreak;\n\n";
864         }
865         if (! $have_default) {
866                 pidl "\tdefault:\n";
867                 pidl "\t\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);\n";
868         }
869         pidl "\t}\n";
870         pidl "buffers:\n";
871         pidl "\tif (!(ndr_flags & NDR_BUFFERS)) goto done;\n";
872         pidl "\tswitch (level) {\n";
873         foreach my $el (@{$e->{DATA}}) {
874                 if ($el->{CASE} eq "default") {
875                         pidl "\tdefault:\n";
876                 } else {
877                         pidl "\tcase $el->{CASE}:\n";
878                 }
879                 if ($el->{TYPE} eq "UNION_ELEMENT") {
880                         ParseElementPushBuffer($el->{DATA}, "r->", "NDR_BUFFERS");
881                 }
882                 pidl "\tbreak;\n\n";
883         }
884         if (! $have_default) {
885                 pidl "\tdefault:\n";
886                 pidl "\t\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);\n";
887         }
888         pidl "\t}\n";
889         pidl "\tndr_push_struct_end(ndr);\n";
890         pidl "done:\n";
891         end_flags($e);
892 }
893
894 #####################################################################
895 # parse a union - pull side
896 sub ParseUnionPull($)
897 {
898         my $e = shift;
899         my $have_default = 0;
900
901         start_flags($e);
902
903         pidl "\tif (!(ndr_flags & NDR_SCALARS)) goto buffers;\n";
904
905         pidl "\tndr_pull_struct_start(ndr);\n";
906
907 #       my $align = union_alignment($e);
908 #       pidl "\tndr_pull_align(ndr, $align);\n";
909
910         pidl "\tswitch (level) {\n";
911         foreach my $el (@{$e->{DATA}}) {
912                 if ($el->{CASE} eq "default") {
913                         pidl "\tdefault: {\n";
914                         $have_default = 1;
915                 } else {
916                         pidl "\tcase $el->{CASE}: {\n";
917                 }
918                 if ($el->{TYPE} eq "UNION_ELEMENT") {
919                         my $e2 = $el->{DATA};
920                         if ($e2->{POINTERS}) {
921                                 pidl "\t\tuint32_t _ptr_$e2->{NAME};\n";
922                         }
923                         ParseElementPullScalar($el->{DATA}, "r->", "NDR_SCALARS");
924                 }
925                 pidl "\tbreak; }\n\n";
926         }
927         if (! $have_default) {
928                 pidl "\tdefault:\n";
929                 pidl "\t\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);\n";
930         }
931         pidl "\t}\n";
932         pidl "buffers:\n";
933         pidl "\tif (!(ndr_flags & NDR_BUFFERS)) goto done;\n";
934         pidl "\tswitch (level) {\n";
935         foreach my $el (@{$e->{DATA}}) {
936                 if ($el->{CASE} eq "default") {
937                         pidl "\tdefault:\n";
938                 } else {
939                         pidl "\tcase $el->{CASE}:\n";
940                 }
941                 if ($el->{TYPE} eq "UNION_ELEMENT") {
942                         ParseElementPullBuffer($el->{DATA}, "r->", "NDR_BUFFERS");
943                 }
944                 pidl "\tbreak;\n\n";
945         }
946         if (! $have_default) {
947                 pidl "\tdefault:\n";
948                 pidl "\t\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);\n";
949         }
950         pidl "\t}\n";
951         pidl "\tndr_pull_struct_end(ndr);\n";
952         pidl "done:\n";
953         end_flags($e);
954 }
955
956 #####################################################################
957 # parse a type
958 sub ParseTypePush($)
959 {
960         my($data) = shift;
961
962         if (ref($data) eq "HASH") {
963                 ($data->{TYPE} eq "STRUCT") &&
964                     ParseStructPush($data);
965                 ($data->{TYPE} eq "UNION") &&
966                     ParseUnionPush($data);
967         }
968 }
969
970 #####################################################################
971 # parse a type
972 sub ParseTypePull($)
973 {
974         my($data) = shift;
975
976         if (ref($data) eq "HASH") {
977                 ($data->{TYPE} eq "STRUCT") &&
978                     ParseStructPull($data);
979                 ($data->{TYPE} eq "UNION") &&
980                     ParseUnionPull($data);
981         }
982 }
983
984 #####################################################################
985 # parse a typedef
986 sub ParseTypedefEthereal($)
987 {
988         my($e) = shift;
989         my $static = fn_prefix($e);
990
991         if ($e->{DATA}->{TYPE} eq "STRUCT") {
992             pidl $static . "int dissect_$e->{NAME}(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int flags)\n";
993             pidl "\n{\n";
994 #               ParseTypePush($e->{DATA});
995             pidl "\treturn offset;\n";
996             pidl "}\n\n";
997         }
998
999         if ($e->{DATA}->{TYPE} eq "UNION") {
1000             pidl $static . "int dissect_$e->{NAME}(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int flags)\n";
1001                 pidl "\n{\n";
1002 #               ParseTypePush($e->{DATA});
1003             pidl "\treturn offset;\n";
1004                 pidl "}\n\n";
1005         }
1006 }
1007
1008
1009 #####################################################################
1010 # parse a function element
1011 sub ParseFunctionElementPush($$)
1012
1013         my $e = shift;
1014         my $inout = shift;
1015
1016         if (util::array_size($e)) {
1017                 if (util::need_wire_pointer($e)) {
1018                     pidl "\toffset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_ptr, &ptr);\n";
1019                     pidl "\tif (ptr) {\n";
1020                         ParseArrayPush($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1021                         pidl "\t}\n";
1022                 } else {
1023                         ParseArrayPush($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1024                 }
1025         } else {
1026                 ParseElementPushScalar($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1027                 if ($e->{POINTERS}) {
1028                         ParseElementPushBuffer($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1029                 }
1030         }
1031 }       
1032
1033 #####################################################################
1034 # parse a function
1035 sub ParseFunctionEthereal($)
1036
1037         my($fn) = shift;
1038         my $static = fn_prefix($fn);
1039
1040         # Comment displaying IDL for this function
1041         
1042         pidl "/*\n\n";
1043         pidl IdlDump::DumpFunction($fn);
1044         pidl "*/\n\n";
1045
1046         # Request
1047
1048         pidl $static . "int $fn->{NAME}_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)\n";
1049         pidl "{\n";
1050         pidl "\tint flags = NDR_SCALARS|NDR_BUFFERS;\n\n";
1051         pidl "\tguint32 ptr;\n\n";
1052
1053         foreach my $e (@{$fn->{DATA}}) {
1054                 if (util::has_property($e, "in")) {
1055                         ParseFunctionElementPush($e, "in");
1056                 }               
1057         }
1058
1059         pidl "\n\treturn offset;\n";
1060         pidl "}\n\n";
1061
1062         # Response
1063
1064         pidl $static . "int $fn->{NAME}_resp(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)\n";
1065         pidl "{\n";
1066         pidl "\tint flags = NDR_SCALARS|NDR_BUFFERS;\n\n";
1067         pidl "\tguint32 ptr;\n\n";
1068
1069         foreach my $e (@{$fn->{DATA}}) {
1070                 if (util::has_property($e, "out")) {
1071                         ParseFunctionElementPush($e, "out");
1072                 }               
1073         }
1074
1075         if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
1076             if ($fn->{RETURN_TYPE} eq "NTSTATUS") {
1077                 pidl "\n\toffset = dissect_ntstatus(tvb, offset, pinfo, tree, drep, hf_rc, NULL);\n";
1078             } else {
1079                 pidl "\tproto_tree_add_text(tree, tvb, offset, -1, \"Unhandled return type '$fn->{RETURN_TYPE}'\");\n";
1080             }
1081         }
1082
1083         pidl "\n\treturn offset;\n";
1084         pidl "}\n\n";
1085 }
1086
1087 #####################################################################
1088 # produce a function call table
1089 sub FunctionTable($)
1090 {
1091         my($interface) = shift;
1092         my($data) = $interface->{DATA};
1093         my $count = 0;
1094         my $uname = uc $interface->{NAME};
1095
1096         foreach my $d (@{$data}) {
1097                 if ($d->{TYPE} eq "FUNCTION") { $count++; }
1098         }
1099
1100         if ($count == 0) {
1101                 return;
1102         }
1103
1104         pidl "static dcerpc_sub_dissector dcerpc_dissectors[] = {\n";
1105         my $num = 0;
1106         foreach my $d (@{$data}) {
1107                 if ($d->{TYPE} eq "FUNCTION") {
1108                     # Strip module name from function name, if present
1109                     my($n) = $d->{NAME};
1110                     $n = substr($d->{NAME}, length($module) + 1),
1111                         if $module eq substr($d->{NAME}, 0, length($module));
1112                     pidl "\t{ $num, \"$n\",\n";
1113                     pidl "\t\t$d->{NAME}_rqst,\n";
1114                     pidl "\t\t$d->{NAME}_resp },\n";
1115                     $num++;
1116                 }
1117         }
1118         pidl "};\n\n";
1119 }
1120
1121
1122 #####################################################################
1123 # parse the interface definitions
1124 sub ParseInterface($)
1125 {
1126         my($interface) = shift;
1127         my($data) = $interface->{DATA};
1128
1129         foreach my $d (@{$data}) {
1130                 if ($d->{TYPE} eq "TYPEDEF") {
1131                     $structs{$d->{NAME}} = $d;
1132             }
1133         }
1134
1135         foreach my $d (@{$data}) {
1136                 ($d->{TYPE} eq "TYPEDEF") &&
1137                     ParseTypedefEthereal($d);
1138                 ($d->{TYPE} eq "FUNCTION") && 
1139                     ParseFunctionEthereal($d);
1140         }
1141
1142         FunctionTable($interface);
1143 }
1144
1145 # Convert an idl type to an ethereal FT_* type
1146
1147 sub type2ft($)
1148 {
1149     my($t) = shift;
1150
1151     return "FT_UINT32", if ($t eq "uint32");
1152     return "FT_UINT16", if ($t eq "uint16");
1153     return "FT_BYTES";
1154 }
1155
1156 # Select an ethereal BASE_* type for an idl type
1157
1158 sub type2base($)
1159 {
1160     my($t) = shift;
1161
1162     return "BASE_DEC", if ($t eq "uint32") or ($t eq "uint16");
1163     return "BASE_NONE";
1164 }
1165
1166 sub NeededFunction($)
1167 {
1168         my $fn = shift;
1169         $needed{"pull_$fn->{NAME}"} = 1;
1170         $needed{"push_$fn->{NAME}"} = 1;
1171         foreach my $e (@{$fn->{DATA}}) {
1172             $needed{"hf_$e->{NAME}_$e->{TYPE}"} = {
1173                 'name' => $e->{NAME},
1174                 'type' => $e->{TYPE},
1175                 'ft'   => type2ft($e->{TYPE}),
1176                 'base' => type2base($e->{TYPE})
1177                 };
1178             $e->{PARENT} = $fn;
1179             $needed{"pull_$e->{TYPE}"} = 1;
1180             $needed{"push_$e->{TYPE}"} = 1;
1181         }
1182 }
1183
1184 sub NeededTypedef($)
1185 {
1186         my $t = shift;
1187         if (util::has_property($t->{DATA}, "public")) {
1188                 $needed{"pull_$t->{NAME}"} = 1;
1189                 $needed{"push_$t->{NAME}"} = 1;         
1190         }
1191         if ($t->{DATA}->{TYPE} eq "STRUCT") {
1192                 for my $e (@{$t->{DATA}->{ELEMENTS}}) {
1193                         $e->{PARENT} = $t->{DATA};
1194                         if ($needed{"pull_$t->{NAME}"}) {
1195                                 $needed{"pull_$e->{TYPE}"} = 1;
1196                         }
1197                         if ($needed{"push_$t->{NAME}"}) {
1198                                 $needed{"push_$e->{TYPE}"} = 1;
1199                         }
1200                 }
1201         }
1202         if ($t->{DATA}->{TYPE} eq "UNION") {
1203                 for my $e (@{$t->{DATA}->{DATA}}) {
1204                         $e->{PARENT} = $t->{DATA};
1205                         if ($e->{TYPE} eq "UNION_ELEMENT") {
1206                                 if ($needed{"pull_$t->{NAME}"}) {
1207                                         $needed{"pull_$e->{DATA}->{TYPE}"} = 1;
1208                                 }
1209                                 if ($needed{"push_$t->{NAME}"}) {
1210                                         $needed{"push_$e->{DATA}->{TYPE}"} = 1;
1211                                 }
1212                         }
1213                 }
1214         }
1215 }
1216
1217 #####################################################################
1218 # work out what parse functions are needed
1219 sub BuildNeeded($)
1220 {
1221         my($interface) = shift;
1222         my($data) = $interface->{DATA};
1223         foreach my $d (@{$data}) {
1224                 ($d->{TYPE} eq "FUNCTION") && 
1225                     NeededFunction($d);
1226         }
1227         foreach my $d (reverse @{$data}) {
1228                 ($d->{TYPE} eq "TYPEDEF") &&
1229                     NeededTypedef($d);
1230         }
1231 }
1232
1233 #####################################################################
1234 # parse the interface definitions
1235 sub ModuleHeader($)
1236 {
1237     my($h) = shift;
1238
1239     $if_uuid = $h->{PROPERTIES}->{uuid};
1240     $if_version = $h->{PROPERTIES}->{version};
1241     $if_endpoints = $h->{PROPERTIES}->{endpoints};
1242 }
1243
1244 #####################################################################
1245 # parse a parsed IDL structure back into an IDL file
1246 sub Parse($$)
1247 {
1248         my($idl) = shift;
1249         my($filename) = shift;
1250
1251         open(OUT, ">$filename") || die "can't open $filename";    
1252
1253         pidl "/* parser auto-generated by pidl */\n\n";
1254         pidl "#ifdef HAVE_CONFIG_H\n";
1255         pidl "#include \"config.h\"\n";
1256         pidl "#endif\n\n";
1257
1258         pidl "#include \"packet-dcerpc.h\"\n";
1259         pidl "#include \"packet-dcerpc-nt.h\"\n\n";
1260         pidl "#include \"packet-dcerpc-common.h\"\n\n";
1261
1262         pidl "#define NDR_SCALARS 1\n";
1263         pidl "#define NDR_BUFFERS 2\n\n";
1264
1265         pidl "extern const value_string NT_errors[];\n\n";
1266
1267         foreach my $x (@{$idl}) {
1268             $module = $x->{NAME}, if $x->{TYPE} eq "INTERFACE";
1269         }
1270
1271         pidl "static int proto_dcerpc_$module = -1;\n\n";
1272
1273         pidl "static gint ett_dcerpc_$module = -1;\n\n";
1274
1275         pidl "static int hf_opnum = -1;\n";
1276         pidl "static int hf_rc = -1;\n";
1277         pidl "static int hf_ptr = -1;\n";
1278         pidl "static int hf_switch = -1;\n";
1279         pidl "static int hf_policy_handle = -1;\n";
1280         pidl "static int hf_array_size = -1;\n";
1281         pidl "static int hf_length_is = -1;\n";
1282
1283         foreach my $x (@{$idl}) {
1284             ($x->{TYPE} eq "MODULEHEADER") && 
1285                 ModuleHeader($x);
1286
1287             if ($x->{TYPE} eq "INTERFACE") { 
1288                 BuildNeeded($x);
1289
1290                 foreach my $y (keys(%needed)) {
1291                     pidl "static int $y = -1;\n", if $y =~ /^hf_/;
1292                 }
1293
1294                 ParseInterface($x);
1295             }
1296         }
1297
1298         pidl "static e_uuid_t uuid_dcerpc_$module = {\n";
1299         pidl "\t0x" . substr($if_uuid, 0, 8);
1300         pidl ", 0x" . substr($if_uuid, 9, 4);
1301         pidl ", 0x" . substr($if_uuid, 14, 4) . ",\n";
1302         pidl "\t{ 0x" . substr($if_uuid, 19, 2);
1303         pidl ", 0x" . substr($if_uuid, 21, 2);
1304         pidl ", 0x" . substr($if_uuid, 24, 2);
1305         pidl ", 0x" . substr($if_uuid, 26, 2);
1306         pidl ", 0x" . substr($if_uuid, 28, 2);
1307         pidl ", 0x" . substr($if_uuid, 30, 2);
1308         pidl ", 0x" . substr($if_uuid, 32, 2);
1309         pidl ", 0x" . substr($if_uuid, 34, 2) . " }\n";
1310         pidl "};\n\n";
1311
1312         pidl "static guint16 ver_dcerpc_$module = " . $if_version . ";\n\n";
1313
1314
1315         pidl "void proto_register_dcerpc_samr(void)\n";
1316         pidl "{\n";
1317         pidl "\tstatic hf_register_info hf[] = {\n";
1318
1319         pidl "\t{ &hf_opnum, { \"Operation\", \"$module.opnum\", FT_UINT16, BASE_DEC, NULL, 0x0, \"Operation\", HFILL }},\n";
1320         pidl "\t{ &hf_policy_handle, { \"Policy handle\", \"$module.policy\", FT_BYTES, BASE_NONE, NULL, 0x0, \"Policy handle\", HFILL }},\n";
1321         pidl "\t{ &hf_rc, { \"Return code\", \"$module.rc\", FT_UINT32, BASE_HEX, VALS(NT_errors), 0x0, \"Return status code\", HFILL }},\n";
1322         pidl "\t{ &hf_switch, { \"Switch\", \"$module.switch\", FT_UINT16, BASE_DEC, NULL, 0x0, \"Switch\", HFILL }},\n";
1323         pidl "\t{ &hf_array_size, { \"Array size\", \"$module.array_size\", FT_UINT32, BASE_DEC, NULL, 0x0, \"Array size\", HFILL }},\n";
1324         pidl "\t{ &hf_length_is, { \"Length is\", \"$module.length_is\", FT_UINT32, BASE_DEC, NULL, 0x0, \"Length is\", HFILL }},\n";
1325         pidl "\t{ &hf_ptr, { \"Pointer\", \"$module.ptr\", FT_UINT32, BASE_HEX, NULL, 0x0, \"Pointer\", HFILL }},\n";
1326
1327         foreach my $x (keys(%needed)) {
1328             next, if !($x =~ /^hf_/);
1329
1330             pidl "\t{ &$x,\n";
1331             pidl "\t  { \"$needed{$x}{name}\", \"$x\", $needed{$x}{ft}, $needed{$x}{base},\n";
1332             pidl"\t  NULL, 0, \"$x\", HFILL }},\n";
1333         }
1334
1335         pidl "\t};\n\n";
1336
1337         pidl "\tstatic gint *ett[] = {\n";
1338         pidl "\t\t&ett_dcerpc_$module,\n";
1339         pidl "\t};\n\n";
1340
1341         pidl "\tproto_dcerpc_$module = proto_register_protocol(\"$module\", \"$module\", \"$module\");\n\n";
1342
1343         pidl "\tproto_register_field_array(proto_dcerpc_$module, hf, array_length (hf));\n";
1344         pidl "\tproto_register_subtree_array(ett, array_length(ett));\n";
1345
1346         pidl "}\n\n";
1347
1348         pidl "void proto_reg_handoff_dcerpc_$module(void)\n";
1349         pidl "{\n";
1350         pidl "\tdcerpc_init_uuid(proto_dcerpc_$module, ett_dcerpc_$module, \n";
1351         pidl "\t\t&uuid_dcerpc_$module, ver_dcerpc_$module, \n";
1352         pidl "\t\tdcerpc_dissectors, hf_opnum);\n";
1353         pidl "}\n";
1354
1355         close(OUT);
1356 }
1357
1358 1;