packet-dcerpc: nca_s_fault_sec_pkg_error
[metze/wireshark/wip.git] / tools / convert_expert_add_info_format.pl
1 #!/usr/bin/env perl
2 #
3 # Copyright 2013 Michael Mann (see AUTHORS file)
4 #
5 # A program to help convert the "old" expert_add_info_format API calls into filterable "items" that
6 # use the other expert API calls.  The program requires 2 passes.  "Pass 1" (generate) collects 
7 # the eligible expert_add_info_format calls and outputs the necessary data into a delimited
8 # file.  "Pass 2" (fix-all) takes the data from the delimited file and replaces the
9 # expert_add_info_format calls with filterable "expert info" calls as well as 
10 # generating a separate files for the  ei variable declarations and array data.
11 # The ei "file" can be copy/pasted into the dissector where appropriate
12 #
13 # Note that the output from "Pass 1" won't always be a perfect conversion for "Pass 2", so
14 # "human interaction" is needed as an intermediary to verify and update the delimited file
15 # before "Pass 2" is done.
16 #
17 # Delimited file field format:
18 # <convert expert_add_info_format_call[1-4]><add ei variable[0|1]><ei var><[GROUP]><[SEVERITY]><[FIELDNAME]><[EXPERTABBREV]>
19 # <pinfo var><proto_item var><tvb var><offset><length><params>
20 #
21 # convert proto_tree_add_text_call enumerations:
22 # 1  - expert_add_info
23 # 2  - expert_add_info_format
24 # 3  - proto_tree_add_expert
25 # 4  - proto_tree_add_expert_format
26 #
27 # Usage: convert_expert_add_info_format.pl action=<generate|fix-all> <file or files>
28 #
29 # Based off of convert_proto_tree_add_text.pl
30 #
31 # Wireshark - Network traffic analyzer
32 # By Gerald Combs <gerald@wireshark.org>
33 # Copyright 1998 Gerald Combs
34 #
35 # This program is free software; you can redistribute it and/or
36 # modify it under the terms of the GNU General Public License
37 # as published by the Free Software Foundation; either version 2
38 # of the License, or (at your option) any later version.
39 #
40 # This program is distributed in the hope that it will be useful,
41 # but WITHOUT ANY WARRANTY; without even the implied warranty of
42 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
43 # GNU General Public License for more details.
44 #
45 # You should have received a copy of the GNU General Public License
46 # along with this program; if not, write to the Free Software
47 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
48 #
49
50 use strict;
51 use warnings;
52
53 use Getopt::Long;
54
55 my %EXPERT_SEVERITY = ('PI_COMMENT' => "PI_COMMENT",
56                                            'PI_CHAT' => "PI_CHAT",
57                                            'PI_NOTE' => "PI_NOTE",
58                                            'PI_WARN' => "PI_WARN",
59                                            'PI_ERROR' => "PI_ERROR");
60
61 my %EXPERT_GROUPS = ('PI_CHECKSUM' => "PI_CHECKSUM",
62                                            'PI_SEQUENCE' => "PI_SEQUENCE",
63                                            'PI_RESPONSE_CODE' => "PI_RESPONSE_CODE",
64                                            'PI_REQUEST_CODE' => "PI_REQUEST_CODE",
65                                            'PI_UNDECODED' => "PI_UNDECODED",
66                                            'PI_REASSEMBLE' => "PI_REASSEMBLE",
67                                            'PI_MALFORMED' => "PI_MALFORMED",
68                                            'PI_DEBUG' => "PI_DEBUG",
69                                            'PI_PROTOCOL' => "PI_PROTOCOL",
70                                            'PI_SECURITY' => "PI_SECURITY",
71                                            'PI_COMMENTS_GROUP' => "PI_COMMENTS_GROUP");
72
73 my @expert_list;
74 my $protabbrev = "";
75
76 # Perl trim function to remove whitespace from the start and end of the string
77 sub trim($)
78 {
79         my $string = shift;
80         $string =~ s/^\s+//;
81         $string =~ s/\s+$//;
82         return $string;
83 }
84
85 # ---------------------------------------------------------------------
86 #
87 # MAIN
88 #
89 my $helpFlag  = '';
90 my $action    = 'generate';
91 my $register  = '';
92
93 my $result = GetOptions(
94                                                 'action=s' => \$action,
95                                                 'register' => \$register,
96                                                 'help|?'   => \$helpFlag
97                                                 );
98
99 if (!$result || $helpFlag || !$ARGV[0]) {
100         usage();
101 }
102
103 sub usage {
104         print "\nUsage: $0 [--action=generate|fix-all|find-all] FILENAME [...]\n\n";
105                 print "  --action = generate (default)\n";
106                 print "    generate - create a delimited file (FILENAME.expert_add_info_input) with\n";
107                 print "               expert_add_info_format fields in FILENAME(s)\n";
108                 print "    fix-all  - Use delimited file (FILENAME.expert_add_info_input) to convert\n";
109                 print "               expert_add_info_format to \"filterable\" expert API\n";
110                 print "               Also generates FILENAME.ei to be copy/pasted into\n";
111                 print "               the dissector where appropriate\n\n";
112                 print "  --register = generate ei_register_info and expert register function calls\n\n";
113
114         exit(1);
115 }
116
117 #
118 # XXX Outline general algorithm here
119 #
120 my $found_total = 0;
121 my $protabbrev_index;
122 my $line_number = 0;
123
124 while (my $fileName = $ARGV[0]) {
125         shift;
126         my $fileContents = '';
127
128         die "No such file: \"$fileName\"\n" if (! -e $fileName);
129
130         # delete leading './'
131         $fileName =~ s{ ^ \. / } {}xo;
132
133         #determine PROTABBREV for dissector based on file name format of (dirs)/packet-PROTABBREV.c
134         $protabbrev_index = rindex($fileName, "packet-");
135         if ($protabbrev_index == -1) {
136                 print "$fileName doesn't fit format of packet-PROTABBREV.c\n";
137                 next;
138         }
139
140         $protabbrev = substr($fileName, $protabbrev_index+length("packet-"));
141         $protabbrev_index = rindex($protabbrev, ".");
142         if ($protabbrev_index == -1) {
143                 print "$fileName doesn't fit format of packet-PROTABBREV.c\n";
144                 next;
145         }
146         $protabbrev = lc(substr($protabbrev, 0, $protabbrev_index));
147
148         # Read in the file (ouch, but it's easier that way)
149         open(FCI, "<", $fileName) || die("Couldn't open $fileName");
150         while (<FCI>) {
151                 $fileContents .= $_;
152         }
153         close(FCI);
154
155         if ($action eq "generate") {
156                 generate_eis(\$fileContents, $fileName);
157         }
158
159         if ($action eq "fix-all") {
160                 # Read in the ei "input" file
161                 $line_number = 0;
162                 my $errors = 0;
163                 open(FCI, "<", $fileName . ".expert_add_info_input") || die("Couldn't open $fileName.expert_add_info_input");
164                 while(my $line=<FCI>){
165                         my @expert_item = split(/;|\n/, $line);
166
167                         $line_number++;
168                         $errors += verify_line(@expert_item);
169
170                         push(@expert_list, \@expert_item);
171                 }
172                 close(FCI);
173
174                 if ($errors > 0) {
175                         print "Aborting conversion.\n";
176                         exit(-1);
177                 }
178
179                 fix_expert_add_info_format(\$fileContents, $fileName);
180
181                 # Write out the ei data
182                 output_ei_data($fileName);
183
184                 # Write out the changed version to a file
185                 open(FCO, ">", $fileName . ".expert_add_info_format");
186                 print FCO "$fileContents";
187                 close(FCO);
188         }
189
190 } # while
191
192 exit $found_total;
193
194 # ---------------------------------------------------------------------
195 # Sanity check the data in the .proto_tree_input file
196 sub verify_line {
197         my( @expert_item) = @_;
198         my $errors = 0;
199
200         #do some basic error checking of the file
201         if (($expert_item[0] eq "1") ||
202                 ($expert_item[0] eq "2") ||
203                 ($expert_item[0] eq "3") ||
204                 ($expert_item[0] eq "4")) {
205                 #expert info conversions
206                 if (!($expert_item[2] =~ /^ei_/)) {
207                         print "$line_number: Poorly formed ei_ variable ($expert_item[2])!\n";
208                         $errors++;
209                 }
210         } else {
211                 print "$line_number: Bad conversion value!\n";
212                 $errors++;
213         }
214
215         if ($expert_item[1] eq "1") {
216                 if (!($expert_item[2] =~ /^ei_/)) {
217                         print "$line_number: Poorly formed ei_ variable ($expert_item[2])!\n";
218                         $errors++;
219                 }
220                 if (!exists($EXPERT_SEVERITY{$expert_item[4]})) {
221                         print "$line_number: Expert severity value '$expert_item[5]' unknown!\n";
222                         $errors++;
223                 }
224                 if (!exists($EXPERT_GROUPS{$expert_item[3]})) {
225                         print "$line_number: Expert group value '$expert_item[4]' unknown!\n";
226                         $errors++;
227                 }
228
229         } elsif ($expert_item[1] ne "0") {
230                         print "$line_number: Bad ei variable generation value!\n";
231                         $errors++;
232         }
233
234         return $errors;
235 }
236
237 sub generate_eis {
238         my( $fileContentsRef, $fileName) = @_;
239         my @args;
240         my $num_items = 0;
241         my @temp;
242         my $str_temp;
243         my $pat;
244
245         $pat = qr /
246                                 (
247                                         (?:expert_add_info_format)\s* \(
248                                         (([^[\,;])*\,){4,}
249                                         [^;]*
250                                         \s* \) \s* ;
251                                 )
252                         /xs;
253
254         while ($$fileContentsRef =~ / $pat /xgso) {
255
256                 my @expert_item = (1, 1, "ei_name", "GROUP", "SEVERITY", "fieldfullname", "fieldabbrevname", 
257                                                          "pinfo", "item", "tvb", "offset", "length", "params");
258                 my $arg_loop = 5;
259                 my $str = "${1}\n";
260                 $str =~ tr/\t\n\r/ /d;
261                 $str =~ s/ \s+ / /xg;
262                 #print "$fileName: $str\n";
263
264                 @args = split(/,/, $str);
265                 #printf "ARGS(%d): %s\n", scalar @args, join("# ", @args);
266                 $args[0] =~ s/expert_add_info_format\s*\(\s*//;
267
268                 $expert_item[7] = $args[0];                     #pinfo
269                 $expert_item[8] = trim($args[1]);       #item
270                 $expert_item[3] = trim($args[2]);       #GROUP
271                 $expert_item[4] = trim($args[3]);       #SEVERITY
272                 $expert_item[5] = trim($args[4]);       #fieldfullname
273                 $expert_item[5] =~ s/\"//;
274
275                 #XXX - conditional?
276                 $expert_item[5] =~ s/\"\s*\)\s*;$//;
277                 $expert_item[5] =~ s/\"$//;
278
279                 #params
280                 $expert_item[12] = "";
281                 while ($arg_loop < scalar @args) {
282                         $expert_item[12] .= trim($args[$arg_loop]);
283                         if ($arg_loop+1 < scalar @args) {
284                                 $expert_item[12] .= ", ";
285                         }
286                         $arg_loop += 1;
287                 }
288                 $expert_item[12] =~ s/\s*\)\s*;$//;
289
290                 #ei variable name
291                 $expert_item[2] = sprintf("ei_%s_%s", $protabbrev, lc($expert_item[5]));
292                 $expert_item[2] =~ s/\s+|-|:/_/g;
293
294                 #field abbreviated name
295                 $expert_item[6] = sprintf("%s.%s", $protabbrev, lc($expert_item[5]));
296                 $expert_item[6] =~ s/\s+|-|:/_/g;
297
298                 push(@expert_list, \@expert_item);
299
300                 $num_items += 1;
301         }
302
303         if ($num_items > 0) {
304                 open(FCO, ">", $fileName . ".expert_add_info_input");
305                 for my $item (@expert_list) {
306                         print FCO join(";", @{$item}), "\n";
307                 }
308                 close(FCO);
309         }
310 }
311
312 # ---------------------------------------------------------------------
313 # Find all expert_add_info_format calls and replace them with the data
314 # found in expert_list
315 sub fix_expert_add_info_format {
316         my( $fileContentsRef, $fileName) = @_;
317         my $found = 0;
318         my $pat;
319
320         $pat = qr /
321                                 (
322                                         (?:expert_add_info_format)\s* \(
323                                         (([^[\,;])*\,){4,}
324                                         [^;]*
325                                         \s* \) \s* ;
326                                 )
327                         /xs;
328
329         $$fileContentsRef =~ s/ $pat /patsub($found, $1)/xges;
330 }
331
332 # ---------------------------------------------------------------------
333 # Format expert info functions with expert_list data
334 sub patsub {
335         my $item_str;
336
337         #print $expert_list[$_[0]][2] . " = ";
338         #print $#{$expert_list[$_[0]]}+1;
339         #print "\n";
340
341         if ($expert_list[$_[0]][0] eq "1") {
342                 $item_str = sprintf("expert_add_info(%s, %s, &%s);",
343                                                  $expert_list[$_[0]][7], $expert_list[$_[0]][8], $expert_list[$_[0]][2]);
344         } elsif ($expert_list[$_[0]][0] eq "2") {
345                 $item_str = sprintf("expert_add_info_format(%s, %s, &%s, \"%s\"",
346                                                  $expert_list[$_[0]][7], $expert_list[$_[0]][8],
347                                                  $expert_list[$_[0]][2], $expert_list[$_[0]][5]);
348                 if (($#{$expert_list[$_[0]]}+1 > 12 ) && ($expert_list[$_[0]][12] ne "")) {
349                         $item_str .= ", $expert_list[$_[0]][12]";
350                 }
351                 $item_str .= ");";
352         } elsif ($expert_list[$_[0]][0] eq "3") {
353                 $item_str = sprintf("proto_tree_add_expert(%s, %s, &%s, %s, %s, %s);",
354                                                  $expert_list[$_[0]][8], $expert_list[$_[0]][7],
355                                                  $expert_list[$_[0]][2], $expert_list[$_[0]][9],
356                                                  $expert_list[$_[0]][10], $expert_list[$_[0]][11]);
357         } elsif ($expert_list[$_[0]][0] eq "4") {
358                 $item_str = sprintf("proto_tree_add_expert_format(%s, %s, &%s, %s, %s, %s, \"%s\"",
359                                                  $expert_list[$_[0]][8], $expert_list[$_[0]][7], $expert_list[$_[0]][2],
360                                                  $expert_list[$_[0]][9], $expert_list[$_[0]][10],
361                                                  $expert_list[$_[0]][11], $expert_list[$_[0]][5]);
362                 if (($#{$expert_list[$_[0]]}+1 > 12) && ($expert_list[$_[0]][12] ne "")) {
363                         $item_str .= ", $expert_list[$_[0]][12]";
364                 }
365                 $item_str .= ");";
366         }
367
368         $_[0] += 1;
369
370         return $item_str;
371 }
372
373 # ---------------------------------------------------------------------
374 # Output the ei variable declarations and expert array.  For now, write them to a file.
375 # XXX - Eventually find the right place to add it to the modified dissector file
376 sub output_ei_data {
377         my( $fileName) = @_;
378         my %eis = ();
379         my $index;
380         my $key;
381
382         #add ei to hash table to prevent against (accidental) duplicates
383         for ($index=0;$index<@expert_list;$index++) {
384                 if ($expert_list[$index][1] eq "1") {
385                         $eis{$expert_list[$index][2]} = $expert_list[$index][2];
386                 }
387         }
388
389         open(FCO, ">", $fileName . ".ei");
390
391         print FCO "/* Generated from convert_expert_add_info_format.pl */\n";
392
393         foreach $key (keys %eis) {
394                 print FCO "static expert_field $key = EI_INIT;\n";
395         }
396         print FCO "\n\n";
397
398         if ($register ne "") {
399                 print FCO "  static ei_register_info ei[] = {\n";
400         }
401
402         %eis = ();
403         for ($index=0;$index<@expert_list;$index++) {
404                 if ($expert_list[$index][1] eq "1") {
405                         if (exists($eis{$expert_list[$index][2]})) {
406                                 print "duplicate ei entry '$expert_list[$index][2]' found!  Aborting conversion.\n";
407                                 exit(-1);
408                         }
409                         $eis{$expert_list[$index][2]} = $expert_list[$index][2];
410
411                         print FCO "      { &$expert_list[$index][2], { \"$expert_list[$index][6]\", $expert_list[$index][3], ";
412                         print FCO "$expert_list[$index][4], \"$expert_list[$index][5]\", EXPFILL }},\r\n";
413                 }
414         }
415
416         if ($register ne "") {
417                 print FCO "  };\n\n\n";
418                 print FCO "  expert_module_t* expert_$protabbrev;\n\n";
419                   
420                 print FCO "  expert_$protabbrev = expert_register_protocol(proto_$protabbrev);\n";
421                 print FCO "  expert_register_field_array(expert_$protabbrev, ei, array_length(ei));\n\n";
422         }
423
424
425         close(FCO);
426 }