Show the "More Fragments" indicator as such, rather than as a "this is
[obnox/wireshark/wip.git] / packet-x11.c
1 /* packet-x11.c
2  * Routines for X11 dissection
3  * Copyright 2000, Christophe Tronche <ch.tronche@computer.org>
4  *
5  * $Id: packet-x11.c,v 1.41 2002/04/17 08:33:08 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from README.developer
12  * 
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * 
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26  */
27
28 /* TODO (in no particular order):
29  *
30  * - keep track of Atom creation by server to be able to display
31  *   non-predefined atoms
32  * - Idem for keysym <-> keycode ???
33  * - Idem for fonts 
34  * - Subtree the request ids (that is x11.create-window.window and
35  *   x11.change-window.window should be  distinct), and add hidden fields
36  *   (so we still have x11.window).
37  * - add hidden fields so we can have x11.circulate-window in addition to
38  *   x11.opcode == 13 (but you could match on x11.opcode == "CirculateWindow"
39  *   now)
40  * - add hidden fields so we have x11.listOfStuff.length
41  * - use a faster scheme that linear list searching for the opcode.
42  * - correct display of Unicode chars.
43  * - Not everything is homogeneous, in particular the handling of items in
44  *   list is a total mess.
45  */
46
47 /* By the way, I wrote a program to generate every request and test
48  * that stuff. If you're interested, you can get it at
49  * http://tronche.com/gui/x/
50  */
51
52 #ifdef HAVE_CONFIG_H
53 # include "config.h"
54 #endif
55
56 #include <assert.h>
57 #include <ctype.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60
61 #ifdef HAVE_SYS_TYPES_H
62 # include <sys/types.h>
63 #endif
64
65 #include <string.h>
66 #include <glib.h>
67 #include <epan/packet.h>
68 #include <epan/conversation.h>
69
70 #include "prefs.h"
71 #include "packet-frame.h"
72
73 #define cVALS(x) (const value_string*)(x)
74
75 /* Initialize the protocol and registered fields */
76 static int proto_x11 = -1;
77
78 #include "x11-declarations.h"
79
80 /* Initialize the subtree pointers */
81 static gint ett_x11 = -1;
82 static gint ett_x11_color_flags = -1;
83 static gint ett_x11_list_of_arc = -1;
84 static gint ett_x11_arc = -1;
85 static gint ett_x11_list_of_atom = -1;
86 static gint ett_x11_list_of_card32 = -1;
87 static gint ett_x11_list_of_color_item = -1;
88 static gint ett_x11_color_item = -1;
89 static gint ett_x11_list_of_keycode = -1;
90 static gint ett_x11_list_of_keysyms = -1;
91 static gint ett_x11_keysym = -1;
92 static gint ett_x11_list_of_point = -1;
93 static gint ett_x11_point = -1;
94 static gint ett_x11_list_of_rectangle = -1;
95 static gint ett_x11_rectangle = -1;
96 static gint ett_x11_list_of_segment = -1;
97 static gint ett_x11_segment = -1;
98 static gint ett_x11_list_of_string8 = -1;
99 static gint ett_x11_list_of_text_item = -1;
100 static gint ett_x11_text_item = -1;
101 static gint ett_x11_gc_value_mask = -1;
102 static gint ett_x11_event_mask = -1;
103 static gint ett_x11_do_not_propagate_mask = -1;
104 static gint ett_x11_set_of_key_mask = -1;
105 static gint ett_x11_pointer_event_mask = -1;
106 static gint ett_x11_window_value_mask = -1;
107 static gint ett_x11_configure_window_mask = -1;
108 static gint ett_x11_keyboard_value_mask = -1;
109
110 /* desegmentation of X11 messages */
111 static gboolean x11_desegment = TRUE;
112
113 static dissector_handle_t data_handle;
114
115 #define TCP_PORT_X11                    6000
116 #define TCP_PORT_X11_2                  6001
117 #define TCP_PORT_X11_3                  6002
118
119 /*
120  * Round a length to a multiple of 4 bytes.
121  */
122 #define ROUND_LENGTH(n) ((((n) + 3)/4) * 4)
123
124 /************************************************************************
125  ***                                                                  ***
126  ***         E N U M   T A B L E S   D E F I N I T I O N S            ***
127  ***                                                                  ***
128  ************************************************************************/
129
130 static const value_string byte_order_vals[] = {
131      { 'B', "Big-endian" },
132      { 'l', "Little-endian" },
133      { 0,   NULL }
134 };
135
136 static const value_string access_mode_vals[] = {
137       { 0, "Disable" },
138       { 1, "Enable" },
139       { 0, NULL }
140 };
141
142 static const value_string all_temporary_vals[] = {
143       { 0, "AllTemporary" },
144       { 0, NULL }
145 };
146
147 static const value_string alloc_vals[] = {
148       { 0, "None" },
149       { 1, "All" },
150       { 0, NULL }
151 };
152
153 static const value_string allow_events_mode_vals[] = {
154       { 0, "AsyncPointer" },
155       { 1, "SyncPointer" },
156       { 2, "ReplayPointer" },
157       { 3, "AsyncKeyboard" },
158       { 4, "SyncKeyboard" },
159       { 5, "ReplayKeyboard" },
160       { 6, "AsyncBoth" },
161       { 7, "SyncBoth" },
162       { 0, NULL }
163 };
164
165 static const value_string arc_mode_vals[] = {
166       { 0, "Chord" },
167       { 1, "PieSlice" },
168       { 0, NULL }
169 };
170
171 static const char *atom_predefined_interpretation[] = {
172       "<error>",
173       "PRIMARY",
174       "SECONDARY",
175       "ARC",
176       "ATOM",
177       "BITMAP",
178       "CARDINAL",
179       "COLORMAP",
180       "CURSOR",
181       "CUT_BUFFER0",
182       "CUT_BUFFER1",
183       "CUT_BUFFER2",
184       "CUT_BUFFER3",
185       "CUT_BUFFER4",
186       "CUT_BUFFER5",
187       "CUT_BUFFER6",
188       "CUT_BUFFER7",
189       "DRAWABLE",
190       "FONT",
191       "INTEGER",
192       "PIXMAP",
193       "POINT",
194       "RECTANGLE",
195       "RESOURCE_MANAGER",
196       "RGB_COLOR_MAP",
197       "RGB_BEST_MAP",
198       "RGB_BLUE_MAP",
199       "RGB_DEFAULT_MAP",
200       "RGB_GRAY_MAP",
201       "RGB_GREEN_MAP",
202       "RGB_RED_MAP",
203       "STRING",
204       "VISUALID",
205       "WINDOW",
206       "WM_COMMAND",
207       "WM_HINTS",
208       "WM_CLIENT_MACHINE",
209       "WM_ICON_NAME",
210       "WM_ICON_SIZE",
211       "WM_NAME",
212       "WM_NORMAL_HINTS",
213       "WM_SIZE_HINTS",
214       "WM_ZOOM_HINTS",
215       "MIN_SPACE",
216       "NORM_SPACE",
217       "MAX_SPACE",
218       "END_SPACE",
219       "SUPERSCRIPT_X",
220       "SUPERSCRIPT_Y",
221       "SUBSCRIPT_X",
222       "SUBSCRIPT_Y",
223       "UNDERLINE_POSITION",
224       "UNDERLINE_THICKNESS",
225       "STRIKEOUT_ASCENT",
226       "STRIKEOUT_DESCENT",
227       "ITALIC_ANGLE",
228       "X_HEIGHT",
229       "QUAD_WIDTH",
230       "WEIGHT",
231       "POINT_SIZE",
232       "RESOLUTION",
233       "COPYRIGHT",
234       "NOTICE",
235       "FONT_NAME",
236       "FAMILY_NAME",
237       "FULL_NAME",
238       "CAP_HEIGHT",
239       "WM_CLASS",
240       "WM_TRANSIENT_FOR",
241 };
242
243 static const value_string auto_repeat_mode_vals[] = {
244       { 0, "Off" },
245       { 1, "On" },
246       { 2, "Default" },
247       { 0, NULL }
248 };
249
250 static const value_string background_pixmap_vals[] = { 
251       { 0, "None" },
252       { 1, "ParentRelative" },
253       { 0, NULL }
254 };
255
256 static const value_string backing_store_vals[] = {
257       { 0, "NotUseful" },
258       { 1, "WhenMapped" },
259       { 2, "Always" },
260       { 0, NULL }
261 };
262
263 static const value_string border_pixmap_vals[] = { 
264       { 0, "CopyFromParent" },
265       { 0, NULL }
266 };
267
268 static const value_string button_vals[] = {
269       { 0x8000, "AnyButton" },
270       { 0, NULL }
271 };
272
273 static const value_string cap_style_vals[] = {
274       { 0, "NotLast" },
275       { 1, "Butt" },
276       { 2, "Round" },
277       { 3, "Projecting" },
278       { 0, NULL }
279 };
280
281 static const value_string class_vals[] = {
282       { 0, "Cursor" },
283       { 1, "Tile" },
284       { 2, "Stipple" },
285       { 0, NULL }
286 };
287
288 static const value_string close_down_mode_vals[] = {
289       { 0, "Destroy" },
290       { 1, "RetainPermanent" },
291       { 2, "RetainTemporary" },
292       { 0, NULL }
293 };
294
295 static const value_string coordinate_mode_vals[] = {
296       { 0, "Origin" },
297       { 1, "Previous" },
298       { 0, NULL }
299 };
300
301 static const value_string direction_vals[] = { 
302       { 0, "RaiseLowest" },
303       { 1, "LowerHighest" },
304       { 0, NULL }
305 };
306
307 #define FAMILY_INTERNET 0
308 #define FAMILY_DECNET   1
309 #define FAMILY_CHAOS    2
310
311 static const value_string family_vals[] = {
312       { FAMILY_INTERNET, "Internet" },
313       { FAMILY_DECNET,   "DECnet" },
314       { FAMILY_CHAOS,    "Chaos" },
315       { 0, NULL }
316 };
317
318 static const value_string fill_rule_vals[] = {
319       { 0, "EvenOdd" },
320       { 1, "Winding" },
321       { 0, NULL }
322 };
323
324 static const value_string fill_style_vals[] = {
325       { 0, "Solid" },
326       { 1, "Tiled" },
327       { 2, "Stippled" },
328       { 3, "OpaqueStippled" },
329       { 0, NULL }
330 };
331
332 static const value_string focus_vals[] = {
333       { 0, "None" },
334       { 1, "PointerRoot" },
335       { 0, NULL }
336 };
337
338 static const value_string function_vals[] = {
339       {  0, "Clear" },
340       {  1, "And" },
341       {  2, "AndReverse" },
342       {  3, "Copy" },
343       {  4, "AndInverted" },
344       {  5, "NoOp" },
345       {  6, "Xor" },
346       {  7, "Or" },
347       {  8, "Nor" },
348       {  9, "Equiv" },
349       { 10, "Invert" },
350       { 11, "OrReverse" },
351       { 12, "CopyInverted" },
352       { 13, "OrInverted" },
353       { 14, "Nand" },
354       { 15, "Set" },  
355       {  0, NULL }
356 };
357
358 static const value_string gravity_vals[] = {
359       {  1, "NorthWest" },
360       {  2, "North" },
361       {  3, "NorthEast" },
362       {  4, "West" },
363       {  5, "Center" },
364       {  6, "East" },
365       {  7, "SouthWest" },
366       {  8, "South" },
367       {  9, "SouthEast" },
368       { 10, "Static" },
369       {  0, NULL }
370 };
371
372 static const value_string image_format_vals[] = {
373       { 0, "Bitmap" },
374       { 1, "XYPixmap" },
375       { 2, "ZPixmap" },
376       { 0, NULL }
377 };
378
379 static const value_string image_pixmap_format_vals[] = {
380       { 1, "XYPixmap" },
381       { 2, "ZPixmap" },
382       { 0, NULL }
383 };
384
385 static const value_string join_style_vals[] = {
386       { 0, "Miter" },
387       { 1, "Round" },
388       { 2, "Bevel" },
389       { 0, NULL }
390 };
391
392 static const value_string key_vals[] = {
393       { 0, "AnyKey" },
394       { 0, NULL }
395 };
396
397 #include "packet-x11-keysym.h"
398
399 static const value_string line_style_vals[] = {
400       { 0, "Solid" },
401       { 1, "OnOffDash" },
402       { 2, "DoubleDash" },
403       { 0, NULL }
404 };
405
406 static const value_string mode_vals[] = {
407       { 0, "Replace" },
408       { 1, "Prepend" },
409       { 2, "Append" },
410       { 0, NULL }
411 };
412
413 static const value_string on_off_vals[] = {
414       { 0, "Off" },
415       { 1, "On" },
416       { 0, NULL }
417 };
418
419 static const value_string opcode_vals[] = {
420       {   1, "CreateWindow" },
421       {   2, "ChangeWindowAttributes" },
422       {   3, "GetWindowAttributes" }, 
423       {   4, "DestroyWindow" },
424       {   5, "DestroySubwindows" },
425       {   6, "ChangeSaveSet" },
426       {   7, "ReparentWindow" },
427       {   8, "MapWindow" },
428       {   9, "MapSubwindows" },
429       {  10, "UnmapWindow" },
430       {  11, "UnmapSubwindows" },
431       {  12, "ConfigureWindow" },
432       {  13, "CirculateWindow" },
433       {  14, "GetGeometry" },
434       {  15, "QueryTree" },
435       {  16, "InternAtom" },
436       {  17, "GetAtomName" },
437       {  18, "ChangeProperty" },
438       {  19, "DeleteProperty" },
439       {  20, "GetProperty" },
440       {  21, "ListProperties" },
441       {  22, "SetSelectionOwner" },
442       {  23, "GetSelectionOwner" },
443       {  24, "ConvertSelection" },
444
445       {  26, "GrabPointer" },
446       {  27, "UngrabPointer" },
447       {  28, "GrabButton" },
448       {  29, "UngrabButton" },
449       {  30, "ChangeActivePointerGrab" },
450       {  31, "GrabKeyboard" },
451       {  32, "UngrabKeyboard" },
452       {  33, "GrabKey" },
453       {  34, "UngrabKey" },
454       {  35, "AllowEvents" },
455       {  36, "GrabServer" },
456       {  37, "UngrabServer" },
457       {  38, "QueryPointer" },
458       {  39, "GetMotionEvents" },
459       {  40, "TranslateCoordinates" },
460       {  41, "WarpPointer" },
461       {  42, "SetInputFocus" },
462       {  43, "GetInputFocus" },
463       {  44, "QueryKeymap" },
464       {  45, "OpenFont" },
465       {  46, "CloseFont" },
466       {  47, "QueryFont" },
467       {  48, "QueryTextExtents" },
468       {  49, "ListFonts" },
469       {  50, "ListFontsWithInfo" },
470       {  51, "SetFontPath" },
471       {  52, "GetFontPath" },
472       {  53, "CreatePixmap" },
473       {  54, "FreePixmap" },
474       {  55, "CreateGC" },
475       {  56, "ChangeGC" },
476       {  57, "CopyGC" },
477       {  58, "SetDashes" },
478       {  59, "SetClipRectangles" },
479       {  60, "FreeGC" },
480       {  61, "ClearArea" },
481       {  62, "CopyArea" },
482       {  63, "CopyPlane" },
483       {  64, "PolyPoint" },
484       {  65, "PolyLine" },
485       {  66, "PolySegment" },
486       {  67, "PolyRectangle" },
487       {  68, "PolyArc" },
488       {  69, "FillPoly" },
489       {  70, "PolyFillRectangle" },
490       {  71, "PolyFillArc" },
491       {  72, "PutImage" },
492       {  73, "GetImage" },
493       {  74, "PolyText8" },
494       {  75, "PolyText16" },
495       {  76, "ImageText8" },
496       {  77, "ImageText16" },
497       {  78, "CreateColormap" },
498       {  79, "FreeColormap" },
499       {  80, "CopyColormapAndFree" },
500       {  81, "InstallColormap" },
501       {  82, "UninstallColormap" },
502       {  83, "ListInstalledColormaps" },
503       {  84, "AllocColor" },
504       {  85, "AllocNamedColor" },
505       {  86, "AllocColorCells" },
506       {  87, "AllocColorPlanes" },
507       {  88, "FreeColors" },
508       {  89, "StoreColors" },
509       {  90, "StoreNamedColor" },
510       {  91, "QueryColors" },
511       {  92, "LookupColor" },
512       {  93, "CreateCursor" },
513       {  94, "CreateGlyphCursor" },
514       {  95, "FreeCursor" },
515       {  96, "RecolorCursor" },
516       {  97, "QueryBestSize" },
517       {  98, "QueryExtension" },
518       {  99, "ListExtensions" },
519       { 100, "ChangeKeyboardMapping" },
520       { 101, "GetKeyboardMapping" },
521       { 102, "ChangeKeyboardControl" },
522       { 103, "GetKeyboardControl" },
523       { 104, "Bell" },
524       { 105, "ChangePointerControl" },
525       { 106, "GetPointerControl" },
526       { 107, "SetScreenSaver" },
527       { 108, "GetScreenSaver" },
528       { 109, "ChangeHosts" },
529       { 110, "ListHosts" },
530       { 111, "SetAccessControl" },
531       { 112, "SetCloseDownMode" },
532       { 113, "KillClient" },
533       { 114, "RotateProperties" },
534       { 115, "ForceScreenSaver" },
535       { 116, "SetPointerMapping" },
536       { 117, "GetPointerMapping" },
537       { 118, "SetModifierMapping" },
538       { 119, "GetModifierMapping" },
539       { 127, "NoOperation" },
540       { 0, NULL }
541 };
542
543 static const value_string ordering_vals[] = {
544       { 0, "UnSorted" },
545       { 1, "YSorted" },
546       { 2, "YXSorted" },
547       { 3, "YXBanded" },
548       { 0, NULL }
549 };
550
551 static const value_string plane_mask_vals[] = {
552       { 0xFFFFFFFF, "AllPlanes" },
553       { 0, NULL }
554 };
555
556 static const value_string pointer_keyboard_mode_vals[] = {
557       { 0, "Synchronous" },
558       { 1, "Asynchronous" },
559       { 0, NULL }
560 };
561
562 static const value_string revert_to_vals[] = {
563       { 0, "None" },
564       { 1, "PointerRoot" },
565       { 2, "Parent" },
566       { 0, NULL }
567 };
568
569 static const value_string insert_delete_vals[] = {
570       { 0, "Insert" },
571       { 1, "Delete" },
572       { 0, NULL }
573 };
574
575 static const value_string screen_saver_mode_vals[] = {
576       { 0, "Reset" },
577       { 1, "Activate" },
578       { 0, NULL }
579 };
580
581 static const value_string shape_vals[] = {
582       { 0, "Complex" },
583       { 1, "Nonconvex" },
584       { 2, "Convex" },
585       { 0, NULL }
586 };
587
588 static const value_string stack_mode_vals[] = {
589       { 0, "Above" },
590       { 1, "Below" },
591       { 2, "TopIf" },
592       { 3, "BottomIf" },
593       { 4, "Opposite" },
594       { 0, NULL }
595 };
596
597 static const value_string subwindow_mode_vals[] = {
598       { 0, "ClipByChildren" },
599       { 1, "IncludeInferiors" },
600       { 0, NULL }
601 };
602
603 static const value_string window_class_vals[] = {
604       { 0, "CopyFromParent" },
605       { 1, "InputOutput" },
606       { 2, "InputOnly" },
607       { 0, NULL }
608 };
609
610 static const value_string yes_no_default_vals[] = {
611       { 0, "No" },
612       { 1, "Yes" },
613       { 2, "Default" },
614       { 0, NULL }
615 };
616
617 static const value_string zero_is_any_property_type_vals[] = {
618       { 0, "AnyPropertyType" },
619       { 0, NULL }
620 };
621
622 static const value_string zero_is_none_vals[] = {
623       { 0, "None" },
624       { 0, NULL }
625 };
626
627 /************************************************************************
628  ***                                                                  ***
629  ***         G L O B A L   V A R I A B L E S   ( A R G H H ! )        ***
630  ***                                                                  ***
631  ************************************************************************/
632
633 static gboolean little_endian = TRUE;
634
635 /************************************************************************
636  ***                                                                  ***
637  ***           F I E L D   D E C O D I N G   M A C R O S              ***
638  ***                                                                  ***
639  ************************************************************************/
640
641 #define VALUE8(tvb, offset) (tvb_get_guint8(tvb, offset))
642 #define VALUE16(tvb, offset) (little_endian ? tvb_get_letohs(tvb, offset) : tvb_get_ntohs(tvb, offset))
643 #define VALUE32(tvb, offset) (little_endian ? tvb_get_letohl(tvb, offset) : tvb_get_ntohl(tvb, offset))
644
645 #define FIELD8(name)  (field8(tvb, offsetp, t, hf_x11_##name))
646 #define FIELD16(name) (field16(tvb, offsetp, t, hf_x11_##name))
647 #define FIELD32(name) (field32(tvb, offsetp, t, hf_x11_##name))
648
649 #define BITFIELD(TYPE, position, name) {\
650   int unused;\
651   int save = *offsetp;\
652   proto_tree_add_item(bitmask_tree, hf_x11_##position##_##name, tvb, bitmask_offset, \
653                       bitmask_size, little_endian); \
654   if (bitmask_value & proto_registrar_get_nth(hf_x11_##position##_##name) -> bitmask) {\
655        TYPE(name);\
656        unused = save + 4 - *offsetp;\
657        if (unused)\
658            proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, unused, little_endian);\
659        *offsetp = save + 4;\
660  }\
661 }
662
663 #define FLAG(position, name) {\
664        proto_tree_add_boolean(bitmask_tree, hf_x11_##position##_mask##_##name, tvb, bitmask_offset, bitmask_size, bitmask_value); }
665
666 #define FLAG_IF_NONZERO(position, name) {\
667   if (bitmask_value & proto_registrar_get_nth(hf_x11_##position##_mask##_##name) -> bitmask)\
668        proto_tree_add_boolean(bitmask_tree, hf_x11_##position##_mask##_##name, tvb, bitmask_offset, bitmask_size, bitmask_value); }
669
670 #define ATOM(name)     { atom(tvb, offsetp, t, hf_x11_##name); }
671 #define BITGRAVITY(name) { gravity(tvb, offsetp, t, #name, hf_x11_##name, "Forget"); }
672 #define BITMASK(name, size) {\
673       proto_item *ti; \
674       guint32 bitmask_value; \
675       int bitmask_offset; \
676       int bitmask_size; \
677       proto_tree *bitmask_tree; \
678       bitmask_value = ((size == 1) ? VALUE8(tvb, *offsetp) : \
679                        ((size == 2) ? VALUE16(tvb, *offsetp) : \
680                                       VALUE32(tvb, *offsetp))); \
681       bitmask_offset = *offsetp; \
682       bitmask_size = size; \
683       ti = proto_tree_add_uint(t, hf_x11_##name##_mask, tvb, *offsetp, size, bitmask_value); \
684       bitmask_tree = proto_item_add_subtree(ti, ett_x11_##name##_mask); \
685       *offsetp += size;
686 #define ENDBITMASK      }
687 #define BITMASK8(name)  BITMASK(name, 1);
688 #define BITMASK16(name) BITMASK(name, 2);
689 #define BITMASK32(name) BITMASK(name, 4);
690 #define BOOL(name)     (add_boolean(tvb, offsetp, t, hf_x11_##name))
691 #define BUTTON(name)   { FIELD8(name); }
692 #define CARD8(name)    { FIELD8(name); }
693 #define CARD16(name)   (FIELD16(name))
694 #define CARD32(name)   (FIELD32(name))
695 #define COLOR_FLAGS(name) { colorFlags(tvb, offsetp, t); }
696 #define COLORMAP(name) { FIELD32(name); }
697 #define CURSOR(name)   { FIELD32(name); }
698 #define DRAWABLE(name) { FIELD32(name); }
699 #define ENUM8(name)    (FIELD8(name))
700 #define ENUM16(name)   { FIELD16(name); }
701 #define FONT(name)     { FIELD32(name); }
702 #define FONTABLE(name) { FIELD32(name); }
703 #define GCONTEXT(name) { FIELD32(name); }
704 #define INT8(name)     { FIELD8(name); }
705 #define INT16(name)    { FIELD16(name); }
706 #define KEYCODE(name)  { FIELD8(name); }
707 #define LISTofARC(name) { listOfArc(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 12); }
708 #define LISTofATOM(name, length) { listOfAtom(tvb, offsetp, t, hf_x11_##name, (length) / 4); }
709 #define LISTofBYTE(name, length) { listOfByte(tvb, offsetp, t, hf_x11_##name, (length)); }
710 #define LISTofCARD8(name, length) { listOfByte(tvb, offsetp, t, hf_x11_##name, (length)); }
711 #define LISTofCARD32(name, length) { listOfCard32(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_item, (length) / 4); }
712 #define LISTofCOLORITEM(name, length) { listOfColorItem(tvb, offsetp, t, hf_x11_##name, (length) / 12); }
713 #define LISTofKEYCODE(name, length) { listOfKeycode(tvb, offsetp, t, hf_x11_##name, (length)); }
714 #define LISTofKEYSYM(name, keycode_count, keysyms_per_keycode) { \
715       listOfKeysyms(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_item, (keycode_count), (keysyms_per_keycode)); }
716 #define LISTofPOINT(name, length) { listOfPoint(tvb, offsetp, t, hf_x11_##name, (length) / 4); }
717 #define LISTofRECTANGLE(name) { listOfRectangle(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 8); }
718 #define LISTofSEGMENT(name) { listOfSegment(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 8); }
719 #define LISTofSTRING8(name, length) { listOfString8(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_string, (length)); }
720 #define LISTofTEXTITEM8(name) { listOfTextItem(tvb, offsetp, t, hf_x11_##name, FALSE, next_offset); }
721 #define LISTofTEXTITEM16(name) { listOfTextItem(tvb, offsetp, t, hf_x11_##name, TRUE, next_offset); }
722 #define OPCODE()       { opcode = FIELD8(opcode); }
723 #define PIXMAP(name)   { FIELD32(name); }
724 #define REQUEST_LENGTH() (requestLength(tvb, offsetp, t))
725 #define SETofEVENT(name) { setOfEvent(tvb, offsetp, t); }
726 #define SETofDEVICEEVENT(name) { setOfDeviceEvent(tvb, offsetp, t);}
727 #define SETofKEYMASK(name) { setOfKeyMask(tvb, offsetp, t); }
728 #define SETofPOINTEREVENT(name) { setOfPointerEvent(tvb, offsetp, t); }
729 #define STRING8(name, length)  { string8(tvb, offsetp, t, #name, hf_x11_##name, length); }
730 #define STRING16(name, length)  { string16(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_bytes, length); }
731 #define TIMESTAMP(name){ timestamp(tvb, offsetp, t, #name, hf_x11_##name); }
732 #define UNDECODED(x)   { proto_tree_add_item(t, hf_x11_undecoded, tvb, *offsetp,  x, little_endian); *offsetp += x; }
733 #define UNUSED(x)      { proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp,  x, little_endian); *offsetp += x; }
734 #define PAD()          { if (next_offset - *offsetp > 0) proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, next_offset - *offsetp, little_endian); *offsetp = next_offset; }
735 #define WINDOW(name)   { FIELD32(name); }
736 #define WINGRAVITY(name) { gravity(tvb, offsetp, t, #name, hf_x11_##name, "Unmap"); }
737
738 #define VISUALID(name) { gint32 v = VALUE32(tvb, *offsetp); \
739     proto_tree_add_uint_format(t, hf_x11_##name, tvb, *offsetp, 4, v, "Visualid: 0x%08x%s", v, \
740                                v ? "" : " (CopyFromParent)"); *offsetp += 4; }
741
742 /************************************************************************
743  ***                                                                  ***
744  ***                  D E C O D I N G   F I E L D S                   ***
745  ***                                                                  ***
746  ************************************************************************/
747
748 static void atom(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
749 {
750       const char *interpretation = NULL;
751
752       guint32 v = VALUE32(tvb, *offsetp);
753       if (v >= 1 && v < array_length(atom_predefined_interpretation))
754             interpretation = atom_predefined_interpretation[v];
755       else if (v)
756             interpretation = "Not a predefined atom";
757       else {
758             header_field_info *hfi = proto_registrar_get_nth(hf);
759             if (hfi -> strings)
760                   interpretation = match_strval(v, cVALS(hfi -> strings));
761       }
762       if (!interpretation) interpretation = "error in Xlib client program ?";
763       proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v, "%s: %u (%s)", 
764                                  proto_registrar_get_nth(hf) -> name, v, interpretation);
765       *offsetp += 4;
766 }
767
768 static guint32 add_boolean(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
769 {
770       guint32 v = VALUE8(tvb, *offsetp);
771       proto_tree_add_boolean(t, hf, tvb, *offsetp, 1, v);
772       *offsetp += 1;
773       return v;
774 }
775
776 static void colorFlags(tvbuff_t *tvb, int *offsetp, proto_tree *t)
777 {
778       unsigned do_red_green_blue = VALUE8(tvb, *offsetp);
779       proto_item *ti;
780       proto_tree *tt;
781       
782       if (do_red_green_blue) {
783             int sep = FALSE;
784             char buffer[512];
785             char *bp = buffer + sprintf(buffer, "flags: ");
786
787             if (do_red_green_blue & 0x1) {
788                   bp += sprintf(bp, "DoRed");
789                   sep = TRUE;
790             }
791
792             if (do_red_green_blue & 0x2) {
793                   if (sep) bp += sprintf(bp, " | ");
794                   bp += sprintf(bp, "DoGreen");
795                   sep = TRUE;
796             }
797
798             if (do_red_green_blue & 0x4) {
799                   if (sep) bp += sprintf(bp, " | ");
800                   bp += sprintf(bp, "DoBlue");
801                   sep = TRUE;
802             }
803
804             if (do_red_green_blue & 0xf8) {
805                   if (sep) bp += sprintf(bp, " + ");
806                   sprintf(bp, "trash");
807             }
808
809             ti = proto_tree_add_uint_format(t, hf_x11_coloritem_flags, tvb, *offsetp, 1, do_red_green_blue,
810                                             "%s", buffer);
811             tt = proto_item_add_subtree(ti, ett_x11_color_flags);
812             if (do_red_green_blue & 0x1)
813                   proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_red, tvb, *offsetp, 1, 
814                                          do_red_green_blue & 0x1);
815             if (do_red_green_blue & 0x2)
816                   proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_green, tvb, *offsetp, 1, 
817                                          do_red_green_blue & 0x2);
818             if (do_red_green_blue & 0x4)
819                   proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_blue, tvb, *offsetp, 1, 
820                                          do_red_green_blue & 0x4);
821             if (do_red_green_blue & 0xf8)
822                   proto_tree_add_boolean(tt, hf_x11_coloritem_flags_unused, tvb, *offsetp, 1, 
823                                          do_red_green_blue & 0xf8);
824       } else
825             proto_tree_add_uint_format(t, hf_x11_coloritem_flags, tvb, *offsetp, 1, do_red_green_blue,
826                                        "flags: none");
827       *offsetp += 1;
828 }
829
830 static void gravity(tvbuff_t *tvb, int *offsetp, proto_tree *t,
831     const char *nameAsChar, int hf, const char *nullInterpretation)
832 {
833       guint8 v = VALUE8(tvb, *offsetp);
834       if (!v)
835             proto_tree_add_uint_format(t, hf, tvb, *offsetp, 1, v, "%s: 0 (%s)", nameAsChar, 
836                                        nullInterpretation);
837       else
838             proto_tree_add_uint(t, hf, tvb, *offsetp, 1, v);
839       *offsetp += 1;
840 }
841
842 static void listOfArc(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
843     int length)
844 {
845       proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
846       proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_arc);
847       while(length--) {
848             gint16 x = VALUE16(tvb, *offsetp);
849             gint16 y = VALUE16(tvb, *offsetp + 2);
850             guint16 width = VALUE16(tvb, *offsetp + 4);
851             guint16 height = VALUE16(tvb, *offsetp + 6);
852             gint16 angle1 = VALUE16(tvb, *offsetp + 8);
853             gint16 angle2 = VALUE16(tvb, *offsetp + 10);
854
855             proto_item *tti = proto_tree_add_none_format(tt, hf_x11_arc, tvb, *offsetp, 12, 
856                                                              "arc: %dx%d+%d+%d, angle %d -> %d (%f degrees -> %f degrees)",
857                                                              width, height, x, y, angle1, angle2,
858                                                              angle1 / 64.0, angle2 / 64.0);
859             proto_tree *ttt = proto_item_add_subtree(tti, ett_x11_arc);
860             proto_tree_add_int(ttt, hf_x11_arc_x, tvb, *offsetp, 2, x);
861             *offsetp += 2;
862             proto_tree_add_int(ttt, hf_x11_arc_y, tvb, *offsetp, 2, y);
863             *offsetp += 2;
864             proto_tree_add_uint(ttt, hf_x11_arc_width, tvb, *offsetp, 2, y);
865             *offsetp += 2;
866             proto_tree_add_uint(ttt, hf_x11_arc_height, tvb, *offsetp, 2, y);
867             *offsetp += 2;
868             proto_tree_add_int(ttt, hf_x11_arc_angle1, tvb, *offsetp, 2, y);
869             *offsetp += 2;
870             proto_tree_add_int(ttt, hf_x11_arc_angle2, tvb, *offsetp, 2, y);
871             *offsetp += 2;
872       }
873 }
874
875 static void listOfAtom(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
876     int length)
877 {
878       proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, little_endian);
879       proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_atom);
880       while(length--)
881             atom(tvb, offsetp, tt, hf_x11_properties_item);
882 }
883
884 static void listOfByte(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
885     int length)
886 {
887       if (length <= 0) length = 1;
888       proto_tree_add_item(t, hf, tvb, *offsetp, length, little_endian);
889       *offsetp += length;
890 }
891
892 static void listOfCard32(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
893     int hf_item, int length)
894 {
895       proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, little_endian);
896       proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_card32);
897       while(length--) {
898             proto_tree_add_uint(tt, hf_item, tvb, *offsetp, 4, VALUE32(tvb, *offsetp));
899             *offsetp += 4;
900       }
901 }
902
903 static void listOfColorItem(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
904     int length)
905 {
906       proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
907       proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_color_item);
908       while(length--) {
909             proto_item *tti;
910             proto_tree *ttt;
911             unsigned do_red_green_blue;
912             guint16 red, green, blue;
913             char buffer[1024];
914             char *bp;
915             const char *sep;
916
917             red = VALUE16(tvb, *offsetp + 4);
918             green = VALUE16(tvb, *offsetp + 6);
919             blue = VALUE16(tvb, *offsetp + 8);
920             do_red_green_blue = VALUE8(tvb, *offsetp + 10);
921
922             bp = buffer + sprintf(buffer, "colorItem: ");
923             sep = "";
924             if (do_red_green_blue & 0x1) {
925                 bp += sprintf(bp, "red = %d", red);
926                 sep = ", ";
927             }
928             if (do_red_green_blue & 0x2) {
929                 bp += sprintf(bp, "%sgreen = %d", sep, green);
930                 sep = ", ";
931             }
932             if (do_red_green_blue & 0x4)
933                 bp += sprintf(bp, "%sblue = %d", sep, blue);
934
935             tti = proto_tree_add_none_format(tt, hf_x11_coloritem, tvb, *offsetp, 12, "%s", buffer);
936             ttt = proto_item_add_subtree(tti, ett_x11_color_item);
937             proto_tree_add_item(ttt, hf_x11_coloritem_pixel, tvb, *offsetp, 4, little_endian);
938             *offsetp += 4;
939             proto_tree_add_item(ttt, hf_x11_coloritem_red, tvb, *offsetp, 2, little_endian);
940             *offsetp += 2;
941             proto_tree_add_item(ttt, hf_x11_coloritem_green, tvb, *offsetp, 2, little_endian);
942             *offsetp += 2;
943             proto_tree_add_item(ttt, hf_x11_coloritem_blue, tvb, *offsetp, 2, little_endian);
944             *offsetp += 2;
945             colorFlags(tvb, offsetp, ttt);
946             proto_tree_add_item(ttt, hf_x11_coloritem_unused, tvb, *offsetp, 1, little_endian);
947             *offsetp += 1;
948       }
949 }
950
951 static GTree *keysymTable = NULL;
952
953 static gint compareGuint32(gconstpointer a, gconstpointer b)
954 {
955       return GPOINTER_TO_INT(b) - GPOINTER_TO_INT(a);;
956 }
957
958 static const char *keysymString(guint32 v)
959 {
960       gpointer res;
961       if (!keysymTable) {
962
963             /* This table is so big that we built it only if necessary */
964
965             const value_string *p = keysym_vals_source;
966             keysymTable = g_tree_new(compareGuint32);
967             for(; p -> strptr; p++)
968                   g_tree_insert(keysymTable, GINT_TO_POINTER(p -> value), p -> strptr);
969       }
970       res = g_tree_lookup(keysymTable, GINT_TO_POINTER(v));
971       return res ? res : "Unknown";
972 }
973
974 static const char *modifiers[] = { "Shift", "Lock", "Control", "Mod1", "Mod2", "Mod3", "Mod4", "Mod5" };
975
976 static void listOfKeycode(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
977     int length)
978 {
979       char buffer[1024];
980       proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
981       proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_keycode);
982
983       while(length--) {
984             char *bp = buffer;
985             const char **m;
986             int i;
987
988             for(i = 8, m = modifiers; i; i--, m++) {
989                 u_char c = tvb_get_guint8(tvb, *offsetp);
990                 *offsetp += 1;
991                 if (c)
992                     bp += sprintf(bp, "  %s=%d", *m, c);
993             }
994
995             proto_tree_add_bytes_format(tt, hf_x11_keycodes_item, tvb, *offsetp - 8, 8, tvb_get_ptr(tvb, *offsetp - 8, 8),      "item: %s", buffer);
996       }
997 }
998
999 static void listOfKeysyms(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1000     int hf_item, int keycode_count, int keysyms_per_keycode)
1001 {
1002       proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, keycode_count * keysyms_per_keycode * 4, little_endian);
1003       proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_keysyms);
1004       proto_item *tti;
1005       proto_tree *ttt;
1006       int i;
1007
1008       while(keycode_count--) {
1009             tti = proto_tree_add_none_format(tt, hf_item, tvb, *offsetp, keysyms_per_keycode * 4,
1010                                                  "keysyms:");
1011             ttt = proto_item_add_subtree(tti, ett_x11_keysym);
1012             for(i = keysyms_per_keycode; i; i--) {
1013                   guint32 v = VALUE32(tvb, *offsetp);
1014                   proto_item_append_text(tti, " %s", keysymString(v));
1015                   proto_tree_add_uint_format(ttt, hf_x11_keysyms_item_keysym, tvb, *offsetp, 4, v,
1016                                              "keysym: 0x%08x (%s)", v, keysymString(v));
1017                   *offsetp += 4;
1018             }
1019       }
1020 }
1021
1022 static void listOfPoint(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, int length)
1023 {
1024       proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, little_endian);
1025       proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_point);
1026       while(length--) {
1027             gint16 x, y;
1028             proto_item *tti;
1029             proto_tree *ttt;
1030
1031             x = VALUE16(tvb, *offsetp);
1032             y = VALUE16(tvb, *offsetp + 2);
1033
1034             tti = proto_tree_add_none_format(tt, hf_x11_point, tvb, *offsetp, 4, "point: (%d,%d)", x, y);
1035             ttt = proto_item_add_subtree(tti, ett_x11_point);
1036             proto_tree_add_int(ttt, hf_x11_point_x, tvb, *offsetp, 2, x);
1037             *offsetp += 2;
1038             proto_tree_add_int(ttt, hf_x11_point_y, tvb, *offsetp, 2, y);
1039             *offsetp += 2;
1040       }
1041 }
1042
1043 static void listOfRectangle(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1044     int length)
1045 {
1046       proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
1047       proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_rectangle);
1048       while(length--) {
1049             gint16 x, y;
1050             unsigned width, height;
1051             proto_item *tti;
1052             proto_tree *ttt;
1053
1054             x = VALUE16(tvb, *offsetp);
1055             y = VALUE16(tvb, *offsetp + 2);
1056             width = VALUE16(tvb, *offsetp + 4);
1057             height = VALUE16(tvb, *offsetp + 6);
1058
1059             tti = proto_tree_add_none_format(tt, hf_x11_rectangle, tvb, *offsetp, 8, 
1060                                                  "rectangle: %dx%d+%d+%d", width, height, x, y);
1061             ttt = proto_item_add_subtree(tti, ett_x11_rectangle);
1062             proto_tree_add_int(ttt, hf_x11_rectangle_x, tvb, *offsetp, 2, x);
1063             *offsetp += 2;
1064             proto_tree_add_int(ttt, hf_x11_rectangle_y, tvb, *offsetp, 2, y);
1065             *offsetp += 2;
1066             proto_tree_add_uint(ttt, hf_x11_rectangle_width, tvb, *offsetp, 2, width);
1067             *offsetp += 2;
1068             proto_tree_add_uint(ttt, hf_x11_rectangle_height, tvb, *offsetp, 2, height);
1069             *offsetp += 2;
1070       }
1071 }
1072
1073 static void listOfSegment(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1074     int length)
1075 {
1076       proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
1077       proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_segment);
1078       while(length--) {
1079             gint16 x1, y1, x2, y2;
1080             proto_item *tti;
1081             proto_tree *ttt;
1082
1083             x1 = VALUE16(tvb, *offsetp);
1084             y1 = VALUE16(tvb, *offsetp + 2);
1085             x2 = VALUE16(tvb, *offsetp + 4);
1086             y2 = VALUE16(tvb, *offsetp + 6);
1087
1088             tti = proto_tree_add_none_format(tt, hf_x11_segment, tvb, *offsetp, 8, 
1089                                                  "segment: (%d,%d)-(%d,%d)", x1, y1, x2, y2);
1090             ttt = proto_item_add_subtree(tti, ett_x11_segment);
1091             proto_tree_add_item(ttt, hf_x11_segment_x1, tvb, *offsetp, 2, little_endian);
1092             *offsetp += 2;
1093             proto_tree_add_item(ttt, hf_x11_segment_y1, tvb, *offsetp, 2, little_endian);
1094             *offsetp += 2;
1095             proto_tree_add_item(ttt, hf_x11_segment_x2, tvb, *offsetp, 2, little_endian);
1096             *offsetp += 2;
1097             proto_tree_add_item(ttt, hf_x11_segment_y2, tvb, *offsetp, 2, little_endian);
1098             *offsetp += 2;
1099       }
1100 }
1101
1102 /* XXX - the protocol tree code should handle non-printable characters.
1103    Note that "non-printable characters" may depend on your locale.... */
1104 static void stringCopy(char *dest, const char *source, int length)
1105 {
1106       u_char c;
1107       while(length--) {
1108             c = *source++;
1109             if (!isgraph(c) && c != ' ') c = '.';
1110             *dest++ = c;
1111       }
1112       *dest++ = '\0';
1113 }
1114
1115 static void listOfString8(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1116     int hf_item, int length)
1117 {
1118       char *s = NULL;
1119       guint allocated = 0;
1120       proto_item *ti;
1121       proto_tree *tt;
1122       int i;
1123
1124       /* Compute total length */
1125       
1126       int scanning_offset = *offsetp; /* Scanning pointer */
1127       int l;
1128       for(i = length; i; i--) {
1129             l = tvb_get_guint8(tvb, scanning_offset);
1130             scanning_offset += 1 + l;
1131       }
1132
1133       ti = proto_tree_add_item(t, hf, tvb, *offsetp, scanning_offset - *offsetp, little_endian);
1134       tt = proto_item_add_subtree(ti, ett_x11_list_of_string8);
1135
1136       /*
1137        * In case we throw an exception, clean up whatever stuff we've
1138        * allocated (if any).
1139        */
1140       CLEANUP_PUSH(g_free, s);
1141
1142       while(length--) {
1143             unsigned l = VALUE8(tvb, *offsetp);
1144             if (allocated < (l + 1)) {
1145                   /* g_realloc doesn't work ??? */
1146                   g_free(s);
1147                   s = g_malloc(l + 1);
1148                   allocated = l + 1;
1149             }
1150             stringCopy(s, tvb_get_ptr(tvb, *offsetp + 1, l), l); /* Nothing better for now. We need a better string handling API. */
1151             proto_tree_add_string_format(tt, hf_item, tvb, *offsetp, l + 1, s, "\"%s\"", s);
1152             *offsetp += l + 1;
1153       }
1154
1155       /*
1156        * Call the cleanup handler to free the string and pop the handler.
1157        */
1158       CLEANUP_CALL_AND_POP;
1159 }
1160
1161 #define STRING16_MAX_DISPLAYED_LENGTH 150
1162
1163 static int stringIsActuallyAn8BitString(tvbuff_t *tvb, int offset, unsigned length)
1164 {
1165       if (length > STRING16_MAX_DISPLAYED_LENGTH) length = STRING16_MAX_DISPLAYED_LENGTH;
1166       for(; length > 0; offset += 2, length--) {
1167             if (tvb_get_guint8(tvb, offset))
1168                 return FALSE;
1169       }
1170       return TRUE;
1171 }
1172
1173 /* length is the length of the _byte_zone_ (that is, twice the length of the string) */
1174
1175 static void string16_with_buffer_preallocated(tvbuff_t *tvb, proto_tree *t,
1176                                               int hf, int hf_bytes,
1177                                               int offset, unsigned length,
1178                                               char **s, int *sLength)
1179 {
1180       int truncated = FALSE;
1181       unsigned l = length / 2;
1182
1183       if (stringIsActuallyAn8BitString(tvb, offset, l)) {
1184             char *dp;
1185             int soffset = offset;
1186
1187             if (l > STRING16_MAX_DISPLAYED_LENGTH) {
1188                   truncated = TRUE;
1189                   l = STRING16_MAX_DISPLAYED_LENGTH;
1190             }
1191             if (*sLength < (int) l + 3) {
1192                   g_free(*s);
1193                   *s = g_malloc(l + 3);
1194                   *sLength = l + 3;
1195             }
1196             dp = *s;
1197             *dp++ = '"';
1198             if (truncated) l -= 3;
1199
1200             while(l--) {
1201                   soffset++;
1202                   *dp++ = tvb_get_guint8(tvb, soffset);
1203                   soffset++;
1204             }
1205             *dp++ = '"';
1206
1207             /* If truncated, add an ellipsis */
1208             if (truncated) { *dp++ = '.'; *dp++ = '.'; *dp++ = '.'; }
1209
1210             *dp++ = '\0';
1211             proto_tree_add_string_format(t, hf, tvb, offset, length, tvb_get_ptr(tvb, offset, length), "%s: %s", 
1212                                         proto_registrar_get_nth(hf) -> name, *s);
1213       } else
1214             proto_tree_add_item(t, hf_bytes, tvb, offset, length, little_endian);
1215
1216 }
1217
1218 static void listOfTextItem(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1219     int sizeIs16, int next_offset)
1220 {
1221       int allocated = 0;
1222       char *s = NULL;
1223       proto_item *ti;
1224       proto_tree *tt;
1225       guint32 fid;
1226
1227       /* Compute total length */
1228       
1229       int scanning_offset = *offsetp; /* Scanning pointer */
1230       int l;                            /* Length of an individual item */
1231       int n = 0;                        /* Number of items */
1232
1233       while(scanning_offset < next_offset) {
1234             l = tvb_get_guint8(tvb, scanning_offset);
1235             scanning_offset++;
1236             if (!l) break;
1237             n++;
1238             scanning_offset += l == 255 ? 4 : l + (sizeIs16 ? l : 0) + 1;
1239       }
1240
1241       ti = proto_tree_add_item(t, hf, tvb, *offsetp, scanning_offset - *offsetp, little_endian);
1242       tt = proto_item_add_subtree(ti, ett_x11_list_of_text_item);
1243
1244       /*
1245        * In case we throw an exception, clean up whatever stuff we've
1246        * allocated (if any).
1247        */
1248       CLEANUP_PUSH(g_free, s);
1249
1250       while(n--) {
1251             unsigned l = VALUE8(tvb, *offsetp);
1252             if (l == 255) { /* Item is a font */
1253                   fid = tvb_get_ntohl(tvb, *offsetp + 1);
1254                   proto_tree_add_uint(tt, hf_x11_textitem_font, tvb, *offsetp, 5, fid);
1255                   *offsetp += 5;
1256             } else { /* Item is a string */
1257                   proto_item *tti;
1258                   proto_tree *ttt;
1259                   gint8 delta = VALUE8(tvb, *offsetp + 1);
1260                   if (sizeIs16) l += l;
1261                   if ((unsigned) allocated < l + 1) {
1262                         /* g_realloc doesn't work ??? */
1263                         g_free(s);
1264                         s = g_malloc(l + 1);
1265                         allocated = l + 1;
1266                   }
1267                   stringCopy(s, tvb_get_ptr(tvb, *offsetp + 2, l), l);
1268                   tti = proto_tree_add_none_format(tt, hf_x11_textitem_string, tvb, *offsetp, l + 2,
1269                                                        "textitem (string): delta = %d, \"%s\"",
1270                                                        delta, s);
1271                   ttt = proto_item_add_subtree(tti, ett_x11_text_item);
1272                   proto_tree_add_item(ttt, hf_x11_textitem_string_delta, tvb, *offsetp + 1, 1, little_endian);
1273                   if (sizeIs16)
1274                         string16_with_buffer_preallocated(tvb, ttt, hf_x11_textitem_string_string16, 
1275                                                           hf_x11_textitem_string_string16_bytes,
1276                                                           *offsetp + 2, l,
1277                                                            &s, &allocated);
1278                   else
1279                         proto_tree_add_string_format(ttt, hf_x11_textitem_string_string8, tvb, 
1280                                                      *offsetp + 2, l, s, "\"%s\"", s);
1281                   *offsetp += l + 2;
1282             }
1283       }
1284
1285       /*
1286        * Call the cleanup handler to free the string and pop the handler.
1287        */
1288       CLEANUP_CALL_AND_POP;
1289 }
1290
1291 static guint32 field8(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
1292 {
1293       guint32 v = VALUE8(tvb, *offsetp);
1294       header_field_info *hfi = proto_registrar_get_nth(hf);
1295       gchar *enumValue = NULL;
1296       gchar *nameAsChar = hfi -> name;
1297
1298       if (hfi -> strings)
1299             enumValue = match_strval(v, cVALS(hfi -> strings));
1300       if (enumValue)
1301             proto_tree_add_uint_format(t, hf, tvb, *offsetp, 1, v,
1302                                        hfi -> display == BASE_DEC ? "%s: %u (%s)" : "%s: 0x%02x (%s)",
1303                                        nameAsChar, v, enumValue);
1304       else
1305             proto_tree_add_item(t, hf, tvb, *offsetp, 1, little_endian);
1306       *offsetp += 1;
1307       return v;
1308 }
1309
1310 static guint32 field16(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
1311 {
1312       guint32 v = VALUE16(tvb, *offsetp);
1313       proto_tree_add_item(t, hf, tvb, *offsetp, 2, little_endian);
1314       *offsetp += 2;
1315       return v;
1316 }
1317
1318 static guint32 field32(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
1319 {
1320       guint32 v = VALUE32(tvb, *offsetp);
1321       header_field_info *hfi = proto_registrar_get_nth(hf);
1322       gchar *enumValue = NULL;
1323       gchar *nameAsChar = hfi -> name;
1324
1325       if (hfi -> strings)
1326             enumValue = match_strval(v, cVALS(hfi -> strings));
1327       if (enumValue)
1328             proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v,
1329                                        hfi -> display == BASE_DEC ? "%s: %u (%s)" : "%s: 0x%08x (%s)",
1330                                        nameAsChar, v, enumValue);
1331       else
1332             proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v, 
1333                                        hfi -> display == BASE_DEC ? "%s: %u" : "%s: 0x%08x",
1334                                        nameAsChar, v);
1335       *offsetp += 4;
1336       return v;
1337 }
1338
1339 static void gcAttributes(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1340 {
1341       BITMASK32(gc_value);
1342       BITFIELD(ENUM8,  gc_value_mask, function);
1343       BITFIELD(CARD32, gc_value_mask, plane_mask);
1344       BITFIELD(CARD32, gc_value_mask, foreground);
1345       BITFIELD(CARD32, gc_value_mask, background);
1346       BITFIELD(CARD16, gc_value_mask, line_width);
1347       BITFIELD(ENUM8,  gc_value_mask, line_style);
1348       BITFIELD(ENUM8,  gc_value_mask, cap_style);
1349       BITFIELD(ENUM8,  gc_value_mask, join_style);
1350       BITFIELD(ENUM8,  gc_value_mask, fill_style);
1351       BITFIELD(ENUM8,  gc_value_mask, fill_rule);
1352       BITFIELD(PIXMAP, gc_value_mask, tile);
1353       BITFIELD(PIXMAP, gc_value_mask, stipple);
1354       BITFIELD(INT16,  gc_value_mask, tile_stipple_x_origin);
1355       BITFIELD(INT16,  gc_value_mask, tile_stipple_y_origin);
1356       BITFIELD(FONT,   gc_value_mask, font);
1357       BITFIELD(ENUM8,  gc_value_mask, subwindow_mode);
1358       BITFIELD(BOOL,   gc_value_mask, graphics_exposures);
1359       BITFIELD(INT16,  gc_value_mask, clip_x_origin);
1360       BITFIELD(INT16,  gc_value_mask, clip_y_origin);
1361       BITFIELD(PIXMAP, gc_value_mask, clip_mask);
1362       BITFIELD(CARD16, gc_value_mask, dash_offset);
1363       BITFIELD(CARD8,  gc_value_mask, gc_dashes);
1364       BITFIELD(ENUM8,  gc_value_mask, arc_mode);
1365       ENDBITMASK;
1366 }
1367
1368 static void gcMask(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1369 {
1370       BITMASK32(gc_value);
1371       FLAG(gc_value, function);
1372       FLAG(gc_value, plane_mask);
1373       FLAG(gc_value, foreground);
1374       FLAG(gc_value, background);
1375       FLAG(gc_value, line_width);
1376       FLAG(gc_value, line_style);
1377       FLAG(gc_value, cap_style);
1378       FLAG(gc_value, join_style);
1379       FLAG(gc_value, fill_style);
1380       FLAG(gc_value, fill_rule);
1381       FLAG(gc_value, tile);
1382       FLAG(gc_value, stipple);
1383       FLAG(gc_value, tile_stipple_x_origin);
1384       FLAG(gc_value, tile_stipple_y_origin);
1385       FLAG(gc_value, font);
1386       FLAG(gc_value, subwindow_mode);
1387       FLAG(gc_value, graphics_exposures);
1388       FLAG(gc_value, clip_x_origin);
1389       FLAG(gc_value, clip_y_origin);
1390       FLAG(gc_value, clip_mask);
1391       FLAG(gc_value, dash_offset);
1392       FLAG(gc_value, gc_dashes);
1393       FLAG(gc_value, arc_mode);
1394       ENDBITMASK;
1395 }
1396
1397 static guint32 requestLength(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1398 {
1399       guint32 res = VALUE16(tvb, *offsetp) * 4;
1400       proto_tree_add_uint(t, hf_x11_request_length, tvb, *offsetp, 2, res);
1401       *offsetp += 2;
1402       return res;
1403 }
1404
1405 static void setOfEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1406 {
1407       BITMASK32(event);
1408       FLAG(event, KeyPress);
1409       FLAG(event, KeyRelease);
1410       FLAG(event, ButtonPress);
1411       FLAG(event, ButtonRelease);
1412       FLAG(event, EnterWindow);
1413       FLAG(event, LeaveWindow);
1414       FLAG(event, PointerMotion);
1415       FLAG(event, PointerMotionHint);
1416       FLAG(event, Button1Motion);
1417       FLAG(event, Button2Motion);
1418       FLAG(event, Button3Motion);
1419       FLAG(event, Button4Motion);
1420       FLAG(event, Button5Motion);
1421       FLAG(event, ButtonMotion);
1422       FLAG(event, KeymapState);
1423       FLAG(event, Exposure);
1424       FLAG(event, VisibilityChange);
1425       FLAG(event, StructureNotify);
1426       FLAG(event, ResizeRedirect);
1427       FLAG(event, SubstructureNotify);
1428       FLAG(event, SubstructureRedirect);
1429       FLAG(event, FocusChange);
1430       FLAG(event, PropertyChange);
1431       FLAG(event, ColormapChange);
1432       FLAG(event, OwnerGrabButton);
1433       FLAG_IF_NONZERO(event, erroneous_bits);
1434       ENDBITMASK;
1435 }
1436
1437 static void setOfDeviceEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1438 {
1439       BITMASK32(do_not_propagate);
1440       FLAG(do_not_propagate, KeyPress);
1441       FLAG(do_not_propagate, KeyRelease);
1442       FLAG(do_not_propagate, ButtonPress);
1443       FLAG(do_not_propagate, ButtonRelease);
1444       FLAG(do_not_propagate, PointerMotion);
1445       FLAG(do_not_propagate, Button1Motion);
1446       FLAG(do_not_propagate, Button2Motion);
1447       FLAG(do_not_propagate, Button3Motion);
1448       FLAG(do_not_propagate, Button4Motion);
1449       FLAG(do_not_propagate, Button5Motion);
1450       FLAG(do_not_propagate, ButtonMotion);
1451       FLAG_IF_NONZERO(do_not_propagate, erroneous_bits);
1452       ENDBITMASK;
1453 }
1454
1455 static void setOfKeyMask(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1456 {
1457       proto_item *ti;
1458       guint32 bitmask_value;
1459       int bitmask_offset;
1460       int bitmask_size;
1461       proto_tree *bitmask_tree;
1462
1463       bitmask_value = VALUE16(tvb, *offsetp);
1464       bitmask_offset = *offsetp;
1465       bitmask_size = 2;
1466       if (bitmask_value == 0x8000)
1467             proto_tree_add_uint_format(t, hf_x11_modifiers_mask_AnyModifier, tvb, *offsetp, 2, 0x8000,
1468                                        "modifiers-masks: 0x8000 (AnyModifier)");
1469       else {
1470             ti = proto_tree_add_uint(t, hf_x11_modifiers_mask, tvb, *offsetp, 2, 
1471                                                  bitmask_value);
1472             bitmask_tree = proto_item_add_subtree(ti, ett_x11_set_of_key_mask);
1473             FLAG(modifiers, Shift);
1474             FLAG(modifiers, Lock);
1475             FLAG(modifiers, Control);
1476             FLAG(modifiers, Mod1);
1477             FLAG(modifiers, Mod2);
1478             FLAG(modifiers, Mod3);
1479             FLAG(modifiers, Mod4);
1480             FLAG(modifiers, Mod5);
1481             FLAG_IF_NONZERO(modifiers, erroneous_bits);
1482       }
1483       *offsetp += 2; 
1484 }
1485
1486 static void setOfPointerEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1487 {
1488       BITMASK16(pointer_event);
1489       FLAG(pointer_event, ButtonPress);
1490       FLAG(pointer_event, ButtonRelease);
1491       FLAG(pointer_event, EnterWindow);
1492       FLAG(pointer_event, LeaveWindow);
1493       FLAG(pointer_event, PointerMotion);
1494       FLAG(pointer_event, PointerMotionHint);
1495       FLAG(pointer_event, Button1Motion);
1496       FLAG(pointer_event, Button2Motion);
1497       FLAG(pointer_event, Button3Motion);
1498       FLAG(pointer_event, Button4Motion);
1499       FLAG(pointer_event, Button5Motion);
1500       FLAG(pointer_event, ButtonMotion);
1501       FLAG(pointer_event, KeymapState);
1502       FLAG_IF_NONZERO(pointer_event, erroneous_bits);
1503       ENDBITMASK;
1504 }
1505
1506 static void string8(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1507     const char *nameAsChar, int hf, unsigned length)
1508 {
1509       char *s = g_malloc(length + 1);
1510
1511       /*
1512        * In case we throw an exception, clean up whatever stuff we've
1513        * allocated (if any).
1514        */
1515       CLEANUP_PUSH(g_free, s);
1516
1517       stringCopy(s, tvb_get_ptr(tvb, *offsetp, length), length);
1518       proto_tree_add_string_format(t, hf, tvb, *offsetp, length, s, "%s: %s", nameAsChar, s);
1519
1520       /*
1521        * Call the cleanup handler to free the string and pop the handler.
1522        */
1523       CLEANUP_CALL_AND_POP;
1524
1525       *offsetp += length;
1526 }
1527
1528 /* The length is the length of the _byte_zone_ (twice the length of the string) */
1529
1530 static void string16(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1531     int hf_bytes, unsigned length)
1532 {
1533       char *s = NULL;
1534       unsigned l = 0;
1535
1536       /*
1537        * In case we throw an exception, clean up whatever stuff we've
1538        * allocated (if any).
1539        */
1540       CLEANUP_PUSH(g_free, s);
1541
1542       length += length;
1543       string16_with_buffer_preallocated(tvb, t, hf, hf_bytes, *offsetp, length, &s, &l);
1544
1545       /*
1546        * Call the cleanup handler to free the string and pop the handler.
1547        */
1548       CLEANUP_CALL_AND_POP;
1549
1550       *offsetp += length;
1551 }
1552
1553 static void timestamp(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1554     const char *nameAsChar, int hf)
1555 {
1556       guint32 v = VALUE32(tvb, *offsetp);
1557       if (!v)
1558             proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, 0, "%s: 0 (CurrentTime)", nameAsChar);
1559       else
1560             proto_tree_add_uint(t, hf, tvb, *offsetp, 4, v);
1561       *offsetp += 4;
1562 }
1563
1564 static void windowAttributes(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1565 {
1566       BITMASK32(window_value);
1567       BITFIELD(PIXMAP, window_value_mask, background_pixmap);
1568       BITFIELD(CARD32, window_value_mask, background_pixel);
1569       BITFIELD(PIXMAP, window_value_mask, border_pixmap);
1570       BITFIELD(CARD32, window_value_mask, border_pixel);
1571       BITFIELD(BITGRAVITY, window_value_mask, bit_gravity);
1572       BITFIELD(WINGRAVITY, window_value_mask, win_gravity);
1573       BITFIELD(ENUM8, window_value_mask, backing_store);
1574       BITFIELD(CARD32, window_value_mask, backing_planes);
1575       BITFIELD(CARD32, window_value_mask, backing_pixel);
1576       BITFIELD(BOOL,   window_value_mask, override_redirect);
1577       BITFIELD(BOOL,   window_value_mask, save_under);
1578       BITFIELD(SETofEVENT, window_value_mask, event_mask);
1579       BITFIELD(SETofDEVICEEVENT, window_value_mask, do_not_propagate_mask);
1580       BITFIELD(COLORMAP, window_value_mask, colormap);
1581       BITFIELD(CURSOR, window_value_mask, cursor);
1582       ENDBITMASK;
1583 }
1584
1585 /*
1586  * Data structure associated with a conversation; keeps track of the
1587  * request for which we're expecting a reply, the frame number of
1588  * the initial connection request, and the byte order of the connection.
1589  *
1590  * An opcode of -3 means we haven't yet seen any requests yet.
1591  * An opcode of -2 means we're not expecting a reply.
1592  * An opcode of -1 means means we're waiting for a reply to the initial
1593  * connection request.
1594  * Other values are the opcode of the request for which we're expecting
1595  * a reply.
1596  *
1597  * XXX - assumes only one outstanding request is awaiting a reply,
1598  * which should always be the case.
1599  */
1600 #define NOTHING_SEEN            -3
1601 #define NOTHING_EXPECTED        -2
1602 #define INITIAL_CONN            -1
1603
1604 #define BYTE_ORDER_BE           0
1605 #define BYTE_ORDER_LE           1
1606 #define BYTE_ORDER_UNKNOWN      -1
1607
1608 typedef struct {
1609       int       opcode;         /* opcode for which we're awaiting a reply */
1610       guint32   iconn_frame;    /* frame # of initial connection request */
1611       int       byte_order;     /* byte order of connection */
1612 } x11_conv_data_t;
1613
1614 static GMemChunk *x11_state_chunk = NULL;
1615
1616 static void x11_init_protocol(void)
1617 {
1618       if (x11_state_chunk != NULL)
1619             g_mem_chunk_destroy(x11_state_chunk);
1620
1621       x11_state_chunk = g_mem_chunk_new("x11_state_chunk",
1622                                         sizeof (x11_conv_data_t),
1623                                         128 * sizeof (x11_conv_data_t),
1624                                         G_ALLOC_ONLY);
1625 }
1626
1627 /************************************************************************
1628  ***                                                                  ***
1629  ***         G U E S S I N G   T H E   B Y T E   O R D E R I N G      ***
1630  ***                                                                  ***
1631  ************************************************************************/
1632
1633 /* If we can't guess, we return TRUE (that is little_endian), cause
1634    I'm developing on a Linux box :-). The (non-)guess isn't cached
1635    however, so we may have more luck next time. I'm quite conservative
1636    in my assertions, cause once it's cached, it's stay in cache, and
1637    we may be fooled up by a packet starting with the end of a request
1638    started in a previous packet...
1639 */
1640
1641 static int numberOfBitSetTable[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
1642
1643 static int numberOfBitSet(tvbuff_t *tvb, int offset, int maskLength)
1644 {
1645       int res = 0;
1646       while(maskLength--) {
1647             int c = tvb_get_guint8(tvb, offset);
1648             offset++;
1649             res += numberOfBitSetTable[c & 0xf] + numberOfBitSetTable[c >> 4];
1650       }
1651       return res;
1652 }
1653
1654 static int listOfStringLengthConsistent(tvbuff_t *tvb, int offset, int length, int listLength)
1655 {
1656       if (listLength > length) return FALSE;
1657       while(listLength--) {
1658             int l;
1659             if (!tvb_bytes_exist(tvb, offset, 1)) return TRUE;
1660             l = tvb_get_guint8(tvb, offset);
1661             if (!l) break;
1662             l++;
1663             if (l > length) return FALSE;
1664             if (!tvb_bytes_exist(tvb, offset, l)) return TRUE;
1665             offset += l;
1666             length -= l;
1667       }
1668       if (length > 3) return FALSE;
1669       return TRUE;
1670 }
1671
1672 static int rounded4(int n)
1673 {
1674       int remainder = n % 4;
1675       int res = n / 4;
1676       if (remainder) res++;
1677       return res;
1678 }
1679
1680 /* We assume the order to be consistent, until proven wrong. */
1681
1682 static gboolean consistentWithOrder(int length, tvbuff_t *tvb, int offset, guint16 (*v16)(tvbuff_t *, gint))
1683 {
1684       switch(tvb_get_guint8(tvb, offset)) {
1685           case 1: /* CreateWindow */
1686             return !tvb_bytes_exist(tvb, offset, 32) || length == 8 + numberOfBitSet(tvb, offset + 7 * 4, 4);
1687
1688           case 2: /* ChangeWindowAttributes */
1689           case 56: /* ChangeGC */
1690             return !tvb_bytes_exist(tvb, offset, 12) || length == 3 + numberOfBitSet(tvb, offset + 8, 4);
1691
1692           case 3: /* GetWindowAttributes */
1693           case 4: /* DestroyWindow */
1694           case 5: /* DestroySubwindows */
1695           case 6: /* ChangeSaveSet */
1696           case 8: /* MapWindow */
1697           case 9: /* MapSubWindow */
1698           case 10: /* UnmapWindow */
1699           case 11: /* UnmapSubwindows */
1700           case 13: /* CirculateWindow */
1701           case 14: /* GetGeometry */
1702           case 15: /* QueryTree */
1703           case 17: /* GetAtomName */
1704           case 21: /* ListProperties */
1705           case 23: /* GetSelectionOwner */
1706           case 27: /* UngrabPointer */
1707           case 32: /* UngrabKeyboard */
1708           case 35: /* AllowEvents */
1709           case 38: /* QueryPointer */
1710           case 46: /* CloseFont */
1711           case 47: /* QueryFont */
1712           case 54: /* FreePixmap */
1713           case 60: /* FreeGC */
1714           case 79: /* FreeColormap */
1715           case 81: /* InstallColormap */
1716           case 82: /* UninstallColormap */
1717           case 83: /* ListInstalledColormaps */
1718           case 95: /* FreeCursor */
1719           case 101: /* GetKeyboardMapping */
1720           case 113: /* KillClient */
1721             return length == 2;
1722
1723           case 7: /* ReparentWindow */
1724           case 22: /* SetSelectionOwner */
1725           case 30: /* ChangeActivePointerGrab */
1726           case 31: /* GrabKeyboard */
1727           case 33: /* GrabKey */
1728           case 39: /* GetMotionEvents */
1729           case 40: /* TranslateCoordinates */
1730           case 53: /* CreatePixmap */
1731           case 57: /* CopyGC */
1732           case 61: /* ClearArea */
1733           case 78: /* CreateColormap */
1734           case 84: /* AllocColor */
1735           case 87: /* AllocColorPlanes */
1736             return length == 4;
1737
1738           case 12: /* ConfigureWindow */
1739             return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + numberOfBitSet(tvb, offset + 8, 2);
1740
1741           case 16: /* InternAtom */
1742           case 98: /* QueryExtension */
1743             return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + rounded4(v16(tvb, offset + 4));
1744
1745           case 18: /* ChangeProperty */
1746             {
1747                   int multiplier, type;
1748                   if (!tvb_bytes_exist(tvb, offset, 17)) return TRUE;
1749                   type = tvb_get_guint8(tvb, 16);
1750                   if (type != 8 && type != 16 && type != 32) return FALSE;
1751                   multiplier = type == 8 ? 1 : type == 16 ? 2 : 4;
1752                   if (!tvb_bytes_exist(tvb, offset, 24)) return TRUE;
1753                   return length == 6 + rounded4((v16 == tvb_get_letohs ? tvb_get_letohl : tvb_get_ntohl)(tvb, offset + 20) * multiplier);
1754             }
1755
1756           case 19: /* DeleteProperty */
1757           case 29: /* UngrabButton */
1758           case 34: /* UngrabKey */
1759           case 42: /* SetInputFocus */
1760           case 80: /* CopyColormapAndFree */
1761           case 86: /* AllocColorCells */
1762           case 97: /* QueryBestSize */
1763           case 105: /* ChangePointerControl */
1764           case 107: /* SetScreenSaver */
1765             return length == 3;
1766
1767           case 20: /* GetProperty */
1768           case 24: /* ConvertSelection */
1769           case 26: /* GrabPointer */
1770           case 28: /* GrabButton */
1771           case 41: /* WarpPointer */
1772             return length == 6;
1773
1774           case 25: /* SendEvent */
1775             return length == 11;
1776
1777           case 36: /* GrabServer */
1778           case 37: /* UngrabServer */
1779           case 43: /* GetInputFocus */
1780           case 44: /* QueryKeymap */
1781           case 52: /* GetFontPath */
1782           case 99: /* ListExtensions */
1783           case 103: /* GetKeyboardControl */
1784           case 104: /* Bell */
1785           case 106: /* GetPointerControl */
1786           case 108: /* GetScreenSaver */
1787           case 110: /* ListHosts */
1788           case 111: /* SetAccessControl */
1789           case 112: /* SetCloseDownMode */
1790           case 115: /* ForceScreenSaver */
1791           case 117: /* GetPointerMapping */
1792           case 119: /* GetModifierMapping */
1793             return length == 1;
1794
1795           case 45: /* OpenFont */
1796           case 85: /* AllocNamedColor */
1797           case 92: /* LookupColor */
1798             return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + rounded4(v16(tvb, offset + 8));
1799
1800           case 48: /* QueryTextExtents */
1801             return length >= 2;
1802
1803           case 49: /* ListFonts */
1804           case 50: /* ListFontsWithInfo */
1805           case 109: /* ChangeHosts */
1806             return !tvb_bytes_exist(tvb, offset, 8) || length == 2 + rounded4(v16(tvb, offset + 6));
1807
1808           case 51: /* SetFontPath */
1809             if (length < 2) return FALSE;
1810             if (!tvb_bytes_exist(tvb, offset, 8)) return TRUE;
1811             return listOfStringLengthConsistent(tvb, offset + 8, (length - 2) * 4, v16(tvb, offset + 4));
1812
1813           case 55: /* CreateGC */
1814             return !tvb_bytes_exist(tvb, offset, 16) || length == 4 + numberOfBitSet(tvb, offset + 12, 4);
1815
1816           case 58: /* SetDashes */
1817             return !tvb_bytes_exist(tvb, offset, 12) || length == 3 + rounded4(v16(tvb, offset + 10));
1818
1819           case 59: /* SetClipRectangles */
1820           case 66: /* PolySegment */
1821           case 67: /* PolyRectangle */
1822           case 70: /* PolyFillRectangle */
1823             return length >= 3 && (length - 3) % 2 == 0;
1824
1825           case 62: /* CopyArea */
1826             return length == 7;
1827
1828           case 63: /* CopyPlane */
1829           case 93: /* CreateCursor */
1830           case 94: /* CreateGlyphCursor */
1831             return length == 8;
1832
1833           case 64: /* PolyPoint */
1834           case 65: /* PolyLine */
1835           case 88: /* FreeColors */
1836             return length >= 3;
1837
1838           case 68: /* PolyArc */
1839           case 71: /* PolyFillArc */
1840             return length >= 3 && (length - 3) % 3 == 0;
1841
1842           case 69: /* FillPoly */
1843           case 76: /* ImageText8 */
1844             return length >= 4;
1845
1846           case 72: /* PutImage */
1847             return length >= 6;
1848
1849           case 73: /* GetImage */
1850           case 96: /* RecolorCursor */
1851             return length == 5;
1852
1853           case 74: /* PolyText8 */
1854             if (length < 4) return FALSE;
1855             return TRUE; /* We don't perform many controls on this one */
1856
1857           case 75: /* PolyText16 */
1858             if (length < 4) return FALSE;
1859             return TRUE; /* We don't perform many controls on this one */
1860
1861           case 77: /* ImageText16 */
1862             return length >= 4;
1863
1864           case 89: /* StoreColors */
1865             return length > 2 && (length - 2) % 3 == 0;
1866
1867           case 90: /* StoreNamedColor */
1868             return !tvb_bytes_exist(tvb, offset, 14) || length == 4 + rounded4(v16(tvb, offset + 12));
1869
1870           case 91: /* QueryColors */
1871             return length >= 2;
1872
1873           case 100: /* ChangeKeyboardMapping */
1874             return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + tvb_get_guint8(tvb, 1) * tvb_get_guint8(tvb, 5);
1875
1876           case 102: /* ChangeKeyboardControl */
1877             return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + numberOfBitSet(tvb, offset + 4, 2);
1878
1879           case 114: /* RotateProperties */
1880             return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + v16(tvb, offset + 8);
1881
1882           case 116: /* SetPointerMapping */
1883             return length == 1 + rounded4(tvb_get_guint8(tvb, 1));
1884
1885           case 118: /* SetModifierMapping */
1886             return length == 1 + tvb_get_guint8(tvb, 1) * 2;
1887             
1888           case 127: /* NoOperation */
1889             return length >= 1;
1890
1891           default:
1892             return TRUE;
1893       }
1894 }
1895
1896 /* -1 means doesn't match, +1 means match, 0 means don't know */
1897
1898 static int x_endian_match(tvbuff_t *tvb, guint16 (*v16)(tvbuff_t *, gint))
1899 {
1900       int offset, nextoffset;
1901       int atLeastOne = 0;
1902
1903       for(offset = 0; tvb_bytes_exist(tvb, offset, 4); offset = nextoffset) {
1904             int length;
1905             length = v16(tvb, offset + 2);
1906             if (!length) return -1;
1907             nextoffset = offset + length * 4;
1908             if (!consistentWithOrder(length, tvb, offset, v16)) return -1;
1909             atLeastOne = 1;
1910       }
1911       return atLeastOne;
1912 }
1913
1914 static gboolean
1915 guess_byte_ordering(tvbuff_t *tvb, packet_info *pinfo,
1916                     x11_conv_data_t *state_info)
1917 {
1918       /* With X the client gives the byte ordering for the protocol,
1919          and the port on the server tells us we're speaking X. */
1920
1921       int le, be, decision, decisionToCache;
1922
1923       if (state_info->byte_order == BYTE_ORDER_BE)
1924             return FALSE;       /* known to be big-endian */
1925       else if (state_info->byte_order == BYTE_ORDER_LE)
1926             return TRUE;        /* known to be little-endian */
1927
1928       if (pinfo->srcport == pinfo->match_port) {
1929             /*
1930              * This is a reply or event; we don't try to guess the
1931              * byte order on it for now.
1932              */
1933             return TRUE;
1934       }
1935
1936       le = x_endian_match(tvb, tvb_get_letohs);
1937       be = x_endian_match(tvb, tvb_get_ntohs);
1938
1939       /* remember that "decision" really means "little_endian". */
1940       if (le == be) {
1941             /* We have no reason to believe it's little- rather than
1942                big-endian, so we guess the shortest length is the
1943                right one.
1944             */
1945             if (!tvb_bytes_exist(tvb, 0, 4))
1946                   /* Not even a way to get the length. We're biased
1947                      toward little endianness here (essentially the
1948                      x86 world right now). Decoding won't go very far
1949                      anyway.
1950                   */
1951                   decision = TRUE;
1952             else
1953                   decision = tvb_get_letohs(tvb, 2) <= tvb_get_ntohs(tvb, 2);
1954       } else
1955           decision = le >= be;
1956
1957       decisionToCache = (le < 0 && be > 0) || (le > 0 && be < 0);
1958       if (decisionToCache) {
1959             /*
1960              * Remember the decision.
1961              */
1962             state_info->byte_order = decision ? BYTE_ORDER_LE : BYTE_ORDER_BE;
1963       }
1964             
1965       /*
1966       fprintf(stderr, "packet %d\tle %d\tbe %d\tlittle_endian %d\tcache %d\n", 
1967               pinfo->fd -> num, le, be, decision, decisionToCache);
1968       */
1969       return decision;
1970 }
1971
1972 /************************************************************************
1973  ***                                                                  ***
1974  ***              D E C O D I N G   O N E   P A C K E T               ***
1975  ***                                                                  ***
1976  ************************************************************************/
1977
1978 /*
1979  * Decode an initial connection request.
1980  */
1981 static void dissect_x11_initial_conn(tvbuff_t *tvb, packet_info *pinfo,
1982     proto_tree *tree, x11_conv_data_t *state_info)
1983 {
1984       int offset = 0;
1985       int *offsetp = &offset;
1986       proto_item *ti;
1987       proto_tree *t;
1988       guint16 auth_proto_name_length, auth_proto_data_length;
1989       gint left;
1990
1991       ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
1992       t = proto_item_add_subtree(ti, ett_x11);
1993
1994       CARD8(byte_order);
1995       UNUSED(1);
1996       CARD16(protocol_major_version);
1997       CARD16(protocol_minor_version);
1998       auth_proto_name_length = CARD16(authorization_protocol_name_length);
1999       auth_proto_data_length = CARD16(authorization_protocol_data_length);
2000       UNUSED(2);
2001       if (auth_proto_name_length != 0) {
2002             STRING8(authorization_protocol_name, auth_proto_name_length);
2003             offset = ROUND_LENGTH(offset);
2004       }
2005       if (auth_proto_data_length != 0) {
2006             STRING8(authorization_protocol_data, auth_proto_data_length);
2007             offset = ROUND_LENGTH(offset);
2008       }
2009       left = tvb_length_remaining(tvb, offset);
2010       if (left)
2011             proto_tree_add_item(t, hf_x11_undecoded, tvb, offset, left, little_endian);
2012
2013       /*
2014        * This is the initial connection request...
2015        */
2016       state_info->iconn_frame = pinfo->fd->num;
2017
2018       /*
2019        * ...and we're expecting a reply to it.
2020        */
2021       state_info->opcode = INITIAL_CONN;
2022 }
2023
2024 static void dissect_x11_request(tvbuff_t *tvb, packet_info *pinfo,
2025     proto_tree *tree, const char *sep, x11_conv_data_t *state_info)
2026 {
2027       int offset = 0;
2028       int *offsetp = &offset;
2029       int next_offset;
2030       proto_item *ti;
2031       proto_tree *t;
2032       int length, opcode;
2033       guint8 v8, v8_2;
2034       guint16 v16;
2035       guint32 v32;
2036       gint left;
2037
2038       length = VALUE16(tvb, 2) * 4;
2039
2040       if (length < 4) {
2041             /* Bogus message length? */
2042             return;
2043       }
2044
2045       next_offset = offset + length;
2046
2047       ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
2048       t = proto_item_add_subtree(ti, ett_x11);
2049
2050       OPCODE();
2051
2052       if (check_col(pinfo->cinfo, COL_INFO)) 
2053           col_append_fstr(pinfo->cinfo, COL_INFO, "%s %s", sep,
2054                           val_to_str(opcode, opcode_vals, "Unknown (%u)"));
2055
2056       /*
2057        * Does this request expect a reply?
2058        */
2059       switch(opcode) {
2060
2061       case 3: /* GetWindowAttributes */
2062       case 14: /* GetGeometry */
2063       case 15: /* QueryTree */
2064       case 16: /* InternAtom */
2065       case 17: /* GetAtomName */
2066       case 20: /* GetProperty */
2067       case 21: /* ListProperties */
2068       case 23: /* GetSelectionOwner */
2069       case 26: /* GrabPointer */
2070       case 31: /* GrabKeyboard */
2071       case 38: /* QueryPointer */
2072       case 39: /* GetMotionEvents */
2073       case 40: /* TranslateCoordinates */
2074       case 44: /* QueryKeymap */
2075       case 47: /* QueryFont */
2076       case 48: /* QueryTextExtents */
2077       case 49: /* ListFonts */
2078       case 73: /* GetImage */
2079       case 83: /* ListInstalledColormaps */
2080       case 84: /* AllocColor */
2081       case 91: /* QueryColors */
2082       case 92: /* LookupColor */
2083       case 97: /* QueryBestSize */
2084       case 98: /* QueryExtension */
2085       case 99: /* ListExtensions */
2086       case 101: /* GetKeyboardMapping */
2087       case 103: /* GetKeyboardControl */
2088       case 106: /* GetPointerControl */
2089       case 108: /* GetScreenSaver */
2090       case 110: /* ListHosts */
2091       case 116: /* SetPointerMapping */
2092       case 117: /* GetPointerMapping */
2093       case 118: /* SetModifierMapping */
2094       case 119: /* GetModifierMapping */
2095             /*
2096              * Those requests expect a reply.
2097              */
2098             state_info->opcode = opcode;
2099             break;
2100
2101       default:
2102             /*
2103              * No reply is expected from any other request.
2104              */
2105             state_info->opcode = NOTHING_EXPECTED;
2106             break;
2107       }
2108
2109       if (!tree) return;
2110
2111       switch(opcode) {
2112
2113       case 1: /* CreateWindow */
2114             CARD8(depth);
2115             REQUEST_LENGTH();
2116             WINDOW(wid);
2117             WINDOW(parent);
2118             INT16(x);
2119             INT16(y);
2120             CARD16(width);
2121             CARD16(height);
2122             CARD16(border_width);
2123             ENUM16(window_class);
2124             VISUALID(visual);
2125             windowAttributes(tvb, offsetp, t);
2126             break;
2127
2128       case 2: /* ChangeWindowAttributes */
2129             UNUSED(1);
2130             REQUEST_LENGTH();
2131             WINDOW(window);
2132             windowAttributes(tvb, offsetp, t);
2133             break;
2134
2135       case 3: /* GetWindowAttributes */
2136       case 4: /* DestroyWindow */
2137       case 5: /* DestroySubwindows */
2138             UNUSED(1);
2139             REQUEST_LENGTH();
2140             WINDOW(window);
2141             break;
2142
2143       case 6: /* ChangeSaveSet */
2144             ENUM8(save_set_mode);
2145             REQUEST_LENGTH();
2146             WINDOW(window);
2147             break;
2148
2149       case 7: /* ReparentWindow */
2150             UNUSED(1);
2151             REQUEST_LENGTH();
2152             WINDOW(window);
2153             WINDOW(parent);
2154             INT16(x);
2155             INT16(y);
2156             break;
2157
2158       case 8: /* MapWindow */
2159       case 9: /* MapSubWindow */
2160       case 10: /* UnmapWindow */
2161       case 11: /* UnmapSubwindows */
2162             UNUSED(1);
2163             REQUEST_LENGTH();
2164             WINDOW(window);
2165             break;
2166
2167       case 12: /* ConfigureWindow */
2168             UNUSED(1);
2169             REQUEST_LENGTH();
2170             WINDOW(window);
2171             BITMASK16(configure_window);
2172             UNUSED(2); 
2173             BITFIELD(INT16,  configure_window_mask, x);
2174             BITFIELD(INT16,  configure_window_mask, y);
2175             BITFIELD(CARD16, configure_window_mask, width);
2176             BITFIELD(CARD16, configure_window_mask, height);
2177             BITFIELD(CARD16, configure_window_mask, border_width);
2178             BITFIELD(WINDOW, configure_window_mask, sibling);
2179             BITFIELD(ENUM8,  configure_window_mask, stack_mode);
2180             ENDBITMASK;
2181             PAD();
2182             break;
2183
2184       case 13: /* CirculateWindow */
2185             ENUM8(direction);
2186             REQUEST_LENGTH();
2187             WINDOW(window);
2188             break;
2189
2190       case 14: /* GetGeometry */
2191       case 15: /* QueryTree */
2192             UNUSED(1);
2193             REQUEST_LENGTH();
2194             DRAWABLE(drawable);
2195             break;
2196
2197       case 16: /* InternAtom */
2198             BOOL(only_if_exists);
2199             REQUEST_LENGTH();
2200             v16 = FIELD16(name_length);
2201             UNUSED(2);
2202             STRING8(name, v16);
2203             PAD();
2204             break;
2205
2206       case 17: /* GetAtomName */
2207             UNUSED(1);
2208             REQUEST_LENGTH();
2209             ATOM(atom);
2210             break;
2211
2212       case 18: /* ChangeProperty */
2213             ENUM8(mode);
2214             REQUEST_LENGTH();
2215             WINDOW(window);
2216             ATOM(property);
2217             ATOM(type);
2218             CARD8(format);
2219             UNUSED(3);
2220             v32 = CARD32(data_length);
2221             LISTofBYTE(data, v32);
2222             PAD();
2223             break;
2224
2225       case 19: /* DeleteProperty */
2226             UNUSED(1);
2227             REQUEST_LENGTH();
2228             WINDOW(window);
2229             ATOM(property);
2230             break;
2231
2232       case 20: /* GetProperty */
2233             BOOL(delete);
2234             REQUEST_LENGTH();
2235             WINDOW(window);
2236             ATOM(property);
2237             ATOM(get_property_type);
2238             CARD32(long_offset);
2239             CARD32(long_length);
2240             break;
2241
2242       case 21: /* ListProperties */
2243             UNUSED(1);
2244             REQUEST_LENGTH();
2245             WINDOW(window);
2246             break;
2247
2248       case 22: /* SetSelectionOwner */
2249             UNUSED(1);
2250             REQUEST_LENGTH();
2251             WINDOW(owner);
2252             ATOM(selection);
2253             TIMESTAMP(time);
2254             break;
2255
2256       case 23: /* GetSelectionOwner */
2257             UNUSED(1);
2258             REQUEST_LENGTH();
2259             ATOM(selection);
2260             break;
2261
2262       case 24: /* ConvertSelection */
2263             UNUSED(1);
2264             REQUEST_LENGTH();
2265             WINDOW(requestor);
2266             ATOM(selection);
2267             ATOM(target);
2268             ATOM(property);
2269             TIMESTAMP(time);
2270             break;
2271
2272       case 26: /* GrabPointer */
2273             BOOL(owner_events);
2274             REQUEST_LENGTH();
2275             WINDOW(grab_window);
2276             SETofPOINTEREVENT(pointer_event_mask);
2277             ENUM8(pointer_mode);
2278             ENUM8(keyboard_mode);
2279             WINDOW(confine_to);
2280             CURSOR(cursor);
2281             TIMESTAMP(time);
2282             break;
2283
2284       case 27: /* UngrabPointer */
2285             UNUSED(1);
2286             REQUEST_LENGTH();
2287             TIMESTAMP(time);
2288             break;
2289
2290       case 28: /* GrabButton */
2291             BOOL(owner_events);
2292             REQUEST_LENGTH();
2293             WINDOW(grab_window);
2294             SETofPOINTEREVENT(event_mask);
2295             ENUM8(pointer_mode);
2296             ENUM8(keyboard_mode);
2297             WINDOW(confine_to);
2298             CURSOR(cursor);
2299             BUTTON(button);
2300             UNUSED(1);
2301             SETofKEYMASK(modifiers);
2302             break;
2303
2304       case 29: /* UngrabButton */
2305             BUTTON(button);
2306             REQUEST_LENGTH();
2307             WINDOW(grab_window);
2308             SETofKEYMASK(modifiers);
2309             UNUSED(2);
2310             break;
2311
2312       case 30: /* ChangeActivePointerGrab */
2313             UNUSED(1);
2314             REQUEST_LENGTH();
2315             CURSOR(cursor);
2316             TIMESTAMP(time);
2317             SETofPOINTEREVENT(event_mask);
2318             UNUSED(2);
2319             break;
2320
2321       case 31: /* GrabKeyboard */
2322             BOOL(owner_events);
2323             REQUEST_LENGTH();
2324             WINDOW(grab_window);
2325             TIMESTAMP(time);
2326             ENUM8(pointer_mode);
2327             ENUM8(keyboard_mode);
2328             UNUSED(2);
2329             break;
2330
2331       case 32: /* UngrabKeyboard */
2332             UNUSED(1);
2333             REQUEST_LENGTH();
2334             TIMESTAMP(time);
2335             break;
2336
2337       case 33: /* GrabKey */
2338             BOOL(owner_events);
2339             REQUEST_LENGTH();
2340             WINDOW(grab_window);
2341             SETofKEYMASK(modifiers);
2342             KEYCODE(key);
2343             ENUM8(pointer_mode);
2344             ENUM8(keyboard_mode);
2345             UNUSED(3);
2346             break;
2347
2348       case 34: /* UngrabKey */
2349             KEYCODE(key);
2350             REQUEST_LENGTH();
2351             WINDOW(grab_window);
2352             SETofKEYMASK(modifiers);
2353             UNUSED(2);
2354             break;
2355
2356       case 35: /* AllowEvents */
2357             ENUM8(allow_events_mode);
2358             REQUEST_LENGTH();
2359             TIMESTAMP(time);
2360             break;
2361
2362       case 36: /* GrabServer */
2363             UNUSED(1);
2364             REQUEST_LENGTH();
2365             break;
2366
2367       case 37: /* UngrabServer */
2368             UNUSED(1);
2369             REQUEST_LENGTH();
2370             break;
2371
2372       case 38: /* QueryPointer */
2373             UNUSED(1);
2374             REQUEST_LENGTH();
2375             WINDOW(window);
2376             break;
2377
2378       case 39: /* GetMotionEvents */
2379             UNUSED(1);
2380             REQUEST_LENGTH();
2381             WINDOW(window);
2382             TIMESTAMP(start);
2383             TIMESTAMP(stop);
2384             break;
2385
2386       case 40: /* TranslateCoordinates */
2387             UNUSED(1);
2388             REQUEST_LENGTH();
2389             WINDOW(src_window);
2390             WINDOW(dst_window);
2391             INT16(src_x);
2392             INT16(src_y);
2393             break;
2394
2395       case 41: /* WarpPointer */
2396             UNUSED(1);
2397             REQUEST_LENGTH();
2398             WINDOW(warp_pointer_src_window);
2399             WINDOW(warp_pointer_dst_window);
2400             INT16(src_x);
2401             INT16(src_y);
2402             CARD16(src_width);
2403             CARD16(src_height);
2404             INT16(dst_x);
2405             INT16(dst_y);
2406             break;
2407
2408       case 42: /* SetInputFocus */
2409             ENUM8(revert_to);
2410             REQUEST_LENGTH();
2411             WINDOW(focus);
2412             TIMESTAMP(time);
2413             break;
2414
2415       case 43: /* GetInputFocus */
2416             UNUSED(1);
2417             REQUEST_LENGTH();
2418             break;
2419
2420       case 44: /* QueryKeymap */
2421             UNUSED(1);
2422             REQUEST_LENGTH();
2423             break;
2424
2425       case 45: /* OpenFont */
2426             UNUSED(1);
2427             REQUEST_LENGTH();
2428             FONT(fid);
2429             v16 = FIELD16(name_length);
2430             UNUSED(2);
2431             STRING8(name, v16);
2432             PAD();
2433             break;
2434
2435       case 46: /* CloseFont */
2436             UNUSED(1);
2437             REQUEST_LENGTH();
2438             FONT(font);
2439             break;
2440
2441       case 47: /* QueryFont */
2442             UNUSED(1);
2443             REQUEST_LENGTH();
2444             FONTABLE(font);
2445             break;
2446
2447       case 48: /* QueryTextExtents */
2448             v8 = BOOL(odd_length);
2449             REQUEST_LENGTH();
2450             FONTABLE(font);
2451             STRING16(string16, (next_offset - offset - (v8 ? 2 : 0)) / 2);
2452             PAD();
2453             break;
2454
2455       case 49: /* ListFonts */
2456             UNUSED(1);
2457             REQUEST_LENGTH();
2458             CARD16(max_names);
2459             v16 = FIELD16(pattern_length);
2460             STRING8(pattern, v16);
2461             PAD();
2462             break;
2463
2464       case 50: /* ListFontsWithInfo */
2465             UNUSED(1);
2466             REQUEST_LENGTH();
2467             CARD16(max_names);
2468             v16 = FIELD16(pattern_length);
2469             STRING8(pattern, v16);
2470             PAD();
2471             break;
2472
2473       case 51: /* SetFontPath */
2474             UNUSED(1);
2475             REQUEST_LENGTH();
2476             v16 = CARD16(str_number_in_path);
2477             UNUSED(2);
2478             LISTofSTRING8(path, v16);
2479             PAD();
2480             break;
2481
2482       case 52: /* GetFontPath */
2483             UNUSED(1);
2484             REQUEST_LENGTH();
2485             break;
2486
2487       case 53: /* CreatePixmap */
2488             CARD8(depth);
2489             REQUEST_LENGTH();
2490             PIXMAP(pid);
2491             DRAWABLE(drawable);
2492             CARD16(width);
2493             CARD16(height);
2494             break;
2495
2496       case 54: /* FreePixmap */
2497             UNUSED(1);
2498             REQUEST_LENGTH();
2499             PIXMAP(pixmap);
2500             break;
2501
2502       case 55: /* CreateGC */
2503             UNUSED(1);
2504             REQUEST_LENGTH();
2505             GCONTEXT(cid);
2506             DRAWABLE(drawable);
2507             gcAttributes(tvb, offsetp, t);
2508             break;
2509
2510       case 56: /* ChangeGC */
2511             UNUSED(1);
2512             REQUEST_LENGTH();
2513             GCONTEXT(gc);
2514             gcAttributes(tvb, offsetp, t);
2515             break;
2516
2517       case 57: /* CopyGC */
2518             UNUSED(1);
2519             REQUEST_LENGTH();
2520             GCONTEXT(src_gc);
2521             GCONTEXT(dst_gc);
2522             gcMask(tvb, offsetp, t);
2523             break;
2524
2525       case 58: /* SetDashes */
2526             UNUSED(1);
2527             REQUEST_LENGTH();
2528             GCONTEXT(gc);
2529             CARD16(dash_offset);
2530             v16 = FIELD16(dashes_length);
2531             LISTofCARD8(dashes, v16);
2532             PAD();
2533             break;
2534
2535       case 59: /* SetClipRectangles */
2536             ENUM8(ordering);
2537             REQUEST_LENGTH();
2538             GCONTEXT(gc);
2539             INT16(clip_x_origin);
2540             INT16(clip_y_origin);
2541             LISTofRECTANGLE(rectangles);
2542             break;
2543
2544       case 60: /* FreeGC */
2545             UNUSED(1);
2546             REQUEST_LENGTH();
2547             GCONTEXT(gc);
2548             break;
2549
2550       case 61: /* ClearArea */
2551             BOOL(exposures);
2552             REQUEST_LENGTH();
2553             WINDOW(window);
2554             INT16(x);
2555             INT16(y);
2556             CARD16(width);
2557             CARD16(height);
2558             break;
2559
2560       case 62: /* CopyArea */
2561             UNUSED(1);
2562             REQUEST_LENGTH();
2563             DRAWABLE(src_drawable);
2564             DRAWABLE(dst_drawable);
2565             GCONTEXT(gc);
2566             INT16(src_x);
2567             INT16(src_y);
2568             INT16(dst_x);
2569             INT16(dst_y);
2570             CARD16(width);
2571             CARD16(height);
2572             break;
2573
2574       case 63: /* CopyPlane */
2575             UNUSED(1);
2576             REQUEST_LENGTH();
2577             DRAWABLE(src_drawable);
2578             DRAWABLE(dst_drawable);
2579             GCONTEXT(gc);
2580             INT16(src_x);
2581             INT16(src_y);
2582             INT16(dst_x);
2583             INT16(dst_y);
2584             CARD16(width);
2585             CARD16(height);
2586             CARD32(bit_plane);
2587             break;
2588
2589       case 64: /* PolyPoint */
2590             ENUM8(coordinate_mode);
2591             v16 = REQUEST_LENGTH();
2592             DRAWABLE(drawable);
2593             GCONTEXT(gc);
2594             LISTofPOINT(points, v16 - 12);
2595             break;
2596
2597       case 65: /* PolyLine */
2598             ENUM8(coordinate_mode);
2599             v16 = REQUEST_LENGTH();
2600             DRAWABLE(drawable);
2601             GCONTEXT(gc);
2602             LISTofPOINT(points, v16 - 12);
2603             break;
2604
2605       case 66: /* PolySegment */
2606             UNUSED(1);
2607             REQUEST_LENGTH();
2608             DRAWABLE(drawable);
2609             GCONTEXT(gc);
2610             LISTofSEGMENT(segments);
2611             break;
2612
2613       case 67: /* PolyRectangle */
2614             UNUSED(1);
2615             REQUEST_LENGTH();
2616             DRAWABLE(drawable);
2617             GCONTEXT(gc);
2618             LISTofRECTANGLE(rectangles);
2619             break;
2620
2621       case 68: /* PolyArc */
2622             UNUSED(1);
2623             REQUEST_LENGTH();
2624             DRAWABLE(drawable);
2625             GCONTEXT(gc);
2626             LISTofARC(arcs);
2627             break;
2628
2629       case 69: /* FillPoly */
2630             UNUSED(1);
2631             v16 = REQUEST_LENGTH();
2632             DRAWABLE(drawable);
2633             GCONTEXT(gc);
2634             ENUM8(shape);
2635             ENUM8(coordinate_mode);
2636             UNUSED(2);
2637             LISTofPOINT(points, v16 - 16);
2638             break;
2639
2640       case 70: /* PolyFillRectangle */
2641             UNUSED(1);
2642             REQUEST_LENGTH();
2643             DRAWABLE(drawable);
2644             GCONTEXT(gc);
2645             LISTofRECTANGLE(rectangles);
2646             break;
2647
2648       case 71: /* PolyFillArc */
2649             UNUSED(1);
2650             REQUEST_LENGTH();
2651             DRAWABLE(drawable);
2652             GCONTEXT(gc);
2653             LISTofARC(arcs);
2654             break;
2655
2656       case 72: /* PutImage */
2657             ENUM8(image_format);
2658             v16 = REQUEST_LENGTH();
2659             DRAWABLE(drawable);
2660             GCONTEXT(gc);
2661             CARD16(width);
2662             CARD16(height);
2663             INT16(dst_x);
2664             INT16(dst_y);
2665             CARD8(left_pad);
2666             CARD8(depth);
2667             UNUSED(2);
2668             LISTofBYTE(data, v16 - 24);
2669             PAD();
2670             break;
2671
2672       case 73: /* GetImage */
2673             ENUM8(image_pixmap_format);
2674             REQUEST_LENGTH();
2675             DRAWABLE(drawable);
2676             INT16(x);
2677             INT16(y);
2678             CARD16(width);
2679             CARD16(height);
2680             CARD32(plane_mask);
2681             break;
2682
2683       case 74: /* PolyText8 */
2684             UNUSED(1);
2685             v16 = REQUEST_LENGTH();
2686             DRAWABLE(drawable);
2687             GCONTEXT(gc);
2688             INT16(x);
2689             INT16(y);
2690             LISTofTEXTITEM8(items);
2691             PAD();
2692             break;
2693
2694       case 75: /* PolyText16 */
2695             UNUSED(1);
2696             v16 = REQUEST_LENGTH();
2697             DRAWABLE(drawable);
2698             GCONTEXT(gc);
2699             INT16(x);
2700             INT16(y);
2701             LISTofTEXTITEM16(items);
2702             PAD();
2703             break;
2704
2705       case 76: /* ImageText8 */
2706             v8 = FIELD8(string_length);
2707             REQUEST_LENGTH();
2708             DRAWABLE(drawable);
2709             GCONTEXT(gc);
2710             INT16(x);
2711             INT16(y);
2712             STRING8(string, v8);
2713             PAD();
2714             break;
2715
2716       case 77: /* ImageText16 */
2717             v8 = FIELD8(string_length);
2718             REQUEST_LENGTH();
2719             DRAWABLE(drawable);
2720             GCONTEXT(gc);
2721             INT16(x);
2722             INT16(y);
2723             STRING16(string16, v8);
2724             PAD();
2725             break;
2726
2727       case 78: /* CreateColormap */
2728             ENUM8(alloc);
2729             REQUEST_LENGTH();
2730             COLORMAP(mid);
2731             WINDOW(window);
2732             VISUALID(visual);
2733             break;
2734
2735       case 79: /* FreeColormap */
2736             UNUSED(1);
2737             REQUEST_LENGTH();
2738             COLORMAP(cmap);
2739             break;
2740
2741       case 80: /* CopyColormapAndFree */
2742             UNUSED(1);
2743             REQUEST_LENGTH();
2744             COLORMAP(mid);
2745             COLORMAP(src_cmap);
2746             break;
2747
2748       case 81: /* InstallColormap */
2749             UNUSED(1);
2750             REQUEST_LENGTH();
2751             COLORMAP(cmap);
2752             break;
2753
2754       case 82: /* UninstallColormap */
2755             UNUSED(1);
2756             REQUEST_LENGTH();
2757             COLORMAP(cmap);
2758             break;
2759
2760       case 83: /* ListInstalledColormaps */
2761             UNUSED(1);
2762             REQUEST_LENGTH();
2763             WINDOW(window);
2764             break;
2765
2766       case 84: /* AllocColor */
2767             UNUSED(1);
2768             REQUEST_LENGTH();
2769             COLORMAP(cmap);
2770             CARD16(red);
2771             CARD16(green);
2772             CARD16(blue);
2773             UNUSED(2);
2774             break;
2775
2776       case 85: /* AllocNamedColor */
2777             UNUSED(1);
2778             REQUEST_LENGTH();
2779             COLORMAP(cmap);
2780             v16 = FIELD16(name_length);
2781             UNUSED(2);
2782             STRING8(name, v16);
2783             PAD();
2784             break;
2785
2786       case 86: /* AllocColorCells */
2787             BOOL(contiguous);
2788             REQUEST_LENGTH();
2789             COLORMAP(cmap);
2790             CARD16(colors);
2791             CARD16(planes);
2792             break;
2793
2794       case 87: /* AllocColorPlanes */
2795             BOOL(contiguous);
2796             REQUEST_LENGTH();
2797             COLORMAP(cmap);
2798             CARD16(colors);
2799             CARD16(reds);
2800             CARD16(greens);
2801             CARD16(blues);
2802             break;
2803
2804       case 88: /* FreeColors */
2805             UNUSED(1);
2806             v16 = REQUEST_LENGTH();
2807             COLORMAP(cmap);
2808             CARD32(plane_mask);
2809             LISTofCARD32(pixels, v16 - 12);
2810             break;
2811
2812       case 89: /* StoreColors */
2813             UNUSED(1);
2814             v16 = REQUEST_LENGTH();
2815             COLORMAP(cmap);
2816             LISTofCOLORITEM(color_items, v16 - 8);
2817             break;
2818
2819       case 90: /* StoreNamedColor */
2820             COLOR_FLAGS(color);
2821             REQUEST_LENGTH();
2822             COLORMAP(cmap);
2823             CARD32(pixel);      
2824             v16 = FIELD16(name_length);
2825             UNUSED(2);
2826             STRING8(name, v16);
2827             PAD();
2828             break;
2829
2830       case 91: /* QueryColors */
2831             UNUSED(1);
2832             v16 = REQUEST_LENGTH();
2833             COLORMAP(cmap);
2834             LISTofCARD32(pixels, v16 - 8);
2835             break;
2836
2837       case 92: /* LookupColor */
2838             UNUSED(1);
2839             REQUEST_LENGTH();
2840             COLORMAP(cmap);
2841             v16 = FIELD16(name_length);
2842             UNUSED(2);
2843             STRING8(name, v16);
2844             PAD();
2845             break;
2846
2847       case 93: /* CreateCursor */
2848             UNUSED(1);
2849             REQUEST_LENGTH();
2850             CURSOR(cid);
2851             PIXMAP(source_pixmap);
2852             PIXMAP(mask);
2853             CARD16(fore_red);
2854             CARD16(fore_green);
2855             CARD16(fore_blue);
2856             CARD16(back_red);
2857             CARD16(back_green);
2858             CARD16(back_blue);
2859             CARD16(x);
2860             CARD16(y);
2861             break;
2862
2863       case 94: /* CreateGlyphCursor */
2864             UNUSED(1);
2865             REQUEST_LENGTH();
2866             CURSOR(cid);
2867             FONT(source_font);
2868             FONT(mask_font);
2869             CARD16(source_char);
2870             CARD16(mask_char);
2871             CARD16(fore_red);
2872             CARD16(fore_green);
2873             CARD16(fore_blue);
2874             CARD16(back_red);
2875             CARD16(back_green);
2876             CARD16(back_blue);
2877             break;
2878
2879       case 95: /* FreeCursor */
2880             UNUSED(1);
2881             REQUEST_LENGTH();
2882             CURSOR(cursor);
2883             break;
2884
2885       case 96: /* RecolorCursor */
2886             UNUSED(1);
2887             REQUEST_LENGTH();
2888             CURSOR(cursor);
2889             CARD16(fore_red);
2890             CARD16(fore_green);
2891             CARD16(fore_blue);
2892             CARD16(back_red);
2893             CARD16(back_green);
2894             CARD16(back_blue);
2895             break;
2896
2897       case 97: /* QueryBestSize */
2898             ENUM8(class);
2899             REQUEST_LENGTH();
2900             DRAWABLE(drawable);
2901             CARD16(width);
2902             CARD16(height);
2903             break;
2904
2905       case 98: /* QueryExtension */
2906             UNUSED(1);
2907             REQUEST_LENGTH();
2908             v16 = FIELD16(name_length);
2909             UNUSED(2);
2910             STRING8(name, v16);
2911             PAD();
2912             break;
2913
2914       case 99: /* ListExtensions */
2915             UNUSED(1);
2916             REQUEST_LENGTH();
2917             break;
2918
2919       case 100: /* ChangeKeyboardMapping */
2920             v8 = FIELD8(keycode_count);
2921             REQUEST_LENGTH();
2922             KEYCODE(first_keycode);
2923             v8_2 = FIELD8(keysyms_per_keycode);
2924             UNUSED(2);
2925             LISTofKEYSYM(keysyms, v8, v8_2);
2926             break;
2927
2928       case 101: /* GetKeyboardMapping */
2929             UNUSED(1);
2930             REQUEST_LENGTH();
2931             KEYCODE(first_keycode);
2932             FIELD8(count);
2933             UNUSED(2);
2934             break;
2935
2936       case 102: /* ChangeKeyboardControl */
2937             UNUSED(1);
2938             REQUEST_LENGTH();
2939             BITMASK32(keyboard_value);
2940             BITFIELD(INT8, keyboard_value_mask, key_click_percent);
2941             BITFIELD(INT8, keyboard_value_mask, bell_percent);
2942             BITFIELD(INT16, keyboard_value_mask, bell_pitch);
2943             BITFIELD(INT16, keyboard_value_mask, bell_duration);
2944             BITFIELD(INT16, keyboard_value_mask, led);
2945             BITFIELD(ENUM8, keyboard_value_mask, led_mode);
2946             BITFIELD(KEYCODE, keyboard_value_mask, keyboard_key);
2947             BITFIELD(ENUM8, keyboard_value_mask, auto_repeat_mode);
2948             ENDBITMASK;
2949             break;
2950
2951       case 103: /* GetKeyboardControl */
2952             UNUSED(1);
2953             REQUEST_LENGTH();
2954             break;
2955
2956       case 104: /* Bell */
2957             INT8(percent);
2958             REQUEST_LENGTH();
2959             break;
2960
2961       case 105: /* ChangePointerControl */
2962             UNUSED(1);
2963             REQUEST_LENGTH();
2964             INT16(acceleration_numerator);
2965             INT16(acceleration_denominator);
2966             INT16(threshold);
2967             BOOL(do_acceleration);
2968             BOOL(do_threshold);
2969             break;
2970
2971       case 106: /* GetPointerControl */
2972             UNUSED(1);
2973             REQUEST_LENGTH();
2974             break;
2975
2976       case 107: /* SetScreenSaver */
2977             UNUSED(1);
2978             REQUEST_LENGTH();
2979             INT16(timeout);
2980             INT16(interval);
2981             ENUM8(prefer_blanking);
2982             ENUM8(allow_exposures);
2983             UNUSED(2);
2984             break;
2985
2986       case 108: /* GetScreenSaver */
2987             UNUSED(1);
2988             REQUEST_LENGTH();
2989             break;
2990
2991       case 109: /* ChangeHosts */
2992             ENUM8(change_host_mode);
2993             REQUEST_LENGTH();
2994             v8 = ENUM8(family);
2995             UNUSED(1);
2996             v16 = CARD16(address_length);
2997             if (v8 == FAMILY_INTERNET && v16 == 4) {
2998                   /*
2999                    * IPv4 addresses.
3000                    * XXX - what about IPv6?  Is that a family of
3001                    * FAMILY_INTERNET (0) with a length of 16?
3002                    */
3003                   LISTofCARD8(ip_address, v16);
3004             } else
3005                   LISTofCARD8(address, v16);
3006             break;
3007
3008       case 110: /* ListHosts */
3009             UNUSED(1);
3010             REQUEST_LENGTH();
3011             break;
3012
3013       case 111: /* SetAccessControl */
3014             ENUM8(access_mode);
3015             REQUEST_LENGTH();
3016             break;
3017
3018       case 112: /* SetCloseDownMode */
3019             ENUM8(close_down_mode);
3020             REQUEST_LENGTH();
3021             break;
3022
3023       case 113: /* KillClient */
3024             UNUSED(1);
3025             REQUEST_LENGTH();
3026             CARD32(resource);
3027             break;
3028
3029       case 114: /* RotateProperties */
3030             UNUSED(1);
3031             v16 = REQUEST_LENGTH();
3032             WINDOW(window);
3033             CARD16(property_number);
3034             INT16(delta);
3035             LISTofATOM(properties, (v16 - 12));
3036             break;
3037
3038       case 115: /* ForceScreenSaver */
3039             ENUM8(screen_saver_mode);
3040             REQUEST_LENGTH();
3041             break;
3042
3043       case 116: /* SetPointerMapping */
3044             v8 = FIELD8(map_length);
3045             REQUEST_LENGTH();
3046             LISTofCARD8(map, v8);
3047             PAD();
3048             break;
3049
3050       case 117: /* GetPointerMapping */
3051             UNUSED(1);
3052             REQUEST_LENGTH();
3053             break;
3054
3055       case 118: /* SetModifierMapping */
3056             v8 = FIELD8(keycodes_per_modifier);
3057             REQUEST_LENGTH();
3058             LISTofKEYCODE(keycodes, v8);
3059             break;
3060
3061       case 119: /* GetModifierMapping */
3062             UNUSED(1);
3063             REQUEST_LENGTH();
3064             break;
3065             
3066       case 127: /* NoOperation */
3067             UNUSED(1);
3068             REQUEST_LENGTH();
3069             break;
3070       }
3071       left = tvb_length_remaining(tvb, offset);
3072       if (left)
3073             proto_tree_add_item(t, hf_x11_undecoded, tvb, offset, left, little_endian);
3074 }
3075
3076 static void dissect_x11_requests(tvbuff_t *tvb, packet_info *pinfo,
3077     proto_tree *tree)
3078 {
3079       volatile int offset = 0;
3080       int length_remaining;
3081       guint8 opcode;
3082       volatile int plen;
3083       proto_item *ti;
3084       proto_tree *t;
3085       volatile gboolean is_initial_creq;
3086       guint16 auth_proto_len, auth_data_len;
3087       const char *volatile sep = NULL;
3088       conversation_t *conversation;
3089       x11_conv_data_t *volatile state_info;
3090       int byte_order;
3091       int length;
3092       tvbuff_t *next_tvb;
3093
3094       while (tvb_reported_length_remaining(tvb, offset) != 0) {
3095             length_remaining = tvb_length_remaining(tvb, offset);
3096
3097             /*
3098              * Can we do reassembly?
3099              */
3100             if (x11_desegment && pinfo->can_desegment) {
3101                   /*
3102                    * Yes - is the X11 request header split across
3103                    * segment boundaries?
3104                    */
3105                   if (length_remaining < 4) {
3106                         /*
3107                          * Yes.  Tell the TCP dissector where the data
3108                          * for this message starts in the data it handed
3109                          * us, and how many more bytes we need, and return.
3110                          */
3111                         pinfo->desegment_offset = offset;
3112                         pinfo->desegment_len = 4 - length_remaining;
3113                         return;
3114                   }
3115             }
3116
3117             /*
3118              * Get the state for this conversation; create the conversation
3119              * if we don't have one, and create the state if we don't have
3120              * any.
3121              */
3122             conversation = find_conversation(&pinfo->src, &pinfo->dst,
3123                 pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
3124             if (conversation == NULL) {
3125                   /*
3126                    * No - create one.
3127                    */
3128                   conversation = conversation_new(&pinfo->src,
3129                         &pinfo->dst, pinfo->ptype, pinfo->srcport,
3130                         pinfo->destport, 0);
3131             }
3132
3133             /*
3134              * Is there state attached to this conversation?
3135              */
3136             state_info = conversation_get_proto_data(conversation, proto_x11);
3137             if (state_info == NULL) {
3138                   /*
3139                    * No - create a state structure and attach it.
3140                    */
3141                   state_info = g_mem_chunk_alloc(x11_state_chunk);
3142                   state_info->opcode = NOTHING_SEEN;    /* nothing seen yet */
3143                   state_info->iconn_frame = 0;  /* don't know it yet */
3144                   state_info->byte_order = BYTE_ORDER_UNKNOWN;  /* don't know it yet */
3145                   conversation_add_proto_data(conversation, proto_x11,
3146                         state_info);
3147             }
3148
3149             /*
3150              * Guess the byte order if we don't already know it.
3151              */
3152             little_endian = guess_byte_ordering(tvb, pinfo, state_info);
3153
3154             /*
3155              * Get the opcode and length of the putative X11 request.
3156              */
3157             opcode = VALUE8(tvb, 0);
3158             plen = VALUE16(tvb, offset + 2);
3159
3160             if (plen == 0) {
3161                   /*
3162                    * This can't be 0, as it includes the header length.
3163                    * A different choice of byte order wouldn't have
3164                    * helped.
3165                    * Give up.
3166                    */
3167                   ti = proto_tree_add_item(tree, proto_x11, tvb, offset, -1, FALSE);
3168                   t = proto_item_add_subtree(ti, ett_x11);
3169                   proto_tree_add_text(t, tvb, offset, -1, "Bogus request length (0)");
3170                   return;
3171             }
3172
3173             if (state_info->iconn_frame == pinfo->fd->num ||
3174                 (state_info->opcode == NOTHING_SEEN &&
3175                  (opcode == 'B' || opcode == 'l') &&
3176                  (plen == 11 || plen == 2816))) {
3177                   /*
3178                    * Either
3179                    *
3180                    *    we saw this on the first pass and this is
3181                    *    it again
3182                    *
3183                    * or
3184                    *    we haven't already seen any requests, the first
3185                    *    byte of the message is 'B' or 'l', and the 16-bit
3186                    *    integer 2 bytes into the data stream is either 11
3187                    *    or a byte-swapped 11.
3188                    *
3189                    * This means it's probably an initial connection
3190                    * request, not a message.
3191                    *
3192                    * 'B' is decimal 66, which is the opcode for a
3193                    * PolySegment request; unfortunately, 11 is a valid
3194                    * length for a PolySegment request request, so we
3195                    * might mis-identify that request.  (Are there any
3196                    * other checks we can do?)
3197                    *
3198                    * 'l' is decimal 108, which is the opcode for a
3199                    * GetScreenSaver request; the only valid length
3200                    * for that request is 1.
3201                    */
3202                   is_initial_creq = TRUE;
3203
3204                   /*
3205                    * We now know the byte order.  Override the guess.
3206                    */
3207                   if (state_info->byte_order == BYTE_ORDER_UNKNOWN) {
3208                         if (opcode == 'B') {
3209                               /*
3210                                * Big-endian.
3211                                */
3212                               state_info->byte_order = BYTE_ORDER_BE;
3213                               little_endian = FALSE;
3214                         } else {
3215                               /*
3216                                * Little-endian.
3217                                */
3218                               state_info->byte_order = BYTE_ORDER_LE;
3219                               little_endian = TRUE;
3220                         }
3221                   }
3222
3223                   /*
3224                    * Can we do reassembly?
3225                    */
3226                   if (x11_desegment && pinfo->can_desegment) {
3227                         /*
3228                          * Yes - is the fixed-length portion of the
3229                          * initial connection header split across
3230                          * segment boundaries?
3231                          */
3232                         if (length_remaining < 10) {
3233                               /*
3234                                * Yes.  Tell the TCP dissector where the
3235                                * data for this message starts in the data
3236                                * it handed us, and how many more bytes we
3237                                * need, and return.
3238                                */
3239                               pinfo->desegment_offset = offset;
3240                               pinfo->desegment_len = 10 - length_remaining;
3241                               return;
3242                         }
3243                   }
3244
3245                   /*
3246                    * Get the lengths of the authorization protocol and
3247                    * the authorization data.
3248                    */
3249                   auth_proto_len = VALUE16(tvb, offset + 6);
3250                   auth_data_len = VALUE16(tvb, offset + 8);
3251                   plen = 12 + ROUND_LENGTH(auth_proto_len) +
3252                         ROUND_LENGTH(auth_data_len);
3253             } else {
3254                   /*
3255                    * This is probably an ordinary request.
3256                    */
3257                   is_initial_creq = FALSE;
3258
3259                   /*
3260                    * The length of a request is in 4-byte words.
3261                    */
3262                   plen *= 4;
3263             }
3264
3265             /*
3266              * Can we do reassembly?
3267              */
3268             if (x11_desegment && pinfo->can_desegment) {
3269                   /*
3270                    * Yes - is the X11 request split across segment
3271                    * boundaries?
3272                    */
3273                   if (length_remaining < plen) {
3274                         /*
3275                          * Yes.  Tell the TCP dissector where the data
3276                          * for this message starts in the data it handed
3277                          * us, and how many more bytes we need, and return.
3278                          */
3279                         pinfo->desegment_offset = offset;
3280                         pinfo->desegment_len = plen - length_remaining;
3281                         return;
3282                   }
3283             }
3284
3285             /*
3286              * Construct a tvbuff containing the amount of the payload
3287              * we have available.  Make its reported length the
3288              * amount of data in the X11 request.
3289              *
3290              * XXX - if reassembly isn't enabled. the subdissector
3291              * will throw a BoundsError exception, rather than a
3292              * ReportedBoundsError exception.  We really want a tvbuff
3293              * where the length is "length", the reported length is "plen",
3294              * and the "if the snapshot length were infinite" length is the
3295              * minimum of the reported length of the tvbuff handed to us
3296              * and "plen", with a new type of exception thrown if the offset
3297              * is within the reported length but beyond that third length,
3298              * with that exception getting the "Unreassembled Packet" error.
3299              */
3300             length = length_remaining;
3301             if (length > plen)
3302                   length = plen;
3303             next_tvb = tvb_new_subset(tvb, offset, length, plen);
3304
3305             /*
3306              * Set the column appropriately.
3307              */
3308             if (is_initial_creq) {
3309                   if (check_col(pinfo->cinfo, COL_INFO)) 
3310                         col_set_str(pinfo->cinfo, COL_INFO, "Initial connection request");
3311             } else {
3312                   if (sep == NULL) {
3313                         /*
3314                          * We haven't set the column yet; set it.
3315                          */
3316                         if (check_col(pinfo->cinfo, COL_INFO)) 
3317                               col_add_str(pinfo->cinfo, COL_INFO, "Requests");
3318
3319                         /*
3320                          * Initialize the separator.
3321                          */
3322                         sep = ":";
3323                   }
3324             }
3325
3326             /*
3327              * Dissect the X11 request.
3328              *
3329              * Catch the ReportedBoundsError exception; if this
3330              * particular message happens to get a ReportedBoundsError
3331              * exception, that doesn't mean that we should stop
3332              * dissecting X11 requests within this frame or chunk of
3333              * reassembled data.
3334              *
3335              * If it gets a BoundsError, we can stop, as there's nothing
3336              * more to see, so we just re-throw it.
3337              */
3338             TRY {
3339                   if (is_initial_creq) {
3340                         dissect_x11_initial_conn(next_tvb, pinfo, tree,
3341                             state_info);
3342                   } else {
3343                         dissect_x11_request(next_tvb, pinfo, tree, sep,
3344                             state_info);
3345                   }
3346             }
3347             CATCH(BoundsError) {
3348                   RETHROW;
3349             }
3350             CATCH(ReportedBoundsError) {
3351                   show_reported_bounds_error(tvb, pinfo, tree);
3352             }
3353             ENDTRY;
3354
3355             /*
3356              * Skip the X11 message.
3357              */
3358             offset += plen;
3359
3360             sep = ",";
3361       }
3362 }
3363
3364 static void
3365 dissect_x11_replies(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3366 {
3367 /* Set up structures we will need to add the protocol subtree and manage it */
3368       proto_item *ti;
3369       proto_tree *x11_tree;
3370         
3371 /* This field shows up as the "Info" column in the display; you should make
3372    it, if possible, summarize what's in the packet, so that a user looking
3373    at the list of packets can tell what type of packet it is. */
3374       if (check_col(pinfo->cinfo, COL_INFO)) 
3375             col_set_str(pinfo->cinfo, COL_INFO, "Replies/events");
3376
3377 /* In the interest of speed, if "tree" is NULL, don't do any work not
3378    necessary to generate protocol tree items. */
3379       if (!tree) return;
3380       ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
3381       x11_tree = proto_item_add_subtree(ti, ett_x11);
3382
3383       /*
3384        * XXX - dissect these in a loop, like the requests.
3385        */
3386       call_dissector(data_handle,tvb, pinfo, x11_tree);
3387 }
3388
3389 /************************************************************************
3390  ***                                                                  ***
3391  ***         I N I T I A L I Z A T I O N   A N D   M A I N            ***
3392  ***                                                                  ***
3393  ************************************************************************/
3394
3395 static void
3396 dissect_x11(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3397 {
3398       if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
3399             col_set_str(pinfo->cinfo, COL_PROTOCOL, "X11");
3400     
3401       if (pinfo->match_port == pinfo->destport)
3402             dissect_x11_requests(tvb, pinfo, tree);
3403       else
3404             dissect_x11_replies(tvb, pinfo, tree);
3405 }
3406
3407 /* Register the protocol with Ethereal */
3408 void proto_register_x11(void)
3409 {                 
3410
3411 /* Setup list of header fields */
3412       static hf_register_info hf[] = {
3413 /*
3414   { &hf_x11_FIELDABBREV,
3415   { "FIELDNAME",           "x11.FIELDABBREV",
3416   FIELDTYPE, FIELDBASE, FIELDCONVERT, BITMASK,          
3417   "FIELDDESCR", HFILL }
3418   },
3419 */
3420 #include "x11-register-info.h"
3421       };
3422
3423 /* Setup protocol subtree array */
3424       static gint *ett[] = {
3425             &ett_x11,
3426             &ett_x11_color_flags,
3427             &ett_x11_list_of_arc,
3428             &ett_x11_arc,
3429             &ett_x11_list_of_atom,
3430             &ett_x11_list_of_card32,
3431             &ett_x11_list_of_color_item,
3432             &ett_x11_color_item,
3433             &ett_x11_list_of_keycode,
3434             &ett_x11_list_of_keysyms,
3435             &ett_x11_keysym,
3436             &ett_x11_list_of_point,
3437             &ett_x11_point,
3438             &ett_x11_list_of_rectangle,
3439             &ett_x11_rectangle,
3440             &ett_x11_list_of_segment,
3441             &ett_x11_segment,
3442             &ett_x11_list_of_string8,
3443             &ett_x11_list_of_text_item,
3444             &ett_x11_text_item,
3445             &ett_x11_gc_value_mask,
3446             &ett_x11_event_mask,
3447             &ett_x11_do_not_propagate_mask,
3448             &ett_x11_set_of_key_mask,
3449             &ett_x11_pointer_event_mask,
3450             &ett_x11_window_value_mask,
3451             &ett_x11_configure_window_mask,
3452             &ett_x11_keyboard_value_mask,
3453       };
3454       module_t *x11_module;
3455
3456 /* Register the protocol name and description */
3457       proto_x11 = proto_register_protocol("X11", "X11", "x11");
3458
3459 /* Required function calls to register the header fields and subtrees used */
3460       proto_register_field_array(proto_x11, hf, array_length(hf));
3461       proto_register_subtree_array(ett, array_length(ett));
3462
3463       register_init_routine(x11_init_protocol);
3464
3465       x11_module = prefs_register_protocol(proto_x11, NULL);
3466       prefs_register_bool_preference(x11_module, "desegment",
3467             "Desegment all X11 messages spanning multiple TCP segments",
3468             "Whether the X11 dissector should desegment all messages spanning multiple TCP segments",
3469             &x11_desegment);
3470 }
3471
3472 void
3473 proto_reg_handoff_x11(void)
3474 {
3475   dissector_handle_t x11_handle;
3476
3477   x11_handle = create_dissector_handle(dissect_x11, proto_x11);
3478   dissector_add("tcp.port", TCP_PORT_X11, x11_handle);
3479   dissector_add("tcp.port", TCP_PORT_X11_2, x11_handle);
3480   dissector_add("tcp.port", TCP_PORT_X11_3, x11_handle);
3481   data_handle = find_dissector("data");
3482 }