nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | #!/usr/bin/perl |
2 | # |
||
3 | # Script to convert xcbproto and mesa protocol files for |
||
4 | # X11 dissector. Creates header files containing code to |
||
5 | # dissect X11 extensions. |
||
6 | # |
||
7 | # Instructions for using this script are in epan/dissectors/README.X11 |
||
8 | # |
||
9 | # Copyright 2008, 2009, 2013, 2014 Open Text Corporation <pharris[AT]opentext.com> |
||
10 | # |
||
11 | # Wireshark - Network traffic analyzer |
||
12 | # By Gerald Combs <gerald@wireshark.org> |
||
13 | # Copyright 1998 Gerald Combs |
||
14 | # |
||
15 | # This program is free software; you can redistribute it and/or |
||
16 | # modify it under the terms of the GNU General Public License |
||
17 | # as published by the Free Software Foundation; either version 2 |
||
18 | # of the License, or (at your option) any later version. |
||
19 | # |
||
20 | # This program is distributed in the hope that it will be useful, |
||
21 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
22 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
23 | # GNU General Public License for more details. |
||
24 | # |
||
25 | # You should have received a copy of the GNU General Public License |
||
26 | # along with this program; if not, write to the Free Software |
||
27 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||
28 | # |
||
29 | |||
30 | #TODO |
||
31 | # - support constructs that are legal in XCB, but don't appear to be used |
||
32 | |||
33 | use 5.010; |
||
34 | |||
35 | use warnings; |
||
36 | use strict; |
||
37 | |||
38 | # given/when is going to be removed (and/or dramatically altered) |
||
39 | # in 5.20. Patches welcome. |
||
40 | # Patches even more welcome if they rewrite this whole thing in a |
||
41 | # language with a proper compatibility document, such as |
||
42 | # http://golang.org/doc/go1compat |
||
43 | no if $] >= 5.018, warnings => "experimental::smartmatch"; |
||
44 | |||
45 | use IO::File; |
||
46 | use XML::Twig; |
||
47 | |||
48 | use File::Spec; |
||
49 | |||
50 | my $srcdir = shift; |
||
51 | die "'$srcdir' is not a directory" unless -d $srcdir; |
||
52 | |||
53 | my @reslist = grep {!/xproto\.xml$/} glob File::Spec->catfile($srcdir, 'xcbproto', 'src', '*.xml'); |
||
54 | my @register; |
||
55 | |||
56 | my $script_name = File::Spec->abs2rel ($0, $srcdir); |
||
57 | |||
58 | my %basictype = ( |
||
59 | char => { size => 1, encoding => 'ENC_ASCII|ENC_NA', type => 'FT_STRING', base => 'BASE_NONE', get => 'VALUE8', list => 'listOfByte', }, |
||
60 | void => { size => 1, encoding => 'ENC_NA', type => 'FT_BYTES', base => 'BASE_NONE', get => 'VALUE8', list => 'listOfByte', }, |
||
61 | BYTE => { size => 1, encoding => 'ENC_NA', type => 'FT_BYTES', base => 'BASE_NONE', get => 'VALUE8', list => 'listOfByte', }, |
||
62 | CARD8 => { size => 1, encoding => 'byte_order', type => 'FT_UINT8', base => 'BASE_HEX_DEC', get => 'VALUE8', list => 'listOfByte', }, |
||
63 | CARD16 => { size => 2, encoding => 'byte_order', type => 'FT_UINT16', base => 'BASE_HEX_DEC', get => 'VALUE16', list => 'listOfCard16', }, |
||
64 | CARD32 => { size => 4, encoding => 'byte_order', type => 'FT_UINT32', base => 'BASE_HEX_DEC', get => 'VALUE32', list => 'listOfCard32', }, |
||
65 | CARD64 => { size => 8, encoding => 'byte_order', type => 'FT_UINT64', base => 'BASE_HEX_DEC', get => 'VALUE64', list => 'listOfCard64', }, |
||
66 | INT8 => { size => 1, encoding => 'byte_order', type => 'FT_INT8', base => 'BASE_DEC', get => 'VALUE8', list => 'listOfByte', }, |
||
67 | INT16 => { size => 2, encoding => 'byte_order', type => 'FT_INT16', base => 'BASE_DEC', get => 'VALUE16', list => 'listOfInt16', }, |
||
68 | INT32 => { size => 4, encoding => 'byte_order', type => 'FT_INT32', base => 'BASE_DEC', get => 'VALUE32', list => 'listOfInt32', }, |
||
69 | INT64 => { size => 8, encoding => 'byte_order', type => 'FT_INT64', base => 'BASE_DEC', get => 'VALUE64', list => 'listOfInt64', }, |
||
70 | float => { size => 4, encoding => 'byte_order', type => 'FT_FLOAT', base => 'BASE_NONE', get => 'FLOAT', list => 'listOfFloat', }, |
||
71 | double => { size => 8, encoding => 'byte_order', type => 'FT_DOUBLE', base => 'BASE_NONE', get => 'DOUBLE', list => 'listOfDouble', }, |
||
72 | BOOL => { size => 1, encoding => 'byte_order', type => 'FT_BOOLEAN',base => 'BASE_NONE', get => 'VALUE8', list => 'listOfByte', }, |
||
73 | ); |
||
74 | |||
75 | my %simpletype; # Reset at the beginning of each extension |
||
76 | my %gltype; # No need to reset, since it's only used once |
||
77 | |||
78 | my %struct = # Not reset; contains structures already defined. |
||
79 | # Also contains this black-list of structures never used by any |
||
80 | # extension (to avoid generating useless code). |
||
81 | ( |
||
82 | # structures defined by xproto, but not used by any extension |
||
83 | 'xproto:CHAR2B' => 1, |
||
84 | 'xproto:ARC' => 1, |
||
85 | 'xproto:FORMAT' => 1, |
||
86 | 'xproto:VISUALTYPE' => 1, |
||
87 | 'xproto:DEPTH' => 1, |
||
88 | 'xproto:SCREEN' => 1, |
||
89 | 'xproto:SetupRequest' => 1, |
||
90 | 'xproto:SetupFailed' => 1, |
||
91 | 'xproto:SetupAuthenticate' => 1, |
||
92 | 'xproto:Setup' => 1, |
||
93 | 'xproto:TIMECOORD' => 1, |
||
94 | 'xproto:FONTPROP' => 1, |
||
95 | 'xproto:CHARINFO' => 1, |
||
96 | 'xproto:SEGMENT' => 1, |
||
97 | 'xproto:COLORITEM' => 1, |
||
98 | 'xproto:RGB' => 1, |
||
99 | 'xproto:HOST' => 1, |
||
100 | 'xproto:POINT' => 1, |
||
101 | |||
102 | # structures defined by xinput, but never used (except by each other)(bug in xcb?) |
||
103 | 'xinput:KeyInfo' => 1, |
||
104 | 'xinput:ButtonInfo' => 1, |
||
105 | 'xinput:ValuatorInfo' => 1, |
||
106 | 'xinput:KbdFeedbackState' => 1, |
||
107 | 'xinput:PtrFeedbackState' => 1, |
||
108 | 'xinput:IntegerFeedbackState' => 1, |
||
109 | 'xinput:StringFeedbackState' => 1, |
||
110 | 'xinput:BellFeedbackState' => 1, |
||
111 | 'xinput:LedFeedbackState' => 1, |
||
112 | 'xinput:KbdFeedbackCtl' => 1, |
||
113 | 'xinput:PtrFeedbackCtl' => 1, |
||
114 | 'xinput:IntegerFeedbackCtl' => 1, |
||
115 | 'xinput:StringFeedbackCtl' => 1, |
||
116 | 'xinput:BellFeedbackCtl' => 1, |
||
117 | 'xinput:LedFeedbackCtl' => 1, |
||
118 | 'xinput:KeyState' => 1, |
||
119 | 'xinput:ButtonState' => 1, |
||
120 | 'xinput:ValuatorState' => 1, |
||
121 | 'xinput:DeviceResolutionState' => 1, |
||
122 | 'xinput:DeviceAbsCalibState' => 1, |
||
123 | 'xinput:DeviceAbsAreaState' => 1, |
||
124 | 'xinput:DeviceCoreState' => 1, |
||
125 | 'xinput:DeviceEnableState' => 1, |
||
126 | 'xinput:DeviceResolutionCtl' => 1, |
||
127 | 'xinput:DeviceAbsCalibCtl' => 1, |
||
128 | 'xinput:DeviceAbsAreaCtrl' => 1, |
||
129 | 'xinput:DeviceCoreCtrl' => 1, |
||
130 | 'xinput:DeviceEnableCtrl' => 1, |
||
131 | 'xinput:DeviceName' => 1, |
||
132 | 'xinput:AddMaster' => 1, |
||
133 | 'xinput:RemoveMaster' => 1, |
||
134 | 'xinput:AttachSlave' => 1, |
||
135 | 'xinput:DetachSlave' => 1, |
||
136 | 'xinput:ButtonClass' => 1, |
||
137 | 'xinput:KeyClass' => 1, |
||
138 | 'xinput:ScrollClass' => 1, |
||
139 | 'xinput:TouchClass' => 1, |
||
140 | 'xinput:ValuatorClass' => 1, |
||
141 | |||
142 | # structures defined by xv, but never used (bug in xcb?) |
||
143 | 'xv:Image' => 1, |
||
144 | |||
145 | # structures defined by xkb, but never used (except by each other)(bug in xcb?) |
||
146 | 'xkb:Key' => 1, |
||
147 | 'xkb:Outline' => 1, |
||
148 | 'xkb:Overlay' => 1, |
||
149 | 'xkb:OverlayKey' => 1, |
||
150 | 'xkb:OverlayRow' => 1, |
||
151 | 'xkb:Row' => 1, |
||
152 | 'xkb:Shape' => 1, |
||
153 | ); |
||
154 | my %enum; # Not reset; contains enums already defined. |
||
155 | my %enum_name; |
||
156 | my %type_name; |
||
157 | my $header; |
||
158 | my $extname; |
||
159 | my @incname; |
||
160 | my %request; |
||
161 | my %genericevent; |
||
162 | my %event; |
||
163 | my %reply; |
||
164 | |||
165 | # Output files |
||
166 | my $impl; |
||
167 | my $reg; |
||
168 | my $decl; |
||
169 | my $error; |
||
170 | |||
171 | # glRender sub-op output files |
||
172 | my $enum; |
||
173 | |||
174 | # Mesa API definitions keep moving |
||
175 | my @mesas = ($srcdir . '/mesa/src/mapi/glapi/gen', # 2010-04-26 |
||
176 | $srcdir . '/mesa/src/mesa/glapi/gen', # 2010-02-22 |
||
177 | $srcdir . '/mesa/src/mesa/glapi'); # 2004-05-18 |
||
178 | my $mesadir = (grep { -d } @mesas)[0]; |
||
179 | |||
180 | sub mesa_category_start { |
||
181 | my ($t, $elt) = @_; |
||
182 | my $name = $elt->att('name'); |
||
183 | my $comment; |
||
184 | if ($name =~ /^\d\.\d$/) { |
||
185 | $comment = "version $name"; |
||
186 | } else { |
||
187 | $comment = "extension $name"; |
||
188 | } |
||
189 | |||
190 | print $enum "/* OpenGL $comment */\n"; |
||
191 | print(" - $comment\n"); |
||
192 | } |
||
193 | |||
194 | sub mesa_category { |
||
195 | my ($t, $elt) = @_; |
||
196 | $t->purge; |
||
197 | } |
||
198 | |||
199 | sub mesa_enum { |
||
200 | my ($t, $elt) = @_; |
||
201 | my $name = $elt->att('name'); |
||
202 | my $value = $elt->att('value'); |
||
203 | |||
204 | print $enum " { $value, \"$name\" },\n" if (length($value) > 3 && length($value) < 10); |
||
205 | $t->purge; |
||
206 | } |
||
207 | |||
208 | sub mesa_type { |
||
209 | my ($t, $elt) = @_; |
||
210 | |||
211 | my $name = $elt->att('name'); |
||
212 | my $size = $elt->att('size'); |
||
213 | my $float = $elt->att('float'); |
||
214 | my $unsigned = $elt->att('unsigned'); |
||
215 | my $base; |
||
216 | |||
217 | $t->purge; |
||
218 | |||
219 | if($name eq 'enum') { |
||
220 | # enum does not have a direct X equivalent |
||
221 | $gltype{'GLenum'} = { size => 4, encoding => 'byte_order', type => 'FT_UINT32', base => 'BASE_HEX', |
||
222 | get => 'VALUE32', list => 'listOfCard32', |
||
223 | val => 'VALS(mesa_enum)', }; |
||
224 | return; |
||
225 | } |
||
226 | |||
227 | $name = 'GL'.$name; |
||
228 | if (defined($float) && $float eq 'true') { |
||
229 | $base = 'float'; |
||
230 | $base = 'double' if ($size == 8); |
||
231 | } else { |
||
232 | $base = 'INT'; |
||
233 | if (defined($unsigned) && $unsigned eq 'true') { |
||
234 | $base = 'CARD'; |
||
235 | } |
||
236 | $base .= ($size * 8); |
||
237 | |||
238 | $base = 'BOOL' if ($name eq 'bool'); |
||
239 | $base = 'BYTE' if ($name eq 'void'); |
||
240 | } |
||
241 | |||
242 | $gltype{$name} = $basictype{$base}; |
||
243 | } |
||
244 | |||
245 | sub registered_name($$) |
||
246 | { |
||
247 | my $name = shift; |
||
248 | my $field = shift; |
||
249 | |||
250 | return "hf_x11_$header"."_$name"."_$field"; |
||
251 | } |
||
252 | |||
253 | sub mesa_function { |
||
254 | my ($t, $elt) = @_; |
||
255 | # rop == glRender sub-op |
||
256 | # sop == GLX minor opcode |
||
257 | my $glx = $elt->first_child('glx'); |
||
258 | unless(defined $glx) { $t->purge; return; } |
||
259 | |||
260 | my $rop = $glx->att('rop'); |
||
261 | unless (defined $rop) { $t->purge; return; } |
||
262 | |||
263 | # Ideally, we want the main name, not the alias name. |
||
264 | # Practically, we'd have to scan the file twice to find |
||
265 | # the functions that we want to skip. |
||
266 | my $alias = $elt->att('alias'); |
||
267 | if (defined $alias) { $t->purge; return; } |
||
268 | |||
269 | my $name = $elt->att('name'); |
||
270 | $request{$rop} = $name; |
||
271 | |||
272 | my $image; |
||
273 | |||
274 | my $length = 0; |
||
275 | my @elements = $elt->children('param'); |
||
276 | |||
277 | # Wireshark defines _U_ to mean "Unused" (compiler specific define) |
||
278 | if (!@elements) { |
||
279 | print $impl <<eot |
||
280 | static void mesa_$name(tvbuff_t *tvb _U_, int *offsetp _U_, proto_tree *t _U_, guint byte_order _U_, int length _U_) |
||
281 | { |
||
282 | eot |
||
283 | ; |
||
284 | } else { |
||
285 | print $impl <<eot |
||
286 | static void mesa_$name(tvbuff_t *tvb, int *offsetp, proto_tree *t, guint byte_order, int length _U_) |
||
287 | { |
||
288 | eot |
||
289 | ; |
||
290 | } |
||
291 | |||
292 | my %type_param; |
||
293 | foreach my $e (@elements) { |
||
294 | # Detect count && variable_param |
||
295 | my $count = $e->att('count'); |
||
296 | my $variable_param = $e->att('variable_param'); |
||
297 | if (defined $count and defined $variable_param) { |
||
298 | $type_param{$variable_param} = 1; |
||
299 | } |
||
300 | } |
||
301 | foreach my $e (@elements) { |
||
302 | # Register field with wireshark |
||
303 | |||
304 | my $type = $e->att('type'); |
||
305 | $type =~ s/^const //; |
||
306 | my $list; |
||
307 | $list = 1 if ($type =~ /\*$/); |
||
308 | $type =~ s/ \*$//; |
||
309 | |||
310 | my $fieldname = $e->att('name'); |
||
311 | my $regname = registered_name($name, $fieldname); |
||
312 | |||
313 | my $info = $gltype{$type}; |
||
314 | my $ft = $info->{'type'}; |
||
315 | my $base = $info->{'base'}; |
||
316 | my $val = $info->{'val'} // 'NULL'; |
||
317 | my $count = $e->att('count'); |
||
318 | my $variable_param = $e->att('variable_param'); |
||
319 | |||
320 | if ($list and $count and $variable_param) { |
||
321 | print $decl "static int ${regname} = -1;\n"; |
||
322 | print $reg "{ &$regname, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},\n"; |
||
323 | print $decl "static int ${regname}_signed = -1;\n"; |
||
324 | print $reg "{ &${regname}_signed, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", FT_INT8, BASE_DEC, NULL, 0, NULL, HFILL }},\n"; |
||
325 | print $decl "static int ${regname}_unsigned = -1;\n"; |
||
326 | print $reg "{ &${regname}_unsigned, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},\n"; |
||
327 | print $decl "static int ${regname}_item_card16 = -1;\n"; |
||
328 | print $reg "{ &${regname}_item_card16, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},\n"; |
||
329 | print $decl "static int ${regname}_item_int16 = -1;\n"; |
||
330 | print $reg "{ &${regname}_item_int16, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", FT_INT16, BASE_DEC, NULL, 0, NULL, HFILL }},\n"; |
||
331 | print $decl "static int ${regname}_item_card32 = -1;\n"; |
||
332 | print $reg "{ &${regname}_item_card32, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},\n"; |
||
333 | print $decl "static int ${regname}_item_int32 = -1;\n"; |
||
334 | print $reg "{ &${regname}_item_int32, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", FT_INT32, BASE_DEC, NULL, 0, NULL, HFILL }},\n"; |
||
335 | print $decl "static int ${regname}_item_float = -1;\n"; |
||
336 | print $reg "{ &${regname}_item_float, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL }},\n"; |
||
337 | } else { |
||
338 | print $decl "static int $regname = -1;\n"; |
||
339 | if ($list and $info->{'size'} > 1) { |
||
340 | print $reg "{ &$regname, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},\n"; |
||
341 | $regname .= '_item'; |
||
342 | print $decl "static int $regname = -1;\n"; |
||
343 | } |
||
344 | print $reg "{ &$regname, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", $ft, $base, $val, 0, NULL, HFILL }},\n"; |
||
345 | |||
346 | if ($e->att('counter') or $type_param{$fieldname}) { |
||
347 | print $impl " int $fieldname;\n"; |
||
348 | } |
||
349 | } |
||
350 | |||
351 | if ($list) { |
||
352 | if ($e->att('img_format')) { |
||
353 | $image = 1; |
||
354 | foreach my $wholename (('swap bytes', 'lsb first')) { |
||
355 | # Boolean values |
||
356 | my $varname = $wholename; |
||
357 | $varname =~ s/\s//g; |
||
358 | my $regname = registered_name($name, $varname); |
||
359 | print $decl "static int $regname = -1;\n"; |
||
360 | print $reg "{ &$regname, { \"$wholename\", \"x11.glx.render.$name.$varname\", FT_BOOLEAN, BASE_NONE, NULL, 0, NULL, HFILL }},\n"; |
||
361 | } |
||
362 | foreach my $wholename (('row length', 'skip rows', 'skip pixels', 'alignment')) { |
||
363 | # Integer values |
||
364 | my $varname = $wholename; |
||
365 | $varname =~ s/\s//g; |
||
366 | my $regname = registered_name($name, $varname); |
||
367 | print $decl "static int $regname = -1;\n"; |
||
368 | print $reg "{ &$regname, { \"$wholename\", \"x11.glx.render.$name.$varname\", FT_UINT32, BASE_HEX_DEC, NULL, 0, NULL, HFILL }},\n"; |
||
369 | } |
||
370 | } |
||
371 | } |
||
372 | } |
||
373 | |||
374 | # The image requests have a few implicit elements first: |
||
375 | if ($image) { |
||
376 | foreach my $wholename (('swap bytes', 'lsb first')) { |
||
377 | # Boolean values |
||
378 | my $varname = $wholename; |
||
379 | $varname =~ s/\s//g; |
||
380 | my $regname = registered_name($name, $varname); |
||
381 | print $impl " proto_tree_add_item(t, $regname, tvb, *offsetp, 1, byte_order);\n"; |
||
382 | print $impl " *offsetp += 1;\n"; |
||
383 | $length += 1; |
||
384 | } |
||
385 | print $impl " UNUSED(2);\n"; |
||
386 | $length += 2; |
||
387 | foreach my $wholename (('row length', 'skip rows', 'skip pixels', 'alignment')) { |
||
388 | # Integer values |
||
389 | my $varname = $wholename; |
||
390 | $varname =~ s/\s//g; |
||
391 | my $regname = registered_name($name, $varname); |
||
392 | print $impl " proto_tree_add_item(t, $regname, tvb, *offsetp, 4, byte_order);\n"; |
||
393 | print $impl " *offsetp += 4;\n"; |
||
394 | $length += 4; |
||
395 | } |
||
396 | } |
||
397 | |||
398 | foreach my $e (@elements) { |
||
399 | my $type = $e->att('type'); |
||
400 | $type =~ s/^const //; |
||
401 | my $list; |
||
402 | $list = 1 if ($type =~ /\*$/); |
||
403 | $type =~ s/ \*$//; |
||
404 | |||
405 | my $fieldname = $e->att('name'); |
||
406 | my $regname = registered_name($name, $fieldname); |
||
407 | |||
408 | my $info = $gltype{$type}; |
||
409 | my $ft = $info->{'type'}; |
||
410 | my $base = $info->{'base'}; |
||
411 | |||
412 | if (!$list) { |
||
413 | my $size = $info->{'size'}; |
||
414 | my $encoding = $info->{'encoding'}; |
||
415 | my $get = $info->{'get'}; |
||
416 | |||
417 | if ($e->att('counter') or $type_param{$fieldname}) { |
||
418 | print $impl " $fieldname = $get(tvb, *offsetp);\n"; |
||
419 | } |
||
420 | print $impl " proto_tree_add_item(t, $regname, tvb, *offsetp, $size, $encoding);\n"; |
||
421 | print $impl " *offsetp += $size;\n"; |
||
422 | $length += $size; |
||
423 | } else { # list |
||
424 | my $list = $info->{'list'}; |
||
425 | my $count = $e->att('count'); |
||
426 | my $variable_param = $e->att('variable_param'); |
||
427 | |||
428 | if (defined($count) && !defined($variable_param)) { |
||
429 | $regname .= ", $regname".'_item' if ($info->{'size'} > 1); |
||
430 | print $impl " $list(tvb, offsetp, t, $regname, $count, byte_order);\n"; |
||
431 | } else { |
||
432 | if (defined($count)) { |
||
433 | # Currently, only CallLists has both a count and a variable_param |
||
434 | # The XML contains a size description of all the possibilities |
||
435 | # for CallLists, but not a type description. Implement by hand, |
||
436 | # with the caveat that more types may need to be added in the |
||
437 | # future. |
||
438 | say $impl " switch($variable_param) {"; |
||
439 | say $impl " case 0x1400: /* BYTE */"; |
||
440 | say $impl " listOfByte(tvb, offsetp, t, ${regname}_signed, $count, byte_order);"; |
||
441 | say $impl " UNUSED(length - $length - $count);"; |
||
442 | say $impl " break;"; |
||
443 | say $impl " case 0x1401: /* UNSIGNED_BYTE */"; |
||
444 | say $impl " listOfByte(tvb, offsetp, t, ${regname}_unsigned, $count, byte_order);"; |
||
445 | say $impl " UNUSED(length - $length - $count);"; |
||
446 | say $impl " break;"; |
||
447 | say $impl " case 0x1402: /* SHORT */"; |
||
448 | say $impl " listOfInt16(tvb, offsetp, t, $regname, ${regname}_item_int16, $count, byte_order);"; |
||
449 | say $impl " UNUSED(length - $length - 2 * $count);"; |
||
450 | say $impl " break;"; |
||
451 | say $impl " case 0x1403: /* UNSIGNED_SHORT */"; |
||
452 | say $impl " listOfCard16(tvb, offsetp, t, $regname, ${regname}_item_card16, $count, byte_order);"; |
||
453 | say $impl " UNUSED(length - $length - 2 * $count);"; |
||
454 | say $impl " break;"; |
||
455 | say $impl " case 0x1404: /* INT */"; |
||
456 | say $impl " listOfInt32(tvb, offsetp, t, $regname, ${regname}_item_int32, $count, byte_order);"; |
||
457 | say $impl " break;"; |
||
458 | say $impl " case 0x1405: /* UNSIGNED_INT */"; |
||
459 | say $impl " listOfCard32(tvb, offsetp, t, $regname, ${regname}_item_card32, $count, byte_order);"; |
||
460 | say $impl " break;"; |
||
461 | say $impl " case 0x1406: /* FLOAT */"; |
||
462 | say $impl " listOfFloat(tvb, offsetp, t, $regname, ${regname}_item_float, $count, byte_order);"; |
||
463 | say $impl " break;"; |
||
464 | say $impl " case 0x1407: /* 2_BYTES */"; |
||
465 | say $impl " listOfCard16(tvb, offsetp, t, $regname, ${regname}_item_card16, $count, ENC_BIG_ENDIAN);"; |
||
466 | say $impl " UNUSED(length - $length - 2 * $count);"; |
||
467 | say $impl " break;"; |
||
468 | say $impl " case 0x1408: /* 3_BYTES */"; |
||
469 | say $impl " UNDECODED(3 * $count);"; |
||
470 | say $impl " UNUSED(length - $length - 3 * $count);"; |
||
471 | say $impl " break;"; |
||
472 | say $impl " case 0x1409: /* 4_BYTES */"; |
||
473 | say $impl " listOfCard32(tvb, offsetp, t, $regname, ${regname}_item_card32, $count, ENC_BIG_ENDIAN);"; |
||
474 | say $impl " break;"; |
||
475 | say $impl " case 0x140B: /* HALF_FLOAT */"; |
||
476 | say $impl " UNDECODED(2 * $count);"; |
||
477 | say $impl " UNUSED(length - $length - 2 * $count);"; |
||
478 | say $impl " break;"; |
||
479 | say $impl " default: /* Unknown */"; |
||
480 | say $impl " UNDECODED(length - $length);"; |
||
481 | say $impl " break;"; |
||
482 | say $impl " }"; |
||
483 | } else { |
||
484 | $regname .= ", $regname".'_item' if ($info->{'size'} > 1); |
||
485 | print $impl " $list(tvb, offsetp, t, $regname, (length - $length) / $gltype{$type}{'size'}, byte_order);\n"; |
||
486 | } |
||
487 | } |
||
488 | } |
||
489 | } |
||
490 | |||
491 | print $impl "}\n\n"; |
||
492 | $t->purge; |
||
493 | } |
||
494 | |||
495 | sub get_op($;$); |
||
496 | sub get_unop($;$); |
||
497 | |||
498 | sub get_ref($$) |
||
499 | { |
||
500 | my $elt = shift; |
||
501 | my $refref = shift; |
||
502 | my $rv; |
||
503 | |||
504 | given($elt->name()) { |
||
505 | when ('fieldref') { |
||
506 | $rv = $elt->text(); |
||
507 | $refref->{$rv} = 1; |
||
508 | $rv = 'f_'.$rv; |
||
509 | } |
||
510 | when ('value') { $rv = $elt->text(); } |
||
511 | when ('op') { $rv = get_op($elt, $refref); } |
||
512 | when (['unop','popcount']) { $rv = get_unop($elt, $refref); } |
||
513 | default { die "Invalid op fragment: $_" } |
||
514 | } |
||
515 | return $rv; |
||
516 | } |
||
517 | |||
518 | sub get_op($;$) { |
||
519 | my $op = shift; |
||
520 | my $refref = shift // {}; |
||
521 | |||
522 | my @elements = $op->children(qr/fieldref|value|op|unop|popcount/); |
||
523 | (@elements == 2) or die ("Wrong number of children for 'op'\n"); |
||
524 | my $left; |
||
525 | my $right; |
||
526 | |||
527 | $left = get_ref($elements[0], $refref); |
||
528 | $right = get_ref($elements[1], $refref); |
||
529 | |||
530 | return "($left " . $op->att('op') . " $right)"; |
||
531 | } |
||
532 | |||
533 | sub get_unop($;$) { |
||
534 | my $op = shift; |
||
535 | my $refref = shift // {}; |
||
536 | |||
537 | my @elements = $op->children(qr/fieldref|value|op|unop|popcount/); |
||
538 | (@elements == 1) or die ("Wrong number of children for 'unop'\n"); |
||
539 | my $left; |
||
540 | |||
541 | $left = get_ref($elements[0], $refref); |
||
542 | |||
543 | given ($op->name()) { |
||
544 | when ('unop') { |
||
545 | return '(' . $op->att('op') . "$left)"; |
||
546 | } |
||
547 | when ('popcount') { |
||
548 | return "popcount($left)"; |
||
549 | } |
||
550 | default { die "Invalid unop element $op->name()\n"; } |
||
551 | } |
||
552 | } |
||
553 | |||
554 | sub qualname { |
||
555 | my $name = shift; |
||
556 | $name = $incname[0].':'.$name unless $name =~ /:/; |
||
557 | return $name |
||
558 | } |
||
559 | |||
560 | sub get_simple_info { |
||
561 | my $name = shift; |
||
562 | my $info = $basictype{$name}; |
||
563 | return $info if (defined $info); |
||
564 | $info = $simpletype{$name}; |
||
565 | return $info if (defined $info); |
||
566 | if (defined($type_name{$name})) { |
||
567 | return $simpletype{$type_name{$name}}; |
||
568 | } |
||
569 | return undef |
||
570 | } |
||
571 | |||
572 | sub get_struct_info { |
||
573 | my $name = shift; |
||
574 | my $info = $struct{$name}; |
||
575 | return $info if (defined $info); |
||
576 | if (defined($type_name{$name})) { |
||
577 | return $struct{$type_name{$name}}; |
||
578 | } |
||
579 | return undef |
||
580 | } |
||
581 | |||
582 | sub getinfo { |
||
583 | my $name = shift; |
||
584 | my $info = get_simple_info($name) // get_struct_info($name); |
||
585 | # If the script fails here search for $name in this script and remove it from the black list |
||
586 | die "$name is defined to be unused in process-x11-xcb.pl but is actually used!" if (defined($info) && $info == "1"); |
||
587 | return $info; |
||
588 | } |
||
589 | |||
590 | sub dump_enum_values($) |
||
591 | { |
||
592 | my $e = shift; |
||
593 | |||
594 | defined($enum{$e}) or die("Enum $e not found"); |
||
595 | |||
596 | my $enumname = "x11_enum_$e"; |
||
597 | return $enumname if (defined $enum{$e}{done}); |
||
598 | |||
599 | say $enum 'static const value_string '.$enumname.'[] = {'; |
||
600 | |||
601 | my $value = $enum{$e}{value}; |
||
602 | for my $val (sort { $a <=> $b } keys %$value) { |
||
603 | say $enum sprintf(" { %3d, \"%s\" },", $val, $$value{$val}); |
||
604 | } |
||
605 | say $enum sprintf(" { %3d, NULL },", 0); |
||
606 | say $enum '};'; |
||
607 | say $enum ''; |
||
608 | |||
609 | $enum{$e}{done} = 1; |
||
610 | return $enumname; |
||
611 | } |
||
612 | |||
613 | # Find all references, so we can declare only the minimum necessary |
||
614 | sub reference_elements($$); |
||
615 | |||
616 | sub reference_elements($$) |
||
617 | { |
||
618 | my $e = shift; |
||
619 | my $refref = shift; |
||
620 | |||
621 | given ($e->name()) { |
||
622 | when ('switch') { |
||
623 | my $lentype = $e->first_child(); |
||
624 | if (defined $lentype) { |
||
625 | given ($lentype->name()) { |
||
626 | when ('fieldref') { $refref->{field}{$lentype->text()} = 1; } |
||
627 | when ('op') { get_op($lentype, $refref->{field}); } |
||
628 | } |
||
629 | } |
||
630 | |||
631 | my @elements = $e->children(qr/(bit)?case/); |
||
632 | for my $case (@elements) { |
||
633 | my @sub_elements = $case->children(qr/list|switch/); |
||
634 | |||
635 | foreach my $sub_e (@sub_elements) { |
||
636 | reference_elements($sub_e, $refref); |
||
637 | } |
||
638 | } |
||
639 | } |
||
640 | when ('list') { |
||
641 | my $type = $e->att('type'); |
||
642 | my $info = getinfo($type); |
||
643 | if (defined $info->{paramref}) { |
||
644 | for my $pref (keys %{$info->{paramref}}) { |
||
645 | $refref->{field}{$pref} = 1; |
||
646 | } |
||
647 | } |
||
648 | |||
649 | my $lentype = $e->first_child(); |
||
650 | if (defined $lentype) { |
||
651 | given ($lentype->name()) { |
||
652 | when ('fieldref') { $refref->{field}{$lentype->text()} = 1; } |
||
653 | when ('op') { get_op($lentype, $refref->{field}); } |
||
654 | when (['unop','popcount']) { get_unop($lentype, $refref->{field}); } |
||
655 | when ('sumof') { $refref->{sumof}{$lentype->att('ref')} = 1; } |
||
656 | } |
||
657 | } else { |
||
658 | $refref->{field}{'length'} = 1; |
||
659 | $refref->{'length'} = 1; |
||
660 | } |
||
661 | } |
||
662 | } |
||
663 | } |
||
664 | |||
665 | sub register_element($$$$;$) |
||
666 | { |
||
667 | my $e = shift; |
||
668 | my $varpat = shift; |
||
669 | my $humanpat = shift; |
||
670 | my $refref = shift; |
||
671 | my $indent = shift // ' ' x 4; |
||
672 | |||
673 | given ($e->name()) { |
||
674 | when ('pad') { return; } # Pad has no variables |
||
675 | when ('switch') { return; } # Switch defines varaibles in a tighter scope to avoid collisions |
||
676 | } |
||
677 | |||
678 | # Register field with wireshark |
||
679 | |||
680 | my $fieldname = $e->att('name'); |
||
681 | my $type = $e->att('type') or die ("Field $fieldname does not have a valid type\n"); |
||
682 | |||
683 | my $regname = 'hf_x11_'.sprintf ($varpat, $fieldname); |
||
684 | my $humanname = 'x11.'.sprintf ($humanpat, $fieldname); |
||
685 | |||
686 | my $info = getinfo($type); |
||
687 | my $ft = $info->{'type'} // 'FT_NONE'; |
||
688 | my $base = $info->{'base'} // 'BASE_NONE'; |
||
689 | my $vals = 'NULL'; |
||
690 | |||
691 | my $enum = $e->att('enum') // $e->att('altenum'); |
||
692 | if (defined $enum) { |
||
693 | my $enumname = dump_enum_values($enum_name{$enum}); |
||
694 | $vals = "VALS($enumname)"; |
||
695 | |||
696 | # Wireshark does not allow FT_BYTES, FT_BOOLEAN, or BASE_NONE to have an enum |
||
697 | $ft =~ s/FT_BYTES/FT_UINT8/; |
||
698 | $ft =~ s/FT_BOOLEAN/FT_UINT8/; |
||
699 | $base =~ s/BASE_NONE/BASE_DEC/; |
||
700 | } |
||
701 | |||
702 | $enum = $e->att('mask'); |
||
703 | if (defined $enum) { |
||
704 | # Create subtree items: |
||
705 | defined($enum{$enum_name{$enum}}) or die("Enum $enum not found"); |
||
706 | |||
707 | # Wireshark does not allow FT_BYTES or BASE_NONE to have an enum |
||
708 | $ft =~ s/FT_BYTES/FT_UINT8/; |
||
709 | $base =~ s/BASE_NONE/BASE_DEC/; |
||
710 | |||
711 | my $bitsize = $info->{'size'} * 8; |
||
712 | |||
713 | my $bit = $enum{$enum_name{$enum}}{bit}; |
||
714 | for my $val (sort { $a <=> $b } keys %$bit) { |
||
715 | my $itemname = $$bit{$val}; |
||
716 | my $item = $regname . '_mask_' . $itemname; |
||
717 | my $itemhuman = $humanname . '.' . $itemname; |
||
718 | my $bitshift = "1U << $val"; |
||
719 | |||
720 | say $decl "static int $item = -1;"; |
||
721 | say $reg "{ &$item, { \"$itemname\", \"$itemhuman\", FT_BOOLEAN, $bitsize, NULL, $bitshift, NULL, HFILL }},"; |
||
722 | } |
||
723 | } |
||
724 | |||
725 | print $decl "static int $regname = -1;\n"; |
||
726 | if ($e->name() eq 'list' and $info->{'size'} > 1) { |
||
727 | print $reg "{ &$regname, { \"$fieldname\", \"$humanname\", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},\n"; |
||
728 | $regname .= '_item'; |
||
729 | print $decl "static int $regname = -1;\n"; |
||
730 | } |
||
731 | print $reg "{ &$regname, { \"$fieldname\", \"$humanname\", $ft, $base, $vals, 0, NULL, HFILL }},\n"; |
||
732 | |||
733 | if ($refref->{sumof}{$fieldname}) { |
||
734 | print $impl $indent."int sumof_$fieldname = 0;\n"; |
||
735 | } |
||
736 | |||
737 | if ($e->name() eq 'field') { |
||
738 | if ($refref->{field}{$fieldname} and get_simple_info($type)) { |
||
739 | # Pre-declare variable |
||
740 | if ($ft eq 'FT_FLOAT') { |
||
741 | print $impl $indent."gfloat f_$fieldname;\n"; |
||
742 | } elsif ($ft eq 'FT_DOUBLE') { |
||
743 | print $impl $indent."gdouble f_$fieldname;\n"; |
||
744 | } elsif ($ft eq 'FT_INT64' or $ft eq 'FT_UINT64') { |
||
745 | print $impl $indent."gint64 f_$fieldname;\n"; |
||
746 | } else { |
||
747 | print $impl $indent."int f_$fieldname;\n"; |
||
748 | } |
||
749 | } |
||
750 | } |
||
751 | } |
||
752 | |||
753 | sub dissect_element($$$$$;$$); |
||
754 | |||
755 | sub dissect_element($$$$$;$$) |
||
756 | { |
||
757 | my $e = shift; |
||
758 | my $varpat = shift; |
||
759 | my $humanpat = shift; |
||
760 | my $length = shift; |
||
761 | my $refref = shift; |
||
762 | my $adjustlength = shift; |
||
763 | my $indent = shift // ' ' x 4; |
||
764 | |||
765 | given ($e->name()) { |
||
766 | when ('pad') { |
||
767 | my $bytes = $e->att('bytes'); |
||
768 | my $align = $e->att('align'); |
||
769 | if (defined $bytes) { |
||
770 | print $impl $indent."UNUSED($bytes);\n"; |
||
771 | $length += $bytes; |
||
772 | } else { |
||
773 | say $impl $indent.'if (*offsetp % '.$align.') {'; |
||
774 | say $impl $indent." UNUSED($align - *offsetp % $align);"; |
||
775 | say $impl $indent."}"; |
||
776 | if ($length % $align != 0) { |
||
777 | $length += $align - $length % $align; |
||
778 | } |
||
779 | if ($adjustlength) { |
||
780 | say $impl $indent.'length = ((length + '.($align-1).') & ~'.($align-1).');'; |
||
781 | } |
||
782 | } |
||
783 | } |
||
784 | when ('field') { |
||
785 | my $fieldname = $e->att('name'); |
||
786 | my $regname = 'hf_x11_'.sprintf ($varpat, $fieldname); |
||
787 | my $type = $e->att('type'); |
||
788 | |||
789 | if (get_simple_info($type)) { |
||
790 | my $info = get_simple_info($type); |
||
791 | my $size = $info->{'size'}; |
||
792 | my $encoding = $info->{'encoding'}; |
||
793 | my $get = $info->{'get'}; |
||
794 | |||
795 | if ($e->att('enum') // $e->att('altenum')) { |
||
796 | my $fieldsize = $size * 8; |
||
797 | print $impl $indent; |
||
798 | if ($refref->{field}{$fieldname}) { |
||
799 | print $impl "f_$fieldname = "; |
||
800 | } |
||
801 | say $impl "field$fieldsize(tvb, offsetp, t, $regname, byte_order);"; |
||
802 | } elsif ($e->att('mask')) { |
||
803 | if ($refref->{field}{$fieldname}) { |
||
804 | say $impl $indent."f_$fieldname = $get(tvb, *offsetp);"; |
||
805 | } |
||
806 | say $impl $indent."{"; |
||
807 | say $impl $indent." proto_item *ti = proto_tree_add_item(t, $regname, tvb, *offsetp, $size, $encoding);"; |
||
808 | say $impl $indent." proto_tree *bitmask_tree = proto_item_add_subtree(ti, ett_x11_rectangle);"; |
||
809 | |||
810 | my $bytesize = $info->{'size'}; |
||
811 | my $byteencoding = $info->{'encoding'}; |
||
812 | my $bit = $enum{$enum_name{$e->att('mask')}}{bit}; |
||
813 | for my $val (sort { $a <=> $b } keys %$bit) { |
||
814 | my $item = $regname . '_mask_' . $$bit{$val}; |
||
815 | |||
816 | say $impl "$indent proto_tree_add_item(bitmask_tree, $item, tvb, *offsetp, $bytesize, $byteencoding);"; |
||
817 | } |
||
818 | |||
819 | say $impl $indent."}"; |
||
820 | say $impl $indent."*offsetp += $size;"; |
||
821 | } else { |
||
822 | if ($refref->{field}{$fieldname}) { |
||
823 | say $impl $indent."f_$fieldname = $get(tvb, *offsetp);"; |
||
824 | } |
||
825 | print $impl $indent."proto_tree_add_item(t, $regname, tvb, *offsetp, $size, $encoding);\n"; |
||
826 | print $impl $indent."*offsetp += $size;\n"; |
||
827 | } |
||
828 | $length += $size; |
||
829 | } elsif (get_struct_info($type)) { |
||
830 | # TODO: variable-lengths (when $info->{'size'} == 0 ) |
||
831 | my $info = get_struct_info($type); |
||
832 | $length += $info->{'size'}; |
||
833 | print $impl $indent."struct_$info->{'name'}(tvb, offsetp, t, byte_order, 1);\n"; |
||
834 | } else { |
||
835 | die ("Unrecognized type: $type\n"); |
||
836 | } |
||
837 | } |
||
838 | when ('list') { |
||
839 | my $fieldname = $e->att('name'); |
||
840 | my $regname = 'hf_x11_'.sprintf ($varpat, $fieldname); |
||
841 | my $type = $e->att('type'); |
||
842 | |||
843 | my $info = getinfo($type); |
||
844 | my $lencalc = "(length - $length) / $info->{'size'}"; |
||
845 | my $lentype = $e->first_child(); |
||
846 | if (defined $lentype) { |
||
847 | given ($lentype->name()) { |
||
848 | when ('value') { $lencalc = $lentype->text(); } |
||
849 | when ('fieldref') { $lencalc = 'f_'.$lentype->text(); } |
||
850 | when ('paramref') { $lencalc = 'p_'.$lentype->text(); } |
||
851 | when ('op') { $lencalc = get_op($lentype); } |
||
852 | when (['unop','popcount']) { $lencalc = get_unop($lentype); } |
||
853 | when ('sumof') { $lencalc = 'sumof_'.$lentype->att('ref'); } |
||
854 | } |
||
855 | } |
||
856 | |||
857 | if (get_simple_info($type)) { |
||
858 | my $list = $info->{'list'}; |
||
859 | my $size = $info->{'size'}; |
||
860 | $regname .= ", $regname".'_item' if ($size > 1); |
||
861 | |||
862 | if ($refref->{sumof}{$fieldname}) { |
||
863 | my $get = $info->{'get'}; |
||
864 | say $impl $indent."{"; |
||
865 | say $impl $indent." int i;"; |
||
866 | say $impl $indent." for (i = 0; i < $lencalc; i++) {"; |
||
867 | say $impl $indent." sumof_$fieldname += $get(tvb, *offsetp + i * $size);"; |
||
868 | say $impl $indent." }"; |
||
869 | say $impl $indent."}"; |
||
870 | } |
||
871 | |||
872 | print $impl $indent."$list(tvb, offsetp, t, $regname, $lencalc, byte_order);\n"; |
||
873 | } elsif (get_struct_info($type)) { |
||
874 | my $si = get_struct_info($type); |
||
875 | my $prefs = ""; |
||
876 | foreach my $pref (sort keys %{$si->{paramref}}) { |
||
877 | $prefs .= ", f_$pref"; |
||
878 | } |
||
879 | |||
880 | print $impl $indent."struct_$info->{'name'}(tvb, offsetp, t, byte_order, $lencalc$prefs);\n"; |
||
881 | } else { |
||
882 | die ("Unrecognized type: $type\n"); |
||
883 | } |
||
884 | |||
885 | if ($adjustlength && defined($lentype)) { |
||
886 | # Some requests end with a list of unspecified length |
||
887 | # Adjust the length field here so that the next $lencalc will be accurate |
||
888 | say $impl $indent."length -= $lencalc * $info->{'size'};"; |
||
889 | } |
||
890 | } |
||
891 | when ('switch') { |
||
892 | my $switchtype = $e->first_child() or die("Switch element not defined"); |
||
893 | |||
894 | my $switchon = get_ref($switchtype, {}); |
||
895 | my @elements = $e->children(qr/(bit)?case/); |
||
896 | for my $case (@elements) { |
||
897 | my @refs = $case->children('enumref'); |
||
898 | my @test; |
||
899 | my $fieldname; |
||
900 | foreach my $ref (@refs) { |
||
901 | my $enum_ref = $ref->att('ref'); |
||
902 | my $field = $ref->text(); |
||
903 | $fieldname //= $field; # Use first named field |
||
904 | if ($case->name() eq 'bitcase') { |
||
905 | my $bit = $enum{$enum_name{$enum_ref}}{rbit}{$field}; |
||
906 | if (! defined($bit)) { |
||
907 | for my $foo (keys %{$enum{$enum_name{$enum_ref}}{rbit}}) { say "'$foo'"; } |
||
908 | die ("Field '$field' not found in '$enum_ref'"); |
||
909 | } |
||
910 | push @test , "$switchon & (1U << $bit)"; |
||
911 | } else { |
||
912 | my $val = $enum{$enum_name{$enum_ref}}{rvalue}{$field}; |
||
913 | if (! defined($val)) { |
||
914 | for my $foo (keys %{$enum{$enum_name{$enum_ref}}{rvalue}}) { say "'$foo'"; } |
||
915 | die ("Field '$field' not found in '$enum_ref'"); |
||
916 | } |
||
917 | push @test , "$switchon == $val"; |
||
918 | } |
||
919 | } |
||
920 | |||
921 | if (@test > 1) { |
||
922 | # We have more than one conditional, add parentheses to them. |
||
923 | # We don't add parentheses to all the conditionals because |
||
924 | # clang complains about the extra parens if you do "if ((x == y))". |
||
925 | my @tests_with_parens; |
||
926 | foreach my $conditional (@test) { |
||
927 | push @tests_with_parens, "($conditional)"; |
||
928 | } |
||
929 | |||
930 | @test = @tests_with_parens; |
||
931 | } |
||
932 | |||
933 | my $list = join ' || ', @test; |
||
934 | say $impl $indent."if ($list) {"; |
||
935 | |||
936 | my $vp = $varpat; |
||
937 | my $hp = $humanpat; |
||
938 | |||
939 | $vp =~ s/%s/${fieldname}_%s/; |
||
940 | $hp =~ s/%s/${fieldname}.%s/; |
||
941 | |||
942 | my @sub_elements = $case->children(qr/pad|field|list|switch/); |
||
943 | |||
944 | my $subref = { field => {}, sumof => {} }; |
||
945 | foreach my $sub_e (@sub_elements) { |
||
946 | reference_elements($sub_e, $subref); |
||
947 | } |
||
948 | foreach my $sub_e (@sub_elements) { |
||
949 | register_element($sub_e, $vp, $hp, $subref, $indent . ' '); |
||
950 | } |
||
951 | foreach my $sub_e (@sub_elements) { |
||
952 | $length = dissect_element($sub_e, $vp, $hp, $length, $subref, $adjustlength, $indent . ' '); |
||
953 | } |
||
954 | |||
955 | say $impl $indent."}"; |
||
956 | } |
||
957 | } |
||
958 | default { die "Unknown field type: $_\n"; } |
||
959 | } |
||
960 | return $length; |
||
961 | } |
||
962 | |||
963 | sub struct { |
||
964 | my ($t, $elt) = @_; |
||
965 | my $name = $elt->att('name'); |
||
966 | my $qualname = qualname($name); |
||
967 | $type_name{$name} = $qualname; |
||
968 | |||
969 | if (defined $struct{$qualname}) { |
||
970 | $t->purge; |
||
971 | return; |
||
972 | } |
||
973 | |||
974 | my @elements = $elt->children(qr/pad|field|list|switch/); |
||
975 | |||
976 | print(" - Struct $name\n"); |
||
977 | |||
978 | $name = $qualname; |
||
979 | $name =~ s/:/_/; |
||
980 | |||
981 | my %refs; |
||
982 | my %paramrefs; |
||
983 | my $size = 0; |
||
984 | my $dynamic = 0; |
||
985 | my $needi = 0; |
||
986 | # Find struct size |
||
987 | foreach my $e (@elements) { |
||
988 | my $count; |
||
989 | $count = 1; |
||
990 | given ($e->name()) { |
||
991 | when ('pad') { |
||
992 | my $bytes = $e->att('bytes'); |
||
993 | my $align = $e->att('align'); |
||
994 | if (defined $bytes) { |
||
995 | $size += $bytes; |
||
996 | next; |
||
997 | } |
||
998 | if (!$dynamic) { |
||
999 | if ($size % $align) { |
||
1000 | $size += $align - $size % $align; |
||
1001 | } |
||
1002 | } |
||
1003 | next; |
||
1004 | } |
||
1005 | when ('list') { |
||
1006 | my $type = $e->att('type'); |
||
1007 | my $info = getinfo($type); |
||
1008 | |||
1009 | $needi = 1 if ($info->{'size'} == 0); |
||
1010 | |||
1011 | my $value = $e->first_child(); |
||
1012 | given($value->name()) { |
||
1013 | when ('fieldref') { |
||
1014 | $refs{$value->text()} = 1; |
||
1015 | $count = 0; |
||
1016 | $dynamic = 1; |
||
1017 | } |
||
1018 | when ('paramref') { |
||
1019 | $paramrefs{$value->text()} = $value->att('type'); |
||
1020 | $count = 0; |
||
1021 | $dynamic = 1; |
||
1022 | } |
||
1023 | when ('op') { |
||
1024 | get_op($value, \%refs); |
||
1025 | $count = 0; |
||
1026 | $dynamic = 1; |
||
1027 | } |
||
1028 | when (['unop','popcount']) { |
||
1029 | get_unop($value, \%refs); |
||
1030 | $count = 0; |
||
1031 | $dynamic = 1; |
||
1032 | } |
||
1033 | when ('value') { |
||
1034 | $count = $value->text(); |
||
1035 | } |
||
1036 | default { die("Invalid list size $_\n"); } |
||
1037 | } |
||
1038 | } |
||
1039 | when ('field') { } |
||
1040 | when ('switch') { |
||
1041 | $dynamic = 1; |
||
1042 | next; |
||
1043 | } |
||
1044 | default { die("unrecognized field: $_\n"); } |
||
1045 | } |
||
1046 | |||
1047 | my $type = $e->att('type'); |
||
1048 | my $info = getinfo($type); |
||
1049 | |||
1050 | $size += $info->{'size'} * $count; |
||
1051 | } |
||
1052 | |||
1053 | my $prefs = ""; |
||
1054 | |||
1055 | if ($dynamic) { |
||
1056 | $size = 0; |
||
1057 | |||
1058 | foreach my $pref (sort keys %paramrefs) { |
||
1059 | $prefs .= ", int p_$pref"; |
||
1060 | } |
||
1061 | |||
1062 | print $impl <<eot |
||
1063 | |||
1064 | static int struct_size_$name(tvbuff_t *tvb _U_, int *offsetp _U_, guint byte_order _U_$prefs) |
||
1065 | { |
||
1066 | int size = 0; |
||
1067 | eot |
||
1068 | ; |
||
1069 | say $impl ' int i, off;' if ($needi); |
||
1070 | |||
1071 | foreach my $ref (sort keys %refs) { |
||
1072 | say $impl " int f_$ref;"; |
||
1073 | } |
||
1074 | |||
1075 | foreach my $e (@elements) { |
||
1076 | my $count; |
||
1077 | $count = 1; |
||
1078 | |||
1079 | my $type = $e->att('type') // ''; |
||
1080 | my $info = getinfo($type); |
||
1081 | |||
1082 | given ($e->name()) { |
||
1083 | when ('pad') { |
||
1084 | my $bytes = $e->att('bytes'); |
||
1085 | my $align = $e->att('align'); |
||
1086 | if (defined $bytes) { |
||
1087 | $size += $bytes; |
||
1088 | } else { |
||
1089 | say $impl ' size = (size + '.($align-1).') & ~'.($align-1).';'; |
||
1090 | } |
||
1091 | } |
||
1092 | when ('list') { |
||
1093 | my $len = $e->first_child(); |
||
1094 | my $infosize = $info->{'size'}; |
||
1095 | my $sizemul; |
||
1096 | |||
1097 | given ($len->name()) { |
||
1098 | when ('op') { $sizemul = get_op($len, \%refs); } |
||
1099 | when (['unop','popcount']) { $sizemul = get_unop($len, \%refs); } |
||
1100 | when ('fieldref') { $sizemul = 'f_'.$len->text(); } |
||
1101 | when ('paramref') { $sizemul = 'p_'.$len->text(); } |
||
1102 | when ('value') { |
||
1103 | if ($infosize) { |
||
1104 | $size += $infosize * $len->text(); |
||
1105 | } else { |
||
1106 | $sizemul = $len->text(); |
||
1107 | } |
||
1108 | } |
||
1109 | default { die "Invalid list size: $_\n"; } |
||
1110 | } |
||
1111 | if (defined $sizemul) { |
||
1112 | if ($infosize) { |
||
1113 | say $impl " size += $sizemul * $infosize;"; |
||
1114 | } else { |
||
1115 | say $impl " for (i = 0; i < $sizemul; i++) {"; |
||
1116 | say $impl " off = (*offsetp) + size + $size;"; |
||
1117 | say $impl " size += struct_size_$info->{name}(tvb, &off, byte_order);"; |
||
1118 | say $impl ' }'; |
||
1119 | } |
||
1120 | } |
||
1121 | } |
||
1122 | when ('field') { |
||
1123 | my $fname = $e->att('name'); |
||
1124 | if (defined($refs{$fname})) { |
||
1125 | say $impl " f_$fname = $info->{'get'}(tvb, *offsetp + size + $size);"; |
||
1126 | } |
||
1127 | $size += $info->{'size'}; |
||
1128 | } |
||
1129 | } |
||
1130 | } |
||
1131 | say $impl " return size + $size;"; |
||
1132 | say $impl '}'; |
||
1133 | $size = 0; # 0 means "dynamic calcuation required" |
||
1134 | } |
||
1135 | |||
1136 | print $decl "static int hf_x11_struct_$name = -1;\n"; |
||
1137 | print $reg "{ &hf_x11_struct_$name, { \"$name\", \"x11.struct.$name\", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},\n"; |
||
1138 | |||
1139 | print $impl <<eot |
||
1140 | |||
1141 | static void struct_$name(tvbuff_t *tvb, int *offsetp, proto_tree *root, guint byte_order _U_, int count$prefs) |
||
1142 | { |
||
1143 | int i; |
||
1144 | for (i = 0; i < count; i++) { |
||
1145 | proto_item *item; |
||
1146 | proto_tree *t; |
||
1147 | eot |
||
1148 | ; |
||
1149 | |||
1150 | my $varpat = 'struct_'.$name.'_%s'; |
||
1151 | my $humanpat = "struct.$name.%s"; |
||
1152 | my $refs = { field => {}, sumof => {} }; |
||
1153 | |||
1154 | foreach my $e (@elements) { |
||
1155 | reference_elements($e, $refs); |
||
1156 | } |
||
1157 | foreach my $e (@elements) { |
||
1158 | register_element($e, $varpat, $humanpat, $refs, " "); |
||
1159 | } |
||
1160 | |||
1161 | $prefs = ""; |
||
1162 | foreach my $pref (sort keys %paramrefs) { |
||
1163 | $prefs .= ", p_$pref"; |
||
1164 | } |
||
1165 | |||
1166 | my $sizecalc = $size; |
||
1167 | $size or $sizecalc = "struct_size_$name(tvb, offsetp, byte_order$prefs)"; |
||
1168 | |||
1169 | print $impl <<eot |
||
1170 | |||
1171 | item = proto_tree_add_item(root, hf_x11_struct_$name, tvb, *offsetp, $sizecalc, ENC_NA); |
||
1172 | t = proto_item_add_subtree(item, ett_x11_rectangle); |
||
1173 | eot |
||
1174 | ; |
||
1175 | my $length = 0; |
||
1176 | foreach my $e (@elements) { |
||
1177 | $length = dissect_element($e, $varpat, $humanpat, $length, $refs, 0, " "); |
||
1178 | } |
||
1179 | |||
1180 | print $impl " }\n}\n"; |
||
1181 | $struct{$qualname} = { size => $size, name => $name, paramref => \%paramrefs }; |
||
1182 | $t->purge; |
||
1183 | } |
||
1184 | |||
1185 | sub union { |
||
1186 | # TODO proper dissection |
||
1187 | # |
||
1188 | # Right now, the only extension to use a union is randr. |
||
1189 | # for now, punt. |
||
1190 | my ($t, $elt) = @_; |
||
1191 | my $name = $elt->att('name'); |
||
1192 | my $qualname = qualname($name); |
||
1193 | $type_name{$name} = $qualname; |
||
1194 | |||
1195 | if (defined $struct{$qualname}) { |
||
1196 | $t->purge; |
||
1197 | return; |
||
1198 | } |
||
1199 | |||
1200 | my @elements = $elt->children(qr/field/); |
||
1201 | my @sizes; |
||
1202 | |||
1203 | print(" - Union $name\n"); |
||
1204 | |||
1205 | $name = $qualname; |
||
1206 | $name =~ s/:/_/; |
||
1207 | |||
1208 | # Find union size |
||
1209 | foreach my $e (@elements) { |
||
1210 | my $type = $e->att('type'); |
||
1211 | my $info = getinfo($type); |
||
1212 | |||
1213 | $info->{'size'} > 0 or die ("Error: Union containing variable sized struct $type\n"); |
||
1214 | push @sizes, $info->{'size'}; |
||
1215 | } |
||
1216 | @sizes = sort {$b <=> $a} @sizes; |
||
1217 | my $size = $sizes[0]; |
||
1218 | |||
1219 | print $decl "static int hf_x11_union_$name = -1;\n"; |
||
1220 | print $reg "{ &hf_x11_union_$name, { \"$name\", \"x11.union.$name\", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},\n"; |
||
1221 | |||
1222 | print $impl <<eot |
||
1223 | |||
1224 | static void struct_$name(tvbuff_t *tvb, int *offsetp, proto_tree *root, guint byte_order, int count) |
||
1225 | { |
||
1226 | int i; |
||
1227 | int base = *offsetp; |
||
1228 | for (i = 0; i < count; i++) { |
||
1229 | proto_item *item; |
||
1230 | proto_tree *t; |
||
1231 | eot |
||
1232 | ; |
||
1233 | |||
1234 | my $varpat = 'union_'.$name.'_%s'; |
||
1235 | my $humanpat = "union.$name.%s"; |
||
1236 | my $refs = { field => {}, sumof => {} }; |
||
1237 | |||
1238 | foreach my $e (@elements) { |
||
1239 | reference_elements($e, $refs); |
||
1240 | } |
||
1241 | foreach my $e (@elements) { |
||
1242 | register_element($e, $varpat, $humanpat, $refs, " "); |
||
1243 | } |
||
1244 | |||
1245 | print $impl <<eot |
||
1246 | item = proto_tree_add_item(root, hf_x11_union_$name, tvb, base, $size, ENC_NA); |
||
1247 | t = proto_item_add_subtree(item, ett_x11_rectangle); |
||
1248 | |||
1249 | eot |
||
1250 | ; |
||
1251 | |||
1252 | foreach my $e (@elements) { |
||
1253 | say $impl ' *offsetp = base;'; |
||
1254 | dissect_element($e, $varpat, $humanpat, 0, $refs, 0, " "); |
||
1255 | } |
||
1256 | say $impl " base += $size;"; |
||
1257 | say $impl ' }'; |
||
1258 | say $impl ' *offsetp = base;'; |
||
1259 | say $impl '}'; |
||
1260 | |||
1261 | $struct{$qualname} = { size => $size, name => $name }; |
||
1262 | $t->purge; |
||
1263 | } |
||
1264 | |||
1265 | sub enum { |
||
1266 | my ($t, $elt) = @_; |
||
1267 | my $name = $elt->att('name'); |
||
1268 | my $fullname = $incname[0].'_'.$name; |
||
1269 | |||
1270 | $enum_name{$name} = $fullname; |
||
1271 | $enum_name{$incname[0].':'.$name} = $fullname; |
||
1272 | |||
1273 | if (defined $enum{$fullname}) { |
||
1274 | $t->purge; |
||
1275 | return; |
||
1276 | } |
||
1277 | |||
1278 | my @elements = $elt->children('item'); |
||
1279 | |||
1280 | print(" - Enum $name\n"); |
||
1281 | |||
1282 | my $value = {}; |
||
1283 | my $bit = {}; |
||
1284 | my $rvalue = {}; |
||
1285 | my $rbit = {}; |
||
1286 | $enum{$fullname} = { value => $value, bit => $bit, rbit => $rbit, rvalue => $rvalue }; |
||
1287 | |||
1288 | my $nextvalue = 0; |
||
1289 | |||
1290 | foreach my $e (@elements) { |
||
1291 | my $n = $e->att('name'); |
||
1292 | my $valtype = $e->first_child(qr/value|bit/); |
||
1293 | if (defined $valtype) { |
||
1294 | my $val = int($valtype->text()); |
||
1295 | given ($valtype->name()) { |
||
1296 | when ('value') { |
||
1297 | $$value{$val} = $n; |
||
1298 | $$rvalue{$n} = $val; |
||
1299 | $nextvalue = $val + 1; |
||
1300 | |||
1301 | # Ugly hack to support (temporary, hopefully) ugly |
||
1302 | # hack in xinput:ChangeDeviceProperty |
||
1303 | # Register certain values as bits also |
||
1304 | given ($val) { |
||
1305 | when (8) { |
||
1306 | $$bit{'3'} = $n; |
||
1307 | $$rbit{$n} = 3; |
||
1308 | } |
||
1309 | when (16) { |
||
1310 | $$bit{'4'} = $n; |
||
1311 | $$rbit{$n} = 4; |
||
1312 | } |
||
1313 | when (32) { |
||
1314 | $$bit{'5'} = $n; |
||
1315 | $$rbit{$n} = 5; |
||
1316 | } |
||
1317 | } |
||
1318 | } |
||
1319 | when ('bit') { |
||
1320 | $$bit{$val} = $n; |
||
1321 | $$rbit{$n} = $val; |
||
1322 | } |
||
1323 | } |
||
1324 | } else { |
||
1325 | $$value{$nextvalue} = $n; |
||
1326 | $nextvalue++; |
||
1327 | } |
||
1328 | } |
||
1329 | |||
1330 | $t->purge; |
||
1331 | } |
||
1332 | |||
1333 | sub request { |
||
1334 | my ($t, $elt) = @_; |
||
1335 | my $name = $elt->att('name'); |
||
1336 | |||
1337 | print(" - Request $name\n"); |
||
1338 | $request{$elt->att('opcode')} = $name; |
||
1339 | |||
1340 | my $length = 4; |
||
1341 | my @elements = $elt->children(qr/pad|field|list|switch/); |
||
1342 | |||
1343 | # Wireshark defines _U_ to mean "Unused" (compiler specific define) |
||
1344 | if (!@elements) { |
||
1345 | print $impl <<eot |
||
1346 | |||
1347 | static void $header$name(tvbuff_t *tvb _U_, packet_info *pinfo _U_, int *offsetp _U_, proto_tree *t _U_, guint byte_order _U_, int length _U_) |
||
1348 | { |
||
1349 | eot |
||
1350 | ; |
||
1351 | } else { |
||
1352 | print $impl <<eot |
||
1353 | |||
1354 | static void $header$name(tvbuff_t *tvb, packet_info *pinfo _U_, int *offsetp, proto_tree *t, guint byte_order, int length _U_) |
||
1355 | { |
||
1356 | eot |
||
1357 | ; |
||
1358 | } |
||
1359 | my $varpat = $header.'_'.$name.'_%s'; |
||
1360 | my $humanpat = "$header.$name.%s"; |
||
1361 | my $refs = { field => {}, sumof => {} }; |
||
1362 | |||
1363 | foreach my $e (@elements) { |
||
1364 | reference_elements($e, $refs); |
||
1365 | } |
||
1366 | foreach my $e (@elements) { |
||
1367 | register_element($e, $varpat, $humanpat, $refs); |
||
1368 | } |
||
1369 | |||
1370 | foreach my $e (@elements) { |
||
1371 | if ($e->name() eq 'list' && $name eq 'Render' && $e->att('name') eq 'data' && -e "$mesadir/gl_API.xml") { |
||
1372 | # Special case: Use mesa-generated dissector for 'data' |
||
1373 | print $impl " dispatch_glx_render(tvb, pinfo, offsetp, t, byte_order, (length - $length));\n"; |
||
1374 | } else { |
||
1375 | $length = dissect_element($e, $varpat, $humanpat, $length, $refs, 1); |
||
1376 | } |
||
1377 | } |
||
1378 | |||
1379 | say $impl '}'; |
||
1380 | |||
1381 | my $reply = $elt->first_child('reply'); |
||
1382 | if ($reply) { |
||
1383 | $reply{$elt->att('opcode')} = $name; |
||
1384 | |||
1385 | $varpat = $header.'_'.$name.'_reply_%s'; |
||
1386 | $humanpat = "$header.$name.reply.%s"; |
||
1387 | |||
1388 | @elements = $reply->children(qr/pad|field|list|switch/); |
||
1389 | |||
1390 | # Wireshark defines _U_ to mean "Unused" (compiler specific define) |
||
1391 | if (!@elements) { |
||
1392 | say $impl "static void $header$name"."_Reply(tvbuff_t *tvb _U_, packet_info *pinfo, int *offsetp _U_, proto_tree *t _U_, guint byte_order _U_)\n{"; |
||
1393 | } else { |
||
1394 | say $impl "static void $header$name"."_Reply(tvbuff_t *tvb, packet_info *pinfo, int *offsetp, proto_tree *t, guint byte_order)\n{"; |
||
1395 | } |
||
1396 | say $impl ' int sequence_number;' if (@elements); |
||
1397 | |||
1398 | my $refs = { field => {}, sumof => {} }; |
||
1399 | foreach my $e (@elements) { |
||
1400 | reference_elements($e, $refs); |
||
1401 | } |
||
1402 | |||
1403 | say $impl ' int f_length;' if ($refs->{field}{'length'}); |
||
1404 | say $impl ' int length;' if ($refs->{length}); |
||
1405 | foreach my $e (@elements) { |
||
1406 | register_element($e, $varpat, $humanpat, $refs); |
||
1407 | } |
||
1408 | |||
1409 | say $impl ''; |
||
1410 | say $impl ' col_append_fstr(pinfo->cinfo, COL_INFO, "-'.$name.'");'; |
||
1411 | say $impl ''; |
||
1412 | say $impl ' REPLY(reply);'; |
||
1413 | |||
1414 | my $first = 1; |
||
1415 | my $length = 1; |
||
1416 | foreach my $e (@elements) { |
||
1417 | $length = dissect_element($e, $varpat, $humanpat, $length, $refs); |
||
1418 | if ($first) { |
||
1419 | $first = 0; |
||
1420 | say $impl ' sequence_number = VALUE16(tvb, *offsetp);'; |
||
1421 | say $impl ' proto_tree_add_uint_format(t, hf_x11_reply_sequencenumber, tvb, *offsetp, 2, sequence_number,'; |
||
1422 | say $impl ' "sequencenumber: %d ('.$header.'-'.$name.')", sequence_number);'; |
||
1423 | say $impl ' *offsetp += 2;'; |
||
1424 | |||
1425 | if ($refs->{field}{length}) { |
||
1426 | say $impl ' f_length = VALUE32(tvb, *offsetp);'; |
||
1427 | } |
||
1428 | if ($refs->{length}) { |
||
1429 | say $impl ' length = f_length * 4 + 32;'; |
||
1430 | } |
||
1431 | say $impl ' proto_tree_add_item(t, hf_x11_replylength, tvb, *offsetp, 4, byte_order);'; |
||
1432 | say $impl ' *offsetp += 4;'; |
||
1433 | |||
1434 | $length += 6; |
||
1435 | } |
||
1436 | } |
||
1437 | |||
1438 | say $impl '}'; |
||
1439 | } |
||
1440 | $t->purge; |
||
1441 | } |
||
1442 | |||
1443 | sub defxid(@) { |
||
1444 | my $name; |
||
1445 | while ($name = shift) { |
||
1446 | my $qualname = qualname($name); |
||
1447 | $simpletype{$qualname} = { size => 4, encoding => 'byte_order', type => 'FT_UINT32', base => 'BASE_HEX', get => 'VALUE32', list => 'listOfCard32', }; |
||
1448 | $type_name{$name} = $qualname; |
||
1449 | } |
||
1450 | } |
||
1451 | |||
1452 | sub xidtype { |
||
1453 | my ($t, $elt) = @_; |
||
1454 | my $name = $elt->att('name'); |
||
1455 | |||
1456 | defxid($name); |
||
1457 | |||
1458 | $t->purge; |
||
1459 | } |
||
1460 | |||
1461 | sub typedef { |
||
1462 | my ($t, $elt) = @_; |
||
1463 | my $oldname = $elt->att('oldname'); |
||
1464 | my $newname = $elt->att('newname'); |
||
1465 | my $qualname = qualname($newname); |
||
1466 | |||
1467 | # Duplicate the type |
||
1468 | my $info = get_simple_info($oldname); |
||
1469 | if ($info) { |
||
1470 | $simpletype{$qualname} = $info; |
||
1471 | } elsif ($info = get_struct_info($oldname)) { |
||
1472 | $struct{$qualname} = $info; |
||
1473 | } else { |
||
1474 | die ("$oldname not found while attempting to typedef $newname\n"); |
||
1475 | } |
||
1476 | $type_name{$newname} = $qualname; |
||
1477 | |||
1478 | $t->purge; |
||
1479 | } |
||
1480 | |||
1481 | sub error { |
||
1482 | my ($t, $elt) = @_; |
||
1483 | |||
1484 | my $number = $elt->att('number'); |
||
1485 | if ($number >= 0) { |
||
1486 | my $name = $elt->att('name'); |
||
1487 | print $error " \"$header-$name\",\n"; |
||
1488 | } |
||
1489 | |||
1490 | $t->purge; |
||
1491 | } |
||
1492 | |||
1493 | sub event { |
||
1494 | my ($t, $elt) = @_; |
||
1495 | |||
1496 | my $number = $elt->att('number'); |
||
1497 | $number or return; |
||
1498 | |||
1499 | my $name = $elt->att('name'); |
||
1500 | my $xge = $elt->att('xge'); |
||
1501 | |||
1502 | if ($xge) { |
||
1503 | $genericevent{$number} = $name; |
||
1504 | } else { |
||
1505 | $event{$number} = $name; |
||
1506 | } |
||
1507 | |||
1508 | my $length = 1; |
||
1509 | my @elements = $elt->children(qr/pad|field|list|switch/); |
||
1510 | |||
1511 | # Wireshark defines _U_ to mean "Unused" (compiler specific define) |
||
1512 | if (!@elements) { |
||
1513 | if ($xge) { |
||
1514 | print $impl <<eot |
||
1515 | |||
1516 | static void $header$name(tvbuff_t *tvb _U_, int length _U_, int *offsetp _U_, proto_tree *t _U_, guint byte_order _U_) |
||
1517 | { |
||
1518 | } else { |
||
1519 | print $impl <<eot |
||
1520 | |||
1521 | static void $header$name(tvbuff_t *tvb _U_, int *offsetp _U_, proto_tree *t _U_, guint byte_order _U_) |
||
1522 | { |
||
1523 | eot |
||
1524 | ; |
||
1525 | } |
||
1526 | } else { |
||
1527 | if ($xge) { |
||
1528 | $length = 10; |
||
1529 | print $impl <<eot |
||
1530 | |||
1531 | static void $header$name(tvbuff_t *tvb, int length _U_, int *offsetp, proto_tree *t, guint byte_order) |
||
1532 | { |
||
1533 | eot |
||
1534 | ; |
||
1535 | } else { |
||
1536 | print $impl <<eot |
||
1537 | |||
1538 | static void $header$name(tvbuff_t *tvb, int *offsetp, proto_tree *t, guint byte_order) |
||
1539 | { |
||
1540 | eot |
||
1541 | ; |
||
1542 | } |
||
1543 | } |
||
1544 | |||
1545 | my $varpat = $header.'_'.$name.'_%s'; |
||
1546 | my $humanpat = "$header.$name.%s"; |
||
1547 | my $refs = { field => {}, sumof => {} }; |
||
1548 | |||
1549 | foreach my $e (@elements) { |
||
1550 | reference_elements($e, $refs); |
||
1551 | } |
||
1552 | foreach my $e (@elements) { |
||
1553 | register_element($e, $varpat, $humanpat, $refs); |
||
1554 | } |
||
1555 | |||
1556 | if ($xge) { |
||
1557 | say $impl " proto_tree_add_uint_format(t, hf_x11_minor_opcode, tvb, *offsetp, 2, $number,"; |
||
1558 | say $impl " \"opcode: $name ($number)\");"; |
||
1559 | foreach my $e (@elements) { |
||
1560 | $length = dissect_element($e, $varpat, $humanpat, $length, $refs); |
||
1561 | } |
||
1562 | } else { |
||
1563 | my $first = 1; |
||
1564 | foreach my $e (@elements) { |
||
1565 | $length = dissect_element($e, $varpat, $humanpat, $length, $refs); |
||
1566 | if ($first) { |
||
1567 | $first = 0; |
||
1568 | say $impl " CARD16(event_sequencenumber);"; |
||
1569 | } |
||
1570 | } |
||
1571 | } |
||
1572 | |||
1573 | say $impl "}\n"; |
||
1574 | |||
1575 | $t->purge; |
||
1576 | } |
||
1577 | |||
1578 | sub include_start { |
||
1579 | my ($t, $elt) = @_; |
||
1580 | my $header = $elt->att('header'); |
||
1581 | unshift @incname, $header; |
||
1582 | } |
||
1583 | |||
1584 | sub include_end { |
||
1585 | shift @incname; |
||
1586 | } |
||
1587 | |||
1588 | sub include |
||
1589 | { |
||
1590 | my ($t, $elt) = @_; |
||
1591 | my $include = $elt->text(); |
||
1592 | |||
1593 | print " - Import $include\n"; |
||
1594 | my $xml = XML::Twig->new( |
||
1595 | start_tag_handlers => { |
||
1596 | 'xcb' => \&include_start, |
||
1597 | }, |
||
1598 | twig_roots => { |
||
1599 | 'import' => \&include, |
||
1600 | 'struct' => \&struct, |
||
1601 | 'xidtype' => \&xidtype, |
||
1602 | 'xidunion' => \&xidtype, |
||
1603 | 'typedef' => \&typedef, |
||
1604 | 'enum' => \&enum, |
||
1605 | }, |
||
1606 | end_tag_handlers => { |
||
1607 | 'xcb' => \&include_end, |
||
1608 | }); |
||
1609 | $xml->parsefile("$srcdir/xcbproto/src/$include.xml") or die ("Cannot open $include.xml\n"); |
||
1610 | |||
1611 | $t->purge; |
||
1612 | } |
||
1613 | |||
1614 | |||
1615 | sub xcb_start { |
||
1616 | my ($t, $elt) = @_; |
||
1617 | $header = $elt->att('header'); |
||
1618 | $extname = ($elt->att('extension-name') or $header); |
||
1619 | unshift @incname, $header; |
||
1620 | |||
1621 | print("Extension $extname\n"); |
||
1622 | |||
1623 | undef %request; |
||
1624 | undef %genericevent; |
||
1625 | undef %event; |
||
1626 | undef %reply; |
||
1627 | |||
1628 | %simpletype = (); |
||
1629 | %enum_name = (); |
||
1630 | %type_name = (); |
||
1631 | |||
1632 | print $error "const char *$header"."_errors[] = {\n"; |
||
1633 | } |
||
1634 | |||
1635 | sub xcb { |
||
1636 | my ($t, $elt) = @_; |
||
1637 | |||
1638 | my $xextname = $elt->att('extension-xname'); |
||
1639 | my $lookup_name = $header . "_extension_minor"; |
||
1640 | my $error_name = $header . "_errors"; |
||
1641 | my $event_name = $header . "_events"; |
||
1642 | my $genevent_name = 'NULL'; |
||
1643 | my $reply_name = $header . "_replies"; |
||
1644 | |||
1645 | print $decl "static int hf_x11_$lookup_name = -1;\n\n"; |
||
1646 | |||
1647 | print $impl "static const value_string $lookup_name"."[] = {\n"; |
||
1648 | foreach my $req (sort {$a <=> $b} keys %request) { |
||
1649 | print $impl " { $req, \"$request{$req}\" },\n"; |
||
1650 | } |
||
1651 | print $impl " { 0, NULL }\n"; |
||
1652 | print $impl "};\n"; |
||
1653 | |||
1654 | say $impl "const x11_event_info $event_name".'[] = {'; |
||
1655 | foreach my $e (sort {$a <=> $b} keys %event) { |
||
1656 | say $impl " { \"$header-$event{$e}\", $header$event{$e} },"; |
||
1657 | } |
||
1658 | say $impl ' { NULL, NULL }'; |
||
1659 | say $impl '};'; |
||
1660 | |||
1661 | if (%genericevent) { |
||
1662 | $genevent_name = $header.'_generic_events'; |
||
1663 | say $impl 'static const x11_generic_event_info '.$genevent_name.'[] = {'; |
||
1664 | |||
1665 | for my $val (sort { $a <=> $b } keys %genericevent) { |
||
1666 | say $impl sprintf(" { %3d, %s },", $val, $header.$genericevent{$val}); |
||
1667 | } |
||
1668 | say $impl sprintf(" { %3d, NULL },", 0); |
||
1669 | say $impl '};'; |
||
1670 | say $impl ''; |
||
1671 | } |
||
1672 | |||
1673 | print $impl "static x11_reply_info $reply_name"."[] = {\n"; |
||
1674 | foreach my $e (sort {$a <=> $b} keys %reply) { |
||
1675 | print $impl " { $e, $header$reply{$e}_Reply },\n"; |
||
1676 | } |
||
1677 | print $impl " { 0, NULL }\n"; |
||
1678 | print $impl "};\n"; |
||
1679 | |||
1680 | print $reg "{ &hf_x11_$lookup_name, { \"extension-minor\", \"x11.extension-minor\", FT_UINT8, BASE_DEC, VALS($lookup_name), 0, \"minor opcode\", HFILL }},\n\n"; |
||
1681 | |||
1682 | print $impl <<eot |
||
1683 | |||
1684 | static void dispatch_$header(tvbuff_t *tvb, packet_info *pinfo, int *offsetp, proto_tree *t, guint byte_order) |
||
1685 | { |
||
1686 | int minor, length; |
||
1687 | minor = CARD8($lookup_name); |
||
1688 | length = REQUEST_LENGTH(); |
||
1689 | |||
1690 | col_append_fstr(pinfo->cinfo, COL_INFO, "-%s", |
||
1691 | val_to_str(minor, $lookup_name, |
||
1692 | "<Unknown opcode %d>")); |
||
1693 | switch (minor) { |
||
1694 | eot |
||
1695 | ; |
||
1696 | |||
1697 | foreach my $req (sort {$a <=> $b} keys %request) { |
||
1698 | print $impl " case $req:\n"; |
||
1699 | print $impl " $header$request{$req}(tvb, pinfo, offsetp, t, byte_order, length);\n"; |
||
1700 | print $impl " break;\n"; |
||
1701 | } |
||
1702 | say $impl " /* No need for a default case here, since Unknown is printed above,"; |
||
1703 | say $impl " and UNDECODED() is taken care of by dissect_x11_request */"; |
||
1704 | print $impl " }\n}\n"; |
||
1705 | print $impl <<eot |
||
1706 | |||
1707 | static void register_$header(void) |
||
1708 | { |
||
1709 | set_handler("$xextname", dispatch_$header, $error_name, $event_name, $genevent_name, $reply_name); |
||
1710 | } |
||
1711 | eot |
||
1712 | ; |
||
1713 | |||
1714 | print $error " NULL\n};\n\n"; |
||
1715 | |||
1716 | push @register, $header; |
||
1717 | } |
||
1718 | |||
1719 | sub find_version { |
||
1720 | #my $git = `which git`; |
||
1721 | #chomp($git); |
||
1722 | #-x $git or return 'unknown'; |
||
1723 | |||
1724 | my $lib = shift; |
||
1725 | # this will generate an error on stderr if git isn't in our $PATH |
||
1726 | # but that's OK. The version is still set to 'unknown' in that case |
||
1727 | # and at least the operator could see it. |
||
1728 | my $ver = `git --git-dir=$lib/.git describe --tags`; |
||
1729 | $ver //= 'unknown'; |
||
1730 | chomp $ver; |
||
1731 | return $ver; |
||
1732 | } |
||
1733 | |||
1734 | sub add_generated_header { |
||
1735 | my ($out, $using) = @_; |
||
1736 | my $ver = find_version($using); |
||
1737 | |||
1738 | $using = File::Spec->abs2rel ($using, $srcdir); |
||
1739 | |||
1740 | print $out <<eot |
||
1741 | /* Do not modify this file. */ |
||
1742 | /* It was automatically generated by $script_name |
||
1743 | using $using version $ver */ |
||
1744 | eot |
||
1745 | ; |
||
1746 | |||
1747 | # Add license text |
||
1748 | print $out <<eot |
||
1749 | /* |
||
1750 | * Copyright 2008, 2009, 2013, 2014 Open Text Corporation <pharris[AT]opentext.com> |
||
1751 | * |
||
1752 | * Wireshark - Network traffic analyzer |
||
1753 | * By Gerald Combs <gerald[AT]wireshark.org> |
||
1754 | * Copyright 1998 Gerald Combs |
||
1755 | * |
||
1756 | * This program is free software; you can redistribute it and/or modify |
||
1757 | * it under the terms of the GNU General Public License as published by |
||
1758 | * the Free Software Foundation; either version 2 of the License, or |
||
1759 | * (at your option) any later version. |
||
1760 | * |
||
1761 | * This program is distributed in the hope that it will be useful, |
||
1762 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
1763 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
1764 | * GNU General Public License for more details. |
||
1765 | * |
||
1766 | * You should have received a copy of the GNU General Public License along |
||
1767 | * with this program; if not, write to the Free Software Foundation, Inc., |
||
1768 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||
1769 | */ |
||
1770 | |||
1771 | eot |
||
1772 | ; |
||
1773 | } |
||
1774 | |||
1775 | # initialize core X11 protocol |
||
1776 | # Do this in the Makefile now |
||
1777 | #system('./process-x11-fields.pl < x11-fields'); |
||
1778 | |||
1779 | # Extension implementation |
||
1780 | $impl = new IO::File "> $srcdir/x11-extension-implementation.h" |
||
1781 | or die ("Cannot open $srcdir/x11-extension-implementation.h for writing\n"); |
||
1782 | $error = new IO::File "> $srcdir/x11-extension-errors.h" |
||
1783 | or die ("Cannot open $srcdir/x11-extension-errors.h for writing\n"); |
||
1784 | |||
1785 | add_generated_header($impl, $srcdir . '/xcbproto'); |
||
1786 | add_generated_header($error, $srcdir . '/xcbproto'); |
||
1787 | |||
1788 | # Open the files generated by process-x11-fields.pl for appending |
||
1789 | $reg = new IO::File ">> $srcdir/x11-register-info.h" |
||
1790 | or die ("Cannot open $srcdir/x11-register-info.h for appending\n"); |
||
1791 | $decl = new IO::File ">> $srcdir/x11-declarations.h" |
||
1792 | or die ("Cannot open $srcdir/x11-declarations.h for appending\n"); |
||
1793 | |||
1794 | print $reg "\n/* Generated by $script_name below this line */\n"; |
||
1795 | print $decl "\n/* Generated by $script_name below this line */\n"; |
||
1796 | |||
1797 | # Mesa for glRender |
||
1798 | if (-e "$mesadir/gl_API.xml") { |
||
1799 | $enum = new IO::File "> $srcdir/x11-glx-render-enum.h" |
||
1800 | or die ("Cannot open $srcdir/x11-glx-render-enum.h for writing\n"); |
||
1801 | add_generated_header($enum, $srcdir . '/mesa'); |
||
1802 | print $enum "static const value_string mesa_enum[] = {\n"; |
||
1803 | print $impl '#include "x11-glx-render-enum.h"'."\n\n"; |
||
1804 | |||
1805 | print("Mesa glRender:\n"); |
||
1806 | $header = "glx_render"; |
||
1807 | |||
1808 | my $xml = XML::Twig->new( |
||
1809 | start_tag_handlers => { |
||
1810 | 'category' => \&mesa_category_start, |
||
1811 | }, |
||
1812 | twig_roots => { |
||
1813 | 'category' => \&mesa_category, |
||
1814 | 'enum' => \&mesa_enum, |
||
1815 | 'type' => \&mesa_type, |
||
1816 | 'function' => \&mesa_function, |
||
1817 | }); |
||
1818 | $xml->parsefile("$mesadir/gl_API.xml") or die ("Cannot open gl_API\n"); |
||
1819 | |||
1820 | print $enum " { 0, NULL }\n"; |
||
1821 | print $enum "};\n"; |
||
1822 | $enum->close(); |
||
1823 | |||
1824 | print $decl "static int hf_x11_glx_render_op_name = -1;\n\n"; |
||
1825 | |||
1826 | print $impl "static const value_string glx_render_op_name"."[] = {\n"; |
||
1827 | foreach my $req (sort {$a <=> $b} keys %request) { |
||
1828 | print $impl " { $req, \"gl$request{$req}\" },\n"; |
||
1829 | } |
||
1830 | print $impl " { 0, NULL }\n"; |
||
1831 | print $impl "};\n"; |
||
1832 | |||
1833 | print $reg "{ &hf_x11_glx_render_op_name, { \"render op\", \"x11.glx.render.op\", FT_UINT16, BASE_DEC, VALS(glx_render_op_name), 0, NULL, HFILL }},\n\n"; |
||
1834 | |||
1835 | # Uses ett_x11_list_of_rectangle, since I am unable to see how the subtree type matters. |
||
1836 | print $impl <<eot |
||
1837 | |||
1838 | static void dispatch_glx_render(tvbuff_t *tvb, packet_info *pinfo, int *offsetp, proto_tree *t, guint byte_order, int length) |
||
1839 | { |
||
1840 | while (length >= 4) { |
||
1841 | guint32 op, len; |
||
1842 | int next; |
||
1843 | proto_item *ti; |
||
1844 | proto_tree *tt; |
||
1845 | |||
1846 | len = VALUE16(tvb, *offsetp); |
||
1847 | |||
1848 | op = VALUE16(tvb, *offsetp + 2); |
||
1849 | ti = proto_tree_add_uint(t, hf_x11_glx_render_op_name, tvb, *offsetp, len, op); |
||
1850 | |||
1851 | tt = proto_item_add_subtree(ti, ett_x11_list_of_rectangle); |
||
1852 | |||
1853 | ti = proto_tree_add_item(tt, hf_x11_request_length, tvb, *offsetp, 2, byte_order); |
||
1854 | *offsetp += 2; |
||
1855 | proto_tree_add_item(tt, hf_x11_glx_render_op_name, tvb, *offsetp, 2, byte_order); |
||
1856 | *offsetp += 2; |
||
1857 | |||
1858 | if (len < 4) { |
||
1859 | expert_add_info(pinfo, ti, &ei_x11_request_length); |
||
1860 | /* Eat the rest of the packet, mark it undecoded */ |
||
1861 | len = length; |
||
1862 | op = -1; |
||
1863 | } |
||
1864 | len -= 4; |
||
1865 | |||
1866 | next = *offsetp + len; |
||
1867 | |||
1868 | switch (op) { |
||
1869 | eot |
||
1870 | ; |
||
1871 | foreach my $req (sort {$a <=> $b} keys %request) { |
||
1872 | print $impl " case $req:\n"; |
||
1873 | print $impl " mesa_$request{$req}(tvb, offsetp, tt, byte_order, len);\n"; |
||
1874 | print $impl " break;\n"; |
||
1875 | } |
||
1876 | print $impl " default:\n"; |
||
1877 | print $impl " proto_tree_add_item(tt, hf_x11_undecoded, tvb, *offsetp, len, ENC_NA);\n"; |
||
1878 | print $impl " *offsetp += len;\n"; |
||
1879 | |||
1880 | print $impl " }\n"; |
||
1881 | print $impl " if (*offsetp < next) {\n"; |
||
1882 | print $impl " proto_tree_add_item(tt, hf_x11_unused, tvb, *offsetp, next - *offsetp, ENC_NA);\n"; |
||
1883 | print $impl " *offsetp = next;\n"; |
||
1884 | print $impl " }\n"; |
||
1885 | print $impl " length -= (len + 4);\n"; |
||
1886 | print $impl " }\n}\n"; |
||
1887 | } |
||
1888 | |||
1889 | $enum = new IO::File "> $srcdir/x11-enum.h" |
||
1890 | or die ("Cannot open $srcdir/x11-enum.h for writing\n"); |
||
1891 | add_generated_header($enum, $srcdir . '/xcbproto'); |
||
1892 | print $impl '#include "x11-enum.h"'."\n\n"; |
||
1893 | |||
1894 | # XCB |
||
1895 | foreach my $ext (@reslist) { |
||
1896 | my $xml = XML::Twig->new( |
||
1897 | start_tag_handlers => { |
||
1898 | 'xcb' => \&xcb_start, |
||
1899 | }, |
||
1900 | twig_roots => { |
||
1901 | 'xcb' => \&xcb, |
||
1902 | 'import' => \&include, |
||
1903 | 'request' => \&request, |
||
1904 | 'struct' => \&struct, |
||
1905 | 'union' => \&union, |
||
1906 | 'xidtype' => \&xidtype, |
||
1907 | 'xidunion' => \&xidtype, |
||
1908 | 'typedef' => \&typedef, |
||
1909 | 'error' => \&error, |
||
1910 | 'errorcopy' => \&error, |
||
1911 | 'event' => \&event, |
||
1912 | 'enum' => \&enum, |
||
1913 | }); |
||
1914 | $xml->parsefile($ext) or die ("Cannot open $ext\n"); |
||
1915 | } |
||
1916 | |||
1917 | print $impl "static void register_x11_extensions(void)\n{\n"; |
||
1918 | foreach my $reg (@register) { |
||
1919 | print $impl " register_$reg();\n"; |
||
1920 | } |
||
1921 | print $impl "}\n"; |
||
1922 | |||
1923 | # |
||
1924 | # Editor modelines |
||
1925 | # |
||
1926 | # Local Variables: |
||
1927 | # c-basic-offset: 4 |
||
1928 | # tab-width: 8 |
||
1929 | # indent-tabs-mode: nil |
||
1930 | # End: |
||
1931 | # |
||
1932 | # ex: set shiftwidth=4 tabstop=8 expandtab: |
||
1933 | # :indentSize=4:tabSize=8:noTabs=true: |
||
1934 | # |