r9576: Couple of small fixes. Generate notice indicating
[ira/wip.git] / source4 / pidl / lib / Parse / Pidl / Ethereal / NDR.pm
1 ##################################################
2 # Samba4 NDR parser generator for IDL structures
3 # Copyright tridge@samba.org 2000-2003
4 # Copyright tpot@samba.org 2001,2005
5 # Copyright jelmer@samba.org 2004-2005
6 # Portions based on idl2eth.c by Ronnie Sahlberg
7 # released under the GNU GPL
8
9 package Parse::Pidl::Ethereal::NDR;
10
11 use strict;
12 use Parse::Pidl::Typelist;
13 use Parse::Pidl::Util qw(has_property ParseExpr property_matches);
14 use Parse::Pidl::NDR;
15 use Parse::Pidl::Dump qw(DumpTypedef DumpFunction);
16 use Parse::Pidl::Ethereal::Conformance qw(ReadConformance);
17
18 my %types;
19
20 my $conformance = {imports=>{}};
21
22 my %ptrtype_mappings = (
23         "unique" => "NDR_POINTER_UNIQUE",
24         "ref" => "NDR_POINTER_REF",
25         "ptr" => "NDR_POINTER_PTR"
26 );
27
28 sub type2ft($)
29 {
30     my($t) = shift;
31  
32     return "FT_UINT$1" if $t =~ /uint(8|16|32|64)/;
33     return "FT_INT$1" if $t =~ /int(8|16|32|64)/;
34     return "FT_UINT64", if $t eq "HYPER_T" or $t eq "NTTIME"
35         or $t eq "NTTIME_1sec" or $t eq "NTTIME_hyper" or $t eq "hyper";
36
37     return "FT_STRING" if ($t eq "string");
38    
39     return "FT_NONE";
40 }
41
42 sub StripPrefixes($)
43 {
44         my ($s) = @_;
45
46         foreach (@{$conformance->{strip_prefixes}}) {
47                 $s =~ s/^$_\_//g;
48         }
49
50         return $s;
51 }
52
53 # Convert a IDL structure field name (e.g access_mask) to a prettier
54 # string like 'Access Mask'.
55
56 sub field2name($)
57 {
58     my($field) = shift;
59
60     $field =~ s/_/ /g;          # Replace underscores with spaces
61     $field =~ s/(\w+)/\u\L$1/g; # Capitalise each word
62     
63     return $field;
64 }
65
66 my %res = ();
67 my $tabs = "";
68 sub pidl_code($)
69 {
70         my $d = shift;
71         if ($d) {
72                 $res{code} .= $tabs;
73                 $res{code} .= $d;
74         }
75         $res{code} .="\n";
76 }
77
78 sub pidl_hdr($) { my $x = shift; $res{hdr} .= "$x\n"; }
79 sub pidl_def($) { my $x = shift; $res{def} .= "$x\n"; }
80
81 sub indent()
82 {
83         $tabs .= "\t";
84 }
85
86 sub deindent()
87 {
88         $tabs = substr($tabs, 0, -1);
89 }
90
91 sub PrintIdl($)
92 {
93         my $idl = shift;
94
95         foreach (split /\n/, $idl) {
96                 pidl_code "/* IDL: $_ */";
97         }
98
99         pidl_code "";
100 }
101
102 #####################################################################
103 # parse the interface definitions
104 sub Interface($)
105 {
106         my($interface) = @_;
107         Const($_,$interface->{NAME}) foreach (@{$interface->{CONSTS}});
108         Typedef($_,$interface->{NAME}) foreach (@{$interface->{TYPEDEFS}});
109         Function($_,$interface->{NAME}) foreach (@{$interface->{FUNCTIONS}});
110 }
111
112 sub Enum($$$)
113 {
114         my ($e,$name,$ifname) = @_;
115         my $valsstring = "$ifname\_$name\_vals";
116         my $dissectorname = "$ifname\_dissect\_".StripPrefixes($name);
117         return if (defined($conformance->{noemit}->{$dissectorname}));
118
119         foreach (@{$e->{ELEMENTS}}) {
120                 if (/([^=]*)=(.*)/) {
121                         pidl_hdr "#define $1 ($2)";
122                 }
123         }
124         
125         pidl_hdr "extern const value_string $valsstring\[];";
126         pidl_hdr "int $dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int hf_index, guint32 param);";
127
128         pidl_def "const value_string ".$valsstring."[] = {";
129         foreach (@{$e->{ELEMENTS}}) {
130                 next unless (/([^=]*)=(.*)/);
131                 pidl_def "\t{ $1, \"$1\" },";
132         }
133
134         pidl_def "{ 0, NULL }";
135         pidl_def "};";
136
137         pidl_code "int";
138         pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int hf_index, guint32 param _U_)";
139         pidl_code "{";
140         indent;
141         pidl_code "offset = dissect_ndr_$e->{BASE_TYPE}(tvb, offset, pinfo, tree, drep, hf_index, NULL);";
142         pidl_code "return offset;";
143         deindent;
144         pidl_code "}\n";
145
146         my $enum_size = $e->{BASE_TYPE};
147         $enum_size =~ s/uint//g;
148         register_type($name, "offset = $dissectorname(tvb, offset, pinfo, tree, drep, \@HF\@, \@PARAM\@);", type2ft($e->{BASE_TYPE}), "BASE_DEC", "0", "VALS($valsstring)", $enum_size / 8);
149 }
150
151 sub Bitmap($$$)
152 {
153         my ($e,$name,$ifname) = @_;
154         my $dissectorname = "$ifname\_dissect\_".StripPrefixes($name);
155
156         register_ett("ett_$ifname\_$name");
157
158
159         pidl_hdr "int $dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int hf_index, guint32 param);";
160
161         pidl_code "int";
162         pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_)";
163         pidl_code "{";
164         indent;
165         pidl_code "proto_item *item = NULL;";
166         pidl_code "proto_tree *tree = NULL;";
167         pidl_code "";
168                 
169         pidl_code "g$e->{BASE_TYPE} flags;";
170         if ($e->{ALIGN} > 1) {
171                 pidl_code "ALIGN_TO_$e->{ALIGN}_BYTES;";
172         }
173
174         pidl_code "";
175
176         pidl_code "if(parent_tree) {";
177         indent;
178         pidl_code "item = proto_tree_add_item(parent_tree, hf_index, tvb, offset, $e->{ALIGN}, TRUE);";
179         pidl_code "tree = proto_item_add_subtree(item,ett_$ifname\_$name);";
180         deindent;
181         pidl_code "}\n";
182
183         pidl_code "offset = dissect_ndr_$e->{BASE_TYPE}(tvb, offset, pinfo, NULL, drep, -1, &flags);";
184
185         pidl_code "proto_item_append_text(item, \": \");\n";
186         pidl_code "if (!flags)";
187         pidl_code "\tproto_item_append_text(item, \"(No values set)\");\n";
188
189         foreach (@{$e->{ELEMENTS}}) {
190                 next unless (/([^ ]*) (.*)/);
191                 my ($en,$ev) = ($1,$2);
192                 my $hf_bitname = "hf_$ifname\_$name\_$en";
193                 my $filtername = "$ifname\.$name\.$en";
194                 
195                 register_hf_field($hf_bitname, field2name($en), $filtername, "FT_BOOLEAN", $e->{ALIGN} * 8, "TFS(&$name\_$en\_tfs)", $ev, "");
196
197                 pidl_def "static const true_false_string $name\_$en\_tfs = {";
198                 pidl_def "   \"$en is SET\",";
199                 pidl_def "   \"$en is NOT SET\",";
200                 pidl_def "};";
201                 
202                 pidl_code "proto_tree_add_boolean(tree, $hf_bitname, tvb, offset-$e->{ALIGN}, $e->{ALIGN}, flags);";
203                 pidl_code "if (flags&$ev){";
204                 pidl_code "\tproto_item_append_text(item, \"$en\");";
205                 pidl_code "\tif (flags & (~$ev))";
206                 pidl_code "\t\tproto_item_append_text(item, \", \");";
207                 pidl_code "}";
208                 pidl_code "flags&=(~$ev);";
209                 pidl_code "";
210         }
211
212         pidl_code "if(flags){";
213         pidl_code "\tproto_item_append_text(item, \"Unknown bitmap value 0x%x\", flags);";
214         pidl_code "}\n";
215         pidl_code "return offset;";
216         deindent;
217         pidl_code "}\n";
218
219         my $size = $e->{BASE_TYPE};
220         $size =~ s/uint//g;
221         register_type($name, "offset = $dissectorname(tvb, offset, pinfo, tree, drep, \@HF\@, \@PARAM\@);", type2ft($e->{BASE_TYPE}), "BASE_DEC", "0", "NULL", $size/8);
222 }
223
224 sub ElementLevel($$$$$)
225 {
226         my ($e,$l,$hf,$myname,$pn) = @_;
227
228         my $param = 0;
229
230         if (defined($conformance->{dissectorparams}->{$myname})) {
231                 $param = $conformance->{dissectorparams}->{$myname};
232         }
233
234         if ($l->{TYPE} eq "POINTER") {
235                 my $type;
236                 if ($l->{LEVEL} eq "TOP") {
237                         $type = "toplevel";
238                 } elsif ($l->{LEVEL} eq "EMBEDDED") {
239                         $type = "embedded";
240                 }
241                 pidl_code "offset = dissect_ndr_$type\_pointer(tvb, offset, pinfo, tree, drep, $myname\_, $ptrtype_mappings{$l->{POINTER_TYPE}}, \"Pointer to ".field2name(StripPrefixes($e->{NAME})) . " ($e->{TYPE})\",$hf);";
242         } elsif ($l->{TYPE} eq "ARRAY") {
243                 
244                 if ($l->{IS_INLINE}) {
245                         warn ("Inline arrays not supported");
246                         pidl_code "/* FIXME: Handle inline array */";
247                 } elsif ($l->{IS_FIXED}) {
248                         pidl_code "int i;";
249                         pidl_code "for (i = 0; i < $l->{SIZE_IS}; i++)";
250                         pidl_code "\toffset = $myname\_(tvb, offset, pinfo, tree, drep);";
251                 } else {
252                         my $af = "";
253                         ($af = "ucarray") if ($l->{IS_CONFORMANT});
254                         ($af = "uvarray") if ($l->{IS_VARYING});
255                         ($af = "ucvarray") if ($l->{IS_CONFORMANT} and $l->{IS_VARYING});
256
257                         pidl_code "offset = dissect_ndr_$af(tvb, offset, pinfo, tree, drep, $myname\_);";
258                 }
259         } elsif ($l->{TYPE} eq "DATA") {
260                 if ($l->{DATA_TYPE} eq "string") {
261                         my $bs = 2; # Byte size defaults to that of UCS2
262
263
264                         ($bs = 1) if (property_matches($e, "flag", ".*LIBNDR_FLAG_STR_ASCII.*"));
265                         
266                         if (property_matches($e, "flag", ".*LIBNDR_FLAG_STR_SIZE4.*") and property_matches($e, "flag", ".*LIBNDR_FLAG_STR_LEN4.*")) {
267                                 pidl_code "char *data;\n";
268                                 pidl_code "offset = dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep, $bs, $hf, FALSE, &data);";
269                                 pidl_code "proto_item_append_text(tree, \": %s\", data);";
270                         } elsif (property_matches($e, "flag", ".*LIBNDR_FLAG_STR_SIZE4.*")) {
271                                 pidl_code "offset = dissect_ndr_vstring(tvb, offset, pinfo, tree, drep, $bs, $hf, FALSE, NULL);";
272                         } else {
273                                 warn("Unable to handle string with flags $e->{PROPERTIES}->{flag}");
274                         }
275                 } else {
276                         my $call;
277
278                         if (defined($types{$l->{DATA_TYPE}})) {
279                                 $call= $types{$l->{DATA_TYPE}}->{CALL};
280                         } elsif ($conformance->{imports}->{$l->{DATA_TYPE}}) {
281                                 $call = $conformance->{imports}->{$l->{DATA_TYPE}};     
282                         } else {
283                                 warn("Unknown data type `$l->{DATA_TYPE}'");
284                                 pidl_code "/* FIXME: Handle unknown data type $l->{DATA_TYPE} */";
285                                 if ($l->{DATA_TYPE} =~ /^([a-z]+)\_(.*)$/)
286                                 {
287                                         pidl_code "offset = $1_dissect_$2(tvb,offset,pinfo,tree,drep,$hf,$param);";
288                                 }
289
290                                 return;
291                         }
292
293                         $call =~ s/\@HF\@/$hf/g;
294                         $call =~ s/\@PARAM\@/$param/g;
295                         pidl_code "$call";
296                 }
297         } elsif ($_->{TYPE} eq "SUBCONTEXT") {
298                 my $num_bits = ($l->{HEADER_SIZE}*8);
299                 pidl_code "guint$num_bits size;";
300                 pidl_code "int start_offset = offset;";
301                 pidl_code "tvbuff_t *subtvb;";
302                 pidl_code "offset = dissect_ndr_uint$num_bits(tvb, offset, pinfo, tree, drep, $hf, &size);";
303                 pidl_code "proto_tree_add_text(tree, tvb, start_offset, offset - start_offset + size, \"Subcontext size\");";
304
305                 pidl_code "subtvb = tvb_new_subset(tvb, offset, size, -1);";
306                 pidl_code "$myname\_(subtvb, 0, pinfo, tree, drep);";
307         } else {
308                 die("Unknown type `$_->{TYPE}'");
309         }
310 }
311
312 sub Element($$$)
313 {
314         my ($e,$pn,$ifname) = @_;
315
316         my $dissectorname = "$ifname\_dissect\_".StripPrefixes($pn)."\_".StripPrefixes($e->{NAME});
317
318         my $call_code = "offset = $dissectorname(tvb, offset, pinfo, tree, drep);";
319
320         my $hf = register_hf_field("hf_$ifname\_$pn\_$e->{NAME}", field2name($e->{NAME}), "$ifname.$pn.$e->{NAME}", type2ft($e->{TYPE}), "BASE_HEX", "NULL", 0, "");
321
322         if (defined($conformance->{noemit}->{$dissectorname})) {
323                 return $call_code;
324         }
325
326         my $add = "";
327
328         foreach (@{$e->{LEVELS}}) {
329                 next if ($_->{TYPE} eq "SWITCH");
330                 pidl_def "static int $dissectorname$add(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep);";
331                 pidl_code "static int";
332                 pidl_code "$dissectorname$add(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)";
333                 pidl_code "{";
334                 indent;
335
336                 ElementLevel($e,$_,$hf,$dissectorname.$add,$pn);
337
338                 pidl_code "";
339                 pidl_code "return offset;";
340                 deindent;
341                 pidl_code "}\n";
342                 $add.="_";
343         }
344
345         return $call_code;
346 }
347
348 sub Function($$$)
349 {
350         my ($fn,$ifname) = @_;
351
352         my %dissectornames;
353
354         foreach (@{$fn->{ELEMENTS}}) {
355             $dissectornames{$_->{NAME}} = Element($_, $fn->{NAME}, $ifname) if not defined($dissectornames{$_->{NAME}});
356         }
357         
358         my $fn_name = $_->{NAME};
359         $fn_name =~ s/^${ifname}_//;
360
361         PrintIdl DumpFunction($fn->{ORIGINAL});
362         pidl_code "static int";
363         pidl_code "$ifname\_dissect\_${fn_name}_response(tvbuff_t *tvb _U_, int offset _U_, packet_info *pinfo _U_, proto_tree *tree _U_, guint8 *drep _U_)";
364         pidl_code "{";
365         indent;
366         foreach (@{$fn->{ELEMENTS}}) {
367                 if (grep(/out/,@{$_->{DIRECTION}})) {
368                         pidl_code "$dissectornames{$_->{NAME}}";
369                         pidl_code "offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);";
370                         pidl_code "";
371                 }
372         }
373
374         if (not defined($fn->{RETURN_TYPE})) {
375         } elsif ($fn->{RETURN_TYPE} eq "NTSTATUS") {
376                 pidl_code "offset = dissect_ntstatus(tvb, offset, pinfo, tree, drep, hf\_$ifname\_status, NULL);";
377         } elsif ($fn->{RETURN_TYPE} eq "WERROR") {
378                 pidl_code "offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf\_$ifname\_werror, NULL);";
379         }
380
381         pidl_code "return offset;";
382         deindent;
383         pidl_code "}\n";
384
385         pidl_code "static int";
386         pidl_code "$ifname\_dissect\_${fn_name}_request(tvbuff_t *tvb _U_, int offset _U_, packet_info *pinfo _U_, proto_tree *tree _U_, guint8 *drep _U_)";
387         pidl_code "{";
388         indent;
389         foreach (@{$fn->{ELEMENTS}}) {
390                 if (grep(/in/,@{$_->{DIRECTION}})) {
391                         pidl_code "$dissectornames{$_->{NAME}}";
392                         pidl_code "offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);";
393                 }
394
395         }
396
397         pidl_code "return offset;";
398         deindent;
399         pidl_code "}\n";
400 }
401
402 sub Struct($$$)
403 {
404         my ($e,$name,$ifname) = @_;
405         my $dissectorname = "$ifname\_dissect\_".StripPrefixes($name);
406
407         return if (defined($conformance->{noemit}->{$dissectorname}));
408
409         register_ett("ett_$ifname\_$name");
410
411         my $res = "";
412         ($res.="\t".Element($_, $name, $ifname)."\n\n") foreach (@{$e->{ELEMENTS}});
413
414         pidl_hdr "int $dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_);";
415
416         pidl_code "int";
417         pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_)";
418         pidl_code "{";
419         indent;
420         pidl_code "proto_item *item = NULL;";
421         pidl_code "proto_tree *tree = NULL;";
422         pidl_code "int old_offset;";
423         pidl_code "";
424
425         if ($e->{ALIGN} > 1) {
426                 pidl_code "ALIGN_TO_$e->{ALIGN}_BYTES;";
427         }
428         pidl_code "";
429
430         pidl_code "old_offset = offset;";
431         pidl_code "";
432         pidl_code "if(parent_tree){";
433         indent;
434         pidl_code "item = proto_tree_add_item(parent_tree, hf_index, tvb, offset, -1, TRUE);";
435         pidl_code "tree = proto_item_add_subtree(item, ett_$ifname\_$name);";
436         deindent;
437         pidl_code "}";
438
439         pidl_code "\n$res";
440
441         pidl_code "proto_item_set_len(item, offset-old_offset);\n";
442         pidl_code "return offset;";
443         deindent;
444         pidl_code "}\n";
445
446         register_type($name, "offset = $dissectorname(tvb,offset,pinfo,tree,drep,\@HF\@,\@PARAM\@);", "FT_NONE", "BASE_NONE", 0, "NULL", 0);
447 }
448
449 sub Union($$$)
450 {
451         my ($e,$name,$ifname) = @_;
452
453         my $dissectorname = "$ifname\_dissect_".StripPrefixes($name);
454         return if (defined($conformance->{noemit}->{$dissectorname}));
455         
456         register_ett("ett_$ifname\_$name");
457
458         my $res = "";
459         foreach (@{$e->{ELEMENTS}}) {
460                 $res.="\n\t\t$_->{CASE}:\n";
461                 if ($_->{TYPE} ne "EMPTY") {
462                         $res.="\t\t\t".Element($_, $name, $ifname)."\n";
463                 }
464                 $res.="\t\tbreak;\n";
465         }
466
467         pidl_code "static int";
468         pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_)";
469         pidl_code "{";
470         indent;
471         pidl_code "proto_item *item = NULL;";
472         pidl_code "proto_tree *tree = NULL;";
473         pidl_code "int old_offset;";
474         pidl_code "g$e->{SWITCH_TYPE} level;";
475         pidl_code "";
476
477         if ($e->{ALIGN} > 1) {
478                 pidl_code "ALIGN_TO_$e->{ALIGN}_BYTES;";
479         }
480
481         pidl_code "";
482
483         pidl_code "old_offset = offset;";
484         pidl_code "if(parent_tree){";
485         indent;
486         pidl_code "item = proto_tree_add_text(parent_tree, tvb, offset, -1, \"$name\");";
487         pidl_code "tree = proto_item_add_subtree(item, ett_$ifname\_$name);";
488         deindent;
489         pidl_code "}";
490
491         pidl_code "";
492
493         pidl_code "offset = dissect_ndr_$e->{SWITCH_TYPE}(tvb, offset, pinfo, tree, drep, hf_index, &level);";
494
495         pidl_code "switch(level) {$res\t}";
496         pidl_code "proto_item_set_len(item, offset-old_offset);\n";
497         pidl_code "return offset;";
498         deindent;
499         pidl_code "}";
500
501         register_type($name, "offset = $dissectorname(tvb, offset, pinfo, tree, drep, \@HF\@, \@PARAM\@);", "FT_NONE", "BASE_NONE", 0, "NULL", 0);
502 }
503
504 sub Const($$)
505 {
506         my ($const,$ifname) = @_;
507         
508         if (!defined($const->{ARRAY_LEN}[0])) {
509                 pidl_hdr "#define $const->{NAME}\t( $const->{VALUE} )\n";
510         } else {
511                 pidl_hdr "#define $const->{NAME}\t $const->{VALUE}\n";
512         }
513 }
514
515 sub Typedef($$)
516 {
517         my ($e,$ifname) = @_;
518
519         PrintIdl DumpTypedef($e->{ORIGINAL});
520
521         {
522                 ENUM => \&Enum,
523                 STRUCT => \&Struct,
524                 UNION => \&Union,
525                 BITMAP => \&Bitmap
526         }->{$e->{DATA}->{TYPE}}->($e->{DATA}, $e->{NAME}, $ifname);
527 }
528
529 sub RegisterInterface($)
530 {
531         my ($x) = @_;
532
533         pidl_code "void proto_register_dcerpc_$x->{NAME}(void)";
534         pidl_code "{";
535         indent;
536
537         $res{code}.=DumpHfList()."\n";
538         $res{code}.="\n".DumpEttList()."\n";
539         
540         if (defined($x->{UUID})) {
541             # These can be changed to non-pidl_code names if the old dissectors
542             # in epan/dissctors are deleted.
543     
544             my $name = "\"" . uc($x->{NAME}) . " (pidl)\"";
545             my $short_name = uc($x->{NAME});
546             my $filter_name = $x->{NAME};
547
548             if (has_property($x, "helpstring")) {
549                 $name = $x->{PROPERTIES}->{helpstring};
550             }
551
552             if (defined($conformance->{protocols}->{$x->{NAME}})) {
553                 $short_name = $conformance->{protocols}->{$x->{NAME}}->{SHORTNAME};
554                 $name = $conformance->{protocols}->{$x->{NAME}}->{LONGNAME};
555                 $filter_name = $conformance->{protocols}->{$x->{NAME}}->{FILTERNAME};
556             }
557
558             pidl_code "proto_dcerpc_$x->{NAME} = proto_register_protocol($name, \"$short_name\", \"$filter_name\");";
559             
560             pidl_code "proto_register_field_array(proto_dcerpc_$x->{NAME}, hf, array_length (hf));";
561             pidl_code "proto_register_subtree_array(ett, array_length(ett));";
562         } else {
563             pidl_code "proto_dcerpc = proto_get_id_by_filter_name(\"dcerpc\");";
564             pidl_code "proto_register_field_array(proto_dcerpc, hf, array_length(hf));";
565             pidl_code "proto_register_subtree_array(ett, array_length(ett));";
566         }
567             
568         deindent;
569         pidl_code "}\n";
570 }
571
572 sub RegisterInterfaceHandoff($)
573 {
574         my $x = shift;
575         pidl_code "void proto_reg_handoff_dcerpc_$x->{NAME}(void)";
576         pidl_code "{";
577         indent;
578         pidl_code "dcerpc_init_uuid(proto_dcerpc_$x->{NAME}, ett_dcerpc_$x->{NAME},";
579         pidl_code "\t&uuid_dcerpc_$x->{NAME}, ver_dcerpc_$x->{NAME},";
580         pidl_code "\t$x->{NAME}_dissectors, hf_$x->{NAME}_opnum);";
581         deindent;
582         pidl_code "}";
583 }
584
585 sub ProcessInterface($)
586 {
587         my ($x) = @_;
588
589         push(@{$conformance->{strip_prefixes}}, $x->{NAME});
590
591         my $define = "__PACKET_DCERPC_" . uc($_->{NAME}) . "_H";
592         pidl_hdr "#ifndef $define";
593         pidl_hdr "#define $define";
594         pidl_hdr "";
595
596         if (defined $x->{PROPERTIES}->{depends}) {
597                 foreach (split / /, $x->{PROPERTIES}->{depends}) {
598                         next if($_ eq "security");
599                         pidl_hdr "#include \"packet-dcerpc-$_\.h\"\n";
600                 }
601         }
602
603         pidl_def "static gint proto_dcerpc_$x->{NAME} = -1;";
604         register_ett("ett_dcerpc_$x->{NAME}");
605         register_hf_field("hf_$x->{NAME}_opnum", "Operation", "$x->{NAME}.opnum", "FT_UINT16", "BASE_DEC", "NULL", 0, "");
606         register_hf_field("hf_$x->{NAME}_status", "Status", "$x->{NAME}.status", "FT_UINT32", "BASE_HEX", "VALS(NT_errors)", 0, "");
607         register_hf_field("hf_$x->{NAME}_werror", "Windows Error", "$x->{NAME}.werror", "FT_UINT32", "BASE_HEX", "NULL", 0, "");
608
609         if (defined($x->{UUID})) {
610                 my $if_uuid = $x->{UUID};
611
612             pidl_def "/* Version information */\n\n";
613             
614             pidl_def "static e_uuid_t uuid_dcerpc_$x->{NAME} = {";
615             pidl_def "\t0x" . substr($if_uuid, 1, 8) 
616                 . ", 0x" . substr($if_uuid, 10, 4)
617             . ", 0x" . substr($if_uuid, 15, 4) . ",";
618             pidl_def "\t{ 0x" . substr($if_uuid, 20, 2) 
619                 . ", 0x" . substr($if_uuid, 22, 2)
620             . ", 0x" . substr($if_uuid, 25, 2)
621             . ", 0x" . substr($if_uuid, 27, 2)
622             . ", 0x" . substr($if_uuid, 29, 2)
623             . ", 0x" . substr($if_uuid, 31, 2)
624             . ", 0x" . substr($if_uuid, 33, 2)
625             . ", 0x" . substr($if_uuid, 35, 2) . " }";
626             pidl_def "};";
627         
628             my $maj = $x->{VERSION};
629             $maj =~ s/\.(.*)$//g;
630             pidl_def "static guint16 ver_dcerpc_$x->{NAME} = $maj;";
631             pidl_def "";
632         }
633
634         Interface($x);
635
636         pidl_code "\n".DumpFunctionTable($x);
637
638         RegisterInterface($x);
639         RegisterInterfaceHandoff($x);
640
641         pidl_hdr "#endif /* $define */";
642 }
643
644
645 sub register_type($$$$$$$)
646 {
647         my ($type,$call,$ft,$base,$mask,$vals,$length) = @_;
648
649         $types{$type} = {
650                 TYPE => $type,
651                 CALL => $call,
652                 FT_TYPE => $ft,
653                 BASE => $base,
654                 MASK => $mask,
655                 VALSSTRING => $vals,
656                 LENGTH => $length
657         };
658 }
659
660 # Loads the default types
661 sub Initialize($)
662 {
663         my $cnf_file = shift;
664
665         $conformance = {};
666
667         ReadConformance($cnf_file, $conformance) or print "Warning: No conformance file `$cnf_file'\n";
668         
669         foreach my $bytes (qw(1 2 4 8)) {
670                 my $bits = $bytes * 8;
671                 register_type("uint$bits", "offset = dissect_ndr_uint$bits(tvb, offset, pinfo, tree, drep, \@HF\@,NULL);", "FT_UINT$bits", "BASE_DEC", 0, "NULL", $bytes);
672                 register_type("int$bits", "offset = dissect_ndr_uint$bits(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);", "FT_INT$bits", "BASE_DEC", 0, "NULL", $bytes);
673         }
674                 
675         register_type("udlong", "offset = dissect_ndr_duint32(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);", "FT_UINT64", "BASE_DEC", 0, "NULL", 4);
676         register_type("bool8", "offset = dissect_ndr_uint8(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_INT8", "BASE_DEC", 0, "NULL", 1);
677         register_type("char", "offset = dissect_ndr_uint8(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_INT8", "BASE_DEC", 0, "NULL", 1);
678         register_type("long", "offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_INT32", "BASE_DEC", 0, "NULL", 4);
679         register_type("dlong", "offset = dissect_ndr_duint32(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_INT64", "BASE_DEC", 0, "NULL", 8);
680         register_type("GUID", "offset = dissect_ndr_uuid_t(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_GUID", "BASE_NONE", 0, "NULL", 4);
681         register_type("policy_handle", "offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep, \@HF\@, NULL, NULL, \@PARAM\@&0x01, \@PARAM\@&0x02);","FT_BYTES", "BASE_NONE", 0, "NULL", 4);
682         register_type("NTTIME", "offset = dissect_ndr_nt_NTTIME(tvb, offset, pinfo, tree, drep, \@HF\@);","FT_ABSOLUTE_TIME", "BASE_NONE", 0, "NULL", 4);
683         register_type("NTTIME_hyper", "offset = dissect_ndr_nt_NTTIME(tvb, offset, pinfo, tree, drep, \@HF\@);","FT_ABSOLUTE_TIME", "BASE_NONE", 0, "NULL", 4);
684         register_type("time_t", "offset = dissect_ndr_time_t(tvb, offset, pinfo,tree, drep, \@HF\@, NULL);","FT_ABSOLUTE_TIME", "BASE_DEC", 0, "NULL", 4);
685         register_type("NTTIME_1sec", "offset = dissect_ndr_nt_NTTIME(tvb, offset, pinfo, tree, drep, \@HF\@);", "FT_ABSOLUTE_TIME", "BASE_NONE", 0, "NULL", 4);
686         register_type("SID", "
687                 dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
688
689                 di->hf_index = \@HF\@;
690
691                 offset = dissect_ndr_nt_SID_with_options(tvb, offset, pinfo, tree, drep, param);
692         ","FT_STRING", "BASE_DEC", 0, "NULL", 4);
693         register_type("WERROR", 
694                 "offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_UINT32", "BASE_DEC", 0, "VALS(NT_errors)", 4);
695
696 }
697
698 #####################################################################
699 # Generate ethereal parser and header code
700 sub Parse($$$$)
701 {
702         my($ndr,$idl_file,$h_filename,$cnf_file) = @_;
703         Initialize($cnf_file);
704
705         $tabs = "";
706
707         %res = (code=>"",def=>"",hdr=>"");
708
709         my $notice = 
710 "/* DO NOT EDIT
711         This filter was automatically generated
712         from $idl_file and $cnf_file.
713         
714         Pidl is a perl based IDL compiler for DCE/RPC idl files. 
715         It is maintained by the Samba team, not the Ethereal team.
716         Instructions on how to download and install Pidl can be 
717         found at http://wiki.ethereal.com/Pidl
718 */
719
720 ";
721
722         pidl_hdr $notice;
723
724         $res{headers} = "\n";
725         $res{headers} .= "#ifdef HAVE_CONFIG_H\n";
726         $res{headers} .= "#include \"config.h\"\n";
727         $res{headers} .= "#endif\n\n";
728         $res{headers} .= "#include <glib.h>\n";
729         $res{headers} .= "#include <string.h>\n";
730         $res{headers} .= "#include <epan/packet.h>\n\n";
731
732         $res{headers} .= "#include \"packet-dcerpc.h\"\n";
733         $res{headers} .= "#include \"packet-dcerpc-nt.h\"\n";
734         $res{headers} .= "#include \"packet-windows-common.h\"\n";
735
736         use File::Basename;     
737         my $h_basename = basename($h_filename);
738
739         $res{headers} .= "#include \"$h_basename\"\n";
740         pidl_code "";
741
742         # Ethereal protocol registration
743
744         ProcessInterface($_) foreach (@$ndr);
745
746         $res{ett} = DumpEttDeclaration();
747         $res{hf} = DumpHfDeclaration();
748
749         my $parser = $notice;
750         $parser.= $res{headers};
751         $parser.=$res{ett};
752         $parser.=$res{hf};
753         $parser.=$res{def};
754         $parser.=$conformance->{override};
755         $parser.=$res{code};
756
757         my $header = "/* autogenerated by pidl */\n\n";
758         $header.=$res{hdr};
759     
760         return ($parser,$header);
761 }
762
763 ###############################################################################
764 # ETT
765 ###############################################################################
766
767 my @ett = ();
768
769 sub register_ett($)
770 {
771         my $name = shift;
772
773         push (@ett, $name);     
774 }
775
776 sub DumpEttList()
777 {
778         my $res = "\tstatic gint *ett[] = {\n";
779         foreach (@ett) {
780                 $res .= "\t\t&$_,\n";
781         }
782
783         return "$res\t};\n";
784 }
785
786 sub DumpEttDeclaration()
787 {
788         my $res = "\n/* Ett declarations */\n";
789         foreach (@ett) {
790                 $res .= "static gint $_ = -1;\n";
791         }
792
793         return "$res\n";
794 }
795
796 ###############################################################################
797 # HF
798 ###############################################################################
799
800 my %hf = ();
801
802 sub register_hf_field($$$$$$$$) 
803 {
804         my ($index,$name,$filter_name,$ft_type,$base_type,$valsstring,$mask,$blurb) = @_;
805
806         return $conformance->{hf_renames}->{$index} if defined ($conformance->{hf_renames}->{$index});
807
808         $hf{$index} = {
809                 INDEX => $index,
810                 NAME => $name,
811                 FILTER => $filter_name,
812                 FT_TYPE => $ft_type,
813                 BASE_TYPE => $base_type,
814                 VALS => $valsstring,
815                 MASK => $mask,
816                 BLURB => $blurb
817         };
818
819         return $index;
820 }
821
822 sub DumpHfDeclaration()
823 {
824         my $res = "";
825
826         $res = "\n/* Header field declarations */\n";
827
828         foreach (keys %hf) 
829         {
830                 $res .= "static gint $_ = -1;\n";
831         }
832
833         return "$res\n";
834 }
835
836 sub DumpHfList()
837 {
838         my $res = "\tstatic hf_register_info hf[] = {\n";
839
840         foreach (values %hf) 
841         {
842                 $res .= "\t{ &$_->{INDEX}, 
843           { \"$_->{NAME}\", \"$_->{FILTER}\", $_->{FT_TYPE}, $_->{BASE_TYPE}, $_->{VALS}, $_->{MASK}, \"$_->{BLURB}\", HFILL }},
844 ";
845         }
846
847         return $res."\t};\n";
848 }
849
850
851 ###############################################################################
852 # Function table
853 ###############################################################################
854
855 sub DumpFunctionTable($)
856 {
857         my $if = shift;
858
859         my $res = "static dcerpc_sub_dissector $if->{NAME}\_dissectors[] = {\n";
860         foreach (@{$if->{FUNCTIONS}}) {
861                 my $fn_name = $_->{NAME};
862                 $fn_name =~ s/^$if->{NAME}_//;
863                 $res.= "\t{ $_->{OPNUM}, \"$fn_name\",\n";
864                 $res.= "\t   $if->{NAME}_dissect_${fn_name}_request, $if->{NAME}_dissect_${fn_name}_response},\n";
865         }
866
867         $res .= "\t{ 0, NULL, NULL, NULL }\n";
868
869         return "$res};\n";
870 }
871
872 1;