r9088: More ethereal parser generator updates
[samba.git] / source / build / pidl / 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
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::Parser;
10
11 use strict;
12 use Parse::Pidl::Typelist;
13 use Parse::Pidl::Util qw(has_property ParseExpr);
14 use Parse::Pidl::NDR;
15 use Parse::Pidl::Ethereal::Conformance qw(EmitProhibited FindDissectorParam);
16
17 my %ptrtype_define_mappings = (
18         "unique" => "NDR_POINTER_UNIQUE",
19         "ref" => "NDR_POINTER_REF",
20         "ptr" => "NDR_POINTER_PTR"
21 );
22
23 sub type2ft($)
24 {
25     my($t) = shift;
26  
27     return "FT_UINT$1" if $t =~ /uint(8|16|32|64)/;
28     return "FT_INT$1" if $t =~ /int(8|16|32|64)/;
29     return "FT_UINT64", if $t eq "HYPER_T" or $t eq "NTTIME"
30         or $t eq "NTTIME_1sec" or $t eq "NTTIME_hyper" or $t eq "hyper";
31    
32    # Type is an enum
33
34     return "FT_UINT16";
35 }
36
37 # Determine the display base for an element
38
39 sub elementbase($)
40 {
41     my($e) = shift;
42
43     if (my $base = has_property($e, "display")) {
44         return "BASE_" . uc($base);
45     }
46  
47     return "BASE_DEC", if $e->{TYPE} eq "ENUM";
48     return "BASE_DEC", if $e->{TYPE} =~ /u?int(8|16|32|64)/;
49     return "BASE_DEC", if $e->{TYPE} eq "NTTIME" or $e->{TYPE} eq "HYPER_T";
50
51     # Probably an enum
52
53     return "BASE_DEC";
54 }
55
56 # Convert a IDL structure field name (e.g access_mask) to a prettier
57 # string like 'Access Mask'.
58
59 sub field2name($)
60 {
61     my($field) = shift;
62
63     $field =~ s/_/ /g;          # Replace underscores with spaces
64     $field =~ s/(\w+)/\u\L$1/g; # Capitalise each word
65     
66     return $field;
67 }
68
69 sub bitmapbase($)
70 {
71     my $e = shift;
72
73     return "16", if has_property($e->{DATA}, "bitmap16bit");
74     return "8", if has_property($e->{DATA}, "bitmap8bit");
75
76     return "32";
77 }
78
79 my %res = ();
80 my $tabs = "";
81 sub pidl_code($)
82 {
83         my $d = shift;
84         if ($d) {
85                 $res{code} .= $tabs;
86                 $res{code} .= $d;
87         }
88         $res{code} .="\n";
89 }
90
91 sub pidl_hdr($) { my $x = shift; $res{hdr} .= "$x\n"; }
92 sub pidl_def($) { my $x = shift; $res{def} .= "$x\n"; }
93
94 sub indent()
95 {
96         $tabs .= "\t";
97 }
98
99 sub deindent()
100 {
101         $tabs = substr($tabs, 0, -1);
102 }
103
104 #####################################################################
105 # parse the interface definitions
106 sub Interface($)
107 {
108         my($interface) = @_;
109         Typedef($_,$interface->{NAME}) foreach (@{$interface->{TYPEDEFS}});
110         Function($_,$interface->{NAME}) foreach (@{$interface->{FUNCTIONS}});
111 }
112
113 sub Enum($$$)
114 {
115         my ($e,$name,$ifname) = @_;
116         my $valsstring = "$ifname\_$name\_vals";
117         my $dissectorname = "$ifname\_dissect\_$name";
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         indent;
130         foreach (@{$e->{ELEMENTS}}) {
131                 next unless (/([^=]*)=(.*)/);
132                 pidl_code "{ $1, \"$2\" },";
133         }
134
135         pidl_def "{ 0, NULL }";
136         deindent;
137         pidl_def "};";
138
139         pidl_code "int";
140         pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int hf_index, guint32 param _U_)";
141         pidl_code "{";
142         indent;
143         pidl_code "offset=dissect_ndr_$e->{BASE_TYPE}(tvb, offset, pinfo, tree, drep, hf_index, NULL);";
144         pidl_code "return offset;";
145         pidl_code "}\n";
146
147         register_type($name, $dissectorname, enum_ft($e), "BASE_DEC", "0", "VALS($valsstring)", enum_size($e));
148 }
149
150 sub Bitmap($$$)
151 {
152         my ($e,$name,$ifname) = @_;
153         my $dissectorname = "$ifname\_dissect\_$name";
154
155         register_ett("ett_$ifname\_$name");
156
157         pidl_hdr "int $dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int hf_index, guint32 param);";
158
159         pidl_code "int";
160         pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_)";
161         pidl_code "{";
162         indent;
163         pidl_code "proto_item *item=NULL;";
164         pidl_code "proto_tree *tree=NULL;";
165         pidl_code "";
166
167         if ($e->{ALIGN} == 8) {
168                 pidl_code "guint8 flags;";
169         } elsif ($e->{ALIGN} == 4) {
170                 pidl_code "guint32 flags;";
171                 pidl_code "ALIGN_TO_4_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         foreach (@{$e->{ELEMENTS}}) {
186                 next unless (/([^=]*)=(.*)/);
187                 my ($en,$ev) = ($1,$2);
188                 my $hf_bitname = "hf_$ifname\_$name\_$en";
189                 my $filtername = "$ifname\.$name\.$en";
190                 
191                 register_hf_field($hf_bitname, $en, $filtername, "FT_BOOLEAN", $e->{ALIGN} * 8, "TFS(&$en\_tfs)", $ev, "");
192
193                 pidl_def "static const true_false_string $name\_tfs = {";
194                 pidl_def "   \"$name is SET\",";
195                 pidl_def "   \"$name is NOT SET\",";
196                 pidl_def "};";
197                 
198                 pidl_code "proto_tree_add_boolean(tree, $hf_bitname, tvb, offset-$e->{ALIGN}, $e->{ALIGN}, flags);";
199                 pidl_code "if (flags&$ev){";
200                 pidl_code "\tproto_item_append_text(item,\"$en\");";
201                 pidl_code "}\n";
202                 pidl_code "flags&=(~$ev);";
203         }
204
205         pidl_code "if(flags){";
206         pidl_code "proto_item_append_text(item, \"UNKNOWN-FLAGS\");";
207         pidl_code "}\n";
208         deindent;
209         pidl_code "return offset;";
210         pidl_code "}\n";
211         register_new_type($name, $dissectorname, bitmap_ft($e), "BASE_HEX", "0", "NULL", $e->{ALIGN});
212 }
213
214 sub FindType($) 
215 {
216         my $foo = shift;
217 #FIXME
218         return {
219                 FT_TYPE => "FIXME",
220                 BASE_TYPE => "FIXME",
221                 VALS => "VALS",
222                 MASK => 0,
223                 DISSECTOR => "FOOBNA"
224         };
225 }
226
227 sub Element($$$)
228 {
229         my ($e,$pn,$ifname) = @_;
230
231         my $hf_index = "hf_$ifname\_$pn\_$e->{NAME}";
232         my $dissectorname = "$ifname\_dissect\_$ifname\_$pn\_$e->{NAME}";
233
234         return if (EmitProhibited($dissectorname));
235
236         my $type = FindType($e->{DATA_TYPE});
237
238         my $hf = register_hf_field($hf_index, $e->{NAME}, "$ifname.$pn.$e->{NAME}", $type->{FT_TYPE}, $type->{BASE_TYPE}, $type->{VALS}, $type->{MASK}, "");
239         
240         pidl_code "static int";
241         pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)";
242         pidl_code "{";
243         indent;
244         pidl_code "guint32 param="  . FindDissectorParam($dissectorname).";";
245         pidl_code "offset=$type->{DISSECTOR}(tvb, offset, pinfo, tree, drep, $hf, param);";
246         pidl_code "return offset;";
247         deindent;
248         pidl_code "}\n";
249 }
250
251 sub Function($$$)
252 {
253         my ($fn,$ifname) = @_;
254         
255         pidl_code "static int";
256         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_)";
257         pidl_code "{";
258         indent;
259         foreach (@{$fn->{ELEMENTS}}) {
260                 Element($_, $fn->{NAME}, $ifname) if (grep(/in/,@{$_->{DIRECTION}}));
261         }
262         pidl_code "return offset;";
263         deindent;
264         pidl_code "}\n";
265
266         pidl_code "static int";
267         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_)";
268         pidl_code "{";
269         indent;
270         foreach (@{$fn->{ELEMENTS}}) {
271                 Element($_, $fn->{NAME}, $ifname) if (grep(/out/,@{$_->{DIRECTION}}));
272         }
273         pidl_code "return offset;";
274         deindent;
275         pidl_code "}\n";
276 }
277
278 sub Struct($$$)
279 {
280         my ($e,$name,$ifname) = @_;
281         my $dissectorname = "$ifname\_dissect\_$name";
282
283         return if (EmitProhibited($dissectorname));
284
285         register_ett("ett_$ifname\_$name");
286
287         pidl_hdr "int $dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_);";
288
289         pidl_code "int";
290         pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_)";
291         pidl_code "{";
292         indent;
293         pidl_code "proto_item *item = NULL;";
294         pidl_code "proto_tree *tree = NULL;";
295         pidl_code "int old_offset;";
296         pidl_code "";
297
298         pidl_code "ALIGN_TO_$e->{ALIGN}_BYTES;";
299         pidl_code "";
300
301         pidl_code "old_offset=offset;";
302         pidl_code "";
303         pidl_code "if(parent_tree){";
304         indent;
305         pidl_code "item=proto_tree_add_item(parent_tree, hf_index, tvb, offset, -1, TRUE);";
306         pidl_code "tree=proto_item_add_subtree(item, ett_$ifname\_$name);";
307         deindent;
308         pidl_code "}";
309
310         pidl_code "";
311
312         Element($_, $name, $ifname) foreach (@{$e->{ELEMENTS}});
313
314         pidl_code "";
315         pidl_code "proto_item_set_len(item, offset-old_offset);";
316         pidl_code "return offset;";
317         deindent;
318         pidl_code "}\n";
319 }
320
321 sub Union($$$)
322 {
323         my ($e,$name,$ifname) = @_;
324
325         my $dissectorname = "$ifname\_dissect_union_$name";
326         
327         register_ett("ett_$ifname\_$name");
328
329         pidl_code "static int";
330         pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_)";
331         pidl_code "{";
332         indent;
333         pidl_code "proto_item *item=NULL;";
334         pidl_code "proto_tree *tree=NULL;";
335         pidl_code "int old_offset;";
336         pidl_code "g$e->{SWITCH_TYPE} level;";
337         pidl_code "";
338
339         if ($e->{ALIGN} == 2) {
340                 pidl_code "ALIGN_TO_2_BYTES;";
341         } elsif ($e->{ALIGN} == 4) {
342                 pidl_code "ALIGN_TO_4_BYTES;";
343         }
344
345
346         pidl_code "";
347
348         pidl_code "old_offset=offset;";
349         pidl_code "if(parent_tree){";
350         indent;
351         pidl_code "item=proto_tree_add_text(parent_tree,tvb,offset,-1,\"$name\");";
352         pidl_code "tree=proto_item_add_subtree(item,ett_$ifname\_$name);";
353         pidl_code "}";
354
355         pidl_code "";
356
357         pidl_code "offset = dissect_ndr_$e->{SWITCH_TYPE}(tvb, offset, pinfo, tree, drep, hf_index, &level);";
358
359         pidl_code "switch(level) {";
360         foreach (@{$e->{ELEMENTS}}) {
361                 pidl_code "$_->{CASE}:";
362                 indent;
363                 Element($_, $name, $ifname);
364                 deindent;
365                 pidl_code "break;";
366         }
367
368         pidl_code "proto_item_set_len(item, offset-old_offset);";
369         pidl_code "return offset;";
370         deindent;
371         pidl_code "}";
372
373 }
374
375 sub Typedef($$)
376 {
377         my ($e,$ifname) = @_;
378
379         {
380                 ENUM => \&Enum,
381                 STRUCT => \&Struct,
382                 UNION => \&Union,
383                 BITMAP => \&Bitmap
384         }->{$e->{DATA}->{TYPE}}->($e->{DATA}, $e->{NAME}, $ifname);
385 }
386
387 sub RegisterInterface($)
388 {
389         my ($x) = @_;
390
391         pidl_code "void proto_register_dcerpc_$x->{NAME}(void)";
392         pidl_code "{";
393         indent;
394
395         $res{code}.=DumpHfList()."\n";
396         $res{code}.="\n".DumpEttList()."\n";
397         
398         if (defined($x->{UUID})) {
399             # These can be changed to non-pidl_code names if the old dissectors
400             # in epan/dissctors are deleted.
401     
402             my $name = "\"" . uc($x->{NAME}) . " (pidl)\"";
403                 if (has_property($x, "helpstring")) {
404                         $name = $x->{PROPERTIES}->{helpstring};
405                 }
406             my $short_name = "idl_$x->{NAME}";
407             my $filter_name = "idl_$x->{NAME}";
408     
409             pidl_code "proto_dcerpc_$x->{NAME} = proto_register_protocol($name, \"$short_name\", \"$filter_name\");";
410             
411             pidl_code "proto_register_field_array(proto_dcerpc_$x->{NAME}, hf, array_length (hf));";
412             pidl_code "proto_register_subtree_array(ett, array_length(ett));";
413         } else {
414             pidl_code "proto_dcerpc = proto_get_id_by_filter_name(\"dcerpc\");";
415             pidl_code "proto_register_field_array(proto_dcerpc, hf, array_length(hf));";
416             pidl_code "proto_register_subtree_array(ett, array_length(ett));";
417         }
418             
419         deindent;
420         pidl_code "}\n";
421 }
422
423 sub RegisterInterfaceHandoff($)
424 {
425         my $x = shift;
426         pidl_code "void proto_reg_handoff_dcerpc_$x->{NAME}(void)";
427         pidl_code "{";
428         indent;
429         pidl_code "dcerpc_init_uuid(proto_dcerpc_$x->{NAME}, ett_dcerpc_$x->{NAME},";
430         pidl_code "\t&uuid_dcerpc_$x->{NAME}, ver_dcerpc_$x->{NAME},";
431         pidl_code "\t$x->{NAME}_dissectors, hf_$x->{NAME}_opnum);";
432         deindent;
433         pidl_code "}";
434 }
435
436 sub ProcessInterface($)
437 {
438         my $x = shift;
439
440         if (defined($x->{UUID})) {
441                 my $if_uuid = $x->{UUID};
442
443             pidl_def "/* Version information */\n\n";
444             
445             pidl_def "static e_uuid_t uuid_dcerpc_$x->{NAME} = {";
446             pidl_def "\t0x" . substr($if_uuid, 1, 8) 
447                 . ", 0x" . substr($if_uuid, 10, 4)
448             . ", 0x" . substr($if_uuid, 15, 4) . ",";
449             pidl_def "\t{ 0x" . substr($if_uuid, 20, 2) 
450                 . ", 0x" . substr($if_uuid, 22, 2)
451             . ", 0x" . substr($if_uuid, 25, 2)
452             . ", 0x" . substr($if_uuid, 27, 2)
453             . ", 0x" . substr($if_uuid, 29, 2)
454             . ", 0x" . substr($if_uuid, 31, 2)
455             . ", 0x" . substr($if_uuid, 33, 2)
456             . ", 0x" . substr($if_uuid, 35, 2) . " }";
457             pidl_def "};";
458         
459             pidl_def "static guint16 ver_dcerpc_$x->{NAME} = $x->{VERSION};";
460             pidl_def "";
461         }
462
463         Interface($x);
464
465         $res{functiontable} = DumpFunctionTable($x);
466
467         RegisterInterface($x);
468         RegisterInterfaceHandoff($x);
469 }
470
471 #####################################################################
472 # Generate ethereal parser and header code
473 sub Parse($$$)
474 {
475         my($ndr,$module,$filename) = @_;
476
477         $tabs = "";
478         my $h_filename = $filename;
479
480         if ($h_filename =~ /(.*)\.c/) {
481                 $h_filename = "$1.h";
482         }
483
484         %res = (code=>"",def=>"",hdr=>"");
485
486         pidl_hdr "/* header auto-generated by pidl */";
487
488         $res{headers} = "";
489         $res{headers} .= "#ifdef HAVE_CONFIG_H\n";
490         $res{headers} .= "#include \"config.h\"\n";
491         $res{headers} .= "#endif\n\n";
492         $res{headers} .= "#include <glib.h>\n";
493         $res{headers} .= "#include <string.h>\n";
494         $res{headers} .= "#include <epan/packet.h>\n\n";
495
496         $res{headers} .= "#include \"packet-dcerpc.h\"\n";
497         $res{headers} .= "#include \"packet-dcerpc-nt.h\"\n";
498         $res{headers} .= "#include \"packet-windows-common.h\"\n";
499         $res{headers} .= "#include \"$h_filename\"\n";
500         pidl_code "";
501
502         # Ethereal protocol registration
503
504         ProcessInterface($_) foreach (@$ndr);
505
506         $res{ett} = DumpEttDeclaration();
507         $res{hf} = DumpHfDeclaration();
508
509         my $parser = "/* parser auto-generated by pidl */";
510         $parser.= $res{headers};
511         $parser.=$res{ett};
512         $parser.=$res{hf};
513         $parser.=$res{def};
514         $parser.=$res{code};
515
516         my $define = "__PACKET_DCERPC_" . uc($_->{NAME}) . "_H";
517         my $header = "#ifndef $define\n#define $define\n\n".$res{hdr} . "\n#endif /* $define */\n";
518     
519         return ($parser,$header);
520 }
521
522 ###############################################################################
523 # ETT
524 ###############################################################################
525
526 my @ett = ();
527
528 sub register_ett($)
529 {
530         my $name = shift;
531
532         push (@ett, $name);     
533 }
534
535 sub DumpEttList()
536 {
537         my $res = "\tstatic gint *ett[] = {\n";
538         foreach (@ett) {
539                 $res .= "\t\t&$_,\n";
540         }
541
542         return "$res\t};\n";
543 }
544
545 sub DumpEttDeclaration()
546 {
547         my $res = "\n/* Ett declarations */\n";
548         foreach (@ett) {
549                 $res .= "static gint $_ = -1;\n";
550         }
551
552         return "$res\n";
553 }
554
555 ###############################################################################
556 # HF
557 ###############################################################################
558
559 my %hf = ();
560
561 sub register_hf_field($$$$$$$$) 
562 {
563         my ($index,$name,$filter_name,$ft_type,$base_type,$valsstring,$mask,$fixme) = @_;
564
565         $hf{$index} = {
566                 INDEX => $index,
567                 NAME => $name,
568                 FILTER => $filter_name,
569                 FT_TYPE => $ft_type,
570                 BASE_TYPE => $base_type,
571                 VALS => $valsstring,
572                 MASK => $mask
573         };
574 }
575
576 sub DumpHfDeclaration()
577 {
578         my $res = "";
579
580         $res = "\n/* Header field declarations */\n";
581
582         foreach (keys %hf) 
583         {
584                 $res .= "static gint $_ = -1;\n";
585         }
586
587         return "$res\n";
588 }
589
590 sub DumpHfList()
591 {
592         my $res = "\tstatic hf_register_info hf[] = {\n";
593
594         foreach (values %hf) 
595         {
596                 $res .= "\t{ &$_->{INDEX}, 
597           { \"$_->{NAME}\", \"$_->{FILTER}\", $_->{FT_TYPE}, $_->{BASE_TYPE}, $_->{VALS}, $_->{MASK}, FIXME, HFILL }},
598 ";
599         }
600
601         return $res."\t};\n";
602 }
603
604
605 ###############################################################################
606 # Function table
607 ###############################################################################
608
609 sub DumpFunctionTable($)
610 {
611         my $if = shift;
612
613         my $res = "static dcerpc_sub_dissector $if->{NAME}\_dissectors[] = {\n";
614         
615         foreach (@{$if->{FUNCTIONS}}) {
616                 $res.= "\t{ $_->{OPNUM}, \"$_->{NAME},\n";
617                 $res.= "\t   $if->{NAME}_dissect_$_->{NAME}_request, $if->{NAME}_dissect_$_->{NAME}_response},\n";
618         }
619
620         $res .= "\t{ 0, NULL, NULL, NULL },\n";
621
622         return "$res\t}\n";
623 }
624
625
626 1;