92199e13f108e40fa99027a9231d1db20588ace2
[samba.git] / source / 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 my %hf;
20 my @ett;
21
22 my $conformance = {imports=>{}};
23
24 my %ptrtype_mappings = (
25         "unique" => "NDR_POINTER_UNIQUE",
26         "ref" => "NDR_POINTER_REF",
27         "ptr" => "NDR_POINTER_PTR"
28 );
29
30 sub type2ft($)
31 {
32     my($t) = shift;
33  
34     return "FT_UINT$1" if $t =~ /uint(8|16|32|64)/;
35     return "FT_INT$1" if $t =~ /int(8|16|32|64)/;
36     return "FT_UINT64", if $t eq "HYPER_T" or $t eq "NTTIME"
37         or $t eq "NTTIME_1sec" or $t eq "NTTIME_hyper" or $t eq "hyper";
38
39     return "FT_STRING" if ($t eq "string");
40    
41     return "FT_NONE";
42 }
43
44 sub StripPrefixes($)
45 {
46         my ($s) = @_;
47
48         foreach (@{$conformance->{strip_prefixes}}) {
49                 $s =~ s/^$_\_//g;
50         }
51
52         return $s;
53 }
54
55 # Convert a IDL structure field name (e.g access_mask) to a prettier
56 # string like 'Access Mask'.
57
58 sub field2name($)
59 {
60     my($field) = shift;
61
62     $field =~ s/_/ /g;          # Replace underscores with spaces
63     $field =~ s/(\w+)/\u\L$1/g; # Capitalise each word
64     
65     return $field;
66 }
67
68 my %res = ();
69 my $tabs = "";
70 sub pidl_code($)
71 {
72         my $d = shift;
73         if ($d) {
74                 $res{code} .= $tabs;
75                 $res{code} .= $d;
76         }
77         $res{code} .="\n";
78 }
79
80 sub pidl_hdr($) { my $x = shift; $res{hdr} .= "$x\n"; }
81 sub pidl_def($) { my $x = shift; $res{def} .= "$x\n"; }
82
83 sub indent()
84 {
85         $tabs .= "\t";
86 }
87
88 sub deindent()
89 {
90         $tabs = substr($tabs, 0, -1);
91 }
92
93 sub PrintIdl($)
94 {
95         my $idl = shift;
96
97         foreach (split /\n/, $idl) {
98                 pidl_code "/* IDL: $_ */";
99         }
100
101         pidl_code "";
102 }
103
104 #####################################################################
105 # parse the interface definitions
106 sub Interface($)
107 {
108         my($interface) = @_;
109         Const($_,$interface->{NAME}) foreach (@{$interface->{CONSTS}});
110         Typedef($_,$interface->{NAME}) foreach (@{$interface->{TYPEDEFS}});
111         Function($_,$interface->{NAME}) foreach (@{$interface->{FUNCTIONS}});
112 }
113
114 sub Enum($$$)
115 {
116         my ($e,$name,$ifname) = @_;
117         my $valsstring = "$ifname\_$name\_vals";
118         my $dissectorname = "$ifname\_dissect\_".StripPrefixes($name)."_enum";
119
120         return if (defined($conformance->{noemit}->{$dissectorname}));
121
122         foreach (@{$e->{ELEMENTS}}) {
123                 if (/([^=]*)=(.*)/) {
124                         pidl_hdr "#define $1 ($2)";
125                 }
126         }
127         
128         pidl_hdr "extern const value_string $valsstring\[];";
129         pidl_hdr "int $dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int hf_index, guint32 param);";
130
131         pidl_def "const value_string ".$valsstring."[] = {";
132         foreach (@{$e->{ELEMENTS}}) {
133                 next unless (/([^=]*)=(.*)/);
134                 pidl_def "\t{ $1, \"$1\" },";
135         }
136
137         pidl_def "{ 0, NULL }";
138         pidl_def "};";
139
140         pidl_code "int";
141         pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int hf_index, guint32 param _U_)";
142         pidl_code "{";
143         indent;
144         pidl_code "offset = dissect_ndr_$e->{BASE_TYPE}(tvb, offset, pinfo, tree, drep, hf_index, NULL);";
145         pidl_code "return offset;";
146         deindent;
147         pidl_code "}\n";
148
149         my $enum_size = $e->{BASE_TYPE};
150         $enum_size =~ s/uint//g;
151         register_type($name, "offset = $dissectorname(tvb, offset, pinfo, tree, drep, \@HF\@, \@PARAM\@);", type2ft($e->{BASE_TYPE}), "BASE_DEC", "0", "VALS($valsstring)", $enum_size / 8);
152 }
153
154 sub Bitmap($$$)
155 {
156         my ($e,$name,$ifname) = @_;
157         my $dissectorname = "$ifname\_dissect\_".StripPrefixes($name)."_bitmap";
158
159         register_ett("ett_$ifname\_$name");
160
161         pidl_hdr "int $dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int hf_index, guint32 param);";
162
163         pidl_code "int";
164         pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_)";
165         pidl_code "{";
166         indent;
167         pidl_code "proto_item *item = NULL;";
168         pidl_code "proto_tree *tree = NULL;";
169         pidl_code "";
170                 
171         pidl_code "g$e->{BASE_TYPE} flags;";
172         if ($e->{ALIGN} > 1) {
173                 pidl_code "ALIGN_TO_$e->{ALIGN}_BYTES;";
174         }
175
176         pidl_code "";
177
178         pidl_code "if(parent_tree) {";
179         indent;
180         pidl_code "item = proto_tree_add_item(parent_tree, hf_index, tvb, offset, $e->{ALIGN}, TRUE);";
181         pidl_code "tree = proto_item_add_subtree(item,ett_$ifname\_$name);";
182         deindent;
183         pidl_code "}\n";
184
185         pidl_code "offset = dissect_ndr_$e->{BASE_TYPE}(tvb, offset, pinfo, NULL, drep, -1, &flags);";
186
187         pidl_code "proto_item_append_text(item, \": \");\n";
188         pidl_code "if (!flags)";
189         pidl_code "\tproto_item_append_text(item, \"(No values set)\");\n";
190
191         foreach (@{$e->{ELEMENTS}}) {
192                 next unless (/([^ ]*) (.*)/);
193                 my ($en,$ev) = ($1,$2);
194                 my $hf_bitname = "hf_$ifname\_$name\_$en";
195                 my $filtername = "$ifname\.$name\.$en";
196                 
197                 register_hf_field($hf_bitname, field2name($en), $filtername, "FT_BOOLEAN", $e->{ALIGN} * 8, "TFS(&$name\_$en\_tfs)", $ev, "");
198
199                 pidl_def "static const true_false_string $name\_$en\_tfs = {";
200                 pidl_def "   \"$en is SET\",";
201                 pidl_def "   \"$en is NOT SET\",";
202                 pidl_def "};";
203                 
204                 pidl_code "proto_tree_add_boolean(tree, $hf_bitname, tvb, offset-$e->{ALIGN}, $e->{ALIGN}, flags);";
205                 pidl_code "if (flags&$ev){";
206                 pidl_code "\tproto_item_append_text(item, \"$en\");";
207                 pidl_code "\tif (flags & (~$ev))";
208                 pidl_code "\t\tproto_item_append_text(item, \", \");";
209                 pidl_code "}";
210                 pidl_code "flags&=(~$ev);";
211                 pidl_code "";
212         }
213
214         pidl_code "if(flags){";
215         pidl_code "\tproto_item_append_text(item, \"Unknown bitmap value 0x%x\", flags);";
216         pidl_code "}\n";
217         pidl_code "return offset;";
218         deindent;
219         pidl_code "}\n";
220
221         my $size = $e->{BASE_TYPE};
222         $size =~ s/uint//g;
223         register_type($name, "offset = $dissectorname(tvb, offset, pinfo, tree, drep, \@HF\@, \@PARAM\@);", type2ft($e->{BASE_TYPE}), "BASE_DEC", "0", "NULL", $size/8);
224 }
225
226 sub ElementLevel($$$$$)
227 {
228         my ($e,$l,$hf,$myname,$pn) = @_;
229
230         my $param = 0;
231
232         if (defined($conformance->{dissectorparams}->{$myname})) {
233                 $param = $conformance->{dissectorparams}->{$myname};
234         }
235
236         if ($l->{TYPE} eq "POINTER") {
237                 my $type;
238                 if ($l->{LEVEL} eq "TOP") {
239                         $type = "toplevel";
240                 } elsif ($l->{LEVEL} eq "EMBEDDED") {
241                         $type = "embedded";
242                 }
243                 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);";
244         } elsif ($l->{TYPE} eq "ARRAY") {
245                 
246                 if ($l->{IS_INLINE}) {
247                         warn ("Inline arrays not supported");
248                         pidl_code "/* FIXME: Handle inline array */";
249                 } elsif ($l->{IS_FIXED}) {
250                         pidl_code "int i;";
251                         pidl_code "for (i = 0; i < $l->{SIZE_IS}; i++)";
252                         pidl_code "\toffset = $myname\_(tvb, offset, pinfo, tree, drep);";
253                 } else {
254                         my $af = "";
255                         ($af = "ucarray") if ($l->{IS_CONFORMANT});
256                         ($af = "uvarray") if ($l->{IS_VARYING});
257                         ($af = "ucvarray") if ($l->{IS_CONFORMANT} and $l->{IS_VARYING});
258
259                         pidl_code "offset = dissect_ndr_$af(tvb, offset, pinfo, tree, drep, $myname\_);";
260                 }
261         } elsif ($l->{TYPE} eq "DATA") {
262                 if ($l->{DATA_TYPE} eq "string") {
263                         my $bs = 2; # Byte size defaults to that of UCS2
264
265
266                         ($bs = 1) if (property_matches($e, "flag", ".*LIBNDR_FLAG_STR_ASCII.*"));
267                         
268                         if (property_matches($e, "flag", ".*LIBNDR_FLAG_STR_SIZE4.*") and property_matches($e, "flag", ".*LIBNDR_FLAG_STR_LEN4.*")) {
269                                 pidl_code "char *data;\n";
270                                 pidl_code "offset = dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep, $bs, $hf, FALSE, &data);";
271                                 pidl_code "proto_item_append_text(tree, \": %s\", data);";
272                         } elsif (property_matches($e, "flag", ".*LIBNDR_FLAG_STR_SIZE4.*")) {
273                                 pidl_code "offset = dissect_ndr_vstring(tvb, offset, pinfo, tree, drep, $bs, $hf, FALSE, NULL);";
274                         } else {
275                                 warn("Unable to handle string with flags $e->{PROPERTIES}->{flag}");
276                         }
277                 } else {
278                         my $call;
279
280                         if (defined($types{$l->{DATA_TYPE}})) {
281                                 $call= $types{$l->{DATA_TYPE}}->{CALL};
282                         } elsif ($conformance->{imports}->{$l->{DATA_TYPE}}) {
283                                 $call = $conformance->{imports}->{$l->{DATA_TYPE}};     
284                         } else {
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
576         if (defined($x->{UUID})) {
577             pidl_code "void proto_reg_handoff_dcerpc_$x->{NAME}(void)";
578             pidl_code "{";
579             indent;
580             pidl_code "dcerpc_init_uuid(proto_dcerpc_$x->{NAME}, ett_dcerpc_$x->{NAME},";
581             pidl_code "\t&uuid_dcerpc_$x->{NAME}, ver_dcerpc_$x->{NAME},";
582             pidl_code "\t$x->{NAME}_dissectors, hf_$x->{NAME}_opnum);";
583             deindent;
584             pidl_code "}";
585         }
586 }
587
588 sub ProcessInterface($)
589 {
590         my ($x) = @_;
591
592         push(@{$conformance->{strip_prefixes}}, $x->{NAME});
593
594         my $define = "__PACKET_DCERPC_" . uc($_->{NAME}) . "_H";
595         pidl_hdr "#ifndef $define";
596         pidl_hdr "#define $define";
597         pidl_hdr "";
598
599         if (defined $x->{PROPERTIES}->{depends}) {
600                 foreach (split / /, $x->{PROPERTIES}->{depends}) {
601                         next if($_ eq "security");
602                         pidl_hdr "#include \"packet-dcerpc-$_\.h\"\n";
603                 }
604         }
605
606         pidl_def "static gint proto_dcerpc_$x->{NAME} = -1;";
607         register_ett("ett_dcerpc_$x->{NAME}");
608         register_hf_field("hf_$x->{NAME}_opnum", "Operation", "$x->{NAME}.opnum", "FT_UINT16", "BASE_DEC", "NULL", 0, "");
609         register_hf_field("hf_$x->{NAME}_status", "Status", "$x->{NAME}.status", "FT_UINT32", "BASE_HEX", "VALS(NT_errors)", 0, "");
610         register_hf_field("hf_$x->{NAME}_werror", "Windows Error", "$x->{NAME}.werror", "FT_UINT32", "BASE_HEX", "NULL", 0, "");
611
612         if (defined($x->{UUID})) {
613                 my $if_uuid = $x->{UUID};
614
615             pidl_def "/* Version information */\n\n";
616             
617             pidl_def "static e_uuid_t uuid_dcerpc_$x->{NAME} = {";
618             pidl_def "\t0x" . substr($if_uuid, 1, 8) 
619                 . ", 0x" . substr($if_uuid, 10, 4)
620             . ", 0x" . substr($if_uuid, 15, 4) . ",";
621             pidl_def "\t{ 0x" . substr($if_uuid, 20, 2) 
622                 . ", 0x" . substr($if_uuid, 22, 2)
623             . ", 0x" . substr($if_uuid, 25, 2)
624             . ", 0x" . substr($if_uuid, 27, 2)
625             . ", 0x" . substr($if_uuid, 29, 2)
626             . ", 0x" . substr($if_uuid, 31, 2)
627             . ", 0x" . substr($if_uuid, 33, 2)
628             . ", 0x" . substr($if_uuid, 35, 2) . " }";
629             pidl_def "};";
630         
631             my $maj = $x->{VERSION};
632             $maj =~ s/\.(.*)$//g;
633             pidl_def "static guint16 ver_dcerpc_$x->{NAME} = $maj;";
634             pidl_def "";
635         }
636
637         Interface($x);
638
639         pidl_code "\n".DumpFunctionTable($x);
640
641         RegisterInterface($x);
642         RegisterInterfaceHandoff($x);
643
644         pidl_hdr "#endif /* $define */";
645 }
646
647
648 sub register_type($$$$$$$)
649 {
650         my ($type,$call,$ft,$base,$mask,$vals,$length) = @_;
651
652         $types{$type} = {
653                 TYPE => $type,
654                 CALL => $call,
655                 FT_TYPE => $ft,
656                 BASE => $base,
657                 MASK => $mask,
658                 VALSSTRING => $vals,
659                 LENGTH => $length
660         };
661 }
662
663 # Loads the default types
664 sub Initialize($)
665 {
666         my $cnf_file = shift;
667
668         $conformance = {};
669
670         ReadConformance($cnf_file, $conformance) or print "Warning: No conformance file `$cnf_file'\n";
671         
672         foreach my $bytes (qw(1 2 4 8)) {
673                 my $bits = $bytes * 8;
674                 register_type("uint$bits", "offset = dissect_ndr_uint$bits(tvb, offset, pinfo, tree, drep, \@HF\@,NULL);", "FT_UINT$bits", "BASE_DEC", 0, "NULL", $bytes);
675                 register_type("int$bits", "offset = dissect_ndr_uint$bits(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);", "FT_INT$bits", "BASE_DEC", 0, "NULL", $bytes);
676         }
677                 
678         register_type("udlong", "offset = dissect_ndr_duint32(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);", "FT_UINT64", "BASE_DEC", 0, "NULL", 4);
679         register_type("bool8", "offset = dissect_ndr_uint8(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_INT8", "BASE_DEC", 0, "NULL", 1);
680         register_type("char", "offset = dissect_ndr_uint8(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_INT8", "BASE_DEC", 0, "NULL", 1);
681         register_type("long", "offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_INT32", "BASE_DEC", 0, "NULL", 4);
682         register_type("dlong", "offset = dissect_ndr_duint32(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_INT64", "BASE_DEC", 0, "NULL", 8);
683         register_type("GUID", "offset = dissect_ndr_uuid_t(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_GUID", "BASE_NONE", 0, "NULL", 4);
684         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);
685         register_type("NTTIME", "offset = dissect_ndr_nt_NTTIME(tvb, offset, pinfo, tree, drep, \@HF\@);","FT_ABSOLUTE_TIME", "BASE_NONE", 0, "NULL", 4);
686         register_type("NTTIME_hyper", "offset = dissect_ndr_nt_NTTIME(tvb, offset, pinfo, tree, drep, \@HF\@);","FT_ABSOLUTE_TIME", "BASE_NONE", 0, "NULL", 4);
687         register_type("time_t", "offset = dissect_ndr_time_t(tvb, offset, pinfo,tree, drep, \@HF\@, NULL);","FT_ABSOLUTE_TIME", "BASE_DEC", 0, "NULL", 4);
688         register_type("NTTIME_1sec", "offset = dissect_ndr_nt_NTTIME(tvb, offset, pinfo, tree, drep, \@HF\@);", "FT_ABSOLUTE_TIME", "BASE_NONE", 0, "NULL", 4);
689         register_type("SID", "
690                 dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
691
692                 di->hf_index = \@HF\@;
693
694                 offset = dissect_ndr_nt_SID_with_options(tvb, offset, pinfo, tree, drep, param);
695         ","FT_STRING", "BASE_DEC", 0, "NULL", 4);
696         register_type("WERROR", 
697                 "offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_UINT32", "BASE_DEC", 0, "VALS(NT_errors)", 4);
698
699 }
700
701 #####################################################################
702 # Generate ethereal parser and header code
703 sub Parse($$$$)
704 {
705         my($ndr,$idl_file,$h_filename,$cnf_file) = @_;
706         Initialize($cnf_file);
707
708         $tabs = "";
709
710         %res = (code=>"",def=>"",hdr=>"");
711         %hf = ();
712         @ett = ();
713
714         my $notice = 
715 "/* DO NOT EDIT
716         This filter was automatically generated
717         from $idl_file and $cnf_file.
718         
719         Pidl is a perl based IDL compiler for DCE/RPC idl files. 
720         It is maintained by the Samba team, not the Ethereal team.
721         Instructions on how to download and install Pidl can be 
722         found at http://wiki.ethereal.com/Pidl
723 */
724
725 ";
726
727         pidl_hdr $notice;
728
729         $res{headers} = "\n";
730         $res{headers} .= "#ifdef HAVE_CONFIG_H\n";
731         $res{headers} .= "#include \"config.h\"\n";
732         $res{headers} .= "#endif\n\n";
733         $res{headers} .= "#include <glib.h>\n";
734         $res{headers} .= "#include <string.h>\n";
735         $res{headers} .= "#include <epan/packet.h>\n\n";
736
737         $res{headers} .= "#include \"packet-dcerpc.h\"\n";
738         $res{headers} .= "#include \"packet-dcerpc-nt.h\"\n";
739         $res{headers} .= "#include \"packet-windows-common.h\"\n";
740
741         use File::Basename;     
742         my $h_basename = basename($h_filename);
743
744         $res{headers} .= "#include \"$h_basename\"\n";
745         pidl_code "";
746
747         # Ethereal protocol registration
748
749         ProcessInterface($_) foreach (@$ndr);
750
751         $res{ett} = DumpEttDeclaration();
752         $res{hf} = DumpHfDeclaration();
753
754         my $parser = $notice;
755         $parser.= $res{headers};
756         $parser.=$res{ett};
757         $parser.=$res{hf};
758         $parser.=$res{def};
759         $parser.=$conformance->{override};
760         $parser.=$res{code};
761
762         my $header = "/* autogenerated by pidl */\n\n";
763         $header.=$res{hdr};
764     
765         return ($parser,$header);
766 }
767
768 ###############################################################################
769 # ETT
770 ###############################################################################
771
772 sub register_ett($)
773 {
774         my $name = shift;
775
776         push (@ett, $name);     
777 }
778
779 sub DumpEttList()
780 {
781         my $res = "\tstatic gint *ett[] = {\n";
782         foreach (@ett) {
783                 $res .= "\t\t&$_,\n";
784         }
785
786         return "$res\t};\n";
787 }
788
789 sub DumpEttDeclaration()
790 {
791         my $res = "\n/* Ett declarations */\n";
792         foreach (@ett) {
793                 $res .= "static gint $_ = -1;\n";
794         }
795
796         return "$res\n";
797 }
798
799 ###############################################################################
800 # HF
801 ###############################################################################
802
803 sub register_hf_field($$$$$$$$) 
804 {
805         my ($index,$name,$filter_name,$ft_type,$base_type,$valsstring,$mask,$blurb) = @_;
806
807         return $conformance->{hf_renames}->{$index} if defined ($conformance->{hf_renames}->{$index});
808
809         $hf{$index} = {
810                 INDEX => $index,
811                 NAME => $name,
812                 FILTER => $filter_name,
813                 FT_TYPE => $ft_type,
814                 BASE_TYPE => $base_type,
815                 VALS => $valsstring,
816                 MASK => $mask,
817                 BLURB => $blurb
818         };
819
820         return $index;
821 }
822
823 sub DumpHfDeclaration()
824 {
825         my $res = "";
826
827         $res = "\n/* Header field declarations */\n";
828
829         foreach (keys %hf) 
830         {
831                 $res .= "static gint $_ = -1;\n";
832         }
833
834         return "$res\n";
835 }
836
837 sub DumpHfList()
838 {
839         my $res = "\tstatic hf_register_info hf[] = {\n";
840
841         foreach (values %hf) 
842         {
843                 $res .= "\t{ &$_->{INDEX}, 
844           { \"$_->{NAME}\", \"$_->{FILTER}\", $_->{FT_TYPE}, $_->{BASE_TYPE}, $_->{VALS}, $_->{MASK}, \"$_->{BLURB}\", HFILL }},
845 ";
846         }
847
848         return $res."\t};\n";
849 }
850
851
852 ###############################################################################
853 # Function table
854 ###############################################################################
855
856 sub DumpFunctionTable($)
857 {
858         my $if = shift;
859
860         my $res = "static dcerpc_sub_dissector $if->{NAME}\_dissectors[] = {\n";
861         foreach (@{$if->{FUNCTIONS}}) {
862                 my $fn_name = $_->{NAME};
863                 $fn_name =~ s/^$if->{NAME}_//;
864                 $res.= "\t{ $_->{OPNUM}, \"$fn_name\",\n";
865                 $res.= "\t   $if->{NAME}_dissect_${fn_name}_request, $if->{NAME}_dissect_${fn_name}_response},\n";
866         }
867
868         $res .= "\t{ 0, NULL, NULL, NULL }\n";
869
870         return "$res};\n";
871 }
872
873 1;