1 ###################################################
2 # parse an Wireshark conformance file
3 # Copyright jelmer@samba.org 2005
4 # released under the GNU GPL
10 Parse::Pidl::Wireshark::Conformance - Conformance file parser for Wireshark
14 This module supports parsing Wireshark conformance files (*.cnf).
18 Pidl needs additional data for Wireshark output. This data is read from
19 so-called conformance files. This section describes the format of these
22 Conformance files are simple text files with a single command on each line.
23 Empty lines and lines starting with a '#' character are ignored.
24 Arguments to commands are separated by spaces.
26 The following commands are currently supported:
30 =item I<TYPE> name dissector ft_type base_type mask valsstring alignment
32 Register new data type with specified name, what dissector function to call
33 and what properties to give header fields for elements of this type.
37 Suppress emitting a dissect_type function for the specified type
39 =item I<PARAM_VALUE> type param
41 Set parameter to specify to dissector function for given type.
43 =item I<HF_FIELD> hf title filter ft_type base_type valsstring mask description
45 Generate a custom header field with specified properties.
47 =item I<HF_RENAME> old_hf_name new_hf_name
49 Force the use of new_hf_name when the parser generator was going to
52 This can be used in conjunction with HF_FIELD in order to make more than
53 one element use the same filter name.
55 =item I<ETT_FIELD> ett
57 Register a custom ett field
59 =item I<STRIP_PREFIX> prefix
61 Remove the specified prefix from all function names (if present).
63 =item I<PROTOCOL> longname shortname filtername
65 Change the short-, long- and filter-name for the current interface in
68 =item I<FIELD_DESCRIPTION> field desc
70 Change description for the specified header field. `field' is the hf name of the field.
72 =item I<IMPORT> dissector code...
74 Code to insert when generating the specified dissector. @HF@ and
75 @PARAM@ will be substituted.
77 =item I<INCLUDE> filename
79 Include conformance data from the specified filename in the dissector.
81 =item I<TFS> hf_name "true string" "false string"
83 Override the text shown when a bitmap boolean value is enabled or disabled.
85 =item I<MANUAL> fn_name
87 Force pidl to not generate a particular function but allow the user
88 to write a function manually. This can be used to remove the function
89 for only one level for a particular element rather than all the functions and
90 ett/hf variables for a particular element as the NOEMIT command does.
92 =item I<CODE START>/I<CODE END>
93 Begin and end a section of code to be put directly into the generated
94 source file for the dissector.
96 =item I<HEADER START>/I<HEADER END>
97 Begin and end a section of code to be put directly into the generated
98 header file for the dissector.
108 package Parse::Pidl::Wireshark::Conformance;
111 use vars qw($VERSION);
115 @EXPORT_OK = qw(ReadConformance ReadConformanceFH valid_ft_type valid_base_type);
120 use Parse::Pidl qw(fatal warning error);
121 use Parse::Pidl::Util qw(has_property);
122 use Parse::Pidl::Typelist qw(addType);
124 sub handle_type($$$$$$$$$$)
126 my ($pos,$data,$name,$dissectorname,$ft_type,$base_type,$mask,$valsstring,$alignment) = @_;
128 unless(defined($alignment)) {
129 error($pos, "incomplete TYPE command");
133 unless ($dissectorname =~ /.*dissect_.*/) {
134 warning($pos, "dissector name does not contain `dissect'");
137 unless(valid_ft_type($ft_type)) {
138 warning($pos, "invalid FT_TYPE `$ft_type'");
141 unless (valid_base_type($base_type)) {
142 warning($pos, "invalid BASE_TYPE `$base_type'");
145 $dissectorname =~ s/^\"(.*)\"$/$1/g;
147 if (not ($dissectorname =~ /;$/)) {
148 warning($pos, "missing semicolon");
151 $data->{types}->{$name} = {
155 DISSECTOR_NAME => $dissectorname,
157 BASE_TYPE => $base_type,
159 VALSSTRING => $valsstring,
160 ALIGNMENT => $alignment
165 TYPE => "CONFORMANCE",
166 BASEFILE => "conformance file",
169 TYPE => "CONFORMANCE",
175 sub handle_tfs($$$$$)
177 my ($pos,$data,$hf,$trues,$falses) = @_;
179 unless(defined($falses)) {
180 error($pos, "incomplete TFS command");
184 $data->{tfs}->{$hf} = {
185 TRUE_STRING => $trues,
186 FALSE_STRING => $falses
190 sub handle_hf_rename($$$$)
192 my ($pos,$data,$old,$new) = @_;
194 unless(defined($new)) {
195 warning($pos, "incomplete HF_RENAME command");
199 $data->{hf_renames}->{$old} = {
207 sub handle_param_value($$$$)
209 my ($pos,$data,$dissector_name,$value) = @_;
211 unless(defined($value)) {
212 error($pos, "incomplete PARAM_VALUE command");
216 $data->{dissectorparams}->{$dissector_name} = {
217 DISSECTOR => $dissector_name,
224 sub valid_base_type($)
227 return 0 unless($t =~ /^BASE_.*/);
234 return 0 unless($t =~ /^FT_.*/);
238 sub handle_hf_field($$$$$$$$$$)
240 my ($pos,$data,$index,$name,$filter,$ft_type,$base_type,$valsstring,$mask,$blurb) = @_;
242 unless(defined($blurb)) {
243 error($pos, "incomplete HF_FIELD command");
247 unless(valid_ft_type($ft_type)) {
248 warning($pos, "invalid FT_TYPE `$ft_type'");
251 unless(valid_base_type($base_type)) {
252 warning($pos, "invalid BASE_TYPE `$base_type'");
255 $data->{header_fields}->{$index} = {
262 BASE_TYPE => $base_type,
263 VALSSTRING => $valsstring,
269 sub handle_strip_prefix($$$)
271 my ($pos,$data,$x) = @_;
273 push (@{$data->{strip_prefixes}}, $x);
276 sub handle_noemit($$$)
278 my ($pos,$data,$type) = @_;
280 if (defined($type)) {
281 $data->{noemit}->{$type} = 1;
283 $data->{noemit_dissector} = 1;
287 sub handle_manual($$$)
289 my ($pos,$data,$fn) = @_;
291 unless(defined($fn)) {
292 warning($pos, "incomplete MANUAL command");
296 $data->{manual}->{$fn} = 1;
299 sub handle_protocol($$$$$$)
301 my ($pos, $data, $name, $longname, $shortname, $filtername) = @_;
303 $data->{protocols}->{$name} = {
304 LONGNAME => $longname,
305 SHORTNAME => $shortname,
306 FILTERNAME => $filtername
310 sub handle_fielddescription($$$$)
312 my ($pos,$data,$field,$desc) = @_;
314 unless(defined($desc)) {
315 warning($pos, "incomplete FIELD_DESCRIPTION command");
319 $data->{fielddescription}->{$field} = {
320 DESCRIPTION => $desc,
330 my $dissectorname = shift @_;
332 unless(defined($dissectorname)) {
333 error($pos, "no dissectorname specified");
337 $data->{imports}->{$dissectorname} = {
338 NAME => $dissectorname,
339 DATA => join(' ', @_),
351 unless(defined($ett)) {
352 error($pos, "incomplete ETT_FIELD command");
356 push (@{$data->{ett}}, $ett);
365 unless(defined($fn)) {
366 error($pos, "incomplete INCLUDE command");
370 ReadConformance($fn, $data);
373 my %field_handlers = (
374 TYPE => \&handle_type,
375 NOEMIT => \&handle_noemit,
376 MANUAL => \&handle_manual,
377 PARAM_VALUE => \&handle_param_value,
378 HF_FIELD => \&handle_hf_field,
379 HF_RENAME => \&handle_hf_rename,
380 ETT_FIELD => \&handle_ett_field,
382 STRIP_PREFIX => \&handle_strip_prefix,
383 PROTOCOL => \&handle_protocol,
384 FIELD_DESCRIPTION => \&handle_fielddescription,
385 IMPORT => \&handle_import,
386 INCLUDE => \&handle_include
389 sub ReadConformance($$)
394 open(IN,"<$f") or return undef;
396 $ret = ReadConformanceFH(*IN, $data, $f);
403 sub ReadConformanceFH($$$)
405 my ($fh,$data,$f) = @_;
408 my $inheaderblock = 0;
419 if ($_ eq "CODE START") {
421 warning({ FILE => $f, LINE => $ln },
422 "CODE START inside CODE section");
424 if ($inheaderblock) {
425 error({ FILE => $f, LINE => $ln },
426 "CODE START inside HEADER section");
431 } elsif ($_ eq "CODE END") {
433 warning({ FILE => $f, LINE => $ln },
434 "CODE END outside CODE section");
436 if ($inheaderblock) {
437 error({ FILE => $f, LINE => $ln },
438 "CODE END inside HEADER section");
443 } elsif ($incodeblock) {
444 if (exists $data->{override}) {
445 $data->{override}.="$_\n";
447 $data->{override} = "$_\n";
450 } elsif ($_ eq "HEADER START") {
451 if ($inheaderblock) {
452 warning({ FILE => $f, LINE => $ln },
453 "HEADER START inside HEADER section");
456 error({ FILE => $f, LINE => $ln },
457 "HEADER START inside CODE section");
462 } elsif ($_ eq "HEADER END") {
463 if (!$inheaderblock) {
464 warning({ FILE => $f, LINE => $ln },
465 "HEADER END outside HEADER section");
468 error({ FILE => $f, LINE => $ln },
469 "CODE END inside HEADER section");
474 } elsif ($inheaderblock) {
475 if (exists $data->{header}) {
476 $data->{header}.="$_\n";
478 $data->{header} = "$_\n";
483 my @fields = /([^ "]+|"[^"]+")/g;
485 my $cmd = $fields[0];
489 my $pos = { FILE => $f, LINE => $ln };
491 next unless(defined($cmd));
493 if (not defined($field_handlers{$cmd})) {
494 warning($pos, "Unknown command `$cmd'");
498 $field_handlers{$cmd}($pos, $data, @fields);
502 warning({ FILE => $f, LINE => $ln },
503 "Expecting CODE END");